house Posted April 16, 2012 Share Posted April 16, 2012 I have a commercial software that provides a .bat file to execute user commands. When you perform a certain action in the software it will launch a certain batch file. I've used this to automate some user interaction with another software. The batch file call several different programs and then looses focus (it isn't the active window when it prompts the user for some info). I found AutoIt when searching for away to make the dos window take focus as the active window once it was launched. My first attempt was executable to send a simple Alt+Tab which I called from the batch file. Occasionally this would break when the dos window wasn't next in the program list. Then I put a Title command in the batch file and I used winwaitactive with the title I gave to the DOS window. Then we upgraded from XP to windows 7 and the dos prompt now shows "Administrator: " (that's two spaces) then the title I gave it. So the code broke again. No problem. I added the prefix to my winwaitactive string and ....no dice.... I added a "If winexists...." statement to debug. I found there are actually two spaces and then it worked. But it didn't maximize the dos window. I then did some more playing around and found "ControlShow(...)" seemed to work. Really it would bring up the dos window and the user could type a response but the DOS window wouldn't recognize the enter key. Once you minimize then maximize the dos window there is now a cursor with the typed input and it responds to the enter key. I went back to my code and changed it back to winwaitactive, then followed up with two send statements for alt+tab and now everything works as expected. Its as if show and active do not mean the same thing as visible, ready, useable etc the same way it does in windows XP. So I got it to work but I don't really feel this is the best solutions nor do I understand why the old code didn't work. Can anyone shed some light? Below is my code. If WinExists($CmdLine[1]) Then ;~ msgbox(0,"HI", "here it is") winwaitActive($CmdLine[1],"",5) ;~user must pass the window title when calling this program ;~ ControlShow($CmdLine[1], "","") ;~this results in the window being on top, you can enter a number but can't press enter and don't see a cursor send("!{TAB}") send("!{TAB}") Else MsgBox(0, "", "AutoCreate... Window not found") EndIf Link to comment Share on other sites More sharing options...
Tankbuster Posted April 16, 2012 Share Posted April 16, 2012 (edited) Please see my post as an assumption of your description, maybe totally wrong but let's give it a try...Edit : BTW: Tested with Win7(x64)See the attached SHOWWIN.ZIP showwin.zip for all code.Let me explain:SLEEP.au3/EXE for the attached batches - sleeping argument in secs to not blow the batch CPU usagetwo batches one is named MY_BATCH.BAT and the other OTHER.BAT (two simply to show that the BAT_2_FRONT checks only for a certain PID/WIN/CommandlineBAT_2_FRONT (the magic stuff :-) )Demo:Start the two batches, they will create a %~n0_RUN.CTL , if you delete the CTL the BATCH will stop, otherwise it will loop.The MY_BATCH will bring his own window to the front, with a pause. And becasue it's his own batch process, the script could do this by using %~n0 as an argument.Of course the BAT_2_FRONT could be started from other CMD as well.with :BAT_2_FRONT.exe <BATCH NAME> eg: BAT_2_FRONT MY_BATCH.BATSo here is what it does.1. It will get all processes from WIN322. Then it will retrieve the PID of a "CMD /C" (this maybe needs to be adopted, but I think windows starts always with cmd /C, but if you use cmd /k ....change it. and the commanline need to have the $CmdLine[1] too.(the reason is: If you run the BATCH and you edit the same BATCH at the same time, the process list will show something like this1. cmd /c MY_BATCH.BAT2. notpad MY_BATCH.BATgot it? )3. Then this PID is used to activate the windows and not the windows title.Why not use Key_send or window title ?The answer is PID is unique and this is based on the command line (actually), while window title as you already know could be different from system to system.ALT+TAB by keysend is.....mmmh.....how should I explain, it's ... .think about flashing in windows in case a other programmer also use BRING 2Front just in the time of your second ALT+TAB.....brrrrr...this will get strange.I hope this gives you some guidance?You I left some explanations open (yes, it's late already...), just ask ... good night #AutoIt3Wrapper_Change2CUI=Y $objWMI = ObjGet("winmgmts:localhostrootCIMV2") $objItems = $objWMI.ExecQuery("Select * From Win32_Process", "WQL", 0x10 + 0x20) local $CMD_PATERN=$CmdLine[1] local $PID_OF_BATCH If IsObj($objItems) Then For $objItem In $objItems if StringInStr($objItem.CommandLine,$CMD_PATERN,2) and StringInStr($objItem.CommandLine,"cmd /c",2) Then ConsoleWrite("Process Name:"&$objItem.CommandLine&@CRLF) $PID_OF_BATCH=$objItem.ProcessID EndIf Next EndIf if $PID_OF_BATCH <> "" Then _WinActivatePID($PID_OF_BATCH) EndIf Exit Func _WinActivatePID($iPID) Local $aList, $i $aList = WinList() For $i = 1 To $aList[0][0] If WinGetProcess($aList[$i][1]) = $iPID Then Return WinActivate($aList[$i][1]) Next Return -1 EndFunc Edited April 16, 2012 by Tankbuster Link to comment Share on other sites More sharing options...
house Posted April 17, 2012 Author Share Posted April 17, 2012 (edited) Yes, you understood the problem perfectly. This is much more bullet proof. In my hunt for a better solution I came across the PID method but I didn't know how to find the PID. The WMI statements are a little beyond my abilities. I did some googling and found enough info to understand how that works. I also didn't know about %~nx0 and %~dp0. I can see these being helpful someday. Seems I could learn for ever and still know nothing (is that a double negative?). This works great on my XP machine, however it doesn't work on the windows 7 machine I'm trying to implement this for. I can see how your solution is very robust but there is something that is preventing the winwaitactive with the title method from working and I believe it is causing the winactive with the PID not to work either. I added some debug statements to write the ID to the console. I can see using the window info tool that the ID is correct. I even isolated the call from mysend.bat with a healthy 15 second sleep before starting batch_2_front.exe. I'm leaning towards there is some crazy setting on the windows 7 machine. I'm going to see if I can get this to work on another machine. $objWMI = ObjGet("winmgmts:localhostrootCIMV2") $objItems = $objWMI.ExecQuery("Select * From Win32_Process", "WQL", 0x10 + 0x20) ;~ local $CMD_PATERN="MY_BATCH.BAT" local $CMD_PATERN=$CmdLine[1] local $PID_OF_BATCH If IsObj($objItems) Then For $objItem In $objItems if StringInStr($objItem.CommandLine,$CMD_PATERN,2) and StringInStr($objItem.CommandLine,"cmd /c",2) Then ConsoleWrite("Process Name:"&$objItem.CommandLine&@CRLF) $PID_OF_BATCH=$objItem.ProcessID ConsoleWrite($objItem.ProcessID & @CRLF) ;~added by BAH EndIf Next EndIf if $PID_OF_BATCH <> "" Then ;~_WinActivatePID($PID_OF_BATCH) ConsoleWrite(_WinActivatePID($PID_OF_BATCH)&@CRLF) ;~added by BAH EndIf Exit I just tried to type the response to the batch file's user inquiry and when I press enter the dos window is shown and shows the answer I typed. I think the dos window is active but not displayed. Edited April 17, 2012 by house Link to comment Share on other sites More sharing options...
Tankbuster Posted April 17, 2012 Share Posted April 17, 2012 The batch you are taking about. "The batch file call several different programs and then looses focus (it isn't the active window when it prompts the user for some info)" Maybe if this is simpler to implement than bringing the CMD to front and display (so I guess) with "ECHO" command some infos, maybe you write (or search here :-) ) for a windows GUI / messagebox that will come to front by default ..... and so make the activate obsolete? (also your user will think you are much smarter because you created a gui and not the old black shell ....) But if you want to stick to the "activate" thing. Question? Could you do a screenshot and post it? Could you post the found the commandline from: $objItem.CommandLine Maybe the "cmd" thing does not work on your Win/? 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