--- lang: ja-jp breaks: true --- # WPF `PrintQueue.CreateXpsDocumentWriter` を使用して別スレッドから印刷しようとするとエラーが発生する。 2022-06-17 ## .NET Frameworkのソースを参照 Win32PrintDialog.cs ```csharp= [SecurityCritical, SecurityTreatAsSafe] internal UInt32 ShowDialog() { UInt32 result = NativeMethods.PD_RESULT_CANCEL; // // Get the process main window handle // IntPtr owner = IntPtr.Zero; if ((System.Windows.Application.Current != null) && (System.Windows.Application.Current.MainWindow != null)) { System.Windows.Interop.WindowInteropHelper helper = new System.Windows.Interop.WindowInteropHelper(System.Windows.Application.Current.MainWindow); owner = helper.CriticalHandle; } try { if (this._printQueue == null || this._printTicket == null) { // Normally printDlgEx.SyncToStruct() probes the printer if both the print queue and print // ticket are not null. // If either is null we probe the printer ourselves // If we dont end users will get notified that printing is disabled *after* // the print dialog has been displayed. ProbeForPrintingSupport(); } // // Create a PrintDlgEx instance to invoke the Win32 Print Dialog // using (PrintDlgExMarshaler printDlgEx = new PrintDlgExMarshaler(owner, this)) { printDlgEx.SyncToStruct(); // // Display the Win32 print dialog // Int32 hr = UnsafeNativeMethods.PrintDlgEx(printDlgEx.UnmanagedPrintDlgEx); if (hr == MS.Win32.NativeMethods.S_OK) { result = printDlgEx.SyncFromStruct(); } } } ``` :::info `System.Windows.Application.Current.MainWindow`が所有するスレッドから印刷ダイアログを表示している模様。 ::: ## `Application.Current.Dispatcher.Invoke` によりメインスレッドで処理を行っても、以下でエラーとなる。 :::info `Application.Current.Dispatcher.Invoke`により、印刷ダイアログの表示までは正常に動作する。 ::: ```csharp= paginator.PageSize = new Size( ia.MediaSizeWidth, ia.MediaSizeHeight ); ``` ```shell= System.InvalidOperationException HResult=0x80131509 Message=このオブジェクトは別のスレッドに所有されているため、呼び出しスレッドはこのオブジェクトにアクセスできません。 Source=WindowsBase スタック トレース: 場所 System.Windows.Threading.Dispatcher.VerifyAccess() 場所 MS.Internal.Documents.FlowDocumentPaginator.set_PageSize(Size value) ``` ## ぐぐる > wpf - Printing the content of a DocumentViewer in a different UI thread > https://jonic.cn/qa/?qa=1008550/wpf-printing-the-content-of-a-documentviewer-in-a-different-ui-thread > PrintDialog and a secondary UI thread severe problem > https://social.msdn.microsoft.com/Forums/en-US/3aad21a4-17fc-40de-badb-8f1c20b25dbe/printdialog-and-a-secondary-ui-thread-severe-problem?forum=wpf > Replacement class for System.Windows.PrintDialog > https://pastebin.com/f1a411397 ## 印刷対象のXamlをUIスレッド上で一旦文字列として取得し、あとはメインスレッド上でXaml(XPS)を再構築して印刷することで解決 Xmalを文字列として取得 ```csharp= // WPFのUIスレッドで実行 public string GetFlowDocumentXmlString(FlowDocument doc) { return XamlWriter.Save(doc); } ``` ```csharp= // WPFのUIスレッドで実行 string xmalString = GetFlowDocumentXmlString(doc); // `PrintQueue.CreateXpsDocumentWriter`がメインスレッド上でのみ実行可能な為、 // メインスレッド上で実行する。 Application.Current.Dispatcher.Invoke(() => { // メインスレッド上でXaml(XPS)を再構築。 FlowDocument doc; { XmlDocument document = new XmlDocument(); document.LoadXml(xmalString); doc =(FlowDocument)XamlReader.Load(new XmlNodeReader(document)); } PrintDocumentImageableArea ia = null; XpsDocumentWriter docWriter = null; docWriter = PrintQueue.CreateXpsDocumentWriter(ref ia); if ( docWriter != null && ia != null ) { DocumentPaginator paginator = ((IDocumentPaginatorSource)doc).DocumentPaginator; Size pageSize = default; pageSize = new Size( ia.MediaSizeWidth, ia.MediaSizeHeight ); paginator.PageSize = pageSize; doc.ColumnWidth = double.PositiveInfinity; docWriter.Write(paginator); } }); ``` ###### tags: `WPF` `PrintQueue.CreateXpsDocumentWriter`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up