如果我想寻求帮助,我会陷入困境:
我的任务是使用带有“print”动词的ShellExecuteEx打印一些不同类型的文件,并且需要保证所有文件的打印顺序。因此,我使用FindFirstInterchangeNotification和FindNextPrinterChangeNotification来监视打印机更改添加作业和打印机更改删除作业的事件,在调用ShellExecuteEx之前,我在后台使用两个不同的线程,因为我对将打印文件的应用程序一无所知我是唯一一个打印的人,我打印的是哪个文件。我的解决方案似乎运行良好,我的程序成功地识别了我的文件的事件打印机更改添加作业,我甚至通过指定作业通知字段文档检查作为附加信息提供给我的内容来验证是否为我的文件发出了此事件。
现在的问题是事件打印机更改删除作业,在这里我没有得到关于打印作业的任何附加信息,尽管我的逻辑对这两个事件都是完全相同的:我编写了一个通用线程函数,它只是用它所用于的事件来执行。我的线程正在识别PRINTER_CHANGE_DELETE_JOB事件,但每次调用findnextprinterchange通知时,只要发生此事件,我就不会在ppPrinterNotifyInfo中获取任何附加数据。这对start事件有效,不过,我使用日志和调试器进行了验证。但是对于PRINTER-CHANGE-DELETE-JOB,我得到的唯一结果是空值。
我已经在网上搜索过了,也有一些类似的问题,但大多数时候都与VB有关,或者根本没有答案。我正在使用C++项目,因为我的代码工作在AdjJOB事件中,我不认为我在做完全错误的事情。但即使是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测试pruproses时,我认为第一个打印机事件是我特殊设置的内部事件。
删除打印作业的通知也会创建0个事件。这一次是在findnextprinterchange通知返回pdwChange中的1024之前发送的,并在打印作业开始后及时关闭。在本例中,恰好生成的0事件包含notifyInfo,其文档名等于我开始打印的文件名。在0事件之后,正好有一个pdwChange为1024的附加事件,但是没有用于notifyInfo的任何数据。
我认为Windows正在使用某种机制,在初始事件被触发后,它将为与0事件相同的事件提供额外的通知,用户使用它通知的实际值,例如256用于PRINTER_CHANGE_ADD_JOB。另一方面,似乎只是触发了一些0事件来为即将发生的事件提供数据,然后获取实际值1024(例如打印机更改/删除作业),但没有更多的数据,因为它已经通过一个非常早的0事件传递给事件消费者。类似于“看,最后的事件还有更多的内容”和“看,我现在已经提供的数据会发生一些事情。”实现这样一种方法,我的打印图现在看起来像预期的那样工作。
当然,我所写的并不适合FindNextPrinterChangeNotification的文档,但它对我来说有点意义。;-)

09-12 06:44