【问题标题】:DLLImport: passing short type parameterDLLImport:传递短类型参数
【发布时间】:2010-11-15 22:26:01
【问题描述】:

我正在尝试将短类型参数传递给从 DLL 导入的 C++ 非托管函数。在我的 C++ DLL 代码中,我有以下函数:

__declspec(dllexport)void ChangeIcon(char *executableFile, char *iconFile,
    UINT16 imageCount)
{
    // Some code, doesn't matter
}

在 C# 托管代码中,我使用以下代码导入此函数:

[DllImport("IconChanger.dll")]
static extern void ChangeIcon(string executableFile, string iconFile,
    ushort imageCount);

然后我称之为:

ushort imageCount = 2;
ChangeIcon("filePath", "iconPath", imageCount);

应用程序执行该功能就好了;但是,会弹出带有以下文本的消息:

托管调试助手“PInvokeStackImbalance”检测到“foo.exe”存在问题。 附加信息:对 PInvoke 函数“bar.IconChanger::ChangeIcon”的调用使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。

如果我不传最后一个参数,消息没有弹出,所以一定是传短类型的原因。我也尝试过使用 int,出现相同的消息。

显然,我在传递这个数字参数时做错了。两者之间如何匹配参数?

【问题讨论】:

    标签: c# c++ pinvoke dllimport parameter-passing


    【解决方案1】:

    确保调用约定匹配。如果您未指定调用约定 StdCall,则假定为。但是对于 C/C++,标准调用约定是 Cdecl。所以要么在你的 C++ 函数上使用__stdcall

    void __declspec(dllexport) __stdcall ChangeIcon(char *executableFile, char *iconFile,
        UINT16 imageCount)
    {
        // Some code, doesn't matter
    }
    

    或在DllImport 上指定CallingConvention.Cdecl

    [DllImport("IconChanger.dll", CallingConvention = CallingConvention.Cdecl)]
    

    附带说明,UInt16 不是符合 CLS 的类型,因此如果您需要这种合规性,您可能需要 Int16

    【讨论】:

    • 这是正确的。不过,如果不声明第三个参数就不会收到 MDA 警告是很神秘的。
    • 注意:默认调用约定被指定为编译器选项(/Gd/Gr/Gz),可能不是__cdecl
    • @André,说得好。我的 C/C++ 知识非常有限。随意修改我的答案以添加有关编译器选项的宝贵信息。
    【解决方案2】:

    因为您在 C++ 函数的参数中使用了 char*,所以我建议您以这种方式导入函数: [DllImport("IconChanger.dll", CallingConvention = CallingConvention.Cdecl)] static extern void ChangeIcon([MarshalAs(UnmanagedType.LPStr)string executableFile, [MarshalAs(UnmanagedType.LPStr)string iconFile, ushort imageCount);

    【讨论】:

    • 不,CharSet.Ansi 是默认值。
    猜你喜欢
    • 1970-01-01
    • 2021-02-12
    • 2015-03-17
    • 1970-01-01
    • 1970-01-01
    • 2019-03-25
    • 2019-02-27
    • 2011-11-09
    相关资源
    最近更新 更多