VC++自定义纸张打印

C++打印机首选项设置 C++打印机彩打设置 前言 最近在开发打印机SDK,之前一直做黑白打印机,后面来了一个彩色打印机,要求彩色文档不但可以打印出彩色纸张,也能打印出黑白纸张;打印机默认是黑白文档打印黑白纸张,彩色文档打印彩色纸张,需要调用windows api来控制。 一、打印机首选项 首先查看打印机是否支持颜色设置(必须先安装打印机驱动,并且正常连接打印机),去电脑查看打印机首选项,【控制面板】->【设备和打印机】->【选中彩色打印机】->【右击选择打印机首选项】->【点击颜色窗口】,如下图所示: 阅读详情

我在网上已不断看到一些网友关于自定义纸张打印的问题,基本上还没有较完美的解决方案,我在这里提供一个WindowsNT/2000/XP下的解决办法,供广大同仁参考。Windows9x/Me下也有解决办法,有兴趣者可共同探讨。
  该方法的主要思想是在程序开始时添加自定义纸张并设为默认纸张,程序结束前删除该自定义纸张并恢复原来的默认纸张类型。这种方法的通用性是显而易见的,如果你正在用Document/View框架,那么你就不必为了自定义纸张而去挖空心思重载其中的一些函数了。
  以下是我的程序片断,请朋友们多提宝贵意见。如果我的代码能为您所用,那是我极大的荣幸。
  注:我在论坛中回复的帖子中个别GlobalAlloc和GlobalFree打错成了Alloc和Free,予以纠正并发表在此。


 

