How to listen for Printer Connections?
The other day, a customer wanted to listen (in C++) for newly added printers. He was trying to use
FindFirstPrinterChangeNotification but was never notified.
It turned out that he was adding network printers, which belonged to a different print server (effectively creating a “Printer Connection”) and that
FindFirstPrinterChangeNotification only works for printers belonging to the local print server (i.e. to the local machine):
|The FindFirstPrinterChangeNotification function creates a change notification object and returns a handle to the object. You can then use this handle in a call to one of the wait functions to monitor changes to the printer or print server.
There is no equivalent to
FindFirstPrinterChangeNotification, which listens for new/changed Printer Connections – and a polling mechanism was not an option. However, there is another way, using WMI.
First of all, here is an overview of the necessary steps. I will explain the why and the how in more detail later.
- To begin, we scan for all existing printer connections.
- Then we have to retrieve the current user’s SID.
- We start listening for changes to the registry key under which printer connections are stored. (We need to know the SID for this.)
- Whenever we are notified, we do another scan and compare the result with the previous scan. The differences are the changes made to the printer connections.
Scanning for current Printer Connections
Using the function
EnumPrinters, supplying the PRINTER_ENUM_CONNECTIONS constant, we can get a list of all currently connected printers and their details.
Getting the current user’s SID
Please refer to the following article to see how to get the SID of the currently logged in user: Getting the Logon SID in C++
Listen for changes made to a registry key
The following article describes how to receive WMI event notifications: Example: Receiving Event Notifications Through WMI
By using the
RegistryKeyChangeEvent class we can apply this to our problem. For each Printer Connection, a new registry key is created below HKEY_CURRENT_USER\Printers\Connections. However, due to the following limitation we cannot use this path, but have to use HKEY_USERS\ <SID> \Printers\Connetionsinstead:
|Changes to the HKEY_CLASSES_ROOT and HKEY_CURRENT_USER hives are not supported by RegistryEvent or classes derived from it, such as RegistryKeyChangeEvent.
The WQL query to use in this case would look like this:
"SELECT * FROM RegistryKeyChangeEvent WHERE KeyPath='<SID>\\\\Printers\\\\Connections' AND Hive='HKEY_USERS'"
Unfortunately, we cannot use the
RegistryValueChangeEvent (because the scope of the query would be too big (we’d receive an error message), so we can only know when something changed below the Printers\Connections key, but not what. This is why we have to rely on EnumPrinters.
I hope this information helps you to implement your own notification mechanism for Printer Connections.