FindNextPrinterChangeNotification对于ppPrinterNotifyInfo返回NULL

FindNextPrinterChangeNotification returns NULL for ppPrinterNotifyInfo

本文关键字:NULL 返回 ppPrinterNotifyInfo 对于 FindNextPrinterChangeNotification      更新时间:2023-10-16

我被问题卡住了,我想寻求一些帮助:

我的任务是使用带有"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中获得任何附加数据。这适用于start事件,不过,我使用日志和调试器进行了验证。但是对于PRINTER_CHANGE_DELETE_JOB,我得到的唯一东西是NULL。

我已经在网上搜索过了,有一些类似的问题,但大多数时间都与VB有关,或者只是没有答案。我正在使用一个c++项目,因为我的代码为ADD_JOB-event工作,我不认为我做了什么完全错误的事情。但即使是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

我认为是这样的:

对于每个打印作业的开始和结束,我在两个不同的线程中观察到两个事件。通过一些调试和日志记录,我认识到FindNextPrinterChangeNotification并不总是只返回我所通知的两个不同的事件,而是通常返回一些0事件。在这些情况下,FindNextPrinterChangeNotification返回0作为pdwChange中的事件。如果我使用notepad.exe打印一个简单的文本文件,我只得到一个事件,用于创建pdwChange值为256的打印作业,并且我需要在notifyInfo中比较我打印的文件名,并且比较两者成功。如果我使用当前的Acrobat Reader 11打印一个pdf文件,我会得到两个事件,一个事件的pdwChange值为256,但打印作业启动的名称类似于"local printdatafile",这显然不是我打印的文件。第二个事件的pdwChange为0,但是notifyInfo中提供的打印作业的名称是我用来打印的文件名。当我使用FreePDF来测试程序时,我认为第一个打印机事件是我特殊设置的内部事件。

删除打印作业的通知也会创建0个事件。这一次,它们在FindNextPrinterChangeNotification在pdwChange中返回1024之前发送,并且在打印作业开始之后及时发送。在本例中,生成的0事件包含notifyInfo,其文档名称等于我开始打印的文件名。在0事件之后,正好有一个pdwChange为1024的额外事件,但是没有notifyInfo的任何数据。

我认为Windows正在使用一些机制,在初始事件被触发后,为相同的事件提供额外的通知,并使用用户通知的实际值,例如PRINTER_CHANGE_ADD_JOB的256。另一方面,似乎一些0事件只是简单地为即将到来的事件提供数据,然后获得真实值,例如PRINTER_CHANGE_DELETE_JOB的1024,但没有更多的数据,因为已经通过非常早的0事件交付给事件消费者。比如"看,最后的事件还有更多"answers"看,我现在已经提供的数据将会发生一些事情。"实现了这样的方法,我的印刷品现在似乎像预期的那样工作了。

当然我写的不适合什么是FindNextPrinterChangeNotification的文档,但它对我来说有点意义。: -)

您没有检查溢出或错误。

FindNextPrinterChangeNotification的文档是这样说的:

PRINTER_NOTIFY_INFO_DISCARDED的Flags成员位PRINTER_NOTIFY_INFO结构,发生溢出或错误,并且通知可能已经丢失。在本例中,没有额外的通知将被发送,直到你做出第二个选择FindNextPrinterChangeNotification调用,指定PRINTER_NOTIFY_OPTIONS_REFRESH .

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