#i nclude
typedef TCHAR PAPERNAME[64]; //打印机纸张名称类型
//检测系统是否为Windows NT/2000/XP
BOOL CPrinter::IsWindowsNT()
{
OSVERSIONINFO vi;
vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&vi);
return (vi.dwPlatformId == VER_PLATFORM_WIN32_NT);
}
//获得默认打印机名称和默认的纸张
BOOL GetDefaultPrinterAndPaper(LPTSTR szPrinterName, int nPrintNameBufferLen, LPTSTR szPaperName)
{
*szPrinterName = 0;
*szPaperName = 0;
CPrintDialog pd(FALSE);
if (pd.GetDefaults())
{
if (pd.m_pd.hDC) DeleteDC(pd.m_pd.hDC);
if (pd.m_pd.hDevMode)
{
LPDEVMODE pdm = (LPDEVMODE)GlobalLock(pd.m_pd.hDevMode);
*(szPaperName + 63) = 0;
_tcsncpy(szPaperName, (LPCTSTR)pdm->dmFormName, 63); //打印纸张名称
GlobalUnlock(pd.m_pd.hDevMode);
GlobalFree(pd.m_pd.hDevMode);
}
if (pd.m_pd.hDevNames)
{
LPDEVNAMES pdn = (LPDEVNAMES)GlobalLock(pd.m_pd.hDevNames);
nPrintNameBufferLen--;
*(szPrinterName + nPrintNameBufferLen) = 0;
_tcsncpy(szPrinterName, (LPTSTR)pdn + pdn->wDeviceOffset, nPrintNameBufferLen); //打印机名称
GlobalUnlock(pd.m_pd.hDevNames);
GlobalFree(pd.m_pd.hDevNames);
}
}
return (*szPrinterName && *szPaperName);
}
//增加规格自定义纸张
//szPaperName: 自定义纸张名称
//PaperSize: 纸张的大小,以0.1mm为单位
//rcPrintableMargin: 打印机的最小可打印边界,以0.1mm为单位。
// 可参见GetDeviceCaps函数说明中的PHYSICALOFFSETX及PHYSICALOFFSETY
BOOL AddCustomPaper(LPCTSTR szPrinterName, PAPERNAME szPaperName, SIZE PaperSize, RECT rcPrintableMargin)
{
BOOL bOk = FALSE;
if (IsWindowsNT()) //Windows NT4/2000/XP才支持
{
FORM_INFO_1 fi1;
fi1.Flags = FORM_USER;
fi1.pName = (LPTSTR)szPaperName;
fi1.Size.cx = PaperSize.cx * 100;
fi1.Size.cy = PaperSize.cy * 100;
fi1.ImageableArea.left = rcPrintableMargin.left * 100;
fi1.ImageableArea.top = rcPrintableMargin.top * 100;
fi1.ImageableArea.right = fi1.Size.cx - rcPrintableMargin.right * 100;
fi1.ImageableArea.bottom = fi1.Size.cy - rcPrintableMargin.bottom * 100;
HANDLE hPrinter = GetPrinterHandle(szPrinterName);
if (hPrinter)
{
bOk = (SetForm(hPrinter, (LPSTR)szPaperName, 1, (LPBYTE)&fi1) || //已存在该类型纸张则更改
AddForm(hPrinter, 1, (LPBYTE)&fi1)); //否则添加此自定义纸张
ClosePrinter(hPrinter);
}
}
return bOk;
}
//删除自定义规格纸张
BOOL DeleteCustomPaper(LPCTSTR szPrinterName, LPCTSTR szPaperName)
{
BOOL bOk = FALSE;
if (IsWindowsNT()) //Windows NT4/2000/XP才支持
{
HANDLE hPrinter = GetPrinterHandle(szPrinterName);
if (hPrinter)
{
bOk = DeleteForm(hPrinter, (LPSTR)szPaperName);
ClosePrinter(hPrinter);
}
}
return bOk;
}
//获取打印机句柄
HANDLE GetPrinterHandle(LPCTSTR szPrinterName)
{
PRINTER_DEFAULTS pds;
HANDLE hPrinter = NULL;
ZeroMemory(&pds, sizeof(PRINTER_DEFAULTS));
pds.DesiredAccess = PRINTER_ALL_ACCESS;
OpenPrinter(szPrinterName, &hPrinter, &pds);
return hPrinter;
}
//由纸张名称得到对应的DEVMODE中的那个dmPaperSize值,返回-1表示有错误
short GetPaperSize(LPCTSTR szPrinterName, LPCTSTR szPortName, PAPERNAME szPaperName)
{
short nPaperSize = -1;
//获得可用打印机纸张类型数目
int nNeeded = DeviceCapabilities(szPrinterName, szPortName, DC_PAPERNAMES, NULL, NULL);
if (nNeeded)
{
PAPERNAME *pszPaperNames = new PAPERNAME[nNeeded]; //分配纸张名称数组
//获得可用打印机纸张名称数组
if (DeviceCapabilities(szPrinterName, szPortName, DC_PAPERNAMES, (LPTSTR)pszPaperNames, NULL) != -1)
{
int i;
//查找纸张类型szPaperName在数组中的索引
for (i = 0; i < nNeeded && _tcscmp(pszPaperNames[i], szPaperName); i++);
if (i < nNeeded)
{
//获得可用打印机纸张尺寸号数目(应该等于打印机纸张类型数目)
nNeeded = DeviceCapabilities(szPrinterName, szPortName, DC_PAPERS, NULL, NULL);
if (nNeeded)
{
LPWORD pPapers = new WORD[nNeeded]; //分配纸张尺寸号数组
//获得可用打印机纸张尺寸号数组
if (DeviceCapabilities(szPrinterName, szPortName, DC_PAPERS, (LPSTR)pPapers, NULL) != -1)
nPaperSize = pPapers[i]; //获得纸张类型szPaperName对应的尺寸号
delete []pPapers;
}
}
}
delete []pszPaperNames;
}
return nPaperSize;
}
//设置打印机的默认纸张和方向
BOOL SetPaper(LPCTSTR szPrinterName, PAPERNAME szPaperName, short nOrientation)
{
BOOL bOk = FALSE;
PRINTER_INFO_2 *ppi2 = GetInfo2(szPrinterName);
if (ppi2)
{
short nPaperSize = GetPaperSize(szPrinterName, ppi2->pPortName, szPaperName);
if (nPaperSize != -1)
{
ppi2->pDevMode->dmFields = DM_PAPERSIZE|DM_PAPERWIDTH|DM_PAPERLENGTH|DM_ORIENTATION;
ppi2->pDevMode->dmPaperSize = nPaperSize;
ppi2->pDevMode->dmPaperWidth = 0;
ppi2->pDevMode->dmPaperLength = 0;
ppi2->pDevMode->dmOrientation = nOrientation;
bOk = SetInfo2(ppi2);
}
GlobalFree((HGLOBAL)ppi2);
}
return bOk;
}
//获取打印机详细信息,返回的指针用后必须以GlobalFree释放
PRINTER_INFO_2 *GetInfo2(LPCTSTR szPrinterName)
{
HANDLE hPrinter = GetPrinterHandle(szPrinterName);
PRINTER_INFO_2 *ppi2 = NULL;
DWORD cbNeeded = 0;
if (hPrinter)
{
GetPrinter(hPrinter, 2, 0, 0, &cbNeeded);
if (cbNeeded)
{
ppi2 = (PRINTER_INFO_2 *)GlobalAlloc(GPTR, cbNeeded);
if (ppi2)
{
if (!GetPrinter(hPrinter, 2, (LPBYTE)ppi2, cbNeeded, &cbNeeded))
{
GlobalFree((HGLOBAL)ppi2);
ppi2 = NULL;
}
}
}
ClosePrinter(hPrinter);
}
return ppi2;
}
//打印机设置
BOOL SetInfo2(PRINTER_INFO_2 *ppi2)
{
HANDLE hPrinter = GetPrinterHandle(ppi2->pPrinterName);
BOOL bOk = FALSE;
DWORD fMode;
if (hPrinter)
{
fMode = DM_IN_BUFFER | DM_OUT_BUFFER;
bOk = (DocumentProperties(NULL, hPrinter,
ppi2->pPrinterName,
ppi2->pDevMode,
ppi2->pDevMode,
fMode) == IDOK &&
::SetPrinter(hPrinter, 2, (LPBYTE)ppi2, 0));
ClosePrinter(hPrinter);
}
return bOk;
}

