编组字符串,C#中的指针(用P / Invoke在C#中编写C DLL的包装器)

时间:2013-01-09 17:42:39

标签: c# arrays string pinvoke marshalling

我正在尝试为使用非托管C DLL接口的USB相机编写包装器。提供的软件是使用Qt用C ++编写的,我试图将这个摄像头集成到我已编写的C#应用​​程序中(该应用程序已经使用了随C#接口提供的不同摄像头)。我已经阅读了一些关于非托管/托管接口的内容,但我仍然遇到了这个特定的DLL。

我在处理P /调用DLL时遇到问题。我已经完成了一些关于处理托管/非托管代码的方法的阅读,似乎因为我只有函数/参数(没有别的),我不能写一个C ++ / CLI包装器而且我被迫坚持P / Invoke。如果这是不真实的话,如果更有效,可以理解一些替代方法的帮助。

无论如何,我现在无法调用一些(read:all)函数。例如,让我们选择这个函数(取自dijSDK.h,在Qt中使用非托管C ++时使用此接口时使用的头文件):

/** \brief Find cameras currently connected to the host
  *
  * \param[out]      pGuidList   List of unique identifiers of connected cameras; memory is allocated by user
  * \param[in,out]   pNumGuids   Pointer to the number of elements in pGuidList to limit the search
  * \n                           Pointer to the number of cameras found
  * \param[in]       mask        optional mask to limit the results in pGuidList
  *
  * \note
  * -    the function lists all supported cameras that are connected to the host having a driver installed
  * -    the cameras are identified by a string in a defined style:
  * \n  <i>[Name of the camera library resp. camera class]:[camera name]:[Serial number of the camera]</i>
  * -    the optional parameter mask may be used to limit the results returned in pGuidList; 
  * \n   mask is in the same style as the results in pGuidList 
  *      therefore the results can be limited to certain camera classes, camera types,
  *      and cameras with a given serial number */

DIJSDK_EXPORT error_t DijSDK_FindCameras(DijSDK_CamGuid* pGuidList, unsigned int* pNumGuids, const DijSDK_CamGuid mask = NULL);

DIJSDK_EXPORT定义如下:

#ifndef DIJSDK_EXPORT
 #define DIJSDK_EXPORT externC DLLEXPORT
#endif

以上函数中使用的两个typedef:

/// Return value of all DijSDK functions
/// \note All return values of type error_t can be casted to the enum <b>DijSDK_EErrorCodeList</b>, see header errorlistinstall.h
typedef int error_t;

// unique DijSDK types
/// Globally unique identifier for all supported cameras. It is used to establish a relation between <b>physical</b> and <b>logical</b> cameras.
typedef char   DijSDK_CamGuid[64];

因此,在查看函数时,用户传入一个已分配的字符串数组和该数组中已分配字符串的数量,该函数应返回一串字符串及其返回的字符串数。我完全不知道如何在C#中实现它。我已经尝试了函数的不同DllImport声明,比如将pGuidList作为...传递

  • StringBuilder

我传入的变量用var = new StringBuilder(64)初始化,传入的uint只有1。

  • StringBuilder[]

我传入的变量用var = new StringBuilder[length]初始化,其中length是传递给函数的uint

  • IntPtr 我传入的变量用Marshal.AllocCoTaskMem(64 * length * Marshal.SystemDefaultCharSize)初始化,其中length与上面相同

然后以pNumGuids传递ref uint。我没有提交mask的论据,因为它是可选的,我不需要使用它。

由于托管导入的签名和非托管DLL不匹配,我经常得到PInvokeStackImbalance,但我无法弄清楚正确的签名是什么。

我对我正在处理的所有功能都有疑问,但我会一次一个地处理它们。我使用的第一个函数是一个“init”函数,它接受一个函数指针参数和一个回调的void指针参数以及它的相关数据,但如果我不需要使用回调,我可以不带参数调用它这是P /调用就好了。此问题中的功能是我需要调用以获取连接设备列表的功能。我想如果我能让这个工作起作用,我将能够找出其余大部分功能。

我正在使用的SDK和文档不是从提供它的公司在线公开获得的。如果有人希望它能看到所有的代码/文档,我可以将它发布在文件服务器上并发布链接。

任何帮助将不胜感激!如果我遗漏了任何东西,请务必向我推荐它= P

解决方案: 在帮助之后,我设法让它运转起来:

DllImport:

[DllImport(DLL,CallingConvention=CallingConvention.Cdecl)]
        public static extern error_t DijSDK_FindCameras([Out] DijSDK_CamGuid[] pCamGuid, ref uint pNumGuids, string mask);

用于DijSDK_CamGuid的结构:

[StructLayout(LayoutKind.Sequential,Size=64)]
public struct DijSDK_CamGuid
{
    [MarshalAs(UnmanagedType.ByValArray,SizeConst=64)]
    public char[] id;
}

findCameras()函数:

private void findCameras()
{
     uint cameralistlen = 5;
     DijSDK_CamGuid[] cameralist = new DijSDK_CamGuid[cameralistlen];
     result = Jenoptik.DijSDK_FindCameras(cameralist, ref cameralistlen, null);
}

2 个答案:

答案 0 :(得分:1)

您是否需要将托管代码中的ID作为字符串处理?如果没有,也许这样的东西可以工作,将字节视为不透明的字节数组:

[StructLayout(LayoutKind.Sequential)]
public struct DijSDK_CamGuid
{
  [MarshalAs(UnmanagedType.ByValAray,SizeConst=64)]
  public byte[] id;
}

然后声明你的p / invoke签名使用带有类型的参数:

DijSDK_CamGuid* 

答案 1 :(得分:1)

尝试以这种方式声明:

    [DllImport("whatever.dll", CallingConvention = CallingConvention.Cdecl)]
    extern public static int DijSDK_FindCameras(byte[] pGuidList, ref int pNumGuids, byte[] mask);

并像这样使用它:

    byte[] CamGuids = new byte[64 * 32];    // Up to 32 cameras
    int GuidsCount = CamGuids.Length / 64;
    int result = DijSDK_FindCameras(CamGuids, ref GuidsCount, null);