2013-04-05 22 views
7

Ho un'applicazione di servizio Windows scritta in C# .NET. Questa applicazione viene utilizzata per generare un report in formato PDF stampando il documento sulla stampante software locale che genera PDF. Funziona bene su Windows XP e Windows 7. Sfortunatamente ho scoperto che su Windows 8 fallisce. Poi ho scoperto che la stampa su qualsiasi stampante (anche fisica) su Windows 8 fallisce quando stampo dal mio servizio. Cosa manca nel mio programma per funzionare? Sto stampa in questo modo:La stampa dal servizio Windows su Windows 8 fallisce

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); 
} 

servizio è impostato su 'account di sistema', senza 'interagire con il desktop' (ma ho provato che troppo o per effettuare il login come utente locale).

Ciò si traduce in salvo su Windows 8. Quando si utilizza 'biglietto di stampa - Approccio 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() 

Usando 'biglietto Stampa - Approccio 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) 

direi che il servizio è in grado di trovare quelle stampanti perché quando ho provato a stampare su una stampante inesistente e ho ottenuto l'eccezione "nome stampante non valida".

Qui Terrò per me alcune domande correlate: Printing from a Windows Service, Printing from a Windows Service, http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/b74bd27d-1cc8-4fca-a6de-2cd1371cf3b7/,

Leggermente correlati: Printing from a .NET Service,

edit:

Nel caso in cui qualcuno è interessato a cercando - ecco la mia applicazione di servizio di esempio che tenta di stampare un documento semplice per la stampante selezionata nel file di configurazione: http://bin.mypage.sk/FILES/PrintTestService.rar

EDIT2:

Interessante. Quando ho provato un codice di stampa diverso non c'è nessun errore:

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

Purtroppo questo è un vecchio GDI + usando la libreria System.Drawing.Graphics che non è compatibile con il mio codice che produce documento impaginato in forma di sistema. Windows.Media.Visual oggetti. Quindi non posso usarlo per stampare il mio documento a meno che non mi piacerebbe passare due settimane a creare l'impaginazione del mio documento da zero.

Edit3:

