SendKeys to inactive application - c#

I am trying to figure out how I can make my C# application to send keys to another application window, without focusing on it.
I have a list of words and 3 notepads files.
Imagine I have all 3 notepad windows opened in order, and my program would take the first word in the listbox and write it in the first Notepad window. The second word in the second Notepad window and third one in the third Notepad window. Then start over and continue.
So I want it to post 1 word in each and continue like that over and over.
But I only figured out how to do it with 1 notepad window (while having it active).
int i = 0;
i = listBox1.SelectedIndex;
i = i + 1;
if (i > listBox1.Items.Count - 1)
i = 0;
listBox1.SelectedIndex = i;
string message = listBox1.SelectedItem.ToString();
SendKeys.Send(message);
SendKeys.Send("{ENTER}");
This would require me to first focus on the notepad window, start the timer and then keep focus on the notepad window. It would then just loop through the list and type the word (1 on each line). And it works fine. But I want to be able to do it on 3 windows.
And then I need to get the window title somehow, not the process name.
I would have 3 processes called Notepad then.
But if they are named Note1, Note2, Note3 how would I do that?
I need help to make some kind of list of what programs to write to:
listofprograms = ["Note1", "Note2", "Note3"];
And it would find the application windows opened with those names,
then somehow write the text into those windows.
Could anyone help me out? Haven't found anything about this so far and trust me I've looked around!

Unfortunately there is no great way to do this. SendKeys is a really simple and desirable API but it only applies to the active window. There is no way to make it work on an inactive window nor is there an API with the same ease of access that works on inactive windows.
Generally when people run up against this problem they have to go one of two routes
Physically active the apps you want to send the keys to one at a time
Drop down to a much lower level of SendMessage or PostMessage to send keyboard events
The second option is generally more reliable but harder to implement.

SendKeys is not made for this type of functionality. To do what you're looking for, you're going to need to use some Win32 API calls in your code. See How to send text to Notepad in C#/Win32? for reference.

If you're looking for a way to send keys to an application, using SendKeys.Send(keys) is an option, but you need to bring the window to the top via the SetForegroundWindow API.
So, if you continue using your approach, you could use FindWindow, SetForegroundWindow to force the Notepad windows to be activated and focused, so that you could send the keys.
[DllImportAttribute("User32.dll")]
private static extern int FindWindow(String ClassName, String WindowName);
[DllImport("user32.dll")]
private static extern IntPtr SetForegroundWindow(int hWnd);
public int Activate(int hWnd)
{
if (hWnd > 0) {
SetForegroundWindow(hWnd);
return hWnd;
}
else {
return -1;
}
}
public int GetWindowHwnd(string className, string windowName) {
int hwnd = 0;
string cls = className == string.Empty ? null : className;
string win = windowName == string.Empty ? null : windowName;
hwnd = FindWindow(cls , win );
return hwnd;
}
Although there is also another solution, which could help you out. Here all Notepad processes are handled:
How to send text to Notepad in C#/Win32?
With some adaptions it should work for your case, too (basically you would iterate and loop through the notepad instances found and place a word in each instance).
You might also want to take a look at the following information about FindWindow:
http://www.pinvoke.net/default.aspx/user32.findwindow
SetKeyboardState:
http://www.pinvoke.net/default.aspx/user32/SetKeyboardState.html
As well as SendMessage:
http://www.pinvoke.net/default.aspx/coredll/SendMessage.html
You should find some useful hints in the examples and descriptions.

Related

List of visible windows in C# returning invisible windows [duplicate]

