Yes - I know this is not exciting - but my colleague can get the same psuedocode to work in a C program, it show a black square with some green bands - but in C# it only draws a black square - see below:
If you copy the code below in the partial class of Form1 (a fresh default Windows Application - you will see my problem. I have tried a million different things - but I guess it how I have stipulated the Win32 calls or something - if anyone can help where I have gone wrong - I would be very grateful.
The code below looks very long but I have decided to put it all in so it is easy to just copy/paste into the partial class for a standard form - so don't let it scare you!
public partial class Form1 : Form
{
[DllImport("gdi32.dll", SetLastError = true)]
static extern IntPtr CreateDIBitmap([In] IntPtr hdc, [In] ref BITMAPINFOHEADER lpbmih, uint fdwInit, byte[] lpbInit, [In] ref BITMAPINFO lpbmi, uint fuUsage);
[DllImport("gdi32.dll", SetLastError = true)]
static extern int SetDIBits(IntPtr hdc, IntPtr hbmp, uint uStartScan, uint
cScanLines, byte[] lpvBits, [In] ref BITMAPINFO lpbmi, uint fuColorUse);
[DllImport("gdi32.dll", SetLastError = true)]
static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
enum TernaryRasterOperations : uint
{
/// <summary>dest = source</summary>
SRCCOPY = 0x00CC0020,
/// <summary>dest = source OR dest</summary>
SRCPAINT = 0x00EE0086,
/// <summary>dest = source AND dest</summary>
SRCAND = 0x008800C6,
/// <summary>dest = source XOR dest</summary>
SRCINVERT = 0x00660046,
/// <summary>dest = source AND (NOT dest)</summary>
SRCERASE = 0x00440328,
/// <summary>dest = (NOT source)</summary>
NOTSRCCOPY = 0x00330008,
/// <summary>dest = (NOT src) AND (NOT dest)</summary>
NOTSRCERASE = 0x001100A6,
/// <summary>dest = (source AND pattern)</summary>
MERGECOPY = 0x00C000CA,
/// <summary>dest = (NOT source) OR dest</summary>
MERGEPAINT = 0x00BB0226,
/// <summary>dest = pattern</summary>
PATCOPY = 0x00F00021,
/// <summary>dest = DPSnoo</summary>
PATPAINT = 0x00FB0A09,
/// <summary>dest = pattern XOR dest</summary>
PATINVERT = 0x005A0049,
/// <summary>dest = (NOT dest)</summary>
DSTINVERT = 0x00550009,
/// <summary>dest = BLACK</summary>
BLACKNESS = 0x00000042,
/// <summary>dest = WHITE</summary>
WHITENESS = 0x00FF0062,
/// <summary>
/// Capture window as seen on screen. This includes layered windows
/// such as WPF windows with AllowsTransparency="true"
/// </summary>
CAPTUREBLT = 0x40000000
}
[DllImport("gdi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
[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)]
public struct BITMAPINFO
{
public BITMAPINFOHEADER bmiHeader;
public RGBQUAD bmiColors;
}
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
private System.IntPtr m_Bitmap;
private BITMAPINFOHEADER m_Bmh;
private BITMAPINFO m_Bmi = new BITMAPINFO();
public Form1()
{
m_Bmh.Init();
m_Bmh.biPlanes = 1;
m_Bmh.biBitCount = 24;
m_Bmh.biCompression = 0;
m_Bmh.biHeight = 100;
m_Bmh.biWidth = 100;
m_Bitmap = (IntPtr)0;
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
int errorNumber = Marshal.GetLastWin32Error();
byte[] testGraphicArray = new byte[300];
for (int i = 0; i < m_Bmh.biWidth; i++)
{
testGraphicArray[i * 3 + 0] = Convert.ToByte(i);
testGraphicArray[i * 3 + 1] = Convert.ToByte(255 - i);
testGraphicArray[i * 3 + 2] = Convert.ToByte(i);
}
IntPtr winPtr = GetDC(this.Handle);
errorNumber = Marshal.GetLastWin32Error();
//Make the bitmap
if (m_Bitmap == (IntPtr)0)
m_Bitmap = CreateDIBitmap(winPtr, ref m_Bmh, (uint)0L, testGraphicArray, ref m_Bmi, (uint)0L);
errorNumber = Marshal.GetLastWin32Error();
int retValue;
//Set data to bitmap
for (int i = 0; i < 100; i++)
{
retValue = SetDIBits((System.IntPtr)winPtr, m_Bitmap, (uint)i, 1, testGraphicArray, ref m_Bmi, (uint)0L);
}
errorNumber = Marshal.GetLastWin32Error();
// Draw the bitmap
if (m_Bitmap != (IntPtr)0)
{
IntPtr hMemDC;
IntPtr Old;
hMemDC = CreateCompatibleDC((System.IntPtr)winPtr);
Old = SelectObject(hMemDC, m_Bitmap);//Select out what was in DC
bool success = BitBlt((System.IntPtr)winPtr, 10, 10, m_Bmh.biWidth, m_Bmh.biHeight, hMemDC, 0, 0, TernaryRasterOperations.SRCCOPY);
errorNumber = Marshal.GetLastWin32Error();
SelectObject(hMemDC, Old);//Put back in the previous stuff back into DC
}
ReleaseDC(this.Handle, winPtr);
}
Is the double-buffering style set?
If so, then .NET arranges for e.Graphics
in OnPaint
to be an in-memory DC, and after the Paint
routine completes, .NET will overwrite everything on-screen from that in-memory layer.
Make sure your control styles are set appropriately. I think you want AllPaintingInWmPaint
turned on, and double buffering turned off.
You're missing a number of other things that are necessary for properly handling WM_PAINT
using native APIs, though, such as using the device context returned by BeginPaint
and later calling EndPaint
. You may need to handle WM_PAINT
from WndProc
and not let .NET dispatch it to OnPaint
and the Paint
event handlers.
I hope you're doing this to learn about the Win32 GDI APIs, and not because you plan to draw on .NET Forms with them in a finished application.
User contributions licensed under CC BY-SA 3.0