PTProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Print / Reach / PrintConfig / PTProvider.cs / 1 / PTProvider.cs

                            /*++ 

Copyright (C) 2002 Microsoft Corporation
All rights reserved.
 
Module Name:
 
    PTProvider.cs 

Abstract: 

    Definition and implementation of the internal managed PTProvider and NativeMethods classes.
    These classes hide from PrintTicketManager and PrintTicketConverter the fact and complexity
    of thunking into unmanaged component to get PrintTicket and PrintCapabilities provider services. 

Author: 
 
    [....] ([....]) 11/22/2002
    Ben Kuhn (benkuhn) 

--*/

using System; 
using System.IO;
using System.Security; 
using System.Globalization; 
using System.Collections.Specialized;
using System.Runtime.InteropServices; 
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;

using System.Printing.Interop; 
using System.Printing;
using Microsoft.Internal; 
 
using System.Windows.Xps.Serialization; // for Toolbox
 
namespace MS.Internal.Printing.Configuration
{
    #region SafePTProviderHandle class
 
    // Subclass Whidbey SafeHandle to wrap unmanaged handle.
    // SafeHandle derives from CriticalFinalizerObject, which makes the finalizer critical and 
    // CLR runtime treats CriticalFinalizerObject subclasses specially during interop marshaling 
    // and finalization. SafeHandle supports reference counting to prevent handle recycling issue
    // (CriticalHandle doesn't). 
    internal sealed class SafePTProviderHandle : System.Runtime.InteropServices.SafeHandle
    {
        // Called by P/Invoke when returning SafeHandle. It's private in order to prevent handle
        // creation by the constructor. 
        /// 
        ///     Critical: This code derives from SafeHandle which is link demand and inheritance demand protected 
        ///     TreatAsSafe: This code initializes the handle to Null 
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        private SafePTProviderHandle() : base(IntPtr.Zero, true)
        {
        }
 
        // We should define other constructors if and only if we need to support user-supplied handles.
        // Do not provide a finalizer - SafeHandle's critical finalizer will call ReleaseHandle() for you. 
        ///  
        ///     Critical: This code touches Handle which is critical
        ///     TreatAsSafe: Exposing Information as to whether a handle is valid or not is deemed as safe 
        /// 
        public override bool IsInvalid
        {
           [SecurityCritical,SecurityTreatAsSafe] 
            get
            { 
                // Need to check IsClosed first to determine if the handle is closed. This is because 
                // SetHandleAsInvalid implementation on base class just marks handle as closed to abstract
                // any values that invalid handles could have. If handle is not closed, then we need to 
                // compare against real invalid values (in case handle was created from the interop call).
                return (IsClosed || (handle == IntPtr.Zero));
            }
        } 

        // Implementation of SafeHandle's this abstract method specifies how to free the handle. 
        // The boolean returned should be true for success and false if the runtime 
        // should fire a SafeHandleCriticalFailure MDA (CustomerDebugProbe) if that
        // MDA is enabled. 
        ///
        /// Critical    - calls into code with SUC applied to enable
        ///               Devmode  manipulation in Intranet Zone
        /// TreatAsSafe - this method is releasing a handle that was gained by elivating 
        ///               it can not demand permisions because this crashes in garbage collection
        /// 
        [System.Security.SecurityCritical, System.Security.SecurityTreatAsSafe] 
        protected override bool ReleaseHandle()
        { 
            // SuppressUnmanagedCodeSecurity should always be used on any P/Invoke methods
            // invoked as part of ReleaseHandle, in order to switch the security check from runtime to
            // JIT time and thus remove a possible failure path from the invocation of the method.
            uint hResult = NativeMethods.UnbindPTProviderThunk(handle); 
            return (hResult < 0x80000000);
        } 
    } 

    #endregion SafePTProviderHandle class 

    #region NativeMethods

