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);
Related
I have an application that I would like to close from my current C# application. The problem is that the application I want to close has an exit confirmation that requires the user to confirm the closing of the application.
When I use this code:
foreach (Process process in runningProcesses)
{
if (process.ProcessName == "ProcessName")
process.CloseMainWindow();
}
the exit confirmation popup still appears on the other application.
When questions similar to this are asked elsewhere, all I can find are people suggesting process.Kill() to get past the exit confirmation. This is not an option for me as I need the other application to close down gently.
Is there a way to send a closing message to the other application that will force it to start its shutdown process without killing the process abruptly?
If you have to close the application gently and it displays a confirmation when trying to close it, then you'll have to handle it as well.
The actual way to do that depends on what exactly the popup is. If it's a standard dialog, something like the following could suffice:
SendMessage(hDlg, WM_COMMAND, IDOK, 0);
If it's a less standard dialog, but still using standard Windows components (like MFC or WinForms or something), you'll have to inspect its window structure (using Spy++ for example), get the handle of the button you need to press and use something like:
SendMessage(hBtn, BM_CLICK, 0, 0);
If however the dialog doesn't use standard windows (like Qt or WPF), you'll need a lot more specialized code. I'd suggest hooking into the parent dialog and pressing the button yourself to see what events are triggered (Spy++ can do that) and mimicking them with SendMessage.
You can send a WM_ENDSESSION message, which in most applications cause all forms to gracefully close.
PostMessage(process.MainWindowHandle, WM_ENDSESSION, IntPtr.Zero, new IntPtr(ENDSESSION_CLOSEAPP));
Definitions:
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
const int WM_ENDSESSION = 0x16;
const int ENDSESSION_CLOSEAPP = 0x1;
Here's my problem: we have an automated build process for our product. During the compilation of one of the VB6 projects a message box is spit out that requires the user to click 'ok' before it can move on. Being an automated process this is a bad thing because it can end up sitting there for hours not moving until someone clicks ok. We've looked into the VB6 code to try and suppress the message box, but no one can seem to figure out how to right now. So as a temp fix I'm working on a program that will run in the background and when the message box pops up, closes it. So far I'm able to detect when the message pops up but I can't seem to find a function to close it properly. The program is being written in C# and I'm using the FindWindow function in user32.dll to get a pointer to the window. So far I've tried closeWindow, endDialog, and postMessage to try and close it but none of them seem to work. closeWindow just minimizes it, endDialog comes up with a bad memory exception, and postMessage does nothing. Does anyone know of any other functions that will take care of this, or any other way of going about getting rid of this message? Thanks in advance.
here's the code I have currently:
class Program
{
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
static void Main(string[] args)
{
IntPtr window = FindWindow(null, "Location Browser Error");
while(window != IntPtr.Zero)
{
Console.WriteLine("Window found, closing...");
//use some function to close the window
window = IntPtr.Zero;
}
}
}
You have to found the window, that is the first step. After you can send the SC_CLOSE message using SendMessage.
Sample
[DllImport("user32.dll")]
Public static extern int SendMessage(int hWnd,uint Msg,int wParam,int lParam);
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_CLOSE = 0xF060;
IntPtr window = FindWindow(null, "Location Browser Error");
if (window != IntPtr.Zero)
{
Console.WriteLine("Window found, closing...");
SendMessage((int) window, WM_SYSCOMMAND, SC_CLOSE, 0);
}
More Information
Find and Close the window using WIN API
When you find the message box, try sending it WM_NOTIFY with a BN_CLICKED type and the ID of the OK button.
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.
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