Wednesday, August 17, 2011

Calling methods of unmanged (C++) DLL from Managed environment

Requirement in detail:
C++ DLL
unmanged C++ DLL and can be modified (source code available)
Some methods of a C++ class is exposed.

Managed environment;
C# application

Issue in detail:
we have known how to expose c functions but no clear picture about c++ functions.
No idea how to keep c++ class instance in c#(manged) environment.

Solution in detail:
In unmanged C++ DLL, introduced new set of C functions and exposed them.
We are dealing with c++ class , through this tunnel.

In C# application, introduced similar kind of class (with functions)
stored c++ class instance in IntPtr member.

code snippets: c++ dll
C++ class (TestClass)

#define UNMANAGEDDLL_API __declspec(dllexport)
class UNMANAGEDDLL_API TestClass
{
public:
TestClass(void);
~TestClass(void);
void PassInt(int value);
};

new interface of C functions

testClassCaller.h

#pragma once
#include "TestClass.h"

extern "C" UNMANAGEDDLL_API TestClass* CreateTestClass();
extern "C" UNMANAGEDDLL_API void DisposeTestClass(TestClass* pObject);
extern "C" UNMANAGEDDLL_API void CallPassInt(TestClass* pObject, int nValue);

testClassCaller.cpp

#include "TestClassCaller.h"

extern "C" UNMANAGEDDLL_API TestClass* CreateTestClass()
{
return new TestClass();
}

extern "C" UNMANAGEDDLL_API void DisposeTestClass(TestClass* pObject)
{
if (pObject != NULL)
{
delete pObject;
pObject = NULL;
}
}
extern "C" UNMANAGEDDLL_API void CallPassInt(TestClass* pObject, int nValue)
{

if (pObject != NULL)
{
pObject->PassInt(nValue);
}
}

Managed enviornment

C# wrapper class
class CSUnmanagedTestClass : IDisposable
{
#region PInvokes
[DllImport("test4.dll")] //test4.dll is unmanged DLL
static private extern IntPtr CreateTestClass();
[DllImport("test4.dll")]
static private extern void DisposeTestClass(IntPtr pTestClassObject);
[DllImport("test4.dll")]
static private extern void CallPassInt(IntPtr pTestClassObject,int nValue);
#endregion PInvokes

#region Members
private IntPtr m_pNativeObject;
#endregion Members

public CSUnmanagedTestClass()
{
this.m_pNativeObject = CreateTestClass();
}

#region IDisposable Members

public void Dispose()
{
//throw new NotImplementedException();
Dispose(true);
}
#endregion
protected virtual void Dispose(bool bDisposing)
{
if (this.m_pNativeObject != IntPtr.Zero)
{
DisposeTestClass(this.m_pNativeObject);
}
if (bDisposing)
{
GC.SuppressFinalize(this);
}
}
~CSUnmanagedTestClass()
{
Dispose(false);

}

#region Wrapper methods
public void PassInt(int nValue)
{
CallPassInt(this.m_pNativeObject, nValue);
}
#endregion Wrapper methods

}
C# main method:
static void Main(string[] args)
{
CSUnmanagedTestClass testclass = new CSUnmanagedTestClass();
testclass.PassInt(34);
testclass.Dispose();
}

More Detail:

http://www.codeproject.com/KB/cs/marshalCPPclass.aspx