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);
}
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!
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.
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
ok, I have found many posts on finding a window by name, etc. What I have not found is how to find and switch the window application focus to last active window. The code I am showing below will give me the list of active applications in the task manager that are active.
What I can not figure out how to do is figure out what application was the last active application, and then switch to it. for example...
I have my custom winform application open.
I click a button
My application switches to the last active window / application.
Here is the working code I have so far. (this is the action on a button, and it expects that the application has a textbox named textbox1. you will also need to add using System.Diagnostics;
private void button1_Click(object sender, EventArgs e)
{
Process[] procs = Process.GetProcesses();
IntPtr hWnd;
foreach (Process proc in procs)
{
if ((hWnd = proc.MainWindowHandle) != IntPtr.Zero)
{
textBox1.Text += (proc.ProcessName.ToString());
textBox1.Text += "\t";
textBox1.Text += (hWnd.ToString());
textBox1.Text += "\r\n";
}
}
}
Check this article out: http://www.whitebyte.info/programming/how-to-get-main-window-handle-of-the-last-active-window
Specifically, this code:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
enum GetWindow_Cmd : uint
{
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern IntPtr GetParent(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[...]
IntPtr targetHwnd = GetWindow(Process.GetCurrentProcess().MainWindowHandle, (uint)GetWindow_Cmd.GW_HWNDNEXT);
while (true)
{
IntPtr temp = GetParent(targetHwnd);
if (temp.Equals(IntPtr.Zero)) break;
targetHwnd = temp;
}
SetForegroundWindow(targetHwnd);
Since my comments didn't help you, here's a little resume (didn't test it though):
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
static extern IntPtr GetLastActivePopup(IntPtr hWnd);
[DllImport("user32.dll", ExactSpelling = true)]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
const uint GA_PARENT = 1;
const uint GA_ROOT = 2;
const uint GA_ROOTOWNER = 3;
public IntPtr GetPreviousWindow()
{
IntPtr activeAppWindow = GetForegroundWindow();
if ( activeAppWindow == IntPtr.Zero )
return IntPtr.Zero;
IntPtr prevAppWindow = GetLastActivePopup(activeAppWindow);
return IsWindowVisible(prevAppWindow) ? prevAppWindow : IntPtr.Zero;
}
public void FocusToPreviousWindow()
{
IntPtr prevWindow = GetPreviousWindow();
if ( prevWindow != IntPtr.Zero )
SetForegroundWindow(prevWindow);
}
I'd like to know how to grab the Window title of the current active window (i.e. the one that has focus) using C#.
See example on how you can do this with full source code here:
http://www.csharphelp.com/2006/08/get-current-window-handle-and-caption-with-windows-api-in-c/
[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;
StringBuilder Buff = new StringBuilder(nChars);
IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
Edited with #Doug McClean comments for better correctness.
If you were talking about WPF then use:
Application.Current.Windows.OfType<Window>().SingleOrDefault(w => w.IsActive);
Based on GetForegroundWindow function | Microsoft Docs:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowTextLength(IntPtr hWnd);
private string GetCaptionOfActiveWindow()
{
var strTitle = string.Empty;
var handle = GetForegroundWindow();
// Obtain the length of the text
var intLength = GetWindowTextLength(handle) + 1;
var stringBuilder = new StringBuilder(intLength);
if (GetWindowText(handle, stringBuilder, intLength) > 0)
{
strTitle = stringBuilder.ToString();
}
return strTitle;
}
It supports UTF8 characters.
Loop over Application.Current.Windows[] and find the one with IsActive == true.
Use the Windows API. Call GetForegroundWindow().
GetForegroundWindow() will give you a handle (named hWnd) to the active window.
Documentation: GetForegroundWindow function | Microsoft Docs
If it happens that you need the Current Active Form from your MDI application: (MDI- Multi Document Interface).
Form activForm;
activForm = Form.ActiveForm.ActiveMdiChild;
you can use process class it's very easy.
use this namespace
using System.Diagnostics;
if you want to make a button to get active window.
private void button1_Click(object sender, EventArgs e)
{
Process currentp = Process.GetCurrentProcess();
TextBox1.Text = currentp.MainWindowTitle; //this textbox will be filled with active window.
}