J'ai écrit une DLL qui surveille notre imprimante réseau. L'imprimante est connectée au serveur par un câble USB. Lorsque j'imprime quelque chose directement depuis le serveur, il affiche correctement les informations sur les pages envoyées/imprimées, mais lorsque j'imprime quelque chose depuis l'un des ordinateurs clients, il n'affiche que son IP, le nombre de pages envoyées/imprimées est toujours de 0.
Je suppose que c'est un défaut de l'API Winspooler, ma question est la suivante : y a-t-il un moyen de le contourner ?
Voici le code, pour ce qu'il vaut :
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);
}
}
}
};