Sign in to follow this  
Followers 0
tphiau

trying to close a window that doesn't have a title - any ideas please?

16 posts in this topic

I am trying to write a script to close (as in WinClose, not terminate) dragon naturally speaking.

Unfortunately, this program doesn't have a window, so it doesn't have a window title.

I can do this:

$PID = ProcessExists("natspeak.exe")

If $PID Then ProcessClose($PID)

But I would rather let dragon close - thereby saving its user files.

Can anyone point me in a useful direction?

I thought this might be easy - and maybe it is.

Cheerio

tony

Share this post


Link to post
Share on other sites



Welcome tphiau,

It should have a hidden window that maybe suitable to close. I normally use WinLister from Nirsoft for detecting these hidden windows. :lmao:

Share this post


Link to post
Share on other sites

I'm in a similiar boat. I am interacting with the first window for my company's time sheet app. Program is called TimeTrak.

When launched a titleless, borderless window comes up (just like a spash screen). On it are four buttons.

I've managed to get it working by using the text on a button

ControlClick ( "" , "TimeTrak" , "Button2" )

If it doesn't have a hidden window (TimeTrak doesn't) then I'd recomend setting the WinDetectHiddenText option and trying

WinClose ( "" , "Naturally Speaking Hidden Text")

~~Tony

Share this post


Link to post
Share on other sites

Could you play a 'wav' file that has the spoken words to save and exit?

