如何从C#PInvoke C ++ DLL函数

时间:2014-10-09 11:17:33

标签: c# pinvoke dllimport

我正在尝试从我的C#应用​​程序中访问显微镜。 SDK是用C ++编写的,我不能在我的应用程序中添加Dlls作为引用(因为它们是非托管代码)。 结果我发现我需要使用DllImport才能在C#中使用这些函数。

不幸的是,这似乎超出了我的想法。

作为示例,一些C ++代码(来自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);

这就是以后的使用方式:

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);

如何将其转换为C#代码?我已经尝试过类似的东西:

    [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")]

但基本上我不知道我在做什么以及接下来需要做什么(比如如何定义函数,如何处理C ++代码中的“接口”)是正确转换的结构等等。)

2 个答案:

答案 0 :(得分:2)

您在C#中的结构定义比您的结构要复杂一些。 看看PInvoke Interop助手。 https://clrinterop.codeplex.com/releases/view/14120 它对初始属性有很大帮助。

答案 1 :(得分:2)

首先,要将这些wchar_t数组转换为.NET string,您需要设置additional attributes

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

接下来,方法CamDiscoverCameras返回一个指向struct 的指针,因此在.NET中,您实际上将接收IntPtr,然后使用该指针转换为结构Marshal.PtrToStructure方法:

[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;
}

并且不要忘记清理 - 从您的代码中看来,结构似乎是在C ++代码中的某处分配的,因此您可能必须将IntPtr传递回C ++代码才能解除分配。