How to give input to a windows application programmatically? - c#

This is with reference to this question:
How to read output and give input to a program from c program?
I found the answer to the above question very useful. In the same way, can I do it for windows applications? Like can I give input into a Windows form (like .net, C# applications) application's text box programmatically? Can I do the action of button click from a program?
If so, can I do it from a C program (with Tiny C compiler or any other on windows platform)? If not, how and in which language can I do it? Please don't take it as a silly question. Any example codes will be very much appreciated.
Edit: Can I do the same with web applications and web pages?

If your application mainly just needs to manipulate other windows, by sending keystrokes etc. i would use AutoIt. It's mainly function is exactly this job and it does it very well.
So maybe you should give it a try, cause not every problem is a nail and can be solved with a hammer (C#) ;-))

You can enumerate all the windows of the system.
You can send windows messages to any window.
E.g. to set the text of a textbox you have to send a WM_SETTEXT message.
FYI: Winspector is a very interesting tool which makes heavy use of this as well (also to debug or otherwise first inspect the windows you're trying to programmatically access).
You might also be interested in this:
AutoIt v3 is a freeware BASIC-like scripting language designed for automating the Windows GUI and general scripting. It uses a combination of simulated keystrokes, mouse movement and window/control manipulation in order to automate tasks in a way not possible or reliable with other languages (e.g. VBScript and SendKeys). AutoIt is also very small, self-contained and will run on all versions of Windows out-of-the-box with no annoying "runtimes" required!

As fretje pointed out, you can certainly do it.
It's much more challenging for windows apps. Because individual controls also count as windows, the total window count will be much higher than you might expect; and finding the specific control you want to send input to can take a lot of work.
But you can programmatically move, resize, check, fill, maximize or otherwise affect an app's windows, once you know which one is your target.
I wrote code to do the discovery process a few years ago. It found all the windows of a target app, then using their size & location data, produced a translucent overlay of each child window, along with the handle number. So I could visually tell which control went with which handle.
EDIT: Added some code. This is some basic C# interop code that will let you make easy calls into user32.dll, which holds the fns to which fretje referred. This just gives you the basic calls for discovery and manipulation; you'll still have to do the hard work of enumerating and examining what you find. If you can find a 3rd-party package that does the job for you, save yourself the trouble; I only did it as a learning experience, and it was pretty laborious.
using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Text;
namespace WinAPI
{
[Flags] public enum WindowStyleFlags : uint
{
WS_OVERLAPPED = 0x00000000,
WS_POPUP = 0x80000000,
// more...
}
[Flags] public enum ExtendedWindowStyleFlags: int
{
WS_EX_DLGMODALFRAME = 0x00000001,
WS_EX_NOPARENTNOTIFY = 0x00000004,
// more...
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct POINT
{
public int Left;
public int Top;
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct FLASHWINFO
{
public int cbSize;
public IntPtr hwnd;
public int dwFlags;
public int uCount;
public int dwTimeout;
}
public delegate int EnumWindowsCallback( IntPtr hwnd, int lParam );
public class User32Dll
{
// Constants & fields
public const int FLASHW_STOP = 0;
public const int FLASHW_CAPTION = 0x00000001;
// lots, lots more, web search for them...
// Self-added, don't know if correct
[DllImport("user32")]
public extern static bool CloseWindow( IntPtr hWnd );
[DllImport("user32")]
public extern static IntPtr GetDesktopWindow();
[DllImport("user32")]
public extern static IntPtr GetForegroundWindow();
[DllImport("user32")]
public extern static int GetDlgItem( IntPtr hWnd, int wMsg );
[DllImport("user32")]
public extern static int GetListBoxInfo( IntPtr hWnd );
[DllImport("user32")]
public extern static bool MoveWindow( IntPtr hWnd, int X, int Y, int Width, int Height, bool Repaint );
[DllImport( "user32" )]
public static extern int SendMessage( IntPtr hWnd, int uMsg, IntPtr wParam, StringBuilder lpString );
[DllImport("user32")]
public static extern bool SetWindowPos( IntPtr hWnd, IntPtr afterWnd, int X, int Y, int cX, int cY, uint uFlags );
[DllImport("user32")]
public extern static int BringWindowToTop (IntPtr hWnd);
[DllImport("user32")]
public extern static int EnumWindows( EnumWindowsCallback lpEnumFunc, int lParam );
[DllImport("user32")]
public extern static int EnumChildWindows( IntPtr hWndParent, EnumWindowsCallback lpEnumFunc, int lParam );
[DllImport( "user32.dll" )]
public static extern int EnumThreadWindows( IntPtr hWndParent, EnumWindowsCallback callback, int lParam );
[DllImport( "user32.dll" )]
public static extern int FindWindow( string lpClassName, string WindowName );
[DllImport( "user32.dll" )]
public static extern int FindWindowEx( IntPtr hWnd, IntPtr hWnd2, string lpsz, string lpsz2 );
[DllImport("user32")]
public extern static int FlashWindow ( IntPtr hWnd, ref FLASHWINFO pwfi);
[DllImport("user32")]
public extern static IntPtr GetAncestor( IntPtr hWnd, uint gaFlags );
[DllImport("user32", CharSet = CharSet.Auto)]
public extern static int GetClassName ( IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32", CharSet = CharSet.Auto)]
public extern static uint GetWindowLong( IntPtr hwnd, int nIndex);
[DllImport("user32")]
public extern static int GetClientRect( IntPtr hWnd, ref RECT lpRect);
[DllImport("user32")]
public extern static int GetWindowRect( IntPtr hWnd, ref RECT lpRect);
[DllImport("user32", CharSet = CharSet.Auto)]
public extern static int GetWindowText( IntPtr hWnd, StringBuilder lpString, int cch );
[DllImport("user32", CharSet = CharSet.Auto)]
public extern static int GetWindowTextLength( IntPtr hWnd );
[DllImport("user32")]
public extern static int IsIconic(IntPtr hWnd);
[DllImport("user32")]
public extern static int IsWindowVisible( IntPtr hWnd );
[DllImport("user32")]
public extern static int IsZoomed(IntPtr hwnd);
[DllImport("user32", CharSet = CharSet.Auto)]
public extern static int PostMessage( IntPtr hWnd, int wMsg, int wParam, int lParam);
[DllImport( "user32.dll" )]
public static extern int RealGetWindowClass( IntPtr hWnd, StringBuilder pszType, uint bufferSize );
[DllImport("user32")]
public extern static int ScreenToClient( IntPtr hWnd, ref POINT lpPoint);
[DllImport("user32", CharSet = CharSet.Auto)]
public extern static int SendMessage( IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public extern static int SetForegroundWindow (IntPtr hWnd);
[DllImport( "user32.dll" )]
public static extern int SetWindowText( IntPtr hWnd, string lpsz );
}
}

Check out the following SO question. There are numerous vendor and open-source tools to do this for you, so you don't have to code at to the Win32 API.
automated-testing-of-windows-forms

Related

Postmessage not being sent until window receives focus. C# .NET

I'm trying to Postmessage send key inputs to an application. The issue is that the message is being sent only when the application becomes active or gains focus.
Here is my goal:
I need the application to receive inputs either while it is not focused, or via some pseudo-focus called via postmessage before the input is sent (I have tried: NativeMethods.PostMessage(mainHwnd, 0x0007, 0, 0); "0x0007" is WM_SETFOCUS but this doesn't do anything). Any assistance would be very helpful, I've been at this for more hours than I care to count.🙏
Here is all of the relevant code I'm using:
using System.Runtime.InteropServices;
using System;
using System.Windows.Forms;
using System.Threading;
internal static class NativeMethods
{
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, UInt32 uMsg, Int32 wParam, Int32 lParam);
}
class Test
{
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
//const int WM_SETFOCUS = 0x0007;
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
public static void SendKey()
{
IntPtr mainHwnd = NativeMethods.FindWindow(null, "Test Application");
NativeMethods.PostMessage(mainHwnd, WM_KEYDOWN, (int)Keys.A, 0);
Thread.Sleep(50);
NativeMethods.PostMessage(mainHwnd, WM_KEYUP, (int)Keys.A, 0);
}
}
class TryTheThing{
public void Send() {
Test.SendKey();
}
}
Windows does not allow you to send keystrokes to non-focused applications. Your only option is to force the window to be focused first. This can be achieved by P/Invoking SetForegroundWindow():
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
NativeMethods.SetForegroundWindow(mainHwnd);

user32.dll SendMessage VolumeUp and VolumeDown issue

I'm trying to make a Unity3D Application that can control the volume of another application. So far I've gotten it to work to change the volume of ALL applications, but I'm having trouble to get it to change just one, e.g. Spotify. This is on Windows 8, but I'd like it to work for Windows 7 as well.
private const int APPCOMMAND_VOLUME_UP = 0xA0000;
private const int APPCOMMAND_VOLUME_DOWN = 0x90000;
private const int WM_APPCOMMAND = 0x319;
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string strClassName, string strWindowName);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
[DllImport("user32.dll")]
public static extern IntPtr GetActiveWindow();
public void DecreaseVolume()
{
IntPtr hWnd = FindWindow("SpotifyMainWindow", "Spotify");
if (hWnd == IntPtr.Zero)
return;
uint pID;
GetWindowThreadProcessId(hWnd, out pID);
Debug.Log(pID);
SendMessage(hWnd, WM_APPCOMMAND, hWnd, (IntPtr)APPCOMMAND_VOLUME_DOWN);
}
public void IncreaseVolume()
{
// same as above, but with APPCOMMAND_VOLUME_UP
}
I'm pretty sure I'm getting the correct handle (hWnd) from FindWindow() because the pID printed out matches the PID of Spotify in my Task Manager, however all this does is change the volume of everything instead of just Spotify. This is the same result as if I didn't specify a specific handle e.g.
SendMessage(IntPtr.Zero, WM_APPCOMMAND, IntPtr.Zero, (IntPtr)APPCOMMAND_VOLUME_DOWN);
or if I use GetActiveWindow().
I've never messed around with these windows api stuff until today, so any help would be very appreciated!

How to scroll Window in other process with Win32API

Im trying to create a program where I can send some process id of a process (that may be firefox, ie, notepad etc) to a method that scrolls window of the process.
I have been trying with GetScrollBarInfo and SetScrollPos which I found at pinvoke without any success. Im not sure if this is the right way or not. I started playing with GetScrollBarInfo, but it doesn't seem to work.
I tried the code found at http://www.pinvoke.net/default.aspx/user32.getscrollbarinfo
[StructLayout(LayoutKind.Sequential)]
public struct SCROLLBARINFO
{
public int cbSize;
public Rectangle rcScrollBar;
public int dxyLineButton;
public int xyThumbTop;
public int xyThumbBottom;
public int reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
public int[] rgstate;
}
private const uint OBJID_HSCROLL = 0xFFFFFFFA;
private const uint OBJID_VSCROLL = 0xFFFFFFFB;
private const uint OBJID_CLIENT = 0xFFFFFFFC;
private int Scroll(int ProcessID)
{
IntPtr handle = Process.GetProcessById(ProcessID).MainWindowHandle;
SCROLLBARINFO psbi = new SCROLLBARINFO();
psbi.cbSize = Marshal.SizeOf(psbi);
int nResult = GetScrollBarInfo(handle, OBJID_CLIENT, ref psbi);
if (nResult == 0)
{
int nLatError = Marshal.GetLastWin32Error();
}
}
GetLastWin32Error() returns errorcode 122 which means "The data area passed to a system call is too small", according to http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
Im not sure what I do wrong. How can I solve this?
You could send a WM_MOUSEWHEEL message to do what you want. For example, to scroll down once in a new notepad window using C++:
HWND hwnd = FindWindowEx(FindWindow(NULL, "Untitled - Notepad"), NULL, "Edit", NULL);
RECT r;
GetClientRect(hwnd, &r);
SendMessage(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA * -1), MAKELPARAM(r.right / 2, r.bottom / 2));
To adapt that to C#, you could do something such as this:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, ref Point lParam);
private void ScrollWindow(IntPtr hwnd, Point p, int scrolls = -1)
{
SendMessage(hwnd, WM_MOUSEWHEEL, (WHEEL_DELTA * scrolls) << 16, ref p);
}
Which could be used to scroll down once in a new notepad window like this:
//Imports
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
...
//Actual code
IntPtr hwnd = FindWindowEx(FindWindow(null, "Untitled - Notepad"), IntPtr.Zero, "Edit", null);
Point p = new Point(0, 0);
ScrollWindow(hwnd, p);
Some programs will require the lParam sent to be a point that's actually above the scrolled area, while others such as notepad will not.
If you're trying to scroll the window of another process, you need to, in effect, simulate clicks on the scroll bar or key presses. The cleanest way to do that is to use UI Automation, which has both .NET and native interfaces.
By asking for the scrollbar info, you're simply getting information about how the scrollbar is displayed. That's not going to give you a way to scroll the window content. You have to get the target application to scroll the content by making it think the user is operating the scrollbar.
http://forums.codeguru.com/showthread.php?446352-How-to-scroll-active-window-SendMessage&p=1686041#post1686041
Final Code
class Program
{
[DllImport("user32.dll")]
static extern bool GetGUIThreadInfo(uint idThread, ref GUITHREADINFO lpgui);
[DllImport("user32.dll")]
public static extern int SetScrollPos(IntPtr hWnd, System.Windows.Forms.Orientation nBar, int nPos, bool bRedraw);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
public struct GUITHREADINFO
{
public int cbSize;
public int flags;
public IntPtr hwndActive;
public IntPtr hwndFocus;
public IntPtr hwndCapture;
public IntPtr hwndMenuOwner;
public IntPtr hwndMoveSize;
public IntPtr hwndCaret;
public System.Drawing.Rectangle rcCaret;
}
const Int32 WM_VSCROLL = 0x0115;
const Int32 SB_LINERIGHT = 1;
static void Main(string[] args)
{
//create process in focus
Process.Start("notepad++", "Source.cpp");
Thread.Sleep(1000);
GUITHREADINFO threadInfo = new GUITHREADINFO();
threadInfo.cbSize = Marshal.SizeOf(threadInfo);
GetGUIThreadInfo(0, ref threadInfo);
SendMessage(threadInfo.hwndFocus, WM_VSCROLL, SB_LINERIGHT, 0);
//SetScrollPos not work. Change only scrollbar without scroll window
//SetScrollPos(threadInfo.hwndFocus, System.Windows.Forms.Orientation.Vertical, 10, true);
}
}

How to hide Start button while openning camera using CameraCaptureDialog in windows mobile

How to hide Start button while openning camera using CameraCaptureDialog in windows mobile
Do you just want to hide the Start button, or the whole taskbar?
You can hide and show the complete taskbar by using this code:
[DllImport("coredll", EntryPoint = "FindWindow")]
public static extern IntPtr FindWindow(
[In] string lpClassName,
[In] string lpWindowName);
[DllImport("coredll", EntryPoint = "ShowWindow")]
public static extern bool ShowWindow(
[In] IntPtr hWnd,
[In] int nCmdShow);
[DllImport("coredll", EntryPoint = "EnableWindow")]
public static extern bool EnableWindow(
[In] IntPtr hWnd,
[In] bool bEnable);
public const int SW_HIDE = 0x0000;
public const int SW_SHOW = 0x0001;
public static void HideTaskBar()
{
IntPtr hWnd = FindWindow("HHTaskBar", null);
EnableWindow(hWnd, false);
ShowWindow(hWnd, Win32.SW_HIDE);
}
public static void ShowTaskBar()
{
IntPtr hWnd = FindWindow("HHTaskBar", null);
EnableWindow(hWnd, true);
ShowWindow(hWnd, Win32.SW_SHOW);
}

Launch System Screensaver from C# Windows Form

Hopefully this is a simple one, but can anyone provide some simple c# code that will launch the currently configured screensaver?
Here is a good site showing how to work with all aspects of the screensaver. See the comments at the end for the code to start the screensaver.
http://www.codeproject.com/KB/cs/ScreenSaverControl.aspx
[DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
private static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
//...
private const int SC_SCREENSAVE = 0xF140;
private const int WM_SYSCOMMAND = 0x0112;
//...
public static void SetScreenSaverRunning()
{
SendMessage
(GetDesktopWindow(), WM_SYSCOMMAND, SC_SCREENSAVE, 0);
}

Categories

Resources