2008-11-12 9 views
2

Nous avons une application avec un code d'installation de l'ancienne imprimante que nous utilisons encore PrintDlg pour. Nous utilisons un modèle personnalisé pour permettre à l'utilisateur de sélectionner l'imprimante à utiliser pour différents types de tâches d'impression (tels que des rapports ou des dessins) ainsi que l'orientation et la taille/source du papier. Il fonctionne sur XP et Vista 32 bits, mais sur Vista x64 il obtient un CDERR_MEMLOCKFAILURE via CommDlgExtendedError(). J'ai essayé de l'exécuter avec seulement l'entrée bare-bones dans la structure PRINTDLG, mais si les paramètres incluent PD_PRINTSETUP ou PD_RETURNDEFAULT, j'obtiens cette erreur. Depuis la sélection de l'imprimante/la mise en page a été divisé en PageSetupDlg et PrintDlgEx, il n'y a pas de transition facile apparente sans changer une bonne quantité de code et/ou changer complètement comment nous présentons l'impression et la configuration de l'imprimante à l'utilisateur.Utiliser PrintDlg sur Vista x64 ne fonctionne pas, fonctionne bien sur 32 bits et XP

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

Notes:
application fonctionne en tant qu'administrateur en raison d'autres contraintes

Répondre

0

J'ai juste rencontré ce problème pendant que j'ajoutais l'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 messages d'erreur, pas de rien. L'appel à ShowDialog revient juste immédiatement. (Notez que je suis en cours d'exécution Vista 64 bits.)

J'ai essayé d'utiliser PrintDlg, mais cela a le même problème. J'ai regardé en ligne et trouvé beaucoup de gens que nous avons des problèmes similaires, mais apparemment tout le monde qui a 64 bits Vista voit cela. Quoi qu'il en soit, j'ai finalement décidé d'écrire ma propre version de PrintDialog (empruntant au code en ligne), mais c'était un peu compliqué (comme certains codes en ligne avaient des bugs) et comme je n'ai jamais trouvé d'exemple complet en ligne, j'ai pensé Je posterais ma solution ici.

Note, ma version laisse quelques choses hors de la boîte de dialogue, comme la "gamme d'impression", "Copies", et "Imprimer dans un fichier". Cela devrait être facile à ajouter, mais mon application n'en avait pas besoin. Je ne pouvais pas non plus comprendre ce que le champ "Type:" affichait, donc je l'ai laissé de côté.

Voici ce que la boîte de dialogue ressemble à:

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

Et voici mon code (je l'ai quitté le code de concepteur comme 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; 
    } 
} 
} 
Questions connexes