2009-09-09 4 views
10

Je suis en train d'imprimer dans une application .NET 3.5 C# à une imprimante réseau et d'obtenir cette exception:résultats PrintDocument.Print en Win32Exception l'opération terminée

L'opération terminée avec succès

Quelle est la cause, et comment peut-elle être résolue?

System.ComponentModel.Win32Exception: The operation completed successfully 
    at System.Drawing.Printing.PrinterSettings.GetHdevmodeInternal() 
    at System.Drawing.Printing.PrinterSettings.GetHdevmode(PageSettings pageSettings) 
    at System.Drawing.Printing.PrintController.OnStartPrint(PrintDocument document, PrintEventArgs e) 
    at System.Windows.Forms.PrintControllerWithStatusDialog.OnStartPrint(PrintDocument document, PrintEventArgs e) 
    at System.Drawing.Printing.PrintController.Print(PrintDocument document) 
    at System.Drawing.Printing.PrintDocument.Print() 
  • le compte dispose des autorisations pour imprimer à l'aide de l'imprimante réseau. Les autorisations sont définies pour tout le monde à imprimer.
  • l'imprimante a été supprimée et recréée.
  • Le paramètre de mise en file d'attente par rapport à l'impression directement sur l'imprimante a été basculé dans les deux sens.
  • autres imprimantes sur la machine fonctionnent bien
  • D'autres clients sur le réseau et les applications sur cette même machine peuvent imprimer sur cette imprimante sans problème.

Pour réduire le problème, j'ai créé une application de console simple. En cours d'exécution en tant qu'utilisateur normal, l'application s'imprime. Lorsqu'il est exécuté en tant que compte de service, il se trompe pour le compte de service.

enter image description here

La résolution à mon problème était de désinstaller le pilote qui est l'origine du problème et installer un ancien pilote.

+1

J'ai déjà eu cette erreur - le message d'erreur est vraiment trompeur. Je suppose que vous avez terminé, mais si vous ne postez pas de code, je vous répondrai. – Brandi

+0

@ p.campbell désolé je ne sais pas. Je me souviens que le manque de documentation sur ces sujets était extrêmement frustrant, donc je ne pouvais pas être plus utile. J'ai quelques questions anciennes que j'ai publiées à l'époque sur des sujets d'impression semi-connexes, je ne sais pas si elles seront pertinentes ou non ou si vous les avez déjà vérifiées. – Brandi

Répondre

1

Il est très difficile de répondre sans code et une exception vous dit que tout est OK. Donc, je vais juste donner quelques idées pour localiser le problème

  1. Testez-le sur une imprimante locale pour vous assurer que l'application fonctionne.
  2. Essayez d'imprimer sur l'imprimante réseau à l'aide du bloc-notes ou de quelque chose de similaire
  3. Double-triple triple permet de vérifier que l'utilisateur de l'application s'exécute comme il a les autorisations pour imprimer sur l'imprimante réseau.
  4. test sur une autre imprimante en réseau (après avoir fait 2 et 3 pour cette imprimante)
17

Le message déconcertant est provoqué par un bogue dans le code PInvoke dans le .NET Framework. L'appel Winapi sous-jacent qui échoue est le DocumentProperties() function. La déclaration de PInvoke pour elle ressemble à ceci:

[DllImport("winspool.drv", CharSet=CharSet.Auto, SetLastError=true)] 
public static extern int DocumentProperties(...); 

La SetLastError propriété est faux. Comme vous pouvez le voir à partir du lien MSDN, la fonction indique l'échec en retournant une valeur négative. Et est pas documenté pour définir le code d'erreur qui est retourné par GetLastError().

La conséquence de ce bogue est que l'infrastructure appellera Marshal.GetLastWin32Error() pour obtenir le code d'erreur et obtiendra une valeur aléatoire puisque DocumentProperties() ne l'a pas définie. Une valeur de 0 n'est pas improbable, ce qui produit le message d'exception "L'opération s'est terminée avec succès".

