【问题标题】:Call a C++ DLL method from a C# application从 C# 应用程序调用 C++ DLL 方法
【发布时间】:2012-01-30 10:38:06
【问题描述】:

我正在尝试在 C# 项目中使用 C++ DLL 中的方法,但我在正确调用它时遇到了问题。 方法是这样的:

如 SDK 手册中所述

DWORD WINAPI PrtRead(句柄 hPrt、DWORD dwTimeout、DWORD *pdwType、LPDWORD pdwParArray、LPDWORD pdwArraySize、LPBYTE pbReadData、LPDWORD pdwReadDataLen)

正如代码中真正定义的那样

extern "C" __declspec(dllimport) DWORD PrtRead (HANDLE hPRT, DWORD dwTimeout, DWORD *pdwType, LPDWORD pdwParArray, LPDWORD pdwArraySize,LPBYTE  pbReadData, LPDWORD pdwReadDataLen);

在 SDK C++ 示例中,他们这样称呼它:

DWORD       dwPar[2];
pdwParArray = &dwPar[0];
dwPar[0] = 0;
dwPar[1] = 0;

DWORD dwRet = PrtRead(hPrinter, dwCurrentTimeout, &dwType, pdwParArray, &dwArraySize, NULL, &dwReadDataLen);

我的问题是获取值 LPDWORD pdwParArray。

DLL 始终在位置 [0] 中返回以下值之一:1、2 或 20,在位置 [1] 中返回以下值之一:1、2 或 4,但我无法做到这一点。

我尝试过这样定义导入:

