请问如何监控打印机的打印队列?

XiaoDi_Liu 2004-01-10 11:09:08
请问如何监控打印机的打印队列,可以获得正在打印文档的文档名,状态,所有者,页数,大小等.谢谢!
...全文
1248 5 打赏 收藏 举报
写回复
5 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
kundy 2004-04-03
关注 @_@
  • 打赏
  • 举报
回复
lhb1980 2004-01-10
一、API介绍:

API是Application Programming Interface的缩写,也就是应用程序调用系统功能的接口。Windows API主要包括系统定义的函数、消息及与之相关的数据类型。我们使用各种开发工具归根结底都是和API打交道。

二、与打印状态相关的API:

Api函数名 函数说明 W3.x W9x NT
EnumJobs 获取打印作业信息 否 是 是
OpenPrinter 获取指定打印机的句柄 否 是 是


在 Windows NT 版本以及 Windows 9x 中,增加了一批全新的、专门用来处理打印机及打印机队列状态的 API 函数。在这里,将通过 API 函数 OpenPrinter 与 EnumJobs,来确定打印机打印作业状态所需的信息。

OpenPrinter,用来获取给定打印机的句柄,通过该句柄可以实现对相应打印机的操作。

函数 EnumJobs,用来列出所指定打印机上正在打印的作业信息,这里给定打印机的引用就是通过使用上述OpenPrinter函数反馈回来的打印机句柄。


EnumJobs函数介绍:

EnumJobs (ByVal hPrinter As Long, ByVal FirstJob As Long, ByVal NoJobs As Long, ByVal Level As Long, pJob As Long, ByVal cbBuf As Long, pcbNeeded As Long, pcReturned As Long)

API函数EnumJobs用于列举给定打印机当前所有正在打印的任务状态信息,该函数可以列举给定打印机简要的或者详细的(Level决定)队列任务状态信息。在引用该函数时,通常先把cbBuf变量设置为0,以获得打印机队列任务的字节数,该字节数存储在pcbNeeded里以决定pJob变量大小,然后再次引用该函数,获得打印机队列任务的详细信息。

参数:

hPrinter

打印机句柄。

FirstJob

统计打印机队列任务数的起始点,0表示从第一个任务开始统计列举所有的打印任务。

NoJobs

需要列举的最大打印任务数。一般设为127。

Level

标示存储在pJob里的信息格式。如果该值为1,数据以JOB_INFO_1的格式存储;如果该值为2,数据以JOB_INFO_2的格式存储。

pJob

数组变量,保存打印任务的所有信息;cbBuf设为0时,该值也为0。Level变量的值决定pJob的数据格式(JOB_INFO_1 OR JOB_INFO_2)

cbBuf

该值通常为0。

pcbNeeded

存储打印机里打印任务的字节数。

pcReturned

用来存放打印任务数量的变量。

通过上表可以看出,这两个API函数只用使用在Windows 9x 以及 Windows NT环境中。

三、开发工具:

C++ Builder作为快速开发Windows平台下应用程序的工具,已经为越来越多的开发者采用。但是,如果要开发出专业的Windows应用软件,还需要使用大量的Windows API函数,以下是笔者应用C++ Builder以及Windows API函数来实现对打印机状态的时时监控。

选择C++ Builder的理由:

一:由于Windows API 都是用C或C++编写的,C++ Builder更易于底层应用。

二:C++ Builder对于Windows API的引用更加简单,这一点是Visual Basic所欠缺的。


四、程序实例:

1、启动C++ Builder程序,新创建一个工程;

2、进入工程,在当前窗体分别添加一个CheckListBox控件、一个Timer控件;

3、在CheckListBox控件的Item属性添加打印机名称列表(假设在网络中HostPrinter主机上有三台打印机Printer1、Printer2、Printer3),则Item项目里内容格式为:\\HostPrinter\Printer1、\\HostPrinter\\Printer2、\\HostPrinter\\Printer3 ;

4、Timer的Interval属性设置为60000(一分钟),在Timer的OnTimer事件加入如下代码:


