Raise events from C to C# (iOS to Unity) - c#

I would like to register for events in Unity and raise those events from C in iOS.
I have the following pattern -
// Unity side register delegate and event handler
private delegate void CallbackDelegate(CBObj data);
public static event CallbackDelegate dataUpdatedEvent;
// for iOS
#if !UNITY_EDITOR && UNITY_IOS
[DllImport("__Internal")]
private static extern void PluginFunction(CallbackDelegate callback);
#endif
public CBObj {
// marshal C objects to c# objects in the constructor here using the Ptr from C
}
[MonoPInvokeCallback(typeof(CallbackDelegate))]
static void CallbackMethod(CBObj dataPtr)
{
if (dataUpdatedEvent != null)
{
CBObj obj = new CBObj(dataPtr);
dataUpdatedEvent(obj);
}
}
// Unity Usage
private CallbackDelegate evt;
void Start(){
evt += updateEvent;
}
public void updateEvent(CBObj data){
// do something with data everytime its called
}
// C code
extern "C" typedef void (*CallBackFuncP) (CBObj dataPtr);
typedef struct
{
float *data1;
int *data2;
} CBObj;
extern "C" {
CallBackFuncP* cb;
void PluginFunction(CallBackFuncP callback) {
// store the the callback function pointer
cb = callback;
}
}
// raise the event somewhere in code
if (cb != NULL) {
CBObj *test = [[CBObj alloc] init];
cb(test)
}
Would this work? Is this the correct pattern? Is there a better way to do it?
Any pointers to do this are highly appreciated.

Unity suggests using UnitySendMessage function to call a C# method from C.
You can use json to format the data
NSDictionary *d = #{ #"data1":1, #"data2":2.0 };
NSData *j = [NSJSONSerialization dataWithJSONObject:d options:0 error:NULL];
NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
UnitySendMessage("GameObjectName", "MethodName", [s UTF8String]);
In unity, create a GameObject named GameObjectName, attach a script with a method named MethodName. Use a json library to decode the string into an object.
public class YourScriptName : Monobehaviour
{
public class CBObj
{
public int data1;
public float data2;
}
public void MethodName(string data)
{
var obj = UnityEngine.JsonUtility.FromJson<CBObj>(data);
}
}

I solved it by the following patter and it worked flawlessly. Hope this helps someone.
// Unity side register delegate and event handler
delegate void Internal_CallbackDelegate(IntPtr dataPtr);
public delegate void CallbackDelegate(CBObj data);
// The above pattern is to deal with pointer conversion from iOS to Unity
public static event CallbackDelegate DataUpdatedEvent;
// YourUnityKlass for iOS
#if !UNITY_EDITOR && UNITY_IOS
[DllImport("__Internal")]
private static extern void PluginFunction(Internal_CallbackDelegate callback);
#endif
// Where this class is declared call in constructor
#if !UNITY_EDITOR && UNITY_IOS
PluginFunction(CallbackMethod);
#endif
public CBObj {
// marshal C objects to c# objects in the constructor here using the Ptr from C
private IntPtr m_Ptr;
internal CBObj(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
throw new ArgumentException("ptr may not be IntPtr.Zero");
m_Ptr = ptr;
// getDataFromC();
}
// get individual pointers by exposing them via C and mashall copy the data as per your needs
}
[MonoPInvokeCallback(typeof(Internal_CallbackDelegate))]
static void CallbackMethod(IntPtr dataPtr)
{
if (DataUpdatedEvent != null)
{
CBObj obj = new CBObj(dataPtr);
DataUpdatedEvent(obj);
}
}
// Unity Usage
void Start(){
YourUnityKlass klass = new YourUnityKlass();
YourUnityKlass.DataUpdatedEvent += updateEvent;
}
public void updateEvent(CBObj data){
// do something with data every time its called
}
// C header - code
typedef struct
{
float *data1;
int *data2;
} CBObj;
typedef void (*CallBackFuncP) (CBObj* dataPtr);
#interface CallbackWrapper : NSObject
{
#public
CallBackFuncP _dataUpdate;
}
- (void) sendDataUpdate:(CBObj*) obj;
#end
// C - impl code
#implementation CallbackWrapper
-(void) sendDataUpdate:(CBObj*) objPtr
{
if (_dataUpdate != NULL){
_dataUpdate(objPtr);
}
}
#end
extern "C" {
void PluginFunction(CallBackFuncP callback) {
// Create a swiftKlass to store your callback pointer
CallbackWrapper* cb = [[SwiftKlass shared] getCallback];
cb->_dataUpdate = callback;
}
}
// Swift usage - Inside say SwiftKlass
#objc public func getCallback() -> CallbackWrapper {
return self.cb
}

