朋友说在一个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. C语言函数可变参数列表

    C语言允许使用可变参数列表,我们常用的printf函数即为可变参数函数,C标准库提供了stdarg.h为我们提供了这方面支持:该头文件提供了一些类型和宏来支持可变参数列表,包括类型va_list,宏v ...

  2. VS2010断点无效

    可能的原因如下: 1. 菜单tools->Options->Debugging->General,有个Require  source files to exactly match t ...

  3. Hadoop学习之Hadoop案例分析

    一.日志数据分析1.背景1.1 ***论坛日志,数据分为两部分组成,原来是一个大文件,是56GB:以后每天生成一个文件,大约是150-200MB之间: 每行记录有5部分组成:1.访问ip:2.访问时间 ...

  4. Linux编程环境介绍(3) -- linux下的c/c++程序开发

    目录: 1. 编辑器( Vi ) [vi 与 vim] vi(visual interface)是linux系统最重要的文本编辑器, 所有的 Unix-Like 系统都会内置vi文本编辑器.  vim ...

  5. 6)图[2]Prim算法[最小生成树]

    Prim 算法 求解方法: 首先将所指定的起点作为已选顶点,然后反复在满足如下条件下的边中选择一条最小边,直到 所有顶点已成为已选顶点为止(选择n-1条边). #include "iostr ...

  6. Zepto Api参考

    zepto API参考 简介 Zepto是一个轻量级的针对现代高级浏览器的JavaScript库, 它与jquery有着类似的api. 如果你会用jquery,那么你也会用zepto. 设计目的 ze ...

  7. Java图形化界面设计——布局管理器之BorderLayout(边界布局)

  8. [置顶] jsp中c标签的使用

    jsp中c标签的使用 核心标签库 它是JSTL中的核心库,为日常任务提供通用支持,如显示和设置变量.重复使用一组项目.测试条件和其他操作(如导入和重定向Web内容).Core标签按功能可分为4种类型: ...

  9. 反射,得到Type引用的三种方式

    1.使用System.Object.GetType()得到Type引用 使用一个SportsCar实例得到类型信息 SportsCar sc=new  SportsCar(); Type t=sc.G ...

  10. .Net Web开发中实现剪切板功能

    我要实现的功能是:在列表页,通过一个按钮复制对应的文章Url,如下图: 如下代码:     <a class="btn btn-success copy" href=&quo ...