朋友说在一个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 ----- 截屏指定窗体并打印的更多相关文章

  1. C#通过WIN32 API实现嵌入程序窗体

    本文实例讲述了C#通过WIN32 API实现嵌入程序窗体的方法,分享给大家供大家参考.具体如下: 这是一个不使用COM,而是通过WIN32 API实现的示例, 它把写字板程序嵌在了自己的一个面板中. ...

  2. 通过 WIN32 API 实现嵌入程序窗体

    写了一个不使用 COM, 而是通过 WIN32 API 实现的示例, 它把写字板程序嵌在了自己的一个面板中. 这么做可能没有实际意义, 因为两个程序之前没有进行有价值的交互, 这里仅仅是为了演示这么做 ...

  3. c#截屏功能的实现

    using System;using System.Collections.Generic;using System.Drawing;using System.Linq;using System.Ru ...

  4. 【转】Android 音量键+电源键 截屏代码小结

    http://104zz.iteye.com/blog/1752961 原文地址:http://blog.csdn.net/hk_256/article/details/7306590 ,转载请注明出 ...

  5. 纯C#实现屏幕指定区域截屏

    以前在别的地方见过一个通过调用系统API实现屏幕截图的例子,从内心来说我不太喜欢在C#代码中出现这种情况,现在什么都讲“和谐”,我觉得这种做法就是破坏了我们的“和谐”代码,呵呵,开玩笑,有的时候,不通 ...

  6. VB用API模拟截屏键PrintScreen

    很多人用 SendKeys "{PRTSC}" 模拟截屏键 PrintScreen 的时候提示<错误:'70' 拒绝的权限>,于是经常遇到人问...干脆写下来 '声明 ...

  7. Unity通过指定摄像机截屏

    简介 介于照抄网上之前的截图教程,然后在实际应用过程中出现了一些小小的问题,修正了一下下,特此分享一下 PS:代码在后面 原理 原理很简单,就是将一个相机的内容渲染到一个贴图上,然后将贴图保存为图片 ...

  8. 一个类实现Java截屏并保存到指定文件夹

    不知小伙伴们有没有遇到过使用java来截屏的需求,截屏后保存到指定的目录,在桌面上没有任何体现,完全不知道已经被截屏了.至于截屏后怎么做,可能有的老铁只是好奇想知道某人在干啥?也有的老铁可能想进行文字 ...

  9. selenium常用的API(一)截屏

    我们在使用selenium测试过程中,可使用截屏功能将用例执行失败的画面截图保存,方便测试执行结束后查看并定位问题. 以下介绍两种截屏方法: 对当前浏览器窗口截屏 使用selenium自带的get_s ...

随机推荐

  1. Nginx +iis反向代理

    一:简介      Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.由俄罗斯的程序设计师Igor Sysoev所 ...

  2. TinyFox 部署在CentOS7 中测试使用

    一:TinyFox介绍 TinyFox 是一款支持OWIN标准的WEB应用的高性能的HTTP服务器,是Jexus Web Server的"姊妹篇".TinyFox本身的功能是htm ...

  3. 搭建单节点Hadoop应用环境

    虚拟机: VirtualBox 5 Server操作系统: Ubuntu Server 14.04.3 LTS 如果对虚拟机空间和性能不做考虑, 且不习惯用Linux命令, 你也可以使用Ubuntu ...

  4. html回车事件

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  5. 【LeetCode题意分析&解答】42. Trapping Rain Water

    Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...

  6. Ubuntu12.04获取root权限

    有的时候我们需要Ubuntu的root权限,我们该如何获取呢? 其实,很简单,我们只需要在终端中输入以下命令即可获得root权限. 第一步,打开终端 ( ctrl+alt+T ) 第二步,输入命令:s ...

  7. 批量添加target属性

    <script> addTarget(); function addTarget(){ var oa=document.getElementsByTagName('a'); for(var ...

  8. uva 10548 - Find the Right Changes(拓展欧几里得)

    题目链接:uva 10548 - Find the Right Changes 题目大意:给定A,B,C,求x,y,使得xA+yB=C,求有多少种解. 解题思路:拓展欧几里得,保证x,y均大于等于0, ...

  9. java String分类trim,substring,replaceAll,indexOf使用功能

    1.trim性能 特征去掉字符串首尾空格,防止不必要的空格导致错误. public class TrimTest { public static void main(String[] args) { ...

  10. ubuntu之iptables

    1.更新iptables并立即生效: a.保存当前设置:iptables-save > /etc/iptables.up.rules b.修改iptables规则: 例如: -I INPUT - ...