2011-11-26 72 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`?了解更多信息。