L'utilisation de PrintDlg sur Vista x64 ne fonctionne pas, fonctionne correctement sur 32 bits et XP

StackOverflow https://stackoverflow.com/questions/285482

Question

Nous avons une application avec une imprimante héritée "Configuration". code que nous utilisons toujours PrintDlg pour. Nous utilisons un modèle personnalisé pour permettre à l'utilisateur de sélectionner l'imprimante à utiliser pour divers types de tâches d'impression (tels que les rapports ou les dessins), ainsi que l'orientation et le format / source du papier.

Cela fonctionne sous XP et Vista 32 bits, mais sous Vista x64, il reçoit un CDERR_MEMLOCKFAILURE via CommDlgExtendedError () . J'ai essayé de l'exécuter avec uniquement l'entrée nue dans la structure PRINTDLG , mais si les paramètres incluent PD_PRINTSETUP ou PD_RETURNDEFAULT , j'obtiens cette erreur.

La sélection de l'imprimante et la mise en page ayant été divisées en PageSetupDlg et PrintDlgEx , il n’ya apparemment pas de transition facile sans une grande quantité de code et / ou une modification complète de la manière dont nous présentons l'impression et la configuration de l'imprimante à l'utilisateur.

Quelqu'un at-il déjà vu ce problème sous Vista 64 bits et avez-vous trouvé des solutions de rechange?

Remarques:
L'application s'exécute en tant qu'administrateur en raison d'autres contraintes

Était-ce utile?

La solution

J'ai trouvé un article lié sur les forums Microsoft: sur Vista x64. , DocumentProperties échoue à partir d'un processus élevé par le contrôle de compte d'utilisateur

.

J'ai vérifié, à l'aide d'un exemple de programme, que PrintDlg exécuté en tant que non-administrateur fonctionne.

Autres conseils

J'ai trouvé un article sur le forum de la communauté Quicken: Solution aux problèmes d'impression de Vista 64 Quicken 2008 et la FAQ connexe: Que se passe-t-il si je ne parviens pas à imprimer ou à recevoir une" Erreur de communication avec l'imprimante "et ? recommandation d’utiliser une imprimante à émulation.

Je viens de rencontrer ce problème alors que j'ajoutais une impression à mon application. J'utilisais la classe PrintDialog et cela fonctionne très bien si elle est compilée en tant qu'application 32 bits, mais ne s'affiche même pas lorsqu'elle est compilée en mode 64 bits. Pas de message d'erreur, pas de rien. L'appel à ShowDialog revient immédiatement. (Notez que j'utilise Vista 64 bits.)

J'ai essayé d'utiliser PrintDlg, mais cela pose le même problème. J'ai regardé en ligne et j'ai constaté que beaucoup de gens rencontraient des problèmes similaires, même si, apparemment, tous ceux qui utilisent Vista 64 bits ne le voient pas. Quoi qu’il en soit, j’ai finalement décidé d’écrire ma propre version de PrintDialog (emprunt de code en ligne), mais c’était un peu délicat (car certains codes en ligne contenaient des bugs) et comme je n’avais jamais trouvé d’exemple complet en ligne, je pensais Je posterais ma solution ici.

Remarque, ma version laisse quelques éléments en dehors de la boîte de dialogue, tels que les "plages d'impression", "Copies" et "Imprimer dans un fichier". Cela devrait être facile à ajouter, mais mon application n'en a pas besoin. Je ne pouvais pas non plus comprendre ce que le & type; Type: " champ affichait donc je l'ai laissé ainsi.

Voici à quoi ressemble le dialogue:

texte alt http://www.geocities.com/deancooper2000/PrintDialog64.jpg