    ///  
    /// Internal proxy class that makes P/Invoke calls into the unmanaged stub provider prntvpt.dll.
    ///  
    /// all input parameters to NativeMethods functions are from trusted source 
    ///
    /// Critical    - Win32 Print API calls which enables printing and print queue/server management 
    ///
    [System.Security.SuppressUnmanagedCodeSecurityAttribute]
    [System.Security.SecurityCritical(System.Security.SecurityCriticalScope.Everything)]
    internal static class NativeMethods 
    {
        ///  
        /// Binds proxy to the specified printer device 
        /// 
        /// printer device name 
        /// max schema version supported by client
        /// schema version preferred by client
        /// device handle proxy is bound to
        /// schema version proxy will use 
        /// HRESULT code
        /// 
        /// Critical    - SUC applied; enables Devmode manipulation in Intranet Zone 
        ///             - callers must demand DefaultPrinting
        ///             - shouldn't be called in Partial Trust 
        ///
        [DllImport(DllImport.PrntvPt, CharSet=CharSet.Unicode)]
        internal static extern uint BindPTProviderThunk(
            [MarshalAs(UnmanagedType.LPWStr)] string deviceName, 
            int maxVersion,
            int prefVersion, 
            out SafePTProviderHandle handle, 
            out int usedVersion);
 
        /// 
        /// Unbinds proxy from the printer device and release any associated unmanaged resources
        /// 
        /// device handle proxy has been bound to 
        /// HRESULT code
        /// 
        /// Critical    - SUC applied; enables Devmode manipulation in Intranet Zone 
        ///             - callers must demand DefaultPrinting
        ///             - shouldn't be called in Partial Trust 
        ///
        [DllImport(DllImport.PrntvPt, CharSet=CharSet.Unicode)]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        internal static extern uint UnbindPTProviderThunk( 
            IntPtr handle);
 
        ///  
        /// Gets the PrintCapabilities relative to the given PrintTicket
        ///  
        /// device handle
        /// buffer that contains XML PrintTicket
        /// size of printTicket buffer
        /// buffer that contains XML PrintCapabilities 
        /// size of printCapabilities buffer
        /// error message if the operation failed 
        /// HRESULT code 
        ///
        /// Critical    - SUC applied; enables Device capabilities manipulation in Intranet Zone 
        ///             - callers must demand DefaultPrinting
        ///             - shouldn't be called in Partial Trust
        ///
        [DllImport(DllImport.PrntvPt, CharSet=CharSet.Unicode)] 
        internal static extern uint GetPrintCapabilitiesThunk2(
            SafePTProviderHandle handle, 
            IntPtr printTicket, 
            int ptSize,
            out IntPtr printCapabilities, 
            out int pcSize,
            [MarshalAs(UnmanagedType.BStr)] out string errorMsg);

        ///  
        /// Merges delta PrintTicket onto base PrintTicket and then validates the merged PrintTicket
        ///  
        /// device handle 
        /// buffer that contains base XML PrintTicket
        /// size of baseTicket buffer 
        /// buffer that contains delta XML PrintTicket
        /// size of deltaTicket buffer
        /// scope that delta PrintTicket and result PrintTicket will be limited to
        /// buffer that contains validated XML PrintTicket 
        /// size of resultTicket buffer
        /// error message if the operation failed 
        /// HRESULT code 
        ///
        /// Critical    - SUC applied; enables Print Ticket manipulation in Intranet Zone 
        ///             - callers must demand DefaultPrinting
        ///             - shouldn't be called in Partial Trust
        ///
        [DllImport(DllImport.PrntvPt, CharSet=CharSet.Unicode)] 
        internal static extern uint MergeAndValidatePrintTicketThunk2(
            SafePTProviderHandle handle, 
            IntPtr baseTicket, 
            int baseTicketSize,
            IntPtr deltaTicket, 
            int deltaTicketSize,
            uint scope,
            out IntPtr resultTicket,
            out int resultTicketSize, 
            [MarshalAs(UnmanagedType.BStr)] out string errorMsg);
 
        ///  
        /// Converts the given Win32 DEVMODE into PrintTicket
        ///  
        /// device handle
        /// buffer that contains the Win32 DEVMODE
        /// size of devMode buffer in bytes
        /// scope that the result PrintTicket will be limited to 
        /// buffer that contains the converted XML PrintTicket
        /// size of printTicket buffer in bytes 
        /// HRESULT code 
        ///
        /// Critical    - SUC applied; enables conversion of a devmode to a PrintTicket in Intranet Zone 
        ///             - callers must demand DefaultPrinting
        ///             - shouldn't be called in Partial Trust
        ///
        [DllImport(DllImport.PrntvPt, CharSet=CharSet.Unicode)] 
        internal static extern uint ConvertDevModeToPrintTicketThunk2(
            SafePTProviderHandle handle, 
            IntPtr devMode, 
            int    dmSize,
            uint   scope, 
            out IntPtr printTicket,
            out int ptSize);

