Sign in to follow this  
Followers 0
Akshay07

Kill an existing instance of my script that is found using _Singleton

15 posts in this topic

Hi all,

Here is what I would like to do:

#include <Misc.au3>
if _Singleton("MyScript",1) = 0 Then
    $answer = Msgbox(1,"Warning","An occurence of MyScript is already running. Click OK to kill it or CANCEL to exit.")
    If $answer = 2 Then   ; CANCEL
        Exit
    Else         ; OK
        ; KILL EXISTING PREVIOUS INSTANCE OF MyScript
    EndIf
EndIf
Msgbox(0,"OK","Only one occurence of MyScript is running")

How can I do the "KILL EXISTING PREVIOUS INSTANCE OF MyScript" part?

Thank you.

Share this post


Link to post
Share on other sites



Why killing the old one and not the new one ?

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

I think ProcessClose(@ScriptName) would work.

Questions I have reading this are:

- how would it know which to kill when the exe names are the same?

- this will kill the wrong one when the EXE has another name.. right?

JOs

Edited by Jos

Visit the SciTE4AutoIt3 Download page for the latest versions        Beta files                                                          Forum Rules
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Share this post


Link to post
Share on other sites

As Jos said it's not that simple.

Can be done like this:

#include <Misc.au3>
If _Singleton("MyScript", 1) = 0 Then
    $answer = MsgBox(1, "Warning", "An occurence of MyScript is already running. Click OK to kill it or CANCEL to exit.")
    If $answer = 2 Then ; CANCEL
        Exit
    Else ; OK
        ; KILL EXISTING PREVIOUS INSTANCE OF MyScript
        $aProc = ProcessList(StringRegExpReplace(@AutoItExe, ".*\\", ""))
        For $i = 0 To UBound($aProc) - 1
            If $aProc[$i][1] <> @AutoItPID Then ProcessClose($aProc[$i][1])
        Next
    EndIf
EndIf
MsgBox(0, "OK", "Only one occurence of MyScript is running")

But still it's not totally right (that first line in Jos's response).

It can (should) be done in much more advanced way.


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Can this help or im missing the point of this topic

#include <Process.au3>
If WinExists("autoit win") Then ProcessClose(WinGetProcess("autoit win"))
AutoItWinSetTitle("autoit win")
While 1
    
WEnd
Edited by bogQ

TCP server and client - Learning about TCP servers and clients connection
Au3 oIrrlicht - Irrlicht project
Au3impact - Another 3D DLL game engine for autoit. (3impact 3Drad related)



460px-Thief-4-temp-banner.jpg
There are those that believe that the perfect heist lies in the preparation.
Some say that it’s all in the timing, seizing the right opportunity. Others even say it’s the ability to leave no trace behind, be a ghost.

 

Share this post


Link to post
Share on other sites

I had problems with _Singleton() on my Notebook and wrote an alternate version of "Enforce Single Instance of Program". In the second posting in that thread I show how to pass a commandline parameter to the parent instance before exiting. I think this example could be easily rewritten to pass an Exit() command to the parent script via WM_COPYDATA so it closes itself.

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Thanks guys.

KaFu, I am afraid your script is too advanced for me, I don't fully understand it :D

The scenario would be that there are two instances of MyScript.exe running, the names would be exactly the same.

What about this (very inspired by what trancexxx proposed):

#include <Misc.au3>
If _Singleton("MyScript", 1) = 0 Then
    $answer = MsgBox(1, "Warning", "An occurence of MyScript is already running. Click OK to kill it or CANCEL to exit.")
    If $answer = 2 Then ; CANCEL
        Exit
    Else ; OK
        ; KILL EXISTING PREVIOUS INSTANCE OF MyScript
        $aProc = ProcessList ( "MyScript.exe" )
        For $i = 1 To $aProc[0][0]
            If $aProc[$i][1] <> @AutoItPID Then ProcessClose($aProc[$i][1])
        Next
    EndIf
EndIf
MsgBox(0, "OK", "Only one occurence of MyScript is running")

Edit: I just tested this and it seems to work fine. I had 3 instances of MyScript.exe running. When starting the 4th one, I clicked on OK and the previous 3 instances were killed.

The only problem is that the corresponding tray icons don't disappear. They do if I move the mouse over these icons (without clicking). I will create another topic for this issue to avoid mixing questions.

Edited by Akshay07

Share this post


Link to post
Share on other sites

In the func WM_COPYDATA() either exit the hard way (commented) or set a var to exit in main loop.

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.2.0
 Author:         myName

 Script Function:
    Template AutoIt script.

#ce ----------------------------------------------------------------------------

; Script Start - Add your code below here

#NoTrayIcon
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

$bExit = False

$hwnd_AutoIt = _EnforceSingleInstance('e15ff08b-84ac-472a-89bf-5f92db683165') ; any 'unique' string; created with http://www.guidgen.com/Index.aspx
Opt("TrayIconHide", 1)

$hGUI = GUICreate("My GUI " & $hwnd_AutoIt,300,300,Default,Default) ; will create a dialog box that when displayed is centered
$label = GUICtrlCreateLabel($CmdLineRaw,10,10,300,100)
GUISetState(@SW_SHOW) ; will display an empty dialog box

