I want to send a pressKey event to a certain application which is not the active application IN Windows so I have to use the sendMessage/postMessage api calls.
However, I need to know the exact child window that is active IN the application and send the pressKey message to it...
I was using GetTopWindow and GetWindow(GW_CHILD) api calls to get the top child window of the main window, and do it again with the obtained child window to get the top grandchildWindow, and keep doing it until I found a childwindow with no more childwindows. This works great for some applications but in some cases it doesn't. Sometimes the parent window is the active window, not one of its childwindows, so getting the parent's top child window will not work cause I will be sending a message to the wrong window.
The only way I found of doing this (getting the handler of the actual active window) was using the GuiThreadInfo api call but it only works if the target application is the active one IN Windows. As I mentioned in the beginning, it isn't so the handler comes null.
I can bring the application to the top using setForegroundWindow api call but I DON'T want to do this. I also tried the AttachThreadInput and GetFocus api calls, but again, they only work if the target application is the active application IN windows.
Any ideas? Thanks
I assume from the things that you have tried that you know how to get a handle to your main window, but if you don't just leave a comment and I will post a snippet for that.
I combined a few things that I found on the net to figure this out, but the main one is this one. I don't have a great app to test this with, but it works in a simple case. One exception is that I think if you use tool windows in your application it will not find that as it is coded because I think the GetLastActivePopup method doesn't include them (not sure about that, and didn't test that case).
[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 GetAncestor(IntPtr hwnd, uint gaFlags);
const uint GA_PARENT = 1;
const uint GA_ROOT = 2;
const uint GA_ROOTOWNER = 3;
public static IntPtr GetAppActiveWindow(IntPtr hwnd)
{
IntPtr activeAppWindow = IntPtr.Zero;
if (hwnd != IntPtr.Zero)
{
//Get the root owner window (make sure we are at the app window
//if you already have a handle to the main window shouldn't have
//to do this but I put it in just in case
hwnd = GetAncestor(hwnd, GA_ROOTOWNER);
while ((activeAppWindow =
GetLastActivePopup(hwnd)) != activeAppWindow)
{
if (IsWindowVisible(activeAppWindow))
break;
hwnd = activeAppWindow;
}
}
return activeAppWindow;
}
If you know the Window title and the Window class name, take a look at FindWindow() and FindWindowEx() and see if those meet your needs.
FindWindow(): http://msdn.microsoft.com/en-us/library/ms633499.aspx
FindWindowEx(): http://msdn.microsoft.com/en-us/library/ms633500(VS.85).aspx
Related
I sent a WM_ACTIVE message using postmessage api to some programs.
When a program is deactivated, sending a message does not actually activate the window, but the program thinks it is active. ( It actually succeeded. )
However, I think it is very inefficient to send postmessage regularly.
If I want to check the WM_ACTIVE value of the program and it is inactivated, I try to send a WM_ACTIVE message again using the POSTMESSAGE API to confuse the program itself with being active, but I can't think of a way. Although there is an idea that hooking would be easy to use, C# did not support other types of global hooking except for the keyboard and mouse.
Can anyone come up with any other ideas? please help me.
To check if a process is focused you should use GetForegroundWindow to get the focused window handle and then use GetWindowThreadProcessId to get the process from that window handle:
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(int hWnd, out int ProcessId);
IntPtr focusedWindow = GetForegroundWindow(); //get the focused window
int focusedProcessID = 0;
GetWindowThreadProcessID(focusedWindow, out focusedProcessID); //get it's process id
Process focusedProcess = Process.GetProcessById(focusedProcessID);//get the focused process
Console.WriteLine("Current Focused Process:" + focusedProcess.ProcessName);
I am trying to destroy a child window created by a third party application. I tried to use WinApi to make this happen but it seems that DestroyWindow(hwnd) doesn't do the trick. I indeed get a handle to work with but nothing happens, the child window remains. I tried to use CloseWindow(hwnd) just to verify the child window can be modified and yes, CloseWindow(hwnd) minimizes the Child Window but I want to close it.
This is my Code:
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool DestroyWindow(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseWindow(IntPtr hWnd);
private static void CloseChildWindow();
{
IntPtr _hwnd = IntPtr.Zero;
if (WindowController.FindWindow(null, "System Alert") != IntPtr.Zero)
{
_hwnd = WindowController.FindWindow(null, "System Alert");
DestroyWindow(_hwnd); //Returns error code 5: Access Denied
CloseWindow(_hwnd); //Minimizes the window therefore _hwnd is correct
}
}
Any ideas on what is happening or a workaround would be appreciated, thanks in advance.
EDIT1: Destroywindow returns code error 5: Access Denied. Any ideas on a workaround?
The documentation for the win32 API DestroyWindow is pretty clear:
A thread cannot use DestroyWindow to destroy a window created by a
different thread.
You may be able to inject a DLL in the third party application, hooking the correct thread and then issuing the DestroyWindow call from here, but I will not recommand that, as it may have weird side effects (read: crash). Some applications don't react well when their windows are destroyed under their feet.
The proper way is probably to fake an user interaction, using regular Windows message (as WM_CLOSE), or SendInput, or UI Automation.
If the user has no way to close that window, you are out of luck.
We only want one instance of our app running at any one time. So on start up it looks to see if the app is running and if it is, it calls SetForegroundWindow on the Main Window.
This is all good and well ... for the most part..
When our app starts up it will show a Splash screen and a Logon form. Both of these forms have ShowInTaskBar = false.
Because of this, if you try to start up another copy of the app when the Logon form is showing, that Logon form is not brought to the front!
Especially as the user cant see anything in the taskbar as well, all they figure is that the app is duff and cannot start. There is no indication that there is another instance running.
Is there any way around this problem?
Well, code is here. Even if the ShowInTaskBar is false, you should be able to bring it to the front.
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(String lpClassName, String lpWindowName);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
public static void bringToFront(string title) {
// Get a handle to the Calculator application.
IntPtr handle = FindWindow(null, title);
// Verify that Calculator is a running process.
if (handle == IntPtr.Zero) {
return;
}
// Make Calculator the foreground application
SetForegroundWindow(handle);
}
Note: you should FindWindow using the form's class and not by name as the splash screen forms sometimes do not have titles or even the controlbox. Use Spy++ to dig deeper.
Use FindWindow on splash. I think this is what you want to do - bring the splash screen in front while loading of the main form.
I think this is the better solution because its restores from minimized state:
public static class WindowHelper
{
public static void BringProcessToFront(Process process)
{
IntPtr handle = process.MainWindowHandle;
if (IsIconic(handle))
{
ShowWindow(handle, SW_RESTORE);
}
SetForegroundWindow(handle);
}
const int SW_RESTORE = 9;
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr handle);
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool ShowWindow(IntPtr handle, int nCmdShow);
[System.Runtime.InteropServices.DllImport("User32.dll")]
private static extern bool IsIconic(IntPtr handle);
}
Simple call:
WindowHelper.BringProcessToFront(process);
FindWindow(null, title);
Will find the first window that matches the query. This may lead to unexpected behavior if another window uses the same title.
Although the chances of this to happen may seem rare or impossible (single instance application) this can easily occur. The windows explorer for instance uses the name of the selected directory as window title (although invisible). Now if the window title is a common term or matches the name of the application directory this can be an issue.
I wanna send key stroke to a program even if it is running in background. But I can do this only for NOTEPAD like this,
[DllImport("user32.dll")]
protected static extern byte VkKeyScan(char ch);
[DllImport("user32.dll", SetLastError = true)]
protected static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.Dll", EntryPoint = "PostMessageA")]
protected static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
char Key = // key value to send
IntPtr hWnd = FindWindowEx(_handle, IntPtr.Zero, "edit", null); // _handle is the windows handle of the program (here its notepad)
PostMessage(hWnd, WM_KEYDOWN, VkKeyScan(Key), 0);
But for all other applications I can't send keystrokes if its in background. Since I don't know the lpszClass of that program (I think this is the userControl name of the typing area in that program. For NotePad it is "edit". I found this surfing internet).
For all other applications what I'm doing is, get the application to foreground, then send the key, then again get my program foreground. I need my program to be run as foreground always.
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
SetForegroundWindow(_handle); // _handle is the windows handle of the program
System.Threading.Thread.Sleep(50); // Waiting few milliseconds till application coming to foreground.
wsh.SendKeys(Key.ToString(), ref wait); // wsh is WshShellClass wsh= new WshShellClass();
SetForegroundWindow(_mainHandle); // _mainHandle is the windows handle of my application
But this way is not working. some keys getting missed and the program foreground->background->foregound->background...... like its dancing...
How to send keys to other applications if its running in background.
or are there any way/source to find the lpszClass of a program ?
Sorry if I have missed any required information. this is a large application. I have posted only required parts here. If someone needs any additional information, pls ask.
I think you'll need to have the background program install a low-level keyboard hook via the win32 function SetWindowsHookEx().
Here's the MSDN documentation for SetWindowsHookEX()
http://msdn.microsoft.com/en-us/library/ms644990(v=vs.85).aspx
And here's the KB article on how to do it from C#
http://support.microsoft.com/kb/318804
This article goes into some detail, too: http://www.codeguru.com/columns/vb/article.php/c4829
I expect your app will get caught by various spyware/anti-virus software as a keyboard logger, though.
Good luck.
You may be able to figure out the lpszClass of the program using an inspection tool such as WinSpy++. It gives you a crosshair that you can drag and position over the desired control. This was able to easily provide me with the "edit" class name for notepad.
If things aren't working, click the "More>>" button in the lower right of WinSpy++, then click the "Locate" button to view the control hierarchy; you may need to post the WM_KEYDOWN message to one of the parent or child controls instead.
I'm trying to get my C# form to be parented correctly in a third party app, I have the handle to the control that I would like my form parented to but just can't seem to get it to work.
alt text http://img693.imageshack.us/img693/8871/examplec.jpg
I would like to create my form so that it is part of the MDIClient, handle 005E0ED6. Just like Window 01D7157D.
Is this possible? If so can it be done in C#?
How have you tried doing it? Did you try SetParent? See the following StackOverflow question to see if it helps. Embedding HWND into external process using SetParent
This code seems to work:
[DllImport("user32.dll")]
private static extern
IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")]
private static extern
IntPtr AttachThreadInput(IntPtr idAttach, IntPtr idAttachTo, int fAttach);
WinAPI.SetParent(this.Handle, otherappshandle);
IntPtr otherprocessID = GetWindowThreadProcessId(otherappshandle, new IntPtr(0));
IntPtr threadID = new IntPtr(AppDomain.GetCurrentThreadId());
AttachThreadInput(threadID , otherprocessID , 1);
Good luck. I've gone down that road, and found that there's enough little irritating gotchas that I eventually gave up on it.
SetParent() and the like will get you part of the way there, but there's a bunch of little gotchas to watch as far as the overall system (message pump blocking etc.) that just make it a time sink.
With WinForms, especially, I'd highly recommend just running your UI in the main process (if you can), and if you want to isolate your processing in another process do that instead.