一段.NET调用WINAPI实现截图代码的BUG。

由于工作需要,在网上找到一段关于.NET调用WIN API实现截图的代码。
    public static Bitmap GetDesktopImage()
    
{
      
//In size variable we shall keep the size of the screen.
      SIZE size;
      
      
//Here we get the handle to the desktop device context.
      IntPtr   hDC = PlatformInvokeUSER32.GetDC(PlatformInvokeUSER32.GetDesktopWindow()); 

      
//Here we make a compatible device context in memory for screen device context.
      IntPtr hMemDC = PlatformInvokeGDI32.createCompatibleDC(hDC);
      
      
//We pass SM_CXSCREEN constant to GetSystemMetrics to get the X coordinates of screen.
      size.cx = PlatformInvokeUSER32.GetSystemMetrics(PlatformInvokeUSER32.SM_CXSCREEN);

      
//We pass SM_CYSCREEN constant to GetSystemMetrics to get the Y coordinates of screen.
      size.cy = PlatformInvokeUSER32.GetSystemMetrics(PlatformInvokeUSER32.SM_CYSCREEN);
      
      
//We create a compatible bitmap of screen size and using screen device context.
      m_HBitmap = PlatformInvokeGDI32.createCompatibleBitmap(hDC, size.cx, size.cy);

      
//As m_HBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
      if (m_HBitmap!=IntPtr.Zero)
      
{
        
//Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
        IntPtr hOld = (IntPtr) PlatformInvokeGDI32.selectObject(hMemDC, m_HBitmap);
        
//We copy the Bitmap to the memory device context.
        PlatformInvokeGDI32.BitBlt(hMemDC, 00,size.cx,size.cy, hDC, 00, PlatformInvokeGDI32.SRCCOPY);
        
//We select the old bitmap back to the memory device context.
        PlatformInvokeGDI32.selectObject(hMemDC, hOld);
        
//We delete the memory device context.
        PlatformInvokeGDI32.deleteDC(hMemDC);
        
//We release the screen device context.
        PlatformInvokeUSER32.ReleaseDC(PlatformInvokeUSER32.GetDesktopWindow(), hDC);
        
//Image is created by Image bitmap handle and returned.
        return System.Drawing.Image.FromHbitmap(m_HBitmap); 
      }

      
//If m_HBitmap is null retunrn null.
      return null;
    }
 

实际运行40次左右就出现错误,CodeError=8,用VC错误代码查看器查看显示为:内存不足。
问题出现在return System.Drawing.Image.FromHbitmap(m_HBitmap); 这一句话。
.NET调用WINAPI创建了一个DC资源后,直接返回到托管代码,并没有显式释放DC资源,运行多次后,系统DC资源被用尽,所以报错。
具体修改方法是利用WIN API的deleteObject(InPtr)释放DC资源。
将如下代码:
return System.Drawing.Image.FromHbitmap(m_HBitmap); 

修改为:

Bitmap bmp = System.Drawing.Image.FromHbitmap(m_HBitmap);
PlatformInvokeGDI32.deleteObject(m_HBitmap);
return bmp;

这样问题就解决了。使用.NET 调用WIN API 时一定要小心系统资源释放的问题,平时用惯了.NET的垃圾收集往往会忽视,导致
程序稳定性很差。

posted on 2004-07-14 23:48  石开  阅读(3122)  评论(6)    收藏  举报

导航