I have a Win32 application that determines whether there are any visible, non-iconic, minimizable windows being shown. To the best of my knowledge it's worked fine for Win9x through to Win8.1, but under Windows 10 it often finds several windows that aren't actually visible on the screen.
To try to identify what's going on I've written a simple test application that enumerates and records all such windows. Here's the essence of the EnumWindows callback code:
BOOL CALLBACK EnumFunc( HWND hWnd, LPARAM lParam )
{
if ( IsWindowVisible( hWnd ) )
{
if ( !IsIconic( hWnd ) )
{
const LONG style = GetWindowLong( hWnd, GWL_STYLE );
if ( WS_MINIMIZEBOX & style )
{
// record window info
}
}
}
return TRUE;
}
Most of the phantom windows under Windows 10 belong to background store app processes such as Mail, Calculator, and Photos. These are listed under the Background processes section of Task Manager, and if I use Task Manager to end those background tasks, their phantom window is no longer found by my test application.
In the above screen shot from my test application you can see that all but 1 of the offending windows belong to threads of the same process id 7768, which is ApplicationFrameHost.exe. The final window with process id 11808 is explorer.exe.
I've looked at the phantom windows with Spy++ and can't see any particular style combination that would help in uniquely identifying them.
I've had a suggestion that the undocumented Windows "bands" may be involved, but I've tried using the (undocumented, so this may be wrong) API:
BOOL WINAPI GetWindowBand (HWND hWnd, PDWORD pdwBand);
but it returns a band of 1 for any window, so doesn't differentiate these phantoms.
How to reliably identify these phantom windows?
The approved way of detecting these phantom windows is to use DwmGetWindowAttribute and DWMWA_CLOAKED.
Here's the code I've used:
static bool IsInvisibleWin10BackgroundAppWindow( HWND hWnd )
{
int CloakedVal;
HRESULT hRes = DwmGetWindowAttribute( hWnd, DWMWA_CLOAKED, &CloakedVal, sizeof( CloakedVal ) );
if ( hRes != S_OK )
{
CloakedVal = 0;
}
return CloakedVal ? true : false;
}
Thanks to Scot Br from MS for posting the answer here
Top-level windows of class ApplicationFrameWindow are containers for Windows Store apps. First, here is the window of Mail shown in Spy:
This is truly visible (not phantom). You can tell that it is because the first child is a window of class Windows.UI.Core.CoreWindow. Interestingly, the owner process of the ApplicationFrameWindow is APPLICATIONFRAMEHOST, but the owner process of the Windows.UI.Core.CoreWindow is a different one: HXMAIL. (I've not seen a child window owned by a different process than the parent one before!)
Compare that with a phantom window (as identified in your RWTool):
It is missing the child of class Windows.UI.Core.CoreWindow.
This suggests an answer to your question: If a top-level window is of class ApplicationFrameWindow, iterate it's children. If the first child has class Windows.UI.Core.CoreWindow, the window is visible, otherwise it is not (i.e. it is phantom).
But what if an old-fashioned, non-store app happened to have a top-level window of class ApplicationFrameWindow? It would not have a child of Windows.UI.Core.CoreWindow. Yet it is visible. How to tell this is an ordinary app and not a Windows Store app? I don't have a foolproof way. You could also check for the existence of the other child windows of a Store app: ApplicationFrameTitleBarWindow and ApplicationFrameInputSinkWindow. The chances of a non-Store app having this exact Windows hierarchy is vanishingly small.
EDIT
The ApplicationFrameWindow's (and also Windows.UI.Core.CoreWindow) have the WS_EX_NOREDIRECTIONBITMAP style set:
The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
At minimum, you could check for this style instead of special casing ApplicationFrameWindow. Though to see if any content was truly visible, you'd still need to make that depend on whether it has a child of Windows.UI.Core.CoreWindow.

How to change back and forth application focus with global hotkey in C#

I am creating my own C# clipboard manager and I have a global hotkey, ALT+H, that will trigger removal of text formatting from the clipboard. My application runs in the backend with a tray icon only. As such this is working fine but my problem is that when I am inside an application, e.g. Word and I am pressing my hotkey, then it will show me all kind of menus inside those applications and I do not want that.
Just for info then this is very related to another question I have on SO currently, How to stop further processing global hotkeys in C#. In the other question, this is based on finding a solution for the hotkey but another approach, which I think could even be better, could be to temporary switch focus to my application and once my hotkey is no longer applicable then the focus can be switched back to the originating application.
However then I have no idea how to switch back to the originating application again!?
My code so far, only focussing on the application changing mechanishmn:
Programs.cs:
// Import the required "SetForegroundWindow" method
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
Form1.cs:
// Change focus to my application (when hotkey is active)
Program.SetForegroundWindow(this.Handle);
I am not fully sure if this actually does work but I can see that the originating application (e.g. Word) looses focus and my application works fine still so I do expect it works fine.
My problem is - how to get the hWnd(?) handle from the originating application so I can switch back to it once done? And what if I am not within any application but e.g. just on the WIndows desktop? What will then happen - can it change back to that?
I would appreciate any hints that can help as I am by far no real C# developer ;-)
I have found the solution myself and will explain what worked out for me. I have this code here:
using System.Runtime.InteropServices;
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
// I get in to here when the clipboard has changed and I need to find the application that has changed the clipboard
// Get the active/originating application handle
IntPtr originatingHandle = GetForegroundWindow();
// ------------------
// Do "some stuff" - this is not required for the application switching but it will get the application process name for the active/originating application
// Get the process ID from the active application
uint processId = 0;
GetWindowThreadProcessId(originatingHandle, out processId);
// Get the process name from the process ID
string appProcessName = Process.GetProcessById((int)processId).ProcessName;
// End "some stuff"
// ------------------
// Change focus to my application - this code is inside my main form (Form1)
SetForegroundWindow(this.Handle);
// Do some more stuff - whatever is required for my application to do
// ...
// Change focus back to the originating application again
SetForegroundWindow(originatingHandle);
At least the above code works for me.

ShowWindowAsync not work in all case

ShowWindowAsync won't work in all case. It works when I try it with notepad, task managger, or visual studio, it's just do the job, restore them when they minimized, but when I try it with windows explorer or another external process, it won't work. In all case, the GetProcessesByName find them, just won't come back from minimized.
PInvokeFunctions class
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(HandleRef hWnd, int nCmdShow);
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr WindowHandle);
Method
public static void FocusProcess(string procName)
{
Process[] objProcesses = Process.GetProcessesByName(procName);
if (objProcesses.Length > 0)
{
IntPtr hWnd = IntPtr.Zero;
hWnd = objProcesses[0].MainWindowHandle;
PInvokeFunctions.ShowWindowAsync(new HandleRef(null, hWnd), Constants.PInvokeConstants.SW_RESTORE); // SW_RESTORE = 9
PInvokeFunctions.SetForegroundWindow(hWnd);
}
}
What you want is actually not possible. You are trying to find the 'main window' of a process and that is an non-existing concept. The topic is discussed at length here: There can be more than one (or zero): Converting a process to a window
When you try to explain this to people, you sometimes get stuck in the Why won't you answer my question? cycle.
"I have a thread ID. How do I get the corresponding window?"
You can use the EnumThreadWindows function to get all the windows on the thread.
"Yes, I know about EnumThreadWindows, but how do I get the window that I want?"
Well, you haven't said what you wanted yet.
"I want the window that corresponds to the thread."
But which one? How will you decide among all the windows?
"That's what I'm asking you!"
But you haven't yet described what you want.
"I want the window corresponding to the thread. Why won't you answer my question?"
Note that saying, "I am looking for the top-level unowned window" is a step forward, but it still doesn't uniquely identify a window. There can be multiple top-level unowned windows in a process. For example, Explorer typically has lots of top-level unowned windows. There's the desktop, the taskbar, your open folder windows, and property sheets. If you ask for "the" top-level unowned window of Explorer, which one do you want?
And then Raymond ads the coup de grâce:
Perhaps people are getting the idea that there is a way to uniquely specify "the" window for a process because the System.Diagnostics.Process object has a property called MainWindowHandle. The documentation for that property doesn't do anything to dispel the notion, either. I have no idea how that property decides among multiple top-level unowned windows.
So, as you see, you need to unask the question. What you want is fundamentally incorrect, since there is no 'main' window for a process like Chrome (remember, all modern browsers isolate browsing tabs in their own process). If you followed the discussion above, you'll know what to do.