eg: Command, Menu, File, Save, OK, Menu, File, Exit (I'm not sure what the commands are)

Speech-Recognition Demo: At a recent Sacramento PC User's Group meeting, a company was demonstrating its latest speech-recognition software. A representative from the company was just about ready to start the demonstration and asked everyone in the room to quiet down. Just then someone in the back of the room yelled, "Format C: Return." Someone else chimed in: "Yes, Return".

Unfortunately, the software worked.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

In the AutoInfo Tool, under the Title... does the window have a Class?

If it does, you could try something like:

Opt('WinTitleMatchMode', 4)
$Class = 'Text Under Where Title Normally is for the "Class"'
WinClose('classname=' & $Class); Or WinKill()

If this is a child window, be sure to check if it is NOT the same as the window you want to leave open.

Edit:

I had a few minutes to try and figure out a solution for you guys... maybe this will help:

$PID = ProcessExists('My.exe')
$Text = 'Put the text of the window you absolutely want to keep here'

$aNarray = FindAllWindowsForApp($PID, $Text); This will create an array of all the windows that my executable has open
KillMyWindows($aNarray); off to kill the unwanted windows

Func FindAllWindowsForApp($az_PID, $t_TextToAvoid)
    Local $az_WindowPID
    Local $gz_GetWinList
    Local $gt_GotWinList = WinList()
        For $i = 1 To $gt_GotWinList[0][0]
        $az_WindowPID = WinGetProcess($gt_GotWinList[$i][0])
        If $az_WindowPID = $az_PID And StringInStr($gt_GotWinList[$i][0], $t_TextToAvoid) = 0 Then
            $gz_GetWinList = $gz_GetWinList & FindClassName($gt_GotWinList[$i][1]) & Chr(01)&Chr(01)
        EndIf
    Next
    Return StringSplit(StringTrimRight($gz_GetWinList, 2), Chr(01)&Chr(01))
EndFunc

Func FindClassName($hwnd)
    Local $class = DllCall("user32.dll", "int", "GetClassName", "hwnd", $hwnd, "str", "", "int", 32768)
    If Not @error Then Return $class[2]
EndFunc

Func KillMyWindows($aNarray)
    Local $OPT = Opt('WinTitleMatchMode', 4)
    Local $OK = 0
    For $i = 1 To UBound($aNarray) - 1
        If StringInStr($aNarray[$i], '#32770') And $OK = 0 Then
            $WinMsgBox = MsgBox(4, 'Common Class', '#32270 is a Common Class for Many Windows' _ 
            & @CRLF & 'Accepting to kill this window may kill un-wanted windows' _ 
            & @CRLF & 'Would you like to continue to kill this window?')
            
            If $WinMsgBox = 6 Then 
                WinKill('classname=' & $aNarray[$i])
                $OK = 1
            Else
                ContinueLoop
            EndIf
        Else
            WinKill('classname=' & $aNarray[$i])
        EndIf
    Next
    Opt('WinTitleMatchMode', $OPT)
EndFunc

We are getting the PID of the Executable that we are running, then we are searching for all windows under that PID, then we are getting the 'Class' of each PID, then we will loop thru each class using my before mentioned suggestion of 'classname=' and kill the window we don't want. I'm not 100% sure this will work for you... but give it a try... I'd like to hear if it does.

Edited by SmOke_N

[center]Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.[/center]

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Just for reference... for 'My.exe'... Be sure to put the executable name of the application you're trying to close the window on.

Edit: Boredom over took once again!

#include <guiconstants.au3>
#include <Array.au3>
$MainGui = GUICreate('Kill A Window', 300, 150)
$Lab1 = GUICtrlCreateLabel('Choose your .exe from the Process List', 50, 10, 200, 20)
$Com1 = GUICtrlCreateCombo('', 10, 30, 280, 65)
$Lab2 = GUICtrlCreateLabel('Is there a window you would like to keep?', 50, 60, 200, 20)
$Com2 = GUICtrlCreateCombo('*\*/*\*/*\*/*\*/*\*/*\*', 10, 80, 280, 65)
$But1 = GUICtrlCreateButton('Populate Exe', 10, 110, 75, 30)
$But2 = GUICtrlCreateButton('Populate Win', 90, 110, 75, 30)
$But3 = GUICtrlCreateButton('Execute', 170, 110, 60, 30)
$But4 = GUICtrlCreateButton('Clear All', 235, 110, 60, 30)

GUISetState()

While 1
    $Msg = GUIGetMsg()
    Select
    Case $Msg = - 3
        Exit
    Case $Msg = $But1
        GUICtrlSetData($Com1, '')
        GUICtrlSetData($Com1, GetProcessList())
    Case $Msg = $But2
        GUICtrlSetData($Com2, '', '*\*/*\*/*\*/*\*/*\*/*\*')
        GUICtrlSetData($Com2, FindAllWindowsForApp(ProcessExists(GUICtrlRead($Com1))), '*\*/*\*/*\*/*\*/*\*/*\*')
    Case $Msg = $But3
        Local $nArray = WindowsToClass(ProcessExists(GUICtrlRead($Com1)), GUICtrlRead($Com2))
        KillMyWindows($nArray)
    Case $Msg = $But4
        GUICtrlSetData($Com1, '')
        GUICtrlSetData($Com2, '')
    EndSelect
WEnd

Func WindowsToClass($az_PID, $WinToKeep)
    Local $az_WindowPID
    Local $gz_GetWinList
    Local $gt_GotWinList = WinList()
        For $i = 1 To $gt_GotWinList[0][0]
        $az_WindowPID = WinGetProcess($gt_GotWinList[$i][0])
        If $az_WindowPID = $az_PID And StringInStr($gt_GotWinList[$i][0], $WinToKeep) = 0 Then
            $gz_GetWinList = $gz_GetWinList & FindClassName($gt_GotWinList[$i][1]) & Chr(01)&Chr(01)
        EndIf
    Next
    Return StringSplit(StringTrimRight($gz_GetWinList, 2), Chr(01)&Chr(01))
EndFunc

Func FindAllWindowsForApp($az_PID)
    Local $az_WindowPID
    Local $gz_GetWinList
    Local $gt_GotWinList = WinList()
        For $i = 1 To $gt_GotWinList[0][0]
        $az_WindowPID = WinGetProcess($gt_GotWinList[$i][0])
        If $az_WindowPID = $az_PID Then
            $gz_GetWinList = $gz_GetWinList & $gt_GotWinList[$i][0] & '|'
        EndIf
    Next
    Return $gz_GetWinList & '*\*/*\*/*\*/*\*/*\*/*\*'
EndFunc

Func FindClassName($hwnd)
    Local $class = DllCall("user32.dll", "int", "GetClassName", "hwnd", $hwnd, "str", "", "int", 32768)
    If Not @error Then Return $class[2]
EndFunc

Func KillMyWindows($aNarray)
    Local $OPT = Opt('WinTitleMatchMode', 4)
    Local $OK = 0
    For $i = 1 To UBound($aNarray) - 1
        If StringInStr($aNarray[$i], '#32770') And $OK = 0 Then
            $WinMsgBox = MsgBox(4, 'Common Class', '#32270 is a Common Class for Many Windows' _ 
            & @CRLF & 'Accepting to kill this window may kill un-wanted windows' _ 
            & @CRLF & 'Would you like to continue to kill this window?')
            
            If $WinMsgBox = 6 Then 
                WinKill('classname=' & $aNarray[$i])
                $OK = 1
            Else
                ContinueLoop
            EndIf
        Else
            WinKill('classname=' & $aNarray[$i])
        EndIf
    Next
    Opt('WinTitleMatchMode', $OPT)
EndFunc

Func GetProcessList()
    Local $ProcList = ProcessList()
    Local $ReturnList = ''
    For $i = 1 to $ProcList[0][0]
        $ReturnList = $ReturnList & $ProcList[$i][0] & '|'
    Next
    $MakeArray = StringSplit(StringTrimRight($ReturnList, 1), '|')
    $ReturnList = ''
    _ArraySort($MakeArray)
    For $i = 1 To UBound($MakeArray) - 1
        $ReturnList = $ReturnList & $MakeArray[$i] & '|'
    Next
    Return $ReturnList
EndFunc
Edited by SmOke_N

[center]Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.[/center]

Share this post


Link to post
Share on other sites

Wow! Blown away completely by your responses.

thanks.

So in order,

MHz,

It took a bit to find a valid download for WinLister. and guess what? When Dragon is running and minimise to the taskbar, Winlister shows nothing. Not until you click on the icon in the taskbar does WinLister show Dragon even exists.

But none of them have a title.

Confussled,

Re playing a command, I'm running other programs that provide ad-ons to Dragon. They all need to be closed down in order. So it might be possible to trick dragon into doing this as you say. I'll dig into that one.

SmOke_N,

first, thanks for your extended answers.

The first thing is, that I don't want to terminate the process. I need dragon to close itself, and save its various files.

I tried using VBS to AppActivate it, and then SendKeys. And while I can get the dragon system tray right click menu to popup, it won't take the keys.

WinLister gives me a class of #32768 when I pop up the dragon tray icon.

I assume that this is not the actual classname though.

I haven't yet had a chance to go through your other code. I am not wanting to kill the process. I can do that easily with these two lines:

$PID = ProcessExists("natspeak.exe")

If $PID Then ProcessClose($PID)

Your last codes found the class accurately (#32270), and did terminate the process. Perhaps I can find a way to use the code to determine how to apply it to WinCLose, so I close the program rather than kill it.

Thanks a bunch,

tony

Share this post


Link to post
Share on other sites

My script I wrote doesn't terminate the process (unless that is the only window tied to it (the process), or #32270 is the name of both classes... remember, it does make a difference if the window is a child... This is why you have the option to put in 'Text' of the 'Title' of the window you want to keep).


[center]Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.[/center]

Share this post


Link to post
Share on other sites

Sounds to me that WinLister is only displaying visible windows for you. Go into options in the toolbar and ensure "Display Hidden Windows" is checked and "Display Windows With 0,0 Size" is checked.

It should show you the invisible windows of the systray icon and perhaps others. Perhaps not, but I would be very surprised if it did not.

Share this post


Link to post
Share on other sites

Sounds to me that WinLister is only displaying visible windows for you. Go into options in the toolbar and ensure "Display Hidden Windows" is checked and "Display Windows With 0,0 Size" is checked.

It should show you the invisible windows of the systray icon and perhaps others. Perhaps not, but I would be very surprised if it did not.

That winlist is a handy tool there MHz, I played with it yesterday!! The script I wrote should do the same thing though for specific applications.


[center]Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.[/center]

Share this post


Link to post
Share on other sites

Hi SmOke_N,

The initial problem is that I don't know what the window title text is. So I'm not sure how to use that as an option.

What I notice is that dragon disappears from the taskbar, but doesn't pop up its normal "saving" window. I will test further to see whether it is saving though.

MHz,

I did as you suggest, and of course, there are quite a number of dragon hidden windows.

one is called "natspeak", which is the name of the .exe task in the taskmanager. Another is "Dragon NaturallySpeaking" Neither of these works with Winclose in the following construct though.

WinClose("natspeak", "")

I'm checking out the WinDetectHiddenText function to see whether this will help here.

thanks again.

tony

Share this post


Link to post
Share on other sites

OK, I experimented some more.

SmOke_N, Your code does seem to Kill (as in terminate) the process.

I think these lines do it:

WinKill('classname=' & $aNarray[$i])

Of course, being dumb with this, I changed WinKill to WinClose, and while it popped up Dragon's saving box, it screwed Dragon up.

Also, because the class is actually 32770, it gets into damaging some other programs (as per your warning).

Did I misunderstand this?

Cheers,

tony

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

The winkill is killing the 'window' thus the name. As I said, if it is the only window available, then it may in fact close the process also.

My suggestion was this, let's say I have 2 windows.

Window one's title is: Learn Something Else

Window two's title is: Whatever

You run my script: Put in Learn Something Else ... this makes sure that that particualr window will not be killed. But now that I think about it, I'll have to look to see if I passed the window to 'not' kill to the window kill. If not you can do that.

Edit:

-------------

Nope I didn't pass it... Here try this, this makes double sure it's not killed (the window you want to save):

Edit2: I had stuff in the wrong place:

#include <guiconstants.au3>
#include <Array.au3>
$MainGui = GUICreate('Kill A Window', 300, 150)
$Lab1 = GUICtrlCreateLabel('Choose your .exe from the Process List', 50, 10, 200, 20)
$Com1 = GUICtrlCreateCombo('', 10, 30, 280, 65)
$Lab2 = GUICtrlCreateLabel('Is there a window you would like to keep?', 50, 60, 200, 20)
$Com2 = GUICtrlCreateCombo('*\*/*\*/*\*/*\*/*\*/*\*', 10, 80, 280, 65)
$But1 = GUICtrlCreateButton('Populate Exe', 10, 110, 75, 30)
$But2 = GUICtrlCreateButton('Populate Win', 90, 110, 75, 30)
$But3 = GUICtrlCreateButton('Execute', 170, 110, 60, 30)
$But4 = GUICtrlCreateButton('Clear All', 235, 110, 60, 30)

GUISetState()

While 1
    $Msg = GUIGetMsg()
    Select
    Case $Msg = - 3
        Exit
    Case $Msg = $But1
        GUICtrlSetData($Com1, '')
        GUICtrlSetData($Com1, GetProcessList())
    Case $Msg = $But2
        GUICtrlSetData($Com2, '', '*\*/*\*/*\*/*\*/*\*/*\*')
        GUICtrlSetData($Com2, FindAllWindowsForApp(ProcessExists(GUICtrlRead($Com1))), '*\*/*\*/*\*/*\*/*\*/*\*')
    Case $Msg = $But3
        Local $nArray = WindowsToClass(ProcessExists(GUICtrlRead($Com1)), GUICtrlRead($Com2))
        KillMyWindows($nArray, GUICtrlRead($Com2))
    Case $Msg = $But4
        GUICtrlSetData($Com1, '')
        GUICtrlSetData($Com2, '')
    EndSelect
WEnd

Func WindowsToClass($az_PID, $WinToKeep)
    Local $az_WindowPID
    Local $gz_GetWinList
    Local $gt_GotWinList = WinList()
        For $i = 1 To $gt_GotWinList[0][0]
        $az_WindowPID = WinGetProcess($gt_GotWinList[$i][0])
        If $az_WindowPID = $az_PID And StringInStr($gt_GotWinList[$i][0], $WinToKeep) = 0 Then
            $gz_GetWinList = $gz_GetWinList & FindClassName($gt_GotWinList[$i][1]) & Chr(01)&Chr(01)
        EndIf
    Next
    Return StringSplit(StringTrimRight($gz_GetWinList, 2), Chr(01)&Chr(01))
EndFunc

Func FindAllWindowsForApp($az_PID)
    Local $az_WindowPID
    Local $gz_GetWinList
    Local $gt_GotWinList = WinList()
        For $i = 1 To $gt_GotWinList[0][0]
        $az_WindowPID = WinGetProcess($gt_GotWinList[$i][0])
        If $az_WindowPID = $az_PID Then
            $gz_GetWinList = $gz_GetWinList & $gt_GotWinList[$i][0] & '|'
        EndIf
    Next
    Return $gz_GetWinList & '*\*/*\*/*\*/*\*/*\*/*\*'
EndFunc

Func FindClassName($hwnd)
    Local $class = DllCall("user32.dll", "int", "GetClassName", "hwnd", $hwnd, "str", "", "int", 32768)
    If Not @error Then Return $class[2]
EndFunc

Func KillMyWindows($aNarray, $DontKill)
    Local $OPT = Opt('WinTitleMatchMode', 4)
    Local $OK = 0
    For $i = 1 To UBound($aNarray) - 1
        If StringInStr($aNarray[$i], '#32770') And $OK = 0 Then
            $WinMsgBox = MsgBox(4, 'Common Class', '#32270 is a Common Class for Many Windows' _
            & @CRLF & 'Accepting to kill this window may kill un-wanted windows' _
            & @CRLF & 'Would you like to continue to kill this window?')
            
            If $WinMsgBox = 6 Then
                If StringInStr($aNarray[$i], $DontKill) = 0 Then WinKill('classname=' & $aNarray[$i])
                $OK = 1
            Else
                ContinueLoop
            EndIf
        ElseIf StringInStr($aNarray[$i], $DontKill) = 0 Then
            WinKill('classname=' & $aNarray[$i])
        EndIf
    Next
    Opt('WinTitleMatchMode', $OPT)
EndFunc

Func GetProcessList()
    Local $ProcList = ProcessList()
    Local $ReturnList = ''
    For $i = 1 to $ProcList[0][0]
        $ReturnList = $ReturnList & $ProcList[$i][0] & '|'
    Next
    $MakeArray = StringSplit(StringTrimRight($ReturnList, 1), '|')
    $ReturnList = ''
    _ArraySort($MakeArray)
    For $i = 1 To UBound($MakeArray) - 1
        $ReturnList = $ReturnList & $MakeArray[$i] & '|'
    Next
    Return $ReturnList
EndFunc
Edited by SmOke_N

[center]Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.[/center]

Share this post


Link to post
Share on other sites

Hi SmOke_N,

I understand what your code does. You obviously have a good handle on scripting.

I ran your modified version, but didn't chose a dragon window (by selecting its text) to keep. (As in, I don't actually have a need to keep one since I'm trying to close dragon).

This time dragon threw up an error screen and dissapeared up its own spout.

This is turning out to be more complex than I imagined.

thanks,

tony

Share this post


Link to post
Share on other sites

Just wish I had dragon to help you out more... I know it's a huge program, so I won't be downloading it to see what could be done. Hope you get it figured out.


[center]Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.[/center]

Share this post


Link to post
Share on other sites

#16 ·  Posted (edited)

You are never going to belive this...

The sweet smell of success!

This did it:

AutoItSetOption("WinTitleMatchMode", 4)

$handle = WinGetHandle("DragonBar", "")

WinClose($handle)

SmOke_N, I noticed one of your scripts (when I replaced WinKill with WinClose, actually popped up the dragon close sequence, but then freaked out. That got me thinking that one of the processes obvously must do the job. So I used WinLister (thnks MHz), and your script SmOke_N to discover which one.

Then just had to figure out how to get hold of it and close it. And the handle was the answer

Yahooooooo! (no trademark infringements intended) :lmao:

thanks again,

tony

Edited by tphiau

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