Sign in to follow this  
Followers 0
house

Windows 7 DOS window and winwaitactive

4 posts in this topic

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

Share this post


Link to post
Share on other sites



#2 ·  Posted (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 usage
  • two 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/Commandline
  • BAT_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.BAT

So here is what it does.

1. It will get all processes from WIN32

2. 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 this

1. cmd /c MY_BATCH.BAT

2. notpad MY_BATCH.BAT

got 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 by Tankbuster

Share this post


Link to post
Share on other sites

#3 ·  Posted (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:"&amp;$objItem.CommandLine&amp;@CRLF)
   $PID_OF_BATCH=$objItem.ProcessID
   ConsoleWrite($objItem.ProcessID &amp; @CRLF)    ;~added by BAH
  EndIf
   Next
EndIf
if $PID_OF_BATCH &lt;&gt; "" Then
;~_WinActivatePID($PID_OF_BATCH)
ConsoleWrite(_WinActivatePID($PID_OF_BATCH)&amp;@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 by house

Share this post


Link to post
Share on other sites

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/?

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0