I am ultimately trying to write something that will check if a specific window exists, and set it as active in the event it is.
I was able to use FindWindow to find a literal windows name.
int hWnd = FindWindow(null, "121226-000377 - company - Oracle RightNow CX Cloud Service");
if (hWnd > 0) //If found
{
SetForegroundWindow(hWnd); //Activate it
}
else
{
MessageBox.Show("Window Not Found!");
}
The number at the front of the title changes and will never be the same twice, therefor I was trying to use Regular Expressions to find if any active window has the name structure as shown above but the numbers can change. I have a regular expresion that works for this, but I don't know how to implement it. I tried:
int hWnd = FindWindow(null, #"^\d+-\d+\s.*?RightNow CX");
if (hWnd > 0) //If found
{
SetForegroundWindow(hWnd); //Activate it
}
else
{
MessageBox.Show("Window Not Found!");
}
But it continually fails. So how do I use the FindWindow/SetForegroundWindow commands while making them use the regular expression to check with?
UPDATE~~~~
I selected a best answer, but here is the actual code for how I got this to work in case anyone is interested.
protected static bool EnumTheWindows(IntPtr hWnd, IntPtr lParam)
{
int size = GetWindowTextLength(hWnd);
if (size++ > 0 && IsWindowVisible(hWnd))
{
StringBuilder sb = new StringBuilder(size);
GetWindowText(hWnd, sb, size);
Match match = Regex.Match(sb.ToString(), #"^\d+-\d+\s.*?RightNow CX",
RegexOptions.IgnoreCase);
// Here we check the Match instance.
if (match.Success)
{
ActivateRNT(sb.ToString());
}
else
{
//this gets triggered for every single failure
}
//do nothing
}
return true;
}
private static void ActivateRNT(string rnt)
{
//Find the window, using the CORRECT Window Title, for example, Notepad
int hWnd = FindWindow(null, rnt);
if (hWnd > 0) //If found
{
SetForegroundWindow(hWnd); //Activate it
}
else
{
MessageBox.Show("Window Not Found!");
}
}
I still need to figure out how to test in the EnumWindows method to throw an alert if the window needed doesn't exist, but I'll worry about that at a later time.
I guess EnumWindows() is what you're looking for, although I'm not 100% sure how you'd use it in C# as you'll need a callback.
Edit: pinvoke.net got some code including an example callback.
Edit 2: The linked [MSDN sample][3] has more details on why/how to do it that way.
If you know the process name of the window searched you could try with something like this:
Process[] processes = Process.GetProcessesByName("notepad");
foreach (Process p in processes)
{
IntPtr pFoundWindow = p.MainWindowHandle;
SetForegroundWindow(pFoundWindow);
}
MSDN on GetProcessesByName
I don't think there is a built-in function/method/API for searching for windows with a regular expression pattern. One way of accomplishing it would be to enumerate the windows such as with this example and then compare the window text in the callback function using the regular expression.
Related
I am trying to restore( or even maximize ) another application and send input to it from my project. I can do it for certain applications like Notepad or Skype, but it doesn't work for other applications such as TeamSpeak.
Any ideas why and how I can solve the problem ?
Here's my code :
private void winact()
{
IntPtr hWnd; //change this to IntPtr
Process[] processRunning = Process.GetProcesses();
string title, name;
foreach (Process pr in processRunning)
{
title = pr.MainWindowTitle.ToLower();
name = pr.ProcessName.ToLower();
if (title.Contains("teamspeak".ToLower()) || name.Contains("teamspeak".ToLower()))
{
hWnd = pr.MainWindowHandle;
ShowWindow(hWnd, 3);
SetForegroundWindow(hWnd); //set to topmost
break;
}
}
}
I use InputSimulator to send the input.
Could you just try this? I think this should work for you.
private void winact()
{
IntPtr hWnd; //change this to IntPtr
Process[] processRunning = Process.GetProcesses();
string title, name;
foreach (Process pr in processRunning)
{
title = pr.MainWindowTitle.ToLower();
name = pr.ProcessName.ToLower();
if (title.Contains("teamspeak".ToLower()) || name.Contains("teamspeak".ToLower()))
{
hWnd = pr.MainWindowHandle;
HwndSource hwndSource = HwndSource.FromHwnd(hWnd);
Window window = hwndSource.RootVisual as Window;
window.Activate();
window.TopMost = true;
ShowWindow(hWnd, 3);
SetForegroundWindow(hWnd); //set to topmost
break;
}
}
}
Apparently the problem was that my application did not run with administrator rights. In order to be able to send input to other apps efficiently, the role of administrator is required.
To do this, I've added an app.manifest to the application, and changed requestedExecutionLevel level from asInvoker to requireAdministrator.
Using InputSimulator worked for other applications, but certain applications, such as games, consider the input to be a simple message and do not process keystrokes as actions. They are however passed to the chat. (this is what I've noticed)
In order to solve this issue, I have written a very script in autoIT which is simply taking the parameter passed to it (only 1) and sends the parameter as a keystroke to the window, currently in foreground. The script is compiled resulting in an executable which I am calling.
I am sure that there is a better way of doing it, but this is the best I've managed to do.
I've a client application which having some tabs in the menu tab as follows.I need to perform some action when the browse tab is selected. how can i get that event in my application. i want to write my own application to perform this action. I tried in this way
int chars = 256;
StringBuilder buff = new StringBuilder(chars);
// Obtain the handle of the active window.
IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, buff, chars) > 0)
{
if (buff.ToString() == mainWindowName)
{
IntPtr WndToFind = FindWindowByCaption(IntPtr.zero, "Browse");
if(WndToFind != IntPtr.Zero)
{
MessageBox.Show("Inside Browse");
}
}
}
I want to dispaly some message when Browse tab is active. Please help me.
If you are using tabcontrol, below is the code to know which tabpage is selected by user.
private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
{
if (tabControl1.SelectedTab == tabControl1.TabPages["tabPage2"])
{
...add your code here
}
}
I am currently attempting to get some text from a child window using SendMessage via C# pinvoke. However, my previous attempts to hardcore the window handle failed as the value changes upon the startup of the application. Is there a way to reliably get the window handle of this child window? Winspector spy shows that the class name of this window is RichEdit20W. My current code is as follows :
IntPtr hWnd= (IntPtr) 0xA0E88; // Hardcode window handle
int txtlen = SendMessage(hWnd, WM_GETTEXTLENGTH, 20, null);
StringBuilder text = new StringBuilder(txtlen);
int RetVal = SendMessage(hWnd, WM_GETTEXT, text.Capacity, text);
If you can get the top-level window (the one with the title bar), you can use FindWindowEx to recurse through the children. This lets you specify the text of the window (use null since you don't know it), and/or the class (which you know).
http://www.pinvoke.net/default.aspx/user32.findwindowex
I ended up using the Managed Windows API to enumerate all descendant windows of the window.
var descendantwindows = childWindows[0].AllDescendantWindows; // Get all descendant windows of CMainWindow
for (int i = 0; i<descendantwindows.Length; i++)
{
if (descendantwindows[i].ClassName == "RichEdit20W")
childHandle = descendantwindows[i].HWnd;
}
You can PInvoke the API [FindWindow][1] in order to have the top level window, or maybe better, if you know the process name, by using:
Process[] processes = Process.GetProcessesByName("yourprocessname");
foreach (Process p in processes)
{
IntPtr pFoundWindow = p.MainWindowHandle;
// Do something with the handle...
//
}
Notice there is more entries because there can be potentially more process instance running at the same time. Then you need some strategy to lookup the top level children to point exactly the window you are looking for.
I have this method:
private delegate void watcherReader(StreamReader sr);
private void watchProc(StreamReader sr) {
while (true) {
string line = sr.ReadLine();
while (line != null) {
if (stop) {
return;
}
//Console.WriteLine(line);
line = stripColors(line);
txtOut.Text += line + "\n";
line = sr.ReadLine();
}
}
}
And it reads the streams from a Process (cmd.exe). When the user closes the cmd.exe window, it causes the CPU usage to jump to 100%. When playing with the debugger I see that it stops on the sr.ReadLine() and never returns. Because this is watching both the StandardErrorStream and the StandardOutputStream it uses 100% on both cores.
Here's some more code of the project if you need it.
[DllImport("User32")]
private static extern int ShowWindow(int hwnd, int nCmdShow); //this will allow me to hide a window
public ConsoleForm(Process p) {
this.p = p;
p.Start();
ShowWindow((int)p.MainWindowHandle, 0); //0 means to hide the window.
this.inStream = p.StandardInput;
this.outStream = p.StandardOutput;
this.errorStream = p.StandardError;
InitializeComponent();
wr = new watcherReader(watchProc);
wr.BeginInvoke(this.outStream, null, null);
wr.BeginInvoke(this.errorStream, null, null);
}
public void start(string[] folders, string serverPath) {
this.inStream.WriteLine("chdir C:\\cygwin\\bin");
this.inStream.WriteLine("bash --login -i");
this.inStream.WriteLine("");
}
//code example from http://geekswithblogs.net/Waynerds/archive/2006/01/29/67506.aspx it is
//to make the textbox autoscroll I don't understand what it does, but it works.
#region autoscroll
[DllImport("User32.dll", CharSet = CharSet.Auto, EntryPoint = "SendMessage")]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
const int WM_VSCROLL = 277;
const int SB_BOTTOM = 7;
private void txtOut_TextChanged(object sender, EventArgs e) {
IntPtr ptrWparam = new IntPtr(SB_BOTTOM);
IntPtr ptrLparam = new IntPtr(0);
SendMessage(((RichTextBox)sender).Handle, WM_VSCROLL, ptrWparam, ptrLparam);
}
#endregion
private void ConsoleForm_FormClosed(object sender, FormClosedEventArgs e) {
this.stop = true;
try {
this.p.Kill();
} catch (InvalidOperationException) {
return;
}
}
Another interesting this is that it doesn't always hide the cmd window like it's supposed to. It hides it the first time, and then the second (or after) it won't hide it. This is when the user can close the cmd.exe window and cause the readline to act funny. It also never reads the last line outputted to cmd unless it exits.
Any suggestions on how to fix this?
I would change:
while(true)
to:
while(!sr.EOS) {
}
It is a better way to check to end the loop.
Whenever you have a while(true) loop in your code you're going to peg your cpu (or at least one core) at 100%, unless you also have a way to break out of the loop. In your case, you do have a return statement, but at no point in the loop do you ever do anything to the stop variable guarding it.
This seems like an interesting issue here. At first glance, it would appear that ReadLine has an issue with the handle being closed from under it while it's trying to read data, and thus would seem to be a bug in the Framework. However, I'm not convinced that easily that it's a bug in the .Net framework...
However, there are a couple low level issues here.
The other answers you have got so far all suggest you modify the while loop. I would do this as well, but I don't think this is the root of your problem. You do not need a sleep in there, because you will get your waitstate from the ReadLine(), unless there is no data to read, and it just returns a failue, THEN you will 'tight-loop'. So, make sure you are checking any and all error states during this loop.
If you do not, I can see issues.
If everything else is working as it should, then if I were you, I would start by trying to identify if you can duplicate it outside of your program with a small demo program. I'm sure there is plenty of error checking in the Framework's Stream handling. However, it looks like you are running some stuff from Cygwin, and that's the output you are reading from the cmd shell.
Try making a simple app that just spits out data to stdout, and stderr, and then make sure the app closes while you are still reading..
Also use the debugger to see what line== after the failure occurs.
Larry
Having while(true) with no sleep in the loop will cause 100% CPU usage.
You need to sleep for some amount of time or break out of the loop at some point so the CPU can do something else.
At the very least you should be doing something along the lines of:
while (sr.Peek() >= 0)
{
Console.WriteLine(sr.ReadLine());
Thread.Sleep(0);
}
I'm creating an alt-tab replacement for Vista but I have some problems listing all active programs.
I'm using EnumWindows to get a list of Windows, but this list is huge. It contains about 400 items when I only have 10 windows open. It seems to be a hwnd for every single control and a lot of other stuff.
So I have to filter this list somehow, but I can't manage to do it exactly as alt-tab does.
This is the code I use to filter the list right now. It works pretty well, but I get some unwanted windows like detached tool-windows in Visual Studio and I also miss windows like iTunes and Warcraft3.
private bool ShouldWindowBeDisplayed(IntPtr window)
{
uint windowStyles = Win32.GetWindowLong(window, GWL.GWL_STYLE);
if (((uint)WindowStyles.WS_VISIBLE & windowStyles) != (uint)WindowStyles.WS_VISIBLE ||
((uint)WindowExStyles.WS_EX_APPWINDOW & windowStyles) != (uint)WindowExStyles.WS_EX_APPWINDOW)
{
return true;
}
return false;
}
Raymond Chen answered this a while back
(https://devblogs.microsoft.com/oldnewthing/20071008-00/?p=24863):
It's actually pretty simple although
hardly anything you'd be able to guess
on your own. Note: The details of this
algorithm are an implementation
detail. It can change at any time, so
don't rely on it. In fact, it already
changed with Flip and Flip3D; I'm just
talking about the Classic Alt+Tab
window here.
For each visible window, walk up its
owner chain until you find the root
owner. Then walk back down the visible
last active popup chain until you find
a visible window. If you're back to
where you're started, then put the
window in the Alt+Tab list. In
pseudo-code:
BOOL IsAltTabWindow(HWND hwnd)
{
// Start at the root owner
HWND hwndWalk = GetAncestor(hwnd, GA_ROOTOWNER);
// See if we are the last active visible popup
HWND hwndTry;
while ((hwndTry = GetLastActivePopup(hwndWalk)) != hwndTry) {
if (IsWindowVisible(hwndTry)) break;
hwndWalk = hwndTry;
}
return hwndWalk == hwnd;
}
Follow the link to Chen's blog entry for more details and some corner conditions.
Thanks Mike B.
The example from Raymonds blog pointed me in the correct direction.
There are however some exceptions that has to be made, Windows Live messenger got alot of hacks for creating shadows under windows etc :#
Here is my complete code, have been using it for one day now and havn't noticed any differences from the real alt tab. There's some underlying code not posted but it's no problem figuring out what it does. :)
private static bool KeepWindowHandleInAltTabList(IntPtr window)
{
if (window == Win32.GetShellWindow()) //Desktop
return false;
//http://stackoverflow.com/questions/210504/enumerate-windows-like-alt-tab-does
//http://blogs.msdn.com/oldnewthing/archive/2007/10/08/5351207.aspx
//1. For each visible window, walk up its owner chain until you find the root owner.
//2. Then walk back down the visible last active popup chain until you find a visible window.
//3. If you're back to where you're started, (look for exceptions) then put the window in the Alt+Tab list.
IntPtr root = Win32.GetAncestor(window, Win32.GaFlags.GA_ROOTOWNER);
if (GetLastVisibleActivePopUpOfWindow(root) == window)
{
WindowInformation wi = new WindowInformation(window);
if (wi.className == "Shell_TrayWnd" || //Windows taskbar
wi.className == "DV2ControlHost" || //Windows startmenu, if open
(wi.className == "Button" && wi.windowText == "Start") || //Windows startmenu-button.
wi.className == "MsgrIMEWindowClass" || //Live messenger's notifybox i think
wi.className == "SysShadow" || //Live messenger's shadow-hack
wi.className.StartsWith("WMP9MediaBarFlyout")) //WMP's "now playing" taskbar-toolbar
return false;
return true;
}
return false;
}
private static IntPtr GetLastVisibleActivePopUpOfWindow(IntPtr window)
{
IntPtr lastPopUp = Win32.GetLastActivePopup(window);
if (Win32.IsWindowVisible(lastPopUp))
return lastPopUp;
else if (lastPopUp == window)
return IntPtr.Zero;
else
return GetLastVisibleActivePopUpOfWindow(lastPopUp);
}
Good work vhanla. My Pascal is a bit rusty, but your solution was a great help. I'm new to this, so please excuse my code and/or way of expressing things. The answer is relatively simple.
To make the list of Alt-Tab Windows, it appears you need three criteria
1) The Window must be visible - using GetWindowVisible
2) The Window must not be a Tool bar Window - using GetWindowInfo
3) The Window must not be cloaked - using DwmGetWindowAttribute
I don't believe that you need to look at class names. I think the WS_EX_APPWINDOW flag often fails the test (e.g. Chrome) - even when used in conjunction with the WS_EX_TOOLWINDOW. Also ... I don't think you need to look at the parent Window if you are enumerating Windows at the top level.
public static bool IsAltTabWindow(IntPtr hWnd)
{
const uint WS_EX_TOOLWINDOW = 0x00000080;
const uint DWMWA_CLOAKED = 14;
// It must be a visible Window
if (!IsWindowVisible(hWnd)) return false;
// It must not be a Tool bar window
WINDOWINFO winInfo = new WINDOWINFO(true);
GetWindowInfo(hWnd, ref winInfo);
if ((winInfo.dwExStyle & WS_EX_TOOLWINDOW) != 0) return false;
// It must not be a cloaked window
uint CloakedVal;
DwmGetWindowAttribute(hWnd, DWMWA_CLOAKED, out CloakedVal, sizeof(uint));
return CloakedVal == 0;
}
This is a function in pascal/delphi, you can easily translate it to C#.
It includes support for Windows 10 applications.
EnumWindows(#ListApps, 0);
function ListApps(LHWindow: HWND; lParam: Pointer): Boolean; stdcall;
var
LHDesktop: HWND;
LHParent: HWND;
LExStyle: DWORD;
AppClassName: array[0..255] of char;
Cloaked: Cardinal;
titlelen: Integer;
title: String;
begin
LHDesktop:=GetDesktopWindow;
GetClassName(LHWindow, AppClassName, 255);
LHParent:=GetWindowLong(LHWindow,GWL_HWNDPARENT);
LExStyle:=GetWindowLong(LHWindow,GWL_EXSTYLE);
if AppClassName = 'ApplicationFrameWindow' then
DwmGetWindowAttribute(LHWindow, DWMWA_CLOAKED, #cloaked, sizeof(Cardinal))
else
cloaked := DWM_NORMAL_APP_NOT_CLOAKED;
if IsWindowVisible(LHWindow)
and (AppClassName <> 'Windows.UI.Core.CoreWindow')
and ( (cloaked = DWM_NOT_CLOAKED) or (cloaked = DWM_NORMAL_APP_NOT_CLOAKED) )
and ( (LHParent=0) or (LHParent=LHDesktop) )
and (Application.Handle<>LHWindow)
and ((LExStyle and WS_EX_TOOLWINDOW = 0) or (LExStyle and WS_EX_APPWINDOW <> 0))
then
begin
titlelen := GetWindowTextLength(LHWindow);
SetLength(title, titlelen);
GetWindowText(LHWindow, PChar(title), titlelen + 1);
{ add each to a list }
But.ListBox1.Items.Add(title);
{ also add each HWND to the list too, later switch using SwitchToThisWindow }
{ ... }
end;
Result := True;
end;