Sending information from my listbox to different app textboxes

Ok I have an app named Sharknadoo that I created,what this app does it reads the value from a combobox from 1 to whatever number and creates that number of textboxes in the right of it.
Now let us presume I do not have the code for this sharknadoo app just the app installed on my desktop.My question is how can I send my listbox.items from "My amazing app" to the sharknadoo textboxes? Presuming I have the same number of items in my listbox as I have textboxes in my other app.I am sorry but I really want to learn how to do this ,someone told me it is possible to achieve but I have no idea on how to achieve it was thinking about using coordinates or something like that,but from what I understood you can even hang on to the fact that the sharknadoo app is using textboxes without even having access to its source code.Thank you in advance friends :D.
Process[] processes = Process.GetProcessesByName("Sharknadoo.exe");
int i = 0;
foreach (Process p in processes)
{
IntPtr windowHandle = p.MainWindowHandle;
string item = listBox1.Items[i].ToString();
listBox1.Items.Add(item);
i++;
}
I realize the logic of my code is not good but it's all I could come up with.
This answer follows similar logic to your code, but instead simulates keyboard strokes and relies on using TAB to navigate boxes, but it should work in your case.
First add some code that we will use later to grab a link to your Sharknadoo application:
// Get a handle to an application window.
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
// Activate an application window.
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
Now assuming you have not touched anything in the app (Very dangerous assumption, it would be better to launch Sharknadoo from your code before doing any of this), the tab index should be at 0 so we can do something like the following when you click the "Send to Sharknadoo" button:
// Send a your array of names to the Sharknadoo application.
public void sendToSharknadoo(String[] detailsToSend)
{
// Get a handle to the Sharknadoo application. The window class
// and window name can be obtained from Sharknadoo using the
// Spy++ tool.
IntPtr windowHandle = FindWindow("SharknadooFrame","Sharknadoo");
// Verify that Sharknadoo is a running process.
if (windowHandle == IntPtr.Zero)
{
MessageBox.Show("Sharknadoo is not running.");
return;
}
// Make Sharknadoo the foreground application and set the number
// of text boxes for your info
SetForegroundWindow(windowHandle);
// Get to first box
SendKeys.SendWait("{TAB}");
// enter number of boxes
SendKeys.SendWait("{DOWN}");
SendKeys.SendWait((string)detailsToSend.Length);
// Now enter your details into each of those boxes
foreach (String s in detailsToSend)
{
// Get next textbox box
SendKeys.SendWait("{TAB}");
// enter text into box
SendKeys.SendWait(s);
}
}
With any luck that will do the trick. However you will probably need to mess with the order a bit put some checks in place.
Note: if you want a faster more aggressive approach that should execute before the user can interfere then try SendKeys.Send() instead of SendKeys.SendWait()
Source:
https://msdn.microsoft.com/en-us/library/ms171548(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys(v=vs.110).aspx
Additional Stack Overflow questions like this one:
Insert text into the textbox of another application

