Recently, in order to learn C #, I decided to create a screen tool by myself, instead of pressing the printscreen key every time for a long time and then going to the clipboard to find the trouble. What you have learned ~
There are three methods to use C # For screen creation.
1. The most managed method is probably using the graphics. copyfromscreen () method. This method has four reloads, but the last called after reverse encoding is:
CopyFromScreen(int sourceX, int sourceY, int destinationX, int destinationY, Size blockRegionSize, CopyPixelOperation copyPixelOperation)
The advantage of calling this method is that the code is simple and does not need to be called by the platform. However, the biggest drawback is that a translucent form cannot be captured. To make the form transparent, you can add a parameter: copypixeloperation. captureblt. However, in this case, only transparent forms are allowed, and other parts of the screen are not captured. Therefore, this method can be basically abandoned. But let's take a look at the internal implementation of copyfromscreen () to see where the problem is. The specific implementation of this method is as follows: reflect from 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));
}
The code above shows that the class library finally calls the Windows API: bitblt (), which is the second method.
2. Platform call: Call Windows API functions. The most important thing to use is bitblt (). Here, I would like to recommend a Website: www.pinvoke.net, a wiki containing almost all APIs, which usually contains sample code ~ I have copied the website to make it easier to query without a network .. It took a day to make it into CHM...
Let's take a look at the description of bitblt (): 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.
Here, we only care about its last parameter // <Param name = "dwrop"> A raster-operation code. </param>
The Chinese translation is probably called the grating operation code. It is probably to control the copy mode from source device context to destination device context. It is a DWORD type, with a value in
// 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, }
.
Now let's continue to talk about the issue of intercepting transparent forms. We know that it is related to the dwrop parameter. The source code that can be found in the codeproject is like this when bitblt () is called:
BitBlt( hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, PlatformInvokeGDI32.TernaryRasterOperations.SourceCopy);
I think this is also the case for general screen software. In this case, you cannot take a transparent form. We should change it to this:
BitBlt( hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, (uint)(PlatformInvokeGDI32.TernaryRasterOperations.SourceCopy | PlatformInvokeGDI32.TernaryRasterOperations.CaptureBlt) );
The test shows that the expected results are achieved. The role of captureblt is above ~
When using bitblt, you need to use several API functions to create and release resources. Example:
Getshorttopimage
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;
}
Although direct platform calling is faster and more flexible than graphics. copyfromscreen (), it is still quite tedious. Handle operations are involved. These operations have been done for us in graphics. copyfromscreen.
The third method is as follows:
To be continued ~ How to use C #. Net for screen software and register global shortcuts (below)