[DllImport("HPRDH.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern ulong PrtRead(IntPtr hPrt, ulong dwTimeout, ref ulong pdwType, XXXXXXXXX , ref ulong pdwArraySize, ref byte[] pbReadData, ref ulong pdwReadDataLen);

像这样变化的XXXXXXXXX


方法定义:

out ulong[] pdwParArray

变量初始化:

ulong[] pdwParArray;

方法返回:

pdwParArray = null

方法定义:

ref ulong[] pdwParArray

变量初始化:

ulong[] pdwParArray = new ulong[2];
pdwParArray[0] = 0;
pdwParArray[1] = 0;

方法返回: pdwParArray[0] = 0; pdwParArray[1] = 超出范围的数组索引;


方法定义: out ulong pdwParArray

变量初始化: ulong[] pdwParArray = new ulong[2];

方法返回: pdwParArray[0] = 0; pdwParArray[1] = 0;


方法定义: ref ulong pdwParArray

变量初始化: ulong[] pdwParArray = new ulong[2];

方法返回: pdwParArray[0] = 0; pdwParArray[1] = 0;


我应该如何在我的 C# 导入中定义 LPDWORD pdwParArray,如何初始化并调用它?

提前致谢

_
_
_
_

编辑: @TheMathemagician

尝试了以下结果:

定义:

[MarshalAs(UnManagedType.LPArray)] ulong[] pdwParArray

结果:

pdwParArray[0] = 0;

pdwParArray[1] = 0;


定义:

[MarshalAs(UnmanagedType.LPArray)] out ulong[] pdwParArray

结果:

pdwParArray[0] = null;

pdwParArray[1] = null;


定义:

[MarshalAs(UnmanagedType.LPArray)] ulong pdwParArray

结果:

无法封送“参数 #4”:托管/非托管类型组合无效(Int64/UInt64 必须与 I8 或 U8 配对)。


定义:

[MarshalAs(UnmaDefinition:nagedType.LPArray)] out ulong pdwParArray

结果:

无法封送“参数 #4”:托管/非托管类型组合无效(Int64/UInt64 必须与 I8 或 U8 配对)。

【问题讨论】:

  • 您使用的是 32 位还是 64 位窗口。看看这里stackoverflow.com/questions/39419/… - 你的整个代码取决于这个问题。
  • 我运行的是 64 位 Windows,但尝试强制程序在 x86 上编译并得到相同的结果

标签: c# c++ .net dll


【解决方案1】:

你说的方法是 WINAPI 调用,而不是 cdecl 在您的 c# 应用程序中,您将其声明为 cdecl

【讨论】:

  • 用你说的声明重试了所有测试,在每种情况下我都得到:对 PInvoke 函数“WincorNixdorf!WincorNixdorf.WincorNixdorfDriver::PrtRead”的调用使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。
【解决方案2】:

由于几乎所有答案都在同一件事上,即使这样它也不起作用,我决定更深入地研究 SDK 示例,并意识到我需要第二次调用 PrtRead(...)获取正确的值。

我最终使用了:

[DllImport("HPRDH.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 PrtRead(IntPtr hPrt, UInt32 dwTimeout, ref UInt32 pdwType, out UInt32 pdwParArray, ref UInt32 pdwArraySize, ref byte[] pbReadData, ref UInt32 pdwReadDataLen);

【讨论】:

    【解决方案3】:

    我注意到的一件事是您为导入的函数指定了错误的 CallingConvention。

    在C++中WINAPI被定义为

    #define WINAPI __stdcall
    

    所以你的 C# 导入应该是

    [DllImport("HPRDH.dll", CallingConvention = CallingConvention.StdCall)]
    public static extern ulong PrtRead(IntPtr hPrt, ulong dwTimeout, ref ulong pdwType, XXXXXXXXX , ref ulong pdwArraySize, ref byte[] pbReadData, ref ulong pdwReadDataLen);
    

    【讨论】:

    • 试过了,得到了同样的错误。所以我决定查看源代码而不是手册,它实际上定义为: extern "C" __declspec(dllimport) DWORD PrtRead (HANDLE hPRT, DWORD dwTimeout, DWORD *pdwType,LPDWORD pdwParArray,LPDWORD pdwArraySize,LPBYTE pbReadData,LPDWORD pdwReadDataLen );
    【解决方案4】:

    使用此处的表格进行转换,并更正调用约定: Pinvoke.net

    【讨论】:

      【解决方案5】:

      尝试将其声明为 [MarshalAs(UnManagedType.LPArray)] ulong[] pdwParArray

      C# 中的 OK ulong 是一个 64 位整数(在 Windows 7 上),我发现如果我将所有 ulong 更改为 Int32,它适用于我使用相同签名构造的 DLL 函数。

      所以我有: [DllImport("SPLibNet.dll", CallingConvention=CallingConvention.StdCall)] 公共静态外部 Int32 PrtRead(IntPtr hPtr, Int32 dwTimeout, ref Int32 pdwType, [MarshalAs(UnmanagedType.LPArray)] Int32[] pdwParArray, ...

      而且我的 DLL 能够在 pdwParArray 中设置值

      【讨论】:

      • 将结果添加到原始问题
      • 试过了,只是用 Cdecl 和 DLL 名称替换了 StdCall,得到了相同的结果
      • 为什么用 Cdecl 代替 StdCall?那就不行了。正如 Volker Mauel 和 Tom Knapen 所说,WINAPI 是 StdCall。
      • 因为方法定义是extern "C" __declspec(dllimport) DWORD PrtRead (HANDLE hPRT, DWORD dwTimeout, DWORD *pdwType, LPDWORD pdwParArray, LPDWORD pdwArraySize,LPBYTE pbReadData, LPDWORD pdwReadDataLen); 当我输入 StdCall 时,我得到 'WincorNixdorf!WincorNixdorf.WincorNixdorfDriver::PrtRead' has unbalanced stack.
      • [DllImport("HPRDH.dll", CallingConvention=CallingConvention.Cdecl)] public static extern Int32 PrtRead(IntPtr hPrt, Int32 dwTimeout, ref Int32 pdwType, [MarshalAs(UnmanagedType.LPArray)] Int32[ ] pdwParArray, ref Int32 pdwArraySize, byte[] pbReadData, ref Int32 pdwReadDataLen);
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-29
      相关资源
      最近更新 更多