我正在使用WPF的屏幕捕获应用程序。我需要捕获应用程序窗口。我有一个捕获窗口的代码,但也有背景。我不希望捕获背景,只是窗口,如果它被调整大小,仍然只有窗口应该在运行时捕获。我对WPF有点新意。请帮我解决一下这个。 这是我的代码:
private void ShowExistingWindow(string processName)
{
var processes = Process.GetProcessesByName(processName);
foreach (var process in processes)
{
// the single-instance already open should have a MainWindowHandle
if (process.MainWindowHandle != IntPtr.Zero)
{
// restores the window in case it was minimized
ShowWindow(process.MainWindowHandle, SW_SHOWNORMAL);
// brings the window to the foreground
SetForegroundWindow(process.MainWindowHandle);
}
}
}
此代码的问题在于,它会使窗口恢复并将其与背景一起捕获。
这是我用于捕获窗口的代码,
public static BitmapSource CaptureWindow(IntPtr hWnd,bool recolorBackground,Color substituteBackgroundColor,bool addToClipboard)
{
Int32Rect rect = GetWindowActualRect(hWnd);
Window blankingWindow = null;
if (recolorBackground)
{
blankingWindow = new Window();
blankingWindow.WindowStyle = WindowStyle.None;
blankingWindow.Title = string.Empty;
blankingWindow.ShowInTaskbar = false;
blankingWindow.AllowsTransparency = true;
blankingWindow.Background = new SolidColorBrush(substituteBackgroundColor);
blankingWindow.Show();
int fudge = 20;
blankingWindow.Left = rect.X - fudge / 2;
blankingWindow.Top = rect.Y - fudge / 2;
blankingWindow.Width = rect.Width + fudge;
blankingWindow.Height = rect.Height + fudge;
}
// bring the to-be-captured window to capture to the foreground
// there's a race condition here where the blanking window
// sometimes comes to the top. Hate those. There is surely
// a non-WPF native solution to the blanking window which likely
// involves drawing directly on the desktop or the target window
SetForegroundWindow(hWnd);
BitmapSource captured = CaptureRegion(
hWnd,
rect.X,
rect.Y,
rect.Width,
rect.Height,
true);
if (blankingWindow != null)
blankingWindow.Close();
return captured;
}
// this accounts for the border and shadow. Serious fudgery here.
private static Int32Rect GetWindowActualRect(IntPtr hWnd)
{
Win32Rect windowRect = new Win32Rect();
Win32Rect clientRect = new Win32Rect();
User32.GetWindowRect(hWnd, out windowRect);
User32.GetClientRect(hWnd, out clientRect);
int sideBorder = (windowRect.Width - clientRect.Width)/2 + 1;
// sooo, yeah.
const int hackToAccountForShadow = 4;
Win32Point topLeftPoint = new Win32Point(windowRect.Left - sideBorder, windowRect.Top - sideBorder);
User32.ClientToScreen(hWnd, ref topLeftPoint);
Int32Rect actualRect = new Int32Rect(
topLeftPoint.X,
topLeftPoint.Y,
windowRect.Width + sideBorder * 2 + hackToAccountForShadow,
windowRect.Height + sideBorder * 2 + hackToAccountForShadow);
return actualRect;
}
public static BitmapSource CaptureRegion(IntPtr hWnd,int x,int y,int width,int height,bool addToClipboard) {
IntPtr sourceDC = IntPtr.Zero;
IntPtr targetDC = IntPtr.Zero;
IntPtr compatibleBitmapHandle = IntPtr.Zero;
BitmapSource bitmap = null;
try
{
width = User32.GetSystemMetrics(User32.SCREEN_X);
height = User32.GetSystemMetrics(User32.SCREEN_Y);
// gets the main desktop and all open windows
sourceDC = GetDC(GetDesktopWindow());
//sourceDC = User32.GetDC(hWnd);
targetDC = CreateCompatibleDC(sourceDC);
// create a bitmap compatible with our target DC
compatibleBitmapHandle = CreateCompatibleBitmap(sourceDC, width, height);
// gets the bitmap into the target device context
SelectObject(targetDC, compatibleBitmapHandle);
// copy from source to destination
BitBlt(targetDC, 0, 0, width, height, sourceDC, x, y, SRCCOPY);
// Here's the WPF glue to make it all work. It converts from an
// hBitmap to a BitmapSource.
bitmap = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
compatibleBitmapHandle, IntPtr.Zero, Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
}
catch (Exception ex)
{
throw new Exception(string.Format("Error capturing region {0},{1},{2},{3}", x, y, width, height), ex);
}
finally
{
DeleteObject(compatibleBitmapHandle);
ReleaseDC(IntPtr.Zero, sourceDC);
ReleaseDC(IntPtr.Zero, targetDC);
}
return bitmap;
}