2008-11-12 7 views
2

У нас есть приложение с некоторым устаревшим «установочным» кодом принтера, который мы все еще используем для PrintDlg. Мы используем настраиваемый шаблон, чтобы пользователь мог выбрать, какой принтер использовать для различных задач печати (например, отчетов или рисунков), а также ориентации и размера или источника бумаги.Использование PrintDlg на Vista x64 не работает, отлично работает на 32 бит и XP

Он работает на XP и 32-битной Vista, но на Vista x64 он получает CDERR_MEMLOCKFAILURE через CommDlgExtendedError(). Я попытался запустить его с помощью только голых костей в структуре PRINTDLG, но если параметры включают PD_PRINTSETUP или PD_RETURNDEFAULT, я получаю эту ошибку.

Поскольку выбор принтера/настройка страницы был разделен на PageSetupDlg и PrintDlgEx, нет очевидного легкого перехода без изменения достаточного количества кода и/или полного изменения того, как мы представляем печать и настройку принтера для пользователя.

Неужели кто-нибудь видел эту проблему на 64-битной Vista и нашли ли вы какие-нибудь работы?

Примечание:
приложение работает в качестве администратора из-за другие ограничения

ответ

0

Я просто столкнулся с этой проблемой, поскольку добавляю печать в свое приложение. Я использовал класс PrintDialog, и он отлично работает, если он скомпилирован как 32-битное приложение, но даже не появляется при компиляции в 64-разрядном режиме. Нет сообщений об ошибках, ничего. Вызов ShowDialog сразу возвращается. (Обратите внимание, что я запускаю 64-разрядную версию Vista.)

Я попытался использовать PrintDlg, но у этой проблемы есть такая же проблема. Я смотрел онлайн и обнаружил, что у нас схожие проблемы, хотя, видимо, не все, у кого 64-битная Vista, видят это. Во всяком случае, я, наконец, решил написать свою собственную версию PrintDialog (заимствование из кода онлайн), но это было немного сложно (поскольку некоторые из онлайновых кодов имели ошибки), и так как я никогда не нашел для этого полного примера онлайн, я подумал Я бы разместил свое решение здесь.

Обратите внимание: моя версия оставляет несколько вещей из диалогового окна, например, «Диапазон печати», «Копии» и «Печать в файл». Это должно быть легко добавить, но мое приложение не нуждалось в них. Я также не мог понять, что отображало поле «Тип:», поэтому я тоже оставил его.

Вот что диалог выглядит следующим образом:

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

И вот мой код (я оставил код дизайнера, как это должно быть довольно легко воссоздать):

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; 
    } 
} 
}