Robert Kirnum
Robert Kirnum

Reputation: 11

How to pass an object pointer from and to a DLL?

I am a seasoned software engineer but somewhat new to C#. I have a DLL which is made up of C++ objects with a C interface as shown. I used this C interface because I was not sure if there was a way of accessing C++ entry points in the DLL from my C# application.

   __declspec(dllexport) void *Constructor();
   __declspec(dllexport) void Destructor(void *pObj);
   __declspec(dllexport) int Method(void *pObj, char *pSrcDst, int len);

This is the C code for the above interface.

extern "C" void *Constructor()
{
   return (void *)new Object;
}
extern "C" void Destructor(void *pObj)
{
   delete (Object *)pObj;
}
extern "C" int Method(void *pObj, char *pSrcDst, int len)
{
   if (!pObj) return 0;
   return ((Object *)pObj)->Method(pSrcDst, len);
}

So far so good. Now, I need to be able to access this interface from a C# application. From what I have learned I have implemented the following C# interface.

   unsafe public class Wrapper
   {
      [SuppressUnmanagedCodeSecurityAttribute()]
      [DllImport("MyDLL.dll")]
      public static extern
         IntPtr Constructor();
      [SuppressUnmanagedCodeSecurityAttribute()]
      [DllImport("MyDLL.dll")]
      public static extern
         void Destructor(IntPtr pObj);
      [SuppressUnmanagedCodeSecurityAttribute()]
      [DllImport("MyDLL.dll")]
      public static extern
         int Method(IntPtr pObj, [In,Out] byte[] pSrcDst, int len);

And here's the C# code which uses the above interface.

  private IntPtr pObject;
  public object()
  {
     pObject = Wrapper.Constructor();
  }
  ~object()
  {
     Wrapper.Destructor(pObject);
  }
  public override byte[] method()
  {
     byte[] bytes = new byte[100];
     int converted = Wrapper.Method(pObject, bytes, bytes.length);
     return bytes;
  }

The code asserts at both the call to Wrapper.Method as well as the Wrapper.Destructor. I assume I am not handling the pointer to the object properly. Any suggestions?

Upvotes: 1

Views: 3148

Answers (2)

svick
svick

Reputation: 244757

The most likely problem is that your code doesn't use the correct calling convention. In C++ the default is __cdecl, but for DllImport, the default is __stdcall.

To fix this, specify the calling convention explicitly:

[DllImport("MyDLL.dll", CallingConvention = CallingConvention.Cdecl)]

Upvotes: 3

Andrei
Andrei

Reputation: 5005

I was under the impression that the best way to do this sort of thing was using a managed c++/CLI wrapper.

Creating simple c++.net wrapper. Step-by-step

and

http://devmaster.net/forums/topic/7357-how-to-build-a-net-wrapper-for-a-c-library/

look like promising leads.

Upvotes: 1

Related Questions