I need to change DEVMODE
of printer for current printing task to pass standard and device-specific settings. I do the following:
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();
}
It fails when I attempt to execute PrinterSettings.SetHdevmode
with a NullReferenceException
and without any meaningful error info. d.PrinterSettings
is not null, the exception is thrown inside of PrinterSettings.SetHdevmode
method.
So my question is: what is wrong? Is the byte[]
to IntPtr
cast wrong? Maybe SetHdevmode
expects something other than a byte[]
array?
I get the byte[] devmode_data
array from the registry. It is a valid value and it is same value that is used in current printer settings.
I modified your code in the following way, since I don't have any valid data for devmode_data
:
devmode = d.PrinterSettings.GetHdevmode();
if (devmode != IntPtr.Zero) d.PrinterSettings.SetHdevmode(devmode);
and now there is no exception here.
Please, provide me with your data for devmode_data
or check for your own, if it is valid or not!
SetHdevmode
expects an HGLOBAL
. You can get an HGLOBAL
from .Net via Marshal.AllocHGlobal
. Then, you can use Marshal.Copy(byte[], int, IntPtr, int)
to copy from your managed byte array to the HGLOBAL
. See below:
var pDevMode = Marshal.AllocHGlobal(devmode_data.Length);
Marshal.Copy(devmode_data, 0, pDevMode, devmode_data.Length);
d.PrinterSettings.SetHdevmode(pDevMode);
Marshal.FreeHGlobal(pDevMode);
The byte array can be partially handled as a structure, but that will require p/Invoke definitions. The PrinterSettings
class, however, will not accept a structure, so doing so would be unneeded in this case. Additionally, the DEVMODE
structure is variable length to allow for printer drivers to add additional opaque data, so it would not be possible to convert without data loss.
See How can I save and restore `PrinterSettings`? for more.
来源:https://stackoverflow.com/questions/8281623/cant-change-devmode-of-a-printer