Как правильно вызвать C ++ DLL из C #, используя правильные типы параметров

Мне предоставили библиотеку DLL, которая должна вызываться C # et al. DLL содержит два метода следующим образом

extern "C" {
__declspec(dllexport) BSTR GroupInit(LPCTSTR bstrIniFile, bool bDiagErr, bool bProcErr);
__declspec(dllexport) void G();
}

class GrouperServer {
public:
BSTR GroupInit(LPCTSTR bstrIniFile, bool bDiagErr, bool bProcErr);
void G();
}

BSTR GrouperServer::GroupInit(LPCTSTR bstrIniFile, bool bDiagErr, bool bProcErr) {
CString strResult = "";
char* sz;
SetVars(bDiagErr, bProcErr);

if (sz = ::GroupInit((char*)bstrIniFile, 1))
strResult = sz;
return strResult.AllocSysString();
}

void G() {
MessageBox(0, "And text here", "MessageBox caption", MB_OK);
}

Я пытаюсь вызвать эти библиотеки DLL из C #, сначала определив класс:

public class GrouperServer {
[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void G();

[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern string GroupInit(
string strCmdFile, bool bAllowBadDiagCodes, bool bAllowBadProcCodes);
}

и делать

this.strCommandFilePath = "C:\\MyDir\\MyCommandFile.txt";
Grouper.GrouperServer.G();
Grouper.GrouperServer.GroupInit(this.strCommandFilePath, true, true);

Вызов метода G() работает, и я получаю окно сообщения, но для вызова GroupInit(), Я получил

Необработанное исключение типа «System.EntryPointNotFoundException» произошло в DrGroupIN.exe. Дополнительная информация: Невозможно найти точку входа с именем «GroupInit» в DLL «GrouperServer.dll».

Как я могу вызвать второй метод GrouInit(...) с правильными параметрами в этом случае?


Редактировать 1.

Я также пытался

[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GroupInit(
string strCmdFile, bool bAllowBadDiagCodes, bool bAllowBadProcCodes);

где это называется через:

IntPtr ptr = Grouper.GrouperServer.GroupInit(this.strCommandFilePath, true, true);
string strString = Marshal.PtrToStringBSTR(ptr);
Marshal.FreeBSTR(ptr);

Но это тоже выдает ошибку выше.

Изменить 2.

Я также пытался

[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl, CharSet=CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern string GroupInit(
[MarshalAs(UnmanagedType.LPTStr)]string strCmdFile,
bool bAllowBadDiagCodes,
bool bAllowBadProcCodes);

Но это тоже выдает ошибку выше.

1

Решение

Мне кажется, что вы не можете вызвать эту DLL с помощью C #. DLL экспортирует функции-члены класса. И вы не можете создать экземпляр этого класса.

Я вижу следующие варианты:

  1. Попросите поставщика DLL экспортировать либо статические функции-члены, либо функции, не являющиеся членами. Затем они должны быть доступны с помощью p / invoke.
  2. Напишите обертку C ++ / CLI в смешанном режиме вокруг DLL. Эта оболочка может легко потреблять неуправляемую DLL. В свою очередь, он может затем предоставить управляемый класс ref, который оборачивает функциональность. Оболочка C ++ / CLI может быть добавлена ​​в качестве ссылки на проект C #.

Тем не менее, эти декларации, кажется, находятся в конфликте:

extern "C" {
__declspec(dllexport) BSTR GroupInit(LPCTSTR bstrIniFile, bool bDiagErr, bool bProcErr);
__declspec(dllexport) void G();
}

class GrouperServer {
public:
BSTR GroupInit(LPCTSTR bstrIniFile, bool bDiagErr, bool bProcErr);
void G();
}

Кажется, что первая пара объявлений не является функциями-членами. Но за ними следует класс с функциями-членами с одинаковыми именами. Вам необходимо четко определить, какие функции вы пытаетесь вызвать.

Возможно, DLL уже содержит функции, не являющиеся членами, которые оборачивают функции-члены. В этом случае вам просто нужно узнать имена, по которым они экспортируются. Используйте Dependency Walker, чтобы сделать это.

Итак, как объявить p / invoke. Вам необходимо знать используемый набор символов и имя, по которому экспортируется функция. Давайте предположим, Unicode. P / invoke будет:

[DllImport("GrouperServer.dll", CallingConvention = CallingConvention.Cdecl,
EntryPoint = "<exported name goes here>")]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern string GroupInit(
[MarshalAs(UnmanagedType.LPWStr)]
string strCmdFile,
bool bAllowBadDiagCodes,
bool bAllowBadProcCodes
);
2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector