Трудно использовать импорт DLL в C #

Доброе утро / день / вечер!

Я получил DLL, которая должна получить теги из системы SCADA (Indusoft Web Studio). Он пришел вместе с образцами VC ++ и VB, которые на самом деле работают отлично. В настоящее время мне нужно получить эти значения и показать их в Интернете (используя ASP.NET). Я решил использовать C # для обработки значений из SCADA в HTML (ну, на самом деле, Microsoft ASP.NET рекомендует это делать). И вот где я застрял, я не могу заставить функцию работать.

Я создал класс для импортированной DLL, вот как это выглядит:

using System.Runtime.InteropServices;

namespace TagAccess
{
public class ISRW
{
[DllImport("C:\\Windows\\SysWOW64\\ISRWExtDLL.dll", CharSet = CharSet.Auto )]
public static extern string UNReadString([MarshalAs(UnmanagedType.BStr)] string szTagName);
}
}

К сожалению, когда я пытаюсь вызвать эту функцию, она дает мне:

    Managed Debugging Assistant 'PInvokeStackImbalance' has detected a problem in 'C:\Users\Denis\Documents\Visual Studio 2013\Projects\TagAccess\TagAccess\bin\Debug\TagAccess.vshost.exe'.

Additional information: A call to PInvoke function 'TagAccess!TagAccess.ISRW::UNReadString' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the
calling convention and parameters of the PInvoke signature match the target unmanaged signature.

То, что прекрасно работает в C, выглядит так:

CString CISRWExt::UNReadString(LPCTSTR szTagName)
{
CString result;
static BYTE parms[] =
VTS_BSTR;
InvokeHelper(0x1, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms,
szTagName);
return result;
}

Какие-либо предложения? Заранее спасибо.

Немного дополнительно для информации выше. Я импортировал другую функцию из DLL, теперь класс выглядит так:

namespace TagAccess
{public class ISRW
{
[DllImport("C:\\Windows\\SysWOW64\\ISRWExtDLL.dll", EntryPoint = "#1", CharSet = CharSet.Unicode,  SetLastError = true, CallingConvention = CallingConvention.Winapi, ThrowOnUnmappableChar = true )]
public static extern string UNReadString([MarshalAs(UnmanagedType.BStr)] string szTagName);

[DllImport("C:\\Windows\\SysWOW64\\ISRWExtDLL.dll", CharSet = CharSet.Auto)]
public static extern string UNWriteString([MarshalAs(UnmanagedType.BStr)] string szTagName, [MarshalAs(UnmanagedType.BStr)] string szValue);

}
}

Функция записи (UNWriteString) фактически записывает значения из C # в SCADA (я вижу изменения значений в средстве просмотра SCADA), но сразу после того, как все работает нормально, я получаю еще одну ошибку:

An unhandled exception of type 'System.NullReferenceException' occurred in mscorlib.dll

Additional information: Object reference not set to an instance of an object.

2

Решение

То, что прекрасно работает в C, выглядит так:

Это не C, это C ++. Метод экземпляра класса C ++ с именем CISRWExt. Привязка методов класса C ++ невозможна, вы не можете правильно вызвать конструктор и деструктор класса. Только компилятор C ++ может сделать это, вам нужно написать оболочку на языке C ++ / CLI.

Метод, который вы показали, однако, является автогенерируемая метод. Он был создан мастером Visual Studio для MFC из библиотеки типов COM-сервера. Какой прекрасный способ использовать COM-сервер из C ++. Это не хороший способ использовать его из C #.

Вам следует полностью обойти эту оболочку ISRWExtDLL.dll и использовать COM-сервер напрямую. C # имеет отличную поддержку COM-серверов с библиотекой типов, вы можете просто использовать Project + Add Reference. Единственное, что вам нужно выяснить, это где находится библиотека типов. Судя по документация продавца, вы должны быть в состоянии найти его обратно в c: \ windows \ syswow64 \ ISRWExt.OCX. Позвоните им, если вам нужна помощь.

2

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

Вы заявили, что можете звонить из C ++ так:

CString CISRWExt::UNReadString(LPCTSTR szTagName)
{
CString result;
static BYTE parms[] =
VTS_BSTR;
InvokeHelper(0x1, DISPATCH_METHOD, VT_BSTR, (void*)&result, parms,
szTagName); //<--- this is a COM dispatch call
return result;
}

это означает, что функция вызывается через COM Interop, а не PInvoke. Вызов с COM-взаимодействием, вероятно, решит некоторые проблемы.
Попробуйте обойти DLL C ++ и напрямую вызвать COM-объект через оболочку взаимодействия COM.

1

CString CISRWExt::UNReadString(LPCTSTR szTagName)

Прежде всего, это C ++, а не C.

Эта функция C ++ не может быть вызвана из C #. Если функция является нестатической функцией-членом, то вы должны знать, что классы C ++ нельзя использовать из C #. И даже если функция является статической функцией-членом, она возвращает CString, Это неуправляемый класс C ++, который не может быть использован кодом C #.

Вам нужно будет создать оболочку для этой DLL. Очевидный способ сделать это — создать библиотеку классов C ++ / CLI в смешанном режиме, которая обернет неуправляемую библиотеку C ++.

0
По вопросам рекламы [email protected]