I'm trying to make a C# application, which is going to control a game. That I'm trying to do is for example: Hold key A for 150ms, Hold left arrow for 500ms and so on.
I was searching a lot and I found the following code. My program firstly target the game and then holding the keys.
I'm holding the keys this way:
Keyboard.HoldKey(Keys.Left);
Thread.sleep(500);
Keyboard.ReleaseKey(Keys.Left);
Here is the Keyboard class:
public class Keyboard
{
public Keyboard()
{
}
[StructLayout(LayoutKind.Explicit, Size = 28)]
public struct Input
{
[FieldOffset(0)]
public uint type;
[FieldOffset(4)]
public KeyboardInput ki;
}
public struct KeyboardInput
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public long time;
public uint dwExtraInfo;
}
const int KEYEVENTF_KEYUP = 0x0002;
const int INPUT_KEYBOARD = 1;
[DllImport("user32.dll")]
public static extern int SendInput(uint cInputs, ref Input inputs, int cbSize);
[DllImport("user32.dll")]
static extern short GetKeyState(int nVirtKey);
[DllImport("user32.dll")]
static extern ushort MapVirtualKey(int wCode, int wMapType);
public static bool IsKeyDown(Keys key)
{
return (GetKeyState((int)key) & -128) == -128;
}
public static void HoldKey(Keys vk)
{
ushort nScan = MapVirtualKey((ushort)vk, 0);
Input input = new Input();
input.type = INPUT_KEYBOARD;
input.ki.wVk = (ushort)vk;
input.ki.wScan = nScan;
input.ki.dwFlags = 0;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;
SendInput(1, ref input, Marshal.SizeOf(input)).ToString();
}
public static void ReleaseKey(Keys vk)
{
ushort nScan = MapVirtualKey((ushort)vk, 0);
Input input = new Input();
input.type = INPUT_KEYBOARD;
input.ki.wVk = (ushort)vk;
input.ki.wScan = nScan;
input.ki.dwFlags = KEYEVENTF_KEYUP;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;
SendInput(1, ref input, Marshal.SizeOf(input));
}
public static void PressKey(Keys vk)
{
HoldKey(vk);
ReleaseKey(vk);
}
}
and its working in notepad/browser etc, but it IS NOT working in any game, no matter fullscreen or window mode.
Can you help me to figure out how I can hold keys in full screen apps/games?
Thanks!
"Hold key A for 150ms, Hold left arrow for 500ms"
See if this works:
Keyboard.HoldKey((byte)Keys.A, 150);
Keyboard.HoldKey((byte)Keys.Left, 500);
Using:
public class Keyboard
{
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
const int KEY_DOWN_EVENT = 0x0001; //Key down flag
const int KEY_UP_EVENT = 0x0002; //Key up flag
public static void HoldKey(byte key, int duration)
{
int totalDuration = 0;
while (totalDuration < duration)
{
keybd_event(key, 0, KEY_DOWN_EVENT, 0);
keybd_event(key, 0, KEY_UP_EVENT, 0);
System.Threading.Thread.Sleep(PauseBetweenStrokes);
totalDuration += PauseBetweenStrokes;
}
}
}
You can get it to work with that, this works great for holding down keys:
public class Keyboard
{
const int PauseBetweenStrokes = 50;
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
const int KEY_DOWN_EVENT = 0x0001; //Key down flag
const int KEY_UP_EVENT = 0x0002; //Key up flag
public static void HoldKey(byte key, int duration)
{
keybd_event(key, 0, KEY_DOWN_EVENT, 0);
System.Threading.Thread.Sleep(duration);
keybd_event(key, 0, KEY_UP_EVENT, 0);
}
}
I did it with Windown API and SendInput method.
If you define the Keyboard class as:
public static class Keyboard
{
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
public static void Delay(int delay)
{
System.Threading.Thread.Sleep(delay);
}
public static void KeyDown(KEYCODE keycode)
{
keybd_event((byte)keycode, 0x0, 0, 0);// presses
}
public static void KeyPress(KEYCODE keycode, int delay = 0)
{
keybd_event((byte)keycode, 0x0, 0, 0);// presses
System.Threading.Thread.Sleep(delay);
keybd_event((byte)keycode, 0x0, 2, 0); //releases
}
public static void KeyUp(KEYCODE keycode)
{
keybd_event((byte)keycode, 0, 2, 0); //release
}
public static void Type(string message)
{
System.Windows.Forms.SendKeys.SendWait(message);
}
}
and the keycode as
public enum KEYCODE {
VK_A = 0x41, VK_B = 0x42, VK_C = 0x43, VK_D = 0x44, VK_E = 0x45, VK_F = 0x46, VK_G = 0x47,
VK_H = 0x48, VK_I = 0x49, VK_J = 0x4A, VK_K = 0x4B, VK_L = 0x4C, VK_M = 0x4D, VK_N = 0x4E, VK_O = 0x4F,
VK_P = 0x50, VK_Q = 0x51, VK_R = 0x52, VK_S = 0x53, VK_T = 0x54, VK_U = 0x55, VK_V = 0x56, VK_W = 0x57,
VK_X = 0x58, VK_Y = 0x59, VK_Z = 0x5A, VK_LSHIFT = 0xA0, VK_RSHIFT = 0xA1, VK_LCONTROL = 0xA2, VK_RCONTROL = 0xA3
}
You can run the following:
Keyboard.KeyDown(KEYCODE.VK_LSHIFT);
Keyboard.KeyPress(KEYCODE.VK_V);
Keyboard.KeyUp(KEYCODE.VK_LSHIFT);
Keyboard.KeyPress(KEYCODE.VK_I);
Keyboard.KeyPress(KEYCODE.VK_N);
Keyboard.KeyPress(KEYCODE.VK_O);
Keyboard.KeyPress(KEYCODE.VK_D);
And it will print Vinod making V in capital since the shift is pressed.
But if you trying to send multiple keystrokes like typing a text you can use the Keyboard.Type() instead like
Keyboard.Type("+vino+d");
and it will print VinoD making V and D capital for more help see the document here
Even I have written something called Robot.cs which has the complete code of Keyboard, Mouse & Process automation.
Related
I've been searching for a while and there are mostly results in C++ or other languages, and not C#. Things I've seen:
keybd_event() // A c++ method that theoretically can be included with a DLL import, but hasn't worked in testing
System.Windows.Forms.SendKeys.Send("{NUMLOCK}"}; // Forms namespace doesn't exist in Windows
Currently, I have code that executes every second or so to watch the state of numlock and update a graphic in my form accordingly. If a bool toggle is set, I also want it to force NumLock on:
internal partial class Interop
{
public static int VK_NUMLOCK = 0x90;
public static int VK_SCROLL = 0x91;
public static int VK_CAPITAL = 0x14;
public static int KEYEVENTF_EXTENDEDKEY = 0x0001; // If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
public static int KEYEVENTF_KEYUP = 0x0002; // If specified, the key is being released. If not specified, the key is being depressed.
[DllImport("User32.dll", SetLastError = true)]
public static extern void keybd_event(
byte bVk,
byte bScan,
int dwFlags,
IntPtr dwExtraInfo);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetKeyState(int nVirtKey);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetAsyncKeyState(int vKey);
}
private void watcher(object source, ElapsedEventArgs e)
{
bool NumLock = (((ushort)GetKeyState(0x90)) & 0xffff) != 0;
if (!NumLock && fixers.watchNumL)
{
// Force NumLock back on
// Simulate a key press
Interop.keybd_event((byte)0x90,0x45,Interop.KEYEVENTF_EXTENDEDKEY | 0,IntPtr.Zero);
// Simulate a key release
Interop.keybd_event((byte)0x90,0x45,Interop.KEYEVENTF_EXTENDEDKEY | Interop.KEYEVENTF_KEYUP, IntPtr.Zero);
NumLock = (((ushort)GetKeyState(0x90)) & 0xffff) != 0;
}
if (NumLock)
{
this.Dispatcher.Invoke(() =>
{
fixerBoxes["NumL"].FixerImg.Source = new BitmapImage(new Uri(#"/graphics/num_lock_on.png", UriKind.Relative));
StatusBox.Text = "Num Lock ON";
});
}
else {
this.Dispatcher.Invoke(() =>
{
fixerBoxes["NumL"].FixerImg.Source = new BitmapImage(new Uri(#"/graphics/num_lock_off.png", UriKind.Relative));
StatusBox.Text = "Num Lock OFF";
});
}
}
public MainWindow()
{
// Start the watcher
System.Timers.Timer myTimer = new System.Timers.Timer();
// Tell the timer what to do when it elapses
myTimer.Elapsed += new ElapsedEventHandler(watcher);
// Set it to go off every second
myTimer.Interval = 1000;
// And start it
myTimer.Enabled = true;
}
Here is a class (with a library) that can do this for you. the library does much more, so it's maybe a bit overkill to use just for this. The approach uses the keybd_event function using pinvoke:
// Simulate a key press
Interop.keybd_event((byte)virtualKey,
0x45,
Interop.KEYEVENTF_EXTENDEDKEY | 0,
IntPtr.Zero);
// Simulate a key release
Interop.keybd_event((byte)virtualKey,
0x45,
Interop.KEYEVENTF_EXTENDEDKEY | Interop.KEYEVENTF_KEYUP,
IntPtr.Zero);
Pressing and releasing the button changes the state of the LED. virtualKey is one of the VK_ constants.
Here are the declarations:
internal partial class Interop
{
public static int VK_NUMLOCK = 0x90;
public static int VK_SCROLL = 0x91;
public static int VK_CAPITAL = 0x14;
public static int KEYEVENTF_EXTENDEDKEY = 0x0001; // If specified, the scan code was preceded by a prefix byte having the value 0xE0 (224).
public static int KEYEVENTF_KEYUP = 0x0002; // If specified, the key is being released. If not specified, the key is being depressed.
[DllImport("User32.dll", SetLastError = true)]
public static extern void keybd_event(
byte bVk,
byte bScan,
int dwFlags,
IntPtr dwExtraInfo);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetKeyState(int nVirtKey);
[DllImport("User32.dll", SetLastError = true)]
public static extern short GetAsyncKeyState(int vKey);
}
I would like to use the numlock button for something other than numlock. So basically I would like to turn off numlock when it is pressed and keep it off. I can capture the button press but it still toggles on/off. I want it off, always. Any suggestions?
Not sure WHY anyone would like to know WHY I want this to be done but here is the reason: I have a bluetooth numeric keypad that I want to use to control a machine. Does that justify the question?
After a couple hours of research I came across the following code which did the trick:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
class SetNumlockKeyOn
{
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
internal int type;
internal short wVk;
internal short wScan;
internal int dwFlags;
internal int time;
internal IntPtr dwExtraInfo;
int dummy1;
int dummy2;
internal int type1;
internal short wVk1;
internal short wScan1;
internal int dwFlags1;
internal int time1;
internal IntPtr dwExtraInfo1;
int dummy3;
int dummy4;
}
[DllImport("user32.dll")]
static extern int SendInput(uint nInputs, IntPtr pInputs, int cbSize);
public static void SetNumlockOn()
{
if (Control.IsKeyLocked(Keys.NumLock)) return;
const int mouseInpSize = 28;//Hardcoded size of the MOUSEINPUT tag !!!
INPUT input = new INPUT();
input.type = 0x01; //INPUT_KEYBOARD
input.wVk = 0x90; //VK_NUMLOCK
input.wScan = 0;
input.dwFlags = 0; //key-down
input.time = 0;
input.dwExtraInfo = IntPtr.Zero;
input.type1 = 0x01;
input.wVk1 = 0x90;
input.wScan1 = 0;
input.dwFlags1 = 2; //key-up
input.time1 = 0;
input.dwExtraInfo1 = IntPtr.Zero;
IntPtr pI = Marshal.AllocHGlobal(mouseInpSize * 2);
Marshal.StructureToPtr(input, pI, false);
int result = SendInput(2, pI, mouseInpSize); //Hardcoded size of the MOUSEINPUT tag !!!
//if (result == 0 || Marshal.GetLastWin32Error() != 0)
// Console.WriteLine(Marshal.GetLastWin32Error());
Marshal.FreeHGlobal(pI);
}
}
Here's an example:
public static class NativeMethods
{
public const byte VK_NUMLOCK = 0x90;
public const uint KEYEVENTF_EXTENDEDKEY = 1;
public const int KEYEVENTF_KEYUP = 0x2;
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
public static void SimulateKeyPress(byte keyCode)
{
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_NUMLOCK, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
public partial class Form1 : Form
{
private bool protectKeys; // To protect from inifite keypress chain reactions
public Form1()
{
InitializeComponent();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (protectKeys)
return;
if (e.KeyCode == Keys.NumLock &&
!(new Microsoft.VisualBasic.Devices.Keyboard().NumLock))
{
protectKeys = true;
NativeMethods.SimulateKeyPress(NativeMethods.VK_NUMLOCK);
protectKeys = false;
}
}
}
I want to translate the Latin keyboard to another Keyboard like uyghur or something like. There is an uyghur keyboard, but the coding of keys are so complex that a normal PC User can't type uighur easily.
So my aim is that to create a software solution for this Problem, such as Chinese Input Systems. in that system you can input Chinese Characters from every kind of Keyboard. that is a kind of clever solution so that everyone can use it problem-less.
So my aim is that I want to write a Windows Service Application, which captures every KeyDown-Strike (only Alphabets) and translates the pressed Key to destination (Unicode) Alphabet and simulates again a Key strike with this translated Alphabet. As result the aimed Alphabet will be showed in the cursor-point. In the End my App discards/Stops the original key from the KEYDOWN pressing,
So that it will not be showed any more.
For example:
Press K.
Capturing the K and Translate it to Unicode like 0xFEBD then send back to cursor point.
Cancel or Discard the key down event of the K. This character should not be seen at the cursor point.
Until now the Step 1 and 2 works fine. My problem is that I can't discard/cancel/stop the last key down event for this key strike, after I capture the key down event.
I am not sure if my idea good/effective enough to realize what I am thinking. Now I am trying only. may be you have a better idea that you can suggest me. here is my code for that:
public class Simulate
{
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
static extern UInt32 SendInput(UInt32 numberOfInputs, INPUT[] input, Int32 sizeOfInputStructure);
[StructLayout(LayoutKind.Sequential, Size = 24)]
struct KEYBDINPUT
{
public UInt16 Vk;
public UInt16 Scan;
public UInt32 Flags;
public UInt32 Time;
public UInt32 ExtraInfo;
}
[StructLayout(LayoutKind.Explicit)]
private struct INPUT
{
[FieldOffset(0)]
public int Type;
[FieldOffset(4)]
public KEYBDINPUT ki;
}
public static void UnicodeInput(UInt16 unicode)
{
INPUT down = new INPUT();
down.Type = 1; //INPUT_KEYBOARD
down.ki.Vk = 0;
down.ki.Scan = unicode;
down.ki.Time = 0;
down.ki.Flags = 0x0004; //KEYEVENTF_UNICODE
down.ki.ExtraInfo = 0;
INPUT up = new INPUT();
up.Type = 1; //INPUT_KEYBOARD
up.ki.Vk = 0;
up.ki.Scan = unicode;
up.ki.Time = 0;
up.ki.Flags = 0x0004; //KEYEVENTF_UNICODE
up.ki.ExtraInfo = 0;
INPUT[] input = new INPUT[2];
input[0] = down;
input[1] = up;
SendInput(1, input, Marshal.SizeOf(typeof(INPUT)));
}
}
/// Capture any window key
///
public static class WinKeyCapture
{
private const int WH_KEYBOARD_LL = 13;
private const int WH_CALLWNDPROC = 4;
private const int WM_KEYDOWN = 0x0100;
private const int WM_CHAR = 0x0102;
const int VK_A = 0x08;// 0x41; //up key
const int VK_DOWN = 0x28; //down key
const int VK_LEFT = 0x25;
const int VK_RIGHT = 0x27;
const uint KEYEVENTF_KEYUP = 0x0002;
const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
const uint KEYEVENTF_CTRL = 0x11;
const uint KEYEVENTF_ADD = 0x6B;
const uint VK_LWIN = 0x5b;
private static LowLevelKeyboardProc _proc = WinKeyCapture.HookCallback;
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint numberOfInputs, INPUT[] inputs, int sizeOfInputStructure);
public static void SetHook()
{
SetHook(_proc);
}
public static void UnHook()
{
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
private static IntPtr _hookID = IntPtr.Zero;
public static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
int vkCode = Marshal.ReadInt32(lParam);
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
// TODO: identify only Alphabets then fire
VKcode(vkCode);
}
//wParam |= 0x4000;
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private static void VKcode(int code)
{
switch (code) // TODO: Complete all other Alphabet-Tranylations
{
case 0x4B:
Simulate.UnicodeInput(0xFEDB);
break;
case 0x54:
Simulate.UnicodeInput(0xFEAD);
break;
case 0x55:
Simulate.UnicodeInput(0xFBE7);
break;
case 0x56:
Simulate.UnicodeInput(0xFEE9);
break;
case 0x59:
Simulate.UnicodeInput(0xFEE1);
break;
case 0x5a:
break;
}
}
/// <summary>
/// simulate key press
/// </summary>
/// <param name="keyCode"></param>
public static void SendKeyPress(KeyCode keyCode)
{
INPUT input = new INPUT {
Type = 1
};
input.Data.Keyboard = new KEYBDINPUT() {
Vk = (ushort)keyCode,
Scan = 0,
Flags = 0,
Time = 0,
ExtraInfo = IntPtr.Zero,
};
INPUT input2 = new INPUT {
Type = 1
};
input2.Data.Keyboard = new KEYBDINPUT() {
Vk = (ushort)keyCode,
Scan = 0,
Flags = 2,
Time = 0,
ExtraInfo = IntPtr.Zero
};
INPUT[] inputs = new INPUT[] { input, input2 };
if (SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT))) == 0)
throw new Exception();
}
/// <summary>
/// simulate key press
/// </summary>
/// <param name="keyCode"></param>
public static void SendUnicodePress(KeyCode keyCode)
{
INPUT input = new INPUT {
Type = 1
};
input.Data.Keyboard = new KEYBDINPUT() {
Vk = (ushort)keyCode,
Scan = 0,
Flags = 0,
Time = 0,
ExtraInfo = IntPtr.Zero,
};
INPUT input2 = new INPUT {
Type = 1
};
input2.Data.Keyboard = new KEYBDINPUT() {
Vk = (ushort)keyCode,
Scan = 0,
Flags = 2,
Time = 0,
ExtraInfo = IntPtr.Zero
};
INPUT[] inputs = new INPUT[] { input, input2 };
if (SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT))) == 0)
throw new Exception();
}
[StructLayout(LayoutKind.Sequential)]
internal struct INPUT
{
public uint Type;
public MOUSEKEYBDHARDWAREINPUT Data;
}
[StructLayout(LayoutKind.Explicit)]
internal struct MOUSEKEYBDHARDWAREINPUT
{
[FieldOffset(0)]
public HARDWAREINPUT Hardware;
[FieldOffset(0)]
public KEYBDINPUT Keyboard;
[FieldOffset(0)]
public MOUSEINPUT Mouse;
}
[StructLayout(LayoutKind.Sequential)]
internal struct HARDWAREINPUT
{
public uint Msg;
public ushort ParamL;
public ushort ParamH;
}
[StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT
{
public ushort Vk;
public ushort Scan;
public uint Flags;
public uint Time;
public IntPtr ExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
internal struct MOUSEINPUT
{
public int X;
public int Y;
public uint MouseData;
public uint Flags;
public uint Time;
public IntPtr ExtraInfo;
}
}
I am working on an application that required reading the mifare card serial number, the language I am working with is C#.
I am new to mifare reader programming, so I am sorry for asking dumb question.
At first I would like to know if there is a different between Mifare UID and Mifare Serial number.
I have managed to get UID with the help of WinSCard library, but I cant figure it out how to get the card serial number which should be 10 digit numbers.
I do appreciate if you could point me to the right direction.
Thanks in advance for the help.
Regards
C# signature of SCardTransmit method
[StructLayout(LayoutKind.Sequential)]
public struct SCARD_IO_REQUEST
{
public int dwProtocol;
public int cbPciLength;
}
[DllImport("winscard.dll")]
public static extern int SCardTransmit(int hCard, ref SCARD_IO_REQUEST pioSendRequest, ref byte SendBuff, int SendBuffLen, ref SCARD_IO_REQUEST pioRecvRequest,
ref byte RecvBuff, ref int RecvBuffLen);
Code Example for read UID of mifare card
private SmartcardErrorCode GetUID(ref byte[] UID)
{
byte[] receivedUID = new byte[10];
UnsafeNativeMethods.SCARD_IO_REQUEST request = new UnsafeNativeMethods.SCARD_IO_REQUEST();
request.dwProtocol = 1; //SCARD_PROTOCOL_T1);
request.cbPciLength = System.Runtime.InteropServices.Marshal.SizeOf(typeof(UnsafeNativeMethods.SCARD_IO_REQUEST));
byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x04 }; //get UID command for Mifare cards
int outBytes = receivedUID.Length;
int status = SCardTransmit(_hCard, ref request, ref sendBytes[0], sendBytes.Length, ref request, ref receivedUID[0], ref outBytes);
UID = receivedUID.Take(8).ToArray();
return status;
}
The Selected answer doesn't work on x64 enviroments.
Here is a Full example code, tested and working on Windows 10 x64.
What this does:
Retrieve the List of Available Readers
Selects to use the First available Reader
Check if there is a Card in the reader and Connects to it.
Transmits to the card the Command to retrieve its UID
Converts the UID into a Hexadecimal string.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace DXCutcsa.VO.Common
{
public class SmartCardReader
{
#region Atributos
private bool _disposed = false;
private IntPtr _ReaderContext = IntPtr.Zero;
private string _ReaderName = string.Empty;
private List<string> _AvailableReaders = new List<string>();
#endregion
#region Win32 APIs
[DllImport("WinScard.dll")]
static extern int SCardEstablishContext(uint dwScope,
IntPtr notUsed1,
IntPtr notUsed2,
out IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardReleaseContext(IntPtr phContext);
[DllImport("WinScard.dll")]
static extern int SCardConnect(IntPtr hContext,
string cReaderName,
uint dwShareMode,
uint dwPrefProtocol,
ref IntPtr phCard,
ref IntPtr ActiveProtocol);
[DllImport("WinScard.dll")]
static extern int SCardDisconnect(IntPtr hCard, int Disposition);
[DllImport("WinScard.dll", EntryPoint = "SCardListReadersA", CharSet = CharSet.Ansi)]
static extern int SCardListReaders(
IntPtr hContext,
byte[] mszGroups,
byte[] mszReaders,
ref UInt32 pcchReaders);
[DllImport("winscard.dll")]
static extern int SCardStatus(
uint hCard,
IntPtr szReaderName,
ref int pcchReaderLen,
ref int pdwState,
ref uint pdwProtocol,
byte[] pbAtr,
ref int pcbAtrLen);
[DllImport("winscard.dll")]
static extern int SCardTransmit(
IntPtr hCard,
ref SCARD_IO_REQUEST pioSendRequest,
ref byte SendBuff,
uint SendBuffLen,
ref SCARD_IO_REQUEST pioRecvRequest,
byte[] RecvBuff,
ref uint RecvBuffLen);
[DllImport("winscard.dll", SetLastError = true)]
static extern int SCardGetAttrib(
IntPtr hCard, // Valor retornado en funcion ScardConnect
UInt32 dwAttrId, // Identificacion de atributos a obtener
byte[] pbAttr, // Puntero al vector atributos recividos
ref IntPtr pcbAttrLen // TamaƱo del vector
);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct ReaderState
{
public ReaderState(string sName)
{
this.szReader = sName;
this.pvUserData = IntPtr.Zero;
this.dwCurrentState = 0;
this.dwEventState = 0;
this.cbATR = 0;
this.rgbATR = null;
}
internal string szReader;
internal IntPtr pvUserData;
internal uint dwCurrentState;
internal uint dwEventState;
internal uint cbATR; // count of bytes in rgbATR
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24, ArraySubType = UnmanagedType.U1)]
internal byte[] rgbATR;
}
[StructLayout(LayoutKind.Sequential)]
public struct SCARD_IO_REQUEST
{
public UInt32 dwProtocol;
public UInt32 cbPciLength;
}
/*****************************************************************/
[DllImport("kernel32.dll", SetLastError = true)]
private extern static IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll")]
private extern static void FreeLibrary(IntPtr handle);
[DllImport("kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr handle, string procName);
#endregion
#region Error codes
public const uint S_SUCCESS = 0x00000000;
public const uint F_INTERNAL_ERROR = 0x80100001;
public const uint E_CANCELLED = 0x80100002;
public const uint E_INVALID_HANDLE = 0x80100003;
public const uint E_INVALID_PARAMETER = 0x80100004;
public const uint E_INVALID_TARGET = 0x80100005;
public const uint E_NO_MEMORY = 0x80100006;
public const uint F_WAITED_TOO_LONG = 0x80100007;
public const uint E_INSUFFICIENT_BUFFER = 0x80100008;
public const uint E_UNKNOWN_READER = 0x80100009;
public const uint E_TIMEOUT = 0x8010000A;
public const uint E_SHARING_VIOLATION = 0x8010000B;
public const uint E_NO_SMARTCARD = 0x8010000C;
public const uint E_UNKNOWN_CARD = 0x8010000D;
public const uint E_CANT_DISPOSE = 0x8010000E;
public const uint E_PROTO_MISMATCH = 0x8010000F;
public const uint E_NOT_READY = 0x80100010;
public const uint E_INVALID_VALUE = 0x80100011;
public const uint E_SYSTEM_CANCELLED = 0x80100012;
public const uint F_COMM_ERROR = 0x80100013;
public const uint F_UNKNOWN_ERROR = 0x80100014;
public const uint E_INVALID_ATR = 0x80100015;
public const uint E_NOT_TRANSACTED = 0x80100016;
public const uint E_READER_UNAVAILABLE = 0x80100017;
public const uint P_SHUTDOWN = 0x80100018;
public const uint E_PCI_TOO_SMALL = 0x80100019;
public const uint E_READER_UNSUPPORTED = 0x8010001A;
public const uint E_DUPLICATE_READER = 0x8010001B;
public const uint E_CARD_UNSUPPORTED = 0x8010001C;
public const uint E_NO_SERVICE = 0x8010001D;
public const uint E_SERVICE_STOPPED = 0x8010001E;
public const uint E_UNEXPECTED = 0x8010001F;
public const uint E_ICC_INSTALLATION = 0x80100020;
public const uint E_ICC_CREATEORDER = 0x80100021;
public const uint E_UNSUPPORTED_FEATURE = 0x80100022;
public const uint E_DIR_NOT_FOUND = 0x80100023;
public const uint E_FILE_NOT_FOUND = 0x80100024;
public const uint E_NO_DIR = 0x80100025;
public const uint E_NO_FILE = 0x80100026;
public const uint E_NO_ACCESS = 0x80100027;
public const uint E_WRITE_TOO_MANY = 0x80100028;
public const uint E_BAD_SEEK = 0x80100029;
public const uint E_INVALID_CHV = 0x8010002A;
public const uint E_UNKNOWN_RES_MNG = 0x8010002B;
public const uint E_NO_SUCH_CERTIFICATE = 0x8010002C;
public const uint E_CERTIFICATE_UNAVAILABLE = 0x8010002D;
public const uint E_NO_READERS_AVAILABLE = 0x8010002E;
public const uint E_COMM_DATA_LOST = 0x8010002F;
public const uint E_NO_KEY_CONTAINER = 0x80100030;
public const uint W_UNSUPPORTED_CARD = 0x80100065;
public const uint W_UNRESPONSIVE_CARD = 0x80100066;
public const uint W_UNPOWERED_CARD = 0x80100067;
public const uint W_RESET_CARD = 0x80100068;
public const uint W_REMOVED_CARD = 0x80100069;
public const uint W_SECURITY_VIOLATION = 0x8010006A;
public const uint W_WRONG_CHV = 0x8010006B;
public const uint W_CHV_BLOCKED = 0x8010006C;
public const uint W_EOF = 0x8010006D;
public const uint W_CANCELLED_BY_USER = 0x8010006E;
public const uint W_CARD_NOT_AUTHENTICATED = 0x8010006F;
#endregion
#region Constructor
public SmartCardReader()
{
}
#endregion
#region Metodos
public long GetUID(ref byte[] UID)
{
long _result = 0;
bool cardInserted = false;
IntPtr _CardContext = IntPtr.Zero;
IntPtr ActiveProtocol = IntPtr.Zero;
// Establish Reader context:
if (this._ReaderContext == IntPtr.Zero)
{
_result = SCardEstablishContext(2, IntPtr.Zero, IntPtr.Zero, out this._ReaderContext);
#region Get List of Available Readers
uint pcchReaders = 0;
int nullindex = -1;
char nullchar = (char)0;
// First call with 3rd parameter set to null gets readers buffer length.
_result = SCardListReaders(this._ReaderContext, null, null, ref pcchReaders);
byte[] mszReaders = new byte[pcchReaders];
// Fill readers buffer with second call.
_result = SCardListReaders(this._ReaderContext, null, mszReaders, ref pcchReaders);
// Populate List with readers.
string currbuff = new ASCIIEncoding().GetString(mszReaders);
int len = (int)pcchReaders;
if (len > 0)
{
while (currbuff[0] != nullchar)
{
nullindex = currbuff.IndexOf(nullchar); // Get null end character.
string reader = currbuff.Substring(0, nullindex);
this._AvailableReaders.Add(reader);
len = len - (reader.Length + 1);
currbuff = currbuff.Substring(nullindex + 1, len);
}
}
#endregion
// Select the first reader:
this._ReaderName = this._AvailableReaders[0];
}
try
{
//Check if there is a Card in the reader:
//dwShareMode: SCARD_SHARE_SHARED = 0x00000002 - This application will allow others to share the reader
//dwPreferredProtocols: SCARD_PROTOCOL_T0 - Use the T=0 protocol (value = 0x00000001)
if (this._ReaderContext != IntPtr.Zero)
{
_result = SCardConnect(this._ReaderContext, this._ReaderName, 0x00000002, 0x00000001, ref _CardContext, ref ActiveProtocol);
if (_result == 0)
{
cardInserted = true;
SCARD_IO_REQUEST request = new SCARD_IO_REQUEST()
{
dwProtocol = (uint)ActiveProtocol,
cbPciLength = (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(SCARD_IO_REQUEST))
};
byte[] sendBytes = new byte[] { 0xFF, 0xCA, 0x00, 0x00, 0x00 }; //<- get UID command for iClass cards
byte[] ret_Bytes = new byte[33];
uint sendLen = (uint)sendBytes.Length;
uint ret_Len = (uint)ret_Bytes.Length;
_result = SCardTransmit(_CardContext, ref request, ref sendBytes[0], sendLen, ref request, ret_Bytes, ref ret_Len);
if (_result == 0)
{
UID = ret_Bytes.Take(4).ToArray(); //only take the first 8, the last 2 bytes are not part of the UID of the card
string dataOut = byteToHexa(UID, UID.Length, true).Trim(); //Devolver la respuesta en Hexadecimal
}
}
}
}
finally
{
SCardDisconnect(_CardContext, 0);
SCardReleaseContext(this._ReaderContext);
}
return _result;
}
private string byteToHexa(byte[] byReadBuffer, int leng, bool bSpace)
{
string text2 = "";
for (short num1 = 0; num1 < leng; num1 = (short)(num1 + 1))
{
short num2 = byReadBuffer[num1];
text2 = text2 + System.Convert.ToString(num2, 16).PadLeft(2, '0');
if (bSpace)
{
text2 = text2 + " ";
}
}
return text2.ToUpper();
}
//Get the address of Pci from "Winscard.dll".
private IntPtr GetPciT0()
{
IntPtr handle = LoadLibrary("Winscard.dll");
IntPtr pci = GetProcAddress(handle, "g_rgSCardT0Pci");
FreeLibrary(handle);
return pci;
}
#endregion
}// Fin de la Clase
}
PInvoke docs helped a lot: https://www.pinvoke.net/default.aspx/winscard.scardtransmit
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.