Mit PrintDlg auf Vista x64 nicht funktioniert, funktioniert auf 32-Bit und XP
-
08-07-2019 - |
Frage
Wir haben eine App mit einigem Legacy-Drucker „setup“ Code bekommen, dass wir noch PrintDlg
verwenden für. Wir verwenden ein eigenes Template dem Benutzer zu ermöglichen, auszuwählen, welche Drucker für verschiedene Arten von Druckaufgaben zu verwenden (wie Berichte oder Zeichnungen) zusammen mit Orientierung und Papierformat / Quelle.
Es funktioniert auf XP und 32-Bit-Vista, aber auf Vista x64 es wird ein CDERR_MEMLOCKFAILURE
über CommDlgExtendedError()
. Ich habe versucht, es nur mit dem nackten Knochen Eingang in der PRINTDLG
Struktur ausgeführt wird, aber wenn die Parameter PD_PRINTSETUP
oder PD_RETURNDEFAULT
umfassen, bekomme ich diesen Fehler.
Da der Druckerauswahl / Seite-Setup wird in PageSetupDlg
und PrintDlgEx
aufgeteilt worden ist, ist es kein offensichtlicher einfacher Übergang ohne eine angemessene Menge an Code zu ändern und / oder zu ändern vollständig, wie wir präsentieren Drucke und Druckerkonfiguration für den Benutzer.
Hat jemand dieses Problem auf 64-Bit-Vista gesehen, und haben festgestellt, Sie Workarounds?
Weitere Informationen:
Anwendung läuft als Administrator aufgrund anderer Einschränkungen
Lösung
Ich fand einen ähnlichen Beitrag auf den Microsoft-Foren: auf Vista x64 , DocumentProperties nicht von UAC-Prozess erhöht
ich mit einem Beispielprogramm überprüft habe, die PrintDlg als Nicht-Admin-Arbeiten ausgeführt werden.
Andere Tipps
fand ich einen Beitrag auf dem Quicken Community-Forum: Lösung zu Druckproblemen Vista 64 Quicken 2008 , und die damit verbundenen FAQ: Was passiert, wenn ich nicht in der Lage zu drucken, oder empfangen "Fehler mit dem Drucker zu kommunizieren"? und die Empfehlung einen Emulationsdrucker verwendet werden.
Ich lief in dieses Problem, da ich den Druck meiner app Zugabe wurde. Ich wurde mit der Printdialog Klasse und es funktioniert super, wenn sie als 32-Bit-Anwendung kompiliert wird, ist aber nicht einmal Pop-up, wenn sie in 64-Bit-Modus kompiliert. Keine Fehlermeldungen, kein gar nichts. Der Aufruf von Showdialog gibt nur sofort. (Beachten Sie, dass ich 64-Bit-Vista leite.)
Ich habe versucht PrintDlg verwenden, aber das hat das gleiche Problem. Ich sah online und eine Menge Leute fanden wir ähnliche Probleme haben, wenn auch offenbar nicht jeder, der diese 64-Bit-Vista sieht hat. Wie dem auch sei, entschied ich mich schließlich meine eigene Version von Printdialog (Anleihen von Code online) zu schreiben, aber das war ein bisschen schwierig (wie einige der Online-Code Bugs hatte) und da ich nie ein vollständiges Beispiel online diese gefunden haben, dachte ich, ich würde meine Lösung hier posten.
Beachten Sie, meine Version läßt ein paar Dinge aus dem Dialog, wie der „Druckbereich“, „Kopien“ und „Print to file“. Dies sollte einfach hinzufügen, aber meine app habe sie nicht brauchen. Ich kann auch nicht herausfinden, was der „Typ:“. Feld anzeigte, damit ich es auch weggelassen
Hier ist, was der Dialog wie folgt aussieht:
alt text http://www.geocities.com/deancooper2000/PrintDialog64.jpg
Und hier ist mein Code (ich den Designer-Code verlassen haben, wie es recht einfach sein sollte, neu):
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;
}
}
}