淺析如何用C#.NET做螢幕截圖軟體以及註冊全域快速鍵(上)

來源:互聯網
上載者:User

  最近為了學習C#,決定自己做一個螢幕工具,來代替長久以來每次都要按下PrintScreen鍵然後到Clipboard裡面尋找之麻煩。學以致用~
用C#做螢幕,大致有三種方法。

1、最managed大概就是使用Graphics.CopyFromScreen()方法,此方法有四個重載,不過經反編可見最後調用的都是:

CopyFromScreen(int sourceX, int sourceY, int destinationX, int destinationY, Size blockRegionSize, CopyPixelOperation copyPixelOperation)

 

調用該方法的優點是代碼簡單,不用平台叫用。不過最大的缺點是:不能截取半透明表單。你要想透明表單的話,可以加一個參數,它就是:CopyPixelOperation.CaptureBlt。但是,這樣的話,只能透明表單,截不到螢幕的其他部分了。所以,該方法已經基本可以放棄了。不過我們還是來研究了一下CopyFromScreen()的內部實現吧,看看問題之所在。下面是該方法的具體實現,reflect自System.Drawing.dll

 

CopyFromScreen

public void CopyFromScreen(int sourceX, int sourceY, int destinationX, int destinationY, Size blockRegionSize, CopyPixelOperation copyPixelOperation)
{
switch (copyPixelOperation)
{
case CopyPixelOperation.NotSourceErase:
case CopyPixelOperation.NotSourceCopy:
case CopyPixelOperation.NoMirrorBitmap:
case CopyPixelOperation.Blackness:
case CopyPixelOperation.SourceErase:
...
case CopyPixelOperation.SourceCopy:
case CopyPixelOperation.SourceAnd:
case CopyPixelOperation.MergePaint:
case CopyPixelOperation.SourcePaint:
case CopyPixelOperation.PatCopy:
case CopyPixelOperation.PatPaint:
case CopyPixelOperation.Whiteness:
case CopyPixelOperation.CaptureBlt:
{
new UIPermission(UIPermissionWindow.AllWindows).Demand();
int width = blockRegionSize.Width;
int height = blockRegionSize.Height;
using (DeviceContext context = DeviceContext.FromHwnd(IntPtr.Zero))
{
HandleRef hSrcDC = new HandleRef(null, context.Hdc);
HandleRef hDC = new HandleRef(null, this.GetHdc());
try
{
if (SafeNativeMethods.BitBlt(hDC, destinationX, destinationY, width, height, hSrcDC, sourceX, sourceY, (int) copyPixelOperation) == 0)
{
throw new Win32Exception();
}
}
finally
{
this.ReleaseHdc();
}
}
return;
}
}
throw new InvalidEnumArgumentException("value", (int) copyPixelOperation, typeof(CopyPixelOperation));
}

通過上面代碼可知,類庫裡面最後調用的是windows 的API :BitBlt(),這就是我們要說的第二種方法。

2、平台叫用,即調用windows的API函數。其中要用到的最主要的就是BitBlt()。在此,本人先給各位推薦個網站,它就是:www.pinvoke.net,一個包含幾乎所有API的wiki,裡面一般還含有範例程式碼~為了便於沒有網路的情況下查詢,本人已經把該網站拷貝下來了。。耗費了一天時間做成CHM。。。
先來看看BitBlt()的description:The BitBlt function performs a bit-block transfer of the color data corresponding to a rectangle of pixels from the specified source device context into a destination device context.
這裡,我們只關心它的最後一個參數/// <param name="dwRop">A raster-operation code.</param>
中文翻譯大概叫作:光柵作業碼。大概就是控制從source device context 到 destination device context的拷貝方式。它是一個DWORD類型,取值在

