【问题标题】:BitBlt returns false, GetLastError returns 6 (Invalid handle)?BitBlt 返回 false,GetLastError 返回 6(无效句柄)?
【发布时间】:2013-04-24 17:12:09
【问题描述】:

自从我上次涉足 GDI 以来已经有几年了,但我不记得以前遇到过这样的问题。我没有遇到异常,但 BitBlt 返回 0 (False),检查 GetLastWIN32Error 显示 6。这似乎是一个无效的句柄。并且目标图像保持空白。

我也添加了对 SelectObject 的调用,但这不应该也不会影响无效句柄错误。

对我缺少什么有什么想法吗?

void MySub()
{
    var bmpSrc = new Bitmap("c:\\temp\\test.bmp", false);
    var bmpDst= new Bitmap(1000, 1000);
    var gSrc = Graphics.FromImage(bmpSrc);
    var gDst = Graphics.FromImage(bmpDst);
    IntPtr HDCSrc = gSrc.GetHdc();
    IntPtr HDCDst = gDst.GetHdc();
    if (!BitBlt(HDCDst, 0, 0, 55, 94, HDCSrc, 0, 0, SRCCOPY))
    {
        int er = Marshal.GetLastWin32Error();
        MessageBox.Show(er.ToString());
    }
    gDst.ReleaseHdc(HDCDst);
    gSrc.ReleaseHdc(HDCSrc);
    pictureBox1.Image = iDst;
}

public static long SRCCOPY = 0x00CC0020;

[DllImport("gdi32.dll", CallingConvention = CallingConvention.ThisCall, SetLastError = true)]
public static extern bool BitBlt(
     IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, long dwRop);

【问题讨论】:

    标签: c# gdi bitblt


    【解决方案1】:

    您对 Win32 API 的调用约定有误。使用:

    CallingConvention = CallingConvention.StdCall
    

    最后一个参数也应该是 UInt32 或等效的。 pinvoke.net 虽然不权威,但非常有用。在这种情况下,它为最后一个参数定义了一个很好的枚举,以防您将任何其他栅格操作与BitBlt 一起使用。

    【讨论】:

    • 另一个好点,我的回应受限于我对这一变化的全部影响缺乏了解,但使用 CallingConvention.StdCall 会导致 BitBlt 调用出现异常:对 PInvoke 函数的调用' Form1::BitBlt' 使堆栈不平衡。这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。如果使用 StdCall,是否还缺少一些其他配置以确保兼容性?
    • 感谢 pinvoke.net 的指针,这对正确定义 bitblt 非常有帮助!
    【解决方案2】:

    终于找到了一个我想要完成的确切例子,这里是:

            var bmpSrc = new Bitmap("c:\\temp\\test.bmp");
            var bmpDst = new Bitmap(1000, 1000);
    
            // Get source image  in memory
            Graphics sourceImageGraphics = Graphics.FromImage(bmpDst);
            IntPtr sourceImageHDC = sourceImageGraphics.GetHdc();
            IntPtr sourceImageCDC = CreateCompatibleDC(sourceImageHDC);
            IntPtr sourceImageHandle = bmpDst.GetHbitmap();
            SelectObject(sourceImageCDC, sourceImageHandle);
    
            // Get overlay image in memory
            Graphics overlayImageGraphics = Graphics.FromImage(bmpSrc);
            IntPtr overlayImageHDC = overlayImageGraphics.GetHdc();
            IntPtr overlayImageCDC = CreateCompatibleDC(overlayImageHDC);
            IntPtr overlayImageHandle = bmpSrc.GetHbitmap();
            SelectObject(overlayImageCDC, overlayImageHandle);
    
            for (int x = 0; x < _Iterations; x++)
                    if (!BitBlt(sourceImageHDC, 0, 0, 55, 94, overlayImageCDC, 0, 0, TernaryRasterOperations.SRCCOPY))
                    {
                        var er = Marshal.GetLastWin32Error();
                        MessageBox.Show(er.ToString());
                    }
    
            // Release source Image memory.
            DeleteDC(sourceImageCDC);
            DeleteObject(sourceImageHandle);
            sourceImageGraphics.ReleaseHdc(sourceImageHDC);
            sourceImageGraphics.Dispose();
    
            // Release overlay Image memory.
            DeleteDC(overlayImageCDC);
            DeleteObject(overlayImageHandle);
            overlayImageGraphics.ReleaseHdc(overlayImageHDC);
            overlayImageGraphics.Dispose();
    
            pictureBox1.Image = bmpDst;
    

    超过 100,000 个 bitblt 与 100,000 个 .DrawImages,bitblt 在我的笔记本电脑上压倒 .DrawImages ~8:1。 :)

    【讨论】:

      【解决方案3】:

      好的,所以这可能是一个评论,但由于有代码,我在这里发布:

      有什么理由需要 p/invoke 吗?有什么问题:

      using(var bmpSrc = new Bitmap("c:\\temp\\test.bmp", false))
      using(var bmpDst = new Bitmap(1000, 1000))
      using(var gDst = Graphics.FromImage(bmpDst))
      {
          gDst.DrawImage(bmpSrc,0,0,55,94);
          //...
      }
      

      【讨论】:

      • 好问题!我实际上看到了 Graphics.Draw 的性能问题......对于渲染量和我们正在触及的用户数量的规模。我的计划是比较 DrawImage 和直接调用 BitBlt 之间的性能,看看是否值得追求。
      猜你喜欢
      • 2015-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-23
      • 2010-12-10
      • 1970-01-01
      • 2023-04-03
      相关资源
      最近更新 更多