简介
使用IntPtr方式对窗口截图,可以避免被其它窗体遮挡而影响截图效果的问题。
步骤
- 通过Spy++或其他工具,获取指定窗口的IntPtr
- 调用CaptureWindow方法截图
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
#region
enum GetWindowCmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
#endregion
class ScreenCapture
{
[DllImport("user32.dll")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern IntPtr GetWindowRect(IntPtr hWnd, out RECT rect);
[DllImport("user32.dll")]
private static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, UInt32 nFlags);
[DllImport("user32.dll")]
private static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, GetWindowCmd uCmd);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateDC(
string lpszDriver, // driver name驱动名
string lpszDevice, // device name设备名
string lpszOutput, // not used; should be NULL
IntPtr lpInitData // optional printer data
);
[DllImport("gdi32.dll")]
private static extern int BitBlt(
IntPtr hdcDest, // handle to destination DC目标设备的句柄
int nXDest, // x-coord of destination upper-left corner目标对象的左上角的X坐标
int nYDest, // y-coord of destination upper-left corner目标对象的左上角的Y坐标
int nWidth, // width of destination rectangle目标对象的矩形宽度
int nHeight, // height of destination rectangle目标对象的矩形长度
IntPtr hdcSrc, // handle to source DC源设备的句柄
int nXSrc, // x-coordinate of source upper-left corner源对象的左上角的X坐标
int nYSrc, // y-coordinate of source upper-left corner源对象的左上角的Y坐标
CopyPixelOperation dwRop // raster operation code光栅的操作值
);
//static extern int BitBlt(IntPtr hdcDest, int xDest, int yDest, int
//wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, CopyPixelOperation rop);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateCompatibleDC(
IntPtr hdc // handle to DC
);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateCompatibleBitmap(
IntPtr hdc, // handle to DC
int nWidth, // width of bitmap, in pixels
int nHeight // height of bitmap, in pixels
);
[DllImport("gdi32.dll")]
private static extern IntPtr SelectObject(
IntPtr hdc, // handle to DC
IntPtr hgdiobj // handle to object
);
[DllImport("gdi32.dll")]
private static extern int DeleteDC(
IntPtr hdc // handle to DC
);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
//[DllImport("User32.dll", CharSet = CharSet.Auto)]
//public static extern int GetClassName(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);
public IntPtr GetFistChildHandle(IntPtr parent)
{
return GetWindow(parent, GetWindowCmd.GW_CHILD);
}
public IntPtr GetNextHandle(IntPtr ptr)
{
return GetWindow(ptr, GetWindowCmd.GW_HWNDNEXT);
}
public string GetClassName(IntPtr ptr)
{
StringBuilder builder = new StringBuilder(20);
GetClassName(ptr, builder, 20);
return builder.ToString();
}
public IntPtr FindHandleByClassName(IntPtr parent, string className)
{
IntPtr childHandle = GetFistChildHandle(parent);
while (childHandle != IntPtr.Zero)
{
string cName = GetClassName(childHandle);
if (cName.Trim().ToLower() == className.Trim().ToLower())
{
return childHandle;
}
childHandle = GetNextHandle(childHandle);
}
return IntPtr.Zero;
}
/// <summary>
/// 抓取屏幕(层叠的窗口)
/// </summary>
/// <param name="x">左上角的横坐标</param>
/// <param name="y">左上角的纵坐标</param>
/// <param name="width">抓取宽度</param>
/// <param name="height">抓取高度</param>
/// <returns></returns>
public Bitmap CaptureScreen(int x, int y, int width, int height)
{
Bitmap bmp = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.CopyFromScreen(new Point(x, y), new Point(0, 0), bmp.Size);
g.Dispose();
}
return bmp;
}
/// <summary>
/// 指定窗口截图
/// </summary>
/// <param name="handle">窗口句柄. (在windows应用程序中, 从Handle属性获得)</param>
/// <returns></returns>
public Bitmap CaptureWindow(IntPtr hWnd)
{
IntPtr hscrdc = GetWindowDC(hWnd);
RECT rect = new RECT();
return CaptureWindow(hWnd, rect);
}
/// <summary>
/// 指定窗口区域截图
/// </summary>
/// <param name="handle">窗口句柄. (在windows应用程序中, 从Handle属性获得)</param>
/// <param name="rect">窗口中的一个区域</param>
/// <returns></returns>
public Bitmap CaptureWindow(IntPtr hWnd, RECT rect)
{
// 获取设备上下文环境句柄
IntPtr hscrdc = GetWindowDC(hWnd);
// 创建一个与指定设备兼容的内存设备上下文环境(DC)
IntPtr hmemdc = CreateCompatibleDC(hscrdc);
IntPtr myMemdc = CreateCompatibleDC(hscrdc);
// 返回指定窗体的矩形尺寸
RECT rect1;
GetWindowRect(hWnd, out rect1);
// 返回指定设备环境句柄对应的位图区域句柄
IntPtr hbitmap = CreateCompatibleBitmap(hscrdc, rect1.Right - rect1.Left, rect1.Bottom - rect1.Top);
IntPtr myBitmap = hbitmap;// CreateCompatibleBitmap(hscrdc, rect.Right - rect.Left, rect.Bottom - rect.Top);
//把位图选进内存DC
// IntPtr OldBitmap = (IntPtr)SelectObject(hmemdc, hbitmap);
SelectObject(hmemdc, hbitmap);
SelectObject(myMemdc, myBitmap);
/////////////////////////////////////////////////////////////////////////////
//
// 下面开始所谓的作画过程,此过程可以用的方法很多,看你怎么调用 API 了
//
/////////////////////////////////////////////////////////////////////////////
// 直接打印窗体到画布
PrintWindow(hWnd, hmemdc, 0);
// IntPtr hw = GetDesktopWindow();
// IntPtr hmemdcClone = GetWindowDC(myBitmap);
BitBlt(myMemdc, 0, 0, rect.Right - rect.Left, rect.Bottom - rect.Top, hmemdc, rect.Left, rect.Top, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
//SelectObject(myMemdc, myBitmap);
Bitmap bmp = Bitmap.FromHbitmap(myBitmap);
DeleteDC(hscrdc);
DeleteDC(hmemdc);
DeleteDC(myMemdc);
return bmp;
}
}