我需要更改当前打印任务的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
数组。它是一个有效值,与当前打印机设置中使用的值相同。
答案 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
结构的长度可变,以允许打印机驱动程序添加其他不透明数据,因此无法在没有数据丢失的情况下进行转换。