重温 Win32 API ----- 截屏指定窗口并打印
2014-12-22 17:12
218 查看
朋友说在一个VC++6.0开发的项目中要加入打印窗口的功能,让帮忙写个代码供其调用。这么老的IDE当然不想碰了,而且也不喜欢MFC笨拙不清晰的封装,所以决定采用纯Win32 API,然后用C++类简单封装一下。
实现文件 WindowPrinter.cpp
1 基本思路
窗口DC和打印机DC是两类不兼容的DC,所以它们之间传送位图只能通过DIB。首先,通过BitBlt()把要打印窗口的客户区拷贝到DDB内存位图中,然后通过GetDIBits()把DDB转换为DIB,最后通过StretchDIBits()向打印机DC输出。2 代码实现
头文件 WinowPrinter.h#pragma once /******************************************************************************** WindowPrinter 打印窗口类 功能描述: 提供截屏窗口并通过默认打印机,自动进行居中缩放打印 使用说明: 样例代码如下。 HWND hwnd = this->GetSafeWnd(); WindowPrinter::PrintWindowClientArea(hwnd); ********************************************************************************/ class WindowPrinter { public: WindowPrinter(); ~WindowPrinter(); public: /* 功能:获取当前默认打印机的DC 返回:成功返回打印机的DC,失败返回NULL */ static HDC GetPrinterDC(); /* 功能:打印窗口客户区内容到打印机,自动缩放居中打印 参数: hWnd-被打印窗口的句柄 */ static void PrintWindowClientArea(HWND hwnd); };
实现文件 WindowPrinter.cpp
#include "stdafx.h" #include "WindowPrinter.h" #include <Winspool.h> WindowPrinter::WindowPrinter() { } WindowPrinter::~WindowPrinter() { } /* 功能:获取当前默认打印机的DC 返回:成功返回打印机的DC,失败返回NULL */ HDC WindowPrinter::GetPrinterDC() { DWORD dwNeeded, dwReturned; HDC hdc; ::EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &dwNeeded, &dwReturned); PRINTER_INFO_4* pinfo4 = (PRINTER_INFO_4*)malloc(dwNeeded); ::EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 4, (BYTE*)pinfo4, dwNeeded, &dwNeeded, &dwReturned); hdc = ::CreateDC(NULL, pinfo4->pPrinterName, NULL, NULL); free(pinfo4); return hdc; } /* 功能:打印窗口客户区内容到打印机,自动缩放居中打印 参数: hWnd-被打印窗口的句柄 */ void WindowPrinter::PrintWindowClientArea(HWND hWnd) { if (hWnd == NULL) return; RECT rectClient; ::GetClientRect(hWnd, &rectClient); int width = rectClient.right - rectClient.left; int height = rectClient.bottom - rectClient.top; // 通过内存DC复制客户区到DDB位图 HDC hdcWnd = ::GetDC(hWnd); HBITMAP hbmWnd = ::CreateCompatibleBitmap(hdcWnd, width, height); HDC hdcMem = ::CreateCompatibleDC(hdcWnd); ::SelectObject(hdcMem, hbmWnd); ::BitBlt(hdcMem, 0, 0, width, height, hdcWnd, 0, 0, SRCCOPY); // 把窗口DDB转为DIB BITMAP bmpWnd; ::GetObject(hbmWnd, sizeof(BITMAP), &bmpWnd); BITMAPINFOHEADER bi; // 信息头 bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = bmpWnd.bmWidth; bi.biHeight = bmpWnd.bmHeight; bi.biPlanes = 1; bi.biBitCount = 32; // 按照每个像素用32bits表示转换 bi.biCompression = BI_RGB; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = 0; bi.biClrImportant = 0; DWORD dwBmpSize = ((bmpWnd.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmpWnd.bmHeight; // 每一行像素位32对齐 char *lpbitmap = (char*)malloc(dwBmpSize); // 像素位指针 ::GetDIBits(hdcMem, hbmWnd, 0, (UINT)bmpWnd.bmHeight, lpbitmap, (BITMAPINFO*)&bi, DIB_RGB_COLORS); ::DeleteDC(hdcMem); ::DeleteObject(hbmWnd); ::ReleaseDC(hWnd, hdcWnd); // 存为文件(可选) BITMAPFILEHEADER bmfHeader; // 文件头 DWORD dwSizeofDIB = dwBmpSize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER); bmfHeader.bfSize = dwSizeofDIB; bmfHeader.bfType = 0x4D42; FILE* fp = NULL; ::_wfopen_s(&fp, L"capture.bmp", L"w"); ::fwrite(&bmfHeader, sizeof(BITMAPFILEHEADER), 1, fp); // 写入文件头 ::fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, fp); // 写入信息头 ::fwrite(lpbitmap, dwBmpSize, 1, fp); // 写入像素位 ::fclose(fp); fp = NULL; // StretchDIBits()缩放打印DIB HDC hdcPrinter = WindowPrinter::GetPrinterDC(); if (hdcPrinter == NULL) return; int pageWidth = ::GetDeviceCaps(hdcPrinter, HORZRES); int pageHeight = ::GetDeviceCaps(hdcPrinter, VERTRES); float scaleX = (float)pageWidth / (float)bmpWnd.bmWidth; float scaleY = (float)pageHeight / (float)bmpWnd.bmHeight; float scale = scaleX < scaleY ? scaleX : scaleY; int xDst, yDst, cxDst, cyDst; cxDst = (int)((float)bmpWnd.bmWidth * scale); cyDst = (int)((float)bmpWnd.bmHeight * scale); xDst = (int)((pageWidth - cxDst) / 2); yDst = (int)((pageHeight - cyDst) / 2); static DOCINFO di = { sizeof(DOCINFO), L"PRINTJOBNAME" }; if (::StartDoc(hdcPrinter, &di) > 0) { if (::StartPage(hdcPrinter) > 0) { ::StretchDIBits(hdcPrinter, xDst, yDst, cxDst, cyDst, 0, 0, bmpWnd.bmWidth, bmpWnd.bmHeight, lpbitmap, (BITMAPINFO*)&bi, DIB_RGB_COLORS, SRCCOPY); ::EndPage(hdcPrinter); } ::EndDoc(hdcPrinter); } ::DeleteDC(hdcPrinter); ::free(lpbitmap); }
相关文章推荐
- 重温 Win32 API ----- 截屏指定窗体并打印
- 重温WIN32 API ------ 窗口上绘制位图文件
- 重温WIN32 API ------ 最简单的Windows窗口封装类
- 重温WIN32 API ------ SetTimer()无窗口调用方式
- 用Win32 API创建不规则窗口
- 用Win32 API创建不规则窗口
- MFC程序对win32的封装总结(窗口类的注册,窗口的创建,窗口的窗口过程指定)
- Silverlight 5 RC新特性探索系列:12.Silverlight 5 RC 窗口模式下访问自定义DLL和WIN32 API
- 重温WIN32 API ------ Window消息跟踪
- win32 API窗口句柄的获得——我的经验
- Win32 API与MFC创建窗口对比
- 学习win32 API开发5-让窗口中显示文字
- Silverlight 5 RC新特性探索系列:12.Silverlight 5 RC 窗口模式下访问自定义DLL和WIN32 API
- JS打印指定内容(新窗口)
- 使用WIN32 API CreateProcess()以无窗口方式创建DOS程序
- [导入] [分享]不用API实现截屏/截取当前窗口内容(“抓图”)
- c# WInform 窗口启动特效,使用win32 api
- 窗口启动特效,使用win32 api
- QTP调用win32 API 实现窗口的最小最大化
- API使指定窗口全屏/恢复全屏