Has C# PrintDocument Started Showing a Varying Printer Dialog for You?
- subsystems09
- Aug 28
- 5 min read
If you maintain a Windows Forms application that prints through PrintDocument and PrintDialog, you may have noticed something strange lately: the printer dialog your users see is no longer consistent. Some users get the familiar classic print dialog. Others get a much larger dialog with an empty preview pane on the right and an odd title bar that reads “Printing from Win32 application” instead of your application’s name. Same application, same code, same printer different dialog.
We recently chased this down for our TE Edit Control component after a customer reported the new dialog appearing, and the investigation took enough wrong turns that the story seemed worth writing up. If you’re seeing the same symptom, this post should save you a day or two.
The symptom
Two versions of the same .NET application, both compiled against .NET Framework 2.0 with identical compiler settings, showed different print dialogs. The older build displayed the classic dialog. The newer build displayed the new dialog with the preview rectangle — a preview that, for a GDI-based PrintDocument, remains permanently empty with a “No preview available” message. The customer wanted the classic dialog back.
The print code itself was ordinary and unchanged for years:
PrintDialog PrtDlg = new PrintDialog();
PrtDlg.Document = pd;
PrtDlg.AllowSomePages = true;
PrtDlg.AllowSelection = true;
PrtDlg.UseEXDialog = true;
if (PrtDlg.ShowDialog() != DialogResult.OK) ...The wrong suspects, in order
Debugging this was an exercise in eliminating variables one at a time — and every variable we eliminated made the mystery stranger.
Suspect 1: the target framework. The new Windows 11 print dialog is known to appear for modern .NET applications, so the obvious theory was that the newer build targeted .NET 6 or 8 while the old one targeted .NET Framework. Except both builds targeted .NET 2.0, compiled with the same Visual Studio 2005 toolchain. Theory eliminated.
Suspect 2: the operating system. Windows 11 22H2 introduced the new “unified” print dialog for classic Win32 applications, so perhaps one test machine had it and the other didn’t. Except both dialogs appeared on the same Windows 11 23H2 machine. Theory eliminated.
Suspect 3: the source code. Perhaps some subtle change in the newer version’s print path — call order, dialog flags, page setup handling — was triggering the new dialog. So we recompiled the old sources and the new sources with the identical compiler on the identical machine. Both binaries behaved… inconsistently. Theory eliminated, and confusion at its peak.
The actual cause: how the exe is launched
Here was the aha moment. The dialog didn’t depend on the version of the DLL, the framework, or the source code at all. It depended on how the executable was started:
Launched from an elevated (Administrator) command prompt: classic print dialog.
Launched from a shortcut, File Explorer, or a non-elevated command prompt: new unified dialog.
We had been unzipping old builds into a folder and running them by typing demo.exe in an always-open elevated developer prompt, while the newest build had been started by double-clicking a shortcut. The launch method — not the build — was the variable all along.
Why elevation matters
The new dialog is not really a dialog in your process. It is hosted out-of-process by a modern packaged (UWP-style) Windows component — which is also why the title bar shows the generic “Printing from Win32 application” text rather than your application’s name, and why the preview pane cannot be populated by a classic GDI PrintDocument.
Because it is a packaged app experience, its activation depends on the calling process’s security context. Packaged app activation generally fails from elevated processes, so when an elevated application calls PrintDlgEx, Windows silently falls back to the classic in-process dialog. A non-elevated process gets the new experience. Your code calls the same API either way; Windows makes the substitution behind your back.
Verifying this is easy: open Task Manager, go to the Details tab, add the “Elevated” column, and launch your application both ways. The dialog will correlate perfectly with that column.
Which applications are affected
This substitution happens at the Windows API level, so it affects any application that displays the standard Windows print dialog — regardless of language, framework, or bitness. We confirmed the identical behavior across our TE Edit Control product line wherever the Windows common dialog is used: the Win32 native SDK, the Win64 native SDK, the .NET Framework builds, and the .NET 9 build all show the classic dialog when elevated and the new unified dialog when not.
Conversely, applications that draw their own print dialog are immune. Our Java and JavaScript editions of TE Edit Control render their own dialog boxes rather than calling PrintDlgEx, and they show the same dialog every time, no matter how the application is launched. That contrast is itself a useful diagnostic: if your product spans multiple platforms and only the Windows-common-dialog versions vary, you’re looking at this OS behavior, not a bug in your code.
The fix: forcing the classic dialog
Windows still ships the classic dialog; it’s just no longer the default for non-elevated processes. A per-user registry value restores it:
reg add "HKCU\Software\Microsoft\Print\UnifiedPrintDialog" /v "PreferLegacyPrintDialog" /d 1 /t REG_DWORD /fThat works, but asking every end user to edit the registry is not a great customer experience, and the setting is machine-wide for that user. For a component or application that wants the classic dialog deterministically — regardless of launch method — the cleaner approach is to set the value just before showing the dialog and restore the previous state immediately after:
using Microsoft.Win32;
RegistryKey k = Registry.CurrentUser.CreateSubKey(
@"Software\Microsoft\Print\UnifiedPrintDialog");
object old = k.GetValue("PreferLegacyPrintDialog");
k.SetValue("PreferLegacyPrintDialog", 1, RegistryValueKind.DWord);
try {
result = PrtDlg.ShowDialog();
} finally {
if (old == null) k.DeleteValue("PreferLegacyPrintDialog", false);
else k.SetValue("PreferLegacyPrintDialog", old);
k.Close();
}This runs fine even on .NET Framework 2.0, uses only HKCU (no admin rights needed), and leaves the user’s own preference untouched. Test it on a real Windows 11 22H2+ machine before shipping — the substitution is made per dialog invocation, but as with anything appcompat-related, verifying on the target configuration is cheap insurance.
Takeaways
If your print dialog changed appearance and you didn’t change anything, you probably didn’t. Windows 11 22H2 changed it for you.
If the behavior seems random across machines or users, check elevation before you diff your code. The same binary shows different dialogs in elevated and non-elevated processes.
The empty preview pane and the “Printing from Win32 application” title are known characteristics of the new unified dialog with classic GDI printing, not bugs in your application.
The behavior is language- and framework-agnostic: native Win32/Win64, .NET Framework, and .NET 9 applications are all affected equally, because the substitution occurs inside the Windows common dialog API.
Applications that draw their own print dialog (such as Java or browser-based JavaScript components) are unaffected.
PreferLegacyPrintDialog gives you back the classic dialog, and the set-and-restore pattern gives your users that behavior without asking them to touch the registry.
We’ve applied this fix pattern for TE Edit Control users who prefer the classic dialog, and it has been reliable across launch methods. Hopefully this writeup spares you the detour through frameworks, OS builds, and source diffs that we took to get here.


Comments