VB – Working with PuTTY

26 11 2009

I tried for a very long time to use VB .NET to simultaneously control multiple PuTTY windows, reading the text from the window, and sending the same text command to all current open windows.

Let me save you a lot of time.

Cant. Be. Done.

There. I said it – i’d have saved myself so much time if only I was told that. I’m not talking about using a StreamWriter here (because I know it’s possible this way), i’m talking having PuTTY windows open completely standalone, and having an application writing to the windows.

Let’s elaborate –

Ok so techincally you can ‘read’ what’s been processed, and that’s via the method of logging the output from the PuTTY terminal into a text file, then using your app to open the text file and read whats happening. You can’t use screen grabbing methods (i.e. user32 GetWindowText API) because PuTTY is a console application. *Note – if anyone wants me to go into detail on how you do this, leave a comment and i’ll do it.

Now, the harder part – writing to multiple windows.

The only viable method I found was to activate a window (by active, I mean set focus – you can activate a window without it having focus, but this is no good), and then send the keys using..


My.Computer.Keyboard.SendKeys("example text to send to window")

Also, the easiest method to activate a window is by doing:


AppActivate(ProcessID)

…however this has it’s flaws, such as failing when activating windows which are minimized.

This works, activate -> send text -> activate -> send text -> activ…. you get the idea.

Now, what if you have a large quantity of windows you wish to send text to? This isn’t a very good way to do it. Most people will tell you to use the SendMessage API or PostMessage API, however because it’s a console window, they don’t work – at best you’ll change the window title because your posting the message to the wrong hWnd.

Take a step back, lets look at Notepad. Notepad (in Win XP at least) has 2 window handles we’re interested in, the actual text area, called ‘Edit’ and the status bar ‘msctls_statusbar32’.

To send text to the ‘Edit’ box, we need to enumerate through the child handles to find the edit box, and use the SendMessage API to send to each of those window handles at the same time.

This quick and dirty example below is in C#, however it’s fundamentally the same code in VB.

Hook our DLL:

[DllImport("user32.dll")] private static extern int SendMessage(IntPtr hWnd, int uMsg, Int32 wParam, string lParam);

Where iPID is my array holding each process ID for the notepad windows:

for (int i = 0; i < iPID.Length; i++)
{
// Set ChildHandle to the window handle for the 'Edit' box
IntPtr ChildHandle = FindWindowEx(Process.GetProcessById(iPID[i]).MainWindowHandle, new IntPtr(0), "Edit", null);
// Call the SendMessage API to send the text to the ChildHandle variable
SendMessage(ChildHandle, 0x000C, 0, textBox1.Text + System.Environment.NewLine);
}

..now, looking back at PuTTY – You’ve got 5 window handles;

– PuTTY
– Layered WS2 Provider
– MSCTFIME UI
– IME
– IME

(that’s not a typo, there’s 2x IME)

Without going into detail, SendMessage to any of those window handles, and the text won’t send. I know what your thinking, send it to the PuTTY handle. Nope – Window Title, it’s a console window!

Now then, I know it *IS* possible to do – somehow, just not via these methods. If you do know a different way to do this, let me know in the comments… please!

Still want to get this to work but having the same trouble as me? Download PuTTY Connection Manager. It’ll save you so much time.