Any windows api to rotate screen in c#? [duplicate] - c#

I'm looking for a way to rotate the display of one of my monitors programmatically.
I have two monitors set up on a desk mount, and I often use them in varying orientations when programming or using various other programs, and in order to change the orientation I jump into display settings and rotate it that way (so i can have one or both in portrait).
Call me lazy as i know thats hardly any hassle to do, but it would be nice to just have a quick little executable on my taskbar that i can run to instantly rotate one of the screens back and forth when i need to.
I've looked into it and found various explanations using DEVMODE structs etc, and it all seems like a really long winded process, is there really not an easier way to do this? Not a windows dll that has this functionailty already?
Thanks in advance.

it's not that hard to achieve this using the mentioned DEVMODE struct and native calls.
I've written a little wrapper that does this:
using System;
using System.Runtime.InteropServices;
public class Display
{
public enum Orientations
{
DEGREES_CW_0 = 0,
DEGREES_CW_90 = 3,
DEGREES_CW_180 = 2,
DEGREES_CW_270 = 1
}
public static bool Rotate(uint DisplayNumber, Orientations Orientation)
{
if(DisplayNumber == 0)
throw new ArgumentOutOfRangeException("DisplayNumber", DisplayNumber, "First display is 1.");
bool result = false;
DISPLAY_DEVICE d = new DISPLAY_DEVICE();
d.cb = Marshal.SizeOf(d);
DEVMODE dm = new DEVMODE();
if(!NativeMethods.EnumDisplayDevices(null, DisplayNumber-1, ref d, 0))
throw new ArgumentOutOfRangeException("DisplayNumber", DisplayNumber, "Number is greater than connected displays.");
if (0 != NativeMethods.EnumDisplaySettings(
d.DeviceName, NativeMethods.ENUM_CURRENT_SETTINGS, ref dm))
{
if ((dm.dmDisplayOrientation + (int)Orientation) % 2 == 1) // Need to swap height and width?
{
int temp = dm.dmPelsHeight;
dm.dmPelsHeight = dm.dmPelsWidth;
dm.dmPelsWidth = temp;
}
switch (Orientation)
{
case Orientations.DEGREES_CW_90:
dm.dmDisplayOrientation = NativeMethods.DMDO_270;
break;
case Orientations.DEGREES_CW_180:
dm.dmDisplayOrientation = NativeMethods.DMDO_180;
break;
case Orientations.DEGREES_CW_270:
dm.dmDisplayOrientation = NativeMethods.DMDO_90;
break;
case Orientations.DEGREES_CW_0:
dm.dmDisplayOrientation = NativeMethods.DMDO_DEFAULT;
break;
default:
break;
}
DISP_CHANGE ret = NativeMethods.ChangeDisplaySettingsEx(
d.DeviceName, ref dm, IntPtr.Zero,
DisplaySettingsFlags.CDS_UPDATEREGISTRY, IntPtr.Zero);
result = ret == 0;
}
return result;
}
public static void ResetAllRotations()
{
try
{
uint i = 0;
while (++i <= 64)
{
Rotate(i, Orientations.DEGREES_CW_0);
}
}
catch(ArgumentOutOfRangeException ex)
{
// Everything is fine, just reached the last display
}
}
}
internal class NativeMethods
{
[DllImport("user32.dll")]
internal static extern DISP_CHANGE ChangeDisplaySettingsEx(
string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd,
DisplaySettingsFlags dwflags, IntPtr lParam);
[DllImport("user32.dll")]
internal static extern bool EnumDisplayDevices(
string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice,
uint dwFlags);
[DllImport("user32.dll", CharSet = CharSet.Ansi)]
internal static extern int EnumDisplaySettings(
string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);
public const int DMDO_DEFAULT = 0;
public const int DMDO_90 = 1;
public const int DMDO_180 = 2;
public const int DMDO_270 = 3;
public const int ENUM_CURRENT_SETTINGS = -1;
}
// See: https://msdn.microsoft.com/en-us/library/windows/desktop/dd183565(v=vs.85).aspx
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
internal struct DEVMODE
{
public const int CCHDEVICENAME = 32;
public const int CCHFORMNAME = 32;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
[System.Runtime.InteropServices.FieldOffset(0)]
public string dmDeviceName;
[System.Runtime.InteropServices.FieldOffset(32)]
public Int16 dmSpecVersion;
[System.Runtime.InteropServices.FieldOffset(34)]
public Int16 dmDriverVersion;
[System.Runtime.InteropServices.FieldOffset(36)]
public Int16 dmSize;
[System.Runtime.InteropServices.FieldOffset(38)]
public Int16 dmDriverExtra;
[System.Runtime.InteropServices.FieldOffset(40)]
public DM dmFields;
[System.Runtime.InteropServices.FieldOffset(44)]
Int16 dmOrientation;
[System.Runtime.InteropServices.FieldOffset(46)]
Int16 dmPaperSize;
[System.Runtime.InteropServices.FieldOffset(48)]
Int16 dmPaperLength;
[System.Runtime.InteropServices.FieldOffset(50)]
Int16 dmPaperWidth;
[System.Runtime.InteropServices.FieldOffset(52)]
Int16 dmScale;
[System.Runtime.InteropServices.FieldOffset(54)]
Int16 dmCopies;
[System.Runtime.InteropServices.FieldOffset(56)]
Int16 dmDefaultSource;
[System.Runtime.InteropServices.FieldOffset(58)]
Int16 dmPrintQuality;
[System.Runtime.InteropServices.FieldOffset(44)]
public POINTL dmPosition;
[System.Runtime.InteropServices.FieldOffset(52)]
public Int32 dmDisplayOrientation;
[System.Runtime.InteropServices.FieldOffset(56)]
public Int32 dmDisplayFixedOutput;
[System.Runtime.InteropServices.FieldOffset(60)]
public short dmColor;
[System.Runtime.InteropServices.FieldOffset(62)]
public short dmDuplex;
[System.Runtime.InteropServices.FieldOffset(64)]
public short dmYResolution;
[System.Runtime.InteropServices.FieldOffset(66)]
public short dmTTOption;
[System.Runtime.InteropServices.FieldOffset(68)]
public short dmCollate;
[System.Runtime.InteropServices.FieldOffset(72)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
public string dmFormName;
[System.Runtime.InteropServices.FieldOffset(102)]
public Int16 dmLogPixels;
[System.Runtime.InteropServices.FieldOffset(104)]
public Int32 dmBitsPerPel;
[System.Runtime.InteropServices.FieldOffset(108)]
public Int32 dmPelsWidth;
[System.Runtime.InteropServices.FieldOffset(112)]
public Int32 dmPelsHeight;
[System.Runtime.InteropServices.FieldOffset(116)]
public Int32 dmDisplayFlags;
[System.Runtime.InteropServices.FieldOffset(116)]
public Int32 dmNup;
[System.Runtime.InteropServices.FieldOffset(120)]
public Int32 dmDisplayFrequency;
}
// See: https://msdn.microsoft.com/en-us/library/windows/desktop/dd183569(v=vs.85).aspx
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal struct DISPLAY_DEVICE
{
[MarshalAs(UnmanagedType.U4)]
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceString;
[MarshalAs(UnmanagedType.U4)]
public DisplayDeviceStateFlags StateFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceKey;
}
// See: https://msdn.microsoft.com/de-de/library/windows/desktop/dd162807(v=vs.85).aspx
[StructLayout(LayoutKind.Sequential)]
internal struct POINTL
{
long x;
long y;
}
internal enum DISP_CHANGE : int
{
Successful = 0,
Restart = 1,
Failed = -1,
BadMode = -2,
NotUpdated = -3,
BadFlags = -4,
BadParam = -5,
BadDualView = -6
}
// http://www.pinvoke.net/default.aspx/Enums/DisplayDeviceStateFlags.html
[Flags()]
internal enum DisplayDeviceStateFlags : int
{
/// <summary>The device is part of the desktop.</summary>
AttachedToDesktop = 0x1,
MultiDriver = 0x2,
/// <summary>The device is part of the desktop.</summary>
PrimaryDevice = 0x4,
/// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
MirroringDriver = 0x8,
/// <summary>The device is VGA compatible.</summary>
VGACompatible = 0x10,
/// <summary>The device is removable; it cannot be the primary display.</summary>
Removable = 0x20,
/// <summary>The device has more display modes than its output devices support.</summary>
ModesPruned = 0x8000000,
Remote = 0x4000000,
Disconnect = 0x2000000
}
// http://www.pinvoke.net/default.aspx/user32/ChangeDisplaySettingsFlags.html
[Flags()]
internal enum DisplaySettingsFlags : int
{
CDS_NONE = 0,
CDS_UPDATEREGISTRY = 0x00000001,
CDS_TEST = 0x00000002,
CDS_FULLSCREEN = 0x00000004,
CDS_GLOBAL = 0x00000008,
CDS_SET_PRIMARY = 0x00000010,
CDS_VIDEOPARAMETERS = 0x00000020,
CDS_ENABLE_UNSAFE_MODES = 0x00000100,
CDS_DISABLE_UNSAFE_MODES= 0x00000200,
CDS_RESET = 0x40000000,
CDS_RESET_EX = 0x20000000,
CDS_NORESET = 0x10000000
}
[Flags()]
internal enum DM : int
{
Orientation = 0x00000001,
PaperSize = 0x00000002,
PaperLength = 0x00000004,
PaperWidth = 0x00000008,
Scale = 0x00000010,
Position = 0x00000020,
NUP = 0x00000040,
DisplayOrientation = 0x00000080,
Copies = 0x00000100,
DefaultSource = 0x00000200,
PrintQuality = 0x00000400,
Color = 0x00000800,
Duplex = 0x00001000,
YResolution = 0x00002000,
TTOption = 0x00004000,
Collate = 0x00008000,
FormName = 0x00010000,
LogPixels = 0x00020000,
BitsPerPixel = 0x00040000,
PelsWidth = 0x00080000,
PelsHeight = 0x00100000,
DisplayFlags = 0x00200000,
DisplayFrequency = 0x00400000,
ICMMethod = 0x00800000,
ICMIntent = 0x01000000,
MediaType = 0x02000000,
DitherType = 0x04000000,
PanningWidth = 0x08000000,
PanningHeight = 0x10000000,
DisplayFixedOutput = 0x20000000
}
You can simply invoke the static Rotate-Function with the display number you want to rotate (Monitor 1=1, Monitor 2=2, etc.) and the degree you need.
Like this:
Display.Rotate(1, Display.Orientations.DEGREES_CW_180);
There is also a little short-hand function ResetAllRotations() to reset all displays.
Regards

Related

EnumDisplayDevices() doesn't return any values in C#

Before this is flagged as a duplicate: Yes, I have tried every solution I could find on StackOverflow but nothing helped.
I'm trying to set the display resolutions of my monitors via C#. I got this working for my main monitor using the ChangeDisplaySettings() and EnumDisplaySettings() Methods from User32.dll.
My Problem is now that I have no idea how I could set the resolution of my second monitor. I tried getting the device name via the EnumDisplayDevices() Method, but all I'm getting is the following output: DeviceName =\ Monitor name = repeated multiple times.
The code that generates this output is seen below. Any idea what I could be doing wrong?
public static void GetDisplayNames()
{
DISPLAY_DEVICE lpDisplayDevice = new();
lpDisplayDevice.cb = Marshal.SizeOf(lpDisplayDevice);
DISPLAY_DEVICE monitor_name = new();
monitor_name.cb = Marshal.SizeOf(monitor_name);
uint devNum = 0;
var msg = "";
while (SystemMethods.EnumDisplayDevices(null, devNum, ref lpDisplayDevice, 0))
{
msg += "DeviceName =" + lpDisplayDevice.DeviceName.Trim() + '\n';
SystemMethods.EnumDisplayDevices(lpDisplayDevice.DeviceName, 0, ref monitor_name, 0);
msg += "Monitor name =" + monitor_name.DeviceString.Trim() + '\n';
++devNum;
}
Console.WriteLine(msg);
}
[DllImport("User32.dll", CharSet = CharSet.Unicode)]
internal static extern bool EnumDisplayDevices(
[param: MarshalAs(UnmanagedType.LPWStr)] string lpDevice,
[param: MarshalAs(UnmanagedType.U4)] uint iDevNum,
ref DISPLAY_DEVICE lpDisplayDevice,
[param: MarshalAs(UnmanagedType.U4)] uint dwFlags);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DISPLAY_DEVICE
{
[MarshalAs(UnmanagedType.U4)]
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceString;
[MarshalAs(UnmanagedType.U4)]
public DisplayDeviceStateFlags StateFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceKey;
}
[Flags()]
public enum DisplayDeviceStateFlags : int
{
/// <summary>The device is part of the desktop.</summary>
AttachedToDesktop = 0x1,
MultiDriver = 0x2,
/// <summary>The device is part of the desktop.</summary>
PrimaryDevice = 0x4,
/// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
MirroringDriver = 0x8,
/// <summary>The device is VGA compatible.</summary>
VGACompatible = 0x10,
/// <summary>The device is removable; it cannot be the primary display.</summary>
Removable = 0x20,
/// <summary>The device has more display modes than its output devices support.</summary>
ModesPruned = 0x8000000,
Remote = 0x4000000,
Disconnect = 0x2000000
}

WebBrowser ContextMenu run action of menu item

I have an application with a WebBrowser Control.
I load a page to it with a button click.
Then I want to run a "Convert to Adobe PDF" action from the context menu of the web browser but... when I try to access the context menu by:
foreach (MenuItem vMenuItem in WebBrowser.ContextMenu.MenuItems)
{
if (vMenuItem.Text.Contains("onwert") && vMenuItem.Text.Contains("PDF"))
{
vMenuItem.PerformClick();
}
}
The IDE displays an error "Object reference not set to an instance of an object" on line with
foreach (MenuItem vMenuItem in WebBrowser.ContextMenu.MenuItems)
I didn't create my own context menu, I want the default context menu to show.
How can I access the WebBrowser's context menu and perform that action?
i'm having a similar problem to you. I have made a reference to your problem in my post here.
If you are still interested in this problem this is working solution that makes use of simulating clicks:
//Example of how to use the code:
Point controlLoc = this.PointToScreen(webbrowser1.Location);
controlLoc.X = controlLoc.X + webbrowser1.Document.GetElementById("sbvdcapimg").OffsetRectangle.Left+65;
controlLoc.Y = controlLoc.Y + webbrowser1.Document.GetElementById("sbvdcapimg").OffsetRectangle.Top+50;
Cursor.Position = controlLoc;
MouseSimulator.ClickRightMouseButton();
controlLoc.X = controlLoc.X + (webbrowser1.Document.GetElementById("sbvdcapimg").OffsetRectangle.Left + 95);
controlLoc.Y = controlLoc.Y + (webbrowser1.Document.GetElementById("sbvdcapimg").OffsetRectangle.Top + 45);
Cursor.Position = controlLoc;
MouseSimulator.ClickLeftMouseButton();
public class MouseSimulator
{
[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);
[StructLayout(LayoutKind.Sequential)]
struct INPUT
{
public SendInputEventType type;
public MouseKeybdhardwareInputUnion mkhi;
}
[StructLayout(LayoutKind.Explicit)]
struct MouseKeybdhardwareInputUnion
{
[FieldOffset(0)]
public MouseInputData mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
struct MouseInputData
{
public int dx;
public int dy;
public uint mouseData;
public MouseEventFlags dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[Flags]
enum MouseEventFlags : uint
{
MOUSEEVENTF_MOVE = 0x0001,
MOUSEEVENTF_LEFTDOWN = 0x0002,
MOUSEEVENTF_LEFTUP = 0x0004,
MOUSEEVENTF_RIGHTDOWN = 0x0008,
MOUSEEVENTF_RIGHTUP = 0x0010,
MOUSEEVENTF_MIDDLEDOWN = 0x0020,
MOUSEEVENTF_MIDDLEUP = 0x0040,
MOUSEEVENTF_XDOWN = 0x0080,
MOUSEEVENTF_XUP = 0x0100,
MOUSEEVENTF_WHEEL = 0x0800,
MOUSEEVENTF_VIRTUALDESK = 0x4000,
MOUSEEVENTF_ABSOLUTE = 0x8000
}
enum SendInputEventType : int
{
InputMouse,
InputKeyboard,
InputHardware
}
public static void ClickRightMouseButton()
{
INPUT mouseDownInput = new INPUT();
mouseDownInput.type = SendInputEventType.InputMouse;
mouseDownInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTDOWN;
SendInput(1, ref mouseDownInput, Marshal.SizeOf(new INPUT()));
INPUT mouseUpInput = new INPUT();
mouseUpInput.type = SendInputEventType.InputMouse;
mouseUpInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTUP;
SendInput(1, ref mouseUpInput, Marshal.SizeOf(new INPUT()));
}
public static void ClickLeftMouseButton()
{
INPUT mouseDownInput = new INPUT();
mouseDownInput.type = SendInputEventType.InputMouse;
mouseDownInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN;
SendInput(1, ref mouseDownInput, Marshal.SizeOf(new INPUT()));
INPUT mouseUpInput = new INPUT();
mouseUpInput.type = SendInputEventType.InputMouse;
mouseUpInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP;
SendInput(1, ref mouseUpInput, Marshal.SizeOf(new INPUT()));
}

How to obtain the dll list of a specified process and loop through it to check if a certain function exists

How to obtain the modules list of a running process(for example a game launcher) then loop through the list and get a handle of the modules(dlls) to check if a certain function exists.
Thanks in advance,
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686849(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms683212(v=vs.85).aspx
But those are for c++ and I wasn't able to find some for c# .
To get the list of running processes:
Process[] processes = Process.GetProcesses();
You can then loop through the processes array looking for your target process.
Then you can call
ProcessModuleCollection modules = targetProcess.Modules;
to get hold of all the modules.
Then you can iterate over that collection and find each module's filename or handle. Note that the handle, the HMODULE in Win32 terms, is given by the BaseAddress property.
Finding out information about the exported functions is a little more difficult. That information is not readily available through the .net classes, and even in raw Win32 it's tricky because your code is executing out of process. You can't do anything with the HMODULE from another process.
The way to check for existence of a function is to use the dbghelp library to parse the PE data of the actual module file. I couldn't find any code on the web to do this, so I produced this translation of another Stack Overflow answer of mine. Note that I used a number of declarations from pinvoke.net. I hope this helps!
using System;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.ComponentModel;
internal static class NativeMethods
{
[Flags]
public enum EFileAccess : uint
{
//
// Standard Section
//
AccessSystemSecurity = 0x1000000, // AccessSystemAcl access type
MaximumAllowed = 0x2000000, // MaximumAllowed access type
Delete = 0x10000,
ReadControl = 0x20000,
WriteDAC = 0x40000,
WriteOwner = 0x80000,
Synchronize = 0x100000,
StandardRightsRequired = 0xF0000,
StandardRightsRead = ReadControl,
StandardRightsWrite = ReadControl,
StandardRightsExecute = ReadControl,
StandardRightsAll = 0x1F0000,
SpecificRightsAll = 0xFFFF,
FILE_READ_DATA = 0x0001, // file & pipe
FILE_LIST_DIRECTORY = 0x0001, // directory
FILE_WRITE_DATA = 0x0002, // file & pipe
FILE_ADD_FILE = 0x0002, // directory
FILE_APPEND_DATA = 0x0004, // file
FILE_ADD_SUBDIRECTORY = 0x0004, // directory
FILE_CREATE_PIPE_INSTANCE = 0x0004, // named pipe
FILE_READ_EA = 0x0008, // file & directory
FILE_WRITE_EA = 0x0010, // file & directory
FILE_EXECUTE = 0x0020, // file
FILE_TRAVERSE = 0x0020, // directory
FILE_DELETE_CHILD = 0x0040, // directory
FILE_READ_ATTRIBUTES = 0x0080, // all
FILE_WRITE_ATTRIBUTES = 0x0100, // all
//
// Generic Section
//
GenericRead = 0x80000000,
GenericWrite = 0x40000000,
GenericExecute = 0x20000000,
GenericAll = 0x10000000,
SPECIFIC_RIGHTS_ALL = 0x00FFFF,
FILE_ALL_ACCESS =
StandardRightsRequired |
Synchronize |
0x1FF,
FILE_GENERIC_READ =
StandardRightsRead |
FILE_READ_DATA |
FILE_READ_ATTRIBUTES |
FILE_READ_EA |
Synchronize,
FILE_GENERIC_WRITE =
StandardRightsWrite |
FILE_WRITE_DATA |
FILE_WRITE_ATTRIBUTES |
FILE_WRITE_EA |
FILE_APPEND_DATA |
Synchronize,
FILE_GENERIC_EXECUTE =
StandardRightsExecute |
FILE_READ_ATTRIBUTES |
FILE_EXECUTE |
Synchronize
}
[Flags]
public enum EFileShare : uint
{
/// <summary>
///
/// </summary>
None = 0x00000000,
/// <summary>
/// Enables subsequent open operations on an object to request read access.
/// Otherwise, other processes cannot open the object if they request read access.
/// If this flag is not specified, but the object has been opened for read access, the function fails.
/// </summary>
Read = 0x00000001,
/// <summary>
/// Enables subsequent open operations on an object to request write access.
/// Otherwise, other processes cannot open the object if they request write access.
/// If this flag is not specified, but the object has been opened for write access, the function fails.
/// </summary>
Write = 0x00000002,
/// <summary>
/// Enables subsequent open operations on an object to request delete access.
/// Otherwise, other processes cannot open the object if they request delete access.
/// If this flag is not specified, but the object has been opened for delete access, the function fails.
/// </summary>
Delete = 0x00000004
}
public enum ECreationDisposition : uint
{
/// <summary>
/// Creates a new file. The function fails if a specified file exists.
/// </summary>
New = 1,
/// <summary>
/// Creates a new file, always.
/// If a file exists, the function overwrites the file, clears the existing attributes, combines the specified file attributes,
/// and flags with FILE_ATTRIBUTE_ARCHIVE, but does not set the security descriptor that the SECURITY_ATTRIBUTES structure specifies.
/// </summary>
CreateAlways = 2,
/// <summary>
/// Opens a file. The function fails if the file does not exist.
/// </summary>
OpenExisting = 3,
/// <summary>
/// Opens a file, always.
/// If a file does not exist, the function creates a file as if dwCreationDisposition is CREATE_NEW.
/// </summary>
OpenAlways = 4,
/// <summary>
/// Opens a file and truncates it so that its size is 0 (zero) bytes. The function fails if the file does not exist.
/// The calling process must open the file with the GENERIC_WRITE access right.
/// </summary>
TruncateExisting = 5
}
[Flags]
public enum EFileAttributes : uint
{
Readonly = 0x00000001,
Hidden = 0x00000002,
System = 0x00000004,
Directory = 0x00000010,
Archive = 0x00000020,
Device = 0x00000040,
Normal = 0x00000080,
Temporary = 0x00000100,
SparseFile = 0x00000200,
ReparsePoint = 0x00000400,
Compressed = 0x00000800,
Offline = 0x00001000,
NotContentIndexed = 0x00002000,
Encrypted = 0x00004000,
Write_Through = 0x80000000,
Overlapped = 0x40000000,
NoBuffering = 0x20000000,
RandomAccess = 0x10000000,
SequentialScan = 0x08000000,
DeleteOnClose = 0x04000000,
BackupSemantics = 0x02000000,
PosixSemantics = 0x01000000,
OpenReparsePoint = 0x00200000,
OpenNoRecall = 0x00100000,
FirstPipeInstance = 0x00080000
}
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle CreateFile(
string lpFileName,
EFileAccess dwDesiredAccess,
EFileShare dwShareMode,
IntPtr lpSecurityAttributes,
ECreationDisposition dwCreationDisposition,
EFileAttributes dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[Flags]
public enum FileMapProtection : uint
{
PageReadonly = 0x02,
PageReadWrite = 0x04,
PageWriteCopy = 0x08,
PageExecuteRead = 0x20,
PageExecuteReadWrite = 0x40,
SectionCommit = 0x8000000,
SectionImage = 0x1000000,
SectionNoCache = 0x10000000,
SectionReserve = 0x4000000,
}
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle CreateFileMapping(
SafeFileHandle hFile,
IntPtr lpFileMappingAttributes,
FileMapProtection flProtect,
uint dwMaximumSizeHigh,
uint dwMaximumSizeLow,
string lpName
);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle CreateFileMapping(
SafeFileHandle hFile,
IntPtr lpFileMappingAttributes,
FileMapProtection flProtect,
uint dwMaximumSizeHigh,
uint dwMaximumSizeLow,
IntPtr lpName
);
[Flags]
public enum FileMapAccess : uint
{
FileMapCopy = 0x0001,
FileMapWrite = 0x0002,
FileMapRead = 0x0004,
FileMapAllAccess = 0x001f,
FileMapExecute = 0x0020,
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr MapViewOfFile(
SafeFileHandle hFileMappingObject,
FileMapAccess dwDesiredAccess,
UInt32 dwFileOffsetHigh,
UInt32 dwFileOffsetLow,
UIntPtr dwNumberOfBytesToMap
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool UnmapViewOfFile(IntPtr lpBaseAddress);
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_FILE_HEADER
{
public UInt16 Machine;
public UInt16 NumberOfSections;
public UInt32 TimeDateStamp;
public UInt32 PointerToSymbolTable;
public UInt32 NumberOfSymbols;
public UInt16 SizeOfOptionalHeader;
public UInt16 Characteristics;
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_DATA_DIRECTORY
{
public UInt32 VirtualAddress;
public UInt32 Size;
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_OPTIONAL_HEADER
{
public UInt16 Magic;
public Byte MajorLinkerVersion;
public Byte MinorLinkerVersion;
public UInt32 SizeOfCode;
public UInt32 SizeOfInitializedData;
public UInt32 SizeOfUninitializedData;
public UInt32 AddressOfEntryPoint;
public UInt32 BaseOfCode;
public UInt32 BaseOfData;
public UInt32 ImageBase;
public UInt32 SectionAlignment;
public UInt32 FileAlignment;
public UInt16 MajorOperatingSystemVersion;
public UInt16 MinorOperatingSystemVersion;
public UInt16 MajorImageVersion;
public UInt16 MinorImageVersion;
public UInt16 MajorSubsystemVersion;
public UInt16 MinorSubsystemVersion;
public UInt32 Win32VersionValue;
public UInt32 SizeOfImage;
public UInt32 SizeOfHeaders;
public UInt32 CheckSum;
public UInt16 Subsystem;
public UInt16 DllCharacteristics;
public UInt32 SizeOfStackReserve;
public UInt32 SizeOfStackCommit;
public UInt32 SizeOfHeapReserve;
public UInt32 SizeOfHeapCommit;
public UInt32 LoaderFlags;
public UInt32 NumberOfRvaAndSizes;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public IMAGE_DATA_DIRECTORY[] DataDirectory;
}
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_NT_HEADERS
{
public UInt32 Signature;
public IMAGE_FILE_HEADER FileHeader;
public IMAGE_OPTIONAL_HEADER OptionalHeader;
}
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern IntPtr ImageNtHeader(
IntPtr ImageBase
);
[StructLayout(LayoutKind.Sequential)]
public struct IMAGE_EXPORT_DIRECTORY
{
public UInt32 Characteristics;
public UInt32 TimeDateStamp;
public UInt16 MajorVersion;
public UInt16 MinorVersion;
public UInt32 Name;
public UInt32 Base;
public UInt32 NumberOfFunctions;
public UInt32 NumberOfNames;
public UInt32 AddressOfFunctions; // RVA from base of image
public UInt32 AddressOfNames; // RVA from base of image
public UInt32 AddressOfNameOrdinals; // RVA from base of image
}
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern IntPtr ImageRvaToVa(
IntPtr NtHeaders,
IntPtr Base,
UInt32 Rva,
IntPtr LastRvaSection
);
}
namespace ConsoleApplication1
{
class Program
{
private static string[] GetExports(string ModuleFileName)
{
SafeFileHandle FileHandle = NativeMethods.CreateFile(
ModuleFileName,
NativeMethods.EFileAccess.GenericRead,
NativeMethods.EFileShare.Read,
IntPtr.Zero,
NativeMethods.ECreationDisposition.OpenExisting,
NativeMethods.EFileAttributes.Normal,
IntPtr.Zero
);
if (FileHandle.IsInvalid)
throw new Win32Exception();
try
{
SafeFileHandle ImageHandle = NativeMethods.CreateFileMapping(
FileHandle,
IntPtr.Zero,
NativeMethods.FileMapProtection.PageReadonly,
0,
0,
IntPtr.Zero
);
if (ImageHandle.IsInvalid)
throw new Win32Exception();
try
{
IntPtr ImagePointer = NativeMethods.MapViewOfFile(
ImageHandle,
NativeMethods.FileMapAccess.FileMapRead,
0,
0,
UIntPtr.Zero
);
if (ImagePointer == IntPtr.Zero)
throw new Win32Exception();
try
{
IntPtr HeaderPointer = NativeMethods.ImageNtHeader(ImagePointer);
if (HeaderPointer == IntPtr.Zero)
throw new Win32Exception();
NativeMethods.IMAGE_NT_HEADERS Header = (NativeMethods.IMAGE_NT_HEADERS)Marshal.PtrToStructure(
HeaderPointer,
typeof(NativeMethods.IMAGE_NT_HEADERS)
);
if (Header.Signature != 0x00004550)// "PE\0\0" as a DWORD
throw new Exception(ModuleFileName + " is not a valid PE file");
IntPtr ExportTablePointer = NativeMethods.ImageRvaToVa(
HeaderPointer,
ImagePointer,
Header.OptionalHeader.DataDirectory[0].VirtualAddress,
IntPtr.Zero
);
if (ExportTablePointer == IntPtr.Zero)
throw new Win32Exception();
NativeMethods.IMAGE_EXPORT_DIRECTORY ExportTable = (NativeMethods.IMAGE_EXPORT_DIRECTORY)Marshal.PtrToStructure(
ExportTablePointer,
typeof(NativeMethods.IMAGE_EXPORT_DIRECTORY)
);
IntPtr NamesPointer = NativeMethods.ImageRvaToVa(
HeaderPointer,
ImagePointer,
ExportTable.AddressOfNames,
IntPtr.Zero
);
if (NamesPointer == IntPtr.Zero)
throw new Win32Exception();
NamesPointer = NativeMethods.ImageRvaToVa(
HeaderPointer,
ImagePointer,
(UInt32)Marshal.ReadInt32(NamesPointer),
IntPtr.Zero
);
if (NamesPointer == IntPtr.Zero)
throw new Win32Exception();
string[] exports = new string[ExportTable.NumberOfNames];
for (int i = 0; i < exports.Length; i++)
{
exports[i] = Marshal.PtrToStringAnsi(NamesPointer);
NamesPointer += exports[i].Length + 1;
}
return exports;
}
finally
{
if (!NativeMethods.UnmapViewOfFile(ImagePointer))
throw new Win32Exception();
}
}
finally
{
ImageHandle.Close();
}
}
finally
{
FileHandle.Close();
}
}
static void Main(string[] args)
{
foreach (string s in GetExports(#"C:\Windows\System32\kernel32.dll"))
{
Console.WriteLine(s);
}
Console.ReadLine();
}
}
}
You need to use P/Invoke to access the C++ functions. I would suggest you check out how to use P/Invoke and http://www.pinvoke.net/ (has a lot of resources for standard dlls), because the topic of P/Invoke is a bit much to be covered here.
Here is an example of how to use the DbgHelp dll to get the symbols from a loaded module. dummy3.dll is a dummy dll I created with C++, .net dlls don't have any symbols. If I understand correct it's because they just contain one large blob of bytecode. If you're enumerating all the loaded modules you'll probably want to use SymEnumerateModules64 like described here:
using System;
using System.Collections;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace dummy
{
class Program
{
static bool EnumSymProc(ref DbgHelp.SYMBOL_INFO pSymInfo,
UInt32 SymbolSize,
IntPtr UserContext)
{
Console.WriteLine(pSymInfo.Address + " " + SymbolSize + " " + pSymInfo.Name);
return true;
}
static void Main(string[] args)
{
Process process = Process.GetCurrentProcess();
ulong BaseOfDll;
string Mask = "*";
bool status;
status = DbgHelp.SymInitialize(process.Handle, null, false);
if (status == false)
{
return;
}
BaseOfDll = DbgHelp.SymLoadModuleEx(process.Handle,
IntPtr.Zero,
"dummy3.dll",
null,
IntPtr.Zero,
0,
IntPtr.Zero,
0);
if (BaseOfDll == 0)
{
DbgHelp.SymCleanup(process.Handle);
return;
}
if (DbgHelp.SymEnumSymbols(process.Handle, // Process handle from SymInitialize.
BaseOfDll, // Base address of module.
Mask, // Name of symbols to match.
new DbgHelp.SymEnumSymbolsProc(EnumSymProc), // Symbol handler procedure.
IntPtr.Zero)) // User context.
{
// SymEnumSymbols succeeded
}
else
{
// SymEnumSymbols failed
Console.WriteLine("SymEnumSymbols failed: " + Marshal.GetLastWin32Error());
}
DbgHelp.SymCleanup(process.Handle);
}
}
public static class DbgHelp
{
[Flags]
public enum SymOpt : uint
{
CASE_INSENSITIVE = 0x00000001,
UNDNAME = 0x00000002,
DEFERRED_LOADS = 0x00000004,
NO_CPP = 0x00000008,
LOAD_LINES = 0x00000010,
OMAP_FIND_NEAREST = 0x00000020,
LOAD_ANYTHING = 0x00000040,
IGNORE_CVREC = 0x00000080,
NO_UNQUALIFIED_LOADS = 0x00000100,
FAIL_CRITICAL_ERRORS = 0x00000200,
EXACT_SYMBOLS = 0x00000400,
ALLOW_ABSOLUTE_SYMBOLS = 0x00000800,
IGNORE_NT_SYMPATH = 0x00001000,
INCLUDE_32BIT_MODULES = 0x00002000,
PUBLICS_ONLY = 0x00004000,
NO_PUBLICS = 0x00008000,
AUTO_PUBLICS = 0x00010000,
NO_IMAGE_SEARCH = 0x00020000,
SECURE = 0x00040000,
SYMOPT_DEBUG = 0x80000000
};
[Flags]
public enum SymFlag : uint
{
VALUEPRESENT = 0x00000001,
REGISTER = 0x00000008,
REGREL = 0x00000010,
FRAMEREL = 0x00000020,
PARAMETER = 0x00000040,
LOCAL = 0x00000080,
CONSTANT = 0x00000100,
EXPORT = 0x00000200,
FORWARDER = 0x00000400,
FUNCTION = 0x00000800,
VIRTUAL = 0x00001000,
THUNK = 0x00002000,
TLSREL = 0x00004000,
}
[Flags]
public enum SymTagEnum : uint
{
Null,
Exe,
Compiland,
CompilandDetails,
CompilandEnv,
Function,
Block,
Data,
Annotation,
Label,
PublicSymbol,
UDT,
Enum,
FunctionType,
PointerType,
ArrayType,
BaseType,
Typedef,
BaseClass,
Friend,
FunctionArgType,
FuncDebugStart,
FuncDebugEnd,
UsingNamespace,
VTableShape,
VTable,
Custom,
Thunk,
CustomType,
ManagedType,
Dimension
};
[Flags]
public enum SymType : uint
{
SymNone,
SymCoff,
SymCv,
SymPdb,
SymExport,
SymDeferred,
SymSym,
SymDia,
SymVirtual,
}
[StructLayout(LayoutKind.Sequential)]
public struct SYMBOL_INFO
{
public uint SizeOfStruct;
public uint TypeIndex;
public ulong Reserved1;
public ulong Reserved2;
public uint Reserved3;
public uint Size;
public ulong ModBase;
public SymFlag Flags;
public ulong Value;
public ulong Address;
public uint Register;
public uint Scope;
public SymTagEnum Tag;
public int NameLen;
public int MaxNameLen;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string Name;
};
[StructLayout(LayoutKind.Sequential)]
public struct MODLOAD_DATA
{
UInt32 ssize;
UInt32 ssig;
object data;
UInt32 size;
UInt32 flags;
}
[StructLayout(LayoutKind.Sequential)]
public struct _IMAGEHLP_LINE64
{
public uint SizeOfStruct;
public uint Key;
public uint LineNumber;
public IntPtr FileName;
public ulong Address;
};
[StructLayout(LayoutKind.Sequential)]
public struct IMAGEHLP_MODULE64
{
public uint SizeOfStruct;
public ulong BaseOfImage;
public uint ImageSize;
public uint TimeDateStamp;
public uint CheckSum;
public uint NumSyms;
public SymType SymType;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string ModuleName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string ImageName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string LoadedImageName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string LoadedPdbName;
public uint CVSig;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 780)]
public string CVData;
public uint PdbSig;
public Guid PdbSig70;
public uint PdbAge;
public bool PdbUnmatched;
public bool DbgUnmatched;
public bool LineNumbers;
public bool GlobalSymbols;
public bool TypeInfo;
public bool SourceIndexed;
public bool Publics;
}
public delegate bool SymEnumSymbolsProc(ref SYMBOL_INFO pSymInfo, uint SymbolSize, IntPtr UserContext);
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern bool SymInitialize(IntPtr hProcess, string UserSearchPath, bool fInvadeProcess);
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern uint SymSetOptions(SymOpt SymOptions);
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern ulong SymLoadModule64(IntPtr hProcess, IntPtr hFile,
string ImageName, string ModuleName,
ulong BaseOfDll, uint SizeOfDll);
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern ulong SymLoadModuleEx(IntPtr hProcess, IntPtr hFile,
string ImageName, string ModuleName, IntPtr BaseOfDll,
UInt32 DllSize, ref MODLOAD_DATA Data, UInt32 Flags);
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern ulong SymLoadModuleEx(IntPtr hProcess, IntPtr hFile,
string ImageName, string ModuleName, IntPtr BaseOfDll,
UInt32 DllSize, IntPtr Data, UInt32 Flags);
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern bool SymGetModuleInfo64(IntPtr hProcess, ulong dwAddress, ref IMAGEHLP_MODULE64 ModuleInfo);
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern bool SymEnumSymbols(IntPtr hProcess, ulong BaseOfDll, string Mask, SymEnumSymbolsProc EnumSymbolsCallback, IntPtr UserContext);
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern bool SymGetLineFromAddr64(IntPtr hProcess,
ulong dwAddr, ref uint pdwDisplacement, ref _IMAGEHLP_LINE64 Line);
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern bool SymFromAddr(IntPtr hProcess,
ulong dwAddr, ref ulong pdwDisplacement, ref SYMBOL_INFO symbolInfo);
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern bool SymEnumSymbolsForAddr(IntPtr hProcess,
ulong Address, SymEnumSymbolsProc EnumSymbolsCallback, IntPtr UserContext);
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern bool SymUnloadModule64(IntPtr hProcess, ulong BaseOfDll);
[DllImport("dbghelp.dll", SetLastError = true)]
public static extern bool SymCleanup(IntPtr hProcess);
}
}

How to change duplex in the middle of a print job from .NET

I have a program which prints a multi-page document. The first page is pre-printed paper, so it should print on the first side, and the rest of the pages should be duplexed.
My initial solution was to just print a blank sheet after the first page, but a lot (or maybe all) printers will use a different side of the pre-printed paper as the front (very bad), depending on whether it is set for duplexing or not.
So I'm stuck trying to convince the printer to change duplexing in the middle of the print job. I've been fighting with this without any luck, and using various code samples, this should theoretically work, but it doesn't.
After each EndPage call, if the duplexing needs to change, it gets the device context from the printer (using reflection on a private field of an internal class, yuck), it uses Marshal to fill in values on the DEVMODE structure, and then calls ResetDC() with the device context and DEVMODE pointer.
I retrieve the DEVMODE structure from the pointer for verification purposes only, I want to make sure I'm setting the correct fields. DEVMODE gets populated correctly and sent to ResetDC() and PrinterSettings.SetHdevmode(), but when I re-retrieve PrinterSettings.GetHdevmode(), the changes I just made are gone. And the printer keeps the old duplex setting.
Edit: I found some issues with code I posted before, such as the fact that OnStartPage calls ResetDC. So I need to be modifying the DEVMODE structure held by StandardPrintController. But it's still not working with these changes:
public class PrinterDuplexController : StandardPrintController
{
public PrinterDuplexController()
{
}
private static FieldInfo dcField = typeof(StandardPrintController)
.GetField("dc",
BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
private static FieldInfo modeHandleField = typeof(StandardPrintController)
.GetField("modeHandle",
BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
protected object dc
{
get
{
return dcField.GetValue(this);
}
}
protected IntPtr Hdc
{
get
{
var dc = this.dc;
return (IntPtr)(dc.GetType().GetProperty("Hdc").GetValue(dc, null));
}
}
protected IntPtr modeHandle
{
get
{
object result = modeHandleField.GetValue(this);
var field = result.GetType().GetField("handle", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
return (IntPtr)field.GetValue(result);
}
}
public override void OnEndPage(PrintDocument document, PrintPageEventArgs e)
{
base.OnEndPage(document, e);
IntPtr pDEVMODE = GlobalLock(modeHandle);
try
{
int[] flags = new int[1];
Marshal.Copy(
new IntPtr(40 + pDEVMODE.ToInt64()),
flags,
0,
1);
flags[0] |= (int)DM.Duplex;
Marshal.Copy(
flags,
0,
new IntPtr(40 + pDEVMODE.ToInt64()),
1);
Marshal.Copy(
new short[] { (short)e.PageSettings.PrinterSettings.Duplex },
0,
new IntPtr(62 + pDEVMODE.ToInt64()),
1);
var debugDevMode = (DEVMODE)Marshal.PtrToStructure(pDEVMODE, typeof(DEVMODE));
ResetDC(Hdc, pDEVMODE);
}
finally
{
GlobalUnlock(modeHandle);
}
}
[DllImport("gdi32.dll")]
//private static extern IntPtr ResetDC(IntPtr hdc, [In] ref DEVMODE lpInitData);
private static extern int ResetDC(IntPtr hdc, IntPtr DevMode);
[DllImport("gdi32.dll")]
public static extern int StartPage(IntPtr hdc);
[DllImport("gdi32.dll")]
public static extern int EndPage(IntPtr hdc);
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern IntPtr GlobalFree(IntPtr handle);
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern IntPtr GlobalLock(IntPtr handle);
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern IntPtr GlobalUnlock(IntPtr handle);
[Flags()]
internal enum DM : int
{
Orientation = 0x1,
PaperSize = 0x2,
PaperLength = 0x4,
PaperWidth = 0x8,
Scale = 0x10,
Position = 0x20,
NUP = 0x40,
DisplayOrientation = 0x80,
Copies = 0x100,
DefaultSource = 0x200,
PrintQuality = 0x400,
Color = 0x800,
Duplex = 0x1000,
YResolution = 0x2000,
TTOption = 0x4000,
Collate = 0x8000,
FormName = 0x10000,
LogPixels = 0x20000,
BitsPerPixel = 0x40000,
PelsWidth = 0x80000,
PelsHeight = 0x100000,
DisplayFlags = 0x200000,
DisplayFrequency = 0x400000,
ICMMethod = 0x800000,
ICMIntent = 0x1000000,
MediaType = 0x2000000,
DitherType = 0x4000000,
PanningWidth = 0x8000000,
PanningHeight = 0x10000000,
DisplayFixedOutput = 0x20000000
}
internal struct POINTL
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode)]
internal struct DEVMODE
{
public const int CCHDEVICENAME = 32;
public const int CCHFORMNAME = 32;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
[FieldOffset(0)]
public string dmDeviceName;
[FieldOffset(32)]
public Int16 dmSpecVersion;
[FieldOffset(34)]
public Int16 dmDriverVersion;
[FieldOffset(36)]
public Int16 dmSize;
[FieldOffset(38)]
public Int16 dmDriverExtra;
[FieldOffset(40)]
public DM dmFields;
[FieldOffset(44)]
Int16 dmOrientation;
[FieldOffset(46)]
Int16 dmPaperSize;
[FieldOffset(48)]
Int16 dmPaperLength;
[FieldOffset(50)]
Int16 dmPaperWidth;
[FieldOffset(52)]
Int16 dmScale;
[FieldOffset(54)]
Int16 dmCopies;
[FieldOffset(56)]
Int16 dmDefaultSource;
[FieldOffset(58)]
Int16 dmPrintQuality;
[FieldOffset(44)]
public POINTL dmPosition;
[FieldOffset(52)]
public Int32 dmDisplayOrientation;
[FieldOffset(56)]
public Int32 dmDisplayFixedOutput;
[FieldOffset(60)]
public short dmColor;
[FieldOffset(62)]
public short dmDuplex;
[FieldOffset(64)]
public short dmYResolution;
[FieldOffset(66)]
public short dmTTOption;
[FieldOffset(68)]
public short dmCollate;
[FieldOffset(72)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
public string dmFormName;
[FieldOffset(102)]
public Int16 dmLogPixels;
[FieldOffset(104)]
public Int32 dmBitsPerPel;
[FieldOffset(108)]
public Int32 dmPelsWidth;
[FieldOffset(112)]
public Int32 dmPelsHeight;
[FieldOffset(116)]
public Int32 dmDisplayFlags;
[FieldOffset(116)]
public Int32 dmNup;
[FieldOffset(120)]
public Int32 dmDisplayFrequency;
}
}
Try making two print jobs, each with the different duplex settings. Fiddle with priorities of the jobs to get them in order instead of hacking around internal fields.

Use Windows API from C# to set primary monitor

I'm trying to use the Windows API to set the primary monitor. It doesn't seem to work - my screen just flicks and nothing happens.
public const int DM_ORIENTATION = 0x00000001;
public const int DM_PAPERSIZE = 0x00000002;
public const int DM_PAPERLENGTH = 0x00000004;
public const int DM_PAPERWIDTH = 0x00000008;
public const int DM_SCALE = 0x00000010;
public const int DM_POSITION = 0x00000020;
public const int DM_NUP = 0x00000040;
public const int DM_DISPLAYORIENTATION = 0x00000080;
public const int DM_COPIES = 0x00000100;
public const int DM_DEFAULTSOURCE = 0x00000200;
public const int DM_PRINTQUALITY = 0x00000400;
public const int DM_COLOR = 0x00000800;
public const int DM_DUPLEX = 0x00001000;
public const int DM_YRESOLUTION = 0x00002000;
public const int DM_TTOPTION = 0x00004000;
public const int DM_COLLATE = 0x00008000;
public const int DM_FORMNAME = 0x00010000;
public const int DM_LOGPIXELS = 0x00020000;
public const int DM_BITSPERPEL = 0x00040000;
public const int DM_PELSWIDTH = 0x00080000;
public const int DM_PELSHEIGHT = 0x00100000;
public const int DM_DISPLAYFLAGS = 0x00200000;
public const int DM_DISPLAYFREQUENCY = 0x00400000;
public const int DM_ICMMETHOD = 0x00800000;
public const int DM_ICMINTENT = 0x01000000;
public const int DM_MEDIATYPE = 0x02000000;
public const int DM_DITHERTYPE = 0x04000000;
public const int DM_PANNINGWIDTH = 0x08000000;
public const int DM_PANNINGHEIGHT = 0x10000000;
public const int DM_DISPLAYFIXEDOUTPUT = 0x20000000;
public const int ENUM_CURRENT_SETTINGS = -1;
public const int CDS_UPDATEREGISTRY = 0x01;
public const int CDS_TEST = 0x02;
public const int CDS_SET_PRIMARY = 0x00000010;
public const long DISP_CHANGE_SUCCESSFUL = 0;
public const long DISP_CHANGE_RESTART = 1;
public const long DISP_CHANGE_FAILED = -1;
public const long DISP_CHANGE_BADMODE = -2;
public const long DISP_CHANGE_NOTUPDATED = -3;
public const long DISP_CHANGE_BADFLAGS = -4;
public const long DISP_CHANGE_BADPARAM = -5;
public const long DISP_CHANGE_BADDUALVIEW = -6;
public static void SetPrimary(Screen screen)
{
DISPLAY_DEVICE d = new DISPLAY_DEVICE();
DEVMODE dm = new DEVMODE();
d.cb = Marshal.SizeOf(d);
uint deviceID = 1;
User_32.EnumDisplayDevices(null, deviceID, ref d, 0); //
User_32.EnumDisplaySettings(d.DeviceName, 0, ref dm);
dm.dmPelsWidth = 2560;
dm.dmPelsHeight = 1600;
dm.dmPositionX = screen.Bounds.Right;
dm.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
User_32.ChangeDisplaySettingsEx(d.DeviceName, ref dm, IntPtr.Zero, CDS_SET_PRIMARY, IntPtr.Zero);
}
I call the method like this:
SetPrimary(Screen.AllScreens[1])
Any ideas?
Here is the full code based on ADBailey's solution:
public class MonitorChanger
{
public static void SetAsPrimaryMonitor(uint id)
{
var device = new DISPLAY_DEVICE();
var deviceMode = new DEVMODE();
device.cb = Marshal.SizeOf(device);
NativeMethods.EnumDisplayDevices(null, id, ref device, 0);
NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref deviceMode);
var offsetx = deviceMode.dmPosition.x;
var offsety = deviceMode.dmPosition.y;
deviceMode.dmPosition.x = 0;
deviceMode.dmPosition.y = 0;
NativeMethods.ChangeDisplaySettingsEx(
device.DeviceName,
ref deviceMode,
(IntPtr)null,
(ChangeDisplaySettingsFlags.CDS_SET_PRIMARY | ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET),
IntPtr.Zero);
device = new DISPLAY_DEVICE();
device.cb = Marshal.SizeOf(device);
// Update remaining devices
for (uint otherid = 0; NativeMethods.EnumDisplayDevices(null, otherid, ref device, 0); otherid++)
{
if (device.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop) && otherid != id)
{
device.cb = Marshal.SizeOf(device);
var otherDeviceMode = new DEVMODE();
NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref otherDeviceMode);
otherDeviceMode.dmPosition.x -= offsetx;
otherDeviceMode.dmPosition.y -= offsety;
NativeMethods.ChangeDisplaySettingsEx(
device.DeviceName,
ref otherDeviceMode,
(IntPtr)null,
(ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET),
IntPtr.Zero);
}
device.cb = Marshal.SizeOf(device);
}
// Apply settings
NativeMethods.ChangeDisplaySettingsEx(null, IntPtr.Zero, (IntPtr)null, ChangeDisplaySettingsFlags.CDS_NONE, (IntPtr)null);
}
}
[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct DEVMODE
{
public const int CCHDEVICENAME = 32;
public const int CCHFORMNAME = 32;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
[System.Runtime.InteropServices.FieldOffset(0)]
public string dmDeviceName;
[System.Runtime.InteropServices.FieldOffset(32)]
public Int16 dmSpecVersion;
[System.Runtime.InteropServices.FieldOffset(34)]
public Int16 dmDriverVersion;
[System.Runtime.InteropServices.FieldOffset(36)]
public Int16 dmSize;
[System.Runtime.InteropServices.FieldOffset(38)]
public Int16 dmDriverExtra;
[System.Runtime.InteropServices.FieldOffset(40)]
public UInt32 dmFields;
[System.Runtime.InteropServices.FieldOffset(44)]
Int16 dmOrientation;
[System.Runtime.InteropServices.FieldOffset(46)]
Int16 dmPaperSize;
[System.Runtime.InteropServices.FieldOffset(48)]
Int16 dmPaperLength;
[System.Runtime.InteropServices.FieldOffset(50)]
Int16 dmPaperWidth;
[System.Runtime.InteropServices.FieldOffset(52)]
Int16 dmScale;
[System.Runtime.InteropServices.FieldOffset(54)]
Int16 dmCopies;
[System.Runtime.InteropServices.FieldOffset(56)]
Int16 dmDefaultSource;
[System.Runtime.InteropServices.FieldOffset(58)]
Int16 dmPrintQuality;
[System.Runtime.InteropServices.FieldOffset(44)]
public POINTL dmPosition;
[System.Runtime.InteropServices.FieldOffset(52)]
public Int32 dmDisplayOrientation;
[System.Runtime.InteropServices.FieldOffset(56)]
public Int32 dmDisplayFixedOutput;
[System.Runtime.InteropServices.FieldOffset(60)]
public short dmColor; // See note below!
[System.Runtime.InteropServices.FieldOffset(62)]
public short dmDuplex; // See note below!
[System.Runtime.InteropServices.FieldOffset(64)]
public short dmYResolution;
[System.Runtime.InteropServices.FieldOffset(66)]
public short dmTTOption;
[System.Runtime.InteropServices.FieldOffset(68)]
public short dmCollate; // See note below!
[System.Runtime.InteropServices.FieldOffset(72)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
public string dmFormName;
[System.Runtime.InteropServices.FieldOffset(102)]
public Int16 dmLogPixels;
[System.Runtime.InteropServices.FieldOffset(104)]
public Int32 dmBitsPerPel;
[System.Runtime.InteropServices.FieldOffset(108)]
public Int32 dmPelsWidth;
[System.Runtime.InteropServices.FieldOffset(112)]
public Int32 dmPelsHeight;
[System.Runtime.InteropServices.FieldOffset(116)]
public Int32 dmDisplayFlags;
[System.Runtime.InteropServices.FieldOffset(116)]
public Int32 dmNup;
[System.Runtime.InteropServices.FieldOffset(120)]
public Int32 dmDisplayFrequency;
}
public enum DISP_CHANGE : int
{
Successful = 0,
Restart = 1,
Failed = -1,
BadMode = -2,
NotUpdated = -3,
BadFlags = -4,
BadParam = -5,
BadDualView = -6
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DISPLAY_DEVICE
{
[MarshalAs(UnmanagedType.U4)]
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceString;
[MarshalAs(UnmanagedType.U4)]
public DisplayDeviceStateFlags StateFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceKey;
}
[Flags()]
public enum DisplayDeviceStateFlags : int
{
/// <summary>The device is part of the desktop.</summary>
AttachedToDesktop = 0x1,
MultiDriver = 0x2,
/// <summary>The device is part of the desktop.</summary>
PrimaryDevice = 0x4,
/// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
MirroringDriver = 0x8,
/// <summary>The device is VGA compatible.</summary>
VGACompatible = 0x10,
/// <summary>The device is removable; it cannot be the primary display.</summary>
Removable = 0x20,
/// <summary>The device has more display modes than its output devices support.</summary>
ModesPruned = 0x8000000,
Remote = 0x4000000,
Disconnect = 0x2000000,
}
[Flags()]
public enum ChangeDisplaySettingsFlags : uint
{
CDS_NONE = 0,
CDS_UPDATEREGISTRY = 0x00000001,
CDS_TEST = 0x00000002,
CDS_FULLSCREEN = 0x00000004,
CDS_GLOBAL = 0x00000008,
CDS_SET_PRIMARY = 0x00000010,
CDS_VIDEOPARAMETERS = 0x00000020,
CDS_ENABLE_UNSAFE_MODES = 0x00000100,
CDS_DISABLE_UNSAFE_MODES = 0x00000200,
CDS_RESET = 0x40000000,
CDS_RESET_EX = 0x20000000,
CDS_NORESET = 0x10000000
}
public class NativeMethods
{
[DllImport("user32.dll")]
public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam);
[DllImport("user32.dll")]
// A signature for ChangeDisplaySettingsEx with a DEVMODE struct as the second parameter won't allow you to pass in IntPtr.Zero, so create an overload
public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, IntPtr lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);
[DllImport("user32.dll")]
public static extern bool EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE devMode);
}
[StructLayout(LayoutKind.Sequential)]
public struct POINTL
{
public int x;
public int y;
}
I ran into exactly the same problem, both from C# and after following the advice here to try it in C++. I eventually discovered that the thing the Microsoft documentation doesn't make clear is that the request to set the primary monitor will be ignored (but with the operation reported as successful!) unless you also set the position of the monitor to (0, 0) on the DEVMODE struct. Of course, this means that you also need to shift the positions of your other monitors so that they stay in the same place relative to the new primary monitor. Per the documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/dd183413%28v=vs.85%29.aspx), call ChangeDisplaySettingsEx for each monitor with the CDS_NORESET flag and then make a final call with everything null.
The following code worked for me:
public static void SetAsPrimaryMonitor(uint id)
{
var device = new DISPLAY_DEVICE();
var deviceMode = new DEVMODE();
device.cb = Marshal.SizeOf(device);
NativeMethods.EnumDisplayDevices(null, id, ref device, 0);
NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref deviceMode);
var offsetx = deviceMode.dmPosition.x;
var offsety = deviceMode.dmPosition.y;
deviceMode.dmPosition.x = 0;
deviceMode.dmPosition.y = 0;
NativeMethods.ChangeDisplaySettingsEx(
device.DeviceName,
ref deviceMode,
(IntPtr)null,
(ChangeDisplaySettingsFlags.CDS_SET_PRIMARY | ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET),
IntPtr.Zero);
device = new DISPLAY_DEVICE();
device.cb = Marshal.SizeOf(device);
// Update remaining devices
for (uint otherid = 0; NativeMethods.EnumDisplayDevices(null, otherid, ref device, 0); otherid++)
{
if (device.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop) && otherid != id)
{
device.cb = Marshal.SizeOf(device);
var otherDeviceMode = new DEVMODE();
NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref otherDeviceMode);
otherDeviceMode.dmPosition.x -= offsetx;
otherDeviceMode.dmPosition.y -= offsety;
NativeMethods.ChangeDisplaySettingsEx(
device.DeviceName,
ref otherDeviceMode,
(IntPtr)null,
(ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET),
IntPtr.Zero);
}
device.cb = Marshal.SizeOf(device);
}
// Apply settings
NativeMethods.ChangeDisplaySettingsEx(null, IntPtr.Zero, (IntPtr)null, ChangeDisplaySettingsFlags.CDS_NONE, (IntPtr)null);
}
Note that a signature for ChangeDisplaySettingsEx with a DEVMODE struct as the second parameter obviously won't allow you to pass in IntPtr.Zero. Create yourself two different signatures for the same extern call, i.e.
[DllImport("user32.dll")]
public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam);
[DllImport("user32.dll")]
public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, IntPtr lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam);
I can't really help you with the winapi-stuff but if you are using a Nvidia card you may have a look at the NVcontrolPanel Api Documentation
Then you could make the secondary output your primary using rundll32.exe NvCpl.dll,dtcfg primary 2
Hope that will help you.
According to the documentation for ChangeDisplaySettingsEx, "the dmSize member must be initialized to the size, in bytes, of the DEVMODE structure." Furthermore, the EnumDisplaySettings documentation states, "Before calling EnumDisplaySettings, set the dmSize member to sizeof(DEVMODE), and set the dmDriverExtra member to indicate the size, in bytes, of the additional space available to receive private driver data". I don't see this happening in the code sample given in the question; that's one reason why it may be failing.
Additionally, you might have errors in the definitions of the DEVMODE and DISPLAY_DEVICE structs, which were not included in the question. Roger Lipscombe's suggestion to get it working from C/C++ first is an excellent way to rule out this type of problem.
Finally, check the return value from ChangeDisplaySettingsEx and see if that gives a clue as to why it might be failing.

Categories

Resources