65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.62/5 (18投票s)

2007年9月6日

CPOL

3分钟阅读

viewsIcon

169540

downloadIcon

11720

这是一个简单的基于对话框的屏幕截图,它使用全局鼠标钩子来捕获用户选择的区域、控件(例如按钮等)以及任何其他窗口。

引言

我刚刚开始用 VC++ 编程,这是我在 CodeProject 上的第一篇文章。 我是在阅读了 CodeProject 本身提供的材料后创建了这个项目的。

每个人都知道每个 Microsoft Windows 都附带的屏幕截图(Prt Scr 按钮)实用程序。 那么为什么还需要另一个屏幕截图应用程序呢? 但 Windows 附带的屏幕截图实用程序非常简单,您只能截取整个屏幕。 但如果您必须截取屏幕的一部分,或者说只截取其他窗口上的特定控件,该怎么办? 别担心; 这是为此而设计的应用程序。 使用此应用程序,您可以捕获选定的区域,而不是整个窗口。 您还可以通过单击它来捕获任何窗口或控件。(您甚至可以只捕获任务栏上的开始按钮或时钟)。 这不是很好吗! 并且它为此使用了一个简单的 Win32 API 函数。

背景

本文使用了 Win32 API 的两个主要函数

  1. SetWindowsHookEx():设置全局鼠标钩子(有关此的更多帮助,请参阅 MSDN。)全局鼠标钩子对于从我们的窗口外部捕获鼠标事件是必需的。
  2. 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 截取 BegptEndpt 之间的区域,并将其发送到 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 撰写了关于扫雷游戏的精彩项目,我从中了解了全局钩子。

历史

应用程序的早期版本存在一个小缺陷。 当它截取窗口时,它未能截取标题栏,这也很重要。 我已在更新版本中修复了该问题。

© . All rights reserved.