2011-11-26 95 views
3

我需要更改打印機的當前打印任務的DEVMODE以通過標準和設備特定的設置。我做到以下幾點:無法更改打印機的DEVMODE

PrintDocument d = new PrintDocument(); 
d.PrinterSettings.PrinterName = "Microsoft XPS Document Writer"; // example printer name   
byte[] devmode_data; // contains a valid value that is obtained from registry 
IntPtr devmode = IntPtr.Zero; 
GCHandle handle = GCHandle.Alloc(devmode_data, GCHandleType.Pinned); 
try 
{ 
    devmode = handle.AddrOfPinnedObject(); 
    if (devmode != IntPtr.Zero) d.PrinterSettings.SetHdevmode(devmode); 
} 
finally 
{ 
    if (handle.IsAllocated) handle.Free(); 
} 

當我嘗試用NullReferenceException,沒有任何有意義的錯誤信息,以執行PrinterSettings.SetHdevmode它失敗。 d.PrinterSettings不爲空,拋出異常的方法是PrinterSettings.SetHdevmode
所以我的問題是:什麼是錯的?鑄造錯誤是byte[]IntPtr?也許SetHdevmode期望byte[]數組以外的東西?我得到byte[] devmode_data數組從註冊表中。這是一個有效值,它與當前打印機設置中使用的值相同。

回答

1

我修改代碼以下面的方式,因爲我沒有任何有效數據devmode_data

devmode = d.PrinterSettings.GetHdevmode(); 
if (devmode != IntPtr.Zero) d.PrinterSettings.SetHdevmode(devmode); 

,現在也沒有例外這裏。

請爲我提供devmode_data的數據,或者檢查您的數據,如果它有效或沒有!

+0

如何將PrinterSettings.GetHdevmode()轉換爲有意義的東西?我試過GCHandle.FromIntPtr(),然後處理。目標,但是會引發異常。 –

+0

只要你知道你想要的結構體的大小,你就可以聲明一個字節數組,然後把它轉換爲指針,'(byte [] *)devmode.ToPointer()'。 –

+0

(byte [] *)devmode.ToPointer() - 這個不能編譯 –

0

SetHdevmode需要HGLOBAL。您可以通過Marshal.AllocHGlobal從.Net獲得HGLOBAL。然後,您可以使用Marshal.Copy(byte[], int, IntPtr, int)從託管字節數組複製到HGLOBAL。見下文:

var pDevMode = Marshal.AllocHGlobal(devmode_data.Length); 
Marshal.Copy(devmode_data, 0, pDevMode, devmode_data.Length); 

d.PrinterSettings.SetHdevmode(pDevMode); 
Marshal.FreeHGlobal(pDevMode); 

的字節數組可以作爲一個結構被部分地處理的,但是,這將需要p/Invoke definitions。然而,PrinterSettings類不會接受一個結構,因此在這種情況下不需要這樣做。此外,DEVMODE結構的可變長度允許打印機驅動程序添加其他不透明數據,因此無法在沒有數據丟失的情況下進行轉換。

請參閱How can I save and restore `PrinterSettings`?瞭解更多信息。