2010-03-13 9 views
7

EDIT: Meine Schuld! Ich erwartete, dass die Änderungen auf die Standarddruckereinstellungen zurückgeschrieben werden, wenn tatsächlich nur die lokale Instanz der PrinterSettings geändert wird. - Der folgende Code scheint wie vorgesehen zu funktionierenWie Druckereigenschaften/Präferenzen Dialog zeigen und Änderungen speichern?

Ich versuche, die benutzerdefinierten Druckereigenschaften eines bestimmten Druckers anzuzeigen. Ich brauche das als Teil eines benutzerdefinierten PrintDialogs, den ich versuche zu schreiben.

Die meisten der Beispiele, die ich online finden kann, verwalten den Dialog, aber alle Änderungen, die der Benutzer macht, gehen verloren, was ihn nutzlos macht.

Beispiel: http://www.codeproject.com/KB/system/PrinterPropertiesWindow.aspx

(in Bezug auf oben Seite: Ich habe versucht, den Code zu ändern, wie durch BartJoy (auf der Seite vorgeschlagen), aber das hat es nicht fix)

Ich habe auch versucht die Probe und Vorschläge auf der pinvoke.net Seite, aber es funktioniert immer noch nicht:

http://www.pinvoke.net/default.aspx/winspool.documentproperties

Aus den oben genannten Websites ich gehe davon aus, dass das Problem nur auf 64-Bit-Windows-a sein könnte nd oder wenn ein Druckername länger als 32 Zeichen ist.

Ich weiß nicht, was ich als nächstes versuchen sollte ... Ich freue mich über Vorschläge und Kommentare!

EDIT: Hier ist, was ich versucht habe:

[DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesW", SetLastError = true, 
ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] 
static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, 
     [MarshalAs(UnmanagedType.LPWStr)] string pDeviceName, 
     IntPtr pDevModeOutput, IntPtr pDevModeInput, 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")] 
static extern IntPtr GlobalLock(IntPtr hMem); 
[DllImport("kernel32.dll")] 
static extern bool GlobalUnlock(IntPtr hMem); 
[DllImport("kernel32.dll")] 
static extern bool GlobalFree(IntPtr hMem); 

private const int DM_PROMPT = 4; 
private const int DM_OUT_BUFFER = 2; 
private const int DM_IN_BUFFER = 8; 

private void OpenPrinterPropertiesDialog() 
{ 
    var printerSettings = new System.Drawing.Printing.PrinterSettings(); 
    var printerName = printerSettings.PrinterName; 

    IntPtr handle; 
    OpenPrinter(printerName, out handle, IntPtr.Zero); 

    IntPtr hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings); 
    IntPtr pDevMode = GlobalLock(hDevMode); 
    int sizeNeeded = DocumentProperties(this.Handle, handle, printerName, pDevMode, pDevMode, 0); 
    IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded); 
    DocumentProperties(this.Handle, handle, printerName, devModeData, pDevMode, DM_IN_BUFFER | DM_PROMPT | DM_OUT_BUFFER); 

    ClosePrinter(handle); 
    GlobalUnlock(hDevMode); 

    printerSettings.SetHdevmode(devModeData); 
    printerSettings.DefaultPageSettings.SetHdevmode(devModeData); 

    GlobalFree(hDevMode); 
    Marshal.FreeHGlobal(devModeData); 
} 

ich die Open und Closeprinter Methode zu verwenden, haben versucht, und die devModeData als Ausgabeparameter in der zweiten Aufforderung übergeben, wie ich es, dass die ursprüngliche seltsam gefunden Code aus dem pinvoke.net hat das nicht gemacht. (Aber ich gebe zu, dass ich nicht weiß, was ich tue - das ist nur Versuch und Irrtum).

Hier ist der ursprüngliche Code aus der pinvoke Website:

private void OpenPrinterPropertiesDialog(PrinterSettings printerSettings) 
{ 
    IntPtr hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings); 
    IntPtr pDevMode = GlobalLock(hDevMode); 
    int sizeNeeded = DocumentProperties(this.Handle, IntPtr.Zero, printerSettings.PrinterName, pDevMode, pDevMode, 0); 
    IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded); 
    DocumentProperties(this.Handle, IntPtr.Zero, printerSettings.PrinterName, IntPtr.Zero, pDevMode, 14); 
    GlobalUnlock(hDevMode); 
    printerSettings.SetHdevmode(devModeData); 
    printerSettings.DefaultPageSettings.SetHdevmode(devModeData); 
    GlobalFree(hDevMode); 
    Marshal.FreeHGlobal(devModeData); 
} 
+0

