从Windows 8上的Windows服务打印失败

时间:2013-04-05 12:30:45

标签: c# windows service printing

我有一个用C#.NET编写的Windows服务应用程序。此应用程序用于通过将文档打印到生成PDF的本地软件打印机来生成报告pdf。这在Windows XP和Windows 7上运行良好。不幸的是我发现在Windows 8上它失败了。然后我发现当我从我的服务打印时,打印到Windows 8上的任何(甚至物理)打印机都会失败。 我的计划中缺少什么工作?我是这样打印的:

FlowDocument document = MyDocument;
var source = document as IDocumentPaginatorSource;
var documentPaginator = source.DocumentPaginator;

using (var printServer = new LocalPrintServer())
{
    PrintQueue queue = printServer.GetPrintQueue(printerName);
    XpsDocumentWriter docWriter = PrintQueue.CreateXpsDocumentWriter(queue);

    // Print ticket - Approach 1
    // PrintTicket printTicket = queue.DefaultPrintTicket.Clone();

    // Print ticket - Approach 2
    var printTicket = new PrintTicket
    {
        PageOrientation = PageOrientation.Landscape,
        PageMediaSize = new PageMediaSize(PageMediaSizeName.ISOA4), // set size of media (paper)
    };


    documentPaginator.PageSize = new Size(document.PageWidth, document.PageHeight);
    docWriter.Write(documentPaginator, printTicket);
}

服务设置为“系统帐户”而没有“与桌面交互”(但我也尝试过或以本地用户身份登录)。

这导致Windows 8出现异常。使用'打印票证 - 方法1'时:

System.Printing.PrintQueueException: PrintTicket provider failed to bind to printer. Win32 error: -2147467231
at MS.Internal.Printing.Configuration.PTProvider..ctor(String deviceName, Int32 maxVersion, Int32 clientVersion)
at MS.Internal.Printing.Configuration.PTProviderBase.Create(String deviceName, Int32 maxVersion, Int32 clientVersion)
at System.Printing.PrintTicketManager..ctor(String deviceName, Int32 clientPrintSchemaVersion)
at System.Printing.PrintQueue.get_DefaultPrintTicket()

使用'打印票证 - 方法2':

Exception encountered: System.Printing.PrintQueueException: Fehler beim Binden des PrintTicket-Anbieters an den Drucker. Win32-Fehler: -2147467231
bei MS.Internal.Printing.Configuration.PTProvider..ctor(String deviceName, Int32 maxVersion, Int32 clientVersion)
bei MS.Internal.Printing.Configuration.PTProviderBase.Create(String deviceName, Int32 maxVersion, Int32 clientVersion)
bei System.Printing.PrintTicketManager..ctor(String deviceName, Int32 clientPrintSchemaVersion)
bei System.Printing.PrintQueue.get_UserPrintTicket()
bei System.Printing.PrintQueue.get_CurrentJobSettings()
bei System.Printing.PrintQueue.CreateSerializationManager(Boolean isBatchMode, Boolean mustSetJobIdentifier)
bei System.Windows.Xps.XpsDocumentWriter.BeginWrite(Boolean batchMode, Boolean asyncMode, Boolean setPrintTicketHandler, PrintTicket printTicket, PrintTicketLevel printTicketLevel, Boolean printJobIdentifierSet)
bei System.Windows.Xps.XpsDocumentWriter.Write(DocumentPaginator documentPaginator, PrintTicket printTicket)

我会说服务能够找到那些打印机,因为当我尝试打印到不存在的打印机时,我的“打印机名称无效”异常。

在这里,我将为自己保留一些相关问题: Printing from a Windows ServicePrinting from a Windows Servicehttp://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/b74bd27d-1cc8-4fca-a6de-2cd1371cf3b7/

温和相关: Printing from a .NET Service

编辑:

如果有人有兴趣尝试 - 这是我的示例服务应用程序,它尝试将简单文档打印到在配置文件中选择的打印机:http://bin.mypage.sk/FILES/PrintTestService.rar

