如何以编程方式打印到在 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 - 查看本文应用于的产品

查看机器翻译免责声明

Microsoft 支持页面的机器翻译

: Microsoft Visual c + +.net (2002) 支持这两个托管的代码模型所提供的.net 框架和非托管本机 Windows 代码模型。本文中信息的部分或全部适用于托管的 Visual c + + 代码,可能只能通过使用.net 框架应用。

展开全部 | 关闭全部

本文内容

概要

在 开发 MFC 应用程序,它有时是用于以编程方式打印到网络打印机或 $ 辅助打印机的非默认打印机的 (不带打印对话框)。若要执行此操作需要 DEVMODE 和 DEVNAMES 结构。这篇文章显示了一个可以设置最多使用 GetPrinter() 调用这些数据结构的方式,并提供有关如何使用它们的示例。

: 在这篇文章中的某些代码不能应用于 Windows 95 和 Windows 98 由于 GetPrinter 可能不适用于网络打印机。

回到顶端 | 提供反馈

更多信息

在 MFC 应用程序的正常打印操作,过程中打印对话框将显示该对话框可选择要打印到的打印机。在打印对话框中显示的默认打印机是在操作系统中指定的默认打印机。 MFC 将存储在默认打印机 CWinApp::m_hDevMode 和 CWinApp::m_hDevNames 中应用程序的受保护的数据成员。因为 MFC 将初始化为 NULL 这些变量,MFC 的打印体系结构默认操作系统的默认打印机第一次执行时打印操作。操作系统默认打印机的 DEVMODE 和 DEVNAMES 然后复制到在 MFC 应用程序的 m_hDevMode 和 m_hDevNames 数据成员。

有时,可能会在需要打印到默认打印机以外的其他打印机,而无需用户通过打印对话框中指定它的情况。辅助打印机或 $ 网络打印机 (假定您的操作系统都已经安装了驱动程序),可以使用非默认打印机

无 论您需要使用非默认打印机在永久的基础上或只有一个打印作业,您将需要 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 函数。有关更多详细信息,请参见上面。

回到顶端 | 提供反馈

时间: 2024-10-07 02:12:29

如何以编程方式打印到在 MFC 中的非默认打印机的相关文章

C#+EntityFramework编程方式详细之Code First 数据迁移

在前几篇的C#+EntityFramework编程方式中介绍了C#+EntityFramework编程方式Code First ,Model First以及Dtatabase First 等编程方式,其中Model First以及Dtatabase First中,如果实体类(Model First)或者数据库(Dtatabase First)变化了,那么就需要数据库(Model First)或者实体类(Dtatabase First)来相应的变化,以保持实体类(Model First)和数据库(

编程方式操作WorkFlow

背景: 刚进某地产公司,就是做一个工作流的小Demo,就是画一条采购的工作流,然后代码实现它. 刚开始的时候真的其实挺迷茫的,然后就从自己比较熟悉的实体做起,接着是controller,然后是view,代码都是参考过N份的,最后代码写的差不多了,然后才开始画一条流程.流程图就画了前后有6份,然后改来改去,还好有各位哥哥帮忙,.最后一条流程总算是走了下来.就在上周五的时候,SA突然让我就开始熟悉需求了,没想到这么快就要开始干活了. 简谈 最开始做工作流的时候,感觉它跟职责链模式很像,它的处理都是一

用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(一)

本文为原创,如有转载,请注明出处:http://www.cnblogs.com/jackybu 前言 章节: 1.需求描述以及c/c++实现日期和月历的基本操作 2.ios实现自绘日期选择控件 3.android实现自绘日期选择控件 目的: 通过一个相对复杂的自定义自绘控件来分享: 1.ios以及android自定义自绘控件的开发流程 2.objc与c/c++混合编程 3.android ndk的环境配置,android studio ndk的编译模式,swig在android ndk开发中的作

ASP.NET MVC下的四种验证编程方式[续篇]

在<ASP.NET MVC下的四种验证编程方式>一文中我们介绍了ASP.NET MVC支持的四种服务端验证的编程方式("手工验证"."标注ValidationAttribute特性"."让数据类型实现IValidatableObject或者IDataErrorInfo"),那么在ASP.NET MVC框架内部是如何提供针对这四种不同编程方式的支持的呢?接下来我们就来聊聊这背后的故事. 一.ModelValidator与ModelVal

即时通讯软件开发 几种网络编程方式

即时通讯软件开发 几种网络编程方式: ISAPI.CGI.WinInet.Winsock 它们之间的区别: 1)ISAPI主要是开发基于浏览器客户端与服务器端程序.效率比CGI方式高,而且也扩展了CGI没有的一些功能.(基于TCP/IP模型中的应用层) 2) CGI主要是开发基于浏览器客户端与服务器端程序.(基于TCP/IP模型中的应用层) 3) WinInet主要是开发客户端程序.(基于TCP/IP模型中的应用层) 4) Winsock主要是基于socket来开发客户端与服务器端程序.(基于T

获取系统当前的输入法列表并通过编程方式切换输入法

1.获取输入法列表 //保存输入法信息的结构     struct _tagInputMethod     {      char szLanguageId[30];      char szLanguageName[100];      char szLanguageImeFileName[100];      HICON hIcon;     }; _tagInputMethod m_InputMethodList[30];     int m_InputMethodCount; //获取输

VB 在Visio 2010 以编程方式创建子进程图

在2010年Visio以编程方式创建子进程图 Office 2010  https://msdn.microsoft.com/en-us/library/gg650651.aspx 简介: 学习如何创建子流程图表以编程方式在Microsoft Visio 2010. 最后修改: 2011年4月07日 适用于: Office 2010 | SharePoint Server 2010 | 2010 | Visio Visio溢价2010 在这篇文章中 概述创建一个流程图创建子流程页面移动一个形状子

EF三种编程方式详细图文教程(C#+EF)

开始学习EF,从网上找了好多,都不是自己想要的,于是边学边把自己学习的过程写下来,以供参考. 操作环境:VS2013+SQLServer2012 Entity Framework4.1之前EF支持“Database First”和“Model First”编程方式,从EF4.1开始EF开始支持支持“Code First”编程方式,今天简单看一下EF三种编程方式. 开始介绍这三种EF操作方式之前,首先在Visual Studio 2013中建立一个数据库连接,这里我们以“EFDemo”数据库为例:

ASP.NET MVC下的四种验证编程方式

原文:ASP.NET MVC下的四种验证编程方式 ASP.NET MVC采用Model绑定为目标Action生成了相应的参数列表,但是在真正执行目标Action方法之前,还需要对绑定的参数实施验证以确保其有效性,我们将针对参数的验证成为Model绑定.总地来说,我们可以采用4种不同的编程模式来进行针对绑定参数的验证. 目录 一.手工验证绑定的参数 二.使用ValidationAttribute特性 三.让数据类型实现IValidatableObject接口 四.让数据类型实现IDataError