Und wie haben Sie den chages wieder gerettet werden verwaltet? Dieser Code ändert die printerSettings, aber die Änderungen werden nicht als die Standarddruckereinstellungen gespeichert :( – Ando

Antwort

3
  • , wenn die Anwendung gestartet:
    • haben Sie die Druckertreiber für die korrekte Größe der DEVMODE Struktur abgefragt, bevor die Zuweisung es?
    • haben Sie den Gerätetreiber gebeten, den Puffer DEVMODE mit den Standardeinstellungen zu initialisieren, nachdem Sie ihn zugewiesen haben?
  • , wenn die Anwendung öffnete den Druckerdialog auf:
    • haben legen Sie die DM_IN_BUFFER und DM_OUT_BUFFER Flags (zusätzlich zu DM_IN_PROMPT) im fMode Parameter DocumentProperties?
    • Haben Sie sowohl pDevModeInput als auch pDevModeOutput auf den Puffer DEVMODE gerichtet, den Sie beim Start der Anwendung initialisiert haben?
    • sind die dmFields Bits im DEVMODE Puffer richtig vor auf Ihre DocumentProperties(... DM_IN_PROMPT ...)
    • nennend Sie den Inhalt des DEVMODE Puffer zwischen Anrufe DocumentProperties(... DM_IN_PROMPT ...) Erhaltung?

See:

+0

danke für die Eingabe. Ich glaube, dass ich diese Dinge tun. Ich habe die Frage aktualisiert und enthalten den Code, den ich ausprobiert habe. –

+0

meine Schuld ! Ich erwartete, dass die Änderungen in die Standarddruckereinstellungen zurückgeschrieben werden, so dass, wenn ich dieselbe Methode mit einer neuen PrinterSettings() aufrufen würde, die vergangenen Änderungen widerspiegeln - Es scheint, dass alles korrekt funktioniert, da die printerSettings aktualisiert werden richtig. –

7

Auch wenn die Antwort Arbeits landete seinen Weg in die Frage, denke ich, die folgenden eine bessere Antwort auf die ursprüngliche Frage stellt,

(1) Da es sich eindeutig nicht ändern die übergebenen PrinterSettings, wenn der Benutzer abbricht.

(2) Weil es ein Dialogresult zurückgibt, die der Anrufer wird wahrscheinlich interessieren

[DllImport("kernel32.dll")] 
static extern IntPtr GlobalLock(IntPtr hMem); 
[DllImport("kernel32.dll")] 
static extern bool GlobalUnlock(IntPtr hMem); 
[DllImport("kernel32.dll")] 
static extern bool GlobalFree(IntPtr hMem); 
[DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesW", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)] 
static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPWStr)] string pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode); 

private const int DM_PROMPT = 4; 
private const int DM_OUT_BUFFER = 2; 
private const int DM_IN_BUFFER = 8; 

private DialogResult EditPrinterSettings(PrinterSettings printerSettings) 
{ 
    DialogResult myReturnValue = DialogResult.Cancel; 
    IntPtr hDevMode = printerSettings.GetHdevmode(printerSettings.DefaultPageSettings); 
    IntPtr pDevMode = GlobalLock(hDevMode); 
    int sizeNeeded = DocumentProperties(this.Handle, IntPtr.Zero, printerSettings.PrinterName, pDevMode, pDevMode, 0); 
    IntPtr devModeData = Marshal.AllocHGlobal(sizeNeeded); 
    long userChoice = DocumentProperties(this.Handle, IntPtr.Zero, printerSettings.PrinterName, devModeData, pDevMode, DM_IN_BUFFER | DM_PROMPT | DM_OUT_BUFFER); 
    long IDOK = (long)DialogResult.OK; 
    if (userChoice == IDOK) 
    { 
     myReturnValue = DialogResult.OK; 
     printerSettings.SetHdevmode(devModeData); 
     printerSettings.DefaultPageSettings.SetHdevmode(devModeData); 
    } 
    GlobalUnlock(hDevMode); 
    GlobalFree(hDevMode); 
    Marshal.FreeHGlobal(devModeData); 
    return myReturnValue; 
} 
+0

@ JeffRow Ich habe gerade den Code versucht, den Sie auf einer Win8 64-Bit-Maschine und DocumentProperties zur Verfügung gestellt -1 zurück und daher, wenn Marshal.AllocHGlobal (sizeNeeded) wird aufgerufen, es wird ein Fehler ausgegeben "Nicht genügend Speicher, um die Ausführung des Programms fortzusetzen". was sinnvoll ist, da die Größe benötigt -1 ist. – Thierry

+1

Während es in einem frühen Stadium ist, scheint dies der stabilste Code zu sein, den ich bisher gefunden habe, um mein Problem zu lösen. Die einzige kleine Änderung basierend auf meinem vorherigen Kommentar ist, dass, um die Größe benötigt zu erhalten, müssen Sie den API-Aufruf zu einem IntPtr.Zero anstelle einer 0 zu ändern, dh Dim sizeNeeded As Integer = DocumentProperties (Me.Handle, IntPtr.Zero , printerSettings.PrinterName, IntPtr.Zero, pDevMode, 0). Danke für das Teilen! – Thierry

7

Wenn Sie x86 Kompilierung und laufen von einer x64-Maschine Ziel, wird der Code von Jeff Roe nicht.: wenn devModeData Zuweisung wird DocumentPropreties immer fehl und gibt eine sizeNeeded von -1, mit einem LastError Code 13.

das Problem zu lösen, entweder stellen Sie sicher, AnyCPU oder einfach nur den Anruf ändern DocumentPropreties auf das Ziel Folgende:

int sizeNeeded = DocumentProperties(pHandle, 
            IntPtr.Zero, 
            printerSettings.PrinterName, 
            IntPtr.Zero, // This solves it 
            pDevMode, 
            fMode); 

Mit IntPtr.Zero anstelle einem richtigen Zeiger auf eine DevMode Struktur sieht falsch, aber der erste Aufruf DocumentProperties versucht nicht, den Speicher an dieser Position zu ändern. Die einzigen vom Aufruf zurückgegebenen Daten sind die Speichergröße, die zum Speichern der Gerätemodusdaten benötigt wird, die die internen Parameter des Druckertreibers darstellen.

Referenz:

Verwandte Themen