"INPUT" is innaccesible due to its protection level - c#

Im trying to build a small app that would send input to a game. After searching for a while, I found many answers that suggest SendInput should be used.
Below there is the code that I'm working on (basically doing a lots of tests to see what works, hence the messiness). I would suggest you ignore most of the code, the line that interests me , or should I say that causes the build problem is:
public static extern uint SendInput(
uint nInputs,[MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);
This gives me the error :
'INPUT' is inaccessible due to its protection level.
I am new to C# (and Windows programming), so I cannot really figure out what I should do to fix that.
Any help would be appreciated.
Thanks in advance.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using WindowsInput;
namespace WindowsFormsApplication1
{
[Flags]
public enum KeyFlag
{
KeyDown = 0x0000,
KeyUp = 0x0002,
Scancode = 0x0008
}
internal static class VirtualKeyboard
{
public static void KeyDown(System.Windows.Forms.Keys key)
{
Console.WriteLine("Sending keybdevent: " + (byte)key);
//keybd_event((byte)key, 0, 0, 0);
/*INPUT[] InputData = new INPUT[2];
Key ScanCode = Microsoft.DirectX.DirectInput.Key.W;
InputData[0].type = 1; //INPUT_KEYBOARD
InputData[0].wScan = (ushort)ScanCode;
InputData[0].dwFlags = (uint)SendInputFlags.KEYEVENTF_SCANCODE;
InputData[1].type = 1; //INPUT_KEYBOARD
InputData[1].wScan = (ushort)ScanCode;
InputData[1].dwFlags = (uint)(SendInputFlags.KEYEVENTF_KEYUP | SendInputFlags.KEYEVENTF_UNICODE);
// send keydown
if (SendInput(2, InputData, Marshal.SizeOf(InputData[1])) == 0)
{
System.Diagnostics.Debug.WriteLine("SendInput failed with code: " +
Marshal.GetLastWin32Error().ToString());
}*/
//InputSimulator.SimulateKeyDown(VirtualKeyCode.VK_E);
Console.WriteLine("Exit.....");
}
[DllImport("user32.dll", SetLastError = true)]
public static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);
public static void SendKey(short keyCode, KeyFlag keyFlag)
{
INPUT[] InputData = new INPUT[1];
InputData[0].type = 1;
InputData[0].ki.wScan = keyCode; // 0x14 = T for example
InputData[0].ki.dwFlags = (int)keyFlag;
InputData[0].ki.time = 0;
InputData[0].ki.dwExtraInfo = IntPtr.Zero;
SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)));
}
public static void PressKey(short key)
{
SendKey(key, KeyFlag.KeyDown | KeyFlag.Scancode);
SendKey(key, KeyFlag.KeyUp | KeyFlag.Scancode);
}
public static void KeyUp(System.Windows.Forms.Keys key)
{
//keybd_event((byte)key, 0, 0x7F, 0);
}
}
}

The INPUT struct must be a higher access level, such as public so other classes can access it. See access modifiers.
public struct INPUT
{
...
}

In C# you have to explicitly mark struct members as public. In c++ they are automatically public. So you must mark INPUT as public.

Related

Processing the full MSAA accessibility tree in C# returns nulls and ints