ControlSetText($hwnd_AutoIt,'',ControlGetHandle($hwnd_AutoIt,'','Edit1'),$hGUI) ; to pass hWnd of main GUI to AutoIt default GUI
GUIRegisterMsg($WM_COPYDATA, "WM_COPYDATA")

While 1
    sleep(10)
    $msg = GUIGetMsg()
    If $msg = $GUI_EVENT_CLOSE Then ExitLoop

    if $bExit = true then ExitLoop

WEnd
GUIDelete()

Func _EnforceSingleInstance($GUID_Program = "")
    If $GUID_Program = "" Then Return
    $hwnd = WinGetHandle($GUID_Program)
    If IsHWnd($hwnd) Then
        $hwnd_Target = ControlGetText($hwnd,'',ControlGetHandle($hwnd,'','Edit1'))
        WM_COPYDATA_SendData(HWnd($hwnd_Target), "Exit")
    EndIf
    AutoItWinSetTitle($GUID_Program)
    Return WinGetHandle($GUID_Program)
EndFunc   ;==>_EnforceSingleInstance

Func WM_COPYDATA($hWnd, $MsgID, $wParam, $lParam)
    ; http://www.autoitscript.com/forum/index.php?showtopic=105861&view=findpost&p=747887
    ; Melba23, based on code from Yashied
    Local $tCOPYDATA = DllStructCreate("dword;dword;ptr", $lParam)
    Local $tMsg = DllStructCreate("char[" & DllStructGetData($tCOPYDATA, 2) & "]", DllStructGetData($tCOPYDATA, 3))
    if StringInStr(DllStructGetData($tMsg, 1),"Exit") then
        ; Exit ; a) the hard way :)
        $bExit = true  ; b) set var to exit in main loop
    endif
EndFunc   ;==>WM_COPYDATA

Func WM_COPYDATA_SendData($hWnd, $sData)
    If Not IsHWnd($hWnd) Then Return 0
    if $sData = "" then $sData = " "
    Local $tCOPYDATA, $tMsg
    $tMsg = DllStructCreate("char[" & StringLen($sData) + 1 & "]")
    DllStructSetData($tMsg, 1, $sData)
    $tCOPYDATA = DllStructCreate("dword;dword;ptr")
    DllStructSetData($tCOPYDATA, 2, StringLen($sData) + 1)
    DllStructSetData($tCOPYDATA, 3, DllStructGetPtr($tMsg))
    $Ret = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hWnd, "int", $WM_COPYDATA, "wparam", 0, "lparam", DllStructGetPtr($tCOPYDATA))
    If (@error) Or ($Ret[0] = -1) Then Return 0
    Return 1
EndFunc   ;==>WM_COPYDATA_SendData

Share this post


Link to post
Share on other sites

It would be easier to use AutoItWinSetTitle and WinExists to create this singleton behaviour:

Global Const $_SingleTonKey = "ac38f004-f30d-401c-8627-8a6ad1c2e763" ; e.g. GUID
If WinExists($_SingleTonKey) Then
        Switch MsgBox(4, 'Instance already running', 'Kill old instance?')
            Case 6
                $iPID = WinGetProcess($_SingleTonKey)
                WinKill($_SingleTonKey)
                Sleep(500)
                ProcessWaitClose($iPID, 500)
                ProcessClose($iPID)
                ; only we are running now
            Case Else
                Exit
                ;the other Instance will continue
        EndSwitch
EndIf
AutoItWinSetTitle($_SingleTonKey)

; Script will be here

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

Thanks, I did not know that it was possible to give a window title to the script. I looked at the help for AutoItWinSetTitle and now I understand how it works.

I have two questions:

1/ For my knowledge, how do you come up with "ac38f004-f30d-401c-8627-8a6ad1c2e763" ? Does it mean something or is is a random sequence to identify the window title?

2/

ProcessWaitClose($iPID, 500)
ProcessClose($iPID)

Why using ProcessWaitClose, then ProcessClose for the same PID? Isn't ProcessWaitClose good enough?

Edited by Akshay07

Share this post


Link to post
Share on other sites

Well, I added a timeout to ProcessWaitClose. It waits 500 milliseconds for the normal AutoIt-Exit (initiated by WinKill), then the process is killed with Processclose if it did not exit yet.

The String I used for $_SingleTonKey is a GUID to ensure it is unique :D For example, use guidgen.com to create a GUID.


*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

The String I used for $_SingleTonKey is a GUID to ensure it is unique :huggles: For example, use guidgen.com to create a GUID.

Awesome! That's very interesting piece of info! Thanks a lot :D

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

Oh, sorry, the Timeout for ProcessWaitClose is in seconds, so change to:

ProcessWaitClose($iPID, 1)
Edited by ProgAndy

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

It would be easier to use AutoItWinSetTitle and WinExists to create this singleton behaviour:

True, but my example will exit the program gracefully, e.g. it will remove it's icon from the tray as OP asked in second thread :D. Remove #NoTrayIcon and Opt("TrayIconHide", 1) from the example I provided.

Share this post


Link to post
Share on other sites

True, but my example will exit the program gracefully, e.g. it will remove it's icon from the tray as OP asked in second thread :D. Remove #NoTrayIcon and Opt("TrayIconHide", 1) from the example I provided.

Using WinKill allows that, too. To give AutoIt more time to exit properly, you can increase the timrout in ProcessWaitClose or remove ProcessClose completely :huggles:

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

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