Comment afficher la boîte de dialog des propriétés / préférences de l’imprimante et enregistrer les modifications?

EDIT: de ma faute! Je m’attendais à ce que les modifications soient réécrites dans les parameters d’imprimante par défaut alors qu’en fait seule l’instance locale de PrinterSettings est modifiée. – Le code ci-dessous semble fonctionner comme prévu

J’essaie d’afficher les propriétés d’imprimante personnalisées d’une imprimante donnée. J’ai besoin de cela dans le cadre d’un PrintDialog personnalisé que j’essaie d’écrire.

La plupart des exemples que je trouve en ligne parviennent à afficher la boîte de dialog, mais tous les changements que l’utilisateur peut apporter sont perdus, ce qui la rend inutile.

Exemple: http://www.codeproject.com/KB/system/PrinterPropertiesWindow.aspx

(concernant la page ci-dessus: j’ai essayé de changer le code comme suggéré par BartJoy (sur la page) mais cela n’a pas résolu le problème)

J’ai aussi essayé l’exemple et les suggestions sur la page pinvoke.net mais cela ne fonctionne toujours pas:

http://www.pinvoke.net/default.aspx/winspool.documentproperties

Parmi les sites Web ci-dessus, je suppose que le problème peut ne concerner que Windows 64 bits et / ou si le nom de l’imprimante comporte plus de 32 caractères.

Je ne sais pas ce que je devrais essayer ensuite … J’apprécie vos suggestions et commentaires!

EDIT: Voici ce que j’ai essayé:

[DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesW", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPWStr)] ssortingng pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode); [DllImport("winspool.drv")] private static extern int OpenPrinter(ssortingng pPrinterName, out IntPtr hPrinter, IntPtr pDefault); [DllImport("winspool.drv")] private static extern int ClosePrinter(IntPtr phPrinter); [DllImport("kernel32.dll")] static extern IntPtr GlobalLock(IntPtr hMem); [DllImport("kernel32.dll")] static extern bool GlobalUnlock(IntPtr hMem); [DllImport("kernel32.dll")] static extern bool GlobalFree(IntPtr hMem); private const int DM_PROMPT = 4; private const int DM_OUT_BUFFER = 2; private const int DM_IN_BUFFER = 8; private void OpenPrinterPropertiesDialog() { var printerSettings = new System.Drawing.Printing.PrinterSettings(); var printerName = printerSettings.PrinterName; IntPtr handle; OpenPrinter(printerName, out handle, IntPtr.Zero); IntPtr hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings); IntPtr pDevMode = GlobalLock(hDevMode); int sizeNeeded = DocumentProperties(this.Handle, handle, printerName, pDevMode, pDevMode, 0); IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded); DocumentProperties(this.Handle, handle, printerName, devModeData, pDevMode, DM_IN_BUFFER | DM_PROMPT | DM_OUT_BUFFER); ClosePrinter(handle); GlobalUnlock(hDevMode); printerSettings.SetHdevmode(devModeData); printerSettings.DefaultPageSettings.SetHdevmode(devModeData); GlobalFree(hDevMode); Marshal.FreeHGlobal(devModeData); } 

J’ai essayé d’utiliser les méthodes OpenPrinter et ClosePrinter et de transmettre devModeData en tant que paramètre de sortie lors du deuxième appel, car j’ai trouvé étrange que le code d’origine de pinvoke.net ne l’ait pas fait. (mais j’avoue que je ne sais pas ce que je fais – ce n’est qu’un essai et une erreur).

Voici le code original du site pinvoke:

 private void OpenPrinterPropertiesDialog(PrinterSettings printerSettings) { IntPtr hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings); IntPtr pDevMode = GlobalLock(hDevMode); int sizeNeeded = DocumentProperties(this.Handle, IntPtr.Zero, printerSettings.PrinterName, pDevMode, pDevMode, 0); IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded); DocumentProperties(this.Handle, IntPtr.Zero, printerSettings.PrinterName, IntPtr.Zero, pDevMode, 14); GlobalUnlock(hDevMode); printerSettings.SetHdevmode(devModeData); printerSettings.DefaultPageSettings.SetHdevmode(devModeData); GlobalFree(hDevMode); Marshal.FreeHGlobal(devModeData); } 

  • quand votre application a démarré:
    • avez-vous demandé au pilote d’imprimante la taille correcte de la structure DEVMODE avant de l’allouer?
    • Avez-vous demandé au pilote de périphérique d’initialiser le tampon DEVMODE avec les parameters par défaut après l’avoir alloué?
  • lorsque votre application ouvre la boîte de dialog de l’imprimante:
    • avez-vous défini les DM_IN_BUFFER et DM_OUT_BUFFER (en plus de DM_IN_PROMPT ) dans le paramètre fMode sur DocumentProperties ?
    • avez-vous pointé pDevModeInput et pDevModeOutput vers la mémoire tampon DEVMODE vous avez initialisée au démarrage de l’application?
    • les bits dmFields du tampon DEVMODE correctement définis avant l’appel de DocumentProperties(... DM_IN_PROMPT ...)
    • DocumentProperties(... DM_IN_PROMPT ...) vous le contenu du tampon DEVMODE entre les appels à DocumentProperties(... DM_IN_PROMPT ...) ?