We want to process the complete accessibility tree of another process. Normally we do this in C++ but we would prefer to move to C#.
We successfully start the process using AccessibleObjectFromWindow.
We then successfully get the children of this top-level accessible object using AccessibleChildren.
However, when we recurse these first level children to look for their children, we get the correct child counts (using Accessibility Explorer as our benchmark), but the children are populated with nulls or integers.
Is there a way to cast the integers back to an accessible object?
Code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using Accessibility;
public partial class Form1 : Form
{
[DllImport("oleacc.dll")]
internal static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint id, ref Guid iid, [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject);
[DllImport("oleacc.dll")]
public static extern uint AccessibleChildren(IAccessible paccContainer, uint iChildStart, uint cChildren, [Out] object[] rgvarChildren, out uint pcObtained);
#region Enumerations
//Obj ID
internal enum OBJID : uint
{
WINDOW = 0x00000000,
SYSMENU = 0xFFFFFFFF,
TITLEBAR = 0xFFFFFFFE,
MENU = 0xFFFFFFFD,
CLIENT = 0xFFFFFFFC,
VSCROLL = 0xFFFFFFFB,
HSCROLL = 0xFFFFFFFA,
SIZEGRIP = 0xFFFFFFF9,
CARET = 0xFFFFFFF8,
CURSOR = 0xFFFFFFF7,
ALERT = 0xFFFFFFF6,
SOUND = 0xFFFFFFF5,
CHILDID_SELF = 0,
SELFLAG_TAKEFOCUS = 0x01
}
#endregion Enumerations
IAccessible iAccessible; //interface: Accessibility namespace
IntPtr handle;
public Form1()
{
InitializeComponent();
}
public bool checkHandle()
{
Guid guid = new Guid("{618736E0-3C3D-11CF-810C-00AA00389B71}");
object obj = null;
// Use any window handle
handle = (IntPtr)66956;
int retVal = AccessibleObjectFromWindow(handle, (uint)OBJID.WINDOW, ref guid, ref obj);
iAccessible = (IAccessible)obj;
string[] data = new string[1];
string accWindowName = iAccessible.get_accName(0);
string accWindowVal = iAccessible.get_accValue(0);
System.Diagnostics.Debug.WriteLine("IAccessible Name : " + accWindowName);
System.Diagnostics.Debug.WriteLine("IAccessible value : " + accWindowVal);
System.Diagnostics.Debug.WriteLine("IAccessible Role is : " + iAccessible.get_accRole(0));
System.Diagnostics.Debug.WriteLine("IAccessible Type: " + iAccessible.GetType());
System.Diagnostics.Debug.WriteLine("IAccessible Focus is: " + iAccessible.accFocus);
System.Diagnostics.Debug.WriteLine("IAccessible Selection is " + iAccessible.get_accState());
//iAccessible.accSelect((int)OBJID.SELFLAG_TAKEFOCUS, 0);
//if (!accWindowName.Contains("Mozilla Firefox"))
// return false;
ProcessChildren(iAccessible, false);
iAccessible = null;
return false;
}
private void ProcessChildren(IAccessible iChild, bool v)
{
IAccessible[] childs = new IAccessible[iChild.accChildCount];
uint obtained = 0;
uint firstChild = 0;
uint childcount = (uint)iChild.accChildCount - 1;
uint ret = AccessibleChildren(iChild, firstChild, childcount, childs, out obtained);
int i = 0;
foreach (IAccessible child in childs)
{
if (child == null)
continue;
if (!Marshal.IsComObject(child)) continue;
string accWindowName = child.get_accName(0);
string accWindowVal = child.get_accValue(0);
ProcessChildren(child, false);
Marshal.ReleaseComObject(child);
}
}
private void button1_Click(object sender, EventArgs e)
{
checkHandle();
}
}
}

Possible targeting SendInput()?

