如何以编程方式打印到在 MFC 中的非默认打印机
http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece763105790245b09c0252bd7a74a2485d315d2390f07506694ea7a7d0d5d83d87f6305ac4957f7b86c65377571eb8f8dd50a8bb485582a9f5631671df65663d50edcba5154cb37e12efeae69f0caf625e7aec5a5de4320c944040a9780fb4d7467&p=c4759a46d7c002fb09be9b7c5b5390&newp=b471c54ad5c242fe19f3cb2d02148c231610db2151ddd4122e958d17&user=baidu&fm=sc&query=%B7%C7%C4%AC%C8%CF%B4%F2%D3%A1%BB%FA&qid=f3d87aaa0004b57b&p1=2
文章编号: 166129 - 查看本文应用于的产品
本文内容
概要
注: 在这篇文章中的某些代码不能应用于 Windows 95 和 Windows 98 由于 GetPrinter 可能不适用于网络打印机。
更多信息
有时,可能会在需要打印到默认打印机以外的其他打印机,而无需用户通过打印对话框中指定它的情况。辅助打印机或 $ 网络打印机 (假定您的操作系统都已经安装了驱动程序),可以使用非默认打印机。
无 论您需要使用非默认打印机在永久的基础上或只有一个打印作业,您将需要 DEVMODE 和 DEVNAMES 结构创建 DC 上的打印机。从 GetPrinter() PRINTER_INFO_2 结构包含填充 DEVMODE 和 DEVNAMES 结构所需的全部信息。
创建一个 DEVMODE 和 DEVNAMES 结构
下面的代码示例演示如何使用 GetPrinter() 创建 DEVMODE 和 DEVNAMES 结构基于打印机名称。该代码是全局函数的返回数据结构,通过它的参数。
#include <winspool.h> // returns a DEVMODE and DEVNAMES for the printer name specified
BOOL GetPrinterDevice(LPTSTR pszPrinterName, HGLOBAL* phDevNames, HGLOBAL* phDevMode)
{
// if NULL is passed, then assume we are setting app object's
// devmode and devnames
if (phDevMode == NULL || phDevNames == NULL)
return FALSE; // Open printer
HANDLE hPrinter;
if (OpenPrinter(pszPrinterName, &hPrinter, NULL) == FALSE)
return FALSE; // obtain PRINTER_INFO_2 structure and close printer
DWORD dwBytesReturned, dwBytesNeeded;
GetPrinter(hPrinter, 2, NULL, 0, &dwBytesNeeded);
PRINTER_INFO_2* p2 = (PRINTER_INFO_2*)GlobalAlloc(GPTR,
dwBytesNeeded);
if (GetPrinter(hPrinter, 2, (LPBYTE)p2, dwBytesNeeded,
&dwBytesReturned) == 0) {
GlobalFree(p2);
ClosePrinter(hPrinter);
return FALSE;
}
ClosePrinter(hPrinter); // Allocate a global handle for DEVMODE
HGLOBAL hDevMode = GlobalAlloc(GHND, sizeof(*p2->pDevMode) +
p2->pDevMode->dmDriverExtra);
ASSERT(hDevMode);
DEVMODE* pDevMode = (DEVMODE*)GlobalLock(hDevMode);
ASSERT(pDevMode); // copy DEVMODE data from PRINTER_INFO_2::pDevMode
memcpy(pDevMode, p2->pDevMode, sizeof(*p2->pDevMode) +
p2->pDevMode->dmDriverExtra);
GlobalUnlock(hDevMode); // Compute size of DEVNAMES structure from PRINTER_INFO_2's data
DWORD drvNameLen = lstrlen(p2->pDriverName)+1; // driver name
DWORD ptrNameLen = lstrlen(p2->pPrinterName)+1; // printer name
DWORD porNameLen = lstrlen(p2->pPortName)+1; // port name // Allocate a global handle big enough to hold DEVNAMES.
HGLOBAL hDevNames = GlobalAlloc(GHND,
sizeof(DEVNAMES) +
(drvNameLen + ptrNameLen + porNameLen)*sizeof(TCHAR));
ASSERT(hDevNames);
DEVNAMES* pDevNames = (DEVNAMES*)GlobalLock(hDevNames);
ASSERT(pDevNames); // Copy the DEVNAMES information from PRINTER_INFO_2
// tcOffset = TCHAR Offset into structure
int tcOffset = sizeof(DEVNAMES)/sizeof(TCHAR);
ASSERT(sizeof(DEVNAMES) == tcOffset*sizeof(TCHAR)); pDevNames->wDriverOffset = tcOffset;
memcpy((LPTSTR)pDevNames + tcOffset, p2->pDriverName,
drvNameLen*sizeof(TCHAR));
tcOffset += drvNameLen; pDevNames->wDeviceOffset = tcOffset;
memcpy((LPTSTR)pDevNames + tcOffset, p2->pPrinterName,
ptrNameLen*sizeof(TCHAR));
tcOffset += ptrNameLen; pDevNames->wOutputOffset = tcOffset;
memcpy((LPTSTR)pDevNames + tcOffset, p2->pPortName,
porNameLen*sizeof(TCHAR));
pDevNames->wDefault = 0; GlobalUnlock(hDevNames);
GlobalFree(p2); // free PRINTER_INFO_2 // set the new hDevMode and hDevNames
*phDevMode = hDevMode;
*phDevNames = hDevNames;
return TRUE;
}
作为了快速参考下面是 DEVNAMES 的声明与每个字段的简短说明:
// commdlg.h
// the first three members are character offsets from the beginning of the // structure pointing to the specific string
typedef struct tagDEVNAMES {
WORD wDriverOffset; // file name of driver (without extension)
WORD wDeviceOffset; // device name
WORD wOutputOffset; // device name of physical output medium
WORD wDefault; // DN_DEFAULTPRN if default printer chosen
} DEVNAMES;
设置应用程序的默认打印机
若要设置默认打印机,您需要设置 m_hDevNames 和 m_hDevMode 数据成员 (它受保护) 该 CWinApp 的成员函数通过该应用程序的派生对象,GetPrinterDevice()。您可以实现下面的函数,并调用它时您需要更改默认打印机。
void CMainFrame::OnActionSetnondefaultprinter()
{
HGLOBAL hDevMode = NULL;
HGLOBAL hDevNames = NULL;
if (GetPrinterDevice(_T("\\\\RED-PRN-25\\PRIV0006"), &hDevNames, &hDevMode))
AfxGetApp()->SelectPrinter(hDevNames, hDevMode);
else
AfxMessageBox(_T("Failed to select custom printer"));
}
绕过打印对话框时使用应用程序的默认打印机
若要绕过打印对话框,OnPreparePrinting 需要被重写,以便可以将 m_bDirect 标志设置为 TRUE。然后调用 DoPreparePrinting,以设置-> m_pd.hDevMode m_pPD pInfo 的值和 pInfo-> m_pPD-> m_pd.hDevNames 到相应的应用程序对象的数据成员和创建 DC 上的打印机。
BOOL CNonDefPrinterView::OnPreparePrinting(CPrintInfo* pInfo)
{
pInfo->m_bDirect = TRUE; // TRUE if bypassing Print Dialog
return DoPreparePrinting(pInfo);
}
绕过打印对话框时使用非默认打印机
要跳过打印对话框,并使用非默认打印机,您需要-> m_pd m_pPD pInfo 数据成员自己设置和创建 DC 上的打印机。以下是将实现此目的的代码:
BOOL CNonDefPrinterView::OnPreparePrinting(CPrintInfo* pInfo)
{
// set to non-default printer without changing default app printer
HGLOBAL hDevMode;
HGLOBAL hDevNames; if (!GetPrinterDevice(_T("\\\\RED-PRN-25\\PRIV0006"), &hDevNames, &hDevMode))
AfxMessageBox(_T("GetPrinterDevice called failed\n")); pInfo->m_pPD->m_pd.hDevMode = hDevMode;
pInfo->m_pPD->m_pd.hDevNames = hDevNames;
pInfo->m_pPD->CreatePrinterDC(); return TRUE;
}
本示例显示了使用 GetPrinterDevice 函数。有关更多详细信息,请参见上面。
如何以编程方式打印到在 MFC 中的非默认打印机的更多相关文章
- 【VC++技术杂谈002】打印技术之获取及设置系统默认打印机
本文主要介绍如何获取以及设置系统的默认打印机. 1.获取系统中的所有打印机 获取系统中的所有打印机可以使用EnumPrinters()函数,该函数可以枚举全部的本地.网络打印机信息.其函数原型为: B ...
- SpringMVC(十六):如何使用编程方式替代/WEB-INF/web.xml中的配置信息
在构建springmvc+mybatis项目时,更常用的方式是采用web.xml来配置,而且一般情况下会在web.xml中使用ContextLoaderListener加载applicationCon ...
- 如何在MFC中创建非矩形button
一般情况下,我们创建的按钮都是矩形的,但有时为了满足特殊的需求,我们要在对话框中创建一个非矩形的按钮,比如,圆形,椭圆等. 要实现一个非矩形的按钮,这就涉及到了自绘控件.自绘控件的方法有很多,可以参考 ...
- EF三种编程方式的区别Database first ,Model first ,code first
首先对于EF中先出现的datebase first和model first两种编程方式,其的区别根据字面意思很容易能够理解. datebase first就是代表数据库优先,那么前提就是先创建数据 ...
- C#+EntityFramework编程方式详细之Code First 数据迁移
在前几篇的C#+EntityFramework编程方式中介绍了C#+EntityFramework编程方式Code First ,Model First以及Dtatabase First 等编程方式, ...
- 多线程编程之二 ---MFC中的多线程开发
下载源代码 五.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消 ...
- MFC模态和非模态对话框编程
MFC中对话框有两种形式,一个是模态对话框(model dialog box),一个是非模态对话框(modeless dialog box). 一.模态对话框(model dialog box) 在程 ...
- 解决在编程方式下无法访问Spark Master问题
我们可以选择使用spark-shell,spark-submit或者编写代码的方式运行Spark.在产品环境下,利用spark-submit将jar提交到spark,是较为常见的做法.但是在开发期间, ...
- 38、数据源Parquet之使用编程方式加载数据
一.概述 Parquet是面向分析型业务的列式存储格式,由Twitter和Cloudera合作开发,2015年5月从Apache的孵化器里毕业成为Apache顶级项目,最新的版本是1.8.0. 列式存 ...
随机推荐
- printf("%f\n",5);
http://zhidao.baidu.com/link?url=87OGcxtDa6fQoeKmk1KylLu4eIBLJSh7CA3n5NWY-Ipm9TxZViFnIui307duCXWhaM0 ...
- 【安装防火墙】没有iptables时的解决办法
一.检查iptables服务状态 首先检查iptables服务的状态 [root@woxplife ~]# service iptables status iptables: Firewall is ...
- 浅谈java中死锁问题
知识点:死锁的产生.死锁的实例 一:死锁的产生 我们在解决多线程共享资源的线程同步问题时,会使用synchronized关键字修饰方法或者通过Lock加锁方式修饰方法.代码块,防止多个线程访问统一资源 ...
- eclipse 在线安装反编译插件
打开eclipse help>install New Software…..>add Name:jd-eclipse_update_site Location:http://jd.beno ...
- 使用PDFminer3k解析pdf为文字遇到:WARING:root:GBK-EUC-H
最近需要把PDF解析为文字,查了查python的模块,发现PDFminer3k能满足需求.我使用的是 windows平台下的python3.6,python2的则下载pdfminer. 首先下载:直接 ...
- Java 类引入 学习记录规整
之前觉得声明一个类,再把另一个包内的声明数值用第一个类打印出来就可以了(加入引入包类) 结果发现是不对的 看了看demo 得出正确结果 ImportTest 被运行 引入下面的Import类 ...
- 项目梳理4——WebApi项目,使用注释填充Description字段
web.config中添加连接字符串: 为webapi添加Description,使用注释来填充此字段 对于所有引用的xxxx.base项目设置生成的xml文档,注意release.debug下都需设 ...
- Springboot统一参数验证方式
Springboot统一验证方式 在提供http api 接口形式的服务中,通过都会传递参数为一个对象.我们需要对这个对象的各个字段进行校验.来判断是否为合法值. 传统的方式为自己获取每个字段的值,自 ...
- jekins 插件离线安装
官网插件地址:http://updates.jenkins-ci.org/download/plugins/ 系统管理->插件管理->高级 选择一个下载好的插件,然后点击上传即可 然后就会 ...
- shell case语句
case 格式 case 值 in 模式1) command1 command2 ... commandN ;; 模式2) command1 command2 ... commandN ;; esac ...