我在网上已不断看到一些网友关于自定义纸张打印的问题,基本上还没有较完美的解决方案,我在这里提供一个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. unable to create ...erroractionpreference....

    Docker on windows 10 can't startup after deleting MobyLinuxVM in Hyper-V manually 重新启动hyper-v就可以解决了

  2. Java课程寒假之开发记账本软件(网页版)之五

    一.实现基本功能之后 可以添加其他功能,比如说添加账户,删除账户,以及查询页面的分页.(我都没写,滑稽) 二.基本功能部分截图

  3. @media 媒体查询

    @media screen and (max-width: 300px) { //当视口宽度小于等于300px时生效 } max-width  相当于  <=  @media screen an ...

  4. Educational Codeforces Round 1

    598A - Tricky Sum    20171103$$ans=\frac{n(n+1)}{2} - 2\sum_{k=0}^{\left \lfloor \log_2 n \right \rf ...

  5. java的方法重载

    1丶java的方法重载特性 满足以下条件的两个或多个方法构成“重载”关系:(1)方法名相同 (2)参数类型不同,参数个数不同或者参数类型的顺序不同 像System.out.println一样,就是重载 ...

  6. 性能测试yslow

    YSlow YSlow可以对网站的页面进行分析,并告诉你为了提高网站性能,如何基于某些规则而进行优化. YSlow可以分析任何网站,并为每一个规则产生一个整体报告,如果页面可以进行优化,则YSlow会 ...

  7. Java基础学习笔记十九 File

    IO概述 回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了.那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再把这些数据 ...

  8. C#获取邮件客户端保存的邮箱密码

    有时候邮件客户端记录了邮箱密码,但自己却忘记了,此时可以使用C#建立一个临时的"邮件服务器",截取密码: IPEndPoint ipEndPoint = new IPEndPoin ...

  9. RMQPOJ3264

    Balanced Lineup POJ-3264 DP分析 设A[i]是要求区间最值的数列,F[i, j]表示从第i个数起连续2^j个数中的最大值.(DP的状态) 初状态是F[i,0]=A[i] 状态 ...

  10. Codeforces Round div2 #541 题解

    codeforces Round #541 abstract: I构造题可能代码简单证明很难 II拓扑排序 III并查集 启发式排序,带链表 IV dp 处理字符串递推问题 V 数据结构巧用:于二叉树 ...