FindNextPrinterChangeNotification возвращает NULL для ppPrinterNotifyInfo

Я застрял в проблеме, где я хотел бы попросить помощи:

У меня есть задача распечатать некоторые файлы разных типов, используя 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


person Thorsten Schöning    schedule 29.04.2013    source источник


Ответы (2)


Вот что я думаю происходит:

Я наблюдаю два события в двух разных потоках для начала и конца каждого задания на печать. С некоторой отладкой и ведением журнала я понял, что FindNextPrinterChangeNotification всегда возвращает не только два отдельных события, о которых я уведомил, но и некоторые 0-события в целом. В этих случаях FindNextPrinterChangeNotification возвращает 0 в качестве событий в pdwChange. Если я печатаю простой текстовый файл с помощью notepad.exe, я получаю только одно событие для создания задания на печать со значением 256 для pdwChange и данных, которые мне нужны в notifyInfo для сравнения имени моего напечатанного файла и сравнения обоих успешно. Если я печатаю pdf-файл с помощью текущего Acrobat Reader 11, я получаю два события, одно имеет pdwChange как 256, но дает что-то вроде «local printdatafile» в качестве имени запущенного задания на печать, которое, очевидно, не является файлом, который я распечатал. Второе событие имеет pdwChange, равное 0, но имя задания на печать, указанное в notifyInfo, — это имя файла, которое я использовал для печати. Поскольку я использую FreePDF для тестирования печати, я думаю, что событие первого принтера является чем-то внутренним для моей специальной настройки.

Уведомления об удалении задания на печать также создают 0 событий. На этот раз они отправляются до того, как FindNextPrinterChangeNotification вернет 1024 в pdwChange, и своевременно очень близко после начала задания на печать. В этом случае ровно одно сгенерированное событие 0 содержит notifyInfo с именем документа, которое равно имени файла, который я начал печатать. После события 0 есть ровно одно дополнительное событие с pdwChange 1024, но без каких-либо данных для notifyInfo.

Я думаю, что Windows использует какой-то механизм, который предоставляет дополнительные уведомления для того же события, что и 0 событий, после того, как начальное событие было запущено с его реальным значением, о котором уведомил пользователь, например. 256 для PRINTER_CHANGE_ADD_JOB. С другой стороны, кажется, что некоторые события 0 просто запускаются, чтобы предоставить данные для предстоящего события, которое затем получает реальное значение, например. 1024 для PRINTER_CHANGE_DELETE_JOB, но без дополнительных данных, поскольку они уже были доставлены потребителю событий с очень ранним событием 0. Что-то вроде «Смотрите, есть еще для последних событий». и «Посмотрите, что-то произойдет с данными, которые я уже предоставил сейчас». Благодаря такому подходу мои отпечатки теперь работают, как и ожидалось.

Конечно, то, что я написал, не соответствует тому, что задокументировано для FindNextPrinterChangeNotification, но для меня это имеет смысл. ;-)

person Thorsten Schöning    schedule 30.04.2013
comment
Есть ли причина, по которой это объяснение было отклонено? Даже MSDN говорит что-то о свертывающихся событиях, нескольких данных событий в одном уведомлении и т. д. - person Thorsten Schöning; 02.05.2013

Вы не проверяете наличие переполнения или ошибок.

Документация для FindNextPrinterChangeNotification говорит следующее:

Если бит PRINTER_NOTIFY_INFO_DISCARDED установлен в члене Flags структуры PRINTER_NOTIFY_INFO, произошло переполнение или ошибка, и уведомления могли быть потеряны. В этом случае никакие дополнительные уведомления не будут отправлены, пока вы не сделаете второй вызов FindNextPrinterChangeNotification, указав PRINTER_NOTIFY_OPTIONS_REFRESH.

Вам нужно проверить этот флаг и сделать, как описано выше, и вы также должны проверить код возврата от FindNextPrinterChangeNotification.

person Carey Gregory    schedule 01.05.2013
comment
Я уже добавил проверку ошибок, но это ничего не изменило в отношении моей проблемы, и никакие данные никогда не удалялись. Отброшенные события всегда являются ошибкой и в моем случае, так как мне нужно знать, было ли удалено задание на печать, и это событие также могло быть отброшено и больше никогда не будет отправлено. - person Thorsten Schöning; 02.05.2013