获取Win32 API在表单上绘制一个正方形

时间:2012-01-12 16:37:32

标签: c# winapi gdi

是的 - 我知道这并不令人兴奋 - 但我的同事可以在C程序中使用相同的伪代码,它显示带有一些绿色条带的黑色方块 - 但在C#中它只绘制一个黑色方块 - 见下文:

enter image description here

如果您在Form1的部分类(一个新的默认Windows应用程序)中复制下面的代码 - 您将看到我的问题。 我已经尝试了一百万种不同的东西 - 但我想我是如何规定Win32的电话或其他东西 - 如果有人可以帮助我出错的地方 - 我将非常感激。

下面的代码看起来很长,但我决定把它全部放进去,所以很容易复制/粘贴到标准表格的部分类中 - 所以不要让它吓到你!

 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);   
        }

1 个答案:

答案 0 :(得分:1)

是否设置了双缓冲样式?

如果是这样,那么.NET会在e.Graphics中安排OnPaint作为内存中的DC,并且在Paint例程完成后,.NET将覆盖屏幕上的所有内容。那个内存层。

确保您的控件样式设置正确。我想你想要AllPaintingInWmPaint开启,双缓冲关闭。

您缺少使用本机API正确处理WM_PAINT所需的其他一些事项,例如使用BeginPaint返回的设备上下文,然后调用EndPaint 。您可能需要处理来自WM_PAINT的{​​{1}},而不是让.NET将其发送给WndProcOnPaint事件处理程序。

我希望您这样做是为了了解Win32 GDI API,而不是因为您计划在完成的应用程序中使用.NET Forms进行绘制。