MesaC
asked on
Wrapping a managed C# DLL in a unmanaged C++ project
Hi,
I am trying to wrap a managed C# DLL so I can call the DLL in an unmanaged C++ project. I am using the approach of <gcroot> so I can use a global instance in the unmanaged project. Everything is working fine except when I’m trying to wrap the Events. I am receiving a C3364 error, “invalid argument for delegate constructor; delegate target needs to be a pointer to a member function”. I’m not sure what it’s asking for here. I would like to trap the event in the C++ class so I can respond accordingly in the unmanaged project. Below are code snippits from each class I'm using.
//Managed C# DLL - contains delegate/events I want to call
public class TestingDelegates
{
public class ConnectionStartThreadArgs : EventArgs…
public delegate void ManagedEvent(int arg);
public event ManagedEvent SomeEvent;
protected virtual void OnStartThreads(object sender, ConnectionStartThreadArgs e)
{
if (MethodDelegate != null)
{
MethodDelegate(this, e);
}
}
}
//This is the class that is called in the unmanaged code, and is the base class to the CommunicationWrapper that wraps the C# DLL.
//interface…
public class ICommunicationWrapper
{
public:
//virtual void StartCommunication() = 0;
virtual void SetIPAddress( CString ip ) = 0;
virtual CString GetIPAddress() = 0;
//functions to create the unmanaged instance
static ICommunicationWrapper *CreateInstance();
static void Destroy(ICommunicationWrap per *instance);
};
//C++ Class .h
//Wrapper class
public class CommunicationWrapper : ICommunicationWrapper
{
public:
gcroot<TestingDelegates ^> _managedObject;
void OnManagedDelegate(System:: Object ^ sender, ManagedLibrary::TestingDel egates::Co nnectionSt artThreadA rgs^ e );
public:
CommunicationWrapper() { _managedObject = gcnew TestingDelegates(); }
};
//.cpp
void CommunicationWrapper::Setu pDelegate( )
{
//this line causes a C3364
_managedObject->MethodDele gate += gcnew ManagedLibrary::TestingDel egates::my MethodDele gate( this, &CommunicationWrapper::OnM anagedDele gate );
}
ICommunicationWrapper *ICommunicationWrapper::Cr eateInstan ce()
{
return ((ICommunicationWrapper *)new CommunicationWrapper());
}
void ICommunicationWrapper::Des troy(IComm unicationW rapper *instance)
{
delete instance;
}
void CommunicationWrapper::OnMa nagedDeleg ate(System ::Object ^ sender, ManagedLibrary::TestingDel egates::Co nnectionSt artThreadA rgs^ e )
{
}
Any ideas???
Thanks
I am trying to wrap a managed C# DLL so I can call the DLL in an unmanaged C++ project. I am using the approach of <gcroot> so I can use a global instance in the unmanaged project. Everything is working fine except when I’m trying to wrap the Events. I am receiving a C3364 error, “invalid argument for delegate constructor; delegate target needs to be a pointer to a member function”. I’m not sure what it’s asking for here. I would like to trap the event in the C++ class so I can respond accordingly in the unmanaged project. Below are code snippits from each class I'm using.
//Managed C# DLL - contains delegate/events I want to call
public class TestingDelegates
{
public class ConnectionStartThreadArgs : EventArgs…
public delegate void ManagedEvent(int arg);
public event ManagedEvent SomeEvent;
protected virtual void OnStartThreads(object sender, ConnectionStartThreadArgs e)
{
if (MethodDelegate != null)
{
MethodDelegate(this, e);
}
}
}
//This is the class that is called in the unmanaged code, and is the base class to the CommunicationWrapper that wraps the C# DLL.
//interface…
public class ICommunicationWrapper
{
public:
//virtual void StartCommunication() = 0;
virtual void SetIPAddress( CString ip ) = 0;
virtual CString GetIPAddress() = 0;
//functions to create the unmanaged instance
static ICommunicationWrapper *CreateInstance();
static void Destroy(ICommunicationWrap
};
//C++ Class .h
//Wrapper class
public class CommunicationWrapper : ICommunicationWrapper
{
public:
gcroot<TestingDelegates ^> _managedObject;
void OnManagedDelegate(System::
public:
CommunicationWrapper() { _managedObject = gcnew TestingDelegates(); }
};
//.cpp
void CommunicationWrapper::Setu
{
//this line causes a C3364
_managedObject->MethodDele
}
ICommunicationWrapper *ICommunicationWrapper::Cr
{
return ((ICommunicationWrapper *)new CommunicationWrapper());
}
void ICommunicationWrapper::Des
{
delete instance;
}
void CommunicationWrapper::OnMa
{
}
Any ideas???
Thanks
ASKER
I tried to put this into place and ran into a problem. When changing the CommunicationWrapper class to be managed with ref class CommunicationWrapper caused the ICommunicationWrapper to need to be managed, which then caused all kinds of problems. Can you post those additional details?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I finally got your example to work. Thanks for your help
If you need to do this in native class, create instance of managed class, and subscribe to event in it. Then create instance of this proxy ref class inside of unmanaged class, and use C++ callback to get event notification.
typedef void (CommunicationWrapper ::*fPtr)(System::Object ^ sender, ManagedLibrary::TestingDel
ref class ProxyClass
{
TestingDelegates ^ _managedObject;
fptr callback;
CommunicationWrapper* wrapper;
// subscribe to event here
// in event handler call callback function:
(wrapper.*callback)( parameters );
};
public class CommunicationWrapper : ICommunicationWrapper
{
gcroot<ProxyClass> proxy;
void OnMangedDelegate(...)
...
proxy = gcnew ProxyClass();
proxy->callback = OnManagedDelegate;
proxy->wrapper = this;
}
Code is not tested, only general idea. If you have problem implementing this, I will post more details.