Jump to content

Accessing singleton


 Share

Recommended Posts

I have an application that has a singleton check.

What I want to do is: when a second instance is run make a OK,CANCEL messagebox popup. If the user pressed cancel, nothing happens, but when the user pressed OK, it will first call the CLOSE method from the first isntance.

Is this possible, and how?

Thanks!

Link to comment
Share on other sites

An easy way is to check for ProcessExists("myapp") and keep the PID if it does. When you ask, you can ProcessClose($pid) if they say OK.

Ok, that seems usefull.

Is there a way to call a method in the other instance before it closes? Either from the new instance or by letting the old instance check if it's closed.

Thanks!

Edit: Hmm, ProcessExists does not use the same method to identify the process than _Singleton. Does it realy need the executable name?

Edited by SaphuA
Link to comment
Share on other sites

Alrighty, interesting.

Perhaps I should explain the problem to make things more clear:

I'm running an application that uses ModernMenuRaw to display an icon in the system tray. Now when the user runs the same application again (this could be desired in some cases) I want to give them the option to either cancel running the new application or close the other application and start up the new one. BUT! Before closing the other application, there is a cleanup method that needs to be called. This can eather be done from the new application or by the old application checking if it's closing (preferred).

Thanks!

Link to comment
Share on other sites

I had the same kind of need the OP has when I was writing a screensaver - how to close the previous instance.

james3mg had a solution...

Global Const $_AUTOIT_WIN_TITLE = "My unique string #qwertyuiopasdf"

If WinExists($_AUTOIT_WIN_TITLE) Then
    $i_RetVal = MsgBox(262144+32+3, "MyApp", _
                "An instance of this program is already   " _
        & @CR & "running. Exit the previous instance?")
    If $i_RetVal = 6 Then
; Close only the last instance, not the current one ...
        WinClose($_AUTOIT_WIN_TITLE)
    EndIf
EndIf

; Stamp this instance only now - only after the previous instance is closed.
AutoItWinSetTitle($_AUTOIT_WIN_TITLE)

:)

I had thought at first that this issue might involve the use of the _Singleton function, but this is only a somewhat similar situation. _Singleton is instead used to keep a second instance from ever starting by closing any second instance as soon as it begins.

Edited by Squirrely1

Das Häschen benutzt Radar

Link to comment
Share on other sites

I have an application that has a singleton check.

What I want to do is: when a second instance is run make a OK,CANCEL messagebox popup. If the user pressed cancel, nothing happens, but when the user pressed OK, it will first call the CLOSE method from the first isntance.

Is this possible, and how?

Thanks!

There's no need to try to call the "cleanup" function from "outside" the process. You just need to set up some IPC between the app instances. The common case is to transfer the command line from 2nd instance to 1st. I'm sure if you searched there'd be many examples how to implement it. So when the 2nd instance formats the command line for the 1st instance to read, encode some switch or other convention to tell the 1st instance to clean up and die. For any IPC that uses a name I recommend using GUID strings. Just avoids the off chance that something like "XXXMyUniqueStringXXX" might be used by some other programmer and not be so unique after all. :)

Link to comment
Share on other sites

I might have messed something up here. I didn't read the OP's post number 5, and only tried to solve the one described in post number 1.

This must be the code he actually needs ...

#Include <Misc.au3>
Global Const $_AUTOIT_WIN_TITLE = "Unique string uiop_asdf"
Global $_sole_instance

$_sole_instance = _Singleton("Another unique string", 1); Returns 0 if another instance found. 
If Not $_sole_instance Then
    $i_msgRet = MsgBox(262144+32+2, "MyApp", _
                'An instance of this program is already running.   ' _
        & @CR & 'Click "Abort" to exit this instance, Retry to' _
        & @CR & 'exit the previous instance, or Ignore for neither.')
    Switch $i_msgRet
        Case 5; "Aborting"
            CleanupThisInstance()
            Exit
        Case 4; "Retrying"
            CleanupPreviousInstance()
            WinClose($_AUTOIT_WIN_TITLE)
    EndSwitch
EndIf

; Stamp this instance only now - only after any previous instance is closed.
AutoItWinSetTitle($_AUTOIT_WIN_TITLE)

Func CleanupPreviousInstance()
    ; Code to cleanup before exiting PREVIOUS instance goes here.
EndFunc

Func CleanupThisInstance()
    ; Code to cleanup before exiting THIS instance goes here.
EndFunc

Das Häschen benutzt Radar

Link to comment
Share on other sites

You aren't looking at Squirrely1's code close enough. It's setting the AutoIt window title. That window exists regardless of what your code does.

Ahh I didn't know that.

So when you close this window, the application that belongs to it also closes?

(Gonna test it now, just thinking out loud)

Edit: Ok, it seems to be working quite well. Awesomeness!

Now all that's left is call the cleanup method.

Edited by SaphuA
Link to comment
Share on other sites

You can't transfer command lines. Command lines are only used when a process is started. What in the world are you talking about?

Read post #5 where the OP talks about starting a second instance of the application. That yields a command line even if it has no parameters. What I'm talking about is an instance control that will work for more than just the problem described in this instance. IOW, reusable code.

Edited by MilesAhead
Link to comment
Share on other sites

Squirrely1: Thanks, but my application doesn't use windows, plus that your method isn't very neat :o

MilesAhead: Thanks, do you happen to have any information on IPC and AutoIt?

I made my instance control ActiveX so I wouldn't have to keep coding the same thing in different programming languages. :)