{

HANDLE hPrinter; //打印机句柄

JOB_INFO_2 jobs[30]; //保留打印作业详细信息

DWORD size=sizeof(jobs);

JOB_INFO_2 *jobs1=NULL; //动态数组用于对大于size的任务进行操作

DWORD pcbNeeded=0; //所有打印字节数

int actNeed=0;

DWORD pcReturned=0; //打印任务数

char buf[19]; //指向打印机或机器名

int ret1; //获得打印机句柄返回值

int ret; //获得打印机任务返回值

TDateTime startTime;

Word Hour=0;

Word Hour1=0;

Word Min=0;

Word Min1=0;

Word Sec=0;

Word MSec=0;

int StartTime=0; //任务开始时间

int NowTime=0; //当前时间

int TotalTime=0; //任务停留时间

String str;

int length;

int PrintCount;

int InitCount=15; //设定的打印队列数量--------报警底线

int InitTime=10; //设定的打印队列事件--------报警底线(分钟)


PrintCount =CheckListBox1->Count ;

for (int i=0; i < PrintCount; i++)

{


//..............取得列表里的打印机

str=CheckListBox1->Items->Strings[i] ;

length=str.Length() ;


//................字符串到字符的转换,

StrPLCopy(buf,str,length);


//................获得打印机句柄

ret1= OpenPrinter(buf, &hPrinter, NULL);


//................获得打印任务数

ret= EnumJobs(hPrinter, 0, 127, 2,0, 0, &pcbNeeded, &pcReturned); //必要的一步,先取出打印机里任务的字节数,然后决定jobs1变量大小。//--------------------------①


//.................重定义Jobs1, 根据pcbNeeded决定使用哪个变量

if (pcbNeeded>size)

{

actNeed=pcbNeeded;

jobs1=new JOB_INFO_2[actNeed];

ret= EnumJobs(hPrinter, 0, 127, 2,(LPBYTE)jobs1, actNeed, &pcbNeeded, &pcReturned);

startTime=SystemTimeToDateTime(jobs1[0].Submitted); //------------------②

delete jobs1;

}

else

{

ret= EnumJobs(hPrinter, 0, 127, 2,(LPBYTE)jobs, size, &pcbNeeded, &pcReturned);//-----------------------------③

if (pcReturned>0)

startTime=SystemTimeToDateTime(jobs[0].Submitted);

}

//.................pcbNeeded>size结束


//................如果队列里有打印任务,比对数量与时间

if (pcReturned>0)

{


//.................时间转换,计算一天内的时间差

{

//............时间比较运算处理;

//............时间转换StartTime转换成分钟


}

DecodeTime(Now(),Hour1, Min1, Sec,MSec);

NowTime=Hour1*60+Min1;

TotalTime=NowTime-StartTime;

}


//依据条件判断是否报警

if ((pcReturned>InitCount) |(TotalTime >InitTime))

{


Beep();


}


pcReturned=0;

pcbNeeded=0;


}


//..........................pcReturned>0结束


}//....................................................for结束



5、编译并运行上述程序:

①程序中,此处的获得打印机任务的目的主要是获得打印机作业的字节数------ pcbNeeded,该变量里字节的大小,将决定进一步获得打印机里作业的状态时所用的变量是Jobs还是Jobs1。

②当pcbNeeded>size,给Jobs1分配空间,然后获得打印机当前作业的状态。

③当pcbNeeded<size,用Jobs作为变量,获得当前打印机作业状态。


用C++ Builder编程监控打印机队列状态:
只需要转换成vc++即可

注:②、③参数引用与①不同。

五、应用分析:

可以说IT技术在制造业得到了广泛的应用,而打印控制与监控则是制造业中众多应用中的较为典型的应用。通常,在生产制造过程中,都有很多打印机用于打印生产排序单、装配单、铭牌、标签等等。因此打印机的时时状态(缺纸、墨尽、卡纸)在这里就显得尤为重要了,如果不能及时的监控到打印机的状态势必会影响生产的正常持续运行。所以为了保证生产正常运行拥有一套用于监控打印机时时状态的程序是很有必要的。
  • 打赏
  • 举报
回复
sxslyy 2004-01-10
更完整的例子可以参考微软的Knowledge Base的文章:“Q158828 OWTO: How To Call Win32 Spooler Enumeration APIs Properly”和微软的Knowledge Base的文章:“Q228769 OWTO: Retrieve Print Job Information”。

http://support.microsoft.com/support/kb/articles/Q158/8/28.asp
http://support.microsoft.com/support/kb/articles/Q228/7/69.asp
  • 打赏
  • 举报
回复
sxslyy 2004-01-10
确定打印队列的状态

问题
  有时,程序员需要显示存在于系统中的各种打印机中打印作业的状态,但似乎不能找到一种方法来查询当前哪些打印机是可用的以及在这些打印机上正在运行哪些作业。
  那么,如何利用 Windows API 函数来查询可用的打印机及其所处的工作状态呢?