Voir:

  • Comment modifier les parameters de l’imprimante avec la fonction DocumentProperties ()
  • Utilisation de la boîte de dialog Propriétés du document
  • la fonction DocumentProperties

Même si la réponse a fini par faire son chemin dans la question, je pense que ce qui suit fournit une meilleure réponse à la question initiale,

(1) Parce que cela ne modifie manifestement pas les PrinterSettings passés si l’utilisateur annule.

(2) Parce qu’il renvoie un DialogResult, qui intéressera probablement l’appelant.

 [DllImport("kernel32.dll")] static extern IntPtr GlobalLock(IntPtr hMem); [DllImport("kernel32.dll")] static extern bool GlobalUnlock(IntPtr hMem); [DllImport("kernel32.dll")] static extern bool GlobalFree(IntPtr hMem); [DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesW", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPWStr)] ssortingng pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode); private const int DM_PROMPT = 4; private const int DM_OUT_BUFFER = 2; private const int DM_IN_BUFFER = 8; private DialogResult EditPrinterSettings(PrinterSettings printerSettings) { DialogResult myReturnValue = DialogResult.Cancel; IntPtr hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings); IntPtr pDevMode = GlobalLock(hDevMode); int sizeNeeded = DocumentProperties(this.Handle, IntPtr.Zero, printerSettings.PrinterName, pDevMode, pDevMode, 0); IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded); long userChoice = DocumentProperties(this.Handle, IntPtr.Zero, printerSettings.PrinterName, devModeData, pDevMode, DM_IN_BUFFER | DM_PROMPT | DM_OUT_BUFFER); long IDOK = (long)DialogResult.OK; if (userChoice == IDOK) { myReturnValue = DialogResult.OK; printerSettings.SetHdevmode(devModeData); printerSettings.DefaultPageSettings.SetHdevmode(devModeData); } GlobalUnlock(hDevMode); GlobalFree(hDevMode); Marshal.FreeHGlobal(devModeData); return myReturnValue; } 

Si vous ciblez la compilation x86 et que vous l’exécutez à partir d’une machine x64, le code de Jeff Roe ne fonctionnera pas: lors de l’allocation de devModeData , DocumentPropreties échouera toujours et retournera une sizeNeeded -1, avec un code LastError 13.

Pour résoudre le problème, assurez-vous de cibler AnyCPU ou modifiez simplement l’appel en DocumentPropreties comme suit:

 int sizeNeeded = DocumentProperties(pHandle, IntPtr.Zero, printerSettings.PrinterName, IntPtr.Zero, // This solves it pDevMode, fMode); 

L’utilisation de IntPtr.Zero au lieu d’un pointeur approprié sur une structure DevMode semble incorrecte, mais le premier appel à DocumentProperties ne tente pas de modifier la mémoire à cet emplacement. La seule donnée renvoyée par l’appel est la taille de la mémoire nécessaire pour stocker les données en mode périphérique représentant les parameters internes du pilote d’imprimante.

Référence:

  • Page PInvoke.Net sur DocumentProperties

De plus, si vous souhaitez utiliser des classes WPF (PrintQueue, PrintTicket), cette page vous indique la direction à suivre:

http://social.msdn.microsoft.com/Forums/en/wpf/thread/0dc695c1-578d-4da5-8f68-b2a257846c02