Thursday, September 19, 2024

Monitoring a print queue from Visual Basic.Net

Although the VB.Net printer handling has improved immeasurably over that offered by Visual Basic 6 there is still a need to turn to the Windows API in order to monitor a print queue.

Note: Some of the API calls used in this example are only supported on Windows NT, 2000, XP and .Net server therefore this technique does not apply to windows 95, Windows 98 or Windows Me

Get a handle to the printer you want to monitor

All of the API calls that access the printer or spooler need a printer handle. This is obtained by passing the unique printer device name to the OpenPrinter API call and must be released when no longer needed, by the ClosePrinter API call.

-==-

Ask for the notifications you are interested in

To minimise the impact of a printer watch on the system performance we can specify precisely which printer events we are interested in. This is done by passing a parameter to FindFirstPrinterChangeNotification using one or more of the following values:

-==-

Specify the information you want returned for the event

When an event occurs, for example if a job is added to the print queue, you will probably want to get information about the job that caused that event. Again, in order to minimise the impact on the system you specify exactly which fields you want information from.

For a print job event the possible fields are:

-==-

To inform the print spooler that you want information on these fields you create a PRINTER_NOTIFY_OPTIONS structure which is passed to FindFirstPrinterChangeNotification and which holds a pointer to an array of PRINTER_NOTIFY_OPTIONS_TYPE, one for each of the above fields that you require. These structures are documented on MSDN

In VB.Net it is easy to translate these structures into classes which can be passed to the API by being marshalled as if they were structures:

-==-

Starting the watch

To start the printer watch you need to pass the printer handle to FindFirstPrinterChangeNotification:

-==-

Waiting for a notification

In the Visual Basic 6 implementation of this a great deal of complexity was added by the fact that it is a single threaded system and so when the program was waiting for the printer notification it was effectively locked up. In Visual Basic .Net this is no longer neccessary as it supports asynchronous events and threading.

The FindFirstPrinterChangeNotification API call returns a Windows synchronisation wait handle. This can be used by the VB.Net common language runtime to trigger a particular subroutine whenever that synchronistation object is signalled. This is done with the Threading.RegisteredWaitHandle object:

-==-

Where PrinterNotifyWaitCallback is a public subroutine that has the correct signature for a WaitOrTimerCallback:

-==-

Getting the information about the event that occured

When that wait object is triggered you have to call FindNextPrinterChangeNotification to find out what event triggered it and get the details.

-==-

This returns a 32 bit number in pdwChange that indicates what event has occured. For example this will contain PRINTER_CHANGE_ADD_JOB when a job is added to the print queue. Additionally it returns a pointer to data allocated by the spooler in lppPrinterNotifyInfo which contains a PRINTER_NOTIFY_INFO structure followed by an array of PRINTER_NOTIFY_INFO_DATA structures. Again in VB.Net these can be represented by classes:

-==-

And you can populate these classes from a pointer using the Marshal.PtrToStructure:

-==-

Feedback?

Comments, praise, criticism or anything else? Write to the the development team and it will passed on as appropriate.

Duncan Jones has been programming in Visual
Basic for 15 years, having started out on Windows 3.0. He is now the lead
programmer for Merrion Computing Ltd – a custom software development house
based in Dublin, Ireland

Related Articles

1 COMMENT

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles