1

I'm trying to create a version 3 virtual printer driver, which uses the XPS filter pipeline to convert the XPS spool file into another PDL and save it to disk.

I'm fine with the conversion side of things (using a pipeline filter), but when it comes to presenting the user with a dialog to select a path to save to, I'm not sure what's best!

I know that when I assign my virtual printer to the 'Print to File' port (FILE:), the spooler will show a default save dialogue before the job hits the print queue, like below on windows 7:

Default save dialog

Only problem is that the default is just a bit too basic. Is there any way to override this default save dialogue for my specific printer driver and provide my own full save dialog?

Thanks a lot!

Andy

Update for the benefit of the comments

This is the call stack of the main thread in Notepad when printing to the Adobe PDF printer and at the stage where the save dialog is showing. I guess my interpretation of this call stack is that there isn't port monitor library involved at the stage when the save dialog is shown. Is my interpretation correct? If so, the question still remains, what's showing the custom save dialog in the Adobe PDF Printer?

ntdll.dll!NtWaitForMultipleObjects+0xa
KERNELBASE.dll!GetCurrentThread+0x36
kernel32.dll!WaitForMultipleObjectsEx+0xb3
USER32.dll!PeekMessageW+0x1cd
DUser.dll+0x14e6
DUser.dll+0x15ef
DUser.dll+0x1565
USER32.dll!TranslateAcceleratorW+0x5e
ntdll.dll!KiUserCallbackDispatcher+0x1f
USER32.dll!WaitMessage+0xa
USER32.dll!MapDialogRect+0x234
USER32.dll!MapDialogRect+0x4c5
USER32.dll!DialogBoxIndirectParamAorW+0x56
USER32.dll!DialogBoxIndirectParamW+0x18
COMDLG32.dll!DllCanUnloadNow+0x590
COMDLG32.dll!Ordinal100+0xb620
COMDLG32.dll!Ordinal100+0xb53f
COMDLG32.dll!Ordinal100+0xb45d
COMDLG32.dll!Ordinal100+0xb31e
COMDLG32.dll!Ordinal100+0xb239
ADUIGP.DLL!DllCanUnloadNow+0x51e
ADUIGP.DLL!DllGetClassObject+0xeef
ADUIGP.DLL!DllCanUnloadNow+0x1441
PS5UI.DLL!DrvDocumentEvent+0xef
WINSPOOL.DRV!Ordinal100+0x20b
WINSPOOL.DRV!DeletePortW+0x2d0
WINSPOOL.DRV!DocumentEvent+0x213
GDI32.dll!ExtFloodFill+0x16b
GDI32.dll!StartDocW+0x58b
notepad.exe+0xa24c
notepad.exe+0x7701
notepad.exe+0x23e8
notepad.exe+0x14eb
USER32.dll!GetSystemMetrics+0x2b1
USER32.dll!GetSystemMetrics+0x4fa
notepad.exe+0x10bc
notepad.exe+0x133c
kernel32.dll!BaseThreadInitThunk+0xd
ntdll.dll!RtlUserThreadStart+0x21
Andy
  • 2,977
  • 2
  • 39
  • 71

2 Answers2

1

Create your own port monitor that provides a better dialog. You can use the sample port monitor in the WDK as a basis for it.

