Printing successfully using impersonation from a 32-bit application on a 64-bit system
There is a known limitation with Windows x64 systems where 32-bit processes fail to print from a thread that uses impersonation (e.g. ImpersonateLoggedOnUser, WindowsIdentity.Impersonate). The simplest workaround is to convert the 32-bit application to 64-bit, but it is not always feasible, especially for legacy applications that rely on components that are only available in 32-bit. As 64-bit systems are getting more common and Windows Server OS has only been available in 64-bit since Windows 2008 R2, more applications are running into this limitation.
I have good news for you if your application is running into this on Windows 8.1 x64 or Windows 2012 R2. There is a hotfix available that addresses the limitation and it is downloadable from the following KB:
"Before you can print, you need to select a printer" error when you try to print from a 32 bit application in Windows 8.1 and Windows Server 2012 R2
https://support.microsoft.com/en-us/kb/3054187.
Why it did not work before.
On Windows 64-bit systems, printer drivers are available only in 64-bit, so they cannot be loaded into 32-bit processes. Thus, a 32-bit process will goes through a 64-bit proxy process called splwow64.exe for printing. I don't get into details of how it is implemented, but let's just say that if a thread is impersonating another user, it cannot communicate with the splwow64 process and any Print Spooler APIs that need to go through the proxy will fail.
How do you know if your application is running into this?
The error message described in the KB is actually from Windows 7 x64 and Windows 2008 R2 when you call:
[Win32]
LogonUser with LOGON32_LOGON_NEW_CREDENTIALS
ImpersonateLoggedOnUser with the token returned by LogonUser
PrintDlg or PrintDlgEx
[Windows Forms]
LogonUser with LOGON32_LOGON_NEW_CREDENTIALS
WindowsIdentity.Impersonate with the token returned by LogonUser
System.Windows.Forms.PrintDialog.ShowDialog
[WPF]
LogonUser with LOGON32_LOGON_NEW_CREDENTIALS
WindowsIdentity.Impersonate with the token returned by LogonUser
System.Windows.Controls.PrintDialog.ShowDialog
On Windows 8.1 x64 or Windows 2012 R2, you won't see any error message, but the following will occur instead:
[Win32] If you use PD_RETURNDC for PrintDlg or PrintDlgEx, it will fail to return a DC in PRINTDLGEX.hDC.
[Windows Forms] PrintDialog.Document.Print will throw Win32Exception: The handle is not valid.
[WPF] Interestingly you can proceed with printing without any problem.
However, when calling LogonUser with LOGON32_LOGON_INTERACTIVE instead of LOGON32_LOGON_NEW_CREDENTIALS, you will see something similar for Win32, Windows Forms and WPF: "Before you can perform printer-related tasks such as page setup or printing a document, you need to install a printer. Do you want to install a printer now?"
These are not the only manifestations of the limitation as any Print Spooler APIs that go through splwow64.exe will fail.
If you believe you are running into this limitation, please give the hotfix a try. For this to work, you also need to install the security update described in the following KB if you have not done so yet:
MS15-044 and MS15-051: Description of the security update for Windows font drivers
https://support.microsoft.com/en-us/kb/3045171/
Follow us on Twitter, www.twitter.com/WindowsSDK.