### 2024-5-28 WindowsFormPaint FormTES_ESEB 测试[C#]GDI+中使用BitBlt绘制图像到窗口
```
#region 测试[C#]GDI+中使用BitBlt绘制图像到窗口
private void pbx01_Paint(object sender, PaintEventArgs e)
{
#region MyRegion
//using (Bitmap bp = new Bitmap("1234.png"))
using (Bitmap bp = (Bitmap)Bitmap.FromFile("123.png"))
//{
// using (var mHdcGraphics = Graphics.FromHwnd(pbx01.Handle))//主设备
// {
// using (var aHdcGraphics = Graphics.FromImage(bp))//辅助设备
// {
// //var mHdc = mHdcGraphics.GetHdc();
// //var aHdc = aHdcGraphics.GetHdc();
// BitBlt(mHdc,0,0,pbx01.Width,pbx01.Height, aHdc, 0,0, (uint)TernaryRasterOperations.SRCCOPY); // 0x00CC0020
// BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, aHdc, 0, 0, 0x00CC0020); // 0x00CC0020
// //BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, aHdc, 0, 0, (uint)RasterOperationMode.SRCCOPY); // 0x00CC0020
// //mHdcGraphics.ReleaseHdc(mHdc);
// //aHdcGraphics.ReleaseHdc(aHdc);
// //也就是说,在BitBlt之前,先将和Graphics有联系的Bitmap选作DC的背景图。
// //猜测,使用Graphics.FromImage的时候,.Net底层并没有将Bitmap对应的HBitmap选入HDC而只是将两个.Net对象联系起来了,而后在DrawImage中有两次SelectObject分别选入和选出以在HBitmap上绘图。所以独立于.Net进行GDI操作的时候,需要在GDI层面再将两者联系起来,使用SelectObject。
// //下面解决方式如下
// var mHdc = mHdcGraphics.GetHdc();
// var auxiliaryHdc = aHdcGraphics.GetHdc();
// var hbitmap = bp.GetHbitmap();
// var holdObject = SelectObject(auxiliaryHdc, hbitmap);
// if (holdObject != IntPtr.Zero)
// {
// //BitBlt(mHdc,0,0,pbx01.Width,pbx01.Height, aHdc, 0,0, (uint)TernaryRasterOperations.SRCCOPY); // 0x00CC0020
// //BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, aHdc, 0, 0, 0x00CC0020); // 0x00CC0020
// bool result = BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, auxiliaryHdc, 0, 0, (uint)RasterOperationMode.SRCCOPY); // 0x00CC0020
// if (result)
// {
// TraceLog($"[C#]GDI+中使用BitBlt绘制图像到窗口 成功:{result}");
// }
// else
// {
// TraceLog($"[C#]GDI+中使用BitBlt绘制图像到窗口 失败:{result}");
// }
// }
// //pbx01.Refresh();
// //释放资源
// DeleteObject(hbitmap);
// mHdcGraphics.ReleaseHdc(mHdc);
// aHdcGraphics.ReleaseHdc(auxiliaryHdc);
// }
// }
//}
#endregion
}
private void btnTestGDI_Click(object sender, EventArgs e)
{
//pbx01.Invalidate();
//pbx01.Update();
//pbx01.Refresh();
using (Bitmap bp = new Bitmap("1234.png"))
//using (Bitmap bp = (Bitmap)Bitmap.FromFile("123.png"))
{
using (var mHdcGraphics = Graphics.FromHwnd(pbx01.Handle))//主设备
{
using (var aHdcGraphics = Graphics.FromImage(bp))//辅助设备
{
//var mHdc = mHdcGraphics.GetHdc();
//var aHdc = aHdcGraphics.GetHdc();
BitBlt(mHdc,0,0,pbx01.Width,pbx01.Height, aHdc, 0,0, (uint)TernaryRasterOperations.SRCCOPY); // 0x00CC0020
BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, aHdc, 0, 0, 0x00CC0020); // 0x00CC0020
//BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, aHdc, 0, 0, (uint)RasterOperationMode.SRCCOPY); // 0x00CC0020
//mHdcGraphics.ReleaseHdc(mHdc);
//aHdcGraphics.ReleaseHdc(aHdc);
//也就是说,在BitBlt之前,先将和Graphics有联系的Bitmap选作DC的背景图。
//猜测,使用Graphics.FromImage的时候,.Net底层并没有将Bitmap对应的HBitmap选入HDC而只是将两个.Net对象联系起来了,而后在DrawImage中有两次SelectObject分别选入和选出以在HBitmap上绘图。所以独立于.Net进行GDI操作的时候,需要在GDI层面再将两者联系起来,使用SelectObject。
//下面解决方式如下
var mHdc = mHdcGraphics.GetHdc();
var auxiliaryHdc = aHdcGraphics.GetHdc();
var hbitmap = bp.GetHbitmap();
var holdObject = SelectObject(auxiliaryHdc, hbitmap);
if (holdObject != IntPtr.Zero)
{
//BitBlt(mHdc,0,0,pbx01.Width,pbx01.Height, aHdc, 0,0, (uint)TernaryRasterOperations.SRCCOPY); // 0x00CC0020
//BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, aHdc, 0, 0, 0x00CC0020); // 0x00CC0020
bool result = BitBlt(mHdc, 0, 0, pbx01.Width, pbx01.Height, auxiliaryHdc, 0, 0, (uint)RasterOperationMode.SRCCOPY); // 0x00CC0020
if (result)
{
TraceLog($"[C#]GDI+中使用BitBlt绘制图像到窗口 成功:{result}");
}
else
{
TraceLog($"[C#]GDI+中使用BitBlt绘制图像到窗口 失败:{result}");
}
}
//pbx01.Refresh();
//释放资源
DeleteObject(hbitmap);
mHdcGraphics.ReleaseHdc(mHdc);
aHdcGraphics.ReleaseHdc(auxiliaryHdc);
}
}
}
}
[DllImport("User32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect);
[DllImport("user32.dll")]
public static extern bool GetClientRect(IntPtr hWnd, out Rect lpRect);
[DllImport("user32.dll", EntryPoint = "GetWindowDC")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hDc);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hDc, int nWidth, int nHeight);
[DllImport("gdi32.dll")]
public static extern bool DeleteDC(IntPtr hDc);
[DllImport("user32.dll")]
public static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateDIBSection(IntPtr hdc, ref BitmapInfo bmi, uint usage, out IntPtr ppvBits, IntPtr hSection, uint dwOffset);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hDc, IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll", SetLastError = true)]
public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hObjectSource, int nXSrc, int nYSrc, uint dwRop);
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
[StructLayout(LayoutKind.Sequential)]
public struct Point
{
public int x;
public int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int Left; //最左坐标
public int Top; //最上坐标
public int Right; //最右坐标
public int Bottom; //最下坐标
public int Width => Right - Left;
public int Height => Bottom - Top;
}
[StructLayout(LayoutKind.Sequential, Pack = 2)]
public struct BitmapFileHeader
{
public ushort bfType;
public uint bfSize;
public ushort bfReserved1;
public ushort bfReserved2;
public uint bfOffBits;
}
[StructLayout(LayoutKind.Sequential)]
public struct BitmapInfoHeader
{
public uint biSize;
public int biWidth;
public int biHeight;
public ushort biPlanes;
public ushort biBitCount;
public uint biCompression;
public uint biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public uint biClrUsed;
public uint biClrImportant;
public void Init()
{
biSize = (uint)Marshal.SizeOf(this);
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RgbQuad
{
public byte rgbBlue;
public byte rgbGreen;
public byte rgbRed;
public byte rgbReserved;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BitmapInfo
{
public BitmapInfoHeader bmiHeader;
public RgbQuad bmiColors;
}
public enum DibColorMode : uint
{
DIB_RGB_COLORS = 0x00,
DIB_PAL_COLORS = 0x01,
DIB_PAL_INDICES = 0x02
}
public enum BitmapCompressionMode : uint
{
BI_RGB = 0,
BI_RLE8 = 1,
BI_RLE4 = 2,
BI_BITFIELDS = 3,
BI_JPEG = 4,
BI_PNG = 5
}
public enum RasterOperationMode : uint
{
SRCCOPY = 0x00CC0020,
SRCPAINT = 0x00EE0086,
SRCAND = 0x008800C6,
SRCINVERT = 0x00660046,
SRCERASE = 0x00440328,
NOTSRCCOPY = 0x00330008,
NOTSRCERASE = 0x001100A6,
MERGECOPY = 0x00C000CA,
MERGEPAINT = 0x00BB0226,
PATCOPY = 0x00F00021,
PATPAINT = 0x00FB0A09,
PATINVERT = 0x005A0049,
DSTINVERT = 0x00550009,
BLACKNESS = 0x00000042,
WHITENESS = 0x00FF0062,
CAPTUREBLT = 0x40000000 //only if WinVer >= 5.0.0 (see wingdi.h)
}
public enum PrintWindowMode : uint
{
[Description("Only the client area of the window is copied to hdcBlt. By default, the entire window is copied.")]
PW_CLIENTONLY = 0x00000001,
[Description("works on windows that use DirectX or DirectComposition")]
PW_RENDERFULLCONTENT = 0x00000002
}
#endregion
```
03-29
1183

06-30
1730
