手把手教你写截图软件!其实写这个程序是受到尘封同学的启发,他写了个窗口截图程序,可是问题在于只能截窗口,似乎和我们常用的QQ截图不一样,由于我当时在网吧,身上没有U盘,没能拷回去研究,所以如果什么地方说错了敬请尘封同学原谅!他在留言中给出了一个关键函数,里面首先用到了GetForegroundWindow,我回去查了下MSDN,结果如下:The GetForegroundWindow function returns a handle to the foreground window (the window with which the user is currently working). The system assigns a slightly higher priority to the thread that creates the foreground window thanit does to other threads. 通俗的讲就是获取一个当前激活的窗口句柄Return ValuesThe return value is a handle to the foreground window. The foreground window can be NULL in certain circumstances, such as when a window is losing activation 这里我发现一个问题,也就是函数可能返回null,在某种情况下。
所以我想尘封的窗口截图不一定能每次成功出于兴趣,我写一个类似QQ的截图程序(当时想了也觉得不怎么难,就是用几个GDI函数),现在就当给初学者点动力(你们完全有能力写),手把手教你们(大牛别笑我!)首先,先思考截图原理是什么样的?我做过这样一个实验,我先运行我的笑脸程序,然后启动浏览器的截图功能,这时笑脸静止了,而当取消截图时,笑脸又开始运动了。
这说明在截图的过程中整个画面是静止的。
现在的问题是,如何使整个画面静止?方法很简单:先创建一个内存DC保存当前桌面背景,然后创建一个WS_POPUP风格的全屏窗口,并把这个窗口的背景图案设置为先前创建的内存DC。
好了,现在就等于在一个窗口上截图了,这个还不简单?只要记录拖放鼠标的起点位置和终点位置,不就知道要截的是哪块区域了吗?这里还有个问题,大家记不记得再用QQ截图时,拖放鼠标会出现一个矩形,我们当然也要画一个矩形,这里用DrawFocusRect(具体用法参照MSDN)接着就是把这个截图区域保存下来,然后让那个全屏窗口自动退出,最后把这个截图显示在我们的窗口中,好了大功告成!关于我的程序,我有几点想说1.菜单项中只有“截图”有效,其他菜单项消息我并没有处理2.我本来也想保存为图片,但尘封用的那个函数我在MSDN中居然没查到,所以如果你有兴趣可以尝试着做3.拖放矩形时如果选择了一点拖,就只能往这一点的斜下方拖(因为我预先把起点保存在Rect.top和Rect.left,也就是规定了起点是左上角)4.不能截视频(以为截图原理不一样,你用QQ也是不能截的)写完这个程序我突然想到了点事情,有时候一个有用有趣的软件,并不需要太多高深的技术(我这话不是否认算法的重要性),他有时候需要的是一种创意。
你说QQ截图给我们日常生活中带来多少欢乐,多少便利!但是说到底,也就是那么几个GDI函数?我们不是科学家,我们所做的也许更多在于方便用户,所以观众身边人,关注他们需要什么,也许灵感就会降落在你头上!想想“搜狗拼音”,其实技术早就存在了,只是没人应用到这打字上来,但是终归有人是有心人,做了尝试(据说这人一开始到百度遭拒,后来被搜狐相中),后来搜狗就像那一夜春风,千树万树梨花开至于细节下次再说吧,看看效果:感谢你提出问题,不过你指的不可以截图是截图没反应还是点击截图然后死机我测试了八台XP电脑,运行的很流畅,多次截图也成功,然后又测试了四台Vista电脑,其中三台运行良好(但没有xp好),另外一台就死机了(至于为什么我也不知道)先确认下你操作无误!你点击截图选项后,若立马点击鼠标右键,则退出截图要想截图,必须点击截图选项后,点击鼠标左键(保持不放),然后拖动鼠标来截图首先我要声明,当时我写这个程序的时候用的是WIN32汇编,不是c语言(这也是为什么我不贴代码的原因),但是在下面的叙述中,为了方便大家学习,我采用c语言描述,里面也许会出现语法问题(本人未用过c写windows程序),希望大家不要在意这些,抓住整体,把握主要思路就行了谢谢!创建程序的主窗口如下图所示:1.在注册主程序窗口类时我们要做下面一件事;****************************************************************************** *********************;创建位图画刷(主要是为了美观);****************************************************************************** *********************hPatternBrush = CreatePatternBrush(LoadBitmap,hInstance,IDB_BACK) stWndClass.hbrBackground = hPatternBrush2.在这个主窗口的WM_CREATE消息中,我们要做一下几件事情:;****************************************************************************** *********************;获得屏幕大小;****************************************************************************** *********************dwWidth = GetSystemMetrics,SM_CXSCREEN ;屏幕宽dwHeight = GetSystemMetrics,SM_CYSCREEN ;屏幕高dwCutWidth = WINDOW_SIZE ;初始化截图宽和高(WINDOW_SIZE)为窗口大小dwCutHeight = WINDOW_SIZE;****************************************************************************** *********************;创建屏幕背景DC和截图DC;****************************************************************************** *********************hScreenDC = GetDC,NULL ;获取屏幕DChBkDC = CreateCompatibleDC,hScreenDC ;创建与屏幕DC相兼容的内存DC(用来保存整个桌面背景)hCutDC = CreateCompatibleDC,hScreenDC ;同上(不过是用来保存截图)hBmp = CreateCompatibleBitmap,hScreenDC,dwWidth,dwHeight ;创建一副位图然后选入DC,这里要注意CreateCompatibleBitmap的第一个参数要用GetDC的返回SelectObject,hBkDC,hBmp ;值,而不能用CreateCompatibleDC的放回值DeleteObject,hBmphBmp = CreateCompatibleBitmap,hScreenDC,dwWidth,dwHeightSelectObject,hCutDC,hBmpDeleteObject,hBmp;****************************************************************************** *********************;使用位图画刷;****************************************************************************** *********************SelectObject,hCutDC,hPatternBrushPatBlt,hCutDC,0,0,WINDOW_SIZE,WINDOW_SIZE,PATCOPY ;因为在截图之前截图DC中什么图案也没,所以为了美观,我们先用画刷图案填充下以上就是我们要在WM_CREATE中要做的事情,我们可以把他们统一写到Init函数中,然后调用3.处理WM_PAINT消息:hDc = BeginPaint,hWnd,&stPSBitBlt,hDc,0,0,dwCutWidth,dwCutHeight,hCutDC,0,0,SRCCOPY ;就是通过这个BitBlt,把图案显示到窗口上(其实还可以再处理下stPS结构,因为只要处理无效区EndPaint,hWnd,&stPS接下来就是响应窗口中截图选项:1.通过另一个线程来创建全屏窗口:CreateThread,NULL,NULL,offset _CreateBk ,NULL,NULL,NULL ;_CreateBk为线程函数(似乎高级语言中不建议直接用CreateThread)在这个函数中我们要做下面几件事情:;****************************************************************************** *********************;创建一个窗口用来静态保存桌面;****************************************************************************** *********************BitBlt,hBkDC,0,0,dwWidth,dwHeight,hScreenDC,0,0,SRCCOPY ;把整个屏幕图像画到屏幕DC中hWin = CreateWindowEx,WS_EX_TOPMOST,offset szScreenClass,NULL,WS_POPUP,0,0,dwWidth,dwHeight,NULL,NULL,hInstance,NULL ;创建全屏窗口ShowWindow,hWin,SW_MAXIMIZE ;最大化显示UpdateWindow,hWin;****************************************************************************** *********************;消息循环;****************************************************************************** *********************这里略(因为和之前的没有任何区别)2.全屏窗口消息的处理这里最重要的有4个消息:WM_RBUTTONDOWN,WM_LBUTTONDOWN,WM_LBUTTONUP,WM_MOUSEMOVE 当选择截图项后,若我们立马点了鼠标右键(WM_RBUTTONDOWN),就说明要退出截图(也就是要退出全屏窗口),我们要这样子做:SendMessage,hWin,WM_CLOSE,0,0 ;hWin为全屏窗口的句柄dwFlag = 0 ;截图标志复位当选择截图项后,若我们点了鼠标左键(WM_LBUTTONUP),就说明要开始截图了,我们要这样子做:dwFlag = 1 ;截图标志置位GetCursorPos,&stPoint ;获取截图起点位置(并保存在左上角,这样导致就只能往“下”拖)stRect.left = stPoint.xstRect.top = stPoint.y在拖动矩形框的时候我们要响应WM_MOUSEMOVE消息:(DrawFocusRect自己MSDN,但同一个矩形DrawFocusRect两次的话,原来线框会消息,因为它采用异或方式画虚线框)if dwFlag ;只有开始截图了(dwFlag置位时),才响应WM_MOUSEMOVE的消息{if dwFlag > 1DrawFocusRect,hScreenDC,&stRect ;取消上次画的矩形GetCursorPos,&stPoint ;当前矩形的右下角stRect.right = stPoint.xstRect.bottom = stPoint.yDrawFocusRect,hScreenDC,addr stRect ;画当前矩形dwFlag++}鼠标一直拖动拖动,当鼠标左键弹起时,说明截图结束,我们要响应WM_LBUTTONUP消息:dwFlag = 0 ;复位截图标志,截图停止就不需要想要WM_MOUSEMOVE消息了GetCursorPos,&stPoint ;获取截图终点位置(右下角)mov eax,@stPoint.x ;获取截图的宽sub eax,stRect.leftmov dwCutWidth,eaxmov eax,@stPoint.y ;获取截图的高(偷懒下,不转换为c语言了)sub eax,stRect.topmov dwCutHeight,eaxBitBlt,hCutDC,0,0,dwCutWidth,dwCutHeight,hBkDC,stRect.left,stRect.top,SRCCOPY ;把截图图案画到截图DC中去InvalidateRect,hWinMain,NULL,TRUE ;强迫主窗口无效,为了显示截图图案SendMessage,hWin,WM_CLOSE,0,0 ;退出全屏窗口大体就是这样,其他还有些细节的工作,希望大家自己完成!。