使用API:EnumPrinters();
以下为代码示例:
// Use for enum printers
#include <Winspool.h>
#pragma comment(lib, "winspool.lib")
BOOL HasPrinters()
{
DWORD Flags = PRINTER_ENUM_FAVORITE | PRINTER_ENUM_LOCAL; //local printers
DWORD cbBuf;
DWORD pcReturned;
DWORD Level = 2;
TCHAR Name[500] ;
LPPRINTER_INFO_2 pPrinterEnum = NULL;
memset(Name,0,sizeof(TCHAR)*500);
::EnumPrinters(Flags, Name, Level, NULL, 0, &cbBuf, &pcReturned);
pPrinterEnum = (LPPRINTER_INFO_2)LocalAlloc(LPTR, cbBuf+4);
if (NULL == pPrinterEnum)
{
TRACE( "Error %1d/n ", GetLastError()) ;
return FALSE;
}
if (!EnumPrinters(
Flags, // DWORD Flags, printer object types
Name, // LPTSTR Name, name of printer object
Level, // DWORD Level, information level
(LPBYTE)pPrinterEnum, // LPBYTE pPrinterEnum, printer information buffer
cbBuf, // DWORD cbBuf, size of printer information buffer
&cbBuf, // LPDWORD pcbNeeded, bytes received or required
&pcReturned) // LPDWORD pcReturned number of printers enumerated
)
{
TRACE( "Error %1d/n ", GetLastError());
return FALSE;
}
if (pcReturned > 0)
{
return TRUE;
}
else
{
return FALSE;
}
}
//指定打印机名打印
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <string>
using namespace std;
#define PRINTER_NAME "HP Officejet J5700 Series"
int main() {
string hello = "!!! Hello Printer !!!\f";
HANDLE hPrinter = NULL;
DOC_INFO_1 DocInfo;
DWORD dwJob;
DWORD dwBytesWritten = 0L;
if(OpenPrinter((LPTSTR)_T(PRINTER_NAME), &hPrinter, NULL )) {
cout << "printer opened" << endl;
DocInfo.pDocName = (LPTSTR)_T("My Document");
DocInfo.pOutputFile = NULL;
DocInfo.pDatatype = (LPTSTR)_T("RAW");
dwJob = StartDocPrinter( hPrinter, 1, (LPBYTE)&DocInfo );
if (dwJob != 0) {
cout << "Print job open" << endl;
if (StartPagePrinter( hPrinter )) {
cout << "Page started" << endl;
// Send the data to the printer.
if (WritePrinter( hPrinter, (void*)hello.c_str(), hello.length(), &dwBytesWritten)) {
if (dwBytesWritten == hello.length()) { cout << "Message sent to printer" << endl; }
}
EndPagePrinter (hPrinter);
cout << "Page Closed" << endl;
}
// Inform the spooler that the document is ending.
EndDocPrinter( hPrinter );
cout << "Print job open" << endl;
} else {
cout << "Could not create print job" << endl;
}
// Close the printer handle.
ClosePrinter( hPrinter );
cout << "printer closed" << endl;
} else {
cout << "Could not open Printer" << endl;
}
cout << "done";
return 0;
}
Visual C++6.0是开发Windows应用程序的强大工具,但是要通过它实现程序的打印功能,一直是初学者的一个难点,经常有朋友询问如何在VC中实现打印功能,他们往往感到在MFC提供的框架内实现这个问题很复杂,不知道如何下手。本例针对这个问题,介绍一种简单的方法实现文字串的打印功能,读者朋友可以在此基础上稍微改动一下,就可以实现文件、图像的打印功能。
一、实现方法
在Windows操作系统下,显示器、打印机和绘图仪都被视为输出设备,正常情况下,系统默认的输出设备是显示器。要使用打印机,首先需要创建一个指向打印机的设备环境句柄,然后通过该句柄调用相关的绘图函数把所需的文字和图形输出至打印机上。当打印结束后,删除这个设备环境句柄即可。
当Windows系统中安装好打印机后,系统总是自动设置一个打印机为系统的默认打印机,在Windows的启动配置文件Win.ini中的[window]段中列出了带有关键字device的默认打印机。下面是某一机器中Win.ini中的[Windows]字段的内容:
[windows]
load=
run=
NullPort=None
device=HP LaserJet 4050(computer000),HPBFDB1,LPT1
在上述关键字device后的字符串中,包含了系统中默认打印机的三个重要属性,它们依次是打印机的设备名HP LaserJet 4050(computer000),驱动程序名是HPBFDB1,输出端口为LPT1。
为了操纵系统默认的打印机,实现程序的打印功能,在程序中可调用API函数GetProfileString()从Win.ini文件中获得device这个设备字符串,该函数的原型为:DWORD GetProfileString( LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize)。函数中lpAppName参数为所要检索的Win.ini文件中的字段名;lpKeyName为字段中的关键字名;lpDefault为默认的字符串;lpReturnedString为检索到的字符串,如果该函数没有从lpKeyName关键字中检索到相应的字符串,则kpRetrunedString返回默认字符串lpDefault;nSize为返回字符串的长度。
获取上述字符串后,再使用strtok()函数将该字符串进行分解,获得与打印机相关的三个属性,作为API函数CreateDC()创建打印机设备环境句柄的参数,CreateDC()函数如果调用成功,则为默认打印机创建一个设备环境句柄,否则返回一个空值(NULL)。该函数的原形为:HDC CreateDC(LPCTSTR lpszDriver,LPCTSTR lpszDevice,LPCTSTR lpszOutput,CONST DEVMODE *lpinitData)。该函数的前三个参数恰好对应打印机的三个属性,最后一个参数为初始化打印机驱动程序的数据,一般情况下该参数设置为NULL就可以了。
在具体打印的过程中,调用int StartDoc( HDC hdc, CONST DOCINFO *lpdi )函数来开始一个打印任务,其中参数lpdi为一个指向DOCINFO结构的指针,该结构如下:
typedef struct {
int cbSize; //结构的尺寸大小;
LPCTSTR lpszDocName; //文档的名字;
LPCTSTR lpszOutput; //输出文档名,一般情况下为NULL;
LPCTSTR lpszDatatype;//用来记录打印过程的数据类型,一般情况下为NULL;
DWORD fwType; //用来支持打印工作的额外信息,一般情况下为NULL;
} DOCINFO, *LPDOCINFO;
开始一个打印任务后,再调用StartPage(hdcprint)函数让打印机走纸,通知打印机有文档将要打印;接下来的工作就是输出数据了,这部分工作对于开发人员来说就象往计算机屏幕上输出文字、图像一样容易,只不过是计算机根据当前的设备环境句柄自动将数据输出到打印机罢了。数据打印完后,需要作一些善后处理工作,使用RestoreDC(hdcprint,-1)函数恢复打印机设备句柄、EndPage(hdcprint)函数让打印机停止打印,最后调用EndDoc(hdcprint)函数结束上述的打印作业。
二、编程步骤
1、启动Visual C++6.0,新建一个基于对话框的应用程序Test,在程序的对话框窗体中加入一个按钮(Button),设置这个Button的属性:ID=IDC_PRINT,CAPTION="打印";
2、使用Class Wizard类向导为该按钮添加一个鼠标单击处理函数OnPrint()
3、修改TestDlg.cpp文件中的OnPrint()函数;
4、添加代码,编译运行程序。
三、程序代码
void CTestDlg::OnPrint()
{
char szprinter[80];
char *szDevice,*szDriver,*szOutput;
HDC hdcprint; // 定义一个设备环境句柄
//定义一个打印作业
static DOCINFO di={sizeof(DOCINFO),"printer",NULL};
// 得到设备字符串存入数组szprinter中
GetProfileString("windows","device",",,,",szprinter,80);
// 将设备字符串分解
if(NULL!=(szDevice=strtok(szprinter,","))&&NULL!=(szDriver=strtok(NULL,","))&&
NULL!=(szOutput=strtok(NULL,",")))
// 创建一个打印机设备句柄
if((hdcprint=CreateDC(szDriver,szDevice,szOutput,NULL))!=0)
{
if(StartDoc(hdcprint,&di)> 0) //开始执行一个打印作业
{
StartPage(hdcprint); //打印机走纸,开始打印
SaveDC(hdcprint); //保存打印机设备句柄
// 输出一行文字
TextOut(hdcprint,1,1,"热烈祝贺编程实例出版发行!",16);
RestoreDC(hdcprint,-1); //恢复打印机设备句柄
EndPage(hdcprint); //打印机停纸,停止打印
EndDoc(hdcprint); //结束一个打印作业
MessageBox("打印完毕!","提示",MB_ICONINFORMATION);
}
// 用API函数DeleteDC销毁一个打印机设备句柄
DeleteDC(hdcprint);
}
else
{
MessageBox("没有默认打印机,或者没有安装打印机!");
return;
}
}