C++ 打印机设置
我在网上已不断看到一些网友关于自定义纸张打印的问题,基本上还没有较完美的解决方案,我在这里提供一个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);
---------------------
作者:laowang2
来源:CSDN
原文:https://blog.csdn.net/wewaa/article/details/5992011
版权声明:本文为博主原创文章,转载请附上博文链接!
C++ 打印机设置的更多相关文章
- win7无法保存打印机设置(错误0x000006d9)解决方法
解决win7打印机共享出现‘无法保存打印机设置’操作无法完成(错误0x000006d9),接下来与大家分享下解决方法, 找到windows firewall服务,启用即可 ============== ...
- 打印机设置(PrintDialog)、页面设置(PageSetupDialog) 及 RDLC报表如何选择指定打印机
如果一台电脑同时连接多个打印机,而且每个打印机使用的纸张大小各不相同(比如:票据打印钱用的小票专用张,办公打印机用的是A4标准纸),在处理打印类的需求时,如果不用代码干预,用户必须每次打印时,都必须在 ...
- C#获取本地打印机列表,并将指定打印机设置为默认打印机
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.W ...
- PrintDocument打印、预览、打印机设置和打印属性的方法
WindowsForm 使用 PrintDocument打印.预览.打印机设置和打印属性的方法. private void Form1_Load(object sender, System.Event ...
- 解决win7打印机共享出现“无法保存打印机设置(错误0x000006d9)的问题
最新解决win7打印机共享出现“无法保存打印机设置(错误0x000006d9)的问题,由系统下载吧率先分享: 有些用户在使用Windows7系统过程中,碰到到win7打印机共享出现“无法保存打印机设置 ...
- WIN7无法保存打印机设置错误0x000006d9处理办法(转载)
办公电脑安装了GHOST版WIN7操作系统,在设置打印机共享时,报(错误0x000006d9),无法设置打印机共享, 查看微软官方文档:说是停止或禁用了Windows防火墙服务,必须启用 Window ...
- .NET环境下有关打印页面设置、打印机设置、打印预览对话框的实现
原文:.NET环境下有关打印页面设置.打印机设置.打印预览对话框的实现 我个人认为,开发MIS,首先就得解决网格的问题,而开发工具为我们提供了如DataGrid.MSHFlexGrid的控件.其次,是 ...
- win7系统内网共享打印机设置
工作中通常使用内网,你同事的计算机连接了一台打印机,老板没给你单独配打印机,莫慌,你可以通过内网连接同事的打印机. 1.在你同事的电脑上启用来宾账户并按照链接设置:https://jingyan.ba ...
- C# 中printDocument打印、预览、打印机设置和打印属性的方法
private void Form1_Load(object sender, System.EventArgs e) { //获取或设置一个值,该值指示是否发送到文件或端口 printDocument ...
随机推荐
- 使用Apache下poi创建和读取excel文件
一:使用apache下poi创建excel文档 @Test /* * 使用Apache poi创建excel文件 */ public void testCreateExcel() { // 1:创建一 ...
- u3d内嵌H5游戏 设置cookie
Intent intent1 = getIntent(); Log.d("SS", "onCreate: "); String data = intent1.g ...
- Mysql 数据库开发规范
设计范式参看,DDL与DDL 库表基础规范 1.注释 每个表要添加注释,对 status 型需指明主要值的含义,如”0-离线,1-在线” 2.表的字段数量 单表字段数一般考虑上限为 30左右,再多的话 ...
- C 输出变量值到文件中的方法
LinphoneChatMessage *message FILE *fpt; fpt = fopen("wendangming.txt", "w");//打开 ...
- PostMessage 解析
首先是 windows API 中的一个函数, 作用就是放一条消息到消息队列里. 这个函数讲一个消息放入到与 指定窗口 创建的线程相联系的消息队列里,不等待线程处理消息就返回,是一步消息模式, 消 ...
- HttpClient学习记录-系列2(源码学习)
如何阅读第三方工具源码? 存在多个入口,而且整个类图存在很多孤岛,自上而下的分析策略貌似不行,还是从use case入手,针对单个面分析.难点是如何做范围界定?不至于陷入黑洞 HttpGet -- ...
- JS------获取一个时间区间的所有天
1:获取一个时间区间的所有日期 function getDiffDate(start, end) { var startTime = getDate(start); var endTime = get ...
- Alpine Linux常用命令
一:Alpine Linux开启SSH远程登陆 1.简介: 最重要的一个服务了,远程登陆需要用它,文件传输需要用它,必备功能.不管你是在实体机上跑,虚拟机上跑,docker里面跑,这个都是必须的. 2 ...
- Flv视频格式如何转换成MP4格式
如何将flv视频格式转换成MP4格式呢?随着现在视频格式的不断多样化,视频格式转换的问题也成了现在生活中常见的问题,那么我们应该怎样将flv视频格式转换成MP4格式呢?下面我们就一起来看一下吧. 操作 ...
- iview form 表单的怪异小BUG
当同一个弹窗中的表单重复利用时: 我原先的代码逻辑是: <Form :label-width="100" class="mt20" ref="c ...