Vous devez donc ignorer le message d'exception; c'est très inutile bien sûr. Malheureusement, cette fonction winapi tombe dans une catégorie de fonctions, comme le font la plupart des fonctions GDI, qui ne produisent qu'un code retour "ça ne marche pas". Il ne donne aucun indice où chercher le problème. Il y a une raison à demi décente pour cette bizarrerie: Windows lui-même fait très peu lorsque vous appelez DocumentProperties(); la plupart du travail est effectué par le pilote d'imprimante. Il n'y a pas d'ensemble de codes d'erreur mis de côté pour l'impression dans le winapi. Tout est possible: les pilotes d'imprimante ne sont pas des fragments subtils de code. C'est le travail du pilote d'imprimante de vous parler des problèmes. Ils sont censés le faire en ouvrant leur propre fenêtre. Théoriquement ils sont de toute façon; La concurrence acharnée dans ce segment de marché ne laisse pas beaucoup d'argent pour payer le bon salaire d'un programmeur ces jours-ci.

Cela ne peut bien sûr pas fonctionner lorsque vous imprimez à partir d'un service. Il n'y a aucun moyen de voir une telle fenêtre popup, qui est la raison principale que Microsoft fortement décourage l'impression à partir d'un service. Ni vous ni le personnel informatique de votre client n'a la possibilité de diagnostiquer des problèmes. Lisez ce blog post pour obtenir des notes supplémentaires sur l'utilisation de PrintDocument à partir d'un service.

Personne n'aime obtenir des conseils comme celui-ci, mais l'écriture est sur le mur. Ne le faites pas.

5

Pour ajouter @ la réponse de HansPassant, voici le code exact en question qui lève l'exception:

Microsoft Référence Source, PrinterSettings.cs

private IntPtr GetHdevmodeInternal(string printer) { 
    // Create DEVMODE 
    int modeSize = SafeNativeMethods.DocumentProperties(NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, printer, IntPtr.Zero, NativeMethods.NullHandleRef, 0); 
    if (modeSize < 1) { 
     throw new InvalidPrinterException(this); 
    } 
    IntPtr handle = SafeNativeMethods.GlobalAlloc(SafeNativeMethods.GMEM_MOVEABLE, (uint)modeSize); // cannot be <0 anyway 
    IntPtr pointer = SafeNativeMethods.GlobalLock(new HandleRef(null, handle)); 

    //Get the DevMode only if its not cached.... 
    if (cachedDevmode != null) { 
     Marshal.Copy(cachedDevmode, 0, pointer, devmodebytes); 
    } 
    else { 
     int returnCode = SafeNativeMethods.DocumentProperties(NativeMethods.NullHandleRef, NativeMethods.NullHandleRef, printer, pointer, NativeMethods.NullHandleRef, SafeNativeMethods.DM_OUT_BUFFER); 
     if (returnCode < 0) { 
      throw new Win32Exception(); // <-------- 
     } 
    } 
0

J'ai aussi eu ce problème. Dans mon cas, j'ai utilisé un thread séparé pour imprimer le rapport, et l'ai synchronisé avec le thread principal via "ManualResetEvent". (J'ai développé de cette façon parce que les forces .Net divisent la logique d'impression en méthodes "PrintPage" ...).

L'erreur se produit en raison d'une incompatibilité (dont je ne peux pas expliquer la source) entre le pilote d'imprimante et cet environnement multithread. J'ai résolu le problème en changeant ma signature de méthode logique d'impression de "void" à "IEnumerable", et briser le retour rendement, une méthode similaire à la "CoRoutines" du moteur de jeu Unity3d. De cette façon, il n'est pas nécessaire de créer plus d'un thread, et mon code d'impression s'organise.

+0

Je ne sais pas pourquoi cela a été refusé, mais vous m'avez aidé à résoudre un problème sur lequel je travaillais depuis des jours. À des fins de test, j'ai lancé mon impression sur le fil de l'interface utilisateur et cela a fonctionné, je suis retourné lancer l'impression à partir d'un autre thread et mettre à jour le pilote de l'imprimante. J'utilisais le PCL6 6.2.6 universel de HP auparavant. Ce pilote n'aime pas être appelé dans un environnement multithread. –

+0

6.2.1, désolé. HP Universal Printing PCL 6 (v6.2.1) –

Questions connexes