方法
  在 Windows NT 版本以及 Windows 9x 中,增加了一批全新的、专门用来处理打印机及打印机队列状态的 API 函数。在本节中,将讨论 API 函数 EnumPrinters 与 EnumJobs,这两个函数可提供给程序员确定打印作业状态所需的信息。
  在 Windows 9x 中添加的函数 EnumPrinters,用来列出所有正在有效运行的打印机的名称及其标识符,此函数可用于列出用户能够访问的无论是在本地工作的还是在网络上运行的所有打印机,在本节的例子中,我们只考虑本地打印机的情况。
  新的 Windows 9x API 中增加的另一个函数 EnumJobs,用来列出所指定打印机上正在打印的作业,为了能够使用这个函数,必须有打印机的句柄,这就需要使用另外一个 API 函数 OpenPrinter。
  需要注意的是,这几个 API 函数只能在 Windows 9x 以及 Windows NT 中使用。

步骤
  按照下列方法生成一个例子程序。选择菜单 Dialog,并从此菜单中选择菜单项 Printer Jobs,此时显示一个所有可用打印机的对话框,在第一个列表框中选择其中一个打印机后,即在第二个列表框中显示该打印机的作业列表。

  实现例子程序的步骤如下:
  1.在 Visual C++ 中利用 AppWizard 创建新的工程 Ld104。
  2.进入 AppStudio,创建新的对话框。把按钮 OK 与 Cancel 移动到对话框的底部。在对话框中添加两个列表框。
  3.进入 ClassWizard,为刚创建的对话模板生成新的对话框类,把此新类命名为 CPrintQDlg。
  4.在 ClassWizard 中,从下拉列表中选择类 CPrintQDlg,从对象列表中选择对象 CPrintQDlg,从消息列表中选择消息 WM_INITDIALOG,点击按钮 Add Function 添加新的函数 OnInitDialog。把下面的代码输入到类 CPrintQDlg 的方法 OnInitDialog 中。


BOOL CPrintQDlg::OnInitDialog()
{
CDialog::OnInitDialog();

int size=4096;
unsigned long sizeNeeded=0;
unsigned long numPrinters;
PPRINTER_INFO_1 pPrinters;
pPrinters=(PPRINTER_INFO_1)LocalAlloc((LMEM_FIXED/LMEM_ZEROINIT),size);
int ret=EnumPrinters(PRINTER_ENUM_LOCAL,NULL,1,
(LPBYTE)pPrinters,size,&sizeNeeded,&numPrinters);
CListBox * list=(CListBox *)GetDlgItem(IDC_LIST1);
for(int i=0;i<(int)numPrinters;++i)
list->AddString(pPrinters[i].pName);
LocalFree(pPrinters);

return TRUE; // return TRUE unless you set the focus to a control
}

  5.在 ClassWizard 中,从下拉列表中选择类 CPrintQDlg,从对象列表中选择对象 IDC_LIST1,从消息列表中选择消息 LBN_SELCHANGE,点击按钮 Add Function 添加新的函数 OnSelectPrinter。把下面的代码输入到类 CPrintQDlg 的方法 OnSelectPrinter 中。

void CPrintQDlg::OnSelectPrinter()
{
HANDLE handle;
JOB_INFO_1 jobs[10];

CListBox * list1=(CListBox *)GetDlgItem(IDC_LIST1);
char buf[256];
list1->GetText(list1->GetCurSel(),buf);

if(!OpenPrinter(buf,&handle,NULL))
{
MessageBox("Could not open printer","Error",
MB_OK/MB_ICONINFORMATION);
return;
}

DWORD size=sizeof(jobs);
DWORD numBytes=0;
DWORD numEntries=0;
int ret=EnumJobs(handle,0,10,1,(LPBYTE)jobs,
size,&numBytes,&numEntries);

CListBox * list2=(CListBox *)GetDlgItem(IDC_LIST2);
for(int i=0;i<(int)numEntries;++i)
{
char buf[80];
sprintf(buf,"Job %ld",jobs[i].JobId);
if(jobs[i].pStatus!=NULL)
strcat(buf,jobs[i].pStatus);
else
{
switch(jobs[i].Status)
{
case JOB_STATUS_PAUSED:
strcat(buf," Paused");
break;
case JOB_STATUS_PRINTED:
strcat(buf," Printed");
break;
case JOB_STATUS_PRINTING:
strcat(buf," Printing");
break;
case JOB_STATUS_SPOOLING:
strcat(buf," Spooling");
break;
}
}
list2->AddString(buf);
}
}

  6.把下面一行代码添加到文件 PrintQDlg.cpp 的顶端。
  #include "winspool.h"
  7.进入 AppStudio 并在菜单 IDR_MAINFRAME 中添加新菜单 Dialog。在此菜单中添加标题为 Printer Jobs 的菜单项,标识符命名为 ID_PRINTER_JOBS。
  8.进入 ClassWizard,从下拉组合框中选择对象 CMainFrame,从对象列表中选择对象 ID_PRINTER_JOBS,从消息列表中选择消息 COMMAND,点击按钮 Add Function 添加新的函数 OnPrinterJobs,把下面的代码输入到此方法中。

