无法更改打印机的DEVMODE

时间:2011-11-26 21:08:32

标签: c# printing intptr dev-mode

我需要更改当前打印任务的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();
}

当我尝试使用PrinterSettings.SetHdevmode执行NullReferenceException并且没有任何有意义的错误信息时,它失败了。 d.PrinterSettings不为null,在PrinterSettings.SetHdevmode方法中抛出异常 所以我的问题是:出了什么问题? byte[]IntPtr投错了吗?也许SetHdevmode需要的不是byte[]数组?

我从注册表中获取byte[] devmode_data数组。它是一个有效值,与当前打印机设置中使用的值相同。

2 个答案:

答案 0 :(得分:1)

我按以下方式修改了您的代码,因为我没有devmode_data的任何有效数据:

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

现在这里没有例外。

请向我提供devmode_data的数据或检查您自己的数据(如果有效)!

答案 1 :(得分:0)

SetHdevmode需要HGLOBAL。您可以通过HGLOBAL从.Net获得Marshal.AllocHGlobal。然后,您可以使用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`?