• 重温 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); }


     

  • 相关阅读:
    实验一
    MVVM Light Toolkit 学习
    配置mongodb分片群集(sharding cluster)
    【silverlight】web发布方法
    MongoDb数据库设计
    【解决方案】添加web服务失败:下载“http://localhost:2540/Service.asmx”时出错。无法生成***类型
    Codeforces #380 div2 C(729C) Road to Cinema
    Codeforces #380 div2 B(729B) Spotlights
    数据挖掘项目总结
    南方电网用电时间序列分析
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/5193905.html
Copyright © 2020-2023  润新知