2010-06-04 3 views
3

J'ai conçu une application multithread, qui commence la plupart des fenêtres dans un thread dédié comme this:PrintDialog dans la fenêtre WPF multithread jeté TargetInvocationException

Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint)); 
newWindowThread.SetApartmentState(ApartmentState.STA); 
newWindowThread.IsBackground = true; 
newWindowThread.Start(); 

Cependant, si dans un de ces fenêtres en propre fils J'essaie d'imprimer quelque chose en appelant simplement

PrintDialog pDialog = new PrintDialog(); 
bool? doPrint = pDialog.ShowDialog(); 

je reçois un TargetInvocationException - il n'a pas l'air comme le PrintDialog ne réside pas dans le même fil que ma fenêtre.

Est-il possible de créer un PrinterDialog indépendant du thread (ou du "thread-save")?

Répondre

3

La réponse est here:

PrintDialog utilise une classe privée Win32PrintDialog qui semble accéder Application.Current.MainWindow à afin d'obtenir la fenêtre HWND mère poignée à utiliser comme une boîte de dialogue d'impression natif parent fenêtre

Quelqu'un a construit un fil-activé PrintDialog here. Cela semble être le seul moyen de faire fonctionner l'impression dans une application Thread-Enabled.

(je avais aimé répéter le code ici, mais il dépasse la longueur maximale des réponses)

Remarque:

  • System.Drawing
  • System.Printing
  • système. Windows.Forms

sont des références nécessaires.

0
using System.Drawing; 
using System.Printing; 
using System.Windows.Forms; 
using System.Windows.Controls; 
using System.Drawing.Printing; 
using System.Security; 
using System.Windows.Interop; 
using System.Runtime.InteropServices; 
using System.Windows.Documents.Serialization; 
using System.Windows.Xps; 
using System.Printing.Interop; 
using System.Windows.Documents; 
using System.Windows.Xps.Packaging; 
using System.Windows.Xps.Serialization; 

Assemblées: System.Printing, ReachFramework

0

Vous pouvez utiliser l'extension de la méthode ShowDialogEx de:

public static class PrintDialogExtensions 
{ 
    private static readonly PropertyInfo CriticalHandleProperty; 

    private static readonly FieldInfo DialogInvokedField; 
    private static readonly FieldInfo PrintTicketField; 
    private static readonly FieldInfo PrintQueueField; 
    private static readonly FieldInfo MinPageField; 
    private static readonly FieldInfo MaxPageField; 
    private static readonly FieldInfo UserPageRangeEnabledField; 
    private static readonly FieldInfo SelectedPagesEnabledField; 
    private static readonly FieldInfo CurrentPageEnabledField; 
    private static readonly FieldInfo PageRangeField; 
    private static readonly FieldInfo PageRangeSelectionField; 

    private static readonly PropertyInfo Win32PrintDialogPrintTicketProperty; 
    private static readonly PropertyInfo Win32PrintDialogPrintQueueProperty; 
    private static readonly PropertyInfo Win32PrintDialogMinPageProperty; 
    private static readonly PropertyInfo Win32PrintDialogMaxPageProperty; 
    private static readonly PropertyInfo Win32PrintDialogPageRangeEnabledProperty; 
    private static readonly PropertyInfo Win32PrintDialogSelectedPagesEnabledProperty; 
    private static readonly PropertyInfo Win32PrintDialogSelectedCurrentPageEnabledProperty; 
    private static readonly PropertyInfo Win32PrintDialogPageRangeProperty; 
    private static readonly PropertyInfo Win32PrintDialogPageRangeSelectionProperty; 
    private static readonly MethodInfo Win32PrintDialogProbeForPrintingSupportMethod; 

    private static readonly Type Win32PrintDialogType; 
    private static readonly Type PrintDlgExMarshalerType; 

    private static readonly MethodInfo PrintDlgExMarshalerSyncToStructMethod; 
    private static readonly MethodInfo PrintDlgExMarshalerSyncFromStructMethod; 
    private static readonly PropertyInfo PrintDlgExMarshalerTypeUnmanagedPrintDlgExProperty; 

