重温 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);
- }
重温 Win32 API ----- 截屏指定窗体并打印的更多相关文章
- C#通过WIN32 API实现嵌入程序窗体
本文实例讲述了C#通过WIN32 API实现嵌入程序窗体的方法,分享给大家供大家参考.具体如下: 这是一个不使用COM,而是通过WIN32 API实现的示例, 它把写字板程序嵌在了自己的一个面板中. ...
- 通过 WIN32 API 实现嵌入程序窗体
写了一个不使用 COM, 而是通过 WIN32 API 实现的示例, 它把写字板程序嵌在了自己的一个面板中. 这么做可能没有实际意义, 因为两个程序之前没有进行有价值的交互, 这里仅仅是为了演示这么做 ...
- c#截屏功能的实现
using System;using System.Collections.Generic;using System.Drawing;using System.Linq;using System.Ru ...
- 【转】Android 音量键+电源键 截屏代码小结
http://104zz.iteye.com/blog/1752961 原文地址:http://blog.csdn.net/hk_256/article/details/7306590 ,转载请注明出 ...
- 纯C#实现屏幕指定区域截屏
以前在别的地方见过一个通过调用系统API实现屏幕截图的例子,从内心来说我不太喜欢在C#代码中出现这种情况,现在什么都讲“和谐”,我觉得这种做法就是破坏了我们的“和谐”代码,呵呵,开玩笑,有的时候,不通 ...
- VB用API模拟截屏键PrintScreen
很多人用 SendKeys "{PRTSC}" 模拟截屏键 PrintScreen 的时候提示<错误:'70' 拒绝的权限>,于是经常遇到人问...干脆写下来 '声明 ...
- Unity通过指定摄像机截屏
简介 介于照抄网上之前的截图教程,然后在实际应用过程中出现了一些小小的问题,修正了一下下,特此分享一下 PS:代码在后面 原理 原理很简单,就是将一个相机的内容渲染到一个贴图上,然后将贴图保存为图片 ...
- 一个类实现Java截屏并保存到指定文件夹
不知小伙伴们有没有遇到过使用java来截屏的需求,截屏后保存到指定的目录,在桌面上没有任何体现,完全不知道已经被截屏了.至于截屏后怎么做,可能有的老铁只是好奇想知道某人在干啥?也有的老铁可能想进行文字 ...
- selenium常用的API(一)截屏
我们在使用selenium测试过程中,可使用截屏功能将用例执行失败的画面截图保存,方便测试执行结束后查看并定位问题. 以下介绍两种截屏方法: 对当前浏览器窗口截屏 使用selenium自带的get_s ...
随机推荐
- BZOJ 2245: [SDOI2011]工作安排( 费用流 )
费用流模板题..限制一下不同愤怒值的工作数就可以了. ------------------------------------------------------------------------- ...
- SGU 101.Domino( 欧拉路径 )
求欧拉路径...直接dfs即可,时间复杂度O(N) -------------------------------------------------------------------------- ...
- Redis Sentinel的Redis集群(主从&Sharding)高可用方案
在不使用redis3.0之后版本的情况下,对于redis服务端一般是采用Sentinel哨兵模式,也就是一主多备的方式. 这里,先抛出三个问题, 问题1:单节点宕机数据丢失?问题2:多节点(节点间没有 ...
- Redis中各种方法的使用
①set ; i< ; i++) { // 不可以重复添加数据 client.AddItemToSet(KKey, "dong升-" + i); } client.Remov ...
- input 输入框获得/失去焦点时隐藏/显示文字(jquery版)
input输入框在获得或失去焦点时隐藏或显示文字,这样的焦点效果想必很多朋友在填写form表格的时候都曾见识过吧,本文使用jquery实现以下,感兴趣的朋友可以参考下哈 大家可以看效果图的搜索输入框, ...
- Ubuntu Server修改IP、DNS、hosts
本文记录下Ubuntu Server 16.04修改IP.DNS.hosts的方法 -------- 1. Ubuntu Server 修改IP sudo vi /etc/network/interf ...
- 使用 http://httpbin.org/ 验证代理地址
发现一个很方便的工具,在Linux 下使用 curl http://httpbin.org/ 可以返回当前使用的一些网络信息
- Canvas 雾玻璃
Demo http://lumixraku.github.io/demos/Fog/Fog.html Canvas tutorial 给大家安利一个学习Canvas的站点 http://www.htm ...
- RIA Service 的 SOAP EndPoint
原文 www.cyqdata.com/cnblogs/article-detail-39983-english 越来越多的朋友都在使用Silverlight开发应用程序,其中我们常用的还会有一个特殊的 ...
- JSP打印九九乘法表
##index.jsp: <%@ page language="java" import="java.util.*" pageEncoding=" ...