void CMainFrame::OnPrinterJobs()
{
CPrintQDlg dlg;

dlg.DoModal();
}

  9.把下面一行代码添加到文件 MainFrame.cpp 的顶端。
  #include "PrintQDlg.h"
  10.编译并运行此例子程序。


  • 打赏
  • 举报
回复
zhangcrony 2004-01-10
//樓上的代碼是C++ Builder的啊﹗
//我提供一段VC++的代碼﹐樓主試試﹗
BOOL GetJobs(HANDLE hPrinter, /* Handle to the printer. */

JOB_INFO_2 **ppJobInfo, /* Pointer to be filled. */
int *pcJobs, /* Count of jobs filled. */
DWORD *pStatus) /* Print Queue status. */

{

DWORD cByteNeeded,
nReturned,
cByteUsed;
JOB_INFO_2 *pJobStorage = NULL;
PRINTER_INFO_2 *pPrinterInfo = NULL;

/* Get the buffer size needed. */
if (!GetPrinter(hPrinter, 2, NULL, 0, &cByteNeeded))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
return FALSE;
}

pPrinterInfo = (PRINTER_INFO_2 *)malloc(cByteNeeded);
if (!(pPrinterInfo))
/* Failure to allocate memory. */
return FALSE;

/* Get the printer information. */
if (!GetPrinter(hPrinter,
2,
(LPSTR)pPrinterInfo,
cByteNeeded,
&cByteUsed))
{
/* Failure to access the printer. */
free(pPrinterInfo);
pPrinterInfo = NULL;
return FALSE;
}

/* Get job storage space. */
if (!EnumJobs(hPrinter,
0,
pPrinterInfo->cJobs,
2,
NULL,
0,
(LPDWORD)&cByteNeeded,
(LPDWORD)&nReturned))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
free(pPrinterInfo);
pPrinterInfo = NULL;
return FALSE;
}
}

pJobStorage = (JOB_INFO_2 *)malloc(cByteNeeded);
if (!pJobStorage)
{
/* Failure to allocate Job storage space. */
free(pPrinterInfo);
pPrinterInfo = NULL;
return FALSE;
}

ZeroMemory(pJobStorage, cByteNeeded);

/* Get the list of jobs. */
if (!EnumJobs(hPrinter,
0,
pPrinterInfo->cJobs,
2,
(LPBYTE)pJobStorage,
cByteNeeded,
(LPDWORD)&cByteUsed,
(LPDWORD)&nReturned))
{
free(pPrinterInfo);
free(pJobStorage);
pJobStorage = NULL;
pPrinterInfo = NULL;
return FALSE;
}

/*
* Return the information.
*/
*pcJobs = nReturned;
*pStatus = pPrinterInfo->Status;
*ppJobInfo = pJobStorage;
free(pPrinterInfo);

return TRUE;

}

BOOL IsPrinterError(HANDLE hPrinter)
{

JOB_INFO_2 *pJobs;
int cJobs,
i;
DWORD dwPrinterStatus;

/*
* Get the state information for the Printer Queue and
* the jobs in the Printer Queue.
*/
if (!GetJobs(hPrinter, &pJobs, &cJobs, &dwPrinterStatus))
return FALSE;

/*
* If the Printer reports an error, believe it.
*/
if (dwPrinterStatus &
(PRINTER_STATUS_ERROR |
PRINTER_STATUS_PAPER_JAM |
PRINTER_STATUS_PAPER_OUT |
PRINTER_STATUS_PAPER_PROBLEM |
PRINTER_STATUS_OUTPUT_BIN_FULL |
PRINTER_STATUS_NOT_AVAILABLE |
PRINTER_STATUS_NO_TONER |
PRINTER_STATUS_OUT_OF_MEMORY |
PRINTER_STATUS_OFFLINE |
PRINTER_STATUS_DOOR_OPEN))
{
return TRUE;
}

/*
* Find the Job in the Queue that is printing.
*/
for (i=0; i < cJobs; i++)
{
if (pJobs[i].Status & JOB_STATUS_PRINTING)
{
/*
* If the job is in an error state,
* report an error for the printer.
* Code could be inserted here to
* attempt an interpretation of the
* pStatus member as well.
*/
if (pJobs[i].Status &
(JOB_STATUS_ERROR |
JOB_STATUS_OFFLINE |
JOB_STATUS_PAPEROUT |
JOB_STATUS_BLOCKED_DEVQ))
{
return TRUE;
}
}
}

/*
* No error condition.
*/
return FALSE;

}
  • 打赏
  • 举报
回复
发帖
VC/MFC

1.6w+

社区成员

VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
帖子事件
创建了帖子
2004-01-10 11:09
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……