C# , detect selected text on windows?

I would make a tools like Google toolbar translate function, but it is for desktop.
What i want to do is
highlight the text in any application (word,pdf,live messenger etc) , and translate by google translate api ,return as a tool tips.
I have search msdn about monitoring text, i only found using copy&paste and monitoring clipboard to tick the event.
so, any idea about that?
thanks you.
A starting point would be to get a reference to the current foreground window. The code below will get the currently selected window and the title of that window:
[ DllImport("user32.dll") ]
static extern int GetForegroundWindow();
[ DllImport("user32.dll") ]
static extern int GetWindowText(int hWnd, StringBuilder text, int count);
private void GetActiveWindow()
{
const int nChars = 256;
int handle = 0;
StringBuilder Buff = new StringBuilder(nChars);
handle = GetForegroundWindow();
if ( GetWindowText(handle, Buff, nChars) > 0 )
{
this.captionWindowLabel.Text = Buff.ToString();
this.IDWindowLabel.Text = handle.ToString();
}
}
You could run this code within a timer: i.e give the user 10 seconds to select a window.
I am not sure how you would retrieve selected text within a window, but I will look into it for you.
I think you'll need to start by getting the handle of any window that is activated when your program is active. My guess is you need to look into InteropServices here to do this.
Using Windows API.
It sounds like you need to have your code intercept any window handle of any process, this is where it gets a bit complex as you have to ensure you do have access permissions to access another process.
Speaking of which, I do not think it is a good idea as you could end up crashing another process by poking around under the hood in regards to the winapi calls to trap the text selection event, not too mention the fact that you would have to determine if the process has any text selected. The best direction I can give is this...an article was written on how to spy on a process on CodeProject here, this can be a step in the right direction, bear in mind that the code used was for the .NET 1.0 framework.
Hope this helps and good luck in your coding,
Best regards,
Tom.

Categories

Resources