I am trying to update a print job with a new property set to the printer's DEVMODE
structure in my C# win forms application. Specifically, the tray to print to.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string lpszDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string lpszOutput;
[MarshalAs(UnmanagedType.LPStr)]
public string lpszDatatype;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct PRINTER_INFO_2
{
[MarshalAs(UnmanagedType.LPStr)]
public string pServerName;
[MarshalAs(UnmanagedType.LPStr)]
public string pPrinterName;
[MarshalAs(UnmanagedType.LPStr)]
public string pShareName;
[MarshalAs(UnmanagedType.LPStr)]
public string pPortName;
[MarshalAs(UnmanagedType.LPStr)]
public string pDriverName;
[MarshalAs(UnmanagedType.LPStr)]
public string pComment;
[MarshalAs(UnmanagedType.LPStr)]
public string pLocation;
public IntPtr pDevMode;
[MarshalAs(UnmanagedType.LPStr)]
public string pSepFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pPrintProcessor;
[MarshalAs(UnmanagedType.LPStr)]
public string pDatatype;
[MarshalAs(UnmanagedType.LPStr)]
public string pParameters;
public IntPtr pSecurityDescriptor;
public int Attributes;
public int Priority;
public int DefaultPriority;
public int StartTime;
public int UntilTime;
public int Status;
public int cJobs;
public int AveragePPM;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DEVMODE
{
private const int CCHDEVICENAME = 32;
private const int CCHFORMNAME = 32;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
public string dmDeviceName;
public ushort dmSpecVersion;
public ushort dmDriverVersion;
public ushort dmSize;
public ushort dmDriverExtra;
public uint dmFields;
// values to set based on dmFields bits
public short dmOrientation;
public short dmPaperSize;
public short dmPaperLength;
public short dmPaperWidth;
public short dmScale;
public short dmCopies;
public short dmDefaultSource;
public short dmPrintQuality;
public int dmPositionX;
public int dmPositionY;
public uint dmDisplayOrientation;
public uint dmDisplayFixedOutput;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
public string dmFormName;
public ushort dmLogPixels;
public uint dmBitsPerPel;
public uint dmPelsWidth;
public uint dmPelsHeight;
public uint dmDisplayFlags;
public uint dmDisplayFrequency;
public uint dmICMMethod;
public uint dmICMIntent;
public uint dmMediaType;
public uint dmDitherType;
public uint dmReserved1;
public uint dmReserved2;
public uint dmPanningWidth;
public uint dmPanningHeight;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class PRINTER_DEFAULTS
{
public IntPtr pDatatype;
public IntPtr pDevMode;
public int DesiredAccess;
}
[Flags]
public enum FModes
{
DM_SIZEOF = 0,
DM_UPDATE = 1,
DM_COPY = 2,
DM_PROMPT = 4,
DM_MODIFY = 8,
DM_OUT_DEFAULT = DM_UPDATE,
DM_OUT_BUFFER = DM_COPY,
DM_IN_PROMPT = DM_PROMPT,
DM_IN_BUFFER = DM_MODIFY,
}
[Flags]
public enum DevModeFields : uint
{
DM_ICMMETHOD = 0x10000,
DM_FORMNAME = 0x00010000,
DM_ICMINTENT = 0x04000000,
DM_MEDIATYPE = 0x08000000,
DM_DITHERTYPE = 0x10000000,
DM_COPIES = 0x00000100,
DM_DEFAULTSOURCE = 0x00000200,
DM_PRINT_QUALITY = 0x00000400,
DM_COLOR = 0x00000800,
DM_DUPLEX = 0x00001000,
DM_YRESOLUTION = 0x00002000,
DM_TTOPTION = 0x00004000,
DM_COLLATE = 0x00008000,
DM_ORIENTATION = 0x00000001,
DM_PAPERSIZE = 0x00000002,
DM_PAPERLENGTH = 0x00000004,
DM_PAPERWIDTH = 0x00000008,
DM_SCALE = 0x00000010
}
// DesiredAccess properties
const int PRINTER_ACCESS_ADMINISTER = 0x4;
const int PRINTER_ACCESS_USE = 0x8;
const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
public enum PaperSource
{
DMRES_HIGH = -4,
DMRES_MEDIUM = -3,
DMRES_LOW = -2,
DMRES_DRAFT = -1,
DMBIN_UPPER = 1,
DMBIN_LOWER = 2,
DMBIN_MIDDLE = 3,
DMBIN_MANUAL = 4,
DMBIN_ENVELOPE = 5,
DMBIN_ENVMANUAL = 6,
DMBIN_AUTO = 7,
DMBIN_TRACTOR = 8,
DMBIN_SMALLFMT = 9,
DMBIN_LARGEFMT = 10,
DMBIN_LARGECAPACITY = 11,
DMBIN_CASSETTE = 14,
DMBIN_FORMSOURCE = 15
}
PRINTER_DEFAULTS settings = new PRINTER_DEFAULTS
{
pDatatype = IntPtr.Zero,
pDevMode = IntPtr.Zero,
DesiredAccess = PRINTER_ACCESS_USE
};
int bytesNeeded = 0;
// get the printer handle
if (OpenPrinter(szPrinterName.Normalize(), out IntPtr hPrinter, settings))
{
// find out size needed for buffer first
GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out bytesNeeded);
if (bytesNeeded > 0)
{
// allocate memory for the printer info
IntPtr pPrinterInfo = Marshal.AllocHGlobal(bytesNeeded);
// fetch pointer to printer info at level 2 (gives us DEVMODE data)
if (GetPrinter(hPrinter, 2, pPrinterInfo, bytesNeeded, out _))
{
// convert the pointer to the readable data
PRINTER_INFO_2 printerInfo = (PRINTER_INFO_2)Marshal.PtrToStructure(pPrinterInfo, typeof(PRINTER_INFO_2));
// for some reason it didnt fetch the DEVMODE data we need, try getting it elsewhere
if (true)
{
// find out size needed for buffer first
bytesNeeded = DocumentProperties(IntPtr.Zero, hPrinter, printerInfo.pPrinterName, IntPtr.Zero, IntPtr.Zero, (int)FModes.DM_SIZEOF);
if (bytesNeeded > 0)
{
// allocate memory for the DEVMODE info
IntPtr pDevMode = Marshal.AllocHGlobal(bytesNeeded);
// fetch pointer to DEVMODE info
int result = DocumentProperties(IntPtr.Zero, hPrinter, szPrinterName.Normalize(), pDevMode, IntPtr.Zero, (int)FModes.DM_OUT_BUFFER);
if (result > 0)
{
printerInfo.pDevMode = pDevMode;
}
}
}
// create the print job
DOCINFOA di = new DOCINFOA
{
lpszDocName = "My C#.NET RAW Document",
lpszDatatype = "RAW"
};
if (StartDocPrinter(hPrinter, 1, di))
{
if (StartPagePrinter(hPrinter))
{
// convert the pointer to readable data
DEVMODE dm = (DEVMODE)Marshal.PtrToStructure(printerInfo.pDevMode, typeof(DEVMODE));
// set new properties for printer
dm.dmFields |= (uint)DevModeFields.DM_DEFAULTSOURCE;
dm.dmDefaultSource = (short)PaperSource.DMBIN_UPPER;
Marshal.StructureToPtr(dm, printerInfo.pDevMode, false);
//overwrite the printers settings
int res = DocumentProperties(IntPtr.Zero, hPrinter, szPrinterName.Normalize(), printerInfo.pDevMode, printerInfo.pDevMode, (int)FModes.DM_IN_BUFFER | (int)FModes.DM_OUT_BUFFER);
if (res > 0)
{
WritePrinter(hPrinter, pBytes, dwCount, out _);
EndPagePrinter(hPrinter);
}
EndDocPrinter(hPrinter);
}
ClosePrinter(hPrinter);
}
}
}
The issue I am having is that the final call to DocumentProperties
does not update the printer job settings. I've checked the structure is valid by inserting an IsDevmodeValid
call each time I read or write to the structure and it returns ok. I've tried setting the DEVMODE
structure both before and after the job is setup. It just does not update the settings when I view the print jobs properties.
Can anyone tell me what I'm missing here? FYI, it prints any documents fine, but to the printer's default tray.
User contributions licensed under CC BY-SA 3.0