我在网上已不断看到一些网友关于自定义纸张打印的问题,基本上还没有较完美的解决方案,我在这里提供一个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++ 打印机设置的更多相关文章

  1. win7无法保存打印机设置(错误0x000006d9)解决方法

    解决win7打印机共享出现‘无法保存打印机设置’操作无法完成(错误0x000006d9),接下来与大家分享下解决方法, 找到windows firewall服务,启用即可 ============== ...

  2. 打印机设置(PrintDialog)、页面设置(PageSetupDialog) 及 RDLC报表如何选择指定打印机

    如果一台电脑同时连接多个打印机,而且每个打印机使用的纸张大小各不相同(比如:票据打印钱用的小票专用张,办公打印机用的是A4标准纸),在处理打印类的需求时,如果不用代码干预,用户必须每次打印时,都必须在 ...

  3. C#获取本地打印机列表,并将指定打印机设置为默认打印机

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.W ...

  4. PrintDocument打印、预览、打印机设置和打印属性的方法

    WindowsForm 使用 PrintDocument打印.预览.打印机设置和打印属性的方法. private void Form1_Load(object sender, System.Event ...

  5. 解决win7打印机共享出现“无法保存打印机设置(错误0x000006d9)的问题

    最新解决win7打印机共享出现“无法保存打印机设置(错误0x000006d9)的问题,由系统下载吧率先分享: 有些用户在使用Windows7系统过程中,碰到到win7打印机共享出现“无法保存打印机设置 ...

  6. WIN7无法保存打印机设置错误0x000006d9处理办法(转载)

    办公电脑安装了GHOST版WIN7操作系统,在设置打印机共享时,报(错误0x000006d9),无法设置打印机共享, 查看微软官方文档:说是停止或禁用了Windows防火墙服务,必须启用 Window ...

  7. .NET环境下有关打印页面设置、打印机设置、打印预览对话框的实现

    原文:.NET环境下有关打印页面设置.打印机设置.打印预览对话框的实现 我个人认为,开发MIS,首先就得解决网格的问题,而开发工具为我们提供了如DataGrid.MSHFlexGrid的控件.其次,是 ...

  8. win7系统内网共享打印机设置

    工作中通常使用内网,你同事的计算机连接了一台打印机,老板没给你单独配打印机,莫慌,你可以通过内网连接同事的打印机. 1.在你同事的电脑上启用来宾账户并按照链接设置:https://jingyan.ba ...

  9. C# 中printDocument打印、预览、打印机设置和打印属性的方法

    private void Form1_Load(object sender, System.EventArgs e) { //获取或设置一个值,该值指示是否发送到文件或端口 printDocument ...

随机推荐

  1. EnumUtil 链表转换工具类

    package com.das.common.util; import org.springframework.util.CollectionUtils; import java.lang.refle ...

  2. 微信&支付宝 支付单文件操作

    https://github.com/dedemao/weixinPay https://github.com/dedemao/alipay https://www.dedemao.com/alipa ...

  3. shell模板-跨目录执行,彩色输出,临时文件,行遍历文件

    参数检查 #!/bin/bash set -e if [ ! -n "$1" ];then echo "Usage: #cmd <> []" exi ...

  4. 死锁的原因及解决办法RLock递归锁

    死锁 说到死锁,可以讲一个科学家吃面的问题: 有几个科学家在一张桌子旁,桌子上只有一把筷子和一碗面,我们将面和筷子都加锁.这是可能会导致一个科学家抢到面,另一个科学家抢到筷子,这是就全部阻塞了,这就是 ...

  5. 【C++/实验三】类和对象

    1.定义一个矩形类,有长,宽两个属性,有成员函数计算矩形的面积. 在该矩形类中,我做了5个主要的测试. 构造函数带默认值参数,利用默认值参数计算矩形面积:rectangle(double x=2.0, ...

  6. windows系统-phpstudy升级mysql8.0.12安装教程及修改密码和安装注意事项

    1.下载安装包,下载地址:mysql8.0.12  .如果你想要下载其它版本可以选择:mysql历史版本地址. 2.下载好,删除phpstudy的mysql目录.如果数据重要的,注意备份数据!同意把m ...

  7. ubuntu下openssh升级

    因客户漏扫扫描出来openssh及openssl存在漏洞,现升级为官方最新版 这里选择编译安装 去官网下载: openssl-1.0.2o.tar.gz openssh7.7.1 zlib-1.2.1 ...

  8. swust oj 962

    括号匹配问题 1000(ms) 65535(kb) 3045 / 13375 假设表达式中允许包含两种括号:圆括号和方括号.编写一个算法判断表达式中的括号是否正确配对. 输入 由括号构成的字符串,包含 ...

  9. js运用3

    1. js的本质就是处理数据.数据来自于后台的数据库. 所以变量就起到一个临时存储数据的作用. ecmascript制定了js的数据类型. 数据类型有哪些? 1. 字符串 string 2. 数字 n ...

  10. Caused by: java.lang.ClassNotFoundException: Could not load requested class :XXX.XXX.XXX 异常处理

    在ssh整合中:出现的异常 Exception sending context initialized event to listener instance of class org.springfr ...