2012-01-12 111 views
1

是的 - 我知道这并不令人兴奋 - 但我的同事可以在C程序中获得相同的伪代码,它显示了带有一些绿色带的黑色正方形 - 但在C#中它只画一个黑色的正方形 - 见下:获取Win32 API在窗体上绘制一个正方形

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

你为什么不使用gdi +? – 2012-01-12 16:41:22

+1

这是一个很长的故事 - 但总之它的测试程序/控制更先进的东西,我超越了另一个软件的绘图功能。 – Vidar 2012-01-12 16:45:13

+0

SetDIBits()失败,m_Bmi未被初始化。这是“太本地化”问题的标志,使得这些代码无效。使用System.Drawing。 – 2012-01-12 16:58:37

回答

1

是双缓冲样式集?

如果是这样,则.NET安排在OnPainte.Graphics为一个内存DC,和Paint例程完成后,.NET将覆盖从内存层屏幕上的一切。

确保您的控件样式设置得当。我想你想打开AllPaintingInWmPaint,并关闭双缓冲。

你错过了一些其他的事情,需要使用本地API妥善处理WM_PAINT,但是,如使用BeginPaint后来打电话EndPaint返回的设备上下文。您可能需要从WndProc处理WM_PAINT,并且不让.NET将它分派到OnPaintPaint事件处理程序。

我希望你这样做是为了了解Win32 GDI API,而不是因为你打算在完成的应用程序中使用它们来绘制.NET Forms。

+0

不 - 我必须为我想要做的事情学习Win32 API - 我永远不会梦想通常这样做,因为它是疯了! :) – Vidar 2012-01-12 16:53:08