TCHAR szPrinterName[32];
PAPERNAME szPaperName, szOldPaperName;
//在您的程序开始时,获取默认打印机名和纸张名
GetDefaultPrinterAndPaper(szPrinterName, 32, szOldPaperName);
_tcscpy(szPaperName, _T("我的自定义纸张"));
//增加自定义纸张
AddCustomPaper(szPrinterName, szPaperName, CSize(1480, 2000), CRect(70, 70, 70, 70));
//并设自定义纸张为默认纸张
SetPaper(szPrinterName, szPaperName, DMORIENT_PORTRAIT);

//在您的程序结束前
//删除自定义纸张
DeleteCustomPaper(szPrinterName, szPaperName);
//并恢复初始默认纸张
SetPaper(szPrinterName, szOldPaperName);

使用VC/MFC打印(Print) 第一部分和第二部分是自己的实现及解决方法,第三部分是参考的文章一:(打印实现的操作流程)<br />    在VC中实现打印操作,网上虽然看了很多的说明或例子,但具体实现时还是感觉迷惑,自己研究了下,将经验总结如下,如有错误,欢迎大家指正,免得误人误己。    自己实现的打印是在CView的派生类(如:CMyView)中,关于MFC内部实现,有很多文章都说明了,这里就不重复了,实现步骤如下:1:在CMyView中定义个函数入void PrintView(),函数实现调用this->OnFilePrint() 阅读详情

相关推荐

VC++打印机编程实战:从GDI打印到RAW数据控制的完整指南

在Windows平台进行硬件交互和企业级应用开发时,打印机控制是一个常见且关键的需求。其核心原理是通过Windows图形设备接口(GDI)或直接数据写入(RAW)与打印子系统通信,实现对纸张、走纸、图形位置等元素的精确操控。这项技术的工程价值在于能够绕过通用打印对话框的限制,满足报表生成、条形码标签打印、票据套打等复杂场景的定制化需求。尤其在需要直接操作硬件端口、维护遗留系统或追求极致性能的工业控制和零售系统中,基于VC++的底层API调用提供了不可替代的精细控制能力。本文聚焦于VC++(特别是MFC框架)

weixin_28693683的博客 331

如何在VC++中使用API直接打印

在Visual  C++中,应用程序通常是使用CView中提供的打印功能,在OnPrint()或OnDraw()中向打印机输出。但是对于对话框中的数据,或基于对话框的程序,打印成了一件繁琐的工作。   该段代码向用户提供了PrintListCtrl()函数,用于打印用户在对话框或FormView中的CListCtrl(控件必须是Report  View  形式的)控件中的内容。在打印过程中,根据控

