屏幕截图(简单的 Win32 对话框式)






4.62/5 (18投票s)
这是一个简单的基于对话框的屏幕截图,它使用全局鼠标钩子来捕获用户选择的区域、控件(例如按钮等)以及任何其他窗口。
引言
我刚刚开始用 VC++ 编程,这是我在 CodeProject 上的第一篇文章。 我是在阅读了 CodeProject 本身提供的材料后创建了这个项目的。
每个人都知道每个 Microsoft Windows 都附带的屏幕截图(Prt Scr 按钮)实用程序。 那么为什么还需要另一个屏幕截图应用程序呢? 但 Windows 附带的屏幕截图实用程序非常简单,您只能截取整个屏幕。 但如果您必须截取屏幕的一部分,或者说只截取其他窗口上的特定控件,该怎么办? 别担心; 这是为此而设计的应用程序。 使用此应用程序,您可以捕获选定的区域,而不是整个窗口。 您还可以通过单击它来捕获任何窗口或控件。(您甚至可以只捕获任务栏上的开始按钮或时钟)。 这不是很好吗! 并且它为此使用了一个简单的 Win32 API 函数。
背景
本文使用了 Win32 API 的两个主要函数
SetWindowsHookEx()
:设置全局鼠标钩子(有关此的更多帮助,请参阅 MSDN。)全局鼠标钩子对于从我们的窗口外部捕获鼠标事件是必需的。BitBlt()
(发音为 Bitblit):用于在源设备上下文和目标设备上下文之间传输颜色数据。 它在这里用于截取屏幕。
Using the Code
MyMouseHook.cpp
以下是来自MyMouseHook.cpp 的代码。 在这里,当用户按下鼠标左键时,我们发送 MOUSE_DOWN
消息,当用户释放鼠标左键时,我们发送 MOUSE_UP
消息。 这两个都是用户消息。
LRESULT CALLBACK MyMouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
//Below Function will Return the Handle of window whose Caption is "Capture "
//We will use this handle to send Message.(Handle is handle to Our Application )
HWND hWndApp = FindWindow(0,L"Capture");
//Wpram will contain which mouse event has been generated
// We will send the User Message for each event we require.
if(wParam== WM_LBUTTONDOWN || wParam == WM_NCLBUTTONDOWN)
{
PostMessage(hWndApp,MOUSE_DOWN,0,0);
}
if(wParam == WM_LBUTTONUP)
{
PostMessage(hWndApp,MOUSE_UP,0,0);
}
}
ScreenCaptureDlg.cpp
以下是用于 ScreenCaptureDlg.cpp 文件的代码的一部分。 当用户在按下 Capture 按钮后第一次按下鼠标按钮时,我们将其作为 Begpt
中的起始点。 在拖动鼠标后,当用户释放按钮时,我们获取 Endpt
中选定矩形的终点。 然后我们从桌面到 MemDC
截取 Begpt
和 Endpt
之间的区域,并将其发送到 SaveBitmap()
函数,该函数将 DC 保存到 .bmp 文件中。 然后我们将创建一个进程来在 PAIN 应用程序中显示 .bmp 文件。 不要担心我在这里没有解释的其他函数。 我在代码中很好地解释了所有事情
case MOUSE_DOWN:
if(CaptureActWnd == TRUE)
{
GetCursorPos(&Begpt); //Will take the Cursor Position
hWndActWnd= WindowFromPoint(Begpt); //Will get the Handle of Window
//Where Your Mouse is Currently
CaptureActiveWindow(); //Will Call the Function to Capture
//That Window
EndDialog(hWndDlg,LOWORD(lParam)); //Will End the Dialog
PostQuitMessage(0); //Will destroy Window
}
OutputDebugString( L"Desktop -GDI, MOUSE_DOWN");
GetCursorPos(&Begpt); // Will Store the Current Cursor
// position in Begpt
break; // Mouse is Down Begpt.x = left,
// Begpt.y = Top
case MOUSE_UP:
if(CaptureActWnd == FALSE)
{
GetCursorPos(&Endpt); //As the Mouse is UP We will get Out Bottom
//Right Points in EndPt.
DrawBox(); //Will Draw the Rectangle Around selected area
// Create a memory device context Compatible with Dialog DC
MemDC = CreateCompatibleDC(DlgDC);
// Create a compatible bitmap
hBitmap = CreateCompatibleBitmap(DlgDC,width,height);
// Select the bitmap into the memory context
SelectObject(MemDC,hBitmap);
// This will copy the our Selected Area into MemDC
BitBlt(MemDC,0,0,width,height ,DeskDC,Begpt.x,Begpt.y,SRCCOPY);
//Will Save the Device Context into Sample.bmp
SaveBitmap(MemDC, hBitmap,"Sample.bmp");
//Will show you the Capture Area Into MSPAINT
ShowImage();
//Send Message to Quit the Window.
SendMessage(hWndDlg,WM_COMMAND,(WPARAM)IDC_Exit,0);
}
break;
关注点
我尝试捕获 WM_MOUSEMOVE
事件以在屏幕上绘制矩形,而不是仅捕获 WM_LBUTTONDOWN
和 WM_LBUTTONUP
,但这使得应用程序变得非常迟缓。 所以我放弃了它,只获取了起始点和终点来绘制矩形并截取屏幕。 因此,当您选择该区域时,您将无法看到矩形,但当您完成选择时,矩形将会出现。
特别感谢
感谢 Arun Krishnan 撰写了关于桌面日历的精彩文章,我从中了解到如何将 DC(Device Context) 保存在 .bmp 文件中。
感谢 Mumtaz Zaheer 撰写了关于扫雷游戏的精彩项目,我从中了解了全局钩子。
历史
应用程序的早期版本存在一个小缺陷。 当它截取窗口时,它未能截取标题栏,这也很重要。 我已在更新版本中修复了该问题。