Pergunta

Nós temos um app com alguma impressora de legado de código "setup" que ainda estamos usando PrintDlg para. Nós usamos um modelo personalizado para permitir que o usuário selecione a impressora a usar vários tipos de impressão de tarefas (tais como relatórios ou desenhos), juntamente com a orientação e tamanho do papel / fonte.

Ele funciona em XP e Vista 32-bit, mas no Vista x64 fica um CDERR_MEMLOCKFAILURE via CommDlgExtendedError(). Eu tentei executá-lo com apenas a entrada de esqueleto na estrutura PRINTDLG, mas se os parâmetros incluem PD_PRINTSETUP ou PD_RETURNDEFAULT, eu recebo esse erro.

Uma vez que a configuração de seleção de impressora / página foi dividido em PageSetupDlg e PrintDlgEx, não há transição fácil aparente sem alterar uma quantidade razoável de código e / ou mudar completamente a forma como presente de impressão ea impressora de configuração para o usuário.

Alguém viu esse problema em 64-bit Vista, e você encontrou quaisquer soluções alternativas?

Notas:
aplicativo é executado como administrador devido a outras restrições

Foi útil?

Solução

Eu encontrei um post relacionado nos fóruns da Microsoft: No Vista x64 , DocumentProperties falha do processo UAC-elevado

eu tenho verificado com um programa de exemplo que PrintDlg funcionando como obras não-administrador.

Outras dicas

Eu encontrei um post no fórum Quicken Comunidade: Solução de Problemas de impressão Vista 64 Quicken 2008 , eo FAQ relacionada: e se eu sou incapaz de imprimir, ou receber "Erro na comunicação com impressora"? ea recomendação para usar uma impressora de emulação.

Eu apenas corri para este problema como eu estava adicionando imprimir para meu aplicativo. Eu estava usando a classe PrintDialog e ele funciona muito bem se ele é compilado como um aplicativo de 32 bits, mas nem sequer aparecer quando compilado no modo de 64 bits. Nenhuma mensagem de erro, sem nada. A chamada para ShowDialog apenas retorna imediatamente. (Note que estou executando 64-bit Vista.)

Eu tentei usar PrintDlg, mas que tem o mesmo problema. Eu olhei em linha e encontrei um monte de pessoas que estão tendo problemas semelhantes, embora, aparentemente, nem todo mundo que tem 64-bit Vista vê isso. De qualquer forma, eu finalmente decidi escrever a minha própria versão do PrintDialog (empréstimos de código on-line), mas este foi um pouco complicado (como parte do código on-line teve bugs) e desde que eu nunca encontrei um exemplo completo on-line para isso, pensei Eu ia postar a minha solução aqui.

Note, minhas folhas de versão algumas coisas fora da caixa de diálogo, como o "Intervalo de impressão", "Cópias", e "Imprimir para arquivo". Isso deve ser fácil para adicionar mas meu aplicativo não precisa deles. Eu também não conseguia descobrir o que o "Tipo:". Campo foi exibindo então eu deixei para fora também

Aqui está o que os olhares de diálogo como:

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

E aqui está o meu código (eu deixei o código do designer como ele deve ser muito fácil para recriar):

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top