// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
//
//
// Abstract:
//
// This file contains Adapters that wrap the PrinterExtension COM Interop types.
//
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Runtime;
using System.Runtime.InteropServices;
using Microsoft.Samples.Printing.PrinterExtension.Types;
namespace Microsoft.Samples.Printing.PrinterExtension
{
// The following three classes are constructable adapters for the root of the
// object model. The balance of the types will typically be interfaces. This
// choice was made so we can share the interface file between projects and enforce
// the same public surface from both the "Reference" and "Implementation" projects.
#region PrinterExtension adapter classes
///
/// Wraps an COM pointer to IPrinterExtensionContext
///
public class PrinterExtensionContext : IPrinterExtensionContext
{
///
/// Wraps an opaque COM pointer to IPrinterExtensionContext and provides usable methods
///
/// Opaque COM pointer to IPrinterExtensionContext
public PrinterExtensionContext(Object comContext)
{
_context = (PrinterExtensionLib.IPrinterExtensionContext)comContext;
}
#region IPrinterExtensionContext methods
///
/// Maps to COM IPrinterExtensionContext::PrinterQueue
///
public IPrinterQueue Queue
{
get { return new PrinterQueue(_context.PrinterQueue); }
}
///
/// Maps to COM IPrinterExtensionContext::PrintSchemaTicket
///
public IPrintSchemaTicket Ticket
{
get { return new PrintSchemaTicket(_context.PrintSchemaTicket); }
}
///
/// Maps to COM IPrinterExtensionContext::DriverProperties
///
public IPrinterPropertyBag DriverProperties
{
get
{
try
{
return new PrinterPropertyBag(_context.DriverProperties, PrintPropertyBagType.DriverProperties);
}
catch (Exception)
{
// If the property bag is not found, instead of
// throwing an exception, return null, which is more appropriate for a property 'get' operation.
return null;
}
}
}
///
/// Maps to COM IPrinterExtensionContext::UserProperties
///
public IPrinterPropertyBag UserProperties
{
get { return new PrinterPropertyBag(_context.UserProperties, PrintPropertyBagType.UserProperties); }
}
#endregion
#region Implementation details
private PrinterExtensionLib.IPrinterExtensionContext _context;
// Prevent default construction
private PrinterExtensionContext()
{
}
#endregion
}
///
/// Wraps an COM pointer to IPrinterExtensionEventArgs
///
public class PrinterExtensionEventArgs : EventArgs, IPrinterExtensionEventArgs
{
///
/// Wraps an opaque COM pointer to IPrinterExtensionEventArgs and provides usable methods
///
/// Opaque COM pointer to IPrinterExtensionEventArgs
public PrinterExtensionEventArgs(Object eventArgs)
{
_eventArgs = (PrinterExtensionLib.IPrinterExtensionEventArgs)eventArgs;
_context = new PrinterExtensionContext(eventArgs);
}
#region IPrinterExtensionEventArgs methods
///
/// Maps to COM IPrinterExtensionEventArgs::BidiNotification
///
public string BidiNotification
{
get { return _eventArgs.BidiNotification; }
}
///
/// Maps to COM IPrinterExtensionEventArgs::ReasonId
///
public Guid ReasonId
{
get { return _eventArgs.ReasonId; }
}
///
/// Maps to COM IPrinterExtensionEventArgs::Request
///
public IPrinterExtensionRequest Request
{
get { return new PrinterExtensionRequest(_eventArgs.Request); }
}
///
/// Maps to COM IPrinterExtensionEventArgs::SourceApplication
///
public string SourceApplication
{
get { return _eventArgs.SourceApplication; }
}
///
/// Maps to COM IPrinterExtensionEventArgs::DetailedReasonId
///
public Guid DetailedReasonId
{
get { return _eventArgs.DetailedReasonId; }
}
///
/// Maps to COM IPrinterExtensionEventArgs::WindowModal
///
public bool WindowModal
{
get
{
if (_eventArgs.WindowModal != 0)
{
return true;
}
return false;
}
}
///
/// Maps to COM IPrinterExtensionEventArgs::WindowParent
///
public IntPtr WindowParent
{
get { return _eventArgs.WindowParent; }
}
#endregion
#region IPrinterExtensionContext methods
///
/// Maps to COM IPrinterExtensionContext::PrinterQueue
///
public IPrinterQueue Queue
{
get { return _context.Queue; }
}
///
/// Maps to COM IPrinterExtensionContext::PrintSchemaTicket
///
public IPrintSchemaTicket Ticket
{
get { return _context.Ticket; }
}
///
/// Maps to COM IPrinterExtensionContext::DriverProperties
///
public IPrinterPropertyBag DriverProperties
{
get { return _context.DriverProperties; }
}
///
/// Maps to COM IPrinterExtensionContext::UserProperties
///
public IPrinterPropertyBag UserProperties
{
get { return _context.UserProperties; }
}
#endregion
#region Implementation details
private PrinterExtensionLib.IPrinterExtensionEventArgs _eventArgs;
///
/// Containment - since multiple inheritance is not possible in C#.
///
private PrinterExtensionContext _context;
#endregion
}
///
/// This class provides wraps IPrinterExtensionContextCollection in a IEnumerable interface
///
public sealed class PrinterQueuesEnumeratedEventArgs : EventArgs, IEnumerable
{
#region IEnumerable methods
public IEnumerator GetEnumerator()
{
for (uint i = 0; i < _contextCollection.Count; i++)
{
yield return new PrinterExtensionContext(_contextCollection.GetAt(i));
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
#endregion
#region Implementation details
internal PrinterQueuesEnumeratedEventArgs(PrinterExtensionLib.IPrinterExtensionContextCollection contextCollection)
{
_contextCollection = contextCollection;
}
private PrinterExtensionLib.IPrinterExtensionContextCollection _contextCollection;
#endregion
}
#if WINDOWS_81_APIS
internal sealed class PrinterExtensionAsyncOperation : IPrinterExtensionAsyncOperation
{
#region IPrinterExtensionAsyncOperation methods
public void Cancel()
{
_asyncOperation.Cancel();
}
#endregion
#region Implementation methods
internal PrinterExtensionAsyncOperation(PrinterExtensionLib.IPrinterExtensionAsyncOperation asyncOperation)
{
_asyncOperation = asyncOperation;
}
private PrinterExtensionLib.IPrinterExtensionAsyncOperation _asyncOperation;
#endregion
}
#endif
#endregion
#region COM Adapter Classes
//
// The following class provide an adapter that exposes a 'Stream' and wraps a
// COM pointer to PrinterExtensionLib.IStream
//
internal class PrinterExtensionLibIStreamAdapter : Stream, IDisposable
{
public PrinterExtensionLibIStreamAdapter(PrinterExtensionLib.IStream stream, bool canWrite = false, bool canSeek = false, bool canRead = true)
{
if (stream != null)
{
_printerExtensionIStream = stream;
}
else
{
throw new ArgumentNullException("stream");
}
_streamValidation = new StreamValidation(canWrite, canSeek, canRead);
}
~PrinterExtensionLibIStreamAdapter()
{
Dispose(false);
}
#region Overridden Stream methods
public override int Read(byte[] buffer, int offset, int count)
{
_streamValidation.ValidateRead(buffer, offset, count);
uint bytesRead = 0;
// Pin the byte array so that it will not be moved by the garbage collector
byte[] tempBuffer = new byte[count];
GCHandle gcHandle = GCHandle.Alloc(tempBuffer, GCHandleType.Pinned);
try
{
_printerExtensionIStream.RemoteRead(out tempBuffer[0], Convert.ToUInt32(count), out bytesRead);
Array.Copy(tempBuffer, 0, buffer, offset, (int)bytesRead); // Safe to cast. Cannot be bigger than 'int count'
}
finally
{
gcHandle.Free();
}
return (int)bytesRead; // Safe to cast; bytesRead can never be larger than 'int count'
}
public override void Write(byte[] buffer, int offset, int count)
{
_streamValidation.ValidateWrite(buffer, offset, count);
uint written;
// Pin the byte array so that it will not be moved by the garbage collector
byte[] tempBuffer = new byte[count];
GCHandle gcHandle = GCHandle.Alloc(tempBuffer, GCHandleType.Pinned);
try
{
Array.Copy(buffer, offset, tempBuffer, 0, count);
_printerExtensionIStream.RemoteWrite(ref tempBuffer[0], Convert.ToUInt32(count), out written);
}
finally
{
gcHandle.Free();
}
if ((int)written < count)
{
throw new IOException();
}
}
public override long Seek(long offset, SeekOrigin origin)
{
_streamValidation.ValidateSeek(offset, origin);
uint istreamSeekOrigin = 0;
switch (origin)
{
case SeekOrigin.Begin:
istreamSeekOrigin = (uint)PrinterExtensionLib.tagSTREAM_SEEK.STREAM_SEEK_SET;
break;
case SeekOrigin.Current:
istreamSeekOrigin = (uint)PrinterExtensionLib.tagSTREAM_SEEK.STREAM_SEEK_CUR;
break;
case SeekOrigin.End:
istreamSeekOrigin = (uint)PrinterExtensionLib.tagSTREAM_SEEK.STREAM_SEEK_END;
break;
}
PrinterExtensionLib._LARGE_INTEGER dlibMove;
PrinterExtensionLib._ULARGE_INTEGER plibNewPosition;
dlibMove.QuadPart = offset;
_printerExtensionIStream.RemoteSeek(dlibMove, istreamSeekOrigin, out plibNewPosition);
return Convert.ToInt64(plibNewPosition.QuadPart);
}
public override long Length
{
get
{
_streamValidation.ValidateSeek();
PrinterExtensionLib.tagSTATSTG statstg;
_printerExtensionIStream.Stat(out statstg, 1 /* STATSFLAG_NONAME*/ );
return Convert.ToInt64(statstg.cbSize.QuadPart);
}
}
public override long Position
{
get { return Seek(0, SeekOrigin.Current); }
set { Seek(value, SeekOrigin.Begin); }
}
public override void SetLength(long value)
{
_streamValidation.ValidateSeek();
PrinterExtensionLib._ULARGE_INTEGER libNewSize;
libNewSize.QuadPart = Convert.ToUInt64(value);
_printerExtensionIStream.SetSize(libNewSize);
}
public override void Flush()
{
_printerExtensionIStream.Commit(0);
}
public override bool CanRead
{
get { return _streamValidation.CanRead; }
}
public override bool CanWrite
{
get { return _streamValidation.CanWrite; }
}
public override bool CanSeek
{
get { return _streamValidation.CanSeek; }
}
#endregion
#region IDisposable methods
protected override void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
try
{
if (disposing)
{
_streamValidation.Dispose();
}
if (_printerExtensionIStream != null)
{
Marshal.ReleaseComObject(_printerExtensionIStream);
_printerExtensionIStream = null;
}
}
finally
{
base.Dispose(disposing);
}
_disposed = true;
}
#endregion
#region Implementation details
// Prevent default construction
private PrinterExtensionLibIStreamAdapter() { }
private bool _disposed = false;
private PrinterExtensionLib.IStream _printerExtensionIStream = null;
private StreamValidation _streamValidation = null;
#endregion
}
//
// The following class provide an adapter that exposes a 'Stream' and wraps a
// COM pointer to the standard COM 'IStream' interface
//
internal class ComIStreamAdapter : Stream, IDisposable
{
public ComIStreamAdapter(System.Runtime.InteropServices.ComTypes.IStream stream, bool canWrite = false, bool canSeek = false, bool canRead = true)
{
if (stream != null)
{
_comIstream = stream;
}
else
{
throw new ArgumentNullException("stream");
}
_streamValidation = new StreamValidation(canWrite, canSeek, canRead);
}
~ComIStreamAdapter()
{
Dispose(false);
}
#region Overridden Stream methods
public override int Read(byte[] buffer, int offset, int count)
{
_streamValidation.ValidateRead(buffer, offset, count);
uint bytesRead = 0;
// Pin the byte array so that it will not be moved by the garbage collector
byte[] tempBuffer = new byte[count];
GCHandle gcHandle = GCHandle.Alloc(tempBuffer, GCHandleType.Pinned);
IntPtr bytesReadPtr = Marshal.AllocHGlobal(sizeof(int));
try
{
_comIstream.Read(tempBuffer, count, bytesReadPtr);
bytesRead = (uint)Marshal.ReadInt32(bytesReadPtr);
Array.Copy(tempBuffer, 0, buffer, offset, (int)bytesRead); // Safe to cast. Cannot be bigger than 'int count'
}
finally
{
Marshal.FreeHGlobal(bytesReadPtr);
gcHandle.Free();
}
return (int)bytesRead; // Safe to cast; bytesRead can never be larger than 'int count'
}
public override void Write(byte[] buffer, int offset, int count)
{
_streamValidation.ValidateWrite(buffer, offset, count);
uint written;
// Pin the byte array so that it will not be moved by the garbage collector
byte[] tempBuffer = new byte[count];
GCHandle gcHandle = GCHandle.Alloc(tempBuffer, GCHandleType.Pinned);
IntPtr writeCountPointer = Marshal.AllocHGlobal(sizeof(int));
try
{
Array.Copy(buffer, offset, tempBuffer, 0, count);
_comIstream.Write(tempBuffer, count, writeCountPointer);
written = (uint)Marshal.ReadInt32(writeCountPointer); // safe to cast. 'written' is always non-negative
}
finally
{
gcHandle.Free();
Marshal.FreeHGlobal(writeCountPointer);
}
if ((int)written < count)
{
throw new IOException();
}
}
public override long Seek(long offset, SeekOrigin origin)
{
_streamValidation.ValidateSeek(offset, origin);
uint istreamSeekOrigin = 0;
switch (origin)
{
case SeekOrigin.Begin:
istreamSeekOrigin = (uint)PrinterExtensionLib.tagSTREAM_SEEK.STREAM_SEEK_SET;
break;
case SeekOrigin.Current:
istreamSeekOrigin = (uint)PrinterExtensionLib.tagSTREAM_SEEK.STREAM_SEEK_CUR;
break;
case SeekOrigin.End:
istreamSeekOrigin = (uint)PrinterExtensionLib.tagSTREAM_SEEK.STREAM_SEEK_END;
break;
}
IntPtr seekPositionPointer = Marshal.AllocHGlobal(sizeof(long));
long seekPosition = 0;
try
{
_comIstream.Seek(offset, (int)istreamSeekOrigin, seekPositionPointer);
seekPosition = Marshal.ReadInt64(seekPositionPointer);
}
finally
{
Marshal.FreeHGlobal(seekPositionPointer);
}
return seekPosition;
}
public override long Length
{
get
{
_streamValidation.ValidateSeek();
System.Runtime.InteropServices.ComTypes.STATSTG statstg;
_comIstream.Stat(out statstg, 1 /* STATSFLAG_NONAME*/ );
return statstg.cbSize;
}
}
public override long Position
{
get { return Seek(0, SeekOrigin.Current); }
set { Seek(value, SeekOrigin.Begin); }
}
public override void SetLength(long value)
{
_streamValidation.ValidateSeek();
_comIstream.SetSize(value);
}
public override void Flush()
{
_comIstream.Commit(0);
}
public override bool CanRead
{
get { return _streamValidation.CanRead; }
}
public override bool CanWrite
{
get { return _streamValidation.CanWrite; }
}
public override bool CanSeek
{
get { return _streamValidation.CanSeek; }
}
#endregion
#region IDisposable methods
protected override void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
try
{
if (disposing)
{
_streamValidation.Dispose();
}
if (_comIstream != null)
{
Marshal.ReleaseComObject(_comIstream);
_comIstream = null;
}
}
finally
{
base.Dispose(disposing);
}
_disposed = true;
}
#endregion
#region Implementation details
// Prevent default construction
private ComIStreamAdapter() { }
private bool _disposed = false;
private System.Runtime.InteropServices.ComTypes.IStream _comIstream = null;
private StreamValidation _streamValidation = null;
#endregion
}
internal class StreamValidation : IDisposable
{
internal StreamValidation(bool canWrite = false, bool canSeek = false, bool canRead = true)
{
_canWrite = canWrite;
_canSeek = canSeek;
_canRead = canRead;
}
internal void ValidateRead(byte[] buffer, int offset, int count)
{
if (!_canRead)
{
throw new NotSupportedException();
}
if (_disposed == true)
{
throw new ObjectDisposedException("COM IStream");
}
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
if (offset < 0)
{
throw new ArgumentOutOfRangeException("offset");
}
if (count < 0)
{
throw new ArgumentOutOfRangeException("count");
}
if ((buffer.Length - offset) < count)
{
throw new ArgumentException();
}
}
internal void ValidateWrite(byte[] buffer, int offset, int count)
{
if (!_canWrite)
{
throw new NotSupportedException();
}
if (_disposed == true)
{
throw new ObjectDisposedException("COM IStream");
}
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
if (offset < 0)
{
throw new ArgumentOutOfRangeException("offset");
}
if (count < 0)
{
throw new ArgumentOutOfRangeException("count");
}
if ((buffer.Length - offset) < count)
{
throw new ArgumentException("Insufficient buffer size");
}
}
internal void ValidateSeek(long offset, SeekOrigin origin)
{
ValidateSeek();
if ((origin < SeekOrigin.Begin) || (origin > SeekOrigin.End))
{
throw new ArgumentException("Invalid value", "origin");
}
}
internal void ValidateSeek()
{
if (!_canSeek)
{
throw new NotSupportedException();
}
if (_disposed == true)
{
throw new ObjectDisposedException("COM IStream");
}
}
public bool CanRead
{
get { return _canRead; }
}
public bool CanWrite
{
get { return _canWrite; }
}
public bool CanSeek
{
get { return _canSeek; }
}
#region IDisposable methods
public void Dispose()
{
_disposed = true;
}
#endregion
#region Implementation details
private bool _disposed = false;
private bool _canWrite = false;
private bool _canSeek = false;
private bool _canRead = true;
#endregion
}
#endregion
#region PrintSchema Adapter Classes
//
// Following are concrete implementation of the PrinterExtension interfaces
// These classes wrap the underlying COM interfaces.
//
internal class PrintSchemaOption : IPrintSchemaOption
{
#region IPrintSchemaOption methods
public bool Selected
{
get { return (0 == _option.Selected) ? false : true; }
}
public PrintSchemaConstrainedSetting Constrained
{
get { return (PrintSchemaConstrainedSetting)_option.Constrained; }
}
#endregion
#region IPrintSchemaDisplayableElement methods
public string DisplayName { get { return _option.DisplayName; } }
public string Name { get { return _option.Name; } }
public string XmlNamespace { get { return _option.NamespaceUri; } }
#endregion
#region Implementation details
internal PrintSchemaOption(PrinterExtensionLib.IPrintSchemaOption option)
{
_option = option;
}
internal PrinterExtensionLib.IPrintSchemaOption InteropOption
{
get { return _option; }
set { _option = value; }
}
//
// Create the correct 'PrintSchemaOption' subclass, possibly exposing one of the these interfaces
// 1. IPrintSchemaPageMediaSizeOption
// 2. IPrintSchemaNUpOption
//
internal static IPrintSchemaOption CreateOptionSubclass(PrinterExtensionLib.IPrintSchemaOption option)
{
// IPrintSchemaNUpOption option
if (option is PrinterExtensionLib.IPrintSchemaNUpOption)
{
return new PrintSchemaNUpOption(option);
}
// IPrintSchemaPageMediaSizeOption option
if (option is PrinterExtensionLib.IPrintSchemaPageMediaSizeOption)
{
return new PrintSchemaPageMediaSizeOption(option);
}
return new PrintSchemaOption(option);
}
internal PrinterExtensionLib.IPrintSchemaOption _option;
// Prevent default constuction
private PrintSchemaOption() { }
#endregion
}
internal sealed class PrintSchemaPageMediaSizeOption : PrintSchemaOption, IPrintSchemaPageMediaSizeOption
{
#region IPrintSchemaPageMediaSizeOption methods
public uint HeightInMicrons
{
get { return _pageMediaSizeOption.HeightInMicrons; }
}
public uint WidthInMicrons
{
get { return _pageMediaSizeOption.WidthInMicrons; }
}
#endregion
#region Implementation details
internal PrintSchemaPageMediaSizeOption(PrinterExtensionLib.IPrintSchemaOption option)
: base(option)
{
_pageMediaSizeOption = _option as PrinterExtensionLib.IPrintSchemaPageMediaSizeOption;
if (null == _pageMediaSizeOption)
{
throw new NotImplementedException("Could not retrieve IPrintSchemaPageMediaSizeOption interface.");
}
}
private PrinterExtensionLib.IPrintSchemaPageMediaSizeOption _pageMediaSizeOption;
#endregion
}
internal sealed class PrintSchemaNUpOption : PrintSchemaOption, IPrintSchemaNUpOption
{
#region IPrintSchemaNUpOption methods
public uint PagesPerSheet
{
get { return _nupOption.PagesPerSheet; }
}
#endregion
#region Implementation details
internal PrintSchemaNUpOption(PrinterExtensionLib.IPrintSchemaOption option) :
base(option)
{
_nupOption = _option as PrinterExtensionLib.IPrintSchemaNUpOption;
if (null == _nupOption)
{
throw new NotImplementedException("Could not retrieve IPrintSchemaNUpOption interface.");
}
}
private PrinterExtensionLib.IPrintSchemaNUpOption _nupOption;
#endregion
}
///
/// This class provides wraps IPrintSchemaOptionCollection in a IEnumerable interface
///
internal sealed class PrintSchemaOptionsCollection : IEnumerable
{
#region IEnumerable methods
public IEnumerator GetEnumerator()
{
for (uint i = 0; i < _optionCollection.Count; i++)
{
yield return new PrintSchemaOption(_optionCollection.GetAt(i));
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
#endregion
#region Implementation details
internal PrintSchemaOptionsCollection(PrinterExtensionLib.IPrintSchemaOptionCollection optionCollection)
{
_optionCollection = optionCollection;
}
private PrinterExtensionLib.IPrintSchemaOptionCollection _optionCollection;
#endregion
}
internal sealed class PrintSchemaFeature : IPrintSchemaFeature
{
#region IPrintSchemaFeature methods
public PrintSchemaSelectionType SelectionType
{
get { return (PrintSchemaSelectionType)_feature.SelectionType; }
}
public IPrintSchemaOption GetOption(string name)
{
return GetOption(name, PrintSchemaConstants.KeywordsNamespaceUri);
}
public IPrintSchemaOption GetOption(string name, string xmlNamespace)
{
PrinterExtensionLib.IPrintSchemaOption option = _feature.GetOption(name, xmlNamespace);
if (option != null)
{
return PrintSchemaOption.CreateOptionSubclass(option);
}
return null;
}
public IPrintSchemaOption SelectedOption
{
get
{
return PrintSchemaOption.CreateOptionSubclass(_feature.SelectedOption);
}
set
{
_feature.SelectedOption = (value as PrintSchemaOption).InteropOption;
}
}
public bool DisplayUI
{
get
{
return (0 == _feature.DisplayUI) ? false : true;
}
}
#endregion
#region IPrintSchemaDisplayableElement methods
public string DisplayName { get { return _feature.DisplayName; } }
public string Name { get { return _feature.Name; } }
public string XmlNamespace { get { return _feature.NamespaceUri; } }
#endregion
#region Implementation details
internal PrintSchemaFeature(PrinterExtensionLib.IPrintSchemaFeature feature)
{
_feature = feature;
}
internal PrinterExtensionLib.IPrintSchemaFeature InteropFeature
{
get { return _feature; }
}
private PrinterExtensionLib.IPrintSchemaFeature _feature;
#endregion
}
internal sealed class PrintSchemaPageImageableSize : IPrintSchemaPageImageableSize
{
#region IPrintSchemaPageImageableSize methods
public uint ExtentHeightInMicrons
{
get { return _pageImageableSize.ExtentHeightInMicrons; }
}
public uint ExtentWidthInMicrons
{
get { return _pageImageableSize.ExtentWidthInMicrons; }
}
public uint ImageableSizeHeightInMicrons
{
get { return _pageImageableSize.ImageableSizeHeightInMicrons; }
}
public uint ImageableSizeWidthInMicrons
{
get { return _pageImageableSize.ImageableSizeWidthInMicrons; }
}
public uint OriginHeightInMicrons
{
get { return _pageImageableSize.OriginHeightInMicrons; }
}
public uint OriginWidthInMicrons
{
get { return _pageImageableSize.OriginWidthInMicrons; }
}
#endregion
#region IPrintSchemaElement methods
public string Name { get { return _pageImageableSize.Name; } }
public string XmlNamespace { get { return _pageImageableSize.NamespaceUri; } }
#endregion
#region Implementation details
internal PrintSchemaPageImageableSize(PrinterExtensionLib.IPrintSchemaPageImageableSize pageImageableSize)
{
_pageImageableSize = pageImageableSize;
}
private PrinterExtensionLib.IPrintSchemaPageImageableSize _pageImageableSize;
#endregion
}
#if WINDOWS_81_APIS
internal sealed class PrintSchemaParameterDefinition : IPrintSchemaParameterDefinition
{
#region IPrintSchemaParameterDefinition methods
public bool UserInputRequired
{
get
{
if (_parameter.UserInputRequired != 0)
{
return true;
}
return false;
}
}
public string UnitType
{
get { return _parameter.UnitType; }
}
public PrintSchemaParameterDataType DataType
{
get { return (PrintSchemaParameterDataType)_parameter.DataType; }
}
public int RangeMin
{
get { return _parameter.RangeMin; }
}
public int RangeMax
{
get { return _parameter.RangeMax; }
}
#endregion
#region IPrintSchemaDisplayableItem methods
public string DisplayName { get { return _parameter.DisplayName; } }
public string Name { get { return _parameter.Name; } }
public string XmlNamespace { get { return _parameter.NamespaceUri; } }
#endregion
#region Implementation details
internal PrintSchemaParameterDefinition(PrinterExtensionLib.IPrintSchemaParameterDefinition parameter)
{
_parameter = parameter;
}
private PrinterExtensionLib.IPrintSchemaParameterDefinition _parameter;
#endregion
}
internal sealed class PrintSchemaParameterInitializer : IPrintSchemaParameterInitializer
{
#region IPrintSchemaParameterInitializer methods
public string StringValue
{
get
{
object value = _parameter.get_Value();
return (string)value;
}
set
{
_parameter.set_Value(value);
}
}
public int IntegerValue
{
get
{
object value = _parameter.get_Value();
return (int)value;
}
set
{
_parameter.set_Value(value);
}
}
#endregion
#region IPrintSchemaElement methods
public string Name { get { return _parameter.Name; } }
public string XmlNamespace { get { return _parameter.NamespaceUri; } }
#endregion
#region Implementation details
internal PrintSchemaParameterInitializer(PrinterExtensionLib.IPrintSchemaParameterInitializer parameter)
{
_parameter = parameter;
}
PrinterExtensionLib.IPrintSchemaParameterInitializer _parameter;
#endregion
}
#endif
internal sealed class PrintSchemaCapabilities : IPrintSchemaCapabilities
{
#region IPrintSchemaCapabilities methods
public IPrintSchemaFeature GetFeatureByKeyName(string keyName)
{
PrinterExtensionLib.IPrintSchemaFeature feature = _capabilities.GetFeatureByKeyName(keyName);
if (feature != null)
{
return new PrintSchemaFeature(feature);
}
return null;
}
public IPrintSchemaFeature GetFeature(string featureName)
{
return GetFeature(featureName, PrintSchemaConstants.KeywordsNamespaceUri);
}
public IPrintSchemaFeature GetFeature(string featureName, string xmlNamespace)
{
PrinterExtensionLib.IPrintSchemaFeature feature = _capabilities.GetFeature(featureName, xmlNamespace);
if (feature != null)
{
return new PrintSchemaFeature(feature);
}
return null;
}
public IPrintSchemaPageImageableSize PageImageableSize
{
get { return new PrintSchemaPageImageableSize(_capabilities.PageImageableSize); }
}
public uint JobCopiesAllDocumentsMaxValue
{
get
{
uint value = _capabilities.JobCopiesAllDocumentsMaxValue;
if (value == 0)
{
throw new NotSupportedException("Property \"JobCopiesAllDocumentsMaxValue\" not found in print capabilities.");
}
return value;
}
}
public uint JobCopiesAllDocumentsMinValue
{
get
{
uint value = _capabilities.JobCopiesAllDocumentsMinValue;
if (value == 0)
{
throw new NotSupportedException("Property \"JobCopiesAllDocumentsMinValue\" not found in print capabilities.");
}
return value;
}
}
public IPrintSchemaOption GetSelectedOptionInPrintTicket(IPrintSchemaFeature feature)
{
PrintSchemaFeature f = feature as PrintSchemaFeature;
PrinterExtensionLib.IPrintSchemaOption option = _capabilities.GetSelectedOptionInPrintTicket(f.InteropFeature);
if (option != null)
{
return PrintSchemaOption.CreateOptionSubclass(option);
}
return null;
}
public IEnumerable GetOptions(IPrintSchemaFeature pFeature)
{
return new PrintSchemaOptionsCollection(
_capabilities.GetOptions(
(pFeature as PrintSchemaFeature).InteropFeature)
);
}
public Stream GetReadStream()
{
return new ComIStreamAdapter(XmlStream,
false, // canWrite
true, // canSeek
true // canRead
);
}
public Stream GetWriteStream()
{
return new ComIStreamAdapter(XmlStream,
true, // canWrite
true, // canSeek
false // canRead
);
}
#if WINDOWS_81_APIS
public IPrintSchemaParameterDefinition GetParameterDefinition(string parameterName)
{
return GetParameterDefinition(parameterName, PrintSchemaConstants.KeywordsNamespaceUri);
}
public IPrintSchemaParameterDefinition GetParameterDefinition(string parameterName, string xmlNamespace)
{
PrinterExtensionLib.IPrintSchemaParameterDefinition parameter = _capabilities2.GetParameterDefinition(parameterName, xmlNamespace);
if (parameter != null)
{
return new PrintSchemaParameterDefinition(parameter);
}
return null;
}
#endif
private System.Runtime.InteropServices.ComTypes.IStream XmlStream
{
get
{
System.Runtime.InteropServices.ComTypes.IStream istream = _capabilities.XmlNode as System.Runtime.InteropServices.ComTypes.IStream;
return istream;
}
}
#endregion
#region Implementation details
internal PrintSchemaCapabilities(PrinterExtensionLib.IPrintSchemaCapabilities caps)
{
_capabilities = caps;
#if WINDOWS_81_APIS
_capabilities2 = (PrinterExtensionLib.IPrintSchemaCapabilities2)caps;
#endif
}
private PrinterExtensionLib.IPrintSchemaCapabilities _capabilities;
#if WINDOWS_81_APIS
private PrinterExtensionLib.IPrintSchemaCapabilities2 _capabilities2;
#endif
#endregion
}
internal class PrintSchemaAsyncOperation : IPrintSchemaAsyncOperation
{
#region IPrintSchemaAsyncOperation methods
public void Cancel()
{
_asyncOperation.Cancel();
}
public void Start()
{
_asyncOperation.Start();
}
public event EventHandler Completed;
#endregion
#region Implementation details
internal PrintSchemaAsyncOperation(PrinterExtensionLib.PrintSchemaAsyncOperation asyncOperation)
{
_asyncOperation = asyncOperation;
_asyncOperation.Completed += _asyncOperation_Completed;
}
void _asyncOperation_Completed(PrinterExtensionLib.IPrintSchemaTicket printTicket, int hrOperation)
{
if (Completed != null)
{
IPrintSchemaTicket ticket = new PrintSchemaTicket(printTicket);
Completed(this, new PrintSchemaAsyncOperationEventArgs(ticket, hrOperation));
}
// This subscriber object (current object) holds a reference to the publishing object (i.e the underlying COM object)
// because it is a class member, and the publishing object holds a reference to the subscriber via the registered delegate.
// This implies neither object will be garbage collected until the application terminates.
// It's expected the event is fired once per instance so unsubscribing the delegate has no side effects.
_asyncOperation.Completed -= _asyncOperation_Completed;
Marshal.ReleaseComObject(_asyncOperation);
_asyncOperation = null;
}
private PrinterExtensionLib.PrintSchemaAsyncOperation _asyncOperation;
#endregion
}
internal class PrintSchemaTicket : IPrintSchemaTicket
{
#region IPrintSchemaTicket methods
public IPrintSchemaCapabilities GetCapabilities()
{
return new PrintSchemaCapabilities(_printTicket.GetCapabilities());
}
public IPrintSchemaFeature GetFeature(string featureName)
{
return GetFeature(featureName, PrintSchemaConstants.KeywordsNamespaceUri);
}
public IPrintSchemaFeature GetFeature(string featureName, string xmlNamespace)
{
PrinterExtensionLib.IPrintSchemaFeature feature = _printTicket.GetFeature(featureName, xmlNamespace);
if (feature != null)
{
return new PrintSchemaFeature(feature);
}
return null;
}
public IPrintSchemaFeature GetFeatureByKeyName(string keyName)
{
PrinterExtensionLib.IPrintSchemaFeature feature = _printTicket.GetFeatureByKeyName(keyName);
if (feature != null)
{
return new PrintSchemaFeature(feature);
}
return null;
}
public uint JobCopiesAllDocuments
{
get
{
uint value = _printTicket.JobCopiesAllDocuments;
if (value == 0)
{
throw new NotSupportedException("Property \"JobCopiesAllDocuments\" not found in print ticket.");
}
return value;
}
set
{
_printTicket.JobCopiesAllDocuments = value;
}
}
public Stream GetReadStream()
{
return new ComIStreamAdapter(XmlStream,
false, // canWrite
true, // canSeek
true // canRead
);
}
public Stream GetWriteStream()
{
return new ComIStreamAdapter(XmlStream,
true, // canWrite
true, // canSeek
false // canRead
);
}
private System.Runtime.InteropServices.ComTypes.IStream XmlStream
{
get
{
System.Runtime.InteropServices.ComTypes.IStream istream = _printTicket.XmlNode as System.Runtime.InteropServices.ComTypes.IStream;
return istream;
}
}
public IPrintSchemaAsyncOperation ValidateAsync()
{
PrinterExtensionLib.PrintSchemaAsyncOperation interopAsyncOperation;
_printTicket.ValidateAsync(out interopAsyncOperation);
return new PrintSchemaAsyncOperation(interopAsyncOperation);
}
public IPrintSchemaAsyncOperation CommitAsync(IPrintSchemaTicket printTicketCommit)
{
PrinterExtensionLib.IPrintSchemaTicket interopTicket = (printTicketCommit as PrintSchemaTicket)._printTicket;
PrinterExtensionLib.PrintSchemaAsyncOperation interopAsyncOperation;
_printTicket.CommitAsync(interopTicket, out interopAsyncOperation);
return new PrintSchemaAsyncOperation(interopAsyncOperation);
}
public void NotifyXmlChanged()
{
_printTicket.NotifyXmlChanged();
}
#if WINDOWS_81_APIS
public IPrintSchemaParameterInitializer GetParameterInitializer(string parameterName)
{
return GetParameterInitializer(parameterName, PrintSchemaConstants.KeywordsNamespaceUri);
}
public IPrintSchemaParameterInitializer GetParameterInitializer(string parameterName, string xmlNamespace)
{
PrinterExtensionLib.IPrintSchemaParameterInitializer parameter = _printTicket2.GetParameterInitializer(parameterName, xmlNamespace);
if (parameter != null)
{
return new PrintSchemaParameterInitializer(parameter);
}
return null;
}
#endif
#endregion
#region Implementation details
internal PrintSchemaTicket(PrinterExtensionLib.IPrintSchemaTicket printTicket)
{
_printTicket = printTicket;
#if WINDOWS_81_APIS
_printTicket2 = (PrinterExtensionLib.IPrintSchemaTicket2)printTicket;
#endif
}
private PrinterExtensionLib.IPrintSchemaTicket _printTicket;
#if WINDOWS_81_APIS
private PrinterExtensionLib.IPrintSchemaTicket2 _printTicket2;
#endif
#endregion
}
internal enum PrintPropertyBagType
{
QueueProperties,
DriverProperties,
UserProperties
}
internal class PrinterPropertyBag : IPrinterPropertyBag
{
#region IPrinterPropertyBag methods
public bool GetBool(string propertyName)
{
try
{
int integerEquivalent = _bag.GetBool(propertyName);
bool boolEquivalent = true;
if (integerEquivalent == 0)
{
boolEquivalent = false;
}
return boolEquivalent;
}
catch (ArgumentException e)
{
// Fix the type of exception thrown when the property does not exist.
if (ShouldConvertExceptionType(e))
{
throw new FileNotFoundException("", e);
}
throw;
}
}
public byte[] GetBytes(string propertyName)
{
try
{
uint count = 0;
IntPtr intptrData = Marshal.AllocCoTaskMem(IntPtr.Size);
_bag.GetBytes(
propertyName,
out count,
intptrData);
byte[] data = new byte[count];
Marshal.Copy(Marshal.ReadIntPtr(intptrData), data, 0, (int)count);
Marshal.FreeCoTaskMem(Marshal.ReadIntPtr(intptrData));
Marshal.FreeCoTaskMem(intptrData);
return data;
}
catch (ArgumentException e)
{
// Fix the type of exception thrown when the property does not exist.
if (ShouldConvertExceptionType(e))
{
throw new FileNotFoundException("", e);
}
throw;
}
}
public int GetInt(string propertyName)
{
try
{
return _bag.GetInt32(propertyName);
}
catch (ArgumentException e)
{
// Fix the type of exception thrown when the property does not exist.
if (ShouldConvertExceptionType(e))
{
throw new FileNotFoundException("", e);
}
throw;
}
}
public string GetString(string propertyName)
{
try
{
return _bag.GetString(propertyName);
}
catch (ArgumentException e)
{
// Fix the type of exception thrown when the property does not exist.
if (ShouldConvertExceptionType(e))
{
throw new FileNotFoundException("", e);
}
throw;
}
}
public void SetBool(string propertyName, bool value)
{
int integerEquivalent = 1;
if (value == false)
{
integerEquivalent = 0;
}
_bag.SetBool(propertyName, integerEquivalent);
}
public void SetBytes(string propertyName, byte[] data)
{
// Pin the byte array so that it will not be moved by the garbage collector
// This would not be required if the COM Interop function took in a byte[] parameter
// as opposed to a byte parameter
GCHandle gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
_bag.SetBytes(propertyName, Convert.ToUInt32(data.Length), ref data[0]);
}
finally
{
gcHandle.Free();
}
}
public void SetInt(string propertyName, int value)
{
_bag.SetInt32(propertyName, value);
}
public void SetString(string propertyName, string value)
{
_bag.SetString(propertyName, value);
}
public Stream GetReadStream(string propertyName)
{
try
{
return new PrinterExtensionLibIStreamAdapter(_bag.GetReadStream(propertyName), false, true, true);
}
catch (COMException e)
{
// Fix the type of exception thrown when the property does not exist.
if (ShouldConvertExceptionType(e))
{
throw new FileNotFoundException("", e);
}
throw;
}
}
public Stream GetWriteStream(string propertyName)
{
return new PrinterExtensionLibIStreamAdapter(_bag.GetWriteStream(propertyName), true, true, false);
}
#endregion
#region Indexer
public PrinterProperty this[string name]
{
get { return new PrinterProperty(this, name); }
}
#endregion
#region Implementation details
internal PrinterPropertyBag(PrinterExtensionLib.IPrinterPropertyBag bag, PrintPropertyBagType type)
{
_bag = bag;
_type = type;
}
///
/// Check if exception thrown when a property is not found in a property bag needs to be converted.
///
///
/// True if the exception type needs to be converted.
private bool ShouldConvertExceptionType(Exception e)
{
// Only the driver property bag throws exceptions other than 'FileNotFoundException'
// when a property is not found.
if (_type != PrintPropertyBagType.DriverProperties)
{
return false;
}
else if (e is ArgumentException)
{
return true;
}
else if (e is COMException)
{
// Since there is no portable way to check the HRESULT across classic .Net and
// .Net for Windows Store apps, all COMExceptions encountered are converted.
return true;
}
return false;
}
private PrinterExtensionLib.IPrinterPropertyBag _bag;
private PrintPropertyBagType _type;
#endregion
}
#if WINDOWS_81_APIS
public sealed class PrintJob : IPrintJob
{
#region IPrintJob methods
public string Name
{
get { return _job.Name; }
}
public ulong Id
{
get { return _job.Id; }
}
public ulong PrintedPages
{
get { return _job.PrintedPages; }
}
public ulong TotalPages
{
get { return _job.TotalPages; }
}
public PrintJobStatus Status
{
get { return (PrintJobStatus)_job.Status; }
}
public DateTime SubmissionTime
{
get { return _job.SubmissionTime; }
}
public void RequestCancel()
{
_job.RequestCancel();
}
#endregion
#region Implementation details
internal PrintJob(PrinterExtensionLib.IPrintJob job)
{
_job = job;
}
PrinterExtensionLib.IPrintJob _job;
#endregion
}
///
/// This class provides wraps IPrintJobCollection in a IEnumerable interface
///
public sealed class PrintJobCollection : IEnumerable
{
#region IEnumerable methods
public IEnumerator GetEnumerator()
{
for (uint i = 0; i < _jobCollection.Count; i++)
{
yield return new PrintJob(_jobCollection.GetAt(i));
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
#endregion
#region Implementation details
internal PrintJobCollection(PrinterExtensionLib.IPrintJobCollection jobCollection)
{
_jobCollection = jobCollection;
}
private PrinterExtensionLib.IPrintJobCollection _jobCollection;
#endregion
}
internal sealed class PrinterQueueView : IPrinterQueueView
{
#region IPrinterQueueView methods
public void SetViewRange(uint viewOffset, uint viewSize)
{
_view.SetViewRange(viewOffset, viewSize);
}
public event EventHandler OnChanged
{
add
{
if (_onChanged == null)
{
_view.OnChanged += _view_OnChanged;
}
_onChanged += value;
}
remove
{
_onChanged -= value;
if (_onChanged == null)
{
_view.OnChanged -= _view_OnChanged;
}
}
}
#endregion
#region Implementation details
internal PrinterQueueView(PrinterExtensionLib.PrinterQueueView view)
{
_view = view;
}
void _view_OnChanged(PrinterExtensionLib.IPrintJobCollection pCollection, uint ulViewOffset, uint ulViewSize, uint ulCountJobsInPrintQueue)
{
if (_onChanged != null)
{
_onChanged(this, new PrinterQueueViewEventArgs(new PrintJobCollection(pCollection), ulViewOffset, ulViewSize, ulCountJobsInPrintQueue));
}
}
private PrinterExtensionLib.PrinterQueueView _view;
private event EventHandler _onChanged;
#endregion
}
internal sealed class PrinterBidiSetRequestCallback : PrinterExtensionLib.IPrinterBidiSetRequestCallback
{
#region IPrinterBidiSetRequestCallback methods
public void Completed(string response, int statusHResult)
{
_callback.Completed(response, statusHResult);
}
#endregion
#region Implementation details
internal PrinterBidiSetRequestCallback(IPrinterBidiSetRequestCallback callback)
{
_callback = callback;
}
private IPrinterBidiSetRequestCallback _callback;
#endregion
}
#endif
internal sealed class PrinterQueue : IPrinterQueue
{
#region IPrinterQueue methods
public string Name
{
get { return _queue.Name; }
}
public void SendBidiQuery(string bidiQuery)
{
_queue.SendBidiQuery(bidiQuery);
}
public IntPtr Handle
{
get { return _queue.Handle; }
}
public IPrinterPropertyBag GetProperties()
{
return new PrinterPropertyBag(_queue.GetProperties(), PrintPropertyBagType.QueueProperties);
}
public event EventHandler OnBidiResponseReceived
{
add
{
if (_onBidiResponseReceived == null)
{
_queue.OnBidiResponseReceived += _queue_OnBidiResponseReceived;
}
_onBidiResponseReceived += value;
}
remove
{
_onBidiResponseReceived -= value;
if (_onBidiResponseReceived == null)
{
_queue.OnBidiResponseReceived -= _queue_OnBidiResponseReceived;
}
}
}
#if WINDOWS_81_APIS
public IPrinterExtensionAsyncOperation SendBidiSetRequestAsync(string bidiRequest, IPrinterBidiSetRequestCallback callback)
{
PrinterBidiSetRequestCallback comCallback = new PrinterBidiSetRequestCallback(callback);
PrinterExtensionLib.IPrinterBidiSetRequestCallback comCallbackInterface = comCallback;
return new PrinterExtensionAsyncOperation(_queue2.SendBidiSetRequestAsync(bidiRequest, comCallbackInterface));
}
public IPrinterQueueView GetPrinterQueueView(uint viewOffset, uint viewSize)
{
return new PrinterQueueView(_queue2.GetPrinterQueueView(viewOffset, viewSize));
}
#endif
#endregion
#region Implementation details
internal PrinterQueue(PrinterExtensionLib.PrinterQueue queue)
{
_queue = queue;
#if WINDOWS_81_APIS
_queue2 = (PrinterExtensionLib.IPrinterQueue2)queue;
#endif
}
private void _queue_OnBidiResponseReceived(string bstrResponse, int hrStatus)
{
if (_onBidiResponseReceived != null)
{
_onBidiResponseReceived(this, new PrinterQueueEventArgs(bstrResponse, hrStatus));
}
}
private event EventHandler _onBidiResponseReceived;
#if WINDOWS_81_APIS
private PrinterExtensionLib.IPrinterQueue2 _queue2;
#endif
private PrinterExtensionLib.PrinterQueue _queue;
#endregion
}
internal sealed class PrinterExtensionRequest : IPrinterExtensionRequest
{
#region IPrinterExtensionRequest methods
public void Complete()
{
_request.Complete();
}
public void Cancel(int hr, string logMessage)
{
_request.Cancel(hr, logMessage);
}
#endregion
#region Implementation details
internal PrinterExtensionRequest(PrinterExtensionLib.IPrinterExtensionRequest request)
{
_request = request;
}
private PrinterExtensionLib.IPrinterExtensionRequest _request;
#endregion
}
#endregion
}