Мониторинг принтера

Я написал DLL, которая следит за нашим сетевым принтером. Принтер подключается к серверу через USB-кабель. Когда я печатаю что-то непосредственно с сервера, он отображает информацию о страницах, отправленных / напечатанных правильно, но когда я что-то печатаю с одного из клиентских компьютеров, он отображает только его IP-адрес, отправлено / напечатано всегда 0.

Я полагаю, что это недостаток API winspooler, у меня вопрос, есть ли способ обойти это?

Вот код, чего он стоит:

typedef struct PRINTERMONITOR_API tagPRINTJOBINFO
{
    // name of the machine that printed
    char *machineName;
    // name of the document
    char *document;
    // total pages actually *printed*
    DWORD totalPages;
    // number of pages sent to the printer
    DWORD printed;
    // private: state of the printJob
    BOOL  done;
} printJobInfo_t;

//-------------------------------------------------------
// Function called when the print job event finishes
//-------------------------------------------------------
typedef void (*Callback)(printJobInfo_t *);

//-------------------------------------------------------
// Printer Monitor class
//-------------------------------------------------------
class PrinterMonitor
{
private:

    //-------------------------------------------------------
    // Handle to the printer.
    //-------------------------------------------------------
    HANDLE                  m_hPrinter;

    //-------------------------------------------------------
    // Handle to the notify object being set when print event
    // occurs.
    //-------------------------------------------------------
    HANDLE                  m_hNotify;

    //-------------------------------------------------------
    // Handle of our worker thread.
    //-------------------------------------------------------
    HANDLE                  m_hThread;

    //-------------------------------------------------------
    // Holds PRINTER_CHANGE_XXX_XXX information about current
    // event.
    //-------------------------------------------------------
    DWORD                   m_dwChanged;

    //-------------------------------------------------------
    // ID of the worker thread.
    //-------------------------------------------------------
    DWORD                   m_dwThreadId;

    //-------------------------------------------------------
    // Name of the printer.
    //-------------------------------------------------------
    char                    *m_pszPrinterName;

    //-------------------------------------------------------
    // Printer event snooping options.
    //-------------------------------------------------------
    PRINTER_NOTIFY_OPTIONS  *m_pOptions;

    //-------------------------------------------------------
    // Output of the event function.
    //-------------------------------------------------------
    PRINTER_NOTIFY_INFO     *m_pOutPut; 

    //-------------------------------------------------------
    // Shall we go away?
    //-------------------------------------------------------
    BOOL                    m_fExit;

public:
    //-------------------------------------------------------
    // Callback function called when the event fires.
    //-------------------------------------------------------
    Callback                m_fpCallback;

    //-------------------------------------------------------
    // Constructor
    // - name of the printer
    // - callback function
    //-------------------------------------------------------
    PrinterMonitor(char *printerName, Callback callback)
    {
        memset(this, 0, sizeof(PrinterMonitor)); // zero me
        m_fpCallback        = callback;
        m_pszPrinterName    = new char[strlen(printerName)];
        strcpy(m_pszPrinterName, printerName);
        m_pOptions          = new PRINTER_NOTIFY_OPTIONS;
        m_hThread           = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PrinterMonitor::StartMonitoring, this, CREATE_SUSPENDED, &m_dwThreadId);
    }

    //-------------------------------------------------------
    // Stop the worker thread and delete some shit
    //-------------------------------------------------------
    ~PrinterMonitor()
    {
        StopMonitor();
        delete(m_pOptions);
        delete[](m_pszPrinterName);
    }

    //-------------------------------------------------------
    // Run the monitor in a seperate thread
    //-------------------------------------------------------
    void RunMonitor()
    {
        ResumeThread(m_hThread);
    }

    //-------------------------------------------------------
    // Stop the monitor, noes.
    //-------------------------------------------------------
    void StopMonitor()
    {
        m_fExit = true;
    }

    //-------------------------------------------------------
    // Checks if this object is a valid monitor
    //-------------------------------------------------------
    BOOL CheckMonitor()
    {
        if (OpenPrinter(this->m_pszPrinterName, &this->m_hPrinter, NULL))
        {
            if (this->m_hPrinter != INVALID_HANDLE_VALUE)
            {
                ClosePrinter(this->m_hPrinter);
                return true;
            }
        }

        return false;
    }

