【问题标题】:C# bitmap comparison (PinvokeStackimbalance exception)C#位图比较(PinvokeStackimbalance异常)
【发布时间】:2012-02-19 12:00:14
【问题描述】:

我正在尝试使用以下方法比较两张图片:

       [DllImport("msvcrt.dll")]
private static extern int memcmp(IntPtr b1, IntPtr b2, long count);

public static bool CompareMemCmp(Bitmap b1, Bitmap b2)
{
    if ((b1 == null) != (b2 == null)) return false;
    if (b1.Size != b2.Size) return false;

    var bd1 = b1.LockBits(new Rectangle(new Point(0, 0), b1.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    var bd2 = b2.LockBits(new Rectangle(new Point(0, 0), b2.Size), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

    try
    {
        IntPtr bd1scan0 = bd1.Scan0;
        IntPtr bd2scan0 = bd2.Scan0;

        int stride = bd1.Stride;
        int len = stride * b1.Height;

        return memcmp(bd1scan0, bd2scan0, len) == 0;
    }
    finally
    {
        b1.UnlockBits(bd1);
        b2.UnlockBits(bd2);
    }
}

我正在像这样使用 CompareMemCmp()(on_click 事件):

        Bitmap img1 = new Bitmap(@"C:\1\1.png");
        Bitmap img2 = new Bitmap(@"C:\1\2.png");

        if (CompareMemCmp(img1, img2) == true)
        { textBox1.Text = "Same"; }
        else { textBox1.Text = "Different"; }

不幸抛出异常:

return memcmp(bd1scan0, bd2scan0, len) == 0;

PinvokeStackimbalance “对 PInvoke 函数 'TextRecognition!TextRecognition.Form1::memcmp' 的调用使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否匹配目标非托管签名。”

可能是什么问题?我已经尝试了不同的方法来解决这个问题..

【问题讨论】:

    标签: c# exception bitmap pinvoke


    【解决方案1】:

    pinvoke.net says the signature should be

    [DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
    static extern int memcmp(byte[] b1, byte[] b2, UIntPtr count);
    

    编辑:pinvoke.net 已将声明的原始版本标记为仅 x64,但它似乎在 x32 上也可以正常运行,只需添加 CallingConvention=CallingConvention.Cdecl

    【讨论】:

    • 错误(甚至在编译之前):'TextRecognition.Form1.memcmp(byte[], byte[], System.UIntPtr)' 的最佳重载方法匹配有一些无效参数
    • 帮助:[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)] private static extern int memcmp(IntPtr b1, IntPtr b2, long count);
    • 我刚刚根据您的解决方案修改了 [import dll] 的后半部分.. ;) 感谢您的提示
    • @Alex 您需要将参数转换为正确的类型,链接的页面有一个示例。长度有点令人困惑,因此将转换包装在私有方法中可能是个好主意。
    • @Alex 啊,Cdecl 就够了,节省了一些类型转换魔法:)
    【解决方案2】:

    签名应该是:

    [DllImport("msvcrt.dll", CallingConvention=CallingConvention.Cdecl)]
    static extern int memcmp(IntPtr b1, IntPtr b2, UIntPtr count);
    

    问题中代码的问题是

    1. 调用约定不匹配:msvcrt.dll 将其函数导出为cdecl
    2. 本机代码中的 count 参数是 size_t,相当于 .net 中指针大小的无符号整数,即 UIntPtr

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多