    private static readonly MethodInfo UnsafeNativeMethodsTypePrintDlgExMethod; 

    private static readonly MethodInfo SrTypeGetMethod; 

    static PrintDialogExtensions() 
    { 
     var windowInteropType = typeof(WindowInteropHelper); 
     CriticalHandleProperty = windowInteropType.GetProperty("CriticalHandle", BindingFlags.Instance | BindingFlags.NonPublic); 

     var type = typeof(PrintDialog); 
     DialogInvokedField = type.GetField("_dialogInvoked", BindingFlags.Instance | BindingFlags.NonPublic); 
     PrintTicketField = type.GetField("_printTicket", BindingFlags.Instance | BindingFlags.NonPublic); 
     PrintQueueField = type.GetField("_printQueue", BindingFlags.Instance | BindingFlags.NonPublic); 
     MinPageField = type.GetField("_minPage", BindingFlags.Instance | BindingFlags.NonPublic); 
     MaxPageField = type.GetField("_maxPage", BindingFlags.Instance | BindingFlags.NonPublic); 
     UserPageRangeEnabledField = type.GetField("_userPageRangeEnabled", BindingFlags.Instance | BindingFlags.NonPublic); 
     SelectedPagesEnabledField = type.GetField("_selectedPagesEnabled", BindingFlags.Instance | BindingFlags.NonPublic); 
     CurrentPageEnabledField = type.GetField("_currentPageEnabled", BindingFlags.Instance | BindingFlags.NonPublic); 
     PageRangeField = type.GetField("_pageRange", BindingFlags.Instance | BindingFlags.NonPublic); 
     PageRangeSelectionField = type.GetField("_pageRangeSelection", BindingFlags.Instance | BindingFlags.NonPublic); 

     var presentationAssembly = Assembly.Load(new AssemblyName("PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")); 

     var unsafeNativeMethodsType = presentationAssembly.GetType("MS.Internal.Printing.UnsafeNativeMethods"); 
     var srType = presentationAssembly.GetType("System.Windows.SR"); 
     Win32PrintDialogType = presentationAssembly.GetType("MS.Internal.Printing.Win32PrintDialog"); 
     PrintDlgExMarshalerType = Win32PrintDialogType.GetNestedType("PrintDlgExMarshaler", BindingFlags.NonPublic); 

     Win32PrintDialogPrintTicketProperty = Win32PrintDialogType.GetProperty("PrintTicket", BindingFlags.Instance | BindingFlags.NonPublic); 
     Win32PrintDialogPrintQueueProperty = Win32PrintDialogType.GetProperty("PrintQueue", BindingFlags.Instance | BindingFlags.NonPublic); 
     Win32PrintDialogMinPageProperty = Win32PrintDialogType.GetProperty("MinPage", BindingFlags.Instance | BindingFlags.NonPublic); 
     Win32PrintDialogMaxPageProperty = Win32PrintDialogType.GetProperty("MaxPage", BindingFlags.Instance | BindingFlags.NonPublic); 
     Win32PrintDialogPageRangeEnabledProperty = Win32PrintDialogType.GetProperty("PageRangeEnabled", BindingFlags.Instance | BindingFlags.NonPublic); 
     Win32PrintDialogSelectedPagesEnabledProperty = Win32PrintDialogType.GetProperty("SelectedPagesEnabled", BindingFlags.Instance | BindingFlags.NonPublic); 
     Win32PrintDialogSelectedCurrentPageEnabledProperty = Win32PrintDialogType.GetProperty("CurrentPageEnabled", BindingFlags.Instance | BindingFlags.NonPublic); 
     Win32PrintDialogPageRangeProperty = Win32PrintDialogType.GetProperty("PageRange", BindingFlags.Instance | BindingFlags.NonPublic); 
     Win32PrintDialogPageRangeSelectionProperty = Win32PrintDialogType.GetProperty("PageRangeSelection", BindingFlags.Instance | BindingFlags.NonPublic); 
     Win32PrintDialogProbeForPrintingSupportMethod = Win32PrintDialogType.GetMethod("ProbeForPrintingSupport", BindingFlags.Instance | BindingFlags.NonPublic); 

     PrintDlgExMarshalerSyncToStructMethod = PrintDlgExMarshalerType.GetMethod("SyncToStruct", BindingFlags.Instance | BindingFlags.NonPublic); 
     PrintDlgExMarshalerSyncFromStructMethod = PrintDlgExMarshalerType.GetMethod("SyncFromStruct", BindingFlags.Instance | BindingFlags.NonPublic); 
     PrintDlgExMarshalerTypeUnmanagedPrintDlgExProperty = PrintDlgExMarshalerType.GetProperty("UnmanagedPrintDlgEx", BindingFlags.Instance | BindingFlags.NonPublic); 

     UnsafeNativeMethodsTypePrintDlgExMethod = unsafeNativeMethodsType.GetMethod("PrintDlgEx", BindingFlags.Static | BindingFlags.NonPublic); 

     SrTypeGetMethod = srType.GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Single(m => String.Equals(m.Name, "Get", StringComparison.OrdinalIgnoreCase) && m.GetParameters().Length == 1); 
    } 