Using SendInput() to send long keystrokes in C#. The problem is that when using it, it works on all programs when called. Is it possible targeting it to work only on a specific program? Like in PostMessage() that uses FindWindow.
My SendInput():
[DllImport("user32.dll")]
internal static extern uint SendInput(
uint nInputs,
[MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs,
int cbSize);
public void KeySend(VirtualKeyShort key)
{
INPUT[] Inputs = new INPUT[1];
INPUT Input = new INPUT();
Input.type = 1;
Input.U.ki.wVk = key;
Inputs[0] = Input;
SendInput(1, Inputs, INPUT.Size);
}
public void KeyUp(VirtualKeyShort key)
{
INPUT[] Inputs = new INPUT[1];
INPUT Input = new INPUT();
Input.type = 1;
Input.U.ki.wVk = key;
Input.U.ki.dwFlags = KEYEVENTF.KEYUP;
Inputs[0] = Input;
SendInput(1, Inputs, INPUT.Size);
}
Thank you.
before launching your sendinput you could do that (for example) if you want to send key to notepad :
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
class Program {
static void Main(string[] args) {
var proc = Process.GetProcessesByName("notepad");
if (proc.Length > 0) {
SetForegroundWindow(proc[0].MainWindowHandle);
}
}
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
}
your window app will have the focus and can receive the keys
you could use EnumWindows if you want to enumerate all application

How to get a value from other application and write it to a file?

I'm trying to make a simple app with no UI, that will take data from another app and store it in output file using C#. That's all. How can I make:
1. Open the process
2. Find the value "X"
2.1 Find the value "Y"
2.2 Find the value "Z"
3. Write values to a file "C:\output.txt"
4. Update every 1000ms for example.
Here are two codes I hardly managed to run. Reading from app:
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
public class MemoryRead
{
const int PROCESS_WM_READ = 0x0010;
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(int hProcess,
int lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);
public static void Main()
{
Process process = Process.GetProcessesByName("notepad")[0];
IntPtr processHandle = OpenProcess(PROCESS_WM_READ, false, process.Id);
int bytesRead = 0;
byte[] buffer = new byte[24];
ReadProcessMemory((int)processHandle, 0x0001BA5B0, buffer, buffer.Length, ref bytesRead);
Console.WriteLine(Encoding.Unicode.GetString(buffer) +
" (" + bytesRead.ToString() + "bytes)");
Console.ReadLine();
}
}
Write to a file:
class WriteTextFile
{
static void Main()
{
string[] lines = { "X", "Y", "Z", };
System.IO.File.WriteAllLines(#"O:\CS\output.txt", lines);
}
}
2 question:
1. How do I "connect" these two codes
2. How do I make the program refresh output every 1sec/2sec/300msec?
Thanks for any help!
P.S. If you know any existing app that will do exact same thing - it will be just OK for me.
UPDATE:
Finally made two pieces working together!
using System;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
class Program
{
const int PROCESS_WM_READ = 0x0010;
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(int hProcess,
int lpBaseAddress, byte[] lpBuffer, int dwSize, ref int lpNumberOfBytesRead);
static void Main()
{
using (StreamWriter writer = new StreamWriter("O:\\out.txt"))
{
Console.SetOut(writer);
Act();
}
}
static void Act()
{
Process process = Process.GetProcessesByName("notepad")[0];
IntPtr processHandle = OpenProcess(PROCESS_WM_READ, false, process.Id);
int bytesRead = 0;
byte[] buffer = new byte[24];
ReadProcessMemory((int)processHandle, 0x0021AAD0, buffer, buffer.Length, ref bytesRead);
Console.WriteLine(Encoding.Unicode.GetString(buffer));
}
}
The code does what I need but only once: it reads the value and stores it in .txt. If the notepad's value is updated, the .txt content will remain unchanged until the program is restarted. How can I make it update over and over with no restarting the program?
C'mon guys, I'm half way there!!
Create a scheduled task that runs the program on an interval.
Edit...
static void Main()
{
var totalRunTime = TimeSpan.FromDays(1);
var elapsed = 0;
while (elapsed < totalRunTime.TotalMilliseconds)
{
using (StreamWriter writer = new StreamWriter("O:\\out.txt"))
{
Console.SetOut(writer);
Act();
}
Threading.Thread.Sleep(350);
elapsed += 350;
}
}

NullReferenceException when querying dhcp reservations with microsoft dhcp server management api

I want to enumerate all dhcp reservation entries of our microsoft dhcp server with the microsoft dhcp server management api in c#.
This is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Net;
using System.Windows.Forms;
using System.Collections;
namespace Sequence
{
[StructLayout(LayoutKind.Sequential)]
public struct DHCP_CLIENT_INFO_ARRAY
{
public uint NumElements;
public IntPtr Clients;
}
[StructLayout(LayoutKind.Sequential)]
public struct DHCP_CLIENT_UID
{
public uint DataLength;
public IntPtr Data;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct DHCP_CLIENT_INFO
{
public uint ip;
public uint subnet;
public DHCP_CLIENT_UID mac;
[MarshalAs(UnmanagedType.LPWStr)]
public string ClientName;
[MarshalAs(UnmanagedType.LPWStr)]
public string ClientComment;
}
class CDHCP
{
public static ArrayList findDhcpClients(string server, string subnet)
{
ArrayList foundClients = new ArrayList();
uint parsedMask = StringIPAddressToUInt32(subnet);
uint resumeHandle = 0;
uint numClientsRead = 0;
uint totalClients = 0;
IntPtr info_array_ptr;
uint response = DhcpEnumSubnetClients(
server,
parsedMask,
ref resumeHandle,
65536,
out info_array_ptr,
ref numClientsRead,
ref totalClients
);
DHCP_CLIENT_INFO_ARRAY rawClients = (DHCP_CLIENT_INFO_ARRAY)Marshal.PtrToStructure(info_array_ptr, typeof(DHCP_CLIENT_INFO_ARRAY));
IntPtr current = rawClients.Clients;
for (int i = 0; i < (int)rawClients.NumElements; i++)
{
DHCP_CLIENT_INFO rawMachine = (DHCP_CLIENT_INFO)Marshal.PtrToStructure(Marshal.ReadIntPtr(current), typeof(DHCP_CLIENT_INFO));
CDHCPCLIENT thisClient = new CDHCPCLIENT();
thisClient.ip = UInt32IPAddressToString(rawMachine.ip);
thisClient.hostname = rawMachine.ClientName;
thisClient.mac = string.Format("{0:x2}-{1:x2}-{2:x2}-{3:x2}-{4:x2}-{5:x2}",
Marshal.ReadByte(rawMachine.mac.Data, 0),
Marshal.ReadByte(rawMachine.mac.Data, 1),
Marshal.ReadByte(rawMachine.mac.Data, 2),
Marshal.ReadByte(rawMachine.mac.Data, 3),
Marshal.ReadByte(rawMachine.mac.Data, 4),
Marshal.ReadByte(rawMachine.mac.Data, 5));
foundClients.Add(thisClient);
current = (IntPtr)((int)current + (int)Marshal.SizeOf(typeof(IntPtr)));
}
return foundClients;
}
public static uint StringIPAddressToUInt32(string ip)
{
IPAddress i = IPAddress.Parse(ip);
byte[] ipByteArray = i.GetAddressBytes();
uint ipUint = (uint)ipByteArray[0] << 24;
ipUint += (uint)ipByteArray[1] << 16;
ipUint += (uint)ipByteArray[2] << 8;
ipUint += (uint)ipByteArray[3];
return ipUint;
}
public static string UInt32IPAddressToString(uint ip)
{
IPAddress i = new IPAddress(ip);
string[] ipArray = i.ToString().Split('.');
return ipArray[3] + "." + ipArray[2] + "." + ipArray[1] + "." + ipArray[0];
}
[DllImport("C:\\Windows\\System32\\dhcpsapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern uint DhcpEnumSubnetClients(
string ServerIpAddress,
uint SubnetAddress,
ref uint ResumeHanle,
uint PreferredMaximum,
out IntPtr ClientInfo,
ref uint ElementsRead,
ref uint ElementsTotal);
}
}
Unfortunately I'm getting a NullReferenceException at this line:
DHCP_CLIENT_INFO_ARRAY rawClients = (DHCP_CLIENT_INFO_ARRAY)Marshal.PtrToStructure(info_array_ptr, typeof(DHCP_CLIENT_INFO_ARRAY));
I' calling the function like this:
public void GetDHCPReservation()
{
ArrayList clients = CDHCP.findDhcpClients("192.168.1.3", "192.168.1.5");
foreach (CDHCPCLIENT c in clients)
{
MessageBox.Show(string.Format("(0,-35}{1,-15}{2,-15}", c.hostname, c.ip, c.mac));
}
}
Can anybody help me?
Thanks in advance.
I think I've just solved my problem.
The reason why I was getting the NullReferenceException was because the IntPtr info_array_ptr always pointed to 0 (zero). That was because of not enough user rights on the dhcp server. After I added the user with which I'm running my application to the domain admins everything worked well.

How can I check and toggle Num-Lock programmatically in C#?

I would like to programmatically check the value of, and be able to toggle num-lock. What's the simplest way to do that in C#?
The reason is that I want to verify num-lock is "ON" at program start.
Thanks
Check How to programmatically turn on the Numlock Key
using System;
using System.Runtime.InteropServices;
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()
{
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);
}
You can do this via P/Invoke with GetKeyboardState and keybd_event.
The MSDN page for keybd_event shows exactly how to toggle num-lock, as well as get it's state (in C++).
There are P/Invoke signitures available on pinvoke.net for keybd_event and GetKeyboardState.
In addition to the answer given by Arsen:
There are problems with heap corruption in 64-bit builds. Programs using this code may crash at any point. To see this, enable the debug option "Enable Windows debug heap allocator". The debugger stops on calling FreeHGlobal.
It helps to calculate the size of the INPUT structure as follows.
int mouseInpSize = Marshal.SizeOf(input);
IntPtr pI = Marshal.AllocHGlobal(mouseInpSize);
Marshal.StructureToPtr(input, pI, false);
int result = SendInput(2, pI, mouseInpSize);
Marshal.FreeHGlobal(pI);

Categories

Resources