快乐天堂 1430

Visio风格源代码组件库,流程图,矢量图,图形编辑,打印,导入,导出,VC++源代码

Visio风格源代码组件库,流程图,矢量图,图形编辑,打印,导入,导出,VC++源代码 -- 100%源码全开放企业级Visio制图解决方案! Visio风格的流程图矢量图编辑功能从E-Form++发布第一个版本就已经具

jackonlyone的专栏 4128

A4 纸张上打印预览

以下是一个简单的示例,演示如何使用 VC++2012 在 A4 纸张上打印预览从上到下排列的 3 张照片,每张照片下方显示文件名。// 获取当前屏幕分辨率。

qq_14860257的博客 250

VC++分页打印功能实现详解:从GDI原理到工业级解决方案

在桌面应用开发中,打印功能是处理文档输出的核心技术,尤其在需要生成报表、票据或清单的业务系统中不可或缺。其底层原理基于Windows图形设备接口(GDI),通过设备上下文(DC)管理坐标映射与绘制命令,实现屏幕到物理纸张的精确转换。这项技术的核心价值在于能够将动态数据源(如数据库记录)按预设布局自动分页,并支持页眉、页脚及页码的自动添加,从而生成专业、规范的打印文档。在工程实践中,一个健壮的分页打印模块需要解决精确页面度量、动态分页算法、打印预览模拟等关键挑战,其实现质量直接关系到应用的稳定性和用户体验。本

weixin_42527654的博客 308

通过VC++实现打印CR80工作证

摘要:本文介绍了使用VC++编程实现CR80标准尺寸(85.6mm×54mm)工作证打印的方法。主要内容包括:1) 配置打印环境,添加必要的Windows打印API头文件;2) 打印机选择功能实现,包括获取打印机句柄和设置默认打印机;3) 完整的CR80工作证打印类实现,涵盖打印机初始化、毫米到像素转换、单张工作证打印等功能。打印功能支持文本信息(姓名、部门等)和照片的精确排版打印,通过计算DPI实现毫米级精确定位,并提供了边框绘制、文字排版等完整解决方案。

让编程变的很简单!! 745

A4 纸张上打印预览文件目录下所有照片

以下是一个简单的示例,演示如何使用 VC++2012 在 A4 纸张上打印预览文件目录下所有照片,从上到下排列每页三张照片,每张照片下方显示照片文件名。// 获取当前屏幕分辨率。// 打印完成,释放资源。满一页,开始打印下一页。

qq_14860257的博客 235

掌握VC++中的打印类及其自定义打印功能

本文还有配套的精品资源,点击获取 简介:在VC++中实现打印功能时,主要涉及MFC库中的打印相关类。本文将深入讲解如何使用 CPrintInfo 类控制打印过程、 CView 类派生实现打印逻辑、 CPrintDialog 类进行打印参数设置,以及 CDC 类处理设备上下文。还包括了预览类 CPreviewDC...

weixin_42393362的博客 1467

用WPF实现打印及打印预览

应该说,WPF极大地简化了我们的打印输出工作,想过去使用VC++做开发的时候,打印及预览可是一件极麻烦的事情,而现在我不会再使用C++来做Windows的桌面应用了——性价比实在太低。 WPF的打印功能是很强大而简便的,它甚至能够直接打印界面上的内容,包括各种控件的显示内容,例如你在界面上摆放了一个datagrid控件,画了一个五角星,或写了一段文字,都可以直接打印出来,这里有一篇文章...

anw53724的博客 1548

VC++分页打印实践教程与源码

在早期的计算机时代,打印技术主要集中在单页的文本文档。随着技术的发展,打印技术已经从简单的文本输出进化到了复杂的图形和彩色打印。现代的分页打印技术不仅涉及到图形用户界面(GUI)的渲染,还包括了对大量数据的高效处理,尤其是在企业级应用中处理报表、图表以及其他复杂文档的打印需求。MFC(Microsoft Foundation Classes)是一组用于封装Windows API的C++类库,它极大地简化了Windows应用程序的开发。