EDIT2:

有趣。当我尝试不同的打印代码时,没有错误:

using (var printDocument = new PrintDocument())
{
    printDocument.PrinterSettings.PrinterName = printerName;
    printDocument.Print();
}

不幸的是,这是使用System.Drawing.Graphics库的较旧的GDI +代码,该代码与我的代码不兼容,该代码以System.Windows.Media.Visual对象的形式生成分页文档。所以我不能用它来打印我的文档,除非我想花两周时间从头开始创建我的文档的分页。

EDIT3:

此处讨论此问题:http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/96e7fc10-3f08-4808-b748-692e30377293 使用'anyCPU'平台有一个“解决方法”。这个解决方法确实有效(我试过了),但是当我的服务需要是x86时,它不适用于我的情况。我已通过我们公司联系MS支持人员,以找到真正的解决方案。

3 个答案:

答案 0 :(得分:2)

解决方案:等待Microsoft修复此错误。我已经报告了这个错误(REG:113040910349062),他们已经确认了,但修复不会很快(在接下来的几个月内)并且没有为它指定日期。

我们使用的解决方法: 创建一个处理打印的小应用程序,将其编译为'anyCPU'应用程序并从服务应用程序运行它(我无法编译为'anyCPU' - 我需要'x86',因为它的依赖性)。此解决方法已经过测试并且有效。但它很脏+导致开销+额外的护理。

编辑:Microsoft提供了一个修补程序,可以解决Windows 8中的此问题:http://support.microsoft.com/kb/2872151/EN-US(“您无法从基于x64的Windows 8或Windows Server 2012版本中的32位WPF应用程序进行打印”)

编辑(2013-11-04):我们测试了此修补程序,它在Windows 8或Windows 8.1上不起作用。目前,我们再次处于与微软沟通的阶段。

编辑(2014年年初):我们收到了微软的回复,他们不知道如何修复此错误并且错误已关闭。因此,目前只有我们的解决方案是将一个小的app exe编译为AnyCPU,由我们的x86服务调用。这种方法有效,但会导致速度减慢,因此我们的产品也难以维护。

答案 1 :(得分:2)

http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/fdcfa0fa-50aa-4a61-be79-5b4c8f65fbf7/我们看到这是向Microsoft报告的,并在Windows 8和Windows Server 2012中被确认为错误。

尝试在非标准用户会话(例如服务)中从32位进程进行打印时会触发此错误。

根据Microsoft的说法,这个错误在Windows 8.1和Windows Server 2012 R2中得到了解决。但是,我们仍然可以在Windows 8.1上重现它。

在同一网站上,Microsoft提供了一种解决方法。此解决方法在Windows 8.1上解决了我们的问题。它可能也适用于Windows 8和Windows Server 2012。

解决方法如下:

  1. 打开Regedit并转到HKEY_CLASSES_ROOT \ CLSID {BA7C0D29-81CA-4901-B450-634E20BB8C34}

  2. 检查“AppID”注册表项的值。在我们的案例中,这是{AA0B85DA-FDDF-4272-8D1D-FF9B966D75B0}

  3. 现在转到HKEY_CLASSES_ROOT \ AppID {AA0B85DA-FDDF-4272-8D1D-FF9B966D75B0}(或您在系统上找到的相应值)
  4. 在此注册表项下,删除名称为“AccessPermission”,“LaunchPermission”和“RunAs”的条目
  5. 由于这是Windows中的一个错误,因此无法在代码中修复它。解决方法可能有副作用,但到目前为止我们还没有看到任何副作用。

答案 2 :(得分:-1)

我有同样的经验从Windows服务打印,但我的问题是在Windows Server 2008,我认为它是因为Windows服务并不意味着具有这种功能。我阅读了很多博客等,并没有找到解决方案。我终于找到了一种方法,服务使用microsoft任务库调用另一个exe进行打印。