dotnet / wpf

WPF is a .NET Core UI framework for building Windows desktop applications.
MIT License
7.1k stars 1.17k forks source link

.NET core WPF print dialog freeze/not supported exception #2609

Open Zubastic opened 4 years ago

Zubastic commented 4 years ago

изображение

System.NotSupportedException: Specified method is not supported.
   at MS.Internal.PrintWin32Thunk.XpsPrintJobStream.Seek(Int64 offset, SeekOrigin origin)
   at System.Printing.PrintQueueStream.Seek(Int64 offset, SeekOrigin origin)
   at System.IO.Compression.ZipArchive.WriteFile()
   at System.IO.Compression.ZipArchive.Dispose(Boolean disposing)
   at System.IO.Compression.ZipArchive.Dispose()
   at System.IO.Packaging.ZipPackage.Dispose(Boolean disposing)
   at System.IO.Packaging.Package.System.IDisposable.Dispose()
   at System.IO.Packaging.Package.Close()
   at System.Windows.Xps.Packaging.XpsDocument.DisposeXpsDocument()
   at System.Printing.PrintQueue.DisposeSerializationManager(Boolean abort)
   at System.Windows.Xps.XpsDocumentWriter.EndWrite(Boolean disposeManager, Boolean abort)
   at System.Windows.Xps.XpsDocumentWriter.SaveAsXaml(Object serializedObject, Boolean isSync)
   at System.Windows.Xps.XpsDocumentWriter.Write(DocumentPaginator documentPaginator, PrintTicket printTicket)
   at System.Windows.Controls.PrintDialog.PrintDocument(DocumentPaginator documentPaginator, String description)
   at WpfNetcoreTest.Program..ctor() in C:\Users\Zubastic\Source\Repos\Zubastic\PrintDialogBug\WpfNetcoreTest\Program.cs:line 18
   at WpfNetcoreTest.App..ctor() in C:\Users\Zubastic\Source\Repos\Zubastic\PrintDialogBug\WpfNetcoreTest\App.xaml.cs:line 18
   at WpfNetcoreTest.App.Main()

Expected behavior: I could print PDF document at printer/save pdf file.

Minimal repro: Repo for reproduce bug: https://github.com/Zubastic/PrintDialogBug

@rladuca could u help me with that issue? 1607 is important for me, because enterprise use LTSB version. At 1809 and newer version all is good.

dmarcello53 commented 4 years ago

Oh well !

hnhai commented 4 years ago

Any dotnet core version fixed this bug ? @dmarcello53 . Please

Zubastic commented 4 years ago

@hnhai windows 1903 and newer is fixed.

Zubastic commented 4 years ago

bump, @danmosemsft could you help with this issue?

danmoseley commented 4 years ago

@Zubastic unfortunately i don't have knowledge of WPF code. Does this mean printing is just broken or only in this particular repo?

@ryalanms is the primary developer in this repo - perhaps he can help.

Zubastic commented 4 years ago

@danmosemsft it depends on windows version. At 1607 its broken (LTSB for enterprise users), at 1809 or newer - it is OK. But enterprise couldn't update :( Thank you for assistance.

danmoseley commented 4 years ago

cc @fabiant3 also

Zubastic commented 4 years ago

Well, additional info about bug:

class System.Printing.PrintQueue 1809: 1809

1607: 1607

if (this.IsXpsOMPrintingSupported()) returning true for 1809 and false for 1607. After that flag this.isWriterAttached is set. And at dispose method exception was thrown at ZipPackage.Dispose() (all stack at first post). Check ?isXpsOMPrintingSupported@?1??IsXpsOMPrintingSupported@PrintQueue@Printing@System@@QE$AAM_NXZ@$$Q4_NA; returning different values.

rladuca commented 4 years ago

IsXpsOMPrintingSupported is pegged to Windows 10 1703 (RS2) and above. This has always been this way since its inception (in .NET Framework, I believe in the 4.7/4.7.1 timeframe).

The problem is likely to be that the serialization manager for the legacy path, NgcSerializationManager, is likely not managing streams in a way conducive to the new underlying packaging libraries. This is, generally, the root cause of almost all printing (and XPS for that matter) issues in .NET Core. The management of streams for packages needs to be overhauled to match System.IO.Packaging and System.IO.Compression. The old assumptions WPF is built on when it contained its own packaging and zip libraries no longer apply.

This isn't a workaround, but a potential test. If you force the value there to be true (perhaps forcing the static underlying the function call here) do things work? Note there may be other instances where another piece of code needs to pivot on this sort of check for printing support, but I don't have a full understanding of all of those places (@miguep maybe?).

@ryalanms One thing you might want to check is if you can just remove the OS check or extend support for it downward. The minimum client is low, but this was guarded so as to not explicitly change behavior on applications targeting lower versions. For .NET Core it might make sense to remove this and move forward. It would need good testing, but might help alleviate the pain of fixing up the legacy serialization classes. Of course, that could just be the outside layer of issues, I haven't tried.

Zubastic commented 4 years ago

This isn't a workaround, but a potential test. If you force the value there to be true (perhaps forcing the static underlying the function call here) do things work?

I change check if (this.IsXpsOMPrintingSupported()) to true and get this exception: Exception

Zubastic commented 4 years ago

Well, if change flag to false and return NgcSerializationManager, it work. flag

ericstj commented 4 years ago

cc @stevenbrix @rladuca

This appears related to https://github.com/dotnet/wpf/commit/a57ed018277fa024e7c900f8343b969c861e64bf

In this case, based on the callstack, it seems that PrintQueueStream is exposing CanSeek (and CanRead) as true https://github.com/dotnet/wpf/blob/5841f8b2984301b6fe8a8153c30e8c13cad2eb16/src/Microsoft.DotNet.Wpf/src/System.Printing/CPP/src/PremiumPrintStream.cpp#L442-L467

But then is directly calling down to the SpoolStream: https://github.com/dotnet/wpf/blob/5841f8b2984301b6fe8a8153c30e8c13cad2eb16/src/Microsoft.DotNet.Wpf/src/System.Printing/CPP/src/PremiumPrintStream.cpp#L338

And the SpoolStream is created with CanRead as false https://github.com/dotnet/wpf/blob/5841f8b2984301b6fe8a8153c30e8c13cad2eb16/src/Microsoft.DotNet.Wpf/src/System.Printing/CPP/src/XpsDeviceSimulatingInteropPrinterHandler.cpp#L180 and hardcodes CanSeek to false: https://github.com/dotnet/wpf/blob/bfe7907b65c0861700edbf73ab05e31b7e23e13f/src/Microsoft.DotNet.Wpf/src/System.Printing/CPP/src/XpsPrintJobStream.cpp#L83-L90

Perhaps the fix here is to simply update PrintStream to delegate the Can* properties to the SpoolStream like it is doing for the actual Read|Write|Seek methods. That will let the calling code "know" that the backing stream cannot read or seek and write the Package/ZipArchive in a way that doesn't do any seeking.

ryalanms commented 3 years ago

This was fixed in .NET 5.0 in our internal repo (in PresentationNative), but was not backported to 3.1.

/cc @dotnet/wpf-developers