FindNextPrinterChangeNotification为ppPrinterNotifyInfo返回NULL

时间:2013-04-29 16:38:10

标签: c++ c winapi printing print-spooler-api

如果我想问一些问题,我会遇到问题:

我的任务是使用带有“print”动词的ShellExecuteEx打印一些不同类型的文件,并且需要保证所有文件的打印顺序。因此,我使用FindFirstPrinterChangeNotification和FindNextPrinterChangeNotification来监视事件PRINTER_CHANGE_ADD_JOB和PRINTER_CHANGE_DELETE_JOB使用后台中的两个不同的线程,我在调用ShellExecuteEx之前启动,因为我对打印文件等的应用程序一无所知。我唯一知道的是我是唯一一个打印和我打印的文件。我的解决方案似乎运行良好,我的程序成功识别我的文件的事件PRINTER_CHANGE_ADD_JOB,我甚至通过指定JOB_NOTIFY_FIELD_DOCUMENT检查通过检查作为附加信息给我的内容来验证此事件。

现在的问题是事件PRINTER_CHANGE_DELETE_JOB,我没有得到关于打印作业的任何附加信息,虽然我的逻辑对于两个事件完全相同:我写了一个通用线程函数,它只是执行了它用于的事件。我的线程正在识别PRINTER_CHANGE_DELETE_JOB事件,但每当发生此事件时,每次调用FindNextPrinterChangeNotification时都不会在ppPrinterNotifyInfo中获得任何添加数据。这适用于启动事件,但我使用我的日志和调试器进行了验证。但是使用PRINTER_CHANGE_DELETE_JOB我唯一得到的就是NULL。

我已经在网上搜索了一些类似的问题,但大部分时间都与VB相关或者根本没有答案。我正在使用C ++项目,因为我的代码适用于ADD_JOB事件我不认为我做错了什么。但即使MSDN也没有提到这种行为,我真的想确保DELETE_JOB事件是我的文档的事件,我不能没有关于打印作业的任何信息。在我收到DELETE_JOB事件后,我的代码甚至无法识别其他事件,这是正常的,因为之后完成了打印作业。

以下是我认为的相关通知代码:

WORD                        jobNotifyFields[1]  = {JOB_NOTIFY_FIELD_DOCUMENT};
PRINTER_NOTIFY_OPTIONS_TYPE pnot[1]             = {JOB_NOTIFY_TYPE, 0, 0, 0, 1, jobNotifyFields};
PRINTER_NOTIFY_OPTIONS      pno                 = {2, 0, 1, pnot};
HANDLE                      defaultPrinter      = PrintWaiter::openDefaultPrinter();
HANDLE                      changeNotification  = FindFirstPrinterChangeNotification(   defaultPrinter,
                                                                                        threadArgs->event,
                                                                                        0, &pno);
[...]
DWORD waitResult = WAIT_FAILED;
while ((waitResult = WaitForSingleObject(changeNotification, threadArgs->wfsoTimeout)) == WAIT_OBJECT_0)
{
    LOG4CXX_DEBUG(logger, L"Irgendein Druckereignis im Thread zum Warten auf Ereignis " << LogStringConv(threadArgs->event) << L" erkannt.");

[...]
    PPRINTER_NOTIFY_INFO    notifyInfo  = NULL;
    DWORD                   events      = 0;
    FindNextPrinterChangeNotification(changeNotification, &events, NULL, (LPVOID*) &notifyInfo);
    if (!(events & threadArgs->event) || !notifyInfo || !notifyInfo->Count)
    {
        LOG4CXX_DEBUG(logger, L"unpassendes Ereignis " << LogStringConv(events) << L" ignoriert");
        FreePrinterNotifyInfo(notifyInfo);
        continue;
    }
[...]

我真的很感激,如果有人可以提供一些提示,说明为什么我没有得到有关打印作业的任何数据。谢谢!

https://forums.embarcadero.com/thread.jspa?threadID=86657&stqc=true

2 个答案:

答案 0 :(得分:0)

以下是我的想法:

我在每个打印作业的开始和结束的两个不同线程中观察到两个事件。通过一些调试和日志记录,我发现FindNextPrinterChangeNotification并不总是只返回我通知的两个不同事件,但一般只返回一些0事件。在这些情况下,FindNextPrinterChangeNotification将返回0作为pdwChange中的事件。如果我使用notepad.exe打印一个简单的文本文件,我只会创建一个事件来创建打印作业,其值为256,用于pdwChange,以及notifyInfo中我需要的数据,用于比较我的打印文件名和比较两个成功。如果我使用当前的Acrobat Reader 11打印pdf文件,我会得到两个事件,一个是pdwChange为256,但是提供了类似“本地printdatafile”的内容,因为打印作业的名称已经开始,这显然不是我打印的文件。第二个事件的pdwChange为0,但notifyInfo中提供的打印作业的名称是我用于打印的文件名。当我使用FreePDF测试pruproses时,我认为第一个打印机事件是我特殊设置的内部事件。

删除打印作业的通知也会创建0个事件。这次是在FindNextPrinterChangeNotification在pdwChange中返回1024之前发送的,并且在打印作业开始后及时非常接近。在这种情况下,正好一个生成的0事件包含notifyInfo,其文档名称等于我开始打印的文件名。在0事件之后,只有一个附加事件,pdwChange为1024,但没有任何notifyInfo数据。

我认为Windows正在使用某种机制,该机制在初始事件被触发之后为0事件提供与同一事件的附加通知,其具有用户通知的实际值,例如, 256为PRINTER_CHANGE_ADD_JOB。另一方面,似乎简单地触发了一些0事件以便为即将发生的事件提供数据,然后该事件获得例如1024用于PRINTER_CHANGE_DELETE_JOB,但不再有数据,因为已经将事件传递给事件消费者,并且事件为0。像“看,最后的事件还有更多。”并且“看,我现在提供的数据会发生一些事情。”实现这种方法我的打印现在似乎按预期工作。

当然我写的内容并不适合FindNextPrinterChangeNotification所记录的内容,但它对我来说有点意义。 ; - )

答案 1 :(得分:0)

您没有检查溢出或错误。

FindNextPrinterChangeNotification的文档说明了这一点:

  

如果在Flags成员中设置了PRINTER_NOTIFY_INFO_DISCARDED位   PRINTER_NOTIFY_INFO结构,发生溢出或错误,以及   通知可能已丢失。在这种情况下,没有额外的   通知将被发送,直到你做一秒钟   指定的FindNextPrinterChangeNotification调用   PRINTER_NOTIFY_OPTIONS_REFRESH。

您需要检查该标志并按上述方式执行操作,并且还应检查FindNextPrinterChangeNotification的返回代码。