从托管代码调用非托管代码

本文关键字:非托管代码 调用 托管代码 | 更新日期: 2023-09-27 18:28:30

有人知道我是如何修复这个错误的吗?

错误:

对PInvoke函数的调用使堆栈不平衡。这可能是因为托管PInvoke签名与非托管目标签名不匹配。请检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配。

我正在使用p/Invoke从托管代码中调用本机代码。本机代码是通过动态链接库导入的。

步骤为

  1. 正在查找包含这些函数的.dll
  2. 正在将.dll加载到内存中
  3. 在内存中查找函数的地址
  4. 将对象的此内存表示转换为数据格式(编组)

DLL有一个声明为的函数

long    __stdcall Connect (long,long,long,long,long,long,long,long);`

在我的应用程序中,我创建了一个代理

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate long delConnect(long a, long b, long c, long d, long e, long f, long g, long h);`

然后我创建了一个类来加载dll并在内存中定位函数的地址

`静态类NativeMethods{[DllImport("kernel32.dll")]public static extern IntPtr LoadLibrary(字符串dllToLoad);

    [DllImport("kernel32.dll")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

    [DllImport("kernel32.dll")]
    public static extern bool FreeLibrary(IntPtr hModule);
}`

现在,当我试图使用该功能,然后我得到错误

IntPtr pDll = NativeMethods.LoadLibrary("serial.dll");
IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "_Connect@32");
delConnect connect = (delConnect)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall,typeof(delConnect)); 
long check = connect(1, 0, 12, 9600, 0, 0, 8, 0);
bool result = NativeMethods.FreeLibrary(pDll);`

我使用过"_Connect@32而不是GetProcAddress方法的函数名称参数中的"Connect",因为名称篡改。

当我调试时,我在包含语句的行中得到了这个错误

长检查=连接(1,0,12,9600,0,0,8,0);

从托管代码调用非托管代码

C/C++long在Windows中是32位的,因此.net中是int。尝试更改它(在Unix上,它更像IntPtr

[UnmanagedFunctionPointer(CallingConvention.StdCall)] 
private delegate int delConnect(int a, int b, int c, int d, int e, int f, int g, int h);

也许可以尝试Cdecl:而不是StdCall

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 

对于Windows API的DllImport,您应该使用

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]

因此,如果可能的话,.NET使用Unicode变体,而不是Ansi变体。

使用LoadLibrary()而不仅仅是直接PInvooking有什么原因吗?

如果你尝试这样做会发生什么:

[DllImport("serial.dll", EntryPoint = "_Connect@32", CallingConvention = CallingConvention.StdCall)]
static extern int DelConnect(int a, int b, int c, int d, int e, int f, int g, int h);

(注意C#int==C++长,正常)