        ///  
        /// Converts the given PrintTicket into Win32 DEVMODE
        ///  
        /// device handle 
        /// buffer that contains the XML PrintTicket
        /// size of printTicket buffer in bytes 
        /// type of default DEVMODE to use as base of conversion
        /// scope that the input PrintTicket will be limited to
        /// buffer that contains the converted Win32 DEVMODE
        /// size of devMode buffer in bytes 
        /// error message if the operation failed
        /// HRESULT code 
        /// 
        /// Critical    - SUC applied; enables conversion of a PrintTicket to devmode in Intranet Zone
        ///             - callers must demand DefaultPrinting 
        ///             - shouldn't be called in Partial Trust
        ///
        [DllImport(DllImport.PrntvPt, CharSet=CharSet.Unicode)]
        internal static extern uint ConvertPrintTicketToDevModeThunk2( 
            SafePTProviderHandle handle,
            IntPtr printTicket, 
            int ptSize, 
            int baseType,
            uint scope, 
            out IntPtr devMode,
            out int dmSize,
            [MarshalAs(UnmanagedType.BStr)] out string errorMsg);
    } 

    #endregion Native Methods 
 
    #region Internal Types
 
    /// 
    /// List of error codes that could be returned by unmanaged component.
    /// 
    /// values must match the definition in GDIPrintTicket.h 
    internal enum NativeErrorCode : uint
    { 
        ///  
        /// no conflicts resolving needed during PrintTicket validation
        ///  
        S_PT_NO_CONFLICT = 0x00040001,

        /// 
        /// some conflicts were resolved during PrintTicket validation 
        /// 
        S_PT_CONFLICT_RESOLVED = 0x00040002, 
 
        /// 
        /// validation failed because of a Schema violation 
        /// 
        E_XML_INVALID = 0xC00CE225,

        ///  
        /// client input PrintTicket is not well-formed
        ///  
        /// Well-formed PrintTicket means its XML structure complies 
        /// with what Print Schema framework defines. Well-formed PrintTicket
        /// is not necessary valid since it can still contain conflict settings. 
        /// 
        E_PRINTTICKET_FORMAT = 0x80040003,

        ///  
        /// client input delta PrintTicket is not well-formed
        ///  
        /// Well-formed PrintTicket means its XML structure complies 
        /// with what Print Schema framework defines. Well-formed PrintTicket
        /// is not necessary valid since it can still contain conflict settings. 
        /// 
        E_DELTA_PRINTTICKET_FORMAT = 0x80040005,
    }
 
    #endregion Internal Types
 
    #region PTProvider class 

    // 



    ///  
    /// Managed PrintTicket provider class that inter-ops with unmanaged DDI driver
    ///  
    internal class PTProvider : IDisposable 
    {
        #region Constructors 

        /// 
        /// Constructs a new PrintTicket provider instance for the given device.
        ///  
        /// name of printer device the provider should be bound to
        /// max schema version supported by client 
        /// schema version requested by client 
        /// 
        /// The PTProvider instance failed to bind to the specified printer. 
        /// 
        ///
        /// Critical    - calls into code with SUC applied to enable
        ///               Devmode  manipulation in Intranet Zone 
        /// TreatAsSafe - this method demands DefaultPrinting to run (not granted in Internet Zone)
        /// 
        [System.Security.SecurityCritical, System.Security.SecurityTreatAsSafe] 
        [System.Drawing.Printing.PrintingPermission(
         System.Security.Permissions.SecurityAction.Demand, 
         Level = System.Drawing.Printing.PrintingPermissionLevel.DefaultPrinting)]
        public PTProvider(string deviceName, int maxVersion, int clientVersion)
        {
            Toolbox.StartEvent(Toolbox.DRXPTPROVIDERGUID); 

            // We are not doing late binding to the device here because we should 
            // indicate right away if there was an error in binding the provider 
            // to the device.  Doing late binding would mean that any instance
            // method could throw a no such printer exception. 
            uint hResult = NativeMethods.BindPTProviderThunk(deviceName,
                                                             maxVersion,
                                                             clientVersion,
                                                             out _providerHandle, 
                                                             out _schemaVersion);
 
            if (!PTUtility.IsSuccessCode(hResult)) 
            {
                throw new PrintQueueException((int)hResult, "PrintConfig.Provider.BindFail", deviceName); 
            }

#if _DEBUG
            if (_schemaVersion != clientVersion) 
            {
                // BindPTProviderThunk() shouldn't succeed if it can't support the requested version. 
                throw new InvalidOperationException("_DEBUG: Client requested Print Schema version " + 
                                                    clientVersion.ToString(CultureInfo.CurrentCulture) +
                                                    " doesn't match to provider Print Schema version " + 
                                                    _schemaVersion.ToString(CultureInfo.CurrentCulture));
            }
#endif
 
            // If succeeded, BindPTProviderThunk() function should ensure that a valid _providerHandle
            // is returned and the returned schemaVersion is within valid range (i.e. no greater than maxVersion) 
            this._deviceName = deviceName; 

            Toolbox.EndEvent(Toolbox.DRXPTPROVIDERGUID); 
        }

