public
Last active

  • Download Gist
NativeMethods.cs
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
internal static class NativeMethods
{
[DllImport("XpsPrint.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
public static extern int StartXpsPrintJob(string printerName, string jobName, string outputFileName, IntPtr progressEvent, SafeWaitHandle completionEvent,
[MarshalAs(UnmanagedType.LPArray)] byte[] printablePagesOn, int printablePagesOnCount, out IXpsPrintJob xpsPrintJob, out IXpsPrintJobStream documentStream, out IXpsPrintJobStream printTicketStream);
}
 
[ComImport, Guid("E974D26D-3D9B-4D47-88CC-3872F2DC3585"), ClassInterface(ClassInterfaceType.None)]
internal class XpsOMObjectFactory
{
}
 
[ComImport, Guid("F9B2A685-A50D-4FC2-B764-B56E093EA0CA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IXpsOMObjectFactory
{
void CreatePackage();
 
[return: MarshalAs(UnmanagedType.Interface)]
IXpsOMPackage CreatePackageFromFile([MarshalAs(UnmanagedType.LPWStr)] string filename, bool reuseObjects);
 
void CreatePackageFromStream();
void CreateStoryFragmentsResource();
void CreateDocumentStructureResource();
void CreateSignatureBlockResource();
void CreateRemoteDictionaryResource();
void CreateRemoteDictionaryResourceFromStream();
void CreatePartResources();
void CreateDocumentSequence();
void CreateDocument();
void CreatePageReference();
void CreatePage();
void CreatePageFromStream();
void CreateCanvas();
void CreateGlyphs();
void CreatePath();
void CreateGeometry();
void CreateGeometryFigure();
void CreateMatrixTransform();
void CreateSolidColorBrush();
void CreateColorProfileResource();
void CreateImageBrush();
void CreateVisualBrush();
void CreateImageResource();
void CreatePrintTicketResource();
void CreateFontResource();
void CreateGradientStop();
void CreateLinearGradientBrush();
void CreateRadialGradientBrush();
void CreateCoreProperties();
void CreateDictionary();
void CreatePartUriCollection();
void CreatePackageWriterOnFile();
void CreatePackageWriterOnStream();
void CreatePartUri();
void CreateReadOnlyStreamOnFile();
}
 
[ComImport, Guid("18C3DF65-81E1-4674-91DC-FC452F5A416F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IXpsOMPackage
{
void GetDocumentSequence();
void SetDocumentSequence();
void GetCoreProperties();
void SetCoreProperties();
void GetDiscardControlPartName();
void SetDiscardControlPartName();
void GetThumbnailResource();
void SetThumbnailResource();
void WriteToFile();
 
void WriteToStream(IXpsPrintJobStream stream, bool optimizeMarkupSize);
};
 
// NOTE: It appears that the IID for IXpsPrintJobStream specified in XpsPrint.h --
// MIDL_INTERFACE("7a77dc5f-45d6-4dff-9307-d8cb846347ca") -- is not correct, or the object
// doesn't implement QueryInterface correctly. However, we can QI for ISequentialStream and
// successfully (at least in Windows 7 SP1 x86) call the Close method as if it existed on that
// interface.
// That is, we obtain the ISequentialStream interface, but work with it as the IXpsPrintJobStream interface.
// Thanks to http://stackoverflow.com/questions/6123507/xps-printing-from-windows-service for this tip.
[ComImport, Guid("0C733A30-2A1C-11CE-ADE5-00AA0044773D"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IXpsPrintJobStream
{
// ISequentialStream methods
void Read([MarshalAs(UnmanagedType.LPArray)] byte[] pv, uint cb, out uint pcbRead);
void Write([MarshalAs(UnmanagedType.LPArray)] byte[] pv, uint cb, out uint pcbWritten);
 
// IXpsPrintJobStream methods
void Close();
}
 
[ComImport, Guid("5AB89B06-8194-425F-AB3B-D7A96E350161"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IXpsPrintJob
{
void Cancel();
IntPtr GetJobStatus();
};
Print.cs
C#
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
/// <summary>
/// Prints the specified XPS document to a printer using the native XPS Print API.
/// </summary>
/// <param name="xpsFilePath">The path to the XPS document.</param>
/// <param name="printerName">The printer name.</param>
/// <param name="printTicket">A PrintTicket with settings for this print job.</param>
/// <returns><c>true</c> if the document was successfully printed; otherwise, <c>false</c>.</returns>
/// <remarks>This method should be called from a background thread.</remarks>
public bool Print(string xpsFilePath, string printerName, PrintTicket printTicket)
{
// try to create the XPS Object Model factory (only available on Windows 7 and Vista with the Platform Update)
IXpsOMObjectFactory xpsFactory = null;
try
{
xpsFactory = (IXpsOMObjectFactory)new XpsOMObjectFactory();
}
catch (COMException)
{
// OS doesn't support XPS Document API
return false;
}
 
bool success = false;
IXpsOMPackage package = null;
 
try
{
// load the saved document as a native XpsOMPackage
package = xpsFactory.CreatePackageFromFile(xpsFilePath, false);
 
using (ManualResetEvent handle = new ManualResetEvent(false))
{
// attempt to start the print job
IXpsPrintJob printJob;
IXpsPrintJobStream docStream, ticketStream;
int hresult = NativeMethods.StartXpsPrintJob(printerName, jobTitle, null, IntPtr.Zero, handle.SafeWaitHandle, null, 0, out printJob, out docStream, out ticketStream);
 
// check for success (NOTE: checking HRESULT value directly instead of calling Marshal.ThrowExceptionForHR to avoid proliferation of 'catch' blocks)
if (hresult >= 0)
{
// write the current printer settings to the print ticket stream
byte[] ticketData = printTicket.GetXmlStream().ToArray();
uint bytesWritten;
ticketStream.Write(ticketData, (uint) ticketData.Length, out bytesWritten);
ticketStream.Close();
 
// write the XPS package to the document stream
package.WriteToStream(docStream, false);
docStream.Close();
 
// wait for printing to finish
handle.WaitOne();
success = true;
}
}
}
catch (COMException)
{
// printing failed
}
catch (DllNotFoundException)
{
// OS doesn't support XPS Print API
}
catch (EntryPointNotFoundException)
{
// OS doesn't support XPS Print API
}
 
// force the XPS package to be released, so that the temporary file can be deleted
if (package != null)
Marshal.FinalReleaseComObject(package);
 
return success;
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.