private:
    //-------------------------------------------------------
    // The worker thread proc
    //-------------------------------------------------------
    static void WINAPI StartMonitoring(void *thisPtr)
    {

        PrinterMonitor* pThis = reinterpret_cast<PrinterMonitor*>(thisPtr);

        if (OpenPrinter(pThis->m_pszPrinterName, &pThis->m_hPrinter, NULL))
        {
            WORD wJobFields[5];
            wJobFields[0]           = JOB_NOTIFY_FIELD_STATUS;
            wJobFields[1]           = JOB_NOTIFY_FIELD_MACHINE_NAME;
            wJobFields[2]           = JOB_NOTIFY_FIELD_TOTAL_PAGES;
            wJobFields[3]           = JOB_NOTIFY_FIELD_PAGES_PRINTED;
            wJobFields[4]           = JOB_NOTIFY_FIELD_DOCUMENT;

            PRINTER_NOTIFY_OPTIONS_TYPE rOptions[1];
            rOptions[0].Type    = JOB_NOTIFY_TYPE;
            rOptions[0].pFields = &wJobFields[0];
            rOptions[0].Count   = 5;

            pThis->m_pOptions->Count    = 1;
            pThis->m_pOptions->Version  = 2;
            pThis->m_pOptions->pTypes   = rOptions;
            pThis->m_pOptions->Flags    = PRINTER_NOTIFY_OPTIONS_REFRESH;

            if ((pThis->m_hNotify = 
                FindFirstPrinterChangeNotification(pThis->m_hPrinter, 0, 0, pThis->m_pOptions)) != INVALID_HANDLE_VALUE)
            {
                while(pThis->m_hNotify != INVALID_HANDLE_VALUE && !pThis->m_fExit)
                {
                    if (WaitForSingleObject(pThis->m_hNotify, 10) == WAIT_OBJECT_0)
                    {
                        FindNextPrinterChangeNotification(pThis->m_hNotify, &pThis->m_dwChanged, (LPVOID)pThis->m_pOptions, (LPVOID*)&pThis->m_pOutPut);

                        printJobInfo_t info = {0};
                        for (unsigned int i=0; i < pThis->m_pOutPut->Count; i++)
                        {
                            PRINTER_NOTIFY_INFO_DATA data = pThis->m_pOutPut->aData[i];

                            if (data.Type == JOB_NOTIFY_TYPE)
                            {
                                switch(data.Field
                                {
                                    case JOB_NOTIFY_FIELD_PAGES_PRINTED:
                                        {
                                            info.printed = data.NotifyData.adwData[0];
                                        }
                                        break;

                                    case JOB_NOTIFY_FIELD_MACHINE_NAME:
                                        {
                                            LPSTR name = (LPSTR) data.NotifyData.Data.pBuf;
                                            unsigned int length = strlen(name); 
                                            info.machineName = new char[length];
                                            strcpy(info.machineName, name);                                         
                                        }
                                        break;

                                    case JOB_NOTIFY_FIELD_TOTAL_PAGES:
                                        {
                                            info.totalPages = data.NotifyData.adwData[0];
                                        }
                                        break;

                                    case JOB_NOTIFY_FIELD_DOCUMENT:
                                        {
                                            LPSTR document = (LPSTR) data.NotifyData.Data.pBuf;
                                            unsigned int length = strlen(document);
                                            info.document = new char[length];
                                            strcpy(info.document, document);                                            
                                        }
                                        break;

                                    case JOB_NOTIFY_FIELD_STATUS:
                                        {
                                            if (data.NotifyData.adwData[0] & JOB_STATUS_PRINTED)
                                            {
                                                info.done = true;
                                            }
                                        }
                                        break;
                                }
                            }
                        }

                        if (info.done)
                        {
                            pThis->m_fpCallback(&info);

                            delete[](info.document);
                            delete[](info.machineName);
                        }
                    }
                }

                if (pThis->m_hPrinter != INVALID_HANDLE_VALUE)
                    ClosePrinter(pThis->m_hPrinter);

                if (pThis->m_hNotify != INVALID_HANDLE_VALUE)
                    FindClosePrinterChangeNotification(pThis->m_hNotify);

            }
        }
    }
};
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
3 574
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Понятно. Сетевой принтер отправляет только основную информацию, если она была добавлена ​​автоматически Windows.

Добавление принтера вручную устранило проблему.

Другие вопросы по теме