Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / MS / Internal / Printing / printdlgexmarshaler.cs / 1 / printdlgexmarshaler.cs
// Microsoft Avalon // Copyright (c) Microsoft Corporation, 2006 // // File: Win32PrintDialog.cs // // 02/17/2006 : robertan - created // //------------------------------------------------------------------------------ using System; using System.Drawing.Printing; using System.Printing.Interop; using System.Printing; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Windows.Controls; namespace MS.Internal.Printing { internal partial class Win32PrintDialog { ////// This class abstracts the Marshaling of the PrintDlgEx structure to/from /// Native memory for displaying the Win32 print dialog via the PrintDlgEx /// API. The reason for this abstraction is to handle a known issue with /// this API. The 32-bit and 64-bit versions of this method have different /// packing schemes for the input structure that need to be handled separately /// to function correctly depending on the CPU archetecture. /// private sealed class PrintDlgExMarshaler : IDisposable { #region Constructor ////// Construct and initialize a PrintDlgExMarshaler instance. /// /// /// A Win32 window handle to use as the parent of this dialog. /// /// /// A reference to the Win32PrintDialog that contains the necessary /// data to display a Win32 Print Dialog via the PrintDlgEx call. /// ////// Critical: - Sets critical data to default values /// - We want creation of this class to be tracked. /// [SecurityCritical] internal PrintDlgExMarshaler( IntPtr owner, Win32PrintDialog dialog ) { _ownerHandle = owner; _dialog = dialog; _unmanagedPrintDlgEx = IntPtr.Zero; } #endregion Constructor #region Finalizer ~PrintDlgExMarshaler() { this.Dispose(true); } #endregion Finalizer #region Internal properties ////// Gets an IntPtr that points to unmanaged memory that represents /// a PRINTDLGEX structure for calling into PrintDlgEx Win32 API. /// ////// Critical: - This exposes critical unmanaged memory buffer /// and should be treated as dangerous since it /// is being passed to managed code. /// internal IntPtr UnmanagedPrintDlgEx { [SecurityCritical] get { return _unmanagedPrintDlgEx; } } #endregion Internal properties #region Internal methods ////// This method synchronizes the internal PRINTDLGEX unmanaged data /// structure with the internal Win32 print dialog configuration /// parameters. You call this prior to a call to PrintDlgEx Win32 /// API to configure the unmanaged memory. /// ////// Critical: - Calls other critical code (ExtractPrintDataAndDevMode, /// AcquireResultFromPrintDlgExStruct, AcquirePrintQueue, /// and AcquirePrintTicket). /// - Sets critical data on the Win32PrintDialog class /// (PrintTicket and PrintQueue) /// [SecurityCritical] internal UInt32 SyncFromStruct() { if (_unmanagedPrintDlgEx == IntPtr.Zero) { return NativeMethods.PD_RESULT_CANCEL; } UInt32 dialogResult = AcquireResultFromPrintDlgExStruct(_unmanagedPrintDlgEx); if ((dialogResult == NativeMethods.PD_RESULT_PRINT) || (dialogResult == NativeMethods.PD_RESULT_APPLY)) { IntPtr devModeHandle; string printerName; UInt32 flags; PageRange pageRange; ExtractPrintDataAndDevMode( _unmanagedPrintDlgEx, out printerName, out flags, out pageRange, out devModeHandle); _dialog.PrintQueue = AcquirePrintQueue(printerName); _dialog.PrintTicket = AcquirePrintTicket(devModeHandle, printerName); if ((flags & NativeMethods.PD_PAGENUMS) == NativeMethods.PD_PAGENUMS) { if (pageRange.PageFrom > pageRange.PageTo) { int temp = pageRange.PageTo; pageRange.PageTo = pageRange.PageFrom; pageRange.PageFrom = temp; } _dialog.PageRangeSelection = PageRangeSelection.UserPages; _dialog.PageRange = pageRange; } else { _dialog.PageRangeSelection = PageRangeSelection.AllPages; } } return dialogResult; } ////// This method synchronizes the managed Win32 data with the PRINTDLGEX /// unmanaged data structure. It is used after a successful call to the /// PrintDlgEx Win32 API. /// ////// Critical: - Calls into critical code (FreeUnmanagedPrintDlgExStruct, /// GetDesktopWindow, and AllocateUnmanagedPrintDlgExStruct). /// [SecurityCritical] internal void SyncToStruct() { if (_unmanagedPrintDlgEx != IntPtr.Zero) { FreeUnmanagedPrintDlgExStruct(_unmanagedPrintDlgEx); } // // If parent is not valid then get the desktop window handle. // if (_ownerHandle == IntPtr.Zero) { _ownerHandle = MS.Win32.UnsafeNativeMethods.GetDesktopWindow(); } // // Allocate an unmanaged PRINTDLGEX structure with our current internal settings. // _unmanagedPrintDlgEx = AllocateUnmanagedPrintDlgExStruct(); } #endregion Internal methods #region Private helper methods ////// Clean up any resources being used. /// /// /// true if managed resources should be disposed; otherwise, false. /// ////// Critical - Accesses unmanaged critical pointer /// TreatAsSafe - Its only freeing the memory and nothing leaves this method. /// [SecurityCritical, SecurityTreatAsSafe] private void Dispose( bool disposing ) { if (disposing) { if (_unmanagedPrintDlgEx != IntPtr.Zero) { FreeUnmanagedPrintDlgExStruct(_unmanagedPrintDlgEx); _unmanagedPrintDlgEx = IntPtr.Zero; } } } ////// Extracts the printer name, flags, pageRange, and devmode handle from the /// given PRINTDLGEX structure. /// /// /// An unmanaged buffer representing the PRINTDLGEX structure. This structure /// is passed around as an unmanaged buffer since the 32-bit and 64-bit versions /// of this buffer are not the same and need to be handled uniquely. /// /// /// An out parameter to store store the printer name. /// /// /// The set of flags that are inside the PRINTDIALOGEX structure. /// /// /// The user specified page range that is in PRINTDLGEX structure. /// This is only useful if the PD_PAGENUMS bit is set in the flags. /// /// /// An out parameter to store the devmode handle. /// ////// Critical: - manipulating unmanaged buffers with critical data in them. /// [SecurityCritical] private void ExtractPrintDataAndDevMode( IntPtr unmanagedBuffer, out string printerName, out UInt32 flags, out PageRange pageRange, out IntPtr devModeHandle ) { IntPtr devNamesHandle = IntPtr.Zero; IntPtr pageRangePtr = IntPtr.Zero; // // Extract the devmode and devnames handles from the appropriate PRINTDLGEX structure // if (!Is64Bit()) { NativeMethods.PRINTDLGEX32 pdex = (NativeMethods.PRINTDLGEX32)Marshal.PtrToStructure( unmanagedBuffer, typeof(NativeMethods.PRINTDLGEX32)); devModeHandle = pdex.hDevMode; devNamesHandle = pdex.hDevNames; flags = pdex.Flags; pageRangePtr = pdex.lpPageRanges; } else { NativeMethods.PRINTDLGEX64 pdex = (NativeMethods.PRINTDLGEX64)Marshal.PtrToStructure( unmanagedBuffer, typeof(NativeMethods.PRINTDLGEX64)); devModeHandle = pdex.hDevMode; devNamesHandle = pdex.hDevNames; flags = pdex.Flags; pageRangePtr = pdex.lpPageRanges; } // // Get a managed copy of the page ranges. This only matters if the PD_PAGENUMS bit is // set in the flags. // if (((flags & NativeMethods.PD_PAGENUMS) == NativeMethods.PD_PAGENUMS) && (pageRangePtr != IntPtr.Zero)) { NativeMethods.PRINTPAGERANGE pageRangeStruct = (NativeMethods.PRINTPAGERANGE)Marshal.PtrToStructure( pageRangePtr, typeof(NativeMethods.PRINTPAGERANGE)); pageRange = new PageRange((int)pageRangeStruct.nFromPage, (int)pageRangeStruct.nToPage); } else { pageRange = new PageRange(1); } // // Get a managed copy of the device name // if (devNamesHandle != IntPtr.Zero) { IntPtr pDevNames = IntPtr.Zero; try { pDevNames = UnsafeNativeMethods.GlobalLock(devNamesHandle); NativeMethods.DEVNAMES devNames = (NativeMethods.DEVNAMES)Marshal.PtrToStructure( pDevNames, typeof(NativeMethods.DEVNAMES)); printerName = Marshal.PtrToStringAuto( (IntPtr)((int)pDevNames + (devNames.wDeviceOffset * Marshal.SystemDefaultCharSize))); } finally { if (pDevNames != IntPtr.Zero) { UnsafeNativeMethods.GlobalUnlock(devNamesHandle); } } } else { printerName = string.Empty; } } ////// Acquires an instance of the PrintQueue that cooresponds to the given printer name. /// /// /// The printer name to search for. /// ////// Critical: - Performs an elevation to access the printing subsystem to lookup /// the PrintQueue based on the printername. /// [SecurityCritical] private PrintQueue AcquirePrintQueue( string printerName ) { PrintQueue printQueue = null; EnumeratedPrintQueueTypes[] types = new EnumeratedPrintQueueTypes[] { EnumeratedPrintQueueTypes.Local, EnumeratedPrintQueueTypes.Connections }; // // This forces us to acquire the cached version of the print queues. // This theoretically should prevent crashing in the printing system // since all it is doing is reading the registry. // PrintQueueIndexedProperty[] props = new PrintQueueIndexedProperty[] { PrintQueueIndexedProperty.Name, PrintQueueIndexedProperty.QueueAttributes }; (new PrintingPermission(PrintingPermissionLevel.DefaultPrinting)).Assert(); //BlessedAssert try { // // Get the PrintQueue instance for the printer // using (LocalPrintServer server = new LocalPrintServer()) { foreach (PrintQueue queue in server.GetPrintQueues(props, types)) { if (printerName.Equals(queue.FullName, StringComparison.OrdinalIgnoreCase)) { printQueue = queue; break; } } } if (printQueue != null) { printQueue.InPartialTrust = true; } } finally { PrintingPermission.RevertAssert(); } return printQueue; } ////// Acquires an instance of a PrintTicket given a handle to a DEVMODE and a printer name. /// /// /// The DEVMODE handle to use for the PrintTicket. /// /// /// The printer name for the PrintTicket converter. /// ////// Critical: - Performs an elevation to access the printing subsystem to lookup /// the PrintQueue based on the printer in the PRINTDLG structure. /// - Calls unmanaged code that has been suppressed. /// [SecurityCritical] private PrintTicket AcquirePrintTicket( IntPtr devModeHandle, string printQueueName ) { PrintTicket printTicket = null; byte[] devModeData = null; // // Copy the devmode into a byte array // IntPtr pDevMode = IntPtr.Zero; try { pDevMode = UnsafeNativeMethods.GlobalLock(devModeHandle); NativeMethods.DEVMODE devMode = (NativeMethods.DEVMODE)Marshal.PtrToStructure( pDevMode, typeof(NativeMethods.DEVMODE)); devModeData = new byte[devMode.dmSize + devMode.dmDriverExtra]; Marshal.Copy(pDevMode, devModeData, 0, devModeData.Length); } finally { if (pDevMode != IntPtr.Zero) { UnsafeNativeMethods.GlobalUnlock(devModeHandle); } } (new PrintingPermission(PrintingPermissionLevel.DefaultPrinting)).Assert(); //BlessedAssert try { // // Convert the devmode data to a PrintTicket object // using (PrintTicketConverter ptConverter = new PrintTicketConverter( printQueueName, PrintTicketConverter.MaxPrintSchemaVersion)) { printTicket = ptConverter.ConvertDevModeToPrintTicket(devModeData); } } finally { PrintingPermission.RevertAssert(); } return printTicket; } ////// Extracts the result value from a given PRINTDLGEX structure. /// /// /// An unmanaged buffer representing the PRINTDLGEX structure. This structure /// is passed around as an unmanaged buffer since the 32-bit and 64-bit versions /// of this buffer are not the same and need to be handled uniquely. /// ////// Critical: - manipulating unmanaged buffers with critical data in them. /// [SecurityCritical] private UInt32 AcquireResultFromPrintDlgExStruct( IntPtr unmanagedBuffer ) { UInt32 result = 0; // // Extract the devmode and devnames handles from the appropriate PRINTDLGEX structure // if (!Is64Bit()) { NativeMethods.PRINTDLGEX32 pdex = (NativeMethods.PRINTDLGEX32)Marshal.PtrToStructure( unmanagedBuffer, typeof(NativeMethods.PRINTDLGEX32)); result = pdex.dwResultAction; } else { NativeMethods.PRINTDLGEX64 pdex = (NativeMethods.PRINTDLGEX64)Marshal.PtrToStructure( unmanagedBuffer, typeof(NativeMethods.PRINTDLGEX64)); result = pdex.dwResultAction; } return result; } ////// Allocates an unmanaged buffer for the PRINTDLGEX structure and /// sets the initial values on it. /// /// NOTE: The reason for returning an unmanaged pointer to a buffer /// and not just a structure that can be passed to the unmanaged APIs /// is because this class is providing an abstraction to a problem that /// exists in the unmanaged print world where the 32-bit and 64-bit /// structure packing is inconsistent. /// ////// Critical: - Allocates and returns unmanaged memory that will /// eventually contain possibly sensitive data. /// [SecurityCritical] private IntPtr AllocateUnmanagedPrintDlgExStruct() { IntPtr unmanagedBuffer = IntPtr.Zero; NativeMethods.PRINTPAGERANGE range; range.nToPage = (uint)_dialog.PageRange.PageTo; range.nFromPage = (uint)_dialog.PageRange.PageFrom; try { if (!Is64Bit()) { NativeMethods.PRINTDLGEX32 pdex = new NativeMethods.PRINTDLGEX32(); pdex.hwndOwner = _ownerHandle; pdex.nMinPage = _dialog.MinPage; pdex.nMaxPage = _dialog.MaxPage; pdex.Flags = NativeMethods.PD_ALLPAGES | NativeMethods.PD_NOCURRENTPAGE | NativeMethods.PD_NOSELECTION | NativeMethods.PD_USEDEVMODECOPIESANDCOLLATE | NativeMethods.PD_DISABLEPRINTTOFILE | NativeMethods.PD_HIDEPRINTTOFILE; if (_dialog.PageRangeEnabled) { pdex.lpPageRanges = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.PRINTPAGERANGE))); pdex.nMaxPageRanges = 1; if (_dialog.PageRangeSelection == PageRangeSelection.UserPages) { pdex.nPageRanges = 1; Marshal.StructureToPtr(range, pdex.lpPageRanges, false); pdex.Flags |= NativeMethods.PD_PAGENUMS; } else { pdex.nPageRanges = 0; } } else { pdex.lpPageRanges = IntPtr.Zero; pdex.nMaxPageRanges = 0; pdex.Flags |= NativeMethods.PD_NOPAGENUMS; } // // If we know a print queue and print ticket, then we need to try to select // the printer in the dialog and use the print ticket. We allocate and setup // a DEVNAMES structure for this as well as convert the PrintTicket to a // DEVMODE. // if (_dialog.PrintQueue != null) { pdex.hDevNames = AllocateAndInitializeDevNames(_dialog.PrintQueue.FullName); if (_dialog.PrintTicket != null) { pdex.hDevMode = AllocateAndInitializeDevMode( _dialog.PrintQueue.FullName, _dialog.PrintTicket); } } int cbBufferSize = Marshal.SizeOf(typeof(NativeMethods.PRINTDLGEX32)); unmanagedBuffer = Marshal.AllocHGlobal(cbBufferSize); Marshal.StructureToPtr(pdex, unmanagedBuffer, false); } else { NativeMethods.PRINTDLGEX64 pdex = new NativeMethods.PRINTDLGEX64(); pdex.hwndOwner = _ownerHandle; pdex.nMinPage = _dialog.MinPage; pdex.nMaxPage = _dialog.MaxPage; pdex.Flags = NativeMethods.PD_ALLPAGES | NativeMethods.PD_NOCURRENTPAGE | NativeMethods.PD_NOSELECTION | NativeMethods.PD_USEDEVMODECOPIESANDCOLLATE | NativeMethods.PD_DISABLEPRINTTOFILE | NativeMethods.PD_HIDEPRINTTOFILE; if (_dialog.PageRangeEnabled) { pdex.lpPageRanges = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.PRINTPAGERANGE))); pdex.nMaxPageRanges = 1; if (_dialog.PageRangeSelection == PageRangeSelection.UserPages) { pdex.nPageRanges = 1; Marshal.StructureToPtr(range, pdex.lpPageRanges, false); pdex.Flags |= NativeMethods.PD_PAGENUMS; } else { pdex.nPageRanges = 0; } } else { pdex.lpPageRanges = IntPtr.Zero; pdex.nMaxPageRanges = 0; pdex.Flags |= NativeMethods.PD_NOPAGENUMS; } // // If we know a print queue and print ticket, then we need to try to select // the printer in the dialog and use the print ticket. We allocate and setup // a DEVNAMES structure for this as well as convert the PrintTicket to a // DEVMODE. // if (_dialog.PrintQueue != null) { pdex.hDevNames = AllocateAndInitializeDevNames(_dialog.PrintQueue.FullName); if (_dialog.PrintTicket != null) { pdex.hDevMode = AllocateAndInitializeDevMode( _dialog.PrintQueue.FullName, _dialog.PrintTicket); } } int cbBufferSize = Marshal.SizeOf(typeof(NativeMethods.PRINTDLGEX64)); unmanagedBuffer = Marshal.AllocHGlobal(cbBufferSize); Marshal.StructureToPtr(pdex, unmanagedBuffer, false); } } catch (Exception) { if (unmanagedBuffer != null) { FreeUnmanagedPrintDlgExStruct(unmanagedBuffer); unmanagedBuffer = IntPtr.Zero; } throw; } return unmanagedBuffer; } ////// Frees an unmanaged buffer. /// /// /// An unmanaged buffer representing the PRINTDLGEX structure. This structure /// is passed around as an unmanaged buffer since the 32-bit and 64-bit versions /// of this buffer are not the same and need to be handled uniquely. /// ////// Critical: - Frees an unmanaged buffer with potentially sensitive data. /// [SecurityCritical] private void FreeUnmanagedPrintDlgExStruct( IntPtr unmanagedBuffer ) { if (unmanagedBuffer == IntPtr.Zero) { return; } IntPtr devModeHandle = IntPtr.Zero; IntPtr devNamesHandle = IntPtr.Zero; IntPtr pageRangePtr = IntPtr.Zero; // // Extract the devmode and devnames handles from the appropriate PRINTDLGEX structure // if (!Is64Bit()) { NativeMethods.PRINTDLGEX32 pdex = (NativeMethods.PRINTDLGEX32)Marshal.PtrToStructure( unmanagedBuffer, typeof(NativeMethods.PRINTDLGEX32)); devModeHandle = pdex.hDevMode; devNamesHandle = pdex.hDevNames; pageRangePtr = pdex.lpPageRanges; } else { NativeMethods.PRINTDLGEX64 pdex = (NativeMethods.PRINTDLGEX64)Marshal.PtrToStructure( unmanagedBuffer, typeof(NativeMethods.PRINTDLGEX64)); devModeHandle = pdex.hDevMode; devNamesHandle = pdex.hDevNames; pageRangePtr = pdex.lpPageRanges; } if (devModeHandle != IntPtr.Zero) { UnsafeNativeMethods.GlobalFree(devModeHandle); } if (devNamesHandle != IntPtr.Zero) { UnsafeNativeMethods.GlobalFree(devNamesHandle); } if (pageRangePtr != IntPtr.Zero) { UnsafeNativeMethods.GlobalFree(pageRangePtr); } Marshal.FreeHGlobal(unmanagedBuffer); } ////// Returns a boolean value representing whether the current runtime is /// 32-bit or 64-bit. /// ////// Critical: - Marshal.SizeOf LinkDemands /// TreatAsSafe: - This method returns nothing that is unsafe. /// [SecurityCritical, SecurityTreatAsSafe] private bool Is64Bit() { IntPtr temp = IntPtr.Zero; return Marshal.SizeOf(temp) == 8; } ////// This method allocates a DEVNAMES structure in unmanaged code and configures /// it to point to the specified printer. /// /// /// The printer name to use for the DEVNAMES structure. /// ////// Returns an IntPtr pointing to a memory address in unmanaged code where /// the structure has been initialized. /// ////// Critical: - Allocates and manipulates unmanaged memory. /// [SecurityCritical] private IntPtr AllocateAndInitializeDevNames( string printerName ) { IntPtr hDevNames = IntPtr.Zero; char[] printer = printerName.ToCharArray(); // // Enough memory for the printer name character array + 3 null characters // + the DEVNAMES structure. The 3 null characters are for the end of the // printer name string, and 2 distinct empty strings. // int cbDevNames = ((printer.Length + 3) * Marshal.SystemDefaultCharSize) + Marshal.SizeOf(typeof(NativeMethods.DEVNAMES)); hDevNames = Marshal.AllocHGlobal(cbDevNames); ushort baseOffset = (ushort)Marshal.SizeOf(typeof(NativeMethods.DEVNAMES)); // // The wDeviceOffset contains an offset in characters to the printer name // within the DEVNAMES structure. The wDriverOffset and wOutputOffset // are offsets to two distinct empty strings that just happen to follow // the printer name string. For more information on how this structure is // layed out, please review the MSDN documentation for DEVNAMES structure. // NativeMethods.DEVNAMES devNames; devNames.wDeviceOffset = (ushort)(baseOffset / Marshal.SystemDefaultCharSize); devNames.wDriverOffset = (ushort)(devNames.wDeviceOffset + printer.Length + 1); devNames.wOutputOffset = (ushort)(devNames.wDriverOffset + 1); devNames.wDefault = 0; Marshal.StructureToPtr(devNames, hDevNames, false); // // Calculate the position of the string containing the printer name // - Printer name character array immediately follows the DEVNAMES structure // - followed by 3 NULL characters // IntPtr offsetName = (IntPtr)((long)hDevNames + (long)baseOffset); IntPtr offsetNull = (IntPtr)((long)offsetName + (printer.Length * Marshal.SystemDefaultCharSize)); // // Write the printer name and 3 NULL characters. The first NULL character // is to null terminate our printer name string. The second and third null // characters are to create to distinct empty strings within the buffer. // // NOTE: The byte array contains the NULL characters in a form that we are // able to write them out. There are 3 * char size bytes total. // byte[] nulls = new byte[3 * Marshal.SystemDefaultCharSize]; Array.Clear(nulls, 0, nulls.Length); Marshal.Copy( printer, 0, offsetName, printer.Length); Marshal.Copy( nulls, 0, offsetNull, nulls.Length); return hDevNames; } ////// This method allocates and initializes an unmanaged DEVMODE structure /// for use to by the PrintDlgEx method based on the specified printer /// and PrintTicket object. /// /// /// The printer that is being targetted by the PrintTicket. /// /// /// The PrintTicket that will be converted to a DEVMODE. /// ////// An unmanaged pointer to an unmanaged DEVMODE structure that can be /// used in the PRINTDLGEX structure for a call to PrintDlgEx. /// ////// Critical: - Allocates and manipulates unmanaged memory. /// - Asserts for DefaultPrinting permissions to be /// able to successfully convert the PrintTicket /// object to a DEVMODE via the PrintTicketConverter. /// [SecurityCritical] private IntPtr AllocateAndInitializeDevMode( string printerName, PrintTicket printTicket ) { byte[] devModeData = null; (new PrintingPermission(PrintingPermissionLevel.DefaultPrinting)).Assert(); //BlessedAssert try { // // Convert the PrintTicket object to a DEVMODE // using (PrintTicketConverter ptConverter = new PrintTicketConverter( printerName, PrintTicketConverter.MaxPrintSchemaVersion)) { devModeData = ptConverter.ConvertPrintTicketToDevMode( printTicket, BaseDevModeType.UserDefault); } } finally { PrintingPermission.RevertAssert(); } // // Make the dev mode data a DEVMODE structure in global memory // IntPtr hDevMode = Marshal.AllocHGlobal(devModeData.Length); Marshal.Copy(devModeData, 0, hDevMode, devModeData.Length); return hDevMode; } #endregion Private helper methods #region Private data private Win32PrintDialog _dialog; ////// Critical: This is a pointer to unmanaged memory containing /// an unmanaged PRINTDLGEX structure. /// [SecurityCritical] private IntPtr _unmanagedPrintDlgEx; ////// Critical: This is a handle to a window that will be used /// as the parent for the Win32 print dialog. /// [SecurityCritical] private IntPtr _ownerHandle; #endregion Private data #region IDisposable implementation ////// Implements the Dispose method for IDisposable. This ensures that /// any unmanaged PRINTDLGEX structure that was allocated by the class /// will be property freed when this class goes away. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } #endregion IDisposable implementation } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. // Microsoft Avalon // Copyright (c) Microsoft Corporation, 2006 // // File: Win32PrintDialog.cs // // 02/17/2006 : robertan - created // //------------------------------------------------------------------------------ using System; using System.Drawing.Printing; using System.Printing.Interop; using System.Printing; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; using System.Windows.Controls; namespace MS.Internal.Printing { internal partial class Win32PrintDialog { ////// This class abstracts the Marshaling of the PrintDlgEx structure to/from /// Native memory for displaying the Win32 print dialog via the PrintDlgEx /// API. The reason for this abstraction is to handle a known issue with /// this API. The 32-bit and 64-bit versions of this method have different /// packing schemes for the input structure that need to be handled separately /// to function correctly depending on the CPU archetecture. /// private sealed class PrintDlgExMarshaler : IDisposable { #region Constructor ////// Construct and initialize a PrintDlgExMarshaler instance. /// /// /// A Win32 window handle to use as the parent of this dialog. /// /// /// A reference to the Win32PrintDialog that contains the necessary /// data to display a Win32 Print Dialog via the PrintDlgEx call. /// ////// Critical: - Sets critical data to default values /// - We want creation of this class to be tracked. /// [SecurityCritical] internal PrintDlgExMarshaler( IntPtr owner, Win32PrintDialog dialog ) { _ownerHandle = owner; _dialog = dialog; _unmanagedPrintDlgEx = IntPtr.Zero; } #endregion Constructor #region Finalizer ~PrintDlgExMarshaler() { this.Dispose(true); } #endregion Finalizer #region Internal properties ////// Gets an IntPtr that points to unmanaged memory that represents /// a PRINTDLGEX structure for calling into PrintDlgEx Win32 API. /// ////// Critical: - This exposes critical unmanaged memory buffer /// and should be treated as dangerous since it /// is being passed to managed code. /// internal IntPtr UnmanagedPrintDlgEx { [SecurityCritical] get { return _unmanagedPrintDlgEx; } } #endregion Internal properties #region Internal methods ////// This method synchronizes the internal PRINTDLGEX unmanaged data /// structure with the internal Win32 print dialog configuration /// parameters. You call this prior to a call to PrintDlgEx Win32 /// API to configure the unmanaged memory. /// ////// Critical: - Calls other critical code (ExtractPrintDataAndDevMode, /// AcquireResultFromPrintDlgExStruct, AcquirePrintQueue, /// and AcquirePrintTicket). /// - Sets critical data on the Win32PrintDialog class /// (PrintTicket and PrintQueue) /// [SecurityCritical] internal UInt32 SyncFromStruct() { if (_unmanagedPrintDlgEx == IntPtr.Zero) { return NativeMethods.PD_RESULT_CANCEL; } UInt32 dialogResult = AcquireResultFromPrintDlgExStruct(_unmanagedPrintDlgEx); if ((dialogResult == NativeMethods.PD_RESULT_PRINT) || (dialogResult == NativeMethods.PD_RESULT_APPLY)) { IntPtr devModeHandle; string printerName; UInt32 flags; PageRange pageRange; ExtractPrintDataAndDevMode( _unmanagedPrintDlgEx, out printerName, out flags, out pageRange, out devModeHandle); _dialog.PrintQueue = AcquirePrintQueue(printerName); _dialog.PrintTicket = AcquirePrintTicket(devModeHandle, printerName); if ((flags & NativeMethods.PD_PAGENUMS) == NativeMethods.PD_PAGENUMS) { if (pageRange.PageFrom > pageRange.PageTo) { int temp = pageRange.PageTo; pageRange.PageTo = pageRange.PageFrom; pageRange.PageFrom = temp; } _dialog.PageRangeSelection = PageRangeSelection.UserPages; _dialog.PageRange = pageRange; } else { _dialog.PageRangeSelection = PageRangeSelection.AllPages; } } return dialogResult; } ////// This method synchronizes the managed Win32 data with the PRINTDLGEX /// unmanaged data structure. It is used after a successful call to the /// PrintDlgEx Win32 API. /// ////// Critical: - Calls into critical code (FreeUnmanagedPrintDlgExStruct, /// GetDesktopWindow, and AllocateUnmanagedPrintDlgExStruct). /// [SecurityCritical] internal void SyncToStruct() { if (_unmanagedPrintDlgEx != IntPtr.Zero) { FreeUnmanagedPrintDlgExStruct(_unmanagedPrintDlgEx); } // // If parent is not valid then get the desktop window handle. // if (_ownerHandle == IntPtr.Zero) { _ownerHandle = MS.Win32.UnsafeNativeMethods.GetDesktopWindow(); } // // Allocate an unmanaged PRINTDLGEX structure with our current internal settings. // _unmanagedPrintDlgEx = AllocateUnmanagedPrintDlgExStruct(); } #endregion Internal methods #region Private helper methods ////// Clean up any resources being used. /// /// /// true if managed resources should be disposed; otherwise, false. /// ////// Critical - Accesses unmanaged critical pointer /// TreatAsSafe - Its only freeing the memory and nothing leaves this method. /// [SecurityCritical, SecurityTreatAsSafe] private void Dispose( bool disposing ) { if (disposing) { if (_unmanagedPrintDlgEx != IntPtr.Zero) { FreeUnmanagedPrintDlgExStruct(_unmanagedPrintDlgEx); _unmanagedPrintDlgEx = IntPtr.Zero; } } } ////// Extracts the printer name, flags, pageRange, and devmode handle from the /// given PRINTDLGEX structure. /// /// /// An unmanaged buffer representing the PRINTDLGEX structure. This structure /// is passed around as an unmanaged buffer since the 32-bit and 64-bit versions /// of this buffer are not the same and need to be handled uniquely. /// /// /// An out parameter to store store the printer name. /// /// /// The set of flags that are inside the PRINTDIALOGEX structure. /// /// /// The user specified page range that is in PRINTDLGEX structure. /// This is only useful if the PD_PAGENUMS bit is set in the flags. /// /// /// An out parameter to store the devmode handle. /// ////// Critical: - manipulating unmanaged buffers with critical data in them. /// [SecurityCritical] private void ExtractPrintDataAndDevMode( IntPtr unmanagedBuffer, out string printerName, out UInt32 flags, out PageRange pageRange, out IntPtr devModeHandle ) { IntPtr devNamesHandle = IntPtr.Zero; IntPtr pageRangePtr = IntPtr.Zero; // // Extract the devmode and devnames handles from the appropriate PRINTDLGEX structure // if (!Is64Bit()) { NativeMethods.PRINTDLGEX32 pdex = (NativeMethods.PRINTDLGEX32)Marshal.PtrToStructure( unmanagedBuffer, typeof(NativeMethods.PRINTDLGEX32)); devModeHandle = pdex.hDevMode; devNamesHandle = pdex.hDevNames; flags = pdex.Flags; pageRangePtr = pdex.lpPageRanges; } else { NativeMethods.PRINTDLGEX64 pdex = (NativeMethods.PRINTDLGEX64)Marshal.PtrToStructure( unmanagedBuffer, typeof(NativeMethods.PRINTDLGEX64)); devModeHandle = pdex.hDevMode; devNamesHandle = pdex.hDevNames; flags = pdex.Flags; pageRangePtr = pdex.lpPageRanges; } // // Get a managed copy of the page ranges. This only matters if the PD_PAGENUMS bit is // set in the flags. // if (((flags & NativeMethods.PD_PAGENUMS) == NativeMethods.PD_PAGENUMS) && (pageRangePtr != IntPtr.Zero)) { NativeMethods.PRINTPAGERANGE pageRangeStruct = (NativeMethods.PRINTPAGERANGE)Marshal.PtrToStructure( pageRangePtr, typeof(NativeMethods.PRINTPAGERANGE)); pageRange = new PageRange((int)pageRangeStruct.nFromPage, (int)pageRangeStruct.nToPage); } else { pageRange = new PageRange(1); } // // Get a managed copy of the device name // if (devNamesHandle != IntPtr.Zero) { IntPtr pDevNames = IntPtr.Zero; try { pDevNames = UnsafeNativeMethods.GlobalLock(devNamesHandle); NativeMethods.DEVNAMES devNames = (NativeMethods.DEVNAMES)Marshal.PtrToStructure( pDevNames, typeof(NativeMethods.DEVNAMES)); printerName = Marshal.PtrToStringAuto( (IntPtr)((int)pDevNames + (devNames.wDeviceOffset * Marshal.SystemDefaultCharSize))); } finally { if (pDevNames != IntPtr.Zero) { UnsafeNativeMethods.GlobalUnlock(devNamesHandle); } } } else { printerName = string.Empty; } } ////// Acquires an instance of the PrintQueue that cooresponds to the given printer name. /// /// /// The printer name to search for. /// ////// Critical: - Performs an elevation to access the printing subsystem to lookup /// the PrintQueue based on the printername. /// [SecurityCritical] private PrintQueue AcquirePrintQueue( string printerName ) { PrintQueue printQueue = null; EnumeratedPrintQueueTypes[] types = new EnumeratedPrintQueueTypes[] { EnumeratedPrintQueueTypes.Local, EnumeratedPrintQueueTypes.Connections }; // // This forces us to acquire the cached version of the print queues. // This theoretically should prevent crashing in the printing system // since all it is doing is reading the registry. // PrintQueueIndexedProperty[] props = new PrintQueueIndexedProperty[] { PrintQueueIndexedProperty.Name, PrintQueueIndexedProperty.QueueAttributes }; (new PrintingPermission(PrintingPermissionLevel.DefaultPrinting)).Assert(); //BlessedAssert try { // // Get the PrintQueue instance for the printer // using (LocalPrintServer server = new LocalPrintServer()) { foreach (PrintQueue queue in server.GetPrintQueues(props, types)) { if (printerName.Equals(queue.FullName, StringComparison.OrdinalIgnoreCase)) { printQueue = queue; break; } } } if (printQueue != null) { printQueue.InPartialTrust = true; } } finally { PrintingPermission.RevertAssert(); } return printQueue; } ////// Acquires an instance of a PrintTicket given a handle to a DEVMODE and a printer name. /// /// /// The DEVMODE handle to use for the PrintTicket. /// /// /// The printer name for the PrintTicket converter. /// ////// Critical: - Performs an elevation to access the printing subsystem to lookup /// the PrintQueue based on the printer in the PRINTDLG structure. /// - Calls unmanaged code that has been suppressed. /// [SecurityCritical] private PrintTicket AcquirePrintTicket( IntPtr devModeHandle, string printQueueName ) { PrintTicket printTicket = null; byte[] devModeData = null; // // Copy the devmode into a byte array // IntPtr pDevMode = IntPtr.Zero; try { pDevMode = UnsafeNativeMethods.GlobalLock(devModeHandle); NativeMethods.DEVMODE devMode = (NativeMethods.DEVMODE)Marshal.PtrToStructure( pDevMode, typeof(NativeMethods.DEVMODE)); devModeData = new byte[devMode.dmSize + devMode.dmDriverExtra]; Marshal.Copy(pDevMode, devModeData, 0, devModeData.Length); } finally { if (pDevMode != IntPtr.Zero) { UnsafeNativeMethods.GlobalUnlock(devModeHandle); } } (new PrintingPermission(PrintingPermissionLevel.DefaultPrinting)).Assert(); //BlessedAssert try { // // Convert the devmode data to a PrintTicket object // using (PrintTicketConverter ptConverter = new PrintTicketConverter( printQueueName, PrintTicketConverter.MaxPrintSchemaVersion)) { printTicket = ptConverter.ConvertDevModeToPrintTicket(devModeData); } } finally { PrintingPermission.RevertAssert(); } return printTicket; } ////// Extracts the result value from a given PRINTDLGEX structure. /// /// /// An unmanaged buffer representing the PRINTDLGEX structure. This structure /// is passed around as an unmanaged buffer since the 32-bit and 64-bit versions /// of this buffer are not the same and need to be handled uniquely. /// ////// Critical: - manipulating unmanaged buffers with critical data in them. /// [SecurityCritical] private UInt32 AcquireResultFromPrintDlgExStruct( IntPtr unmanagedBuffer ) { UInt32 result = 0; // // Extract the devmode and devnames handles from the appropriate PRINTDLGEX structure // if (!Is64Bit()) { NativeMethods.PRINTDLGEX32 pdex = (NativeMethods.PRINTDLGEX32)Marshal.PtrToStructure( unmanagedBuffer, typeof(NativeMethods.PRINTDLGEX32)); result = pdex.dwResultAction; } else { NativeMethods.PRINTDLGEX64 pdex = (NativeMethods.PRINTDLGEX64)Marshal.PtrToStructure( unmanagedBuffer, typeof(NativeMethods.PRINTDLGEX64)); result = pdex.dwResultAction; } return result; } ////// Allocates an unmanaged buffer for the PRINTDLGEX structure and /// sets the initial values on it. /// /// NOTE: The reason for returning an unmanaged pointer to a buffer /// and not just a structure that can be passed to the unmanaged APIs /// is because this class is providing an abstraction to a problem that /// exists in the unmanaged print world where the 32-bit and 64-bit /// structure packing is inconsistent. /// ////// Critical: - Allocates and returns unmanaged memory that will /// eventually contain possibly sensitive data. /// [SecurityCritical] private IntPtr AllocateUnmanagedPrintDlgExStruct() { IntPtr unmanagedBuffer = IntPtr.Zero; NativeMethods.PRINTPAGERANGE range; range.nToPage = (uint)_dialog.PageRange.PageTo; range.nFromPage = (uint)_dialog.PageRange.PageFrom; try { if (!Is64Bit()) { NativeMethods.PRINTDLGEX32 pdex = new NativeMethods.PRINTDLGEX32(); pdex.hwndOwner = _ownerHandle; pdex.nMinPage = _dialog.MinPage; pdex.nMaxPage = _dialog.MaxPage; pdex.Flags = NativeMethods.PD_ALLPAGES | NativeMethods.PD_NOCURRENTPAGE | NativeMethods.PD_NOSELECTION | NativeMethods.PD_USEDEVMODECOPIESANDCOLLATE | NativeMethods.PD_DISABLEPRINTTOFILE | NativeMethods.PD_HIDEPRINTTOFILE; if (_dialog.PageRangeEnabled) { pdex.lpPageRanges = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.PRINTPAGERANGE))); pdex.nMaxPageRanges = 1; if (_dialog.PageRangeSelection == PageRangeSelection.UserPages) { pdex.nPageRanges = 1; Marshal.StructureToPtr(range, pdex.lpPageRanges, false); pdex.Flags |= NativeMethods.PD_PAGENUMS; } else { pdex.nPageRanges = 0; } } else { pdex.lpPageRanges = IntPtr.Zero; pdex.nMaxPageRanges = 0; pdex.Flags |= NativeMethods.PD_NOPAGENUMS; } // // If we know a print queue and print ticket, then we need to try to select // the printer in the dialog and use the print ticket. We allocate and setup // a DEVNAMES structure for this as well as convert the PrintTicket to a // DEVMODE. // if (_dialog.PrintQueue != null) { pdex.hDevNames = AllocateAndInitializeDevNames(_dialog.PrintQueue.FullName); if (_dialog.PrintTicket != null) { pdex.hDevMode = AllocateAndInitializeDevMode( _dialog.PrintQueue.FullName, _dialog.PrintTicket); } } int cbBufferSize = Marshal.SizeOf(typeof(NativeMethods.PRINTDLGEX32)); unmanagedBuffer = Marshal.AllocHGlobal(cbBufferSize); Marshal.StructureToPtr(pdex, unmanagedBuffer, false); } else { NativeMethods.PRINTDLGEX64 pdex = new NativeMethods.PRINTDLGEX64(); pdex.hwndOwner = _ownerHandle; pdex.nMinPage = _dialog.MinPage; pdex.nMaxPage = _dialog.MaxPage; pdex.Flags = NativeMethods.PD_ALLPAGES | NativeMethods.PD_NOCURRENTPAGE | NativeMethods.PD_NOSELECTION | NativeMethods.PD_USEDEVMODECOPIESANDCOLLATE | NativeMethods.PD_DISABLEPRINTTOFILE | NativeMethods.PD_HIDEPRINTTOFILE; if (_dialog.PageRangeEnabled) { pdex.lpPageRanges = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.PRINTPAGERANGE))); pdex.nMaxPageRanges = 1; if (_dialog.PageRangeSelection == PageRangeSelection.UserPages) { pdex.nPageRanges = 1; Marshal.StructureToPtr(range, pdex.lpPageRanges, false); pdex.Flags |= NativeMethods.PD_PAGENUMS; } else { pdex.nPageRanges = 0; } } else { pdex.lpPageRanges = IntPtr.Zero; pdex.nMaxPageRanges = 0; pdex.Flags |= NativeMethods.PD_NOPAGENUMS; } // // If we know a print queue and print ticket, then we need to try to select // the printer in the dialog and use the print ticket. We allocate and setup // a DEVNAMES structure for this as well as convert the PrintTicket to a // DEVMODE. // if (_dialog.PrintQueue != null) { pdex.hDevNames = AllocateAndInitializeDevNames(_dialog.PrintQueue.FullName); if (_dialog.PrintTicket != null) { pdex.hDevMode = AllocateAndInitializeDevMode( _dialog.PrintQueue.FullName, _dialog.PrintTicket); } } int cbBufferSize = Marshal.SizeOf(typeof(NativeMethods.PRINTDLGEX64)); unmanagedBuffer = Marshal.AllocHGlobal(cbBufferSize); Marshal.StructureToPtr(pdex, unmanagedBuffer, false); } } catch (Exception) { if (unmanagedBuffer != null) { FreeUnmanagedPrintDlgExStruct(unmanagedBuffer); unmanagedBuffer = IntPtr.Zero; } throw; } return unmanagedBuffer; } ////// Frees an unmanaged buffer. /// /// /// An unmanaged buffer representing the PRINTDLGEX structure. This structure /// is passed around as an unmanaged buffer since the 32-bit and 64-bit versions /// of this buffer are not the same and need to be handled uniquely. /// ////// Critical: - Frees an unmanaged buffer with potentially sensitive data. /// [SecurityCritical] private void FreeUnmanagedPrintDlgExStruct( IntPtr unmanagedBuffer ) { if (unmanagedBuffer == IntPtr.Zero) { return; } IntPtr devModeHandle = IntPtr.Zero; IntPtr devNamesHandle = IntPtr.Zero; IntPtr pageRangePtr = IntPtr.Zero; // // Extract the devmode and devnames handles from the appropriate PRINTDLGEX structure // if (!Is64Bit()) { NativeMethods.PRINTDLGEX32 pdex = (NativeMethods.PRINTDLGEX32)Marshal.PtrToStructure( unmanagedBuffer, typeof(NativeMethods.PRINTDLGEX32)); devModeHandle = pdex.hDevMode; devNamesHandle = pdex.hDevNames; pageRangePtr = pdex.lpPageRanges; } else { NativeMethods.PRINTDLGEX64 pdex = (NativeMethods.PRINTDLGEX64)Marshal.PtrToStructure( unmanagedBuffer, typeof(NativeMethods.PRINTDLGEX64)); devModeHandle = pdex.hDevMode; devNamesHandle = pdex.hDevNames; pageRangePtr = pdex.lpPageRanges; } if (devModeHandle != IntPtr.Zero) { UnsafeNativeMethods.GlobalFree(devModeHandle); } if (devNamesHandle != IntPtr.Zero) { UnsafeNativeMethods.GlobalFree(devNamesHandle); } if (pageRangePtr != IntPtr.Zero) { UnsafeNativeMethods.GlobalFree(pageRangePtr); } Marshal.FreeHGlobal(unmanagedBuffer); } ////// Returns a boolean value representing whether the current runtime is /// 32-bit or 64-bit. /// ////// Critical: - Marshal.SizeOf LinkDemands /// TreatAsSafe: - This method returns nothing that is unsafe. /// [SecurityCritical, SecurityTreatAsSafe] private bool Is64Bit() { IntPtr temp = IntPtr.Zero; return Marshal.SizeOf(temp) == 8; } ////// This method allocates a DEVNAMES structure in unmanaged code and configures /// it to point to the specified printer. /// /// /// The printer name to use for the DEVNAMES structure. /// ////// Returns an IntPtr pointing to a memory address in unmanaged code where /// the structure has been initialized. /// ////// Critical: - Allocates and manipulates unmanaged memory. /// [SecurityCritical] private IntPtr AllocateAndInitializeDevNames( string printerName ) { IntPtr hDevNames = IntPtr.Zero; char[] printer = printerName.ToCharArray(); // // Enough memory for the printer name character array + 3 null characters // + the DEVNAMES structure. The 3 null characters are for the end of the // printer name string, and 2 distinct empty strings. // int cbDevNames = ((printer.Length + 3) * Marshal.SystemDefaultCharSize) + Marshal.SizeOf(typeof(NativeMethods.DEVNAMES)); hDevNames = Marshal.AllocHGlobal(cbDevNames); ushort baseOffset = (ushort)Marshal.SizeOf(typeof(NativeMethods.DEVNAMES)); // // The wDeviceOffset contains an offset in characters to the printer name // within the DEVNAMES structure. The wDriverOffset and wOutputOffset // are offsets to two distinct empty strings that just happen to follow // the printer name string. For more information on how this structure is // layed out, please review the MSDN documentation for DEVNAMES structure. // NativeMethods.DEVNAMES devNames; devNames.wDeviceOffset = (ushort)(baseOffset / Marshal.SystemDefaultCharSize); devNames.wDriverOffset = (ushort)(devNames.wDeviceOffset + printer.Length + 1); devNames.wOutputOffset = (ushort)(devNames.wDriverOffset + 1); devNames.wDefault = 0; Marshal.StructureToPtr(devNames, hDevNames, false); // // Calculate the position of the string containing the printer name // - Printer name character array immediately follows the DEVNAMES structure // - followed by 3 NULL characters // IntPtr offsetName = (IntPtr)((long)hDevNames + (long)baseOffset); IntPtr offsetNull = (IntPtr)((long)offsetName + (printer.Length * Marshal.SystemDefaultCharSize)); // // Write the printer name and 3 NULL characters. The first NULL character // is to null terminate our printer name string. The second and third null // characters are to create to distinct empty strings within the buffer. // // NOTE: The byte array contains the NULL characters in a form that we are // able to write them out. There are 3 * char size bytes total. // byte[] nulls = new byte[3 * Marshal.SystemDefaultCharSize]; Array.Clear(nulls, 0, nulls.Length); Marshal.Copy( printer, 0, offsetName, printer.Length); Marshal.Copy( nulls, 0, offsetNull, nulls.Length); return hDevNames; } ////// This method allocates and initializes an unmanaged DEVMODE structure /// for use to by the PrintDlgEx method based on the specified printer /// and PrintTicket object. /// /// /// The printer that is being targetted by the PrintTicket. /// /// /// The PrintTicket that will be converted to a DEVMODE. /// ////// An unmanaged pointer to an unmanaged DEVMODE structure that can be /// used in the PRINTDLGEX structure for a call to PrintDlgEx. /// ////// Critical: - Allocates and manipulates unmanaged memory. /// - Asserts for DefaultPrinting permissions to be /// able to successfully convert the PrintTicket /// object to a DEVMODE via the PrintTicketConverter. /// [SecurityCritical] private IntPtr AllocateAndInitializeDevMode( string printerName, PrintTicket printTicket ) { byte[] devModeData = null; (new PrintingPermission(PrintingPermissionLevel.DefaultPrinting)).Assert(); //BlessedAssert try { // // Convert the PrintTicket object to a DEVMODE // using (PrintTicketConverter ptConverter = new PrintTicketConverter( printerName, PrintTicketConverter.MaxPrintSchemaVersion)) { devModeData = ptConverter.ConvertPrintTicketToDevMode( printTicket, BaseDevModeType.UserDefault); } } finally { PrintingPermission.RevertAssert(); } // // Make the dev mode data a DEVMODE structure in global memory // IntPtr hDevMode = Marshal.AllocHGlobal(devModeData.Length); Marshal.Copy(devModeData, 0, hDevMode, devModeData.Length); return hDevMode; } #endregion Private helper methods #region Private data private Win32PrintDialog _dialog; ////// Critical: This is a pointer to unmanaged memory containing /// an unmanaged PRINTDLGEX structure. /// [SecurityCritical] private IntPtr _unmanagedPrintDlgEx; ////// Critical: This is a handle to a window that will be used /// as the parent for the Win32 print dialog. /// [SecurityCritical] private IntPtr _ownerHandle; #endregion Private data #region IDisposable implementation ////// Implements the Dispose method for IDisposable. This ensures that /// any unmanaged PRINTDLGEX structure that was allocated by the class /// will be property freed when this class goes away. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } #endregion IDisposable implementation } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DynamicMetaObject.cs
- TextSelectionHighlightLayer.cs
- AxHost.cs
- TabPanel.cs
- BuildProviderUtils.cs
- CodeTypeMemberCollection.cs
- HeaderedItemsControl.cs
- PathSegment.cs
- PersistenceProviderFactory.cs
- ProcessRequestArgs.cs
- ConnectionManagementElementCollection.cs
- MetadataProperty.cs
- WebPartDescription.cs
- TextSimpleMarkerProperties.cs
- MemberInfoSerializationHolder.cs
- DataGridPagerStyle.cs
- DbProviderFactory.cs
- Transform3D.cs
- PropertyInfoSet.cs
- OrderByExpression.cs
- DeploymentSection.cs
- ButtonAutomationPeer.cs
- StatusBarPanelClickEvent.cs
- SessionParameter.cs
- RawTextInputReport.cs
- PersonalizationStateInfoCollection.cs
- AttributeProviderAttribute.cs
- XmlHelper.cs
- BamlTreeMap.cs
- InstanceStoreQueryResult.cs
- InputDevice.cs
- DocumentOrderQuery.cs
- User.cs
- InheritedPropertyChangedEventArgs.cs
- GorillaCodec.cs
- WindowsEditBox.cs
- ColorTypeConverter.cs
- Padding.cs
- precedingquery.cs
- CodeDomComponentSerializationService.cs
- XmlSchemaSimpleTypeUnion.cs
- DetailsViewPageEventArgs.cs
- CompareValidator.cs
- MemberListBinding.cs
- ItemDragEvent.cs
- SafeNativeMethods.cs
- SqlResolver.cs
- TemplateBindingExpressionConverter.cs
- StatusBarPanel.cs
- SqlDataSourceFilteringEventArgs.cs
- CodeDomSerializerException.cs
- ChangePasswordAutoFormat.cs
- InfoCardRSAPKCS1KeyExchangeDeformatter.cs
- QilTernary.cs
- MatrixTransform3D.cs
- BitmapEffectDrawingContent.cs
- CodeDOMProvider.cs
- GroupBox.cs
- XamlTemplateSerializer.cs
- ChangeInterceptorAttribute.cs
- RMPermissions.cs
- Propagator.Evaluator.cs
- Vector3DCollectionValueSerializer.cs
- CacheDependency.cs
- DefaultObjectMappingItemCollection.cs
- StyleXamlParser.cs
- TreeNodeCollectionEditor.cs
- WebPartAuthorizationEventArgs.cs
- XmlWriter.cs
- FixedSchema.cs
- ContractHandle.cs
- WriteableBitmap.cs
- ListBindableAttribute.cs
- XmlSchemaException.cs
- BulletedListEventArgs.cs
- SHA256.cs
- DataGridViewCellStyleConverter.cs
- MatrixConverter.cs
- SendMailErrorEventArgs.cs
- PropertyPath.cs
- SqlStatistics.cs
- HashAlgorithm.cs
- XmlNullResolver.cs
- HandlerWithFactory.cs
- Types.cs
- ApplicationActivator.cs
- XPathDocumentIterator.cs
- FixedTextSelectionProcessor.cs
- TextAnchor.cs
- ObjectNavigationPropertyMapping.cs
- XmlILModule.cs
- VirtualizedCellInfoCollection.cs
- KnownBoxes.cs
- PrimitiveRenderer.cs
- SafeMILHandle.cs
- InternalTransaction.cs
- SchemaElement.cs
- SoapMessage.cs
- SqlCacheDependencySection.cs
- ProfileParameter.cs