Search code examples
c#printingeasyhookapimonitor

Hooking into Win32 printing API from C# using EasyHook


Something similar was asked before, but didn't receive any answers. My question is a bit more generic.

I'm looking for a way to use EasyHook library in a C# app that would enable me to intercept the key printing API calls from, say, notepad.exe.

My goal is to redirect the Notepad's printing to a different printer than the one Notepad selected.

This, of course, is just an artificial test. But if it proves successful, I would use the solution to redirect printing from an actual legacy app which has no way to configure the target printer. It simply prints to the system default printer, which is not always acceptable to users.

Furthermore, the original source code of the app has been lost when the vendor went out of business, many years ago, so there's no chance of modifying it. But I hope to solve it using API hooks, as explained.

Now, the problem is that I'm not entirely sure, which APIs to hook!

Using API Monitor v2 I was able to determine that Notepad calls into the OpenPrinterW inside PrintConfig.dll. I wasn't able to find the headers for this specific DLL, but I've found a very similar function inside winspool.drv.

NOTE: I've determined that the previous statement was wrong, much to my joy! There isn't any other function other than the one in winspool.drv. I misread the API Monitor's output and assumed that PrintConfig.dll is the implementing library, when in fact it is only the calling one. Phew! But sadly, still no cigar, so the question stands.

Unfortunately, all my attempts at hooking it have failed. My code simply isn't getting called. On the other hand, hooking e.g. the kernel32.dll's ReadFile works as expected in all my tests.

It's worth mentioning that I'm not married to the idea of hooking specifically OpenPrinterW. The reasons I chose to start here are:

  1. The API Monitor shows that it is indeed the one being called (at least by Notepad).
  2. It looks like the right one, because it accepts the printer name and returns a handle, which is then passed to other printing calls. If I could change the printer name inside my hook before calling the actual OpenPrinterW, I'd feel like I'm probably 90% there.

So... Any ideas?


Solution

  • I found the problem after adding some additional logging code to my hook DLL.

    At the moment I'm attempting to install the hook into the Notepad process from inside my injected DLL, the winspool.drv module isn't yet loaded into the process. It only gets loaded the first time it is actually needed. Doh!

    A simple LoadLibrary call solved the problem for me and I can now successfully intercept the OpenPrinterW API.

    Now for the remaining 10% of the problem... :)