So I am trying to update a combobox in another application programmatically. The application I am updating has a combobox, some textboxes, and a number of checkboxes. Depending on the item selected in the combobox certain checkboxes will become enabled or disabled. The problem I am having is that, although I can change the current item in the combobox, the gui doesn't seem to be updated the checkboxes accordingly.
Here is my code
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
const int CB_SETCURSEL = 0x014E;
static void Main(string[] args)
{
var startinfo = new ProcessStartInfo("path");
// Get an object that contains all the process resources
Process rtugen = Process.Start(startinfo);
// wait until the process has a main window handle
while (rtugen.MainWindowHandle == IntPtr.Zero)
{
rtugen.Refresh();
}
IntPtr hWnd = rtugen.MainWindowHandle;
IntPtr controllerType = FindWindowEx(hWnd, IntPtr.Zero, "ComboBox", null);
SendMessage(controllerType, CB_SETCURSEL, 12, "");
int send_cbn_selchange = MakeWParam((int)controllerType, CBN_SELCHANGE);
int i = SendMessage(hWnd, 0x111, send_cbn_selchange,0);
}
static int MakeWParam(int loWord, int hiWord)
{
return (loWord & 0xFFFF) + ((hiWord & 0xFFFF) << 16);
}
So, the above code does update the combobox, but the GUI doesn't seem to update the checkboxes after the update is made. I monitored the combobox change in spy++ and it showed me the same command being sent. Any ideas on what is going wrong?
Eventually I found this solution online to change the value of the combobox so that the application recognizes the change. Once you have a handle on the combobox you can use the WM_KEYDOWN msg to simulate key down action.
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
const int CB_SETCURSEL = 0x014E;
const int VK_DOWN = 0x28;
const int WM_KEYDOWN = 0x0100;
static void Main(string[] args)
{
var startinfo = new ProcessStartInfo("path");
// Get an object that contains all the process resources
Process rtugen = Process.Start(startinfo);
// wait until the process has a main window handle
while (rtugen.MainWindowHandle == IntPtr.Zero)
{
rtugen.Refresh();
}
IntPtr hWnd = rtugen.MainWindowHandle;
IntPtr controllerType = FindWindowEx(hWnd, IntPtr.Zero, "ComboBox", null);
SendMessage(controllerType, CB_SETCURSEL, 0, "");
for (int i = 0; i < Index; i++)
SendMessage(controllerType, WM_KEYDOWN, VK_DOWN, 0);
}
Related
This code opens a Dialog by clicking a Button on a Form
IntPtr m = FindWindow("TForm1", "Smart Design");
IntPtr b = FindWindowEx(m, IntPtr.Zero, "TButton", "Update List");
SendMessage(b, BM_CLICK, 0, 0);
How to click OK button on the opened dialog?
I tried this code but it fails:
IntPtr d = FindWindow("TDialog4", "Information");
IntPtr k = FindWindowEx(d, IntPtr.Zero, "TButton7", "OK");
SendMessage(k, BM_CLICK, 0, 0);
I'd try sending the dialog a WM_COMMAND instead.
private const uint WM_COMMAND = 0x0111;
private const int BM_CLICKED = 245;
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int SendMessage(IntPtr hWnd, uint msg,
int wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle,
IntPtr childAfter, string className, string windowTitle);
SendMessage(k, WM_COMMAND, (BM_CLICKED << 16) | 1, k);
So I'm stuck with a problem, I'm trying to send keys to a game and I have the game in the foreground with help of SetForegroundWindow and I'm using SendInputs API to send the keys to the game.
If I focus on another application the keys are sent to that application but as soon as I focus on the application I want the keys to be sent to, they don't appear there.
I'm trying to save me some time to recruit guild members for my guild and with that I'm trying to send keys to the game.
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern IntPtr GetMessageExtraInfo();
[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
Process[] procs = Process.GetProcessesByName("BlackDesert64");
if (procs.Length > 0)
{
if (procs[0].MainWindowHandle != IntPtr.Zero)
{
SetForegroundWindow(procs[0].MainWindowHandle);
Thread.Sleep(1000);
}
}
INPUT[] inputs = new INPUT[]
{
new INPUT
{
type = INPUT_KEYBOARD,
u = new InputUnion
{
ki = new KEYBDINPUT
{
wVk = 0x49,
wScan = 0049,
dwFlags = KEYEVENTF_UNICODE,
dwExtraInfo = GetMessageExtraInfo(),
}
}
},
new INPUT
{
type = INPUT_KEYBOARD,
u = new InputUnion
{
ki = new KEYBDINPUT
{
wVk = 0x49,
wScan = 0049,
dwFlags = KEYEVENTF_KEYUP,
dwExtraInfo = GetMessageExtraInfo(),
}
}
}
};
SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
Rest of the code:
https://pastebin.com/RUm7A311
UPDATE
So I've found the API Interceptor that allows to send keys to a game that uses DirectX and I've set it up but still no outcome.. anyone who can point me in the right direction?
What does value SendInput return?
If it returns 0, then its an indication that some error has happened. You can try to invoke GetLastError, to see if the input was blocked by the UIPI, alternatively try to run your code with local administrator privileges.
Are you sure that procs[0].MainWindowHandle is the correct window handle?
Lastly try to send the message directly to the handle using SendMessage.
Implementation using SendMessage (no need to focus on the window).
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("User32.dll")]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindows);
[DllImport("User32.dll")]
private static extern Int32 SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, StringBuilder lParam);
void SendKeys()
{
IntPtr hWnd = FindWindow("Notepad", "Untitled - Notepad");
if (!hWnd.Equals(IntPtr.Zero))
{
IntPtr edithWnd = FindWindowEx(hWnd, IntPtr.Zero, "Edit", null);
if (!edithWnd.Equals(IntPtr.Zero))
{
SendMessage(edithWnd, WM_SETTEXT, IntPtr.Zero, new StringBuilder("Test"));
}
}
}
Reference: how-do-i-input-to-another-application
For your problem here is trick,
Use
String Keys = "Test";
SendKeys.Send(Keys);
this code to send keys to any application.
Just put this code in timer_start()
add some delay before starting of timer and stop timer after execution.
Now run your project which will initiate timer, before timeout open your game and wait for keys to press!!
Check this link which contains all Keys and their code to send
https://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send(v=vs.110).aspx
I am using the following code in C# to simulate the keyboard pressing:
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
[DllImport("user32")]
private static extern bool SetForegroundWindow(IntPtr hwnd);
void sim_key(string text, string proc)
{
var process = Process.GetProcessesByName(proc).FirstOrDefault();
if (process != null && process.MainWindowHandle != IntPtr.Zero)
{
SetForegroundWindow(process.MainWindowHandle);
SendKeys.Send(kat_id);
}
}
I tested it on Windows Xp, 7, 8.1, 10, and Server 2012. On windows 7 and Xp, the external app window is handled properly, however the keys are not being sent. On systems above Win 7 everything is correct. How should I fix it?
Edit:
I checked it on .NET 4.0 Client Profile and .NET 4.6.1 on 32 and 64 bit machines, but results are the same as described above.
I think you can go with this rough code
const int WM_CHAR = 0x0102;
const int WM_KEYDOWN = 0x0100;
if (process != null && process.MainWindowHandle != IntPtr.Zero)
{
PostMessage(process.MainWindowHandle, WM_CHAR, (int) <a character you want to send> , 1);
}
Use
PostMessage(process.MainWindowHandle, WM_KEYDOWN, 13, 1);
to send the "Enter".
Note that you can use SendMessage instead of PostMessage. The difference is the last one does not wait the processing of the key. They have the same signature:
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
You don't need calling SetForegroundWindow(process.MainWindowHandle); if you just want to send keys.
Thank you for your answer. I tried using PostMessage to send Ctrl+F10 to the other window. Here is my code:
public const int WM_KEYDOWN = 0x100;
public const int WM_KEYUP = 0x101;
public const int VK_CONTROL = 0x11;
public const int VK_F10 = 0x79;
PostMessage(process.MainWindowHandle, WM_KEYDOWN, VK_CONTROL, null);
PostMessage(process.MainWindowHandle, WM_KEYDOWN, VK_F10, null);
PostMessage(process.MainWindowHandle, WM_KEYUP, VK_F10, null);
PostMessage(process.MainWindowHandle, WM_KEYUP, VK_CONTROL, null);
However, it doesn't pass the keys to the app.
I am currently developing a program that will send a "key press" (the letter A or 0x41 in virtual key codes) to another program (notepad) every X seconds.
The problem is that for it to work I need the other program (notepad) to be in the FOREGROUND, example :
Process[] processes = Process.GetProcessesByName("notepad");
foreach (Process proc in processes) {
SetForegroundWindow(proc.MainWindowHandle);
// Do Whatever
}
Thread.Sleep(1000);
Is there a way to do that WITHOUT notepad having to be in the foreground ?
Like something that could run in the background ?
You could do it via winApi. Try to use SendMessage
According to this link you can do following:
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
public static void sendKeystroke(ushort k)
{
const uint WM_KEYDOWN = 0x100;
const uint WM_SYSCOMMAND = 0x018;
const uint SC_CLOSE = 0x053;
IntPtr WindowToFind = FindWindow(null, "Untitled1 - Notepad++");
IntPtr result3 = SendMessage(WindowToFind, WM_KEYDOWN, ((IntPtr)k), (IntPtr)0);
//IntPtr result3 = SendMessage(WindowToFind, WM_KEYUP, ((IntPtr)c), (IntPtr)0);
}
I am trying to automate a sequence of user inputs to a compiled application in C# using Win32 API. I do not have any source code for the application I am trying to control and it is running while I am trying to control it. In my code, I have a single button that, when clicked, needs to make a sequence of 3 inputs to the application I am trying to control:
Select an item in a treeview
Click a button
Click another button
The way it works is the button in step 2 performs an action depending on the item selected in the treeview in step 1. I am able to get the button clicks to work just fine by simply sending a message, but I cannot figure out how to select the TreeView item I want. The TreeView is static, so the items and layout will never change. It has the following layout:
-itemsA
-itemsB
--itemB1
-itemsC
Where itemB1 is the item that needs to be selected in order for the button clicks in steps 2 and 3 to work. By default ItemsB is collapsed, so I probably need to expand it before I can select ItemB1? Here is my code. I really appreciate any help!!
//Find Window API
[DllImport("User32.dll")]
public static extern Int32 FindWindow(String lpClassName, String lpWindowName);
//Find WindowEx API
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
//Send Message API
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(int hWnd, int msg, int wParam, IntPtr lParam);
private const int BN_CLICKED = 245;
//Method called by button click
public static void Start()
{
int hwnd = 0;
int prod = 0;
IntPtr hwndChild = IntPtr.Zero;
IntPtr treeChild = IntPtr.Zero;
IntPtr prodChild = IntPtr.Zero;
hwnd = FindWindow(null, "Application");
if (hwnd > 0)
{
//Get Handle for TreeView, THIS IS WHERE I AM STUCK!!
treeChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "AfxMDIFrame80", null);
treeChild = FindWindowEx((IntPtr)treeChild, IntPtr.Zero, "AfxMDIFrame80", null);
treeChild = FindWindowEx((IntPtr)treeChild, IntPtr.Zero, "SysTreeView32", null);
//Need to Add code to select item in TreeView ???
//Click First Button
hwndChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "AfxMDIFrame80", null);
hwndChild = FindWindowEx((IntPtr)hwndChild, IntPtr.Zero, "AfxMDIFrame80", null);
hwndChild = FindWindowEx((IntPtr)hwndChild, IntPtr.Zero, "#32770", null);
IntPtr scanBtn = FindWindowEx((IntPtr)hwndChild, IntPtr.Zero, "Button", "&Scan");
SendMessage((int)scanBtn, BN_CLICKED, 0, IntPtr.Zero);
//Click Second Button
prod = FindWindow("#32770", "Product: WPC");
prodChild = FindWindowEx((IntPtr)prod, IntPtr.Zero, "Button", "&Collect");
SendMessage((int)prodChild, BN_CLICKED, 0, IntPtr.Zero);
}
}//END Start
Hans,
Can you give me an example of how I would do this? The problem I am really having is finding the handle for the treeview item I want to select. If I use Spy++ to find the current handle and hardcode it into my method, it works fine, like this:
SendMessage((int)treeChild, TV_SELECTITEM, TVGN_CARET, (IntPtr)0x092DCB30);
If I use SendMessage and send TVGN_ROOT to the TreeView Handle, will it return an IntPtr with the handle for the item to select in the treeview, or how does that work? I am also experimenting with AutoIt, but I was hoping to keep all of my code in one application.
I figured it out, so I'll post for anyone else who is interested, I have had a hard time finding documentation on this. Here is the majority of my code:
//Define TreeView Flags and Messages
private const int BN_CLICKED = 0xF5;
private const int TV_FIRST = 0x1100;
private const int TVGN_ROOT = 0x0;
private const int TVGN_NEXT = 0x1;
private const int TVGN_CHILD = 0x4;
private const int TVGN_FIRSTVISIBLE = 0x5;
private const int TVGN_NEXTVISIBLE = 0x6;
private const int TVGN_CARET = 0x9;
private const int TVM_SELECTITEM = (TV_FIRST + 11);
private const int TVM_GETNEXTITEM = (TV_FIRST + 10);
private const int TVM_GETITEM = (TV_FIRST + 12);
//Find Window API
[DllImport("User32.dll")]
public static extern Int32 FindWindow(String lpClassName, String lpWindowName);
//Find WindowEx API
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
//Send Message API
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(int hWnd, int msg, int wParam, IntPtr lParam);
public static void Start()
{
//Handle variables
int treeItem = 0;
IntPtr treeChild = IntPtr.Zero;
int hwnd = FindWindow(null, "Application"); //Handle for the application to be controlled
if (hwnd > 0)
{
//Select TreeView Item
treeChild = FindWindowEx((IntPtr)hwnd, IntPtr.Zero, "AfxMDIFrame80", null);
treeChild = FindWindowEx((IntPtr)treeChild, IntPtr.Zero, "AfxMDIFrame80", null);
treeChild = FindWindowEx((IntPtr)treeChild, IntPtr.Zero, "SysTreeView32", null);
treeItem = SendMessage((int)treeChild, TVM_GETNEXTITEM, TVGN_ROOT, IntPtr.Zero);
treeItem = SendMessage((int)treeChild, TVM_GETNEXTITEM, TVGN_NEXT, (IntPtr)treeItem);
treeItem = SendMessage((int)treeChild, TVM_GETNEXTITEM, TVGN_CHILD, (IntPtr)treeItem);
SendMessage((int)treeChild, TVM_SELECTITEM, TVGN_CARET, (IntPtr)treeItem);
// ...Continue with my automation...
}
}
I may still not understand this 100%, but hopefully this helps. The SendMessage returns value will depend on what message you are sending, in this case, it was an int containing the handle of a TreeView item. The first argument is the handle to the TreeView itself. The second argument is the Message you want to send. The 3rd and 4th arguments are flags. The 3rd specifies the type of item, the 4th is the handle of the current TreeView item.
Thanks for the help Hans! Anyone else, please feel free to elaborate.
You'll need to walk the nodes with TVM_GETNEXTITEM, starting at TVGN_ROOT. Then select it with TVM_SELECTITEM. Pass the TVGN_FIRSTVISIBLE to ensure it is visible, shouldn't be necessary if you just automate it.
Take a look at AutoIt to avoid writing grungy code like this.
I know this is quite late in coming, but if you are having a similar issue (as am I). You might take a look at AutoHotKey, especially if you are familiar with SendMessage. This would save you the need to compile and a lot of complexity, but to your point it would be possible to navigate through the structure using arrow key presses.