[英]How to show printer properties/preferences dialog and save changes?
編輯:我的錯! 我希望在實際上只更改PrinterSettings的本地實例時,將更改寫回默認的打印機設置。 - 以下代碼似乎按預期工作
我試圖顯示給定打印機的自定義打印機屬性。 我需要這個作為我想寫的自定義PrintDialog的一部分。
我在網上找到的大多數示例都設法顯示對話框,但用戶可能做出的任何更改都會丟失,這使得它無用。
示例: http : //www.codeproject.com/KB/system/PrinterPropertiesWindow.aspx
(關於上面的頁面:我試圖改變BartJoy建議的代碼(在頁面上)但是沒有修復它)
我也嘗試過pinvoke.net頁面上的示例和建議,但它仍然不起作用:
http://www.pinvoke.net/default.aspx/winspool.documentproperties
從上面的網站我假設問題可能只在64位Windows上和/或如果打印機名稱超過32個字符。
我不知道接下來應該嘗試什么...我感謝任何建議和意見!
編輯:這是我嘗試過的:
[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);
}
我試圖使用OpenPrinter和ClosePrinter方法並在第二次調用中將devModeData作為輸出參數傳遞,因為我發現奇怪的是pinvoke.net的原始代碼沒有這樣做。 (但我承認,我不知道我在做什么 - 這只是反復試驗)。
以下是pinvoke網站的原始代碼:
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);
}
如果你定位x86編譯並從x64機器運行,那么來自Jeff Roe的代碼將不起作用:在分配devModeData
, DocumentPropreties
將始終失敗並返回sizeNeeded
為-1,其LastError
代碼為13。
要解決此問題,請確保將目標設為AnyCPU,或者只是將對DocumentPropreties
的調用更改為以下內容:
int sizeNeeded = DocumentProperties(pHandle,
IntPtr.Zero,
printerSettings.PrinterName,
IntPtr.Zero, // This solves it
pDevMode,
fMode);
使用IntPtr.Zero
而不是指向DevMode結構的正確指針看起來是錯誤的,但是對DocumentProperties的第一次調用不會嘗試修改該位置的內存。 調用返回的唯一數據是存儲表示打印驅動程序內部參數的設備模式數據所需的內存大小。
參考:
即使答案最終解決了問題,我認為以下內容為原始問題提供了更好的答案,
(1)因為如果用戶取消,它顯然不會修改傳入的PrinterSettings。
(2)因為它返回一個DialogResult,調用者可能會對此感興趣。
[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;
}
DEVMODE
結構的正確大小? DEVMODE
緩沖區? fMode
參數中的DM_IN_BUFFER
和DM_OUT_BUFFER
標志(除了DM_IN_PROMPT
) fMode
為DocumentProperties
? pDevModeInput
和pDevModeOutput
指向你在應用程序啟動時初始化的DEVMODE
緩沖區? DocumentProperties(... DM_IN_PROMPT ...)
之前正確設置的DEVMODE
緩沖區中的dmFields
位 DocumentProperties(... DM_IN_PROMPT ...)
調用之間保留了DEVMODE
緩沖區的內容? 看到:
此外,如果您想使用WPF類(PrintQueue,PrintTicket)執行此操作,此頁面將指向正確的方向:
http://social.msdn.microsoft.com/Forums/en/wpf/thread/0dc695c1-578d-4da5-8f68-b2a257846c02
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.