UPD. I have the same situation in C++ win32 code.
C#:
WinAPI part:
const uint EVENT_CONSOLE_CARET = 0x4001;
const uint EVENT_CONSOLE_END_APPLICATION = 0x4007;
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll", SetLastError = true))]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax,
IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc,
uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
static extern bool UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
Code:
Process process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.Start();
_winEventProc = new WinEventDelegate(WinEventProc);
m_hhook = SetWinEventHook(EVENT_CONSOLE_CARET,
EVENT_CONSOLE_END_APPLICATION,
IntPtr.Zero,
_winEventProc,
(uint) process.Id,
0,
WINEVENT_OUTOFCONTEXT);
lastError = Marshal.GetLastWin32Error();
My program cannot catch events from process that I've created. If I change "(uint) process.Id" to "(uint) 0" it working good. I changed "(uint) process.Id" to specific process Id (watched it in task manager) and result was the same(bad). I even tried:
1) start cmd.exe (*)
2) start my program without creating new cmd.exe process
3) press any key at cmd.exe(*)
4) use GetWindowThreadProcessId in _winEventProc
5) re-run my program with pID that I get on 4 step
And it doesn't work. I don't know why but it working well only with processID 0.
p.s. sorry for my bad english
Related
I am trying to intercept VB MsgBoxes from a word template and click them automatically. This code is inserted in a C# Winforms Application, in a class and KillMbox() runs at the click of a button from that form.
I have tried the app in Debug Mode of Visual Studio and the code ran perfectly, intercepting the VBA messagebox.
However, after I have closed the Debug Mode and tried again, I receive An unhandled exception of type 'System.NullReferenceException' occurred in Unknown Module. Object reference not set to an instance of an object.
The error appears at the line GetWindowText(txtHandle, sb, len + 1);.
I have tried the app at a different computer in Debug Mode and it has the same issue, working only for the first time.
In Build version, the app just crashes, receiving App-Name has stopped working.
[DllImport("user32.dll")] static extern int FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")] static extern int SendMessage(int hWnd, int wMsg, int wParam, int lParam);
[DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern int GetWindowTextLength(IntPtr hWnd);
public static void KillMbox()
{
for (int h = 0; h == 0;)
{
Thread.Sleep(1000);
h = FindWindow(null, "Microsoft Word");
if (h != 0)
{
IntPtr hAsIntPtr = new IntPtr(h);
IntPtr txtHandle = FindWindowEx(hAsIntPtr, IntPtr.Zero, "Static", null);
int len = GetWindowTextLength(txtHandle);
StringBuilder sb = new StringBuilder();
GetWindowText(txtHandle, sb, len + 1);
SendMessage(h, 16, 0, 0);
MessageBox.Show(sb.ToString());
}
}
}
Is this a code-related error or a bug? Thank you!
More recently, simulating a click using PostMessage has begun to activate the window. Previously, this was not and the click was performed in an inactive window without focus.
int coords = (y << 16) + x;
IntPtr lParam = new IntPtr(coords);
PostMessage(hwnd, WM_LBUTTONDOWN, IntPtr.Zero, lParam);
PostMessage(hwnd, WM_LBUTTONUP, IntPtr.Zero, lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
const Int32 WM_LBUTTONDOWN = 0x201;
const Int32 WM_LBUTTONUP = 0x202;
So I recently stumbled onto a blog that described how to run your WinForms application from another process.
I instantly thought this was something really cool an unique and wanted to test it out myself. While there was no code it explained how to do so and this is what I've done.
class Program
{
[Flags]
public enum ThreadAccess : int
{
TERMINATE = (0x0001),
SUSPEND_RESUME = (0x0002),
GET_CONTEXT = (0x0008),
SET_CONTEXT = (0x0010),
SET_INFORMATION = (0x0020),
QUERY_INFORMATION = (0x0040),
SET_THREAD_TOKEN = (0x0080),
IMPERSONATE = (0x0100),
DIRECT_IMPERSONATION = (0x0200)
}
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
[Flags]
public enum ProcessAccessFlags : uint
{
All = 0x001F0FFF,
Terminate = 0x00000001,
CreateThread = 0x00000002,
VirtualMemoryOperation = 0x00000008,
VirtualMemoryRead = 0x00000010,
VirtualMemoryWrite = 0x00000020,
DuplicateHandle = 0x00000040,
CreateProcess = 0x000000080,
SetQuota = 0x00000100,
SetInformation = 0x00000200,
QueryInformation = 0x00000400,
QueryLimitedInformation = 0x00001000,
Synchronize = 0x00100000
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
byte[] lpBuffer,
Int32 nSize,
out IntPtr lpNumberOfBytesWritten);
[DllImport("kernel32.dll")]
static extern IntPtr CreateRemoteThread(IntPtr hProcess,
IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress,
IntPtr lpParameter, uint dwCreationFlags, out IntPtr lpThreadId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
ProcessAccessFlags processAccess,
bool bInheritHandle,
int processId
);
public static IntPtr OpenProcess(Process proc, ProcessAccessFlags flags)
{
return OpenProcess(flags, false, proc.Id);
}
static void Main(string[] args)
{
Process notepad = null;
Process[] processes = Process.GetProcesses();
foreach (var process in processes)
{
if (process.ProcessName.ToLower() == "notepad")
{
notepad = process;
}
}
OpenProcess(notepad, ProcessAccessFlags.All);
byte[] payload = File.ReadAllBytes(#"C:\Users\developer\source\repos\WindowsFormsApp2\WindowsFormsApp2\bin\Debug\WindowsFormsApp2.exe");
foreach (ProcessThread pt in notepad.Threads)
{
IntPtr openThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pt.Id);
SuspendThread(openThread);
CloseHandle(openThread);
}
WriteProcessMemory(notepad.Handle, notepad.Modules[0].BaseAddress, payload, payload.Length, out IntPtr lpNumberOfBytesWritten);
CreateRemoteThread(notepad.Handle, IntPtr.Zero, 0x0, notepad.Modules[0].BaseAddress, IntPtr.Zero, 0x0, out _);
}
}
It's something very simple that is supposed to suspend the process and all of it's threads.
And then write the bytearray from my other application which is a simple WinForms application witha button that when you click on it, it shows a MessageBox saying Hello World
But as soon as I run the code, notepad crashes and nothing shows up, where did I go wrong?
Check out this Memory problem with application in C# Windows Forms and also this High memory usage of a windows forms method. I'm led to believe you may have a caching issue or are not writing safe code for memory management. I would start by looking at your entry point to the program and debugging the foreach blocks.
For an example, I have a project (c#) which gives output from 1 to 5 numbers. And if that was one, I want the program to write 'A' in note pad. I didn't use FORM to create my project in c#. It's written in XML. So, May i know how could i do this.?
Like, i tried - SendKeys.Send("{A}"); when the event is fired. But as my project is not a form. I couldn't do it. Can anyone help me on this. :(
Thank You.
MY ACTUAL PROJECT:
I have done with emotion recognition. I have done with Second life emotions. I want to input the emotion detection in (C#) to second life. Only this is left. If I have had clarified my doubt, I could do it. Thank you.
In order to put "A" into the NotePad you can do
Find out NotePad Edit Window (assuming notepad.exe is executing)
Send WM_CHAR message to the window found
The code can be like that
Required Native API declarations:
internal delegate Boolean EnumerationCallback(IntPtr handle, IntPtr parameter);
[DllImport("User32.dll",
CallingConvention = CallingConvention.Winapi,
EntryPoint = "EnumWindows",
CharSet = CharSet.Unicode,
SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean EnumWindows(EnumerationCallback lpEnumFunc,
IntPtr lParam);
[DllImport("User32.dll",
CallingConvention = CallingConvention.Winapi,
EntryPoint = "EnumChildWindows",
CharSet = CharSet.Unicode,
SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern Boolean EnumChildWindows(IntPtr hwndParent,
EnumerationCallback lpEnumFunc,
IntPtr lParam);
[DllImport("user32.dll",
CallingConvention = CallingConvention.Winapi,
EntryPoint = "GetClassNameW",
CharSet = CharSet.Unicode,
SetLastError = true)]
internal extern static int GetClassName(IntPtr hWnd,
[MarshalAs(UnmanagedType.LPWStr)]
StringBuilder name,
int size);
[DllImport("User32.dll",
CallingConvention = CallingConvention.Winapi,
EntryPoint = "GetWindowThreadProcessId",
SetLastError = true)]
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd,
out IntPtr ProcessId);
[DllImport("User32.dll",
EntryPoint = "SendMessageW",
CallingConvention = CallingConvention.Winapi,
SetLastError = true,
CharSet = CharSet.Unicode)]
internal extern static IntPtr SendMessage(IntPtr handle,
int message,
IntPtr wParam,
IntPtr lParam);
const int WM_CHAR = 0x102;
The solution itself:
public void PrintA() {
IntPtr handleNotePad = IntPtr.Zero;
IntPtr handleNotePadEdit = IntPtr.Zero;
// First, find NotePad Main window
EnumWindows(
(IntPtr h, IntPtr p) => {
int processId;
GetWindowThreadProcessId(h, out processId);
if (Process.GetProcessById(processId).ProcessName != "notepad")
return true;
handleNotePad = h;
return false;
},
IntPtr.Zero);
// Second find NotePad EDIT window as a child of NotePad Main window
EnumChildWindows(handleNotePad,
(IntPtr h, IntPtr p) => {
StringBuilder s = new StringBuilder();
s.Length = 500;
GetClassName(h, s, s.Length);
if (s.ToString() != "Edit")
return true;
handleNotePadEdit = h;
return false;
},
IntPtr.Zero);
// Finally, send the message
SendMessage(handleNotePadEdit, WM_CHAR, (IntPtr) 'A', IntPtr.Zero);
}
How might one invoke a callback whenever the current active window changes. I've seen how it might be done using CBTProc. However, global events aren't easy to hook into with managed code. I'm interested in finding a way that doesn't require polling. I'd prefer an event driven approach.
Regards
Create a new windows forms project, add a textbox, make it multiline, and set the textbox Dock property to fill, name it Log and paste in the following code (you'll need to add System.Runtime.InteropServices to your usings)...
WinEventDelegate dele = null;
public Form1()
{
InitializeComponent();
dele = new WinEventDelegate(WinEventProc);
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
}
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
private const uint WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_SYSTEM_FOREGROUND = 3;
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
private string GetActiveWindowTitle()
{
const int nChars = 256;
IntPtr handle = IntPtr.Zero;
StringBuilder Buff = new StringBuilder(nChars);
handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
Log.Text += GetActiveWindowTitle() + "\r\n";
}
I know this thread is old, but for sake of future use:
when running the code you'll notice a crash after a while. This is caused from the line in the Form constructor:
public Form1()
{
InitializeComponent();
WinEventDelegate dele = new WinEventDelegate(WinEventProc);//<-causing ERROR
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
}
Instead of the above make the following modification:
public Form1()
{
InitializeComponent();
dele = new WinEventDelegate(WinEventProc);
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
}
WinEventDelegate dele = null;
..works now as expected!
You can use SetWinEventHook and listen for the EVENT_SYSTEM_FOREGROUND event. Use the WINEVENT_OUTOFCONTEXT flag to avoid the global-hook problem.