Anyway, there's tons of examples in many programming dialects. It's a very common control/component to create.

Link to comment
Share on other sites

Ahh I didn't know that.

So when you close this window, the application that belongs to it also closes?

(Gonna test it now, just thinking out loud)

Edit: Ok, it seems to be working quite well. Awesomeness!

Now all that's left is call the cleanup method.

you're probably just interested at the moment in getting what you're working on done but if you'd

like to mess around with it sometime you can download the ActiveX Control from my site.

This Page describes it. I have no help file for it at the moment. It's designed to drop on a form in a programming IDE but you can also dynamically create the control from ActiveX aware scripting languages. One of these days I'll have to code up a demo for it. :)

Link to comment
Share on other sites

Keep it simple :o

_CheckScript()
; here follows your code
While Sleep(100000)
WEnd
Func OnAutoItExit()
; here goes the cleanup code
    SplashTextOn("", @CRLF & StringTrimRight(@ScriptName, 4) & " cleanup starting. ", -1, 90, -1, -1, 17, "", 20, 900)
    SoundPlay(@WindowsDir & "\media\notify.wav", 1)
    Sleep(1000)
    SplashTextOn("", @CRLF & StringTrimRight(@ScriptName, 4) & " cleanup ended. ", -1, 90, -1, -1, 17, "", 20, 900)
    Sleep(2000)
EndFunc  ;==>OnAutoItExit
Func _CheckScript()
    Local $O = ObjGet("winmgmts:\\" & @ComputerName & "\root\CIMV2")
    Local $OI, $CI = $O.ExecQuery("SELECT * FROM Win32_Process", "WQL", 0x30)
    For $OI In $CI
        If $OI.ProcessId = @AutoItPID Then ContinueLoop
        If $OI.Name = StringTrimRight(@ScriptName, 4) & ".EXE" Then _AskWhat2do($OI.ProcessId)
        If $OI.Name = "AutoIt3.exe" And StringInStr($OI.CommandLine, StringTrimRight(@ScriptName, 4) & ".au3") Then _AskWhat2do($OI.ProcessId)
    Next
EndFunc  ;==>_CheckScript
Func _AskWhat2do($Pid)
    If MsgBox(4 + 32 + 262144, @ScriptName, "Terminate process " & $Pid & " ?") = 7 Then Return
    Local $i, $aWinList = WinList()
    For $i = 1 To $aWinList[0][0]
        If WinGetProcess($aWinList[$i][1]) = $Pid Then WinClose($aWinList[$i][1])
    Next
EndFunc  ;==>_AskWhat2do

Give it a try :)

Tinyboy

Link to comment
Share on other sites

Perhaps I will wait for the demo then :D Thanks for the information though.

I'm still trying to find more information on how to achieve what I want to, so any input is very welcome.

Sorry. I keep forgetting that my ActiveX Controls are limited in AutoIt due the the way Events are handled.

But it can still pass command line info to the first app instance. Just can't send the extra user string that would come in handy. In any case I threw together a demo that shows transfer of the first command line param from the 2nd instance to the 1st.

CODE

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

AutoIt Version: 3.3.0.0

Author: MilesAhead

Script Function: Demo for TellTailX ActiveX Control

Unfortunately I can't show off the event handlers of the Control

because they won't function correctly in true interpreted langauges.

The line by line execution makes them more trouble then they are

worth. :)

The events will work in C#, VB, VC++, Delphi. It is designed to install

in a programming IDE toolbox such as Visual Studio or Delphi IDE.

When dropped on a form the Guid strings for Mutex and Memory Mapped File

Names are generated automatically. The event handlers can be assigned

using the Property editor of the IDE just like any control.

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

; Script Start - Add your code below here

$paramStr = ""

Global $mainInstance = False

Global $usrString = ""

Global $tt = ObjCreate("TellTailXControl1.TellTailX")

If @error Then

MsgBox(0, "test", "ObjCreate Failed")

Exit

EndIf

$tt.MapFileName = "{261AE7CC-38A3-4C70-9057-3C4C4D3A47C5}"

$tt.MutexName = "{8D24D263-CAF6-41EA-BA32-5514F8EF7851}"

$tt.Enabled = True

;2nd instance copies command line info to Memory Mapped File and dies if AutoKill

$tt.AutoKill = True

If $tt.Execute() And Not $tt.GetErrorCode() Then

$mainInstance = True

EndIf

; presumably this loop would be inside the GUI msg loop if

; it were a GUI app. When the CopyData method returns

; True then the 1st instance has gotten some data from

; the Memory Mapped File. The Control has methods

; GetParamStr() and GetParamCount() that mimick the

; Delphi ParamStr() and ParamCount() functions.

; There is also a limited character array called

; UserString that can be used to copy an Ansi

; string. UserString needs to be read and written

; using event handlers so that's why I gave up trying

; to show it here. Doesn't work right in line

; by line environments.

While 1

While Not $tt.CopyData()

Sleep(50)

Wend

$paramStr = $tt.GetParamStr(1)

If $paramStr = "quit" Then ExitLoop

WEnd

MsgBox(0, "test", "2nd Instance ParamStr(1) is " & $paramStr)

$tt = 0

Exit

The Control uses the CopyData() method to allow flexibility in the client application.

You can test for shared data using a Timer, polling as in this example, a separate

thread using WaitForSingleObject() in compiled languages, or an Idle loop handler etc..

In some time to come I should get a .chm help file for the thing. :o

Edited by MilesAhead
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...