I'm trying to take process names as a string from a listBox in a for loop and search for all windows of those applications. When I add items manually to the listBox, it works fine; but when I use an embedded text file to store and load process names to the listBox, it searches for all items but finds only the last one. For the other ones, Process.GetProcessesByName() throws an exception: Sequence contains no elements.
[DllImport("user32.dll")]
static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
static IEnumerable<IntPtr> EnumerateProcessWindowHandles(int processId)
{
var handles = new List<IntPtr>();
foreach (ProcessThread thread in Process.GetProcessById(processId).Threads)
EnumThreadWindows(thread.Id, (hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero);
return handles;
}
Searching algorithm:
public void searchForApplications()
{
for (int i = 0; i < listBox1.Items.Count; i++)
{
try
{
foreach (var handle in EnumerateProcessWindowHandles
(Process.GetProcessesByName(listBox1.Items[i].ToString()).First().Id))
{
StringBuilder message = new StringBuilder(1000);
SendMessage(handle, WM_GETTEXT, message.Capacity, message);
if (message.ToString().Length > 0)
{
addNewApplication(new Applications(message.ToString(), message.ToString(),
int.Parse(handle.ToString())));
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
Thank you.
If GetProcessesByName doesn't find any processes matching the name you passed in (check your list), then it will return an empty array and First() will throw an InvalidOperationException. You should probably use FirstOrDefault() and check for null before getting the Id:
// ...
var process = Process.GetProcessesByName(listBox1.Items[i].ToString()).FirstOrDefault();
if (process != null)
{
foreach (var handle in EnumerateProcessWindowHandles(process.Id))
{
// ...
}
}
// ...
Related
I am making an Application in C# which reads CAN (Control Area Network) messages and sends them too. I need to do it in 10 milliseconds. The OS i am using is Windows Embedded 7 Pro.
public void ID0008Update10ms(DataTable supportPoints, int a)
{
System.TimeSpan timer10ms = System.TimeSpan.FromMilliseconds(10);
intialiseCAN();
while (a==1)
{
Stopwatch t = Stopwatch.StartNew();
sendCAN();
getCAN();
ID0006NavComStatus(supportPoints);
string state = Convert.ToString(gNavStatus);
while (t.Elapsed < timer10ms)
{ /*nothing*/}
}
}
The issue is the sendCAN() and reciveCAN() dynamically load the .dll file
public int sendCAN(ref can_msg msg, IntPtr pDll)
{
if (pDll == IntPtr.Zero)
{
MessageBox.Show("Loading Failed");
}
IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "CAN_Transmission");
CAN_Transmission sendCAN = (CAN_Transmission)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(CAN_Transmission));
int result = sendCAN( ref msg);
return result;
}
This makes the cycle slow, I am not able to send the Message within 10ms. Can anyone propose a better way. Please remember. I use Windows Embedded.
You should move as much as possible outside the loop. If it doesn't absolutely have to be there, move it. Along the lines of....
private CAN_TransmissionMethod CAN_Transmission;
//Cache the delegate outside the loop.
private bool InitialiseCAN2(IntPtr pDll)
{
if (pDll == IntPtr.Zero)
{
Log("Loading Failed");
return false;
}
IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "CAN_Transmission");
CAN_Transmission = (CAN_TransmissionMethod)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(CAN_Transmission));
return true;
}
public int sendCAN(ref can_msg msg)
{
if (CAN_Transmission == null)
return -1;//Can't send, no delegate, Log, Fail, Explode... make a cup of tea.
int result = CAN_Transmission( ref msg);
return result;
}
public void ID0008Update10ms(DataTable supportPoints, int a)
{
System.TimeSpan timer10ms = System.TimeSpan.FromMilliseconds(10);
intialiseCAN();
initialiseCAN2(pDll)
while (a==1)
{
Stopwatch t = Stopwatch.StartNew();
sendCAN(ref thereIsSupposedToBeAMessageHere);
getCAN(ref probablySupposedToBeSomethingHereToo);
ID0006NavComStatus(supportPoints);
string state = Convert.ToString(gNavStatus);
while (t.Elapsed < timer10ms)
{ /*nothing*/}
}
}
I wrote a simple C# console application to write text to an notepad process. I took the pieces for writing to the process from SO, but I wanted to take this to the next step, make it a little more useful.
delegate void WriteText(Process[] notepads, bool WriteAll, int index);
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
static void Main(params string[] args)
{
if (args.Length != 0)
{
if (args != null)
{
string fullStr = "";
foreach (string str in args)
{
fullStr += str + " ";
}
int index = 0;
WriteToNotepad(fullStr, ref index);
Thread.Sleep(500);
Console.WriteLine(string.Format("Wrote ' {0} ' to notepad[ {1} ] !", fullStr, index));
Console.ReadLine();
}
}
}
static void WriteToNotepad(string text, ref int chosenNotepad)
{
WriteText write = (Process[] notepads, bool WriteAll, int index) =>
{
if (!WriteAll)
{
if (notepads.Length == 0) return;
if (notepads[index] != null)
{
IntPtr child = FindWindowEx(notepads[index].MainWindowHandle, new IntPtr(0), "Edit", null);
SendMessage(child, 0x000c, 0, text);
}
}
else
{
for (int notepadIndex = 0; notepadIndex < notepads.Length; notepadIndex++)
{
IntPtr child = FindWindowEx(notepads[notepadIndex].MainWindowHandle, new IntPtr(0), "Edit", null);
SendMessage(child, 0x000c, 0, text);
}
}
};
Process[] notes = Process.GetProcessesByName("notepad");
if (notes.Length < 1)
{
for (int i = 0; i < notes.Length; i++)
{
Console.WriteLine(string.Format("{0}: {1}", i, notes[i].Id));
}
Console.WriteLine("\nPick a number to select which notepad to edit.\nEnter 'ALL' to modify memory of every notepad process active: ");
string answer = Console.ReadLine();
if (answer == "ALL")
{
write(notes, true, 0);
}
else
{
try
{
int ans = Convert.ToInt32(answer);
chosenNotepad = ans;
write(notes, false, Convert.ToInt32(ans));
}
catch (Exception ex)
{
Console.WriteLine("\n\n\n" + ex.Message);
}
}
}
}
PROBLEM: If you spectate the code, you'll see that I gather the text to write from static void Main(params string[] args), so I have arguments like this.
It will write the text to the notepad correctly! :) Except it's not the way it should work...
If you take a look at the function WriteToNotepad() it will save all the processes with name notepad to the variable names notes.
I have 3 notepads wide open, which means notes length should be 3, and if it is, it will print all the notepad indexes & names, and the user can select which one to modify, if user inputs 'ALL' the program will modify every notepad process there is. The problem is, it straight modifies first notepad process there is.
I simply can't find the problem here, any help would be appreciated! :)
Your if (notes.Length < 1) makes the method return without doing anything, leaving ref int chosenNotepad to its default value, 0, then printing a lie.
Change it to if (notes.Any()).
You can find this out by placing breakpoints and stepping through your code.
I am trying to traverse the controls of a WinForms form (Windows CE) and retrieve/match their textual contents and names (that is, the Name property assigned to the WinForms Control object).
I do this from within a different process, thus WinAPI.
For traversing and for retrieving the text I wrote the following code. TextPresent uses DescendantControls for the traversing and Text to retrieve the text. I am fairly confident that the traversing code works correctly already - if not, please let me know. However, all of the controls that are returned have an empty text.
The code can be used as follows:
var foregroundWindow = new WinCEControl(GetForegroundWindow()); // working properly
Assert.That("The Window Title", foregroundWindow.Text); // working properly
Assert.That(manorMenu.TextPresent("Text to find")); // not working although /
// "Text to find" is a value within the control tree of the window.
As for the name, I do not even know how to retrieve it at all. So far my searching was unsuccessful.
public class WinCEControl
{
[DllImport("coredll.dll", SetLastError = true)]
private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
[DllImport("coredll.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
private static extern bool SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
private const int WM_GETTEXT = 0x000D;
private const uint GW_CHILD = 5;
private const uint GW_HWNDLAST = 1;
private const uint GW_HWNDNEXT = 2;
public WinCEControl(IntPtr handle)
{
this.Handle = handle;
}
public IntPtr Handle { get; private set; }
public string Text
{
get
{
var stringBuilder = new StringBuilder(256);
SendMessage(this.Handle, WM_GETTEXT, stringBuilder.Capacity, stringBuilder);
return stringBuilder.ToString();
}
}
public IEnumerable<WinCEControl> Children()
{
var childHandle = GetWindow(Handle, GW_CHILD);
if (childHandle == IntPtr.Zero)
{
yield break;
}
var lastHandle = GetWindow(childHandle, GW_HWNDLAST);
while (childHandle != lastHandle)
{
yield return new WinCEWindow(childHandle);
childHandle = GetWindow(childHandle, GW_HWNDNEXT);
}
yield return new WinCEWindow(lastHandle);
}
public IEnumerable<WinCEControl> DescendantControls()
{
var nodes = new Queue<WinCEControl>(new[] { this });
while (nodes.Any())
{
var node = nodes.Dequeue();
if (node != this)
{
yield return node;
}
foreach (var n in node.Children()) nodes.Enqueue(n);
}
}
public bool TextPresent(string text)
{
foreach (var descendantControl in DescendantControls())
{
if (descendantControl.Text == text)
{
return true;
}
}
return false;
}
}
My goal is to be able to perform UI tests against a running application on the CE device. If there is a solid C# library to achieve the same which works on Windows CE I am very hear.
Update: As mentioned in my comment I have failed to find a library or framework for automating foreign WinForms processes on the Win CE. I tried the "simple-wince-gui-automation" and it fails to retrieve the texts, too.
I have the Internet Explorer Handle and i have the tab Handle that i want to select.
How can i select this tab?
I know how to select a tab by Index (Using IEAccessible), but i can't get the tabIndex from the handle. The Spy++ doesn't sort them in order.
There's a way hack way to do it. Not supported, and dependent upon the version of IE as well as the language of the OS.
In an IE instance, the control with the name "Tab Row" is the
thing that holds all the various tabs. Given an IAccessible
corresponding to that thing, it's easy to enumerate the children,
and get the tabs. An automation app can inspect the URL on each
tab, and then call IAccessible.accDoDefaultAction(0), to activate
a tab by URL. That's the basic approach.
But I couldn't figure how to directly get the "Tab Row" control
of an IE instance, from a SHDocVw.WebBrowser COM object, which is
what an app gets out of SHDocVw.ShellWindowsClass. I tried it a
million ways, and finally the simplest way I could find to get it
to work is this: get the WebBrowser COM object, get the HWND from that
object (which is really the HWND numerous levels "up"), then traverse down the OS HWND hierarchy to find the HWND
with the name "DirectUIHWND". From there, walk down the IAccessible
tree, to find the "Tab Row", then select the tab and invoke the
method.
It sounds ugly to describe, and it hurt to code it this way. I
could not figure out a way to do the traversal only in HWNDs or
only in IAccessible. I have no idea why I needed to do both.
In Code
First, get the HWND of the WebBrowser:
SHDocVw.WebBrowser ietab = ... ?
string urlOfTabToActivate = ietab.LocationURL;
IntPtr hwnd = (IntPtr) ietab.HWND;
Then get the HWND of the DirectUI thing in the IE instance that controls that WebBrowser:
var directUi = GetDirectUIHWND(hwnd);
This is the hacky part. The GetDirectUIHWND method is defined like this:
private static IntPtr GetDirectUIHWND(IntPtr ieFrame)
{
// try IE 9 first:
IntPtr intptr = FindWindowEx(ieFrame, IntPtr.Zero, "WorkerW", null);
if (intptr == IntPtr.Zero)
{
// IE8 and IE7
intptr = FindWindowEx(ieFrame, IntPtr.Zero, "CommandBarClass", null);
}
intptr = FindWindowEx(intptr, IntPtr.Zero, "ReBarWindow32", null);
intptr = FindWindowEx(intptr, IntPtr.Zero, "TabBandClass", null);
intptr = FindWindowEx(intptr, IntPtr.Zero, "DirectUIHWND", null);
return intptr;
}
...where FindWindowEx is a dllimport:
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent,
IntPtr hwndChildAfter,
string lpszClass,
string lpszWindow);
Then, get the IAccessible for that DirectUI thing:
var iacc = AccessibleObjectFromWindow(directUi);
...where, of course, AccessibleObjectFromWindow is a DllImport, with some magic around it:
[DllImport("oleacc.dll")]
internal static extern int AccessibleObjectFromWindow
(IntPtr hwnd, uint id, ref Guid iid,
[In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject);
private static IAccessible AccessibleObjectFromWindow(IntPtr hwnd)
{
Guid guid = new Guid("{618736e0-3c3d-11cf-810c-00aa00389b71}"); // IAccessible
object obj = null;
uint id = 0U;
int num = AccessibleObjectFromWindow(hwnd, id, ref guid, ref obj);
var acc = obj as IAccessible;
return acc;
}
Ok, then, you walk down the IAccessible tree, to find the "Tab Row". In IE this is the thing that displays all the tabs for the various browser windows.
var tabRow = FindAccessibleDescendant(iacc, "Tab Row");
...where that method is:
private static IAccessible FindAccessibleDescendant(IAccessible parent, String strName)
{
int c = parent.accChildCount;
if (c == 0)
return null;
var children = AccChildren(parent);
foreach (var child in children)
{
if (child == null) continue;
if (strName.Equals(child.get_accName(0)))
return child;
var x = FindAccessibleDescendant(child, strName);
if (x!=null) return x;
}
return null;
}
}
And...
private static List<IAccessible> AccChildren(IAccessible accessible)
{
object[] res = GetAccessibleChildren(accessible);
var list = new List<IAccessible>();
if (res == null) return list;
foreach (object obj in res)
{
IAccessible acc = obj as IAccessible;
if (acc != null) list.Add(acc);
}
return list;
}
Then, get the IAccessible within THAT, and click it:
var tabs = AccChildren(tabRow);
int tc = tabs.Count;
int k = 0;
// walk through the tabs and tick the chosen one
foreach (var candidateTab in tabs)
{
k++;
// the last tab is "New Tab", which we don't want
if (k == tc) continue;
// the URL on *this* tab
string localUrl = UrlForTab(candidateTab);
// same? if so, tick it. This selects the given tab among all
// the others, if any.
if (urlOfTabToActivate != null
&& localUrl.Equals(urlOfTabToActivate))
{
candidateTab.accDoDefaultAction(0);
return;
}
}
....where UrlForTab is....
private static string UrlForTab(IAccessible tab)
{
try
{
var desc = tab.get_accDescription(0);
if (desc != null)
{
if (desc.Contains("\n"))
{
string url = desc.Substring(desc.IndexOf("\n")).Trim();
return url;
}
else
{
return desc;
}
}
}
catch { }
return "??";
}
Whew. I could not find a cleaner, simpler way to do this.
I'm making an application where I interact with each running application. Right now, I need a way of getting the window's z-order. For instance, if Firefox and notepad are running, I need to know which one is in front.
Any ideas? Besides doing this for each application's main window I also need to do it for its child and sister windows (windows belonging to the same process).
You can use the GetTopWindow function to search all child windows of a parent window and return a handle to the child window that is highest in z-order. The GetNextWindow function retrieves a handle to the next or previous window in z-order.
GetTopWindow: http://msdn.microsoft.com/en-us/library/ms633514(VS.85).aspx
GetNextWindow: http://msdn.microsoft.com/en-us/library/ms633509(VS.85).aspx
Nice and terse:
int GetZOrder(IntPtr hWnd)
{
var z = 0;
for (var h = hWnd; h != IntPtr.Zero; h = GetWindow(h, GW.HWNDPREV)) z++;
return z;
}
If you need more reliability:
/// <summary>
/// Gets the z-order for one or more windows atomically with respect to each other. In Windows, smaller z-order is higher. If the window is not top level, the z order is returned as -1.
/// </summary>
int[] GetZOrder(params IntPtr[] hWnds)
{
var z = new int[hWnds.Length];
for (var i = 0; i < hWnds.Length; i++) z[i] = -1;
var index = 0;
var numRemaining = hWnds.Length;
EnumWindows((wnd, param) =>
{
var searchIndex = Array.IndexOf(hWnds, wnd);
if (searchIndex != -1)
{
z[searchIndex] = index;
numRemaining--;
if (numRemaining == 0) return false;
}
index++;
return true;
}, IntPtr.Zero);
return z;
}
(According to the Remarks section on GetWindow, EnumChildWindows is safer than calling GetWindow in a loop because your GetWindow loop is not atomic to outside changes. According to the Parameters section for EnumChildWindows, calling with a null parent is equivalent to EnumWindows.)
Then instead of a separate call to EnumWindows for each window, which would also be not be atomic and safe from concurrent changes, you send each window you want to compare in a params array so their z-orders can all be retrieved at the same time.
Here is my C# solution:
The function returns the zIndex among the siblings of the given HWND, starting at 0 for the lowest zOrder.
using System;
using System.Runtime.InteropServices;
namespace Win32
{
public static class HwndHelper
{
[DllImport("user32.dll")]
private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
public static bool GetWindowZOrder(IntPtr hwnd, out int zOrder)
{
const uint GW_HWNDPREV = 3;
const uint GW_HWNDLAST = 1;
var lowestHwnd = GetWindow(hwnd, GW_HWNDLAST);
var z = 0;
var hwndTmp = lowestHwnd;
while (hwndTmp != IntPtr.Zero)
{
if (hwnd == hwndTmp)
{
zOrder = z;
return true;
}
hwndTmp = GetWindow(hwndTmp, GW_HWNDPREV);
z++;
}
zOrder = int.MinValue;
return false;
}
}
}
// Find z-order for window.
Process[] procs = Process.GetProcessesByName("notepad");
Process top = null;
int topz = int.MaxValue;
foreach (Process p in procs)
{
IntPtr handle = p.MainWindowHandle;
int z = 0;
do
{
z++;
handle = GetWindow(handle, 3);
} while(handle != IntPtr.Zero);
if (z < topz)
{
top = p;
topz = z;
}
}
if(top != null)
Debug.WriteLine(top.MainWindowTitle);
For get Z-Order implement this function (by using GetWindow Windows API function)
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
static int GetWindowZOrder(IntPtr hWnd)
{
var zOrder = -1;
while ((hWnd = GetWindow(hWnd, 2 /* GW_HWNDNEXT */)) != IntPtr.Zero) zOrder++;
return zOrder;
}
The return value is a zero-based index. Returning -1 indicates an invalid hWnd.
The approach is to go up through the windows to the top. The total number of climbs is the value of the Z-Order.