Пара моментов, на которые я наткнулся при создании оболочки dll:
- Мне пришлось вызвать функцию-член неуправляемого класса. Потребовалось некоторое время, чтобы выяснить, что я не могу сделать это, используя DllImport напрямую, но должен написать «обертку» сам.
- В самой оболочке также недостаточно просто обернуть функцию-член. Я должен быть в состоянии создать указатель на класс C ++, поэтому я должен экспортировать указатель в конструктор (по крайней мере, я так понимаю, может быть, это не совсем правильно). Сначала я попытался просто экспортировать функцию-член, она скомпилировалась, но вернула «AccessViolationException» во время выполнения. Застрял там тоже на некоторое время.
Следовательно, моя оболочка выглядит следующим образом (как предложено в с использованием класса, определенного в c ++ dll в коде c # ):
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 () возвращает указатель на этот класс CcnOCRsdk из неуправляемой библиотеки DLL, функцию-член которой я должен вызвать.
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 #. Когда я сделал это, не указав точку входа точно так же, как в выводе из дампа, я получил ошибку «невозможно найти точку входа».
[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.