2

早上好/白天/晚上!

我收到了必须从 SCADA 系统(Indusoft Web Studio)检索标签的 dll。它与实际上工作得很好的 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.
4

3 回答 3

2

在 C 中完美运行的功能如下所示:

它不是 C,它是 C++。一个名为 CISRWExt 的 C++ 类的实例方法。无法调用 C++ 类方法,不能正确调用类的构造函数和析构函数。只有 C++ 编译器可以做到这一点,您需要用 C++/CLI 语言编写一个包装器。

但是,您展示的方法是自动生成的方法。它是由用于 MFC 的 Visual Studio 向导从 COM 服务器的类型库生成的。这是从 C++ 使用 COM 服务器的好方法。这不是从 C# 中使用它的好方法。

您应该完全绕过这个 ISRWExtDLL.dll 包装器并直接使用 COM 服务器。C# 对带有类型库的 COM 服务器提供了出色的支持,您可以简单地使用 Project + Add Reference。你唯一需要知道的是这个类型库的位置。从供应商的文档来看,您应该可以在 c:\windows\syswow64\ISRWExt.OCX 中找到它。如果您需要帮助,请给他们打电话。

于 2014-07-14T11:16:35.640 回答
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 互操作调用,而不是 PInvoke。使用 COM 互操作调用可能会解决一些问题。尝试绕过 C++ dll 并通过 COM 互操作包装器直接调用 COM 对象。

于 2014-07-14T10:42:37.190 回答
0
CString CISRWExt::UNReadString(LPCTSTR szTagName)

首先,这是 C++ 而不是 C。

无法从 C# 调用此 C++ 函数。如果该函数是非静态成员函数,那么您应该知道 C++ 类不能从 C# 中使用。即使该函数是静态成员函数,它也会返回CString. 这是 C# 代码不能使用的非托管 C++ 类。

您将需要为此 DLL 创建一个包装器。显而易见的方法是创建一个混合模式的 C++/CLI 类库来包装非托管 C++ 库。

于 2014-07-14T11:11:06.247 回答