Pregunta

Tenemos una aplicación con alguna impresora heredada '' configuración '' código que todavía estamos usando PrintDlg para. Utilizamos una plantilla personalizada para permitir al usuario seleccionar qué impresora usar para varios tipos de tareas de impresión (como informes o dibujos) junto con la orientación y el tamaño / fuente del papel.

Funciona en XP y Vista de 32 bits, pero en Vista x64 obtiene un CDERR_MEMLOCKFAILURE a través de CommDlgExtendedError () . Intenté ejecutarlo solo con la entrada básica en la estructura PRINTDLG , pero si los parámetros incluyen PD_PRINTSETUP o PD_RETURNDEFAULT , obtengo ese error.

Dado que la selección de impresora / configuración de página se ha dividido en PageSetupDlg y PrintDlgEx , no hay una transición fácil aparente sin cambiar una buena cantidad de código y / o cambiar completamente cómo presentamos la impresión y la configuración de la impresora al usuario.

¿Alguien ha visto este problema en Vista de 64 bits y ha encontrado alguna solución?

Notas:
La aplicación se ejecuta como administrador debido a otras restricciones

¿Fue útil?

Solución

Encontré una publicación relacionada en los foros de Microsoft: En Vista x64 , DocumentProperties falla del proceso elevado por UAC

He verificado con un programa de muestra que PrintDlg se ejecuta como trabajos no administrativos.

Otros consejos

Encontré una publicación en el foro de la Comunidad Quicken: Solución de problemas de impresión Vista 64 Quicken 2008 , y las preguntas frecuentes relacionadas: ¿Qué sucede si no puedo imprimir o recibir " Error de comunicación con la impresora " ;? y el recomendación de usar una impresora de emulación.

Acabo de encontrarme con este problema al agregar la impresión a mi aplicación. Estaba usando la clase PrintDialog y funciona muy bien si se compila como una aplicación de 32 bits, pero ni siquiera aparece cuando se compila en modo de 64 bits. No hay mensajes de error, no hay nada. La llamada a ShowDialog simplemente regresa de inmediato. (Tenga en cuenta que estoy ejecutando Vista de 64 bits).

Intenté usar PrintDlg, pero eso tiene el mismo problema. Busqué en línea y encontré a muchas personas con problemas similares, aunque aparentemente no todos los que tienen Vista de 64 bits ven esto. De todos modos, finalmente decidí escribir mi propia versión de PrintDialog (tomando prestado del código en línea), pero esto fue un poco complicado (ya que algunos de los códigos en línea tenían errores) y como nunca encontré un ejemplo completo en línea para esto, pensé Publicaría mi solución aquí.

Tenga en cuenta que mi versión deja algunas cosas fuera del cuadro de diálogo, como "Intervalo de impresión", "Copias" e "Imprimir en archivo". Esto debería ser fácil de agregar, pero mi aplicación no los necesitaba. Tampoco pude averiguar cuál es el " Tipo: " se estaba visualizando el campo, así que también lo omití.

Así es como se ve el diálogo:

texto alternativo http://www.geocities.com/deancooper2000/PrintDialog64.jpg

Y aquí está mi código (he dejado el código del diseñador ya que debería ser bastante fácil de recrear):

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;
    }
}
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top