我设计了一个多线程应用程序,它在this这样的专用线程中启动大多数窗口:
Thread newWindowThread = new Thread(new ThreadStart(ThreadStartingPoint));
newWindowThread.SetApartmentState(ApartmentState.STA);
newWindowThread.IsBackground = true;
newWindowThread.Start();
但是,如果在其中一个窗口自己的线程中,我尝试通过简单地调用
来打印一些东西PrintDialog pDialog = new PrintDialog();
bool? doPrint = pDialog.ShowDialog();
我得到一个TargetInvocationException - 它看起来像PrintDialog与我的窗口不在同一个线程中。
有没有办法创建与线程无关(或“线程保存”)的PrinterDialog?
答案 0 :(得分:3)
答案是here:
PrintDialog使用私有类 Win32PrintDialog似乎访问 Application.Current.MainWindow in 以获取父HWND窗口 句柄用作本机打印对话框 窗口父母
有人构建了支持Thread的PrintDialog here。这似乎是使打印在启用Thread的应用程序中工作的唯一方法。
(我喜欢在这里重复代码,但它超过了答案的最大长度)
注:
是必需的参考资料。
答案 1 :(得分: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;
程序集: System.Printing , ReachFramework
答案 2 :(得分:0)
您可以使用方法扩展名ShowDialogEx:
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;
}
}