Figure 4 Adding a Window Node

string name = String.IsNullOrEmpty(cproxy.GetComponentName()) ?
"<noname>" : cproxy.GetComponentName();
TreeNode node = procnode.Nodes.Add(cproxy.Handle.ToString(),
name + " [" + cproxy.GetClassName() + "]");
node.Tag = cproxy;
...
if (treeWindow.Nodes.Count == 0)
{
treeWindow.Nodes.Add("No managed processes running.");
treeWindow.Nodes.Add("Select View->Refresh.");
}
this.treeWindow.EndUpdate();


Figure 5 Listing Windows by Process

using System;
using System.Text;
using System.Diagnostics;
using System.Windows.Forms;
using System.Collections.Generic;
using Microsoft.ManagedSpy;

class Program
{
static void Main(string[] args)
{
Dictionary<int, int> topWindowCounts =
new Dictionary<int, int>();

foreach (ControlProxy proxy in ControlProxy.TopLevelWindows)
{
if (!topWindowCounts.ContainsKey(proxy.OwningProcess.Id))
{
topWindowCounts.Add(proxy.OwningProcess.Id, 0);
}
topWindowCounts[proxy.OwningProcess.Id]++;
}

foreach (int pid in topWindowCounts.Keys)
{
Process p = Process.GetProcessById(pid);
Console.WriteLine("Process: " + p.ProcessName +
" has " + topWindowCount[pid].ToString() +
" top level windows");
}
}
}


Figure 6 ControlProxy Properties

Property
Description
IntPtr Handle Returns the underlying HWND of the Control. This would be equivalent to accessing the Handle property on the Control.
array<ControlProxy^>^ Children Returns an array of ControlProxy classes that represent the child windows of the Control.
Process^ OwningProcess Returns a Process object that the Control is running in.
bool IsManaged If the window that the ControlProxy is examining represents a managed System.Windows.Forms.Control, then the value returned is true. Otherwise it is false. Most ControlProxy methods only work if the window is a System.Windows.Forms.Control.
Type^ ComponentType Returns the Type of the Control. Note that this Type is originally from an Assembly loaded in the process being spied. The Assembly and Type are reloaded in the spying process when the ControlProxy is first created.
ControlProxy^ Parent Returns the parent window as a ControlProxy. Use Parent and Children to navigate the window chain of the process.

 


Figure 7 Modifying Other Instances of an Application

private void button1_Click(object sender, EventArgs e) 
{
foreach (Process p in
Process.GetProcessesByName("WindowsApplication1"))
{
if (p.Id != Process.GetCurrentProcess().Id)
{
ControlProxy proxy =
ControlProxy.FromHandle(p.MainWindowHandle);
string val = (string)proxy.GetValue("MyStringValue");
MessageBox.Show("Changing " + val + " to " + MyStringValue);
proxy.SetValue("MyStringValue", (object)MyStringValue);
}
}
}

public string MyStringValue
{
get { return this.textBox1.Text; }
set { this.textBox1.Text = value; }
}


Figure 11 Testing Code

private void button1_Click(object sender, EventArgs e) 
{
Process[] procs = Process.GetProcessesByName("Multiply");
if (procs.Length != 1) return;
ControlProxy proxy =
ControlProxy.FromHandle(procs[0].MainWindowHandle);
if (proxy == null) return;

//find the controls we are interested in...
if (cbutton1 == null)
{
foreach (ControlProxy child in proxy.Children)
{
if (child.GetComponentName() == "textBox1") {
textBox1 = child;
}
else if (child.GetComponentName() == "textBox2") {
textBox2 = child;
}
else if (child.GetComponentName() == "textBox3") {
textBox3 = child;
}
else if (child.GetComponentName() == "button1") {
cbutton1 = child;
}
}

//sync testchanged on textbox3 so we can tell if it has changed.
textBox1.SetValue("Text", "5");
textBox2.SetValue("Text", "7");
textBox3.SetValue("Text", "");
textBox3.EventFired +=
new ControlProxyEventHandler(textBox3_EventFired);
textBox3.SubscribeEvent("TextChanged");
}
else textBox3.SetValue("Text", "");

//now click on the button to start the test...
if (cbutton1 != null)
{
cbutton1.SendMessage(WM_LBUTTONDOWN, IntPtr.Zero, IntPtr.Zero);
cbutton1.SendMessage(WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
Application.DoEvents();
}

if (result == 35) MessageBox.Show("Passed!");
else MessageBox.Show("Fail!");
}

void textBox3_EventFired(object sender, ProxyEventArgs ed)
{
int val;
if (int.TryParse((string)textBox3.GetValue("Text"), out val) )
{
result = val;
}
}