        #endregion Constructors
 
        #region Public Properties
 
        #endregion Public Properties 

        #region Public Methods 

        /// 
        /// Gets the PrintCapabilities relative to the given PrintTicket.
        ///  
        /// The stream that contains XML PrintTicket based on which PrintCapabilities should be built.
        /// Stream that contains XML PrintCapabilities. 
        ///  
        /// The PTProvider instance has already been disposed.
        ///  
        /// 
        /// The input PrintTicket specified by  is not well-formed.
        /// 
        ///  
        /// The PTProvider instance failed to retrieve the PrintCapabilities.
        ///  
        /// 
        /// Critical    - calls into code with SUC applied to enable
        ///               Device capabilities manipulation in Intranet Zone 
        /// TreatAsSafe - this method demands DefaultPrinting to run (not granted in Internet Zone)
        ///
        [System.Security.SecurityCritical, System.Security.SecurityTreatAsSafe]
        [System.Drawing.Printing.PrintingPermission( 
         System.Security.Permissions.SecurityAction.Demand,
        Level = System.Drawing.Printing.PrintingPermissionLevel.DefaultPrinting)] 
        public MemoryStream GetPrintCapabilities(MemoryStream printTicket) 
        {
            if (_disposed) 
            {
                throw new ObjectDisposedException("PTProvider");
            }
 
            IntPtr printCapData = IntPtr.Zero;
            int printCapLength = 0; 
            string errorMsg = null; 
            NativeBuffer ticketBuffer = new NativeBuffer(IntPtr.Zero, 0);
            MemoryStream printCapabilities = null; 

            try
            {
                if (printTicket != null) 
                {
                    ticketBuffer = PackStreamToNativeBuffer(printTicket, "printTicket"); 
                } 

                // 

                uint hResult = NativeMethods.GetPrintCapabilitiesThunk2(_providerHandle,
                                                                        ticketBuffer.data,
                                                                        ticketBuffer.length, 
                                                                        out printCapData,
                                                                        out printCapLength, 
                                                                        out errorMsg); 

                if (!PTUtility.IsSuccessCode(hResult)) 
                {
                    if (hResult == (uint)NativeErrorCode.E_PRINTTICKET_FORMAT)
                    {
                        throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, 
                                      "{0} {1} {2}",
                                      PrintSchemaTags.Framework.PrintTicketRoot, 
                                      PTUtility.GetTextFromResource("FormatException.XMLNotWellFormed"), 
                                      errorMsg),
                                      "printTicket"); 
                    }
                    else
                    {
                        throw new PrintQueueException((int)hResult, 
                                                      "PrintConfig.Provider.GetPrintCapFail",
                                                      _deviceName, 
                                                      errorMsg); 
                    }
                } 

                printCapabilities = CopyNativeBufferToStream(printCapData, printCapLength);
            }
            finally 
            {
                if (ticketBuffer.data != IntPtr.Zero) 
                { 
                    Marshal.FreeCoTaskMem(ticketBuffer.data);
                } 

                if (printCapData != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(printCapData); 
                }
            } 
 
