Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to PInvoke C++ DLL Function from C#

I am trying to access a Microscope from within my C# application. The SDK is written in C++ and I can not add the Dlls as references in my application (due to them being unmanaged code). As a result I found out that I will need to use DllImport in order to use the functions with C#.

Unfortunately this seems to be way over my head.

As an example some of the C++ code (from a sample app included in the SDK):

interface Camera;
typedef Camera * CameraHandle;

struct CameraInfo
{
  wchar_t               camera_name[64];        // camera head type
  wchar_t               controller_name[64];    // controller type
  wchar_t               firmware_version[64];   // firmware version
  long                  lib_id;                 // library ID
  long                  controller_id;          // controller ID
  long                  camera_id;              // camera ID
  CameraHandle          handle;                 // handle to opened camera
  long                  status;                 // status (0 = available)
  CameraInfo()
  {
    memset(this,0,sizeof(*this));
  }
};
typedef struct CameraInfo CameraInfo;

CamDiscoverCameras(OUT const struct CameraInfo ** info, OUT long * count);

And this is how it is used later on:

CamResult               result;          //enum CamResult{...}
const CameraInfo*       camera_info  = NULL;
long                    camera_count = 0, pre_lib_id, pre_controller_id;

result = CamDiscoverCameras(&camera_info, &camera_count);

How do I convert this to C# code? I have already tried something like:

    [StructLayout(LayoutKind.Sequential)]
    struct CameraInfo
    {
        string              camera_name;            // camera head type
        string              controller_name;        // controller type
        string              firmware_version;       // firmware version
        int                 lib_id;                 // library ID
        int                 controller_id;          // controller ID
        int                 camera_id;              // camera ID
        public IntPtr       handle;                 // handle to opened camera
        int                 status;                 // status (0 = available)
    }

    [DllImport("Cam.dll", EntryPoint = "CamDiscoverCameras")]

But basically I have no idea of what I am doing and what needs to be done next (like how the function needs to be defined, how to deal with that "interface" in the C++ code, is the structure converted correctly and so on).

like image 658
Daniel M Avatar asked Oct 09 '14 11:10

Daniel M


2 Answers

First of all, to convert those wchar_t arrays to .NET string you will need to set additional attributes.

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct CameraInfo
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
    string camera_name;            // camera head type
...

Next, the method CamDiscoverCameras returns a pointer to the struct, so in .NET you will be actually receiving an IntPtr and then converting that pointer to a struct using Marshal.PtrToStructure method:

[DllImport("Cam.dll", EntryPoint = "CamDiscoverCameras")]
// you can create enum of ints here and return it
static extern int CamDiscoverCameras(out IntPtr info, out int count);

CameraInfo DiscoverCameraInfos()
{
    IntPtr info; int count;
    int camResult = CamDiscoverCameras(out info, out count);
    var camInfo = (CameraInfo) Marshal.PtrToStructure(info, typeof(CameraInfo));
    // cleanup code - pass your IntPtr to C++ code
    // for it to delete the struct as it seems it was allocated there
    return camInfo;
}

And don't forget to cleanup - from your code it seems that the structure is being allocated somewhere in C++ code, so you likely would have to pass the IntPtr back to C++ code for it to deallocate it.

like image 185
Alovchin Avatar answered Nov 11 '22 06:11

Alovchin


Your struct definition in C# is a bit more complex then yours. Have a look at the PInvoke Interop Assistant. https://clrinterop.codeplex.com/releases/view/14120 It helps a lot with the initial attributes.

like image 35
Michael Steinecke Avatar answered Nov 11 '22 06:11

Michael Steinecke