早上好/白天/晚上!
我收到了必须从SCADA系统(Indusoft Web Studio)检索标签的dll。它与VC ++和VB样本一起实际上工作得很好。目前我需要获取这些值并在Web上显示它们(使用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.
答案 0 :(得分:2)
在C中完美无缺的效果如下:
它不是C,它是C ++。名为CISRWExt的C ++类的实例方法。 Pinvoking C ++类方法是不可能的,你无法正确调用类的构造函数和析构函数。只有C ++编译器可以做到这一点,你需要用C ++ / CLI语言编写一个包装器。
您展示的方法是自动生成的方法。它是由MFC的Visual Studio向导从COM服务器的类型库生成的。这是从C ++使用COM服务器的好方法。它不是从C#中使用它的好方法。
您应该完全绕过此ISRWExtDLL.dll包装并直接使用COM服务器。 C#对具有类型库的COM服务器提供了出色的支持,您只需使用Project + Add Reference即可。您唯一需要知道的是此类型库所在的位置。从vendor's documentation判断,您应该能够在c:\ windows \ syswow64 \ ISRWExt.OCX中找到它。如果您需要帮助,请给他们打电话。
答案 1 :(得分:1)
你声明你可以用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互操作调用可能会解决一些麻烦。 尝试绕过C ++ DLL并通过COM interop包装器直接调用COM对象。
答案 2 :(得分:0)
CString CISRWExt::UNReadString(LPCTSTR szTagName)
首先,这是C ++而不是C。
无法从C#调用此C ++函数。如果函数是非静态成员函数,那么您应该知道不能从C#中使用C ++类。即使该函数是静态成员函数,它也会返回CString
。这是一个无法被C#代码使用的非托管C ++类。
您需要为此DLL创建一个包装器。显而易见的方法是创建一个包装非托管C ++库的混合模式C ++ / CLI类库。