kamyers1 Posted September 7, 2009 Share Posted September 7, 2009 (edited) Using AutoitX (not Autoit!), I would like to send characters to an inactive window in order to force that window to execute one of its menu options. The menu is non-standard, so WinMenuSelectItem doesn't work. Send works, but only if the window is active, and that isn't adequate for my needs. ControlSend can send characters to various controls on the window, but I can't find any way to get it to activate the menu items. The window in question is the main form (ThunderRT6MDIForm) of a VB6 based application. I thought that I had another solution, but it doesn't work. Here is what I tried: 1. I get the window handle using WinGetHandle from AutoitX. That part works ok, and I have verified that the correct handle value is returned by using other tools. 2. I wrote a little VB utility to send characters to a specific window handle by using the SendMessageA Windows API function. When I run the VB utility, still no luck! My VB code is pretty simple, and I output stuff from each step in my code so that I can verify they are working as anticipated. Everything seems perfect until I make the actual API call. But then there is no response from the application, and I get back a result value of 8975925931411505152 from the API call. I assume that is some kind of error code, but have no idea what it means. My VB code is posted below. Can anyone here help out? Thanks, Kevin M. With a new Notepad window open, if I run the code listed below from a console window, here is what I get: C:\myApp\bin>test.vbs handle=1512254 SendCharsByHandle 1512254 ☼ nArgs=2 Handle=1512254 nArg=2, MyStr=☼, nChars=1 wparam=15 handle=1512254, message=258, wparam=15, lparam=0 result=8975925931411505152 Here is test.vbs: set AutoIt=WScript.CreateObject("AutoItX3.Control") set Shell=CreateObject("WScript.Shell") AppWindowName="Untitled - Notepad" AutoIt.WinActivate AppWindowName WScript.Sleep(1000) handle=AutoIt.WinGetHandle(AppWindowName) WScript.Echo "handle=" & CLng("&h" & handle) rem char(15) is CTRL-O, should execute Notepad's File->Open menu item. command="SendCharsByHandle " & CLng("&h" & handle) & " " & chr(15) WScript.Echo command execCmd(command) WScript.Quit(0) function execCmd(command) set oCommand=shell.exec(command) do until oCommand.Status=1 and oCommand.StdOut.AtEndOfStream if oCommand.StdOut.AtEndOfStream then WScript.Sleep 100 else WScript.Echo oCommand.StdOut.ReadLine end if loop 'until oCommand.Status=1 and oCommand.StdOut.AtEndOfStream execCmd=oCommand.ExitCode end function 'execCmd Here is SendCharsByHandle.VB: expandcollapse popupImports System Module SendKeysByHandle Public Declare Function SendMessage Lib "user32" _ Alias "SendMessageA" (ByVal hwnd As Long, _ ByVal wMsg As Long, _ ByVal wparam As Long, _ ByVal lparam As Long) As Long Sub Main() Dim MyStr As String Dim nArgs, nArg, nChars, nChar As Short Dim result As Long Dim handle As Long Dim message As Long Dim wparam As Long Dim lparam As Long Const WM_CHAR = &H102 message = WM_CHAR 'WM_CHAR message constant lparam = 0 nArgs = UBound(Environment.GetCommandLineArgs()) Console.WriteLine("nArgs=" & nArgs) If nArgs > 0 Then If IsNumeric(Environment.GetCommandLineArgs(1)) Then handle = CLng(Environment.GetCommandLineArgs(1)) Console.WriteLine("Handle=" & handle) For nArg = 2 To nArgs MyStr = Environment.GetCommandLineArgs(nArg) nChars = Len(MyStr) Console.WriteLine("nArg=" & nArg & ", MyStr=" & MyStr & ", nChars=" & nChars) For nChar = 1 To Len(MyStr) wparam = CLng(Asc(Mid(MyStr, nChar, 1))) Console.WriteLine("wparam=" & wparam) Console.WriteLine("handle=" & handle & ", message=" & message & ", wparam=" & wparam & ", lparam=" & lparam) result = SendMessage(handle, message, wparam, lparam) Console.WriteLine("result=" & result) Next Next Else Console.WriteLine("Invalid arguments. Correct syntax is: SendKeysByHandle <handle> <string>") End If Else Console.WriteLine("Invalid arguments. Correct syntax is: SendKeysByHandle <handle> <string>") End If End Sub End Module Edited September 7, 2009 by kamyers1 Link to comment Share on other sites More sharing options...
LarryDalooza Posted September 7, 2009 Share Posted September 7, 2009 You will need to concede after some amount of trying that some apps are coded to ignore messages if the window is not active. Lar. AutoIt has helped make me wealthy Link to comment Share on other sites More sharing options...
kamyers1 Posted September 7, 2009 Author Share Posted September 7, 2009 But I tried several different apps including Notepad and Calculator, and none of them responded! I suspect there is probably something wrong with my VB code, maybe something do with the handle. Perhaps the handle value needs to get converted from a Long to a "true" handle, but I don't know how to do that if so. Was hoping that some of the gurus on this site might know. I have also posted to Microsoft's VB forum with no luck so far. Link to comment Share on other sites More sharing options...
kamyers1 Posted September 7, 2009 Author Share Posted September 7, 2009 (edited) I made some corrections to my VB code that eliminates the non-zero result value from calling SendMessage, but I'm still not having any luck getting apps to respond to the sent text in any way, not even if they are active. Not even simple apps like Notepad and Calculator. Latest VB code below... expandcollapse popupImports System.Runtime.InteropServices Imports System Module SendCharsByHandle <DllImport("user32", EntryPoint:="FindWindow")> _ Private Function FindWindow( _ ByVal lpClassName As String, _ ByVal lpWindowName As String) As Int32 End Function <DllImport("user32", EntryPoint:="GetWindow")> _ Private Function GetWindow( _ ByVal hwnd As Int32, _ ByVal wCmd As Int32) As Int32 End Function <DllImport("user32", EntryPoint:="GetWindowText")> _ Private Function GetWindowText( _ ByVal hwnd As Int32, _ ByVal lpString As System.Text.StringBuilder, _ ByVal cch As Int32) As Int32 End Function <DllImport("user32", EntryPoint:="SendMessageA")> _ Private Function SendMessage( _ ByVal hwnd As UInteger, _ ByVal wMsg As UInteger, _ ByVal wparam As UInteger, _ ByVal lparam As UInteger) As UInteger End Function Sub Main() Dim MyStr As String Dim nArgs, nArg, nChars, nChar As Short Dim result As UInteger Dim handle, handle2 As UInteger Dim message As UInteger Dim wparam As UInteger Dim lparam As UInteger Dim gotHandle As Boolean Const WM_CHAR As UInteger = &H102 message = WM_CHAR 'WM_CHAR message constant lparam = 0 nArgs = UBound(Environment.GetCommandLineArgs()) Console.WriteLine("nArgs=" & nArgs) If nArgs > 0 Then If IsNumeric(Environment.GetCommandLineArgs(1)) Then handle = CLng(Environment.GetCommandLineArgs(1)) gotHandle = GetHandleFromPartialCaption(handle2, "Untitled - Notepad") Console.WriteLine("Handle=" & handle & ", handle2=" & handle2) If gotHandle Then handle = handle2 For nArg = 2 To nArgs MyStr = Environment.GetCommandLineArgs(nArg) nChars = Len(MyStr) Console.WriteLine("nArg=" & nArg & ", MyStr=" & MyStr & ", nChars=" & nChars) For nChar = 1 To Len(MyStr) wparam = CLng(Asc(Mid(MyStr, nChar, 1))) Console.WriteLine("wparam=" & wparam) Console.WriteLine("handle=" & handle & ", message=" & message & ", wparam=" & wparam & ", lparam=" & lparam) result = SendMessage(handle, message, wparam, lparam) Console.WriteLine("result=" & result) Next Next Else Console.WriteLine("Invalid arguments. Correct syntax is: SendKeysByHandle <handle> <string>") End If Else Console.WriteLine("Invalid arguments. Correct syntax is: SendKeysByHandle <handle> <string>") End If End Sub Private Function GetHandleFromPartialCaption(ByRef lWnd As Int32, ByVal sCaption As String) As Boolean Dim Caption As New System.Text.StringBuilder(256) Dim lhWndP As Int32 Const GW_HWNDNEXT As Int32 = 2 GetHandleFromPartialCaption = False lhWndP = FindWindow(vbNullString, vbNullString) Do While lhWndP <> 0 GetWindowText(lhWndP, Caption, Caption.Capacity) If InStr(1, Caption.ToString(), sCaption) > 0 Then GetHandleFromPartialCaption = True lWnd = lhWndP Exit Do End If lhWndP = GetWindow(lhWndP, GW_HWNDNEXT) Loop End Function End Module Edited September 7, 2009 by kamyers1 Link to comment Share on other sites More sharing options...
kamyers1 Posted September 7, 2009 Author Share Posted September 7, 2009 Sorry, just posted re-formatted code. I wasn't familiar with this forum's methods for handling code. Link to comment Share on other sites More sharing options...
kamyers1 Posted September 8, 2009 Author Share Posted September 8, 2009 Ok, been working on this all day and all night, still no luck. I've got to be missing something simple. Currently I am able to send text to the Edit control in a Notepad application using VB, but I can't seem to figure out the right mechanism for sending accelerator keys, e.g. Ctrl-O for File->Open, even if the Notepad window is already active. I know that can be done, because the AutoItX Send method can do it, so I must be doing something wrong. Once again, my purpose in doing this is that I need to send accelerator keys to an *inactive* window, which AutoItX can't currently seem to do (I've already tried). So I am writing VB code to try to work around this limitation. But if I can't manage to send the appropriate messages to a simple application like Notepad when it is already active, then I don't stand a prayer of accomplishing my real goal with other apps that aren't currently active. I know this isn't a VB forum, but folks on here are experienced with writing code to control other apps, so I am hoping that someone can spot what I am missing. Current version of code that I am trying to run is listed below. By the way, Notepad "beeps" when this code runs, and Winspector Spy seems to show that it is receiving the appropriate messages, so surely I must be fairly close... Oh by the way, the WM_COMMAND version that is commented out below *does* work, but I don't want to use that for general purpose work, because it requires knowing menu id values that are application specific and a bit of a pain to come up with. Much nicer if I could just manage to send the stupid accelerator keys! Thanks, KM expandcollapse popupModule crazy Private Declare Auto Function FindWindow Lib "user32" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr Private Declare Auto Function PostMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Boolean Private Declare Auto Function GetWindow Lib "user32" (ByVal hWnd As IntPtr, ByVal uCmd As Integer) As IntPtr Private Const WM_KEYDOWN = &H100 Private Const WM_CHAR = &H102 Private Const WM_KEYUP = &H101 Private Const WM_COMMAND = &H111 Private Const GW_CHILD = 5 Sub Main() Dim whnd As IntPtr = FindWindow(vbNullString, "untitled - notepad") Dim Cwhnd As IntPtr = GetWindow(whnd, GW_CHILD) 'PostMessage(whnd, WM_KEYDOWN, &H11, &H11D0001) 'PostMessage(whnd, WM_KEYDOWN, &H4F, &H440001) 'PostMessage(whnd, WM_CHAR, &HF, &H440001) 'PostMessage(whnd, WM_KEYUP, &H4F, &HC0440001) 'PostMessage(whnd, WM_KEYUP, &H11, &HC11D0001) 'PostMessage(whnd, WM_COMMAND, &H10002, &H0) PostMessage(Cwhnd, WM_KEYDOWN, &H11, &H1D0001) PostMessage(Cwhnd, WM_KEYDOWN, &H4F, &H180001) PostMessage(Cwhnd, WM_CHAR, &HF, &H180001) PostMessage(Cwhnd, WM_KEYUP, &H4F, &HC0180001) PostMessage(Cwhnd, WM_KEYUP, &H11, &HC01D0001) 'Dim Txt As String = "CRAZY" 'For x As Integer = 0 To Txt.Length - 1 ' PostMessage(Cwhnd, WM_KEYDOWN, CInt(Asc(Txt.Chars(x))), &H2F0001) 'Next End Sub End Module Link to comment Share on other sites More sharing options...
Lowlight Posted August 21, 2015 Share Posted August 21, 2015 What was the outcome of this...... like, years later. I'm having the exact same problem. ControlSend and ControlClick do not work when the window is INACTIVE but work fine when it IS active. The Class you gave is the EXACT same class I'm working with, so I'm assuming that you were working with Stealthbot. I was not able to get it to work with Notepad, Calculator or ANY window for that matter. I've Come to the conclusion that both ControlSend and ControlClick just simply do not work as described and are comepletely broken in AutoitX3. I am pouring over the forums here and this is like the closes post I've found to the issue I am having. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now