我在创建 dll 包装器时偶然发现的几点:
- 我不得不调用非托管类的成员函数。花了一些时间发现我不能直接使用 DllImport 来做到这一点,而必须自己编写一个“包装器”。
- 在包装器本身中,仅包装成员函数也是不够的。我必须能够创建指向 C++ 类的指针,所以我必须将指针导出到构造函数(至少,我是这么理解的,也许这并不完全正确。)。我最初尝试只导出成员函数,它编译但在运行时返回“AccessViolationException”。也卡在那里一段时间。
因此,我的包装器看起来像这样(如using a class defined in a c++ dll in c# code 中所建议的那样):
public class __declspec(dllexport) Wrapper
{
public:
CcnOCRsdk* SDKCreate()
{
return new CcnOCRsdk();
}
bool CcnOCRsdk_HKID(CcnOCRsdk* pSDK, char *code, RECO_DATA *o_data)
{
return pSDK->convertHKID_Name(code, o_data);
}
void SDKDelete(CcnOCRsdk* pSDK)
{
delete pSDK;
}
};
__declspec(dllexport) 在类级别导出类的所有公共成员。
SDKCreate() 从我必须调用的成员函数的非托管 dll 返回指向该 CcnOCRsdk 类的指针。
CcnOCRsdk_HKID 调用该成员函数。请注意,传递了指向 CcnOCRsdk 的指针。
代码构建到 dll 中后,我必须使用 DUMPBIN 来找出我编写的包装 dll 的“损坏”入口点。
对于我的包装器,结果如下所示
1 0 00001240 ??4Wrapper@TSSL@@QAEAAV01@ABV01@@Z = __t2m@??4Wrapper@TSSL@@QAEAAV01@ABV01@@Z ([T2M] public: class TSSL::Wrapper & __thiscall TSSL::Wrapper::operator=(class TSSL::Wrapper const &))
2 1 00001220 ?CcnOCRsdk_HKID@Wrapper@TSSL@@QAE_NPAVCcnOCRsdk@@PADPAURECO_DATA@@@Z = __t2m@?CcnOCRsdk_HKID@Wrapper@TSSL@@QAE_NPAVCcnOCRsdk@@PADPAURECO_DATA@@@Z ([T2M] public: bool __thiscall TSSL::Wrapper::CcnOCRsdk_HKID(class CcnOCRsdk *,char *,struct RECO_DATA *))
3 2 00001200 ?SDKCreate@Wrapper@TSSL@@QAEPAVCcnOCRsdk@@XZ = ?SDKCreate@Wrapper@TSSL@@QAEPAVCcnOCRsdk@@XZ (public: class CcnOCRsdk * __thiscall TSSL::Wrapper::SDKCreate(void))
4 3 00001410 ?SDKDelete@Wrapper@TSSL@@QAEXPAVCcnOCRsdk@@@Z = ?SDKDelete@Wrapper@TSSL@@QAEXPAVCcnOCRsdk@@@Z (public: void __thiscall TSSL::Wrapper::SDKDelete(class CcnOCRsdk *))
现在我终于准备好在 C# 中使用我的包装器了。当我在没有完全按照 dumpbin 的输出指定入口点的情况下执行此操作时,出现“无法找到入口点”错误。
[DllImport(@"TSSLWrapper.dll", EntryPoint = "?SDKCreate@Wrapper@TSSL@@QAEPAVCcnOCRsdk@@XZ")]
public static extern IntPtr SDKCreate();
[DllImport(@"TSSLWrapper.dll", EntryPoint = "?CcnOCRsdk_HKID@Wrapper@TSSL@@QAE_NPAVCcnOCRsdk@@PADPAURECO_DATA@@@Z")]
public static extern bool CcnOCRsdk_HKID(IntPtr ptr, string num, out RECO_DATA o_data);
RECO_DATA 被定义为 JaredPar 建议的。
最后一步是享受结果。
首先我必须调用类构造函数,然后将指针传递给函数的实际调用
RECO_DATA recoData = new cnOCRsdk.RECO_DATA();
string num = "262125355174";
IntPtr ptr = cnOCRsdk.SDKCreate();
bool res = cnOCRsdk.CcnOCRsdk_HKID(ptr, num, out recoData);
我的 res 返回 true,我在 recoData 中得到了我期望的结果。