简单截图软件的编写——心得总结
2010-06-26 11:10
302 查看
在公司不能用QQ,简单快捷的QQ截图就不能用了,面对工作中有时需要截屏记录的数据,时而感到烦躁不已。于是在某晚下定决心,自己编写一个截屏的小程序,以QQ截图为蓝本,打造山寨版QQ截图。
开发工具为:Visual Studio 2005
代码托管到了GitHub上:win32-screen-capture
语言用的是C++,此程序用纯Windows API编写。
一开始的想法就是要做成跟QQ截图差不多的玩意儿,所以在设计思路上参考了QQ的做法。首先QQ是通过点击按钮或触发快捷键来启动截图这个功能,在功能启动之后,会给屏幕“蒙”上一层深灰色的“膜”。随后通过鼠标左键的点击拖拽来确定截图区域,在确定截图区域之后就可以将该区域的图像截取并保存。
我的猜想是QQ在收到“启动截图”功能的消息时会创建一个新的窗口,此窗口为透明且永远在最前,这就是我们观感上那层灰色的“膜”。然后由此窗口来接受鼠标的划定区域消息,此区域通过在膜窗口中点击鼠标左键和拖拽创建矩形而确定。在划定区域后,所要做的事情就比较简单了,主要有两件:1. 将位图信息写入剪切板。2. 将截图区域保存为常见图像格式。
好了,到目前为止,我已经完成了对QQ截图设计思路的分析,接下来的一步就是要想办法实现了。
首先要解决的问题是如何创建“膜”窗口,此窗口为透明且无标题栏。
我在网上搜索了一下如何建立透明窗口的文章,得到了以下结果:
在使用以上代码创建正常窗口后,在WM_CREATE响应代码中插入以上函数,即可实现窗口的无标题透明化。其中SetLayeredWindowsAttributes函数的功能是调整窗口的透明度,trans_degree即为窗口透明程度。0x80000为WS_EX_LAYERED属性,在为窗口设置该属性后才能将其变为透明。
接下来问题就是要保存截下来的图片,用以下代码实现:
至此,这个小截图工具就能够基本实现了,如何通过鼠标消息获取矩形区域在这里不再赘述。最后完成的程序能够截图保存为.BMP格式,但是图像未写入剪切板,此功能尚待添加。并且QQ截图圈定区域后能显示出该区域原本的像素值,此功能在最后完成的程序中也未实现。
这个小程序虽然很简单,但还是能够Windows程序设计的一些基本元素均有体现,但是功能尚未完善,还是那句老话,学习无止境,编程无黎明!
开发工具为:Visual Studio 2005
代码托管到了GitHub上:win32-screen-capture
语言用的是C++,此程序用纯Windows API编写。
一开始的想法就是要做成跟QQ截图差不多的玩意儿,所以在设计思路上参考了QQ的做法。首先QQ是通过点击按钮或触发快捷键来启动截图这个功能,在功能启动之后,会给屏幕“蒙”上一层深灰色的“膜”。随后通过鼠标左键的点击拖拽来确定截图区域,在确定截图区域之后就可以将该区域的图像截取并保存。
我的猜想是QQ在收到“启动截图”功能的消息时会创建一个新的窗口,此窗口为透明且永远在最前,这就是我们观感上那层灰色的“膜”。然后由此窗口来接受鼠标的划定区域消息,此区域通过在膜窗口中点击鼠标左键和拖拽创建矩形而确定。在划定区域后,所要做的事情就比较简单了,主要有两件:1. 将位图信息写入剪切板。2. 将截图区域保存为常见图像格式。
好了,到目前为止,我已经完成了对QQ截图设计思路的分析,接下来的一步就是要想办法实现了。
首先要解决的问题是如何创建“膜”窗口,此窗口为透明且无标题栏。
我在网上搜索了一下如何建立透明窗口的文章,得到了以下结果:
hwnd = CreateWindow( appName, _T( "Capture your window" ), WS_POPUP | WS_SYSMENU | WS_SIZEBOX, 0, 0, width, height, NULL, NULL, hInstance, NULL );
bool setTransparentWindow( HWND hwnd, int trans_degree ) { //加入WS_EX_LAYERED扩展属性 SetWindowLong( hwnd, GWL_EXSTYLE, GetWindowLong( hwnd, GWL_EXSTYLE ) ^ 0x80000 ); HINSTANCE hInst = LoadLibrary( _T( "User32.DLL" ) ); if( hInst ) { typedef BOOL (WINAPI *MYFUNC) ( HWND, COLORREF, BYTE, DWORD ); MYFUNC fun = NULL; //取得SetLayeredWindowAttributes函数指针 fun = (MYFUNC) GetProcAddress( hInst, "SetLayeredWindowAttributes" ); if( fun ) fun( hwnd, 0, trans_degree, 2 ); FreeLibrary( hInst ); } else return false; return true; }
在使用以上代码创建正常窗口后,在WM_CREATE响应代码中插入以上函数,即可实现窗口的无标题透明化。其中SetLayeredWindowsAttributes函数的功能是调整窗口的透明度,trans_degree即为窗口透明程度。0x80000为WS_EX_LAYERED属性,在为窗口设置该属性后才能将其变为透明。
接下来问题就是要保存截下来的图片,用以下代码实现:
HBITMAP CopyDCToBitmap(HDC hScrDC, LPRECT lpRect) { HDC hMemDC; // 屏幕和内存设备描述表 HBITMAP hBitmap,hOldBitmap; // 位图句柄 int nX, nY, nX2, nY2; // 选定区域坐标 int nWidth, nHeight; // 位图宽度和高度 // 确保选定区域不为空矩形 if (IsRectEmpty(lpRect)) return NULL; // 获得选定区域坐标 nX = lpRect->left; nY = lpRect->top; nX2 = lpRect->right; nY2 = lpRect->bottom; nWidth = nX2 - nX; nHeight = nY2 - nY; //为指定设备描述表创建兼容的内存设备描述表 hMemDC = CreateCompatibleDC(hScrDC); // 创建一个与指定设备描述表兼容的位图 hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight); // 把新位图选到内存设备描述表中 hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap); // 把屏幕设备描述表拷贝到内存设备描述表中 StretchBlt(hMemDC,0,0,nWidth,nHeight,hScrDC,nX,nY,nWidth,nHeight,SRCCOPY); //BitBlt(hMemDC, 0, 0, nWidth, nHeight,hScrDC, nX, nY, SRCCOPY); //得到屏幕位图的句柄 hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap); //清除 DeleteDC(hMemDC); DeleteObject(hOldBitmap); // 返回位图句柄 return hBitmap; } //把HBITMAP保存成位图 BOOL SaveBmp(HBITMAP hBitmap, LPCWSTR FileName) { HDC hDC; //当前分辨率下每象素所占字节数 int iBits; //位图中每象素所占字节数 WORD wBitCount; //定义调色板大小, 位图中像素字节大小 ,位图文件大小 , 写入文件字节数 DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0; //位图属性结构 BITMAP Bitmap; //位图文件头结构 BITMAPFILEHEADER bmfHdr; //位图信息头结构 BITMAPINFOHEADER bi; //指向位图信息头结构 LPBITMAPINFOHEADER lpbi; //定义文件,分配内存句柄,调色板句柄 HANDLE fh, hDib, hPal,hOldPal=NULL; //计算位图文件每个像素所占字节数 hDC = CreateDC( _T( "DISPLAY" ), NULL, NULL, NULL); iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES); DeleteDC(hDC); if (iBits <= 1) wBitCount = 1; else if (iBits <= 4) wBitCount = 4; else if (iBits <= 8) wBitCount = 8; else wBitCount = 24; GetObject(hBitmap, sizeof(Bitmap), (LPSTR)&Bitmap); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = Bitmap.bmWidth; bi.biHeight = Bitmap.bmHeight; bi.biPlanes = 1; bi.biBitCount = wBitCount; bi.biCompression = BI_RGB; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrImportant = 0; bi.biClrUsed = 0; dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight; //为位图内容分配内存 hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER)); lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib); *lpbi = bi; // 处理调色板 hPal = GetStockObject(DEFAULT_PALETTE); if (hPal) { hDC = ::GetDC(NULL); hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE); RealizePalette(hDC); } // 获取该调色板下新的像素值 GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) +dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS); //恢复调色板 if (hOldPal) { ::SelectPalette(hDC, (HPALETTE)hOldPal, TRUE); RealizePalette(hDC); ::ReleaseDC(NULL, hDC); } //创建位图文件 fh = CreateFile( FileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL ); if (fh == INVALID_HANDLE_VALUE) return FALSE 4000 ; // 设置位图文件头 bmfHdr.bfType = 0x4D42; // "BM" dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize; bmfHdr.bfSize = dwDIBSize; bmfHdr.bfReserved1 = 0; bmfHdr.bfReserved2 = 0; bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; // 写入位图文件头 WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL); // 写入位图文件其余内容 WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL); //清除 GlobalUnlock(hDib); GlobalFree(hDib); CloseHandle(fh); return TRUE; }
至此,这个小截图工具就能够基本实现了,如何通过鼠标消息获取矩形区域在这里不再赘述。最后完成的程序能够截图保存为.BMP格式,但是图像未写入剪切板,此功能尚待添加。并且QQ截图圈定区域后能显示出该区域原本的像素值,此功能在最后完成的程序中也未实现。
这个小程序虽然很简单,但还是能够Windows程序设计的一些基本元素均有体现,但是功能尚未完善,还是那句老话,学习无止境,编程无黎明!
相关文章推荐
- VC6.0编写层析软件移植到VS2003心得
- 软件文档编写入门——软件工程视频总结(二)
- Android 2.3.5/4.0.3/4.1PowerManager简单总结和心得体会
- 30 多年的软件经验,总结出 10 个编写出更好代码的技巧
- 软件测试总结报告的编写
- 计算机软件概论以及HTML的简单编写
- 【图形化编程软件】 sikuli常用函数、简单事件操作 键盘操作 个人总结笔记
- Shell脚本简单总结及编写脚本中的小技巧
- 软件文档编写入门——软件工程视频总结(二)
- Shell脚本简单总结及编写脚本中的小技巧
- 学习总结 vs软件简单了解
- java简单优化和编写规范,自己总结的。
- 最近几年做软件项目的心得总结
- 用j2me编写palm软件的一点心得(一)
- C语言学习之1(Microsoft Visual Studio即VC6软件的安装及hello world 简单例子编写)
- [Linux学习日记]Ubuntu推荐软件以及简单脚本编写
- 正则表达式创建方式的区别及编写简单的正则方式(js学习总结)
- ASP.NET控件编写心得总结- 以后会写详细一点
- 关于android中两种service的编写简单总结
- JDBC增删改查模版编写与案例 --->张国亮总结心得第二季