Related

Unmanaged c++ DLL to get struct from c#

Is it possible to call a method in c# from c++ DLL ?
I have good communication c# -> C++ , but I would like to be able to initiate a call C++ -> c# to poll some data
my code looks something like this...
host.h
/*
define the exporter for the C API
*/
#ifdef DLL_EXPORT
#define DLL_EXPORT __declspec(dllexport)
#else
#define DLL_EXPORT __declspec(dllimport)
#endif
class myClass
{
public:
myCLass(){
//do some initialising
}
~myCLass(){
//do some tidying
}
int getInt(int target) {
switch (target)
{
case 0:
return someIntValue;
case 1:
return someOtherIntValue;
default:
return 0;
}
}
std::string getString(int target) {
switch (target)
{
case 0:
return someStringValue;
case 1:
return someOtherStringValue;
default:
return "";
}
}
}
extern "C" {
DLL_EXPORT myClass* myClassConstructor();
DLL_EXPORT void DestroySpatialser(const myClass* _pContext);
DLL_EXPORT int getInt(myClass* _pContext, int target);
DLL_EXPORT void getString(myClass* _pContext, int target, __out BSTR* returnStr);
}
host.cpp
extern "C" {
myClass* myClassConstructor()
{
return new myClass();
}
void myClassDestructor(const myClass* _pContext)
{
if (_pContext != nullptr)
{
_pContext->~myClass();
delete _pContext;
}
}
//example
int getInt(myClass* _pContext, int target)
{
if (_pContext == nullptr)
{
return K_ERR_INT;
}
return _pContext->getInt(target);
}
void getString(myClass* _pContext, int target, __out BSTR* returnStr)
{
std::string str;
if (_pContext == nullptr)
{
str = K_ERR_CHAR;
}
else {
str = _pContext->getString(target);
}
const std::string stdStr = str;
_bstr_t bstrStr = stdStr.c_str();
*returnStr = bstrStr.copy();
}
}
csharp.cs
private const string dllname = "myhost";
[DllImport(dllname)]
private static extern IntPtr myClassConstructor();
[DllImport(dllname)]
private static extern void myClassDestructor(IntPtr _pContext);
[DllImport(dllname)]
private static extern int getInt(IntPtr _pContext, int target);
[DllImport(dllname)]
private static extern float getFloat(IntPtr _pContext, int target);
[DllImport(dllname, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
extern static void getString(IntPtr _pContext, int target, [MarshalAs(UnmanagedType.BStr)] out String str);
private static IntPtr _pContext;
public static IntPtr Create()
{
_pContext = myClassConstructor();
Debug.Log("_pContextcreated");
return _pContext;
}
public static void Destroy()
{
myClassDestructor(_pContext );
}
private static int _getInt(int target)
{
return getInt(_pContext , target);
}
private static string _getString(int target)
{
String str;
getString(_pContext , target, out str);
return str;
}
This all works fine.
I'd like to add the ability to get a value from the .cs app (it will be a struct of 3 floats) which should be called from the instance of myClass.
I don't want to initiate this on c# side (i know how to do that).
Any advice?
EDIT
I implemented the solution found here
https://forum.unity.com/threads/communicating-c-with-c.89930/#post-586885
with two changes (see comments below for why)
public int whatever = 0;
public delegate int myCallbackDelegate( int n, int m );
private myCallbackDelegate myCallback; // <-- add this line
[DllImport ("DLLImport_CProj")]
private static extern int TakesCallback( myCallbackDelegate fp, int n, int m );
void Awake()
{
myCallback = new myCallbackDelegate( this.myCallback ) // <-- add this
int resp = TakesCallback(myCallback, 10, 20 ); // <-- change to this
Debug.Log( resp );
}
Well, One way I can think of is to pass a JSON string as char array from C++ to C# and then parse it on C# and get the data. it's a communication method both languages are familiar with.
Also, you will need to pass a callback from C# to C++ to allow this like explained in this question.
Let me know if this helps :)
Make your C# types COMVisible, which means you will be able to call them from COM aware C++ code, e.g., using ATL.

c++ native code DLL using an abstract class into a wrapper to be used in C# module

Hi i am having the same problem with abstract class.i am trying to wrap my cpp Dll calls to use in the C# module.
Dll is using the Factory pattern.which contain a class Factory,MiddileWare ,And their costrong textrresponding child class.Could any one help me to start the wrapper. i am stuck in between this.Your help will be appreciated. i am giving the flow here:
MiddleWareFactory.h
#pragma once
#include "MiddleWareConnection.h"
#include "std afx.h"
#ifdef MIDDLEWAREFACTORY_EXPORTS
#define MIDDLEWAREFACTORY_API __declspec(dllexport)
#else
#define MIDDLEWAREFACTORY_API __declspec(dllimport)
#endif
MIDDLEWAREFACTORY_API enum eMiddleWareEngine
{
eRabitMQ = 0,
eZeroMQ,
eActiveMQ
};
// This class is exported from the MiddleWareFactory.dll
class MIDDLEWAREFACTORY_API CMiddleWareFactory
{
public:
CMiddleWareFactory(void);
~CMiddleWareFactory();
// TODO: add your methods here.
//Function to Create the object of Broker module:implemnted the Factory concept.
BOOL CreateInstance(CMiddleWareConnection** pMObj);
int m_eMomEngine;//To define which MOM need to enable.
};
extern MIDDLEWAREFACTORY_API int nMiddleWareFactory;
MIDDLEWAREFACTORY_API int fnMiddleWareFactory(void);
MiddleWareConnection.h
#pragma once
class CMiddleWareConnection
{
public:
virtual ~CMiddleWareConnection(void)
{
}
//Pure virtual fuctions for interfacing
virtual BOOL Connect(int nServerType)=0;
virtual BOOL CreateSessionExchange() = 0;
virtual BOOL CreateQueue(LPCTSTR lpszQueueName) = 0;
virtual BOOL Disconnect() = 0;
virtual BOOL Send(void *MomItem,LPCTSTR lpszKey, int &nSendCount)=0;
virtual BOOL Receive() = 0;
virtual void StopReceiver() = 0;
virtual void GetData(void* pMsg, int &nMsgLen,int nMsgType,int &nReceiveCount)=0;
};
RabbitMQ.h
#pragma once
#include "MiddleWareConnection.h"
#include "Amqp.h"
#pragma comment(lib, "rabbitmq.4.lib")
#define GET_DATA(a){memcpy(&a, pDataPtr, sizeof(a));pDataPtr+=sizeof(a);}
#define GET_DATA_EX(s,n){memcpy(s, pDataPtr, n);pDataPtr+=n;}
typedef struct _ROUTINE_KEY
{
CString RoutingKey;
}ROUTEKEY, *LPROUTEKEY;
class CRabbitMQ :
public CMiddleWareConnection
{
public:
CRabbitMQ(CAppConfig &rConfig);
~CRabbitMQ();
void InitializeRBMQ(CAppConfig &rConfig);//Initialize RBMQ Config;
BOOL Connect(int nServerType);
BOOL Disconnect(void);
BOOL Send(void *MomItem, LPCTSTR lpszKey, int &nSendCount);
BOOL Receive(void);
BOOL CreateQueue(LPCTSTR lpszQueueName);
BOOL CreateSessionExchange();
BOOL BindQueue(LPCTSTR lpszQueue, LPCTSTR lpszExchangeName, LPCTSTR lpszKey);
bool IsConnected(){return m_bConnected;}
void SetKeyQueueCombination( TCHAR *pszQueueName, TCHAR *pszRoutingKey);
void StopReceiver();
bool ReEstablishRMQMWConnection();
void GetData(LPBYTE &pMsg, int &nMsgLen,int &nReceiveCount);
void GetData(void* pMsg, int &nMsgLen,int nMsgType,int &nReceiveCount);
BOOL GetNext_JasonListItem(LPJASON_ITEM pItem);
LPRABBIT_MQ_ITEM GetNextItem();
};
Here i want to expose the rabbitMq class functions[Connect,send,Recieve ete from MiddleWareConnection.h to C# module.
Thanks
below I posted a small code example of a wrapping C++/CLI class. You could create a new C++/CLI project which links your native library and create a class following the example below. This will produce a managed assembly that you could reference from C# side. Hope it helps!
#include <Windows.h>
#include <vcclr.h>
using namespace System;
using namespace System::Text;
using namespace System::Collections::Generic;
using namespace System::Runtime::InteropServices;
public ref class CMiddleWareConnection_Net
{
public:
CMiddleWareConnection_Net()
{
pMiddleWareConnection = NULL;
}
~CMiddleWareConnection_Net()
{
//Release pMiddleWareConnection
if (pMiddleWareConnection)
delete pMiddleWareConnection;
}
void InitializeRBMQ(CAppConfig_Net config)
{
// CAppConfig_Net is another ref class
// which provides a toNative method
// returning a plain C++ CAppConfig object
CAppConfig rConfig = config.toNative();
pMiddleWareConnection = CRabbitMQ(rConfig);
}
bool Connect(int nServerType)
{
return (pMiddleWareConnection->Connect(nServerType) == TRUE);
}
bool Disconnect(void)
{
return (pMiddleWareConnection->Disconnect() == TRUE);
}
bool Send(array<Byte>^ MomItem, String^ lpszKey, int% nSendCount)
{
//Assuming MomItem is a byte array...
unsigned char *pData = new unsigned char[MomItem->Length];
Marshal::Copy(MomItem, 0, IntPtr(pData), MomItem->Length);
//Marshal String^ to LPCSTR
IntPtr ip = Marshal::StringToHGlobalAnsi(lpszKey);
LPCSTR str = static_cast<LPCSTR>(ip.ToPointer());
bool bRet = (pMiddleWareConnection->Send(pData, str, nSendCount) == TRUE);
//Freeing memory
delete[] pData;
Marshal::FreeHGlobal(ip);
return bRet;
}
bool Receive(void)
{
return (pMiddleWareConnection->Receive() == TRUE);
}
/* Other methods */
...
private:
CMiddleWareConnection *pMiddleWareConnection;
};
****MiddleWareFactory.h****
BOOL CreateInstance(CMiddleWareConnection** pMObj)
{
//if( some config value)
*pMObj = new RabbitMq();
// esle
/***other MOm like OBCS,OSCS etec...**/
}
****MiddlewareConnection.h****
have the basic abstract functions....
**Rabbitmq.h**
it is one of the child class.
****Wrapper****
CLRWrapper::CppMathWrapper::CppMathWrapper()
{
cppMath = new cCppMath();
oFact->createInstance(&cppMath);'// here i want to pass the reference & wanna get back the child class type:now i am stuck here..how can we pass/marshal the object:im getting the error
}
BOOL CLRWrapper::CppMathWrapper::connect(type)
{
return (cppMath->Connect(nServerType) == TRUE);
}
..........And so On............
CLR Wrapper.cpp(11) : error C2664: 'Factory::createInstance' : cannot convert parameter 1 from 'cli::interior_ptr' to 'Base **'
1> with
1> [
1> Type=cCppMath *
1> ]
1> Cannot convert a managed type to an unmanaged type
}
instead of this we are using createinstance()[InitializeRBMQ() is inside connect(),so it will be handled inside i think]
void InitializeRBMQ(CAppConfig_Net config)
{
// CAppConfig_Net is another ref class
// which provides a toNative method
// returning a plain C++ CAppConfig object
CAppConfig rConfig = config.toNative();
pMiddleWareConnection = CRabbitMQ(rConfig);
}
C# side
i want to expose :
private static void Main(string[] args)
{
CppMathWrapper wrapper = new CppMathWrapper();
wrapper.connect(0);
}
i tried one example with CPPMath class.In real i am attaching the code below:
CLRWrapper::CppMathWrapper::CppMathWrapper()
{
middlewareConnection *oConn;// MiddleConnection.h pointer
middleWareFactory oFact= new middleWareFactory ();// MiddleWareFactory.h object
oFact->createInstance(&oConn);'// here i want to pass the reference & wanna get back the child class type:now i am stuck here..how can we pass/marshal the object:im getting the error.How could i wrap the object....the same like
}
BOOL CLRWrapper::CppMathWrapper::connect(type)
{
return (oConn->Connect(nServerType) == TRUE);
}
..........And so On............

C# marshaling C struct

I've this C-C# code that works:
.h
typedef struct {
float a;
float b;
} MyStruct;
extern MyStruct mystruct;
__declspec(dllexport) void GetMyStruct (MyStruct* s);
__declspec(dllexport) void SetMyStruct (MyStruct* s);
.c
MyStruct mystruct;
void GetMyStruct (MyStruct* s)
{
*s = AeroLink_IOPkt;
}
void SetMyStruct (MyStruct* s)
{
AeroLink_IOPkt = *s;
}
void test()
{
// some code that update element in struct
// mystruct.a = 0.4;
// mystruct.a = 0.1;
}
.cs
public struct MyStruct
{
public float a;
public float b;
}
[DllImport(DLL_NAME, EntryPoint = "GetMyStruct")]
protected static extern void GetMyStruct(ref MyStruct s);
[DllImport(DLL_NAME, EntryPoint = "SetMyStruct")]
protected static extern void SetMyStruct(ref MyStruct s);
This way, every time I need to set data from C# to C, I must call void SetMyStruct and vice-versa if I want to get data from C (updated from void test) to C# I must call GetMyStruct. I must do this 50 times per seconds.
Is there a way to avoid calling SetMyStruct and GetMyStruct every time? I would like to use SetMyStruct one time and then have all changes be reflected, from and to. I do not know if this is possible.
You can do this with unsafe and pointers.
You need to compile your C# program with "Unsafe" enabled.
EDIT: A better way:
Add a following function to the library:
__declspec(dllexport) void GetMyStructRef (MyStruct** s);
void GetMyStructRef(MyStruct** s)
{
*s = &mystruct;
}
In C#:
[DllImport(DLL_NAME, EntryPoint = "GetMyStructRef")]
protected static extern void GetMyStructRef(ref MyStruct* s);
MyStruct* data;
GetMyStructRef(ref data);
Console.WriteLine($"{data->a} {data->b}");
Old answer:
unsafe class MyClass : IDisposable
{
[DllImport(DLL_NAME, EntryPoint = "GetMyStruct")]
protected static extern void GetMyStruct(MyStruct* s);
[DllImport(DLL_NAME, EntryPoint = "SetMyStruct")]
protected static extern void SetMyStruct(MyStruct* s);
GCHandle handle;
MyStruct* structRef;
public void MyClass()
{
//we need to get a pinned reference to your struct
handle = GCHandle.Alloc(new MyStruct(), GCHandleType.Pinned);
structRef = (MyStruct*)handle.AddrOfPinnedObject().ToPointer();
SetMyStruct(structRef);
}
public void Dispose()
{
//We need to free the handle to release memory
//GC will not collect it without this
handle.Free();
}
}

Event from external callback

I'm creating a project of data transmitter using custom DLL written in ANSI C. My aim is to send chunks of data, which each of them must be confirmed after sending by build in OnDataSendingDone callback.
The problem is that I have no idea how to hook that callback to an event, so I can wait for it after each SendByte. Maybe event is not such a good idea.
My question is: how to wait for the OnDataSendingDone callback after SendByte?
Please give me some clues. Here is the code snippet:
class LibWrapper
{
[DllImport(dllPath, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SetCallback")]
public static extern bool SetCallback(byte functype, Delegate func);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackDelegate(UInt32 handle);
private static CallbackDelegate OnDataSendingDone;
public void OnDataSendingDoneCallback(CallbackDelegate callback)
{
OnDataSendingDone_ft = new CallbackDelegate2(callback);
SetCallback(FT_DATASENDINGDONE, OnDataSendingDone_ft);
}
}
class Transmitter
{
LibWrapper lib = new LibWrapper();
byte[] data = new byte[10];
public void OnDataSendingDone(UInt32 handle)
{
return;
}
lib.OnDataSendingDoneCallback(OnDataSendingDone);
public void TransmitData()
{
// here: sequential data transmission
foreach (byte b in data)
{
lib.SendByte(b);
// here: wait for OnDataSendingDone
}
}
}
If I understand correctly, you could do something like this:
class Transmitter
{
LibWrapper lib = new LibWrapper();
private AutoResetEvent evt = new AutoResetEvent(false);
byte[] data;
public void OnDataSendingDone(UInt32 handle)
{
evt.Set();
}
public void TransmitData()
{
// here: sequential data transmission
foreach (byte b in data)
{
lib.SendByte(b);
if (!evt.WaitOne(15000)) // or whatever timeout makes sense
throw new Exception("timed out");
}
}
}

How to override a C++ virtual method (not in an interface class) in C# via C++/CLI

For reference, this question deals with accessing the C++ NaturalPoint Camera SDK via C#.
I am trying to pass along the implementation of a virtual method from C++ to C#. The trouble I am having is that the C++ virtual method is not in an interface class and I am not able to change that. Here is the class declaration:
class CLAPI cCameraListener
{
public:
cCameraListener() {};
~cCameraListener() {};
virtual void FrameAvailable();
virtual void FrameOverflow();
virtual void ButtonPressed();
};
The CLAPI is defined as:
#define CLAPI __declspec(dllexport)
I can't inherit from the cCameraListener class in a ref class since it isn't an interface class and haven't come up with any way to expose the virtual methods to a managed class. I also need to be able to register the listener which I talk about more below.
Here is the working C++ implementation for listening for frames:
// process frames as they arrive
class FrameListener: public cCameraListener
{
public:
Camera *myCamera;
FrameListener(Camera *cameraPtr)
{
myCamera = cameraPtr;
};
void FrameAvailable()
{
Frame *thisFrame = myCamera->GetFrame();
// do something with the frame here
thisFrame->Release();
};
};
int _tmain(int argc, _TCHAR* argv[])
{
// startup camera
CameraManager::X().WaitForInitialization();
Camera *camera = CameraManager::X().GetCamera();
if(camera==0)
{
// print an error
return 1;
}
// set camera properties
camera->SendEmptyFrames(false);
camera->SendInvalidFrames(false);
camera->SetVideoType(SegmentMode);
// setup frame listener
FrameListener *myListener = new FrameListener(camera);
camera->AttachListener(myListener);
// start the camera
camera->Start();
// while loop holding thread
// clean up
camera->Release();
CameraManager::X().Shutdown();
return 0;
}
Here is some of the existing C++/CLI wrapper code:
Link: https://code.google.com/p/npcamerasdkdotnet/
public ref class MCamera{
public:
MCamera(Camera * camera){
this->camera = camera;
}
~MCamera(){
delete this->camera;
}
void Start(){camera->Start();}
void SetExposure(int Value){camera->SetExposure(Value);}
void SetThreshold(int Value){camera->SetThreshold(Value);}
void SetIntensity(int Value){camera->SetIntensity(Value);}
// TODO - WRAP THESE METHODS
//void AttachListener(cCameraListener * Listener);
//void RemoveListener(cCameraListener * Listener);
// other wrapped methods here...
private:
Camera * camera;
};
Notice that within the MCamera wrapper class, the AttachListener method needs to be implemented and requires a pointer to the cCameraListener class talked about above.
Any suggestions would be appreciated! Thanks!
The solution is not so hard you need to wrap the listener in the manage class something like that:
class CameraListenerImp;
/**
* Managed Version of the listener which will be used by managed clients
*/
public ref class ManagedCameraListener abstract
{
public:
ManagedCameraListener();
virtual void FrameAvailable() abstract;
virtual void FrameOverflow() abstract;
virtual void ButtonPressed() abstract;
~ManagedCameraListener();
CameraListenerImp* GetUnManagedListener()
{
return _unmanagedListener;
}
private:
CameraListenerImp* _unmanagedListener;
};
// Unmanaged to managed listener wraper
class CameraListenerImp : public cCameraListener
{
public:
CameraListenerImp( ManagedCameraListener^ in )
{
theClass = in;
}
virtual void FrameAvailable()
{
theClass->FrameAvailable();
}
virtual void FrameOverflow()
{
theClass->FrameOverflow();
}
virtual void ButtonPressed()
{
theClass->ButtonPressed();
}
private:
gcroot < ManagedCameraListener^ > theClass;
};
///////////////////////////////////////////////////////////
// ManagedCameraListener imp
ManagedCameraListener::ManagedCameraListener()
{
_unmanagedListener = new CameraListenerImp( this );
}
ManagedCameraListener::~ManagedCameraListener()
{
delete _unmanagedListener;
}
///////////////////////////////////////////////////////////
// ManagedCameraListener imp end
public ref class MCamera
{
public:
MCamera(Camera * camera)
{
this->camera = camera;
}
~MCamera()
{
delete this->camera;
}
void AttachListener( ManagedCameraListener^ listener )
{
// call unmanaged version of the AttachListener
this->camera->AttachListener( listener->GetUnManagedListener() );
}
void RemoveListener( ManagedCameraListener^ listener )
{
// call unmanaged version of the RemoveListener
this->camera->RemoveListener( listener->GetUnManagedListener() );
}
private:
Camera * camera;
};
/**
* Managed implementation
*/
public ref class MyOwnManagedCameraListener : public ManagedCameraListener
{
public:
virtual void FrameAvailable() override { / do something hard / }
virtual void FrameOverflow() override { / do something hard / }
virtual void ButtonPressed() override { / do something hard */ }
};
int main(array ^args)
{
MCamera^ cam = gcnew MCamera( camera );
MyOwnManagedCameraListener^ listener = gcnew MyOwnManagedCameraListener();
cam->AttachListener( listener );
cam->RemoveListener( listener );
return 0;
}

Categories

Resources