1

如果我想寻求帮助,我遇到了问题:

我的任务是使用带有“打印”动词的 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

4

2 回答 2

0

您不是在检查溢出或错误。

FindNextPrinterChangeNotification的文档是这样说的:

如果在 PRINTER_NOTIFY_INFO 结构的 Flags 成员中设置了 PRINTER_NOTIFY_INFO_DISCARDED 位,则发生溢出或错误,并且通知可能已丢失。在这种情况下,在您进行第二个指定 PRINTER_NOTIFY_OPTIONS_REFRESH 的 FindNextPrinterChangeNotification 调用之前,不会发送其他通知。

您需要检查该标志并执行上述操作,并且您还应该检查来自FindNextPrinterChangeNotification.

于 2013-05-01T18:02:43.117 回答
0

这是我认为正在发生的事情:

对于每个打印作业的开始和结束,我在两个不同的线程中观察到两个事件。通过一些调试和日志记录,我认识到 FindNextPrinterChangeNotification 并不总是只返回我通知过的两个不同的事件,但通常会返回一些 0 事件。在这些情况下,FindNextPrinterChangeNotification 返回 0 作为 pdwChange 中的事件。如果我使用 notepad.exe 打印一个简单的文本文件,我只会得到一个用于创建打印作业的事件,pdwChange 的值为 256,并且我需要在 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 事件相同的事件提供额外的通知,它是用户通知的真实值,例如 PRINTER_CHANGE_ADD_JOB 的 256。另一方面,似乎一些 0 事件被简单地触发以提供即将发生的事件的数据,然后为 PRINTER_CHANGE_DELETE_JOB 获得例如 1024 的实际值,但没有更多数据,因为它已经很早就交付给了事件消费者0 事件。像“看,最后的事件还有更多”。“看,我现在已经提供的数据将会发生一些事情。” 实施这种方法,我的打印现在似乎按预期工作。

当然,我写的内容不符合 FindNextPrinterChangeNotification 记录的内容,但对我来说有点道理。;-)

于 2013-04-30T13:25:26.297 回答