我目前正在尝试为使用非托管 C DLL 进行接口的 USB 相机编写包装器。提供的软件是使用 Qt 用 C++ 编写的,我正在尝试将此相机集成到我已经编写的 C# 应用程序中(该应用程序已经使用了一个带有 C# 接口的不同相机)。我读过一堆关于非托管/托管接口的文章,但我仍然被这个特定的 DLL 所困扰。
我在处理 P/Invoking DLL 时遇到了麻烦。我已经阅读了大量关于处理托管/非托管代码的方法,似乎因为我只有函数/参数(没有别的),我无法编写 C++/CLI 包装器并被迫坚持 P/Invoke。如果这是不正确的,如果更有效的话,将不胜感激对替代方法的一些帮助。
无论如何,我目前无法调用一些(阅读:全部)函数。例如,让我们选择这个函数(取自 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
是和上面一样的 uint
然后pNumGuids
作为ref uint
. 我不提交参数,mask
因为它是可选的,我不需要使用它。
由于托管导入的签名和非托管 DLL 的签名不匹配,我经常得到一个PInvokeStackImbalance
,但我无法弄清楚正确的签名是什么。
我对我正在处理的所有功能都有疑问,但我会一次处理一个。我使用的第一个函数是一个“init”函数,它接受一个函数指针参数和一个用于回调的 void 指针参数及其关联数据,但如果我不需要使用回调,我可以不带参数调用它那就是 P/Invoking 就好了。这个问题中的函数是我需要调用的函数以获取附加设备的列表。我想如果我能让这个工作正常,我就能弄清楚其余的大部分功能。
我正在使用的 SDK 和文档并未从提供它的公司在线公开获得。如果有人希望它查看所有代码/文档,我可以将其发布在文件服务器上并发布指向它的链接。
任何帮助将非常感激!如果有什么我遗漏的,请务必质问我=P
解决方案: 在帮助之后,我设法让它工作:
DLL导入:
[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);
}