Carey Gregory
  • 6,836
  • 2
  • 26
  • 47
  • I don't think it's the port monitor that the dialog comes from though, isn't it the spooler system that shows the dialog? The UI side of the port monitor is just for adding/removing ports as far as I was concerned. Showing a save dialog in a port monitor looks to be a bit hacky from what I've read. – Andy Jul 09 '12 at 07:43
  • Port monitors run as part of the spooler process. There's nothing hacky at all about showing a save dialog from the UI side of a port monitor. It's how virtually all print-to-file solutions are implemented (the FILE: port, Adobe PDF, etc). If you need to direct output from a print job, a port monitor is precisely the place to do it. Hacky would be trying to display such a dialog from a print driver. – Carey Gregory Jul 09 '12 at 14:14
  • I'm guessing I must be missing something, but it seems to be that the Adobe PDF printer shows it's save dialogue during the StartDocPre event (at least for GDI prints). I was guessing they were implementing the IPrintOemUI2::DocumentEvent method and listening to DOCUMENTEVENT_STARTDOCPOST. I'd like to think I have a good understanding of the basics of this all, but every document assumes knowledge that the average developer doesn't have. So frustrating. – Andy Jul 09 '12 at 15:07
  • Thanks for the help you're giving me by the way! I didn't mean the first comment to sound rude or arrogant! :) – Andy Jul 09 '12 at 15:08
  • It could be showing it from DocumentEvent -- don't know for sure. But many print-to-file type apps do show a dialog from a port monitor. (And yes, the documentation on the Windows printing subsystem is just downright awful and always has been.) No worries.... I didn't interpret your response as rudeness or arrogance. – Carey Gregory Jul 09 '12 at 17:53
  • Just to confirm, if I switch the Adobe PDF reader to using the *nul:* port, the save dialog still shows. I'm sure it must be in a user interface plugin library. Question is, if they use the StartDocPre event, how do they persist the users save location preference so they can use it in the port monitor? For that particular even it seems you only get a const DOCINFO structure... Any ideas? – Andy Jul 10 '12 at 07:46
  • Also, what port monitor mechanism/method exactly is it that other printers use to show a save dialog? Looking at the methods that a port monitor supports, I can't see anything that would fire at the pre-spool stage... http://msdn.microsoft.com/en-us/library/windows/hardware/ff561061(v=vs.85).aspx – Andy Jul 10 '12 at 08:54
  • For persisting the file name they probably use the SetJob function and the pParameters member of the JOB_INFO_2 struct. The port monitor can then retrieve it with GetJob(). If you need to present a dialog before spooling has begun, then a port monitor won't do. You'll need a print driver for that. – Carey Gregory Jul 10 '12 at 15:57
  • Cool, that's what I thought, unfortunately though, from bitter experince, the pParameters member of the JOB_INFO_2 structure is not a good idea. It's used by the print system and between the ui plugin events and the port monitor, it can and will be overwritten (I think on XP/2003). I guess more research is needed! :) – Andy Jul 11 '12 at 07:48
  • I'm working on using the devmode at the moment, but it seems the first private area is badly formed, on my system, meaning I can't reliably get to my private devmode! Argh! – Andy Jul 11 '12 at 07:49
0

Implement your needs extending the WDK XPSDrvSample and change the inf file to point to another location to ensure that all files the printer needs are "fresh", doing so you will avoid the basic dialog. Now you have to implement your own save dialog using a custom port monitor or using a stream filter added to the pipeline path.

Good luck !

PD: you may also use redmon to redirect output to an external app to manage the output.

jmhostalet
  • 4,399
  • 4
  • 38
  • 47
  • I understand the XPSDrv Sample, but when you say 'implement your own save dialog using a custom port monitor', you say it as it there is a well defined way to do this, which from my research, ain't true! ;) Can you elaborate on where you'd put it? I'm sure putting a save dialog in the port monitor would block the print during the 'printing' stage which would be undesirable. Implementing a save dialog in a pipeline filter feels a bit weird, but I could look into it! Although I seem to remember that I read somewhere that filter UI is only supported in Vista and later and we need to support XP! – Andy Jul 11 '12 at 09:44
  • Would a 'stream' filter run during 'spooling' stage as opposed to other filters that seem to operating during the 'printing' stage? – Andy Jul 11 '12 at 09:45
  • Yup, just reading the document here: http://msdn.microsoft.com/en-us/library/windows/hardware/gg463364.aspx... It suggests that filters can only show asynchronous UI to users, so a blocking save dialog would be out the question. It also says Vista and later. – Andy Jul 11 '12 at 11:33