Et voici mon code (j'ai laissé le code du concepteur car il devrait être assez facile à recréer):

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.Printing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Zemetrics.Diagnostics;

namespace Utils
{
/// <summary>
/// The PrintDialog64 class replaces the standard PrintDialog with one that works in Vista x64
/// </summary>
public partial class PrintDialog64 : Form
{
    #region Private members 
    [DllImport("winspool.drv", EntryPoint="DocumentPropertiesW")]
    private static extern int DocumentProperties(IntPtr hWnd,IntPtr hPrinter,[MarshalAs(UnmanagedType.LPWStr)] string pDeviceName,IntPtr pDevMode,IntPtr devModeIn,int fMode);

    [DllImport("winspool.drv")] private static extern int    OpenPrinter(string pPrinterName,out IntPtr hPrinter,IntPtr pDefault);
    [DllImport("winspool.drv")] private static extern int    ClosePrinter(IntPtr phPrinter);
    [DllImport("kernel32.dll")] private static extern IntPtr GlobalLock(IntPtr hMem);
    [DllImport("kernel32.dll")] private static extern int    GlobalUnlock(IntPtr hMem);
    [DllImport("kernel32.dll")] private static extern int    GlobalFree(IntPtr hMem);

    private const int DM_PROMPT     = 4;
    private const int DM_OUT_BUFFER = 2;
    private const int DM_IN_BUFFER  = 8;

    private List<PrinterItem> printers;
    private string            printerName;
    private string            originalName;
    private IntPtr            hDevMode = IntPtr.Zero;
    #endregion

    /// <summary>
    /// Gets or sets the printer that prints the document       
    /// </summary>
    public PrinterSettings PrinterSettings { get; set; }

    /// <summary>
    /// Gets or sets a value indicating the PrintDocument used to obtain PrinterSettings.       
    /// </summary>
    public PrintDocument Document { get; set; }

    /// <summary>
    /// Constructs a replacement for the standard PrintDialog with one that works in Vista x64
    /// </summary>
    public PrintDialog64()
    {
        InitializeComponent();
    }

    #region PrinterItem class
    /// <summary>
    /// The PrinterItem class holds a reference to a PrintQueue and allows us to sort a list based on printer name
    /// </summary>
    private class PrinterItem : IComparable<PrinterItem>
    {
        #region Private members
        private PrinterItem() {}
        #endregion

        /// <summary>
        /// Construct a PrinterItem by supplying a reference to the printer's PrintQueue class
        /// </summary>
        ///
        /// \param[in]  printer Reference to PrintQueue class for this printer
        public PrinterItem(PrintQueue printer)
        {
            Printer = printer;
        }

        /// <summary>
        /// Reference to PrintQueue class for this printer
        /// </summary>
        public PrintQueue Printer { get; set; }

        /// <summary>
        /// The string for this class is simply the FullName of the printer
        /// </summary>
        public override string ToString()
        {
            return Printer.FullName;
        }

        #region IComparable<PrinterItem> Members
        /// <summary>
        /// Implements IComparable interface to allow sorting of PrinterItem classes (based on printer name)
        /// </summary>
        ///
        /// \param[in]  other The other PrinterItem class that we are to compare this one to
        public int CompareTo(PrinterItem other)
        {
            return other.Printer.FullName.CompareTo(this.Printer.FullName);
        }
        #endregion
    }
    #endregion

    private List<PrinterItem> GetPrinters()
    {
        List<PrinterItem> printers = new List<PrinterItem>();

        EnumeratedPrintQueueTypes[] Queue_types = {EnumeratedPrintQueueTypes.Local,EnumeratedPrintQueueTypes.Connections};

        try {
            using (LocalPrintServer server = new LocalPrintServer())
                foreach (PrintQueue printer in server.GetPrintQueues(Queue_types))
                    printers.Add(new PrinterItem(printer));                 
            } catch {}

        printers.Sort();
        return printers;                
    }

    private void PrintDialog64_Shown(object sender, EventArgs e)
    {
        originalName = Document.PrinterSettings.PrinterName;
        printers     = GetPrinters();
        int index=0, i=0;

        foreach(PrinterItem printer in printers) {
            nameComboBox.Items.Add(printer.ToString());

            if (printer.ToString() == originalName) index = i;
            i++;
            }

        nameComboBox.SelectedIndex = index;
    }

    private void nameComboBox_Leave(object sender, EventArgs e)
    {
        string text = nameComboBox.Text;

        foreach(Object field in nameComboBox.Items)
            if (((string) field).ToLower().StartsWith(text.ToLower())) nameComboBox.SelectedItem = field;

        if (nameComboBox.SelectedIndex < 0)
            nameComboBox.SelectedIndex = 0;
    }

    private void nameComboBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        PrintQueue printer = printers[nameComboBox.SelectedIndex].Printer;

        if (hDevMode!=IntPtr.Zero) GlobalFree(hDevMode);

        PrinterSettings.PrinterName = printerName = printer.FullName;
        hDevMode                    = PrinterSettings.GetHdevmode(Document.DefaultPageSettings);            

        statusValue .Text = printer.QueueStatus.ToString()=="None" ? "Ready" : printer.QueueStatus.ToString();
        whereValue  .Text = printer.Location=="" ? printer.QueuePort.Name : printer.Location;
        commentValue.Text = printer.Comment;
    }

    private void propertiesButton_Click(object sender, EventArgs e)
    {
        IntPtr handle;
        OpenPrinter(printerName, out handle, IntPtr.Zero);

        IntPtr pDevMode = GlobalLock( hDevMode );
        DocumentProperties(this.Handle, handle, printerName, pDevMode, pDevMode, DM_IN_BUFFER | DM_PROMPT | DM_OUT_BUFFER);
        GlobalUnlock( hDevMode );

        PrinterSettings.SetHdevmode( hDevMode );
        PrinterSettings.DefaultPageSettings.SetHdevmode( hDevMode );
        ClosePrinter(handle);
    }

    private void pageDefaultsButton_Click(object sender, EventArgs e)
    {
        PageSetupDialog setup = new PageSetupDialog(); 
        setup.PageSettings = Document.DefaultPageSettings;

        if (setup.ShowDialog() == DialogResult.OK) {
            if (hDevMode!=IntPtr.Zero) GlobalFree(hDevMode);

            hDevMode = PrinterSettings.GetHdevmode( Document.DefaultPageSettings = setup.PageSettings );
            }
    }

    private void okButton_Click(object sender, EventArgs e)
    {
        if (hDevMode!=IntPtr.Zero) GlobalFree(hDevMode);
    }

    private void cancelButton_Click(object sender, EventArgs e)
    {
        if (hDevMode!=IntPtr.Zero) GlobalFree(hDevMode);

        PrinterSettings.PrinterName = originalName;
    }
}
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top