            return printCapabilities;
        } 

        /// 
        /// Merges delta PrintTicket with base PrintTicket and then validates the merged PrintTicket.
        ///  
        /// The MemoryStream that contains base XML PrintTicket.
        /// The MemoryStream that contains delta XML PrintTicket. 
        /// scope that delta PrintTicket and result PrintTicket will be limited to 
        /// The returned conflict resolving status.
        /// MemoryStream that contains validated and merged PrintTicket XML. 
        /// 
        /// The PTProvider instance has already been disposed.
        /// 
        ///  
        /// The base PrintTicket specified by  is not well-formed,
        /// or delta PrintTicket specified by  is not well-formed. 
        ///  
        /// 
        /// The PTProvider instance failed to merge and validate the input PrintTicket(s). 
        /// 
        ///
        /// Critical    - calls into code with SUC applied to enable enable Print Ticket
        ///               manipulation in Intranet Zone 
        /// TreatAsSafe - this method demands DefaultPrinting to run (not granted in Internet Zone)
        /// 
        [System.Security.SecurityCritical, System.Security.SecurityTreatAsSafe] 
        [System.Drawing.Printing.PrintingPermission(
         System.Security.Permissions.SecurityAction.Demand, 
         Level = System.Drawing.Printing.PrintingPermissionLevel.DefaultPrinting)]
        public MemoryStream MergeAndValidatePrintTicket(MemoryStream basePrintTicket,
                                                        MemoryStream deltaPrintTicket,
                                                        PrintTicketScope scope, 
                                                        out ConflictStatus conflictStatus)
        { 
            if (_disposed) 
            {
                throw new ObjectDisposedException("PTProvider"); 
            }

            IntPtr outPTData = IntPtr.Zero;
            int outPTLength = 0; 
            string errorMsg = null;
 
            NativeBuffer baseTicketBuffer = new NativeBuffer(IntPtr.Zero, 0); 
            NativeBuffer deltaTicketBuffer = new NativeBuffer(IntPtr.Zero, 0);
 
            MemoryStream validatedPrintTicket = null;
            conflictStatus = ConflictStatus.NoConflict;

            try 
            {
                baseTicketBuffer = PackStreamToNativeBuffer(basePrintTicket, "basePrintTicket"); 
 
                if (deltaPrintTicket != null)
                { 
                    deltaTicketBuffer = PackStreamToNativeBuffer(deltaPrintTicket, "deltaPrintTicket");
                }

                uint hResult = NativeMethods.MergeAndValidatePrintTicketThunk2(_providerHandle, 
                                                                               baseTicketBuffer.data,
                                                                               baseTicketBuffer.length, 
                                                                               deltaTicketBuffer.data, 
                                                                               deltaTicketBuffer.length,
                                                                               (uint)scope, 
                                                                               out outPTData,
                                                                               out outPTLength,
                                                                               out errorMsg);
 
                if (!PTUtility.IsSuccessCode(hResult))
                { 
                    if ((hResult == (uint)NativeErrorCode.E_PRINTTICKET_FORMAT) || 
                        (hResult == (uint)NativeErrorCode.E_DELTA_PRINTTICKET_FORMAT))
                    { 
                        throw new ArgumentException(String.Format(CultureInfo.CurrentCulture,
                                      "{0} {1} {2}",
                                      PrintSchemaTags.Framework.PrintTicketRoot,
                                      PTUtility.GetTextFromResource("FormatException.XMLNotWellFormed"), 
                                      errorMsg),
                                      (hResult == (uint)NativeErrorCode.E_PRINTTICKET_FORMAT) ? "basePrintTicket" : "deltaPrintTicket"); 
                    } 
                    else
                    { 
                        throw new PrintQueueException((int)hResult,
                                                      "PrintConfig.Provider.MergeValidateFail",
                                                      _deviceName,
                                                      errorMsg); 
                    }
                } 
 
                validatedPrintTicket = CopyNativeBufferToStream(outPTData, outPTLength);
 
                // convert the success hResult to an enum value
                switch (hResult)
                {
                    case (uint)NativeErrorCode.S_PT_CONFLICT_RESOLVED: 
                        conflictStatus = ConflictStatus.ConflictResolved;
                        break; 
                    case (uint)NativeErrorCode.S_PT_NO_CONFLICT: 
                        conflictStatus = ConflictStatus.NoConflict;
                        break; 
                    default:
                        throw new PrintQueueException((int)hResult,
                                                      "PrintConfig.Provider.MergeValidateFail",
                                                      _deviceName); 
                }
            } 
            finally 
            {
                if (baseTicketBuffer.data != IntPtr.Zero) 
                {
                    Marshal.FreeCoTaskMem(baseTicketBuffer.data);
                }
 
                if (deltaTicketBuffer.data != IntPtr.Zero)
                { 
                    Marshal.FreeCoTaskMem(deltaTicketBuffer.data); 
                }
 
                if (outPTData != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(outPTData);
                } 
            }
 
            return validatedPrintTicket; 
        }
 
        /// 
        /// Converts the given Win32 DEVMODE into PrintTicket.
        /// 
        /// Byte buffer containing the Win32 DEVMODE. 
        /// scope that the result PrintTicket will be limited to
        /// MemoryStream that contains the converted XML PrintTicket. 
        ///  
        /// The PTProvider instance has already been disposed.
        ///  
        /// 
        /// The DEVMODE specified by  is not well-formed.
        /// 
        ///  
        /// The PTProvider instance failed to convert the DEVMODE to a PrintTicket.
        ///  
        /// 
        /// Critical    - calls into code with SUC applied to enable conversion of a devmode to a PrintTicket
        ///               manipulation in Intranet Zone 
        /// TreatAsSafe - this method demands DefaultPrinting to run (not granted in Internet Zone)
        ///
        [System.Security.SecurityCritical, System.Security.SecurityTreatAsSafe]
        [System.Drawing.Printing.PrintingPermission( 
         System.Security.Permissions.SecurityAction.Demand,
         Level = System.Drawing.Printing.PrintingPermissionLevel.DefaultPrinting)] 
        public MemoryStream ConvertDevModeToPrintTicket(byte[] devMode, 
                                                        PrintTicketScope scope)
        { 
            if (_disposed)
            {
                throw new ObjectDisposedException("PTProvider");
            } 

            IntPtr outPTData = IntPtr.Zero; 
            int outPTLength = 0; 
            IntPtr umDevMode = IntPtr.Zero;
            MemoryStream printTicket = null; 

            try
            {
                // Allocate unmanaged buffer and copy devMode byte array into the unmanaged buffer 
                umDevMode = Marshal.AllocCoTaskMem(devMode.Length);
                Marshal.Copy(devMode, 0, umDevMode, devMode.Length); 
 
                uint hResult = NativeMethods.ConvertDevModeToPrintTicketThunk2(_providerHandle,
                                                                               umDevMode, 
                                                                               devMode.Length,
                                                                               (uint)scope,
                                                                               out outPTData,
                                                                               out outPTLength); 

                if (!PTUtility.IsSuccessCode(hResult)) 
                { 
                    throw new PrintQueueException((int)hResult,
                                                  "PrintConfig.Provider.DevMode2PTFail", 
                                                  _deviceName);
                }

                printTicket = CopyNativeBufferToStream(outPTData, outPTLength); 
            }
            finally 
            { 
                if (umDevMode != IntPtr.Zero)
                { 
                    Marshal.FreeCoTaskMem(umDevMode);
                }

                if (outPTData != IntPtr.Zero) 
                {
                    Marshal.FreeCoTaskMem(outPTData); 
                } 
            }
 
            return printTicket;
        }

        ///  
        /// Converts the given PrintTicket into Win32 DEVMODE.
        ///  
        /// MemoryStream containing the XML PrintTicket. 
        /// Type of default DEVMODE to use as base of conversion.
        /// scope that the input PrintTicket will be limited to 
        /// Byte buffer that contains the converted Win32 DEVMODE.
        /// 
        /// The PTProvider instance has already been disposed.
        ///  
        /// 
        /// The PrintTicket specified by  is not well-formed. 
        ///  
        /// 
        /// The PTProvider instance failed to convert the PrintTicket to a DEVMODE. 
        /// 
        ///
        /// Critical    - calls into code with SUC applied to enable the conversion
        ///               of a PrintTicket to devmode in Intranet Zone 
        /// TreatAsSafe - this method demands DefaultPrinting to run
        /// 
        [System.Security.SecurityCritical, System.Security.SecurityTreatAsSafe] 
        [System.Drawing.Printing.PrintingPermission(
         System.Security.Permissions.SecurityAction.Demand, 
         Level = System.Drawing.Printing.PrintingPermissionLevel.DefaultPrinting)]
        public byte[] ConvertPrintTicketToDevMode(MemoryStream printTicket,
                                                  BaseDevModeType baseType,
                                                  PrintTicketScope scope) 
        {
            if (_disposed) 
            { 
                throw new ObjectDisposedException("PTProvider");
            } 

            IntPtr umDevMode = IntPtr.Zero;
            int umDevModeLen = 0;
            string errorMsg = null; 
            NativeBuffer ticketBuffer = new NativeBuffer(IntPtr.Zero, 0);
 
            byte[] devMode = null; 

            try 
            {
                ticketBuffer = PackStreamToNativeBuffer(printTicket, "printTicket");

                uint hResult = NativeMethods.ConvertPrintTicketToDevModeThunk2(_providerHandle, 
                                                                               ticketBuffer.data,
                                                                               ticketBuffer.length, 
                                                                               (int)baseType, 
                                                                               (uint)scope,
                                                                               out umDevMode, 
                                                                               out umDevModeLen,
                                                                               out errorMsg);

 
                if (!PTUtility.IsSuccessCode(hResult))
                { 
                    if ((hResult == (uint)NativeErrorCode.E_XML_INVALID) || 
                        (hResult == (uint)NativeErrorCode.E_PRINTTICKET_FORMAT))
                    { 
                        throw new ArgumentException(String.Format(CultureInfo.CurrentCulture,
                                      "{0} {1} {2}",
                                      PrintSchemaTags.Framework.PrintTicketRoot,
                                      PTUtility.GetTextFromResource("FormatException.XMLNotWellFormed"), 
                                      errorMsg),
                                      "printTicket"); 
                    } 
                    else
                    { 
                        throw new PrintQueueException((int)hResult,
                                                      "PrintConfig.Provider.PT2DevModeFail",
                                                      _deviceName,
                                                      errorMsg); 
                    }
                } 
 
                devMode = new byte[umDevModeLen];
 
                // Copy unmanaged devMode buffer into the managed byte array
                Marshal.Copy(umDevMode, devMode, 0, umDevModeLen);
            }
            finally 
            {
                if (ticketBuffer.data != IntPtr.Zero) 
                { 
                    Marshal.FreeCoTaskMem(ticketBuffer.data);
                } 

                if (umDevMode != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(umDevMode); 
                }
            } 
 
            return devMode;
        } 

        #endregion Public Methods

        #region Private Types 

        ///  
        /// struct that contains the result from packing a stream into a native byte buffer 
        /// 
        private struct NativeBuffer 
        {
            public int length;
            public IntPtr data;
 
            public NativeBuffer (IntPtr d, int l)
            { 
                length = l; 
                data = d;
            } 
        }

        #endregion Private Types
 
        #region Private Methods
 
        ///  
        /// Copies the managed source stream data to the native buffer
        ///  
        /// 
        /// This method reads the stream from its current cursor to the end.
        /// Caller is responsible for freeing the native buffer created (by using CoTaskMemFree).
        ///  
        /// the source MemoryStream
        /// name of the input argument 
        /// struct containing result of the stream packing 
        ///
        /// Critical    - the method copies content from the managed stream object to unmanaged memory 
        ///
        [SecurityCritical]
        private static NativeBuffer PackStreamToNativeBuffer(MemoryStream srcStream, string argName)
        { 
            long startPosition = srcStream.Position;
            IntPtr umBufferHead = IntPtr.Zero; 
            NativeBuffer retBuffer = new NativeBuffer(IntPtr.Zero, 0); 

            try 
            {
                int bytesRead = 0;
                int bytesWritten = 0;
                byte[] srcBytes = new byte[BLOCK_TRANSFER_SIZE]; 

                // MemoryStream supports seeking, so we can know its Length directly 
                // and allocate the full unmanaged buffer up-front 
                int srcLength = (int)srcStream.Length;
 
                umBufferHead = Marshal.AllocCoTaskMem(srcLength);
                IntPtr umBufferCur = umBufferHead;
                int bytesRemain = srcLength;
 
                do
                { 
                    // Read block by block from source stream into the srcBytes 
                    // working buffer array, and then copy into the unmanaged buffer
                    bytesRead = srcStream.Read(srcBytes, 
                                               0,
                                               srcBytes.Length);

                    if ((bytesRead <= 0) || 
                        (bytesRead > srcBytes.Length) ||
                        (bytesRead > bytesRemain)) 
                    { 
                        break;
                    } 

                    Marshal.Copy(srcBytes, 0, umBufferCur, bytesRead);

                    // The sum of bytesWritten and bytesRemain should always be srcLength, 
                    // and bytesRead here always have a positive value.
                    bytesWritten += bytesRead; 
                    bytesRemain -= bytesRead; 

                    if (bytesWritten < srcLength) 
                    {
                        // We have more data to copy, so advance the unmanaged buffer cursor
                        umBufferCur = new IntPtr(umBufferCur.ToInt64() + bytesRead);
                    } 
                } while (true);
 
                // Verify we have written all the bytes from srcStream 
                if (bytesWritten != srcLength)
                { 
                    bytesWritten = 0;

                    throw new ArgumentException(String.Format(CultureInfo.CurrentCulture,
                                                PTUtility.GetTextFromResource("PrintConfig.Provider.PTStreamContentFail"), 
                                                PrintSchemaTags.Framework.PrintTicketRoot),
                                                argName); 
                } 

                // Packing succeeded, so instantiate the NativeBuffer object to return 
                retBuffer = new NativeBuffer(umBufferHead, bytesWritten);
            }
            finally
            { 
                // Restore srcStream's current position
                srcStream.Position = startPosition; 
 
                // If we failed somewhere in this function, but umBufferHead is allocated, we need to free it here.
                if ((retBuffer.data == IntPtr.Zero) && (umBufferHead != IntPtr.Zero)) 
                {
                    Marshal.FreeCoTaskMem(umBufferHead);
                    umBufferHead = IntPtr.Zero;
                } 
            }
 
            return retBuffer; 
        }
 
        /// 
        /// Copies the native buffer data to the returned managed memory stream
        /// 
        ///  
        /// Throws anything that Stream.Write can throw. Does not free the native buffer.
        /// The output stream is reset to the beginning of the stream at return time. 
        ///  
        /// buffer that contains native data
        /// size of umBuffer buffer 
        ///
        /// Critical    - the method copies unmanaged memory content into a managed stream object
        ///
        [SecurityCritical] 
        private static MemoryStream CopyNativeBufferToStream(IntPtr umBuffer, int bufferSize)
        { 
            byte[] byteData = new byte[bufferSize]; 

            // copy native buffer data to managed byte array 
            Marshal.Copy(umBuffer, byteData, 0, bufferSize);

            // create a new non-resizable memory stream based on the managed byte array
            MemoryStream outStream = new MemoryStream(byteData); 

            // reset output stream position to the beginning 
            outStream.Seek(0, SeekOrigin.Begin); 

            return outStream; 
        }

        #endregion Private Methods
 
        #region Private Fields
 
        ///  
        /// name of printer device this provider instance is bound to
        ///  
        private string _deviceName;

        /// 
        /// handle of unmanaged provider this provider instance is bound to 
        /// 
        private SafePTProviderHandle _providerHandle; 
 
        /// 
        /// major schema version this provider instance is using 
        /// 
        private int _schemaVersion;

        ///  
        /// boolean of whether or not this instance is disposed
        ///  
        private bool _disposed; 

        ///  
        /// size of block buffer to use when transferring between managed bytes and unmanaged bytes
        /// 
        /// 
        /// Modifying this could slightly improve performance. 
        /// 
        private const int BLOCK_TRANSFER_SIZE = 0x1000; 
 
        #endregion Private Fields
 
        // No need to implement the finalizer since we are using SafeHandle to wrap the unmanaged resource.

        #region IDisposable Members
 
        public void Dispose()
        { 
            Dispose(true); 
        }
 
        ///
        /// Critical    - calls into SafeHandle Dispose() method to release unmanaged handle
        /// TreatAsSafe - the class constructor demands DefaultPrinting to run (not granted in Internet Zone)
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        protected virtual void Dispose(bool disposing) 
        { 
            if (!this._disposed)
            { 
                if (disposing)
                {
                    // If disposing is explicitly called by client, free managed resources
                    _deviceName = null; 
                }
 
                // Free unmanaged resources 
                // SafeHandle's Dispose() will call subclass's ReleaseHandle() and set _isClosed to TRUE,
                // but it won't set the protected handle field to be NULL. 
                if (_providerHandle != null)
                {
                    _providerHandle.Dispose();
                    _providerHandle = null; 
                }
 
                this._disposed = true; 
            }
        } 

        #endregion
    }
 
    #endregion PTProvider class
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK