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.
Related
My environment is Windows 10 20H2(64bit) and Visual Studio 2019.
I am developing an app as C# WPF(.NET 5) project. And I want to write a code that HDR(High Dynamic Range) is active currently on the system.
In this document, I got some hints about Windows HDR. But I could only find articles about for UWP and DirectX.
I would ideally like to use the .NET API or Win32 API. Does Windows 10 provide those APIs?
You can use the Connecting and Configuring Displays (CCD) API.
specifically the DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO request (which is not really documented in MSDN but is defined in wingdi.h)
Here is some C# Console Application sample code that dumps for each monitor if it supports HDR and if it's enabled.
static void Main()
{
var err = GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out var pathCount, out var modeCount);
if (err != 0)
throw new Win32Exception(err);
var paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
var modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
err = QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (err != 0)
throw new Win32Exception(err);
foreach (var path in paths)
{
// get display name
var info = new DISPLAYCONFIG_TARGET_DEVICE_NAME();
info.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
info.header.size = Marshal.SizeOf<DISPLAYCONFIG_TARGET_DEVICE_NAME>();
info.header.adapterId = path.targetInfo.adapterId;
info.header.id = path.targetInfo.id;
err = DisplayConfigGetDeviceInfo(ref info);
if (err != 0)
throw new Win32Exception(err);
var colorInfo = new DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO();
colorInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
colorInfo.header.size = Marshal.SizeOf<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO>();
colorInfo.header.adapterId = path.targetInfo.adapterId;
colorInfo.header.id = path.targetInfo.id;
err = DisplayConfigGetDeviceInfo(ref colorInfo);
if (err != 0)
throw new Win32Exception(err);
Console.WriteLine(info.monitorFriendlyDeviceName);
Console.WriteLine(" Advanced Color Supported: " + colorInfo.advancedColorSupported);
Console.WriteLine(" Advanced Color Enabled : " + colorInfo.advancedColorEnabled);
Console.WriteLine();
}
}
private enum DISPLAYCONFIG_DEVICE_INFO_TYPE
{
DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7,
DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8,
DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9,
DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10,
DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11,
}
private enum DISPLAYCONFIG_COLOR_ENCODING
{
DISPLAYCONFIG_COLOR_ENCODING_RGB = 0,
DISPLAYCONFIG_COLOR_ENCODING_YCBCR444 = 1,
DISPLAYCONFIG_COLOR_ENCODING_YCBCR422 = 2,
DISPLAYCONFIG_COLOR_ENCODING_YCBCR420 = 3,
DISPLAYCONFIG_COLOR_ENCODING_INTENSITY = 4,
}
private enum DISPLAYCONFIG_SCALING
{
DISPLAYCONFIG_SCALING_IDENTITY = 1,
DISPLAYCONFIG_SCALING_CENTERED = 2,
DISPLAYCONFIG_SCALING_STRETCHED = 3,
DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4,
DISPLAYCONFIG_SCALING_CUSTOM = 5,
DISPLAYCONFIG_SCALING_PREFERRED = 128,
}
private enum DISPLAYCONFIG_ROTATION
{
DISPLAYCONFIG_ROTATION_IDENTITY = 1,
DISPLAYCONFIG_ROTATION_ROTATE90 = 2,
DISPLAYCONFIG_ROTATION_ROTATE180 = 3,
}
private enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY
{
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = -1,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED = 16,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_VIRTUAL = 17,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = unchecked((int)0x80000000),
}
private enum DISPLAYCONFIG_TOPOLOGY_ID
{
DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001,
DISPLAYCONFIG_TOPOLOGY_CLONE = 0x00000002,
DISPLAYCONFIG_TOPOLOGY_EXTEND = 0x00000004,
DISPLAYCONFIG_TOPOLOGY_EXTERNAL = 0x00000008,
}
private enum DISPLAYCONFIG_PATH
{
DISPLAYCONFIG_PATH_ACTIVE = 0x00000001,
DISPLAYCONFIG_PATH_PREFERRED_UNSCALED = 0x00000004,
DISPLAYCONFIG_PATH_SUPPORT_VIRTUAL_MODE = 0x00000008,
}
private enum DISPLAYCONFIG_SOURCE_FLAGS
{
DISPLAYCONFIG_SOURCE_IN_USE = 0x00000001,
}
private enum DISPLAYCONFIG_TARGET_FLAGS
{
DISPLAYCONFIG_TARGET_IN_USE = 0x00000001,
DISPLAYCONFIG_TARGET_FORCIBLE = 0x00000002,
DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_BOOT = 0x00000004,
DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_PATH = 0x00000008,
DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_SYSTEM = 0x00000010,
DISPLAYCONFIG_TARGET_IS_HMD = 0x00000020,
}
private enum QDC
{
QDC_ALL_PATHS = 0x00000001,
QDC_ONLY_ACTIVE_PATHS = 0x00000002,
QDC_DATABASE_CURRENT = 0x00000004,
QDC_VIRTUAL_MODE_AWARE = 0x00000010,
QDC_INCLUDE_HMD = 0x00000020,
}
private enum DISPLAYCONFIG_SCANLINE_ORDERING
{
DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2,
DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED,
DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3,
}
private enum DISPLAYCONFIG_PIXELFORMAT
{
DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
DISPLAYCONFIG_PIXELFORMAT_16BPP = 2,
DISPLAYCONFIG_PIXELFORMAT_24BPP = 3,
DISPLAYCONFIG_PIXELFORMAT_32BPP = 4,
DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5,
}
private enum DISPLAYCONFIG_MODE_INFO_TYPE
{
DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE = 3,
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_DEVICE_INFO_HEADER
{
public DISPLAYCONFIG_DEVICE_INFO_TYPE type;
public int size;
public LUID adapterId;
public uint id;
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
public uint value;
public DISPLAYCONFIG_COLOR_ENCODING colorEncoding;
public int bitsPerColorChannel;
public bool advancedColorSupported => (value & 0x1) == 0x1;
public bool advancedColorEnabled => (value & 0x2) == 0x2;
public bool wideColorEnforced => (value & 0x4) == 0x4;
public bool advancedColorForceDisabled => (value & 0x8) == 0x8;
}
[StructLayout(LayoutKind.Sequential)]
private struct POINTL
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct LUID
{
public uint LowPart;
public int HighPart;
public long Value => ((long)HighPart << 32) | LowPart;
public override string ToString() => Value.ToString();
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_SOURCE_MODE
{
public uint width;
public uint height;
public DISPLAYCONFIG_PIXELFORMAT pixelFormat;
public POINTL position;
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_RATIONAL
{
public uint Numerator;
public uint Denominator;
public override string ToString() => Numerator + " / " + Denominator;
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_2DREGION
{
public uint cx;
public uint cy;
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO
{
public POINTL PathSourceSize;
public RECT DesktopImageRegion;
public RECT DesktopImageClip;
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO
{
public ulong pixelRate;
public DISPLAYCONFIG_RATIONAL hSyncFreq;
public DISPLAYCONFIG_RATIONAL vSyncFreq;
public DISPLAYCONFIG_2DREGION activeSize;
public DISPLAYCONFIG_2DREGION totalSize;
public uint videoStandard;
public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_TARGET_MODE
{
public DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
}
[StructLayout(LayoutKind.Explicit)]
private struct DISPLAYCONFIG_MODE_INFO_union
{
[FieldOffset(0)]
public DISPLAYCONFIG_TARGET_MODE targetMode;
[FieldOffset(0)]
public DISPLAYCONFIG_SOURCE_MODE sourceMode;
[FieldOffset(0)]
public DISPLAYCONFIG_DESKTOP_IMAGE_INFO desktopImageInfo;
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_PATH_SOURCE_INFO
{
public LUID adapterId;
public uint id;
public uint modeInfoIdx;
public DISPLAYCONFIG_SOURCE_FLAGS statusFlags;
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_PATH_TARGET_INFO
{
public LUID adapterId;
public uint id;
public uint modeInfoIdx;
public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
public DISPLAYCONFIG_ROTATION rotation;
public DISPLAYCONFIG_SCALING scaling;
public DISPLAYCONFIG_RATIONAL refreshRate;
public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
public bool targetAvailable;
public DISPLAYCONFIG_TARGET_FLAGS statusFlags;
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_PATH_INFO
{
public DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
public DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
public DISPLAYCONFIG_PATH flags;
}
[StructLayout(LayoutKind.Sequential)]
private struct DISPLAYCONFIG_MODE_INFO
{
public DISPLAYCONFIG_MODE_INFO_TYPE infoType;
public uint id;
public LUID adapterId;
public DISPLAYCONFIG_MODE_INFO_union info;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct DISPLAYCONFIG_SOURCE_DEVICE_NAME
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string viewGdiDeviceName;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS
{
public uint value;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct DISPLAYCONFIG_TARGET_DEVICE_NAME
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
public DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags;
public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
public ushort edidManufactureId;
public ushort edidProductCodeId;
public uint connectorInstance;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string monitorFriendlyDeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string monitorDevicePat;
}
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32")]
private static extern int GetDisplayConfigBufferSizes(QDC flags, out int numPathArrayElements, out int numModeInfoArrayElements);
[DllImport("user32")]
private static extern int QueryDisplayConfig(QDC flags, ref int numPathArrayElements, [In, Out] DISPLAYCONFIG_PATH_INFO[] pathArray, ref int numModeInfoArrayElements, [In, Out] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, out DISPLAYCONFIG_TOPOLOGY_ID currentTopologyId);
[DllImport("user32")]
private static extern int QueryDisplayConfig(QDC flags, ref int numPathArrayElements, [In, Out] DISPLAYCONFIG_PATH_INFO[] pathArray, ref int numModeInfoArrayElements, [In, Out] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, IntPtr currentTopologyId);
[DllImport("user32")]
private static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO requestPacket);
[DllImport("user32")]
private static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SOURCE_DEVICE_NAME requestPacket);
[DllImport("user32")]
private static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_TARGET_DEVICE_NAME requestPacket);
I trying to fill Wacom tablet screen with my application. How can I find this screen working area?
At this moment I just trying to find this screen by Device Friendly name using ScreenInterrogatory class (code below), but it requires me to know device name. I looking for a way to do this for any Wacom device without knowing the device name (using Wintab api).
//
public Screen GetWacomWorkingArea(string wacomDeviceName)
{
foreach(var screen in System.Windows.Forms.Screen.AllScreens)
{
if(screen.DeviceFriendlyName == wacomDeviceName)
{
return screen.WorkingArea;
}
}
}
//
public static class ScreenInterrogatory
{
public const int ERROR_SUCCESS = 0;
#region enums
public enum QUERY_DEVICE_CONFIG_FLAGS : uint
{
QDC_ALL_PATHS = 0x00000001,
QDC_ONLY_ACTIVE_PATHS = 0x00000002,
QDC_DATABASE_CURRENT = 0x00000004
}
public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY : uint
{
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = 0xFFFFFFFF,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = 0x80000000,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_FORCE_UINT32 = 0xFFFFFFFF
}
public enum DISPLAYCONFIG_SCANLINE_ORDERING : uint
{
DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2,
DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED,
DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3,
DISPLAYCONFIG_SCANLINE_ORDERING_FORCE_UINT32 = 0xFFFFFFFF
}
public enum DISPLAYCONFIG_ROTATION : uint
{
DISPLAYCONFIG_ROTATION_IDENTITY = 1,
DISPLAYCONFIG_ROTATION_ROTATE90 = 2,
DISPLAYCONFIG_ROTATION_ROTATE180 = 3,
DISPLAYCONFIG_ROTATION_ROTATE270 = 4,
DISPLAYCONFIG_ROTATION_FORCE_UINT32 = 0xFFFFFFFF
}
public enum DISPLAYCONFIG_SCALING : uint
{
DISPLAYCONFIG_SCALING_IDENTITY = 1,
DISPLAYCONFIG_SCALING_CENTERED = 2,
DISPLAYCONFIG_SCALING_STRETCHED = 3,
DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4,
DISPLAYCONFIG_SCALING_CUSTOM = 5,
DISPLAYCONFIG_SCALING_PREFERRED = 128,
DISPLAYCONFIG_SCALING_FORCE_UINT32 = 0xFFFFFFFF
}
public enum DISPLAYCONFIG_PIXELFORMAT : uint
{
DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
DISPLAYCONFIG_PIXELFORMAT_16BPP = 2,
DISPLAYCONFIG_PIXELFORMAT_24BPP = 3,
DISPLAYCONFIG_PIXELFORMAT_32BPP = 4,
DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5,
DISPLAYCONFIG_PIXELFORMAT_FORCE_UINT32 = 0xffffffff
}
public enum DISPLAYCONFIG_MODE_INFO_TYPE : uint
{
DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32 = 0xFFFFFFFF
}
public enum DISPLAYCONFIG_DEVICE_INFO_TYPE : uint
{
DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF
}
#endregion
#region structs
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
public uint LowPart;
public int HighPart;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_PATH_SOURCE_INFO
{
public LUID adapterId;
public uint id;
public uint modeInfoIdx;
public uint statusFlags;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_PATH_TARGET_INFO
{
public LUID adapterId;
public uint id;
public uint modeInfoIdx;
private DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
private DISPLAYCONFIG_ROTATION rotation;
private DISPLAYCONFIG_SCALING scaling;
private DISPLAYCONFIG_RATIONAL refreshRate;
private DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
public bool targetAvailable;
public uint statusFlags;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_RATIONAL
{
public uint Numerator;
public uint Denominator;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_PATH_INFO
{
public DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
public DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
public uint flags;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_2DREGION
{
public uint cx;
public uint cy;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO
{
public ulong pixelRate;
public DISPLAYCONFIG_RATIONAL hSyncFreq;
public DISPLAYCONFIG_RATIONAL vSyncFreq;
public DISPLAYCONFIG_2DREGION activeSize;
public DISPLAYCONFIG_2DREGION totalSize;
public uint videoStandard;
public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_TARGET_MODE
{
public DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINTL
{
private int x;
private int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_SOURCE_MODE
{
public uint width;
public uint height;
public DISPLAYCONFIG_PIXELFORMAT pixelFormat;
public POINTL position;
}
[StructLayout(LayoutKind.Explicit)]
public struct DISPLAYCONFIG_MODE_INFO_UNION
{
[FieldOffset(0)]
public DISPLAYCONFIG_TARGET_MODE targetMode;
[FieldOffset(0)]
public DISPLAYCONFIG_SOURCE_MODE sourceMode;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_MODE_INFO
{
public DISPLAYCONFIG_MODE_INFO_TYPE infoType;
public uint id;
public LUID adapterId;
public DISPLAYCONFIG_MODE_INFO_UNION modeInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS
{
public uint value;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_DEVICE_INFO_HEADER
{
public DISPLAYCONFIG_DEVICE_INFO_TYPE type;
public uint size;
public LUID adapterId;
public uint id;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DISPLAYCONFIG_TARGET_DEVICE_NAME
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
public DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags;
public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
public ushort edidManufactureId;
public ushort edidProductCodeId;
public uint connectorInstance;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string monitorFriendlyDeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string monitorDevicePath;
}
#endregion
#region DLL-Imports
[DllImport("user32.dll")]
public static extern int GetDisplayConfigBufferSizes(
QUERY_DEVICE_CONFIG_FLAGS flags, out uint numPathArrayElements, out uint numModeInfoArrayElements);
[DllImport("user32.dll")]
public static extern int QueryDisplayConfig(
QUERY_DEVICE_CONFIG_FLAGS flags,
ref uint numPathArrayElements, [Out] DISPLAYCONFIG_PATH_INFO[] PathInfoArray,
ref uint numModeInfoArrayElements, [Out] DISPLAYCONFIG_MODE_INFO[] ModeInfoArray,
IntPtr currentTopologyId
);
[DllImport("user32.dll")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName);
#endregion
private static string MonitorFriendlyName(LUID adapterId, uint targetId)
{
var deviceName = new DISPLAYCONFIG_TARGET_DEVICE_NAME
{
header =
{
size = (uint)Marshal.SizeOf(typeof (DISPLAYCONFIG_TARGET_DEVICE_NAME)),
adapterId = adapterId,
id = targetId,
type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME
}
};
var error = DisplayConfigGetDeviceInfo(ref deviceName);
if (error != ERROR_SUCCESS)
throw new Win32Exception(error);
return deviceName.monitorFriendlyDeviceName;
}
private static IEnumerable<string> GetAllMonitorsFriendlyNames()
{
uint pathCount, modeCount;
var error = GetDisplayConfigBufferSizes(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount);
if (error != ERROR_SUCCESS)
throw new Win32Exception(error);
var displayPaths = new DISPLAYCONFIG_PATH_INFO[pathCount];
var displayModes = new DISPLAYCONFIG_MODE_INFO[modeCount];
error = QueryDisplayConfig(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS,
ref pathCount, displayPaths, ref modeCount, displayModes, IntPtr.Zero);
if (error != ERROR_SUCCESS)
throw new Win32Exception(error);
for (var i = 0; i < modeCount; i++)
if (displayModes[i].infoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_TARGET)
yield return MonitorFriendlyName(displayModes[i].adapterId, displayModes[i].id);
}
public static string DeviceFriendlyName(this Screen screen)
{
var allFriendlyNames = GetAllMonitorsFriendlyNames();
for (var index = 0; index < Screen.AllScreens.Length; index++)
if (Equals(screen, Screen.AllScreens[index]))
return allFriendlyNames.ToArray()[index];
return null;
}
}
Trying to use the following code example which works fine in WinForm application but not in VSTO. Is there some sort of permissions that allow access?
Can set the default printer but can't get or set printer settings.
Get the following exception from within addin:
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
http://www.pinvoke.net/default.aspx/winspool.SetDefaultPrinter
http://www.pinvoke.net/default.aspx/winspool/OpenPrinter.html
visual studio project template is a {Word/Outlook} 2013 and 2016 VSTO Add-in
string name = #"\\{printer server name}\{printer name}";
PRNsettings p = new PRNsettings();
var v = p.ChangePrinterSetting(name, new PrinterData { colour = 1, copies = 1, duplex = 1, source = 7 });
public class PrinterData
{
public PrinterData()
{
copies = -1;
colour = -1;
duplex = -1;
source = -1;
}
public int copies { get; set; }
public int colour { get; set; }
public int duplex { get; set; }
public int source { get; set; }
}
public class PRNsettings
{
private IntPtr hPrinter = new System.IntPtr();
private PRINTER_DEFAULTS PrinterValues = new PRINTER_DEFAULTS();
private PRINTER_INFO_2 pinfo = new PRINTER_INFO_2();
private DEVMODE dm;
private IntPtr ptrDM;
private IntPtr ptrPrinterInfo;
private int sizeOfDevMode = 0;
private int lastError;
private int nBytesNeeded;
private long nRet;
private int intError;
private System.Int32 nJunk;
private IntPtr yDevModeData;
[DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern Int32 GetLastError();
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesA", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter,
[MarshalAs(UnmanagedType.LPStr)] string pDeviceNameg, IntPtr pDevModeOutput, ref IntPtr pDevModeInput, int fMode);
[DllImport("winspool.Drv", EntryPoint = "GetPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool GetPrinter(IntPtr hPrinter, Int32 dwLevel, IntPtr pPrinter, Int32 dwBuf, out Int32 dwNeeded);
[DllImport("winspool.drv", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, PRINTER_DEFAULTS pDefault);
[DllImport("winspool.drv", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern bool SetPrinter(IntPtr hPrinter, int Level, IntPtr pPrinter, int Command);
[DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SetDefaultPrinter(string Name);
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_DEFAULTS
{
public int pDatatype;
public int pDevMode;
public int DesiredAccess;
}
[StructLayout(LayoutKind.Sequential)]
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 Int32 Attributes;
public Int32 Priority;
public Int32 DefaultPriority;
public Int32 StartTime;
public Int32 UntilTime;
public Int32 Status;
public Int32 cJobs;
public Int32 AveragePPM;
}
private const short CCDEVICENAME = 32;
private const short CCFORMNAME = 32;
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCDEVICENAME)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
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 short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCFORMNAME)]
public string dmFormName;
public short dmUnusedPadding;
public short dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
public uint dmMediaType;
}
private const int DM_DUPLEX = 0x1000;
private const int DM_IN_BUFFER = 8;
private const int DM_OUT_BUFFER = 2;
private const int PRINTER_ACCESS_ADMINISTER = 0x4;
private const int PRINTER_ACCESS_USE = 0x8;
private const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
private const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
public int returnSource;
public int returnDuplex;
public int returnColor;
public int returnCopies;
public bool SetDefault(string name)
{
try
{
return SetDefaultPrinter(name);
}
catch (Exception) { return false; }
}
public bool ChangePrinterSetting(string PrinterName, PrinterData PS)
{
try
{
dm = this.GetPrinterSettings(PrinterName);
// Sent back to allow reset of the settings back to original.
returnSource = dm.dmDefaultSource;
returnDuplex = dm.dmDuplex;
returnColor = dm.dmColor;
returnCopies = dm.dmCopies;
if (PS.source > -1)
dm.dmDefaultSource = (short)PS.source;
if (PS.duplex > -1)
dm.dmDuplex = (short)PS.duplex;
if (PS.colour > -1)
dm.dmColor = (short)PS.colour;
if (PS.copies > -1)
dm.dmCopies = (short)PS.copies;
Marshal.StructureToPtr(dm, yDevModeData, true);
pinfo.pDevMode = yDevModeData;
pinfo.pSecurityDescriptor = IntPtr.Zero;
Marshal.StructureToPtr(pinfo, ptrPrinterInfo, false);
lastError = Marshal.GetLastWin32Error();
nRet = Convert.ToInt16(SetPrinter(hPrinter, 2, ptrPrinterInfo, 0));
// Error
if (nRet == 0)
return false;
if (hPrinter != IntPtr.Zero)
ClosePrinter(hPrinter);
return Convert.ToBoolean(nRet);
}
catch (Exception) { return false; }
}
public DEVMODE GetPrinterSettings(string PrinterName)
{
PrinterData PData = new PrinterData();
DEVMODE dm;
const int PRINTER_ACCESS_ADMINISTER = 0x4;
const int PRINTER_ACCESS_USE = 0x8;
const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
PrinterValues.pDatatype = 0;
PrinterValues.pDevMode = 0;
PrinterValues.DesiredAccess = PRINTER_ALL_ACCESS;
nRet = Convert.ToInt32(OpenPrinter(PrinterName,
out hPrinter, PrinterValues));
GetPrinter(hPrinter, 2, IntPtr.Zero, 0, out nBytesNeeded);
Marshal.AllocCoTaskMem(nBytesNeeded);
ptrPrinterInfo = Marshal.AllocHGlobal(nBytesNeeded);
nRet = Convert.ToInt32(GetPrinter(hPrinter, 2, ptrPrinterInfo, nBytesNeeded, out nJunk));
pinfo = (PRINTER_INFO_2)Marshal.PtrToStructure(ptrPrinterInfo, typeof(PRINTER_INFO_2));
IntPtr Temp = new IntPtr();
if (pinfo.pDevMode == IntPtr.Zero)
{
IntPtr ptrZero = IntPtr.Zero;
sizeOfDevMode = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, ptrZero, ref ptrZero, 0);
ptrDM = Marshal.AllocCoTaskMem(sizeOfDevMode);
int i = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, ptrDM, ref ptrZero, DM_OUT_BUFFER);
pinfo.pDevMode = ptrDM;
}
intError = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, IntPtr.Zero, ref Temp, 0);
yDevModeData = Marshal.AllocHGlobal(intError);
intError = DocumentProperties(IntPtr.Zero, hPrinter, PrinterName, yDevModeData, ref Temp, 2);
dm = (DEVMODE)Marshal.PtrToStructure(yDevModeData, typeof(DEVMODE));
return dm;
}
}
If you get this error when building for AnyCPU or x64 you might find my answer here helpfull:
WinSpool OpenPrinter Access Denied - building for AnyCPU\x64
Here is my main program:
class Program
{
static void Main(string[] args)
{
Printer printer = new Printer();
IntPtr printerHandle = printer.getPrinterHandle("TASKalfa 2551ci");
UInt32 jobId = printer.getJobId();
Console.WriteLine(printerHandle+","+jobId);
printer.getJob(printerHandle, jobId);
Console.ReadLine();
}
}
I got the following error message from VS 2015 Community Edition, when I call printer.getJob Method, even I have catched the System.NullReferenceException.
System.NullReferenceException was unhandled
Message: An unhandled exception of type 'System.NullReferenceException' occurred in mscorlib.dll
Additional information: Object reference not set to an instance of an object.
I have checked that both variable printerHandle and jobId are not null, so I cannot figure out what is problem.
However the value of printerHandle is not a constant, is it correct?
Here is my printer object source code:
using System;
using System.Collections;
using System.Management;
using System.Runtime.InteropServices;
class Printer
{
public Printer()
{
}
public ArrayList getPrinterNameList()
{
ArrayList result = new ArrayList();
var printerQuery = new ManagementObjectSearcher("SELECT * from Win32_Printer");
foreach (var printer in printerQuery.Get())
{
result.Add(printer.GetPropertyValue("Name"));
}
return result;
}
public UInt32 getJobId()
{
UInt32 jobId=0;
var printJobQuery = new ManagementObjectSearcher("select * from Win32_PrintJob");
foreach (var printJob in printJobQuery.Get())
{
jobId= (UInt32)printJob.Properties["JobId"].Value;
}
return jobId;
}
public IntPtr getPrinterHandle(String printerName)
{
IntPtr result=new IntPtr(0);
Console.WriteLine ("OpenPrinter="+OpenPrinter(printerName,out result, result));
return result;
}
public void getJob(IntPtr printerHandle,UInt32 jobId)
{
int BUFFER_SIZE = 250;
IntPtr pcbNeeed = new IntPtr(0);
byte[] byteBuffer = new byte[BUFFER_SIZE];
try
{
Console.WriteLine("GetJob="+GetJob(printerHandle, (Int32)jobId, 1, out byteBuffer, BUFFER_SIZE, out pcbNeeed));
}
catch (System.NullReferenceException err)
{
Console.WriteLine(err.Message);
}
}
[DllImport("winspool.drv", SetLastError = true)]
static extern int OpenPrinter(string pPrinterName, out IntPtr phPrinter, IntPtr pDefault);
[DllImport(
"winspool.drv",
EntryPoint = "GetJobW",
SetLastError = true,
CharSet = CharSet.Ansi,
ExactSpelling = false,
CallingConvention = CallingConvention.StdCall)]
private static extern bool GetJob
([InAttribute()] IntPtr hPrinter,
[InAttribute()] Int32 JobId,
[InAttribute()] Int32 Level,
[OutAttribute()] out byte[] pJob,
[InAttribute()] Int32 cbBuf,
[OutAttribute()] out IntPtr pcbNeeded);
}
Here is my WIN API version:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string msg = null;
var hPrinter = new IntPtr();
bool open = NativeMethods.OpenPrinterW("TASKalfa 2551ci", ref hPrinter, IntPtr.Zero);
Debug.Assert(open);
/* Query for 99 jobs */
const uint firstJob = 0u;
const uint noJobs = 99u;
const uint level = 1u;
// Get byte size required for the function
uint needed;
uint returned;
IntPtr tempptr = IntPtr.Zero;
bool b1 = NativeMethods.EnumJobsW(
hPrinter, firstJob, noJobs, level, IntPtr.Zero, 0, out needed, out returned);
uint lastError = NativeMethods.GetLastError();
Console.WriteLine("b1="+b1);
//Debug.Assert(lastError == NativeConstants.ERROR_INSUFFICIENT_BUFFER);
NativeMethods.FormatMessage(0x1300, ref tempptr, lastError, 0, ref msg, 255, ref tempptr);
Console.WriteLine("lastError=" + msg);
// Populate the structs
IntPtr pJob = Marshal.AllocHGlobal((int)needed);
uint bytesCopied;
uint structsCopied;
bool b2 = NativeMethods.EnumJobsW(
hPrinter, firstJob, noJobs, level, pJob, needed, out bytesCopied, out structsCopied);
lastError = NativeMethods.GetLastError();
Console.WriteLine("b2="+b2);
NativeMethods.FormatMessage(0x1300, ref tempptr, lastError, 0, ref msg, 255, ref tempptr);
Console.WriteLine("lastError="+ msg);
var jobInfos = new JOB_INFO_1W[structsCopied];
int sizeOf = Marshal.SizeOf(typeof(JOB_INFO_1W));
IntPtr pStruct = pJob;
for (int i = 0; i < structsCopied; i++)
{
var jobInfo_1W = (JOB_INFO_1W)Marshal.PtrToStructure(pStruct, typeof(JOB_INFO_1W));
jobInfos[i] = jobInfo_1W;
pStruct += sizeOf;
}
Marshal.FreeHGlobal(pJob);
Console.WriteLine("structsCopied="+structsCopied);
Console.ReadLine();
}
public class NativeConstants
{
public const int ERROR_INSUFFICIENT_BUFFER = 122;
}
public partial class NativeMethods
{
[DllImport("kernel32.dll", EntryPoint = "GetLastError")]
public static extern uint GetLastError();
[System.Runtime.InteropServices.DllImport("Kernel32.dll")]
public extern static int FormatMessage(int flag, ref IntPtr source, uint msgid, int langid, ref string buf, int size, ref IntPtr args);
}
public partial class NativeMethods
{
[DllImport("Winspool.drv", EntryPoint = "OpenPrinterW")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool OpenPrinterW([In] [MarshalAs(UnmanagedType.LPWStr)] string pPrinterName,
ref IntPtr phPrinter, [In] IntPtr pDefault);
[DllImport("Winspool.drv", EntryPoint = "EnumJobsW")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumJobsW([In] IntPtr hPrinter, uint FirstJob, uint NoJobs, uint Level, IntPtr pJob,
uint cbBuf, [Out] out uint pcbNeeded, [Out] out uint pcReturned);
}
[StructLayout(LayoutKind.Sequential)]
public struct JOB_INFO_1W
{
public uint JobId;
[MarshalAs(UnmanagedType.LPWStr)]
public string pPrinterName;
[MarshalAs(UnmanagedType.LPWStr)]
public string pMachineName;
[MarshalAs(UnmanagedType.LPWStr)]
public string pUserName;
[MarshalAs(UnmanagedType.LPWStr)]
public string pDocument;
[MarshalAs(UnmanagedType.LPWStr)]
public string pDatatype;
[MarshalAs(UnmanagedType.LPWStr)]
public string pStatus;
public uint Status;
public uint Priority;
public uint Position;
public uint TotalPages;
public uint PagesPrinted;
public SYSTEMTIME Submitted;
}
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEMTIME
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}
}
}
I am using Windows 10.
This is my solution:
using System;
using System.Text;
using System.Management;
using System.Runtime.InteropServices;
namespace WinApi
{
class PrintJob
{
private const int ERROR_INSUFFICIENT_BUFFER = 122;
public PrintJob()
{
string sql = "select * from Win32_PrintJob";
var printJobQuery = new ManagementObjectSearcher(sql);
foreach (ManagementObject printJob in printJobQuery.Get())
{
getJobDetail(printJob);
Console.WriteLine("====================");
}
}
private void getJobDetail(ManagementObject thePrintJob)
{
UInt32 jobId = 0, needed = 0;
String printerName;
bool result;
IntPtr printerHandle = new IntPtr(0);
jobId = (UInt32)thePrintJob.Properties["JobId"].Value;
printerName = (String)thePrintJob.Properties["DriverName"].Value;
Console.WriteLine("Job Id=" + jobId + ",Printer Name=" + printerName);
result=OpenPrinter(printerName,out printerHandle, IntPtr.Zero);
Console.Write("Open Printer " + printerName);
if (result)
{
Console.WriteLine(" success.");
result = GetJob(printerHandle, jobId, 2, IntPtr.Zero,0,out needed);
if (Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER)
Console.WriteLine("Get Job 1 failure, error code=" + Marshal.GetLastWin32Error());
else
{
Console.WriteLine("buffer size required=" + needed);
IntPtr buffer = Marshal.AllocHGlobal((int)needed);
result = GetJob(printerHandle, jobId, 2, buffer, needed, out needed);
JOB_INFO_2 jobInfo=(JOB_INFO_2)Marshal.PtrToStructure(buffer, typeof(JOB_INFO_2));
DEVMODE dMode = (DEVMODE)Marshal.PtrToStructure(jobInfo.pDevMode, typeof(DEVMODE));
Console.WriteLine("Job Id=" + jobInfo.JobId + ",Printer Name=" + Marshal.PtrToStringAnsi(jobInfo.pDriverName) + ",Copies=" + dMode.dmCopies);
Marshal.FreeHGlobal(buffer);
}
ClosePrinter(printerHandle);
Console.WriteLine("Printer " + printerName+" is closed");
}
else
Console.WriteLine(" failed.");
}
[DllImport("winspool.drv", SetLastError = true)]
static extern bool OpenPrinter(string pPrinterName, out IntPtr phPrinter, IntPtr pDefault);
[DllImport("winspool.drv", CharSet = CharSet.Auto)]
static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport(
"winspool.drv",
EntryPoint = "GetJob",
SetLastError = true,
ExactSpelling = false,
CallingConvention = CallingConvention.StdCall)]
private static extern bool GetJob
([InAttribute()] IntPtr hPrinter,
[InAttribute()] UInt32 JobId,
[InAttribute()] UInt32 Level,
[OutAttribute()] IntPtr pJob,
[InAttribute()] UInt32 cbBuf,
[OutAttribute()] out UInt32 pcbNeeded);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct JOB_INFO_2
{
public UInt32 JobId;
public IntPtr pPrinterName;
public IntPtr pMachineName;
public IntPtr pUserName;
public IntPtr pDocument;
public IntPtr pNotifyName;
public IntPtr pDatatype;
public IntPtr pPrintProcessor;
public IntPtr pParameters;
public IntPtr pDriverName;
public IntPtr pDevMode;
public IntPtr pStatus;
public IntPtr pSecurityDescriptor;
public UInt32 Status;
public UInt32 Priority;
public UInt32 Position;
public UInt32 StartTime;
public UInt32 UntilTime;
public UInt32 TotalPages;
public UInt32 Size;
public SYSTEMTIME Submitted;
public UInt32 Time;
public UInt32 PagesPrinted;
}
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEMTIME
{
public short wYear;
public short wMonth;
public short wDayOfWeek;
public short wDay;
public short wHour;
public short wMinute;
public short wSecond;
public short wMilliseconds;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DEVMODE
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
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 short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmFormName;
public short dmLogPixels;
public int dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
}
}
}
I have a class that is attempting to create a process from within a service using credentials provided.
When launching the process I am seeing an error Cannot create a file when that file already exists. What is causing this?
I've tried calling all types of executables, so I know it's not the process being created throwing this.
public class ProcessAsUser
{
static ProcessAsUser()
{
UserToken = IntPtr.Zero;
}
private static IntPtr UserToken { get; set; }
public int StartProcess(ProcessStartInfo processStartInfo)
{
UserToken = IntPtr.Zero;
LogInOtherUser(processStartInfo);
var startUpInfo = new Native.STARTUPINFO();
uint creationFlags = 0;
if (processStartInfo.CreateNoWindow) creationFlags |= Native.CREATE_NO_WINDOW;
var processInfo = new Native.PROCESS_INFORMATION();
bool processStarted = Native.CreateProcessAsUser(
UserToken, // user token
processStartInfo.FileName, // application name
processStartInfo.Arguments, // commandline
IntPtr.Zero, // process attributes
IntPtr.Zero, // thread attributes
true, // inherrit handle
creationFlags, // creation flags
IntPtr.Zero, // environment
processStartInfo.WorkingDirectory+"\\", // current directory
ref startUpInfo,
out processInfo
);
if (!processStarted)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
return 0;
}
int processId = (int)processInfo.dwProcessId;
Native.CloseHandle(processInfo.hProcess);
Native.CloseHandle(processInfo.hThread);
ProcessId = processId;
return ProcessId;
}
public int ProcessId;
private static void LogInOtherUser(ProcessStartInfo processStartInfo)
{
if (UserToken == IntPtr.Zero)
{
var tempUserToken = IntPtr.Zero;
var password = SecureStringToString(processStartInfo.Password);
bool loginResult = Native.LogonUser(processStartInfo.UserName, processStartInfo.Domain, password,
Native.LOGON32_LOGON_BATCH, Native.LOGON32_PROVIDER_DEFAULT,
ref tempUserToken);
if (loginResult)
{
UserToken = tempUserToken;
}
else
{
Native.CloseHandle(tempUserToken);
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
private static String SecureStringToString(SecureString value)
{
var stringPointer = Marshal.SecureStringToBSTR(value);
try
{
return Marshal.PtrToStringBSTR(stringPointer);
}
finally
{
Marshal.FreeBSTR(stringPointer);
}
}
public static void ReleaseUserToken()
{
Native.CloseHandle(UserToken);
}
}
internal class Native
{
internal const int LOGON32_LOGON_INTERACTIVE = 2;
internal const int LOGON32_LOGON_BATCH = 4;
internal const int LOGON32_PROVIDER_DEFAULT = 0;
public const int DUPLICATE_SAME_ACCESS = 2;
public const int CREATE_NO_WINDOW = 0x08000000;
public const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
[StructLayout(LayoutKind.Sequential)]
internal class PROCESS_INFORMATION
{
public IntPtr hProcess = IntPtr.Zero;
public IntPtr hThread = IntPtr.Zero;
public uint dwProcessId = 0;
public uint dwThreadId = 0;
}
[StructLayout(LayoutKind.Sequential)]
internal class STARTUPINFO
{
public int cb;
public string lpReserved;
public string lpDesktop = string.Empty;
public string lpTitle;
public int dwX = 0;
public int dwY = 0;
public int dwXSize = 0;
public int dwYSize = 0;
public int dwXCountChars = 0;
public int dwYCountChars = 0;
public int dwFillAttribute = 0;
public int dwFlags = 0;
public short wShowWindow = 0;
public short cbReserved2 = 0;
public IntPtr lpReserved2 = IntPtr.Zero;
public IntPtr hStdInput = IntPtr.Zero;
public IntPtr hStdOutput = IntPtr.Zero;
public IntPtr hStdError = IntPtr.Zero;
public STARTUPINFO()
{
cb = Marshal.SizeOf(this);
}
}
[StructLayout(LayoutKind.Sequential)]
internal class SECURITY_ATTRIBUTES
{
public SECURITY_ATTRIBUTES()
{
nLength = Marshal.SizeOf(this);
}
public int nLength;
public IntPtr lpSecurityDescriptor = IntPtr.Zero;
public bool bInheritHandle;
}
[DllImport("advapi32.dll", EntryPoint = "LogonUserW", SetLastError = true, CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.StdCall)]
internal static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUserA", SetLastError = true, CharSet = CharSet.Ansi)]
internal static extern bool CreateProcessAsUser(
IntPtr hToken,
[MarshalAs(UnmanagedType.LPStr)] string lpApplicationName,
[MarshalAs(UnmanagedType.LPStr)] string lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandle,
uint dwCreationFlags,
IntPtr lpEnvironment,
[MarshalAs(UnmanagedType.LPStr)] string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true, CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
internal static extern bool CloseHandle(IntPtr handle);
}