c'è discussione su questo problema qui: http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/96e7fc10-3f08-4808-b748-692e30377293 C'è un 'soluzione' per poter utilizzare la piattaforma 'AnyCPU'. Questo workaround funziona davvero (l'ho provato) ma non è utilizzabile nel mio caso quando il mio servizio deve essere x86. Ho contattato il supporto MS attraverso la nostra azienda per trovare una soluzione reale.

+1

Si dovrebbe provare a configurare il servizio per interagire con il desktop PLUS abilitare i servizi interattivi sulla macchina. Vedere qui http://msdn.microsoft.com/en-us/library/windows/desktop/ms683502.aspx NOTA in Windows 8 il valore della chiave del Registro di sistema NoInteractiveServices è 1 per impostazione predefinita, è necessario impostarlo su 0. –

+0

@ SimonMourier: ho modificato il flag di registro su 0, quindi riavviato e ho selezionato 'Permetti al servizio di interagire con il desktop' sul servizio. Il risultato è lo stesso. – MiroJanosik

risposta

2

Soluzione: attendere che Microsoft risolva questo problema. Ho segnalato il bug (REG: 113040910349062), lo hanno confermato, ma la correzione non sarà presto (nei prossimi mesi) e non c'è una data specificata per questo.

Soluzione che usiamo: creare una piccola applicazione che gestisce la stampa, compilarlo come applicazione 'AnyCPU' ed eseguirlo da un'applicazione di servizio (che io non riesco a compilare come 'AnyCPU' - ho bisogno di 'x 86' a causa delle sue dipendenze). Questa soluzione alternativa è stata testata e funziona. Ma è sporco + causa sovraccarico + extra cura.

Edit: Microsoft fornisce un aggiornamento rapido che dovrebbe risolvere questo problema in Windows 8: http://support.microsoft.com/kb/2872151/EN-US ("Non è possibile stampare da un'applicazione WPF a 32 bit in una versione x64 di Windows 8 o Windows Server 2012")

Modifica (2013-11-04): abbiamo testato l'aggiornamento rapido e non funziona su Windows 8 o Windows 8.1. Attualmente siamo di nuovo in una fase di comunicazione con Microsoft.

Modifica (2014-inizio dell'anno): abbiamo ricevuto una risposta da Microsoft che non sanno come risolvere questo bug e il bug è chiuso. Quindi, per il momento, la sola soluzione per noi è avere una piccola app exe compilata come AnyCPU che viene chiamata dal nostro servizio x86. Questo approccio funziona, ma provoca rallentamenti e il nostro prodotto è anche più difficile da mantenere a causa di questo.

+0

Hai provato la modifica del registro nella mia risposta? Questo funziona per noi su diverse macchine. – NineBerry

+0

Ciao, non l'ho ancora testato. Lo proverò tra settimane o mesi. Sfortunatamente, la priorità di questo compito è ora più bassa e non posso impostare le priorità sul mio progetto. – MiroJanosik

-1

Ho avuto la stessa esperienza di stampa da un servizio Windows ma il mio problema era in Windows Server 2008, penso sia perché i servizi Windows non sono pensati per avere queste funzionalità. Ho letto molti blog ecc. E non ho trovato alcuna soluzione. Ho finalmente trovato un modo in cui il servizio richiama un altro exe per stampare usando la libreria dei task microsoft.

+0

Bene, ma la stampa dal servizio in questo modo funziona da Windows 7 e funziona in Windows XP. Non voglio alcuna interazione con l'utente (selezionando una stampante o altro) e quindi perché non funzionerebbe. Inoltre, come ho postato più tardi nella mia 2a modifica, posso ancora stampare qualcosa (ma non abbastanza) se uso legacy GDI +. – MiroJanosik

+1

Ho provato il tuo suggerimento - Ho creato un eseguibile che fa il lavoro di stampa. L'eseguibile di per sé funziona bene e stampa ciò di cui ho bisogno, ma dopo averlo eseguito dal servizio, l'eccezione viene lanciata nello stesso modo in cui si trovava prima nel servizio. Sto eseguendo l'eseguibile con Process.Start(). – MiroJanosik

+0

questo è il punto, non è possibile chiamare un processo in questo modo in un servizio di finestra. Ti consiglio di dare un'occhiata alla libreria dei compiti di microsoft e imposta un'attività di Windows per eseguire l'applicazione della tua console. Ci sono molti documenti in msdn e codeproject. – serdna

2

A http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/fdcfa0fa-50aa-4a61-be79-5b4c8f65fbf7/ vediamo che questo è stato segnalato a Microsoft e ha confermato come un bug in Windows 8 e Windows Server 2012.

Questo bug viene attivato quando si tenta di stampare da un processo a 32 bit in sessione utente non standard (come ad esempio un servizio).

Secondo Microsoft, questo errore è stato risolto in Windows 8.1 e Windows Server 2012 R2. Tuttavia, possiamo ancora riprodurlo su Windows 8.1.

Sullo stesso sito, Microsoft offre una soluzione alternativa. Questa soluzione alternativa ha risolto il problema per noi su Windows 8.1. Probabilmente funziona anche su Windows 8 e Windows Server 2012.

La soluzione è la seguente:

  1. Aprire Regedit e andare in HKEY_CLASSES_ROOT \ CLSID {BA7C0D29-81CA-4901-B450-634E20BB8C34}

  2. Controllare il valore della voce di registro "AppID". Nel nostro caso questo è stato {AA0B85DA-fddf-4272-8D1D-FF9B966D75B0}

  3. Passare al HKEY_CLASSES_ROOT \ AppID {AA0B85DA-fddf-4272-8D1D-FF9B966D75B0} (o il rispettivo valore che avete trovato sul vostro sistema)
  4. Sotto questa chiave di registro, eliminare le voci con il nome "AccessPermission", "LaunchPermission" e "RunAs"

Poiché si tratta di un bug in Windows, non è possibile risolvere il problema nel codice. La soluzione alternativa potrebbe avere effetti collaterali, ma non abbiamo visto nessuno finora nel nostro scenario.

+0

Ciao, ho fatto alcuni test di base e questa soluzione funziona. Devo fare più test su macchine diverse. – MiroJanosik