gpt4 book ai didi

printing - 从 Windows 服务进行 XPS 打印

转载 作者:行者123 更新时间:2023-12-02 10:49:23 24 4
gpt4 key购买 nike

我正在尝试从 .net 框架上的 Windows 服务打印 XPS 文档。由于 Microsoft 不支持使用 System.Drawing.Printing 或 System.Printing (WPF) 进行打印,因此我使用 native XPSPrint API。这是 Aspose 在 http://www.aspose.com/documentation/.net-components/aspose.words-for-.net/howto-print-a-document-on-a-server-via-the-xpsprint-api.html 中向我建议的。

当我尝试从 Windows 服务打印 XPS 文档时,结果包含奇怪的字符而不是我想要的文本。

我尝试使用不同的打印机(包括虚拟打印机,例如 PDFCreator)、服务的不同用户和用户权限、不同的 xps 生成器(aspose、word 2007、word 2010)、不同的平台(Windows 7、Windows 2008 R2) )但都有相同的结果。

有人知道怎么解决这个问题吗?任何帮助将不胜感激!

对于那些想尝试的人,我通过以下方式分享了一些文件:

https://docs.google.com/leaf?id=0B4J93Ly5WzQKNWU2ZjM0MDYtMjFiMi00NzM0LTg4MTgtYjVlNDA5NWQyMTc3&hl=nl

  • document.xps:要打印的 XPS 文档
  • document_printed_to_pdfcreator.pdf:演示问题所在的打印文档
  • XpsPrintTest.zip:包含示例代码的示例 VS2010 解决方案

托管 Windows 服务的示例代码是:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.IO;
using System.Threading;
using System.Runtime.InteropServices;

