This tutorial is written in C# and will address the following:
Finding window handles using the .NET System.Diagnostics.Process class.
Accessing a separate and completely independent application via the Win32 API using the handles we gathered. ( in this case we will be using !Yahoo Messenger)
Gain access to a child window of the independent application and manipulate it (send a string or press a button) by passing a byte array.( in this case the child window will be the send message text box and the send message send button.)
//We'll need to import the System.Diagnostics library so we can access the Process class.
using System.Diagnostics;
//These methods are imported in from the user32.dll. I recommend putting them in a separate class under the same
//namespace in order to avoid cluttering up your code.
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, IntPtr lParam);
[DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);
[DllImport("user32.dll")] public static extern uint SendMessage(IntPtr hWnd, uint MSG, uint zero, byte[] text);
[DllImport("user32.dll")] public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
/// Win32 SDK constants
/// </summary>
public const uint WM_SETTEXT = 0x000C;
public const uint WM_GETTEXT = 0x000D;
public const uint EM_SETSEL = 0x000000B1;
public const uint WM_GETTEXTLENGTH = 0x000E;
public const uint SMTO_ABORTIFHUNG = 0x0002;
public const int BM_CLICK = 0x00F5;
//We will call this method whenever we want to send a message to Yahoo Messenger from our application
public void PostToMessengerChat()
{
//you can find the name of the process that owns the windows you are trying to access by
//accessing the task-manager. Then load a process array with the following line.
Process[] processes = Process.GetProcessesByName("YahooMessenger");
//Declare a null window handle called hwnd.
IntPtr hwnd = IntPtr.Zero;
//Declare a null window handle called mainHand
IntPtr mainHand = IntPtr.Zero;
//Iterate through the process array until we find the window we want
foreach (Process p in processes)
{
//get WindowTitle and check it's the one you want
String checkString = p.MainWindowTitle;
//all !Yahoo chat rooms end with this patternString
String patternString = "-- Chat";
if (checkString.Contains(patternString))
{
//the pattern matches ! This is the window we want. Get it's handle.
mainHand = p.MainWindowHandle;
}
}
//find the class name of the child window using spy++ (YIMInputWindow)
//this function returns the handle of the window that matches the class name string.
IntPtr childWindow = Win32API.FindWindowEx(mainHand, IntPtr.Zero, "YIMInputWindow", IntPtr.Zero);
//WM_GETTEXTLENGTH - get the length of the users text in the text input window text if there is any
int textLength = Win32API.SendMessage(childWindow, Win32API.WM_GETTEXTLENGTH, 0, IntPtr.Zero);
//create a StringBuilder to hold users text input StringBuilders are {Zero Based}
StringBuilder writingtext = new StringBuilder(textLength + 1);
//WM_GETTEXT - sendmessage with a stringbuilder arg and length arg returns a stringbuilder that contains the
//current text in the YIMInputWindow. This is, so that when we send our message it doesnt mess up the current
//users text if they happen to be typing. This part is a bit weird because the method loads the stringbuilder
//yet we never assign it. By passing the stringbuilder to this method our result is a stringbuilder containing
//the users current text.
Win32API.SendMessage(childWindow, Win32API.WM_GETTEXT, textLength + 1, writingtext);
//create a byte array of the string we will be sending, in this case it is the currently playing MP3.
byte[] encryptedText_byte = System.Text.Encoding.ASCII.GetBytes((": hears: " +
playList.Items[currentSongNumber]).ToCharArray());
//WM_SETTEXT - send our song string byteArray
Win32API.SendMessage(childWindow, Win32API.WM_SETTEXT, 0, encryptedText_byte);
//find the send buttons window handle
IntPtr buttonWindow = Win32API.FindWindowEx(mainHand, IntPtr.Zero, "Button", "&Send");
//BM_CLICK - click the button to send the song message to the chat
Win32API.SendMessage(buttonWindow, Win32API.BM_CLICK, 0, encryptedText_byte);
//WM_SETTEXT - put the users current text back to it's original place
encryptedText_byte = System.Text.Encoding.ASCII.GetBytes((writingtext.ToString()).ToCharArray());
Win32API.SendMessage(childWindow, Win32API.WM_SETTEXT, 0, encryptedText_byte);
//WM_SETSEL - put the cursor at the end of the users text so they can keep typing
Win32API.SendMessage(childWindow, Win32API.EM_SETSEL, writingtext.Length, writingtext.Length);
}
Your feedback is welcome.