我正在尝试为使用非托管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);
}
答案 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);