重温 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 ...
随机推荐
- linux install nginx error
1 2 3 4 5 6 7 8 9 10 11 [mahao01@127.0.0.1 nginx-1.2.9]$ make make -f objs/Makefile make[1]: Enterin ...
- eclipse注解快捷键
Search 功能:全局文件内容搜索快捷键: Ctrl + H -------------------------------------------------------------------- ...
- 以正方教务系统为例,用php模拟登陆抓取课表、空教室
课程格子和超级课程表这两个应用,想必大学生都很熟悉,使用自己的学号和教务系统的密码,就可以将自己的课表导入,随时随地都可以在手机上查看. 其实稍微了解一点php的话,我们也可以做一个类似这样的web ...
- codeforces 630P. Area of a Star
题目链接 圆上n个点等距离分布, 求构成的星星的面积. 我们可以求三角形OAB的面积, ∠CAE = 1/2 ∠ COE = PI/n, 那么∠CAO = PI/2n, ∠AOB非常好求, 就是PI/ ...
- vs2008 edit spin 十六进制实现
由于做的东西中涉及到一个控件,查了一下叫spin box,但是,spin box控件只在对话框里面才能使用,而且比较麻烦,更何况还要用十六进制,查到就有可多edit+spin来做,后来找到一个样例着手 ...
- HDU 3336 Count the string
题解:利用next数组来保存前缀位置,递推求解. #include <cstdio> #include <cstring> char pat[200005]; int next ...
- VS2010/MFC对话框:字体对话框
字体对话框) 在上一节为大家讲解了文件对话框的使用,本节则主要介绍字体对话框如何应用. 字体对话框的作用是用来选择字体.我们也经常能够见到.MFC使用CFontDialog类封装了字体对话框的所有操作 ...
- 学习pthreads,给线程传递多个參数
上篇博文中.boss线程给其它线程传递的仅仅有一个參数,那么假如是多个參数呢?怎么传递呢?也许你会有这种疑问,带着这个疑问,我们进入本文的世界,这里传递多个參数,採用结构体,为什么呢?由于结构体里能够 ...
- linux线程之pthread_join和pthread_detach
在任何一个时间点上,线程是可结合的(joinable)或者是分离的(detached).一个可结合的线程能够被其他线程收回其资源和杀死.在 被其他线程回收之前,它的存储器资源(例如栈)是不释放的.相反 ...
- 如何得到Sessionid的值
当用户向一个网站请求第一个页面时,用户会话启动.当第一个页面被请求时,web服务器将asp.net_sessionID cookie添加进用户的浏览器.可以使用newsession属性探测新会话的启 ...