    [SecurityCritical] 
    [SuppressUnmanagedCodeSecurity] 
    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    private static extern IntPtr GetActiveWindow(); 

    [SuppressUnmanagedCodeSecurity] 
    [SecurityCritical] 
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false)] 
    private static extern Int32 MessageBox(HandleRef hWnd, String text, String caption, Int32 type); 

    public static Boolean? ShowDialogEx(this PrintDialog dialog) 
    { 
     var ticket = PrintTicketField.GetValue(dialog); 
     var queue = PrintQueueField.GetValue(dialog); 
     var minPage = (UInt32)MinPageField.GetValue(dialog); 
     var maxPage = (UInt32)MaxPageField.GetValue(dialog); 
     var userPageRangeEnabled = (Boolean)UserPageRangeEnabledField.GetValue(dialog); 
     var selectedPagesEnabled = (Boolean)SelectedPagesEnabledField.GetValue(dialog); 
     var currentPageEnabled = (Boolean)CurrentPageEnabledField.GetValue(dialog); 
     var pageRange = (PageRange)PageRangeField.GetValue(dialog); 
     var pageRangeSelection = (PageRangeSelection)PageRangeSelectionField.GetValue(dialog); 

     DialogInvokedField.SetValue(dialog, false); 
     var win32PrintDialog = Activator.CreateInstance(Win32PrintDialogType); 
     var win32MinPage = (UInt32)Win32PrintDialogMinPageProperty.GetValue(win32PrintDialog, null); 

     Win32PrintDialogPrintTicketProperty.SetValue(win32PrintDialog, ticket, null); 
     Win32PrintDialogPrintQueueProperty.SetValue(win32PrintDialog, queue, null); 
     Win32PrintDialogMinPageProperty.SetValue(win32PrintDialog, Math.Max(1U, Math.Min(minPage, maxPage)), null); 
     Win32PrintDialogMaxPageProperty.SetValue(win32PrintDialog, Math.Max(win32MinPage, Math.Max(minPage, maxPage)), null); 
     Win32PrintDialogPageRangeEnabledProperty.SetValue(win32PrintDialog, userPageRangeEnabled, null); 
     Win32PrintDialogSelectedPagesEnabledProperty.SetValue(win32PrintDialog, selectedPagesEnabled, null); 
     Win32PrintDialogSelectedCurrentPageEnabledProperty.SetValue(win32PrintDialog, currentPageEnabled, null); 
     var win32PrintDialogMinPage = (UInt32)Win32PrintDialogMinPageProperty.GetValue(win32PrintDialog, null); 
     var win32PrintDialogMaxPage = (UInt32)Win32PrintDialogMaxPageProperty.GetValue(win32PrintDialog, null); 
     Win32PrintDialogPageRangeProperty.SetValue(win32PrintDialog, new PageRange(Math.Max((Int32)win32PrintDialogMinPage, pageRange.PageFrom), Math.Min((Int32)win32PrintDialogMaxPage, pageRange.PageTo)), null); 
     Win32PrintDialogPageRangeSelectionProperty.SetValue(win32PrintDialog, pageRangeSelection, null); 

     var num = ShowWin32Dialog(win32PrintDialog); 
     switch (num) 
     { 
      case 2U: 
      case 1U: 
       PrintTicketField.SetValue(dialog, Win32PrintDialogPrintTicketProperty.GetValue(win32PrintDialog, null)); 
       PrintQueueField.SetValue(dialog, Win32PrintDialogPrintQueueProperty.GetValue(win32PrintDialog, null)); 
       PageRangeField.SetValue(dialog, Win32PrintDialogPageRangeProperty.GetValue(win32PrintDialog, null)); 
       PageRangeSelectionField.SetValue(dialog, Win32PrintDialogPageRangeSelectionProperty.GetValue(win32PrintDialog, null)); 
       DialogInvokedField.SetValue(dialog, true); 
       break; 
     } 
     return (Int32)num == 1; 
    } 

    private static UInt32 ShowWin32Dialog(Object win32Dialog) 
    { 
     var num1 = 0U; 
     var num2 = IntPtr.Zero; 

     if (Application.Current != null) 
     { 
      Application.Current.Dispatcher.Invoke(new Action(() => 
      { 
       if (Application.Current.MainWindow != null) 
       { 
        var windowInteropHelper = new WindowInteropHelper(Application.Current.MainWindow); 
        num2 = (IntPtr)CriticalHandleProperty.GetValue(windowInteropHelper, null); 
       } 
      })); 
     } 

     try 
     { 
      var queue = (PrintQueue)Win32PrintDialogPrintQueueProperty.GetValue(win32Dialog, null); 
      var ticket = (PrintTicket)Win32PrintDialogPrintTicketProperty.GetValue(win32Dialog, null); 

      if (queue == null || ticket == null) 
       Win32PrintDialogProbeForPrintingSupportMethod.Invoke(win32Dialog, null); 

      using (var printDlgExMarshaler = (IDisposable)Activator.CreateInstance(PrintDlgExMarshalerType, BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { num2, win32Dialog }, null)) 
      { 
       PrintDlgExMarshalerSyncToStructMethod.Invoke(printDlgExMarshaler, null); 
       var unmanagedPrintDlgEx = PrintDlgExMarshalerTypeUnmanagedPrintDlgExProperty.GetValue(printDlgExMarshaler, null); 
       if ((Int32)UnsafeNativeMethodsTypePrintDlgExMethod.Invoke(null, new[] { unmanagedPrintDlgEx }) == 0) 
        num1 = (UInt32)PrintDlgExMarshalerSyncFromStructMethod.Invoke(printDlgExMarshaler, null); 
      } 

     } 
     catch (Exception ex) 
     { 
      if (String.Equals(ex.GetType().FullName, "System.Printing.PrintingNotSupportedException", StringComparison.Ordinal)) 
      { 
       string text = (String)SrTypeGetMethod.Invoke(null, new Object[] { "PrintDialogInstallPrintSupportMessageBox" }); 
       string caption = (String)SrTypeGetMethod.Invoke(null, new Object[] { "PrintDialogInstallPrintSupportCaption" }); 
       int type = 64 | ((caption == null || caption.Length <= 0 ? 0 : ((int)caption[0] == 8207 ? 1 : 0)) != 0 ? 1048576 : 0); 
       if (num2 == IntPtr.Zero) 
        num2 = GetActiveWindow(); 
       if (MessageBox(new HandleRef(null, num2), text, caption, type) != 0) 
        num1 = 0U; 
      } 
      else 
       throw; 
     } 

     return num1; 
    } 
}