weixin_28235889的博客 616

使用VC++创建图片打印程序DEMO

MFC(Microsoft Foundation Classes)为开发Windows应用程序提供了一系列的类库。在打印方面,MFC 提供了一整套完善的打印支持类,从最基础的CView类开始,便内置了对打印和打印预览的支持。CView类是文档-视图架构中“视图”部分的基类,负责提供与用户交互的界面,并处理视图相关的消息。继承自CView的打印类如CScrollView和CFormView,能够支持滚动和表单视图的打印。

weixin_42590539的博客 927

在VC++中使用API直接打印

介绍: 这一段代码,用以演示《如何在VC++中使用API直接打印》。并且该段代码可以直接嵌入各种工程中,有实际使用的价值。   用途: 在Visual C++中,应用程序通常是使用CView中提供的打印功能,在OnPrint()或OnDraw()中向打印机输出。但是对于对话框中的数据,或基于对话框的程序,打印成了一件繁琐的工作。  该段代码向用户提供了PrintListCtrl()函数,用于打印用

guoxiaoli的专栏 933

VC++分页打印功能实现详解与源代码

MFC(Microsoft Foundation Classes)是微软公司提供的一套C++类库,用于简化Windows应用程序的开发。它封装了大部分Windows API,使得开发者可以不用深入了解底层API就可以进行Windows软件开发。MFC提供了一系列的类,包括文档/视图架构,控件类,以及与数据库、网络等功能相关的类。这些类为常见任务提供了即插即用的解决方案,大大加速了应用程序的开发进程。CDC类是MFC中一个非常核心的类,它封装了设备上下文相关的操作。

weixin_42596246的博客 1119

VC++ GDI多条形码打印实战:从原理到工业级应用

在工业自动化和物流管理系统中,条形码打印是连接物理世界与信息系统的关键技术。其核心原理在于将数据编码为特定宽度的条空图形序列,通过光学扫描设备快速识别。从技术价值看,稳定高效的打印方案能直接提升MES(制造执行系统)、WMS(仓库管理系统)等核心业务系统的数据采集效率和准确性。面对批量、多类型条码(如Code 128、QR Code)混排的工业标签打印需求,开发者常遇到驱动兼容性差、打印队列堵塞等工程难题。本文聚焦于使用VC++与Windows GDI这一经典技术组合,深入剖析设备坐标映射、GDI资源管理等

weixin_32325225的博客 312

visual c++源码自定义打印机纸张大小

VC源码自定义打印机纸张大小

K230开发板实战:5步搞定YOLOv8模型部署(附常见报错解决方案)

本文提供了一份详细的K230开发板部署YOLOv8模型的实战教程。内容涵盖从环境准备、模型转换到代码编写的完整流程,并重点解析了使用AICube工具链时常见的“生成部署文件异常”等报错解决方案,旨在帮助开发者高效完成嵌入式AI模型部署。

weixin_29053073的博客 786

【VC++技术杂谈003】打印技术之打印机状态监控

  在上一篇博文中我主要介绍了如何获取以及设置系统的默认打印机,本文将介绍如何对打印机状态进行实时监控,记录下所打印的文档、打印的份数以及打印时间等打印信息。   1.打印机虚脱机技术   在正式介绍如何对打印机状态进行实时监控之前,我们有必要先了解一下打印机虚脱机技术。   独占设备是指在一个程序(作业、用户)的整个运行期间独占设备,直到该程序(作业、用户)完成。系统的独占设备是有限的(...

weixin_34238633的博客 1519

ST-Link V2的隐藏技能:多通道串口调试的终极指南

本文深入探讨了ST-Link V2的多通道串口调试功能,突破传统烧录工具的限制。通过详细的硬件配置、Arduino IDE设置和实战案例,展示了如何利用SWD接口实现多通道数据监控,提升STM32F103C8T6等开发板的调试效率。文章还提供了PCB布局优化和性能调优技巧,助力开发者充分发挥ST-Link V2的潜能。

weixin_29285605的博客 357
上一篇: STL的find_if函数
下一篇: 串口DCB结构详细说明
laowang2
博客等级 码龄21年 164粉丝 85原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值