namespace PrintXpsService
{
public partial class XpsPrintService : ServiceBase
{
// Change name of printer here
private String f_printerName = "PDFCreator";

// path to some file where logging is done
private String f_logFile = @"C:\temp\testdoc\xps_printing_service_log.txt";

// path to xps file to print
private String f_xpsFile = @"C:\temp\testdoc\document.xps";

public XpsPrintService()
{
InitializeComponent();
}

private void Log(String fmt, params Object[] args)
{
try
{
DateTime now = DateTime.Now;

using (StreamWriter wrt = new StreamWriter(f_logFile, true))
{
wrt.Write("{0} {1} - ", now.ToShortDateString(), now.ToShortTimeString());
wrt.WriteLine(fmt, args);
}
}
catch (Exception ex)
{
}
}

protected override void OnStart(string[] args)
{
// uncomment to allow to connect debugger
//int i = 0;
//while (i == 0)
//{
// if (i == 0)
// {
// Thread.Sleep(1000);
// }
//}

Log("Starting Service");
try
{
Log("Printing xps file {0}", f_xpsFile);

using (Stream stream = new FileStream(f_xpsFile, FileMode.Open, FileAccess.Read))
{
Log("Starting to print on printer {0}", f_printerName);
String jobName = f_xpsFile;
this.Print(stream, jobName);
}
Log("Document printed");
}
catch (Exception ex)
{
Log("Exception during execution: {0}", ex.Message);
Log(" {0}", ex.StackTrace);
Exception inner = ex.InnerException;
while (inner != null)
{
Log("=== Inner Exception: {0}", inner.Message);
Log(" {0}", inner.StackTrace);
inner = inner.InnerException;
}
}
}

protected override void OnStop()
{
}

public void Print(Stream stream, String jobName)
{
String printerName = f_printerName;
IntPtr completionEvent = CreateEvent(IntPtr.Zero, true, false, null);
try
{
IXpsPrintJob job;
IXpsPrintJobStream jobStream;

StartJob(printerName, jobName, completionEvent, out job, out jobStream);
CopyJob(stream, job, jobStream);
WaitForJob(completionEvent, -1);
CheckJobStatus(job);
}
finally
{
if (completionEvent != IntPtr.Zero)
CloseHandle(completionEvent);
}
}

private void StartJob(String printerName,
String jobName, IntPtr completionEvent,
out IXpsPrintJob job,
out IXpsPrintJobStream jobStream)
{
int result = StartXpsPrintJob(printerName, jobName, null, IntPtr.Zero, completionEvent,
null, 0, out job, out jobStream, IntPtr.Zero);
if (result != 0)
throw new Win32Exception(result);
}


private void CopyJob(Stream stream, IXpsPrintJob job, IXpsPrintJobStream jobStream)
{
try
{
byte[] buff = new byte[4096];
while (true)
{
uint read = (uint)stream.Read(buff, 0, buff.Length);
if (read == 0)
break;
uint written;
jobStream.Write(buff, read, out written);

if (read != written)
throw new Exception("Failed to copy data to the print job stream.");
}

// Indicate that the entire document has been copied.
jobStream.Close();
}
catch (Exception)
{
// Cancel the job if we had any trouble submitting it.
job.Cancel();
throw;
}
}

private void WaitForJob(IntPtr completionEvent, int timeout)
{
if (timeout < 0)
timeout = -1;

switch (WaitForSingleObject(completionEvent, timeout))
{
case WAIT_RESULT.WAIT_OBJECT_0:
// Expected result, do nothing.
break;

case WAIT_RESULT.WAIT_TIMEOUT:
// timeout expired
throw new Exception("Timeout expired");

case WAIT_RESULT.WAIT_FAILED:
throw new Exception("Wait for the job to complete failed");

default:
throw new Exception("Unexpected result when waiting for the print job.");
}
}

private void CheckJobStatus(IXpsPrintJob job)
{
XPS_JOB_STATUS jobStatus;
job.GetJobStatus(out jobStatus);
switch (jobStatus.completion)
{
case XPS_JOB_COMPLETION.XPS_JOB_COMPLETED:
// Expected result, do nothing.
break;
case XPS_JOB_COMPLETION.XPS_JOB_IN_PROGRESS:
// expected, do nothing, can occur when printer is paused
break;
case XPS_JOB_COMPLETION.XPS_JOB_FAILED:
throw new Win32Exception(jobStatus.jobStatus);
default:
throw new Exception("Unexpected print job status.");
}
}

[DllImport("XpsPrint.dll", EntryPoint = "StartXpsPrintJob")]
private static extern int StartXpsPrintJob(
[MarshalAs(UnmanagedType.LPWStr)] String printerName,
[MarshalAs(UnmanagedType.LPWStr)] String jobName,
[MarshalAs(UnmanagedType.LPWStr)] String outputFileName,
IntPtr progressEvent, // HANDLE
IntPtr completionEvent, // HANDLE
[MarshalAs(UnmanagedType.LPArray)] byte[] printablePagesOn,
UInt32 printablePagesOnCount,
out IXpsPrintJob xpsPrintJob,
out IXpsPrintJobStream documentStream,
IntPtr printTicketStream); // This is actually "out IXpsPrintJobStream", but we don't use it and just want to pass null, hence IntPtr.

[DllImport("Kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);

[DllImport("Kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern WAIT_RESULT WaitForSingleObject(IntPtr handle, Int32 milliseconds);

[DllImport("Kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseHandle(IntPtr hObject);
}

/// <summary>
/// This interface definition is HACKED.
///
/// It appears that the IID for IXpsPrintJobStream specified in XpsPrint.h as
/// MIDL_INTERFACE("7a77dc5f-45d6-4dff-9307-d8cb846347ca") is not correct and the RCW cannot return it.
/// But the returned object returns the parent ISequentialStream inteface successfully.
///
/// So the hack is that we obtain the ISequentialStream interface but work with it as
/// with the IXpsPrintJobStream interface.
/// </summary>
[Guid("0C733A30-2A1C-11CE-ADE5-00AA0044773D")] // This is IID of ISequenatialSteam.
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IXpsPrintJobStream
{
// ISequentualStream 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();
}

[Guid("5ab89b06-8194-425f-ab3b-d7a96e350161")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IXpsPrintJob
{
void Cancel();
void GetJobStatus(out XPS_JOB_STATUS jobStatus);
}

[StructLayout(LayoutKind.Sequential)]
struct XPS_JOB_STATUS
{
public UInt32 jobId;
public Int32 currentDocument;
public Int32 currentPage;
public Int32 currentPageTotal;
public XPS_JOB_COMPLETION completion;
public Int32 jobStatus; // UInt32
};

enum XPS_JOB_COMPLETION
{
XPS_JOB_IN_PROGRESS = 0,
XPS_JOB_COMPLETED = 1,
XPS_JOB_CANCELLED = 2,
XPS_JOB_FAILED = 3
}

enum WAIT_RESULT
{
WAIT_OBJECT_0 = 0,
WAIT_ABANDONED = 0x80,
WAIT_TIMEOUT = 0x102,
WAIT_FAILED = -1 // 0xFFFFFFFF
}
}

注意:更多信息的一些链接:

最佳答案

我与微软讨论了这个问题,我们发现该问题与打印机后台处理程序中不正确的字体替换有关。当打印机设置为不后台打印文档时,它们也可以从 Windows 服务正确打印。否则,除了 arial(也许还有其他一些字体)之外的所有字体都将被另一种字体替换。在我提供的示例中,calibri 被 wingdings 替代。

因此,他们承认这是一个错误,但目前他们不会解决它。这将取决于有多少人会遭受这个错误的困扰,以便他们决定是否愿意修复它......

关于printing - 从 Windows 服务进行 XPS 打印,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6123507/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com