重温 Win32 API ----- 截屏指定窗体并打印

简介:

朋友说在一个VC++6.0开发的项目中要增加打印窗体的功能,让帮忙写个代码供其调用。

这么老的IDE当然不想碰了,并且也不喜欢MFC笨拙不清晰的封装。所以决定採用纯Win32 API,然后用C++类简单封装一下。

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); }


 

 




本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5193905.html,如需转载请自行联系原作者

相关文章
|
7月前
|
程序员 API C语言
Win32 API介绍​(COORD、GetStdHandle、GetConsoleCursorInfo 、SetConsoleCursorInfo)、<locale.h>本地化、类项
Win32 API介绍​(COORD、GetStdHandle、GetConsoleCursorInfo 、SetConsoleCursorInfo)、<locale.h>本地化、类项
|
7月前
|
监控 编译器 API
常用Win32 API的简单介绍
常用Win32 API的简单介绍
|
存储 编译器 API
【Win32准备】API,Win32入口程序,宽字符(下)
【Win32准备】API,Win32入口程序,宽字符
|
存储 编译器 API
【Win32准备】API,Win32入口程序,宽字符(上)
【Win32准备】API,Win32入口程序,宽字符
|
安全 API C++
Win32环境下代码注入与API钩子的实现
本文详细的介绍了在Visual Studio(以下简称VS)下实现API钩子的编程方法,阅读本文需要基础:有操作系统的基本知识(进程管理,内存管理),会在VS下编写和调试Win32应用程序和动态链接库(以下简称DLL)。
1267 0