// Summary:    //     Determines how the source color in a copy pixel operation is combined with    //     the destination color to result in a final color.    public enum CopyPixelOperation    {        // Summary:        //     The bitmap is not mirrored.        NoMirrorBitmap = -2147483648,        //        // Summary:        //     The destination area is filled by using the color associated with index 0        //     in the physical palette. (This color is black for the default physical palette.)        Blackness = 66,        //        // Summary:        //     The source and destination colors are combined using the Boolean OR operator,        //     and then resultant color is then inverted.        NotSourceErase = 1114278,        //        // Summary:        //     The inverted source area is copied to the destination.        NotSourceCopy = 3342344,        //        // Summary:        //     The inverted colors of the destination area are combined with the colors        //     of the source area using the Boolean AND operator.        SourceErase = 4457256,        //        // Summary:        //     The destination area is inverted.        DestinationInvert = 5570569,        //        // Summary:        //     The colors of the brush currently selected in the destination device context        //     are combined with the colors of the destination are using the Boolean XOR        //     operator.        PatInvert = 5898313,        //        // Summary:        //     The colors of the source and destination areas are combined using the Boolean        //     XOR operator.        SourceInvert = 6684742,        //        // Summary:        //     The colors of the source and destination areas are combined using the Boolean        //     AND operator.        SourceAnd = 8913094,        //        // Summary:        //     The colors of the inverted source area are merged with the colors of the        //     destination area by using the Boolean OR operator.        MergePaint = 12255782,        //        // Summary:        //     The colors of the source area are merged with the colors of the selected        //     brush of the destination device context using the Boolean AND operator.        MergeCopy = 12583114,        //        // Summary:        //     The source area is copied directly to the destination area.        SourceCopy = 13369376,        //        // Summary:        //     The colors of the source and destination areas are combined using the Boolean        //     OR operator.        SourcePaint = 15597702,        //        // Summary:        //     The brush currently selected in the destination device context is copied        //     to the destination bitmap.        PatCopy = 15728673,        //        // Summary:        //     The colors of the brush currently selected in the destination device context        //     are combined with the colors of the inverted source area using the Boolean        //     OR operator. The result of this operation is combined with the colors of        //     the destination area using the Boolean OR operator.        PatPaint = 16452105,        //        // Summary:        //     The destination area is filled by using the color associated with index 1        //     in the physical palette. (This color is white for the default physical palette.)        Whiteness = 16711778,        //        // Summary:        //     Windows that are layered on top of your window are included in the resulting        //     image. By default, the image contains only your window. Note that this generally        //     cannot be used for printing device contexts.        CaptureBlt = 1073741824,    }

裡面。

現在繼續回來說截取透明表單的問題,我們知道它跟dwRop參數有關,在codeproject上面可以找到的源碼,調用BitBlt()時,都是這樣的:

BitBlt( hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, PlatformInvokeGDI32.TernaryRasterOperations.SourceCopy);

我想一般的螢幕軟體也是這樣做的,這樣做的話,你是不能截取到透明表單的,我們應該改成這個樣子:

BitBlt( hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, (uint)(PlatformInvokeGDI32.TernaryRasterOperations.SourceCopy | PlatformInvokeGDI32.TernaryRasterOperations.CaptureBlt) );

通過實驗可知是實現了預期效果。CaptureBlt的作用在上面~
需要注意的是,當我們使用BitBlt的時候,涉及裝置上下文控制代碼操作,需要用到另外幾個API函數來建立和釋放資源。貼個例子:

 

GetDesktopImage

public static Bitmap GetDesktopImage()
{
//In size variable we shall keep the size of the screen.
SIZE size;

//Variable to keep the handle to bitmap.
IntPtr hBitmap;

//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 using screen device context.
hBitmap = PlatformInvokeGDI32.CreateCompatibleBitmap(hDC, size.cx, size.cy);

//As hBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
if (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, hBitmap);
//We copy the Bitmap to the memory device context.
PlatformInvokeGDI32.BitBlt( hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, (uint)(PlatformInvokeGDI32.TernaryRasterOperations.SRCCOPY | PlatformInvokeGDI32.TernaryRasterOperations.CAPTUREBLT) );
//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 stored in local variable.
Bitmap bmp = System.Drawing.Image.FromHbitmap(hBitmap);
//Release the memory to avoid memory leaks.
PlatformInvokeGDI32.DeleteObject(hBitmap);
//This statement runs the garbage collector manually.
GC.Collect();
//Return the bitmap
return bmp;
}

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

 

 

可見雖然直接的平台叫用相比Graphics.CopyFromScreen()速度快,靈活,但是還是相當繁瑣的。涉及到控制代碼操作。這些操作在Graphics.CopyFromScreen()已經替我們做了。
下面來說第三種方法:

待續~淺析如何用C#.NET做螢幕軟體以及註冊全域快速鍵(下)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.