PrintVerifier architecture
Time to discuss the architecture of PrintVerifier and how it works. The following image has a stack-wise illustration of the PrintVerifier architecture.
I wish I had been able to animate the image since that would have explained the details so much better. Anyway, since that wasn't easy to do let me try to explain how this works.
From the PrintVerifier perspective, there are two important boundaries to monitor...the boundary between printing applications and the print subsystem and the boundary between the core printer drivers and 3rd party plug-in drivers. These two boundaries have been classified as the PrintAPI and PrintDriver verification layers respectively. The term "verification layer" comes from Application Verifier where it is used to indicate a single set of tests. The collection of these verification layers makes up the AppVerifier package.
AppVerifier works by modifying the unmanaged DLLs Method Tables so that the required checks are performed before and/or after the real function is executed. This is also called "Function Hooking". Since PrintVerifier is part of AppVerifier, it employs the same mechanism for monitoring print-specific functions and interfaces. For example, the address of the Win32 API OpenPrinter is replaced with an internal PrintVerifier method that will trigger a series of tests such as resource tracking, handle leaks and multi-threaded handle use. You can find more details about how AppVerifier implements function hooking here.
The PrintAPI layer hooks Win32 APIs such as OpenPrinter, ClosePrinter, ResetPrinter, EnumPrinters, SetJob, GetJob, WritePrinter, SetPrinter, PTOpenProvider, PTConvertDevModeToPrintTicket and PTCloseProvider. So a call-stack resulting from an application calling say OpenPrinter would look like:
0:000> k
ChildEBP RetAddr
0007e268 6e9d7245 WINSPOOL!OpenPrinterW
0007e294 76ee00a4 vfprint!VfHookOpenPrinterW+0x83
0007e6dc 76ee2285 foo!main+0xe1
So the vfPrint!VfHookOpenPrinterW method will perform the required checks both before and after the call to winspool!OpenPrinterW. Note that the "hooked" functions specified above form a very small subset of the total list of functions hooked by the PrintAPI layer.
The PrintDriver layer hooks the IPrintOemUni, IPrintOemUni2, IPrintOemUni3, IPrintOemPS, IPrintOemPS2, IPrintOemUI, IPrintOemUI2 and IPrintOemPrintTicketProvider interfaces. It also hooks rendering DDIs such as OEMStartDoc, OEMTextOut and OEMEndDoc. For example, a call to IPrintOemUni2::ImageProcessing would look like:
0:014> k
ChildEBP RetAddr
04e6d9bc 6e9db919 BITMAP!COemUni2::ImageProcessing
04e6d9ec 6c7e36c7 vfprint!CPrintVerifierOemUni2::ImageProcessing+0x45
04e6da20 6c7f928d UNIDRV!HComImageProcessing+0x3c
04e6dc14 76894afa UNIDRV!DrvSendPage+0xfa
Again, the vfPrint!CPrintVerifierOemUni2::ImageProcessing method will perform the required checks both before and after the call to the plug-in's ImageProcessing method.
I hope this post has given you a fairly clear picture of how PrintVerifier works. If not, don't worry. Try giving PrintVerifier a whirl and that might help you understand it better. We also have more posts in the works that will help you get a crystal clear understanding of how you can use PrintVerifier to the fullest possible extent.