c# - 对 PInvoke 函数的调用使堆栈不平衡

标签 c# pinvoke

对 native 代码进行 .NET 4 函数调用会导致以下异常:

A call to PInvoke function 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.

这是我在 native 代码中的定义:

typedef void ( CALLBACK* CB_DOWNLOADING )
(
      ULONG,    // secs elapsed
      LPARAM,   // custom callback param
      LPBOOL    // abort?
);


FETCH_API HttpFetchW
(
      LPCWSTR         url,
      IStream**       retval,
      LPCWSTR         usrname  = NULL,
      LPCWSTR         pwd      = NULL,
      BOOL            unzip    = TRUE,
      CB_DOWNLOADING  cb       = NULL,
      LPARAM          cb_param = 0,
      LPWSTR          ctype    = NULL,
      ULONG           ctypelen = 0
);

这是 .NET 的对应物:

[DllImport(dllPath, CharSet = CharSet.Unicode, SetLastError = true, CallingConvention =     CallingConvention.Cdecl)]
        internal static extern FETCH HttpFetchW
        (
            [MarshalAs(UnmanagedType.LPWStr)]
            string url,
            out System.Runtime.InteropServices.ComTypes.IStream retval,
            [MarshalAs(UnmanagedType.LPWStr)] 
            string usrname,
            [MarshalAs(UnmanagedType.LPWStr)] 
            string pwd,
            bool unzip,
            dlgDownloadingCB cb,
            IntPtr cb_param,
            [MarshalAs(UnmanagedType.LPWStr)] 
            string ctype,
            ulong ctypelen
        );

其中 FETCH 是一个枚举。

[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
    internal delegate void dlgDownloadingCB(ulong elapsedSec, IntPtr lParam, bool abort);


internal static void DownloadingCB(ulong elapsedSec, IntPtr lParam, bool abort)
        {
           // Console.WriteLine("elapsedSec = " + elapsedSec.ToString());
        }

任何人都可以在 .NET 4 中提出替代方案吗?

非常感谢您的帮助。

最佳答案

HttpFetchW 中唯一明显的错误是 C# ulong 是 64 位宽,C++ ULONG 是 32 位宽.最后一个参数的 C# 代码应该是 uint

要检查的其他事项包括调用约定。你确定是 cdecl 吗?您确定 SetLastError 应该是 true 吗?

至于回调,你用ulong犯了同样的错误。 abort 参数是 LPBOOL。这是指向 BOOL 的指针。因此,您应该将 C# 参数声明为 ref 参数。回调是用 CALLBACK 声明的,它是 stdcall

所以代表应该是:

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate void dlgDownloadingCB(
    uint elapsedSec, 
    IntPtr lParam, 
    ref bool abort
);

或者简单地删除 UnmanagedFunctionPointer 属性,因为默认值为 stdcall

我认为非常有可能因为回调是 stdcall,函数也是如此。我希望 FETCH_API 宏扩展为返回枚举和调用约定。因为你没有提供这些细节,我只能猜测。您需要检查一下。

我们无法检查的另一件事是 CB_DOWNLOADING

无论如何,根据这些假设,函数变为:

[DllImport(dllPath, CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern FETCH HttpFetchW(
    string url,
    out System.Runtime.InteropServices.ComTypes.IStream retval,
    string usrname,
    string pwd,
    bool unzip,
    dlgDownloadingCB cb,
    IntPtr cb_param,
    string ctype,
    uint ctypelen
);

关于c# - 对 PInvoke 函数的调用使堆栈不平衡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19082923/

相关文章:

c# - 在 MVVM 中打开一个新窗口

c# - "Value can not be null"单例模式错误

c# - Dataset 到数据集中的每个元素

c# - 在 C# 中使用 QPDF

c# - PInvoke 样式传递带有成员动态指针数组的结构

c# DLLImport 以 char* 作为参数调用 c++ 方法

c# - 如何从 Azure Function (HTTP) 返回数据流

c# - AnsiBStr SafeArray 上的 PInvoke

c# - 找不到入口点

c# - 删除扩展 WPF 工具包样式中的关闭按钮