Domanda

Abbiamo un'app con alcune stampanti legacy " setup " codice che stiamo ancora utilizzando PrintDlg per. Utilizziamo un modello personalizzato per consentire all'utente di selezionare quale stampante utilizzare per vari tipi di attività di stampa (come report o disegni) insieme all'orientamento e al formato / origine della carta.

Funziona su XP e Vista a 32 bit, ma su Vista x64 ottiene un CDERR_MEMLOCKFAILURE tramite CommDlgExtendedError () . Ho provato a eseguirlo solo con l'input bare-bones nella struttura PRINTDLG , ma se i parametri includono PD_PRINTSETUP o PD_RETURNDEFAULT , ottengo quell'errore.

Poiché la selezione della stampante / impostazione della pagina è stata suddivisa in PageSetupDlg e PrintDlgEx , non vi è alcuna transizione apparente facile senza cambiare una buona quantità di codice e / o cambiare completamente il modo in cui presentiamo all'utente la stampa e la configurazione della stampante.

Qualcuno ha visto questo problema su Vista a 64 bit e hai trovato qualche soluzione?

Note:
L'applicazione funziona come amministratore a causa di altri vincoli

È stato utile?

Soluzione

Ho trovato un post correlato nei forum di Microsoft: Su Vista x64 , DocumentProperties non riesce a causa di un processo UAC elevato

Ho verificato con un programma di esempio che PrintDlg funziona come non amministratore.

Altri suggerimenti

Ho trovato un post sul forum di Quicken Community: Soluzione ai problemi di stampa Vista 64 Quicken 2008 e le relative FAQ: Cosa succede se non riesco a stampare o ricevere " Errore di comunicazione con la stampante " ;? e il raccomandazione di utilizzare una stampante di emulazione.

Ho riscontrato questo problema durante l'aggiunta della stampa alla mia app. Stavo usando la classe PrintDialog e funziona benissimo se è compilata come un'app a 32 bit, ma non compare nemmeno quando viene compilata in modalità a 64 bit. Nessun messaggio di errore, niente di niente. La chiamata a ShowDialog ritorna immediatamente. (Nota che sto eseguendo Vista a 64 bit.)

Ho provato ad usare PrintDlg, ma questo ha lo stesso problema. Ho guardato online e ho trovato molte persone con problemi simili, sebbene apparentemente non tutti quelli che hanno Vista a 64 bit lo vedono. Ad ogni modo, ho finalmente deciso di scrivere la mia versione di PrintDialog (prendendo in prestito dal codice online), ma questo è stato un po 'complicato (dato che alcuni dei codici online avevano dei bug) e dato che non ho mai trovato un esempio completo online per questo, ho pensato Pubblicherei la mia soluzione qui.

Nota, la mia versione lascia alcune cose fuori dalla finestra di dialogo, come "Intervallo di stampa", "" Copie ", e" Stampa su file ". Questo dovrebbe essere facile da aggiungere ma la mia app non ne aveva bisogno. Inoltre, non sono riuscito a capire quale sia il "Tipo: " il campo veniva visualizzato, quindi l'ho lasciato fuori anch'io.

Ecco come appare la finestra di dialogo:

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

Ed ecco il mio codice (ho lasciato fuori il codice del designer in quanto dovrebbe essere abbastanza facile da ricreare):

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;
    }
}
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top