AutoHotkey Community

It is currently May 27th, 2012, 6:42 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 12 posts ] 
Author Message
PostPosted: July 29th, 2011, 9:32 am 
Hello,

Is there a way to use #SingleInstance Force conditionally?

When a parameter is passed to the script, I'd like to make it not a single instance. But when it is run normally without parameters, I'd like to force it to be a single instance.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 29th, 2011, 12:32 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
IIRC, you can use ...
Quote:
/f or /force -- Launch unconditionally, skipping any warning dialogs.
Source: Scripts - Passing Command Line Parameters to a Script


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 29th, 2011, 4:42 pm 
Oh, that is not the perfect solution for me. Users of my program won't understand it.

Thanks anyway.

It would be great if the language supports conditional directive. I recently had a similar problem when including some files, trying to make it conditional.


Report this post
Top
  
Reply with quote  
 Post subject: Longhand way to do it
PostPosted: July 29th, 2011, 10:09 pm 
Offline

Joined: January 21st, 2009, 5:49 pm
Posts: 176
Others with more AHK experience may be able to do it with fewer lines of code, but I wanted to learn to "kill every process instance but this one" so I gave it a shot. :)

The compiled instance(s) with command line param(s) stay running.

The compiled instance that comes up with no command line params kills all the others.

Code:

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#SingleInstance off
HasParam := 0

If 0 > 0
{
   HasParam := 1
}

If HasParam = 0
{   
   killed := KillOtherCopies()
   MsgBox, 4160, , %killed% Other Copies Killed
}


While 1
{
   Sleep, 250
}

KillOtherCopies()
{
   local nkilled := 0
   if !A_IsCompiled
      return
   PID := DllCall("GetCurrentProcessId")
   for proc in ComObjGet("winmgmts:").ExecQuery("Select * from Win32_Process")
    if (proc.Name = A_ScriptName) && (proc.ProcessID != PID)
      {
         PPID := proc.ProcessID
         ;MsgBox, 4160, , Killing %PPID%, 2
         Process,close,%PPID%
         nkilled += 1
      }
      return nkilled
}



edit: changed function to return number of killed instances

_________________
"I don't want to belong to any club that would have me as a member."
- Groucho Marx


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 30th, 2011, 1:57 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
Here's another method, compatible with AutoHotkey Basic:
Code:
DetectHiddenWindows On ; List all running instances of this script:
WinGet instances, List, %A_ScriptFullPath% ahk_class AutoHotkey
if (instances > 1) { ; There are 2 or more instances of this script.
    this_pid := DllCall("GetCurrentProcessId"),  closed := 0
    Loop % instances { ; For each instance,
        WinGet pid, PID, % "ahk_id " instances%A_Index%
        if (pid != this_pid) { ; If it's not THIS instance,
            WinClose % "ahk_id " instances%A_Index% ; close it.
            closed += 1
        }
    }
    MsgBox Closed %closed% instance of this script.
}
#Persistent ; Don't exit automatically for this test.
#SingleInstance Off ; Allow new instances to start.

I could simplify slightly, removing DllCall and instead comparing instances%A_Index% to A_ScriptHwnd, but then it would require AutoHotkey_L v1.1.01. :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 30th, 2011, 5:57 pm 
Thanks guys, much appreciated.

Do you think it's possible to leave instances run with parameters but to kill only the one without parameters?


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: July 30th, 2011, 6:47 pm 
Offline

Joined: February 6th, 2010, 5:17 pm
Posts: 57
You could use a lockfile (or in this example a lockregistry):
Code:
#SingleInstance Off
#Persistent
has_params = %0%
if (!has_params)
{
  RegRead, is_running, HKCU, Software\SingleInstanceScript, is_running
  if (is_running)
  {
    MsgBox, 48, Already Running, Another instance of this script is already running. This script will now exit.
    ExitApp
  }
  RegWrite, REG_DWORD, HKCU, Software\SingleInstanceScript, is_running, 1
  OnExit, delete_key
}
return

delete_key:
RegDelete, HKCU, Software\SingleInstanceScript
ExitApp


[Edit]If something happens and the script doesn't run the OnExit (computer locks up, power goes out, etc.), then you wouldn't be able to start the program without parameters without deleting the registry key, so I added a check (from Lexikos' script) so it will always delete the key if there is only 1 process running.
Code:
#SingleInstance Off
#Persistent
WinGet instances, List, %A_ScriptFullPath% ahk_class AutoHotkey
if (instances = 1)
  RegDelete, HKCU, Software\SingleInstanceScript
has_params = %0%
if (!has_params)
{
  RegRead, is_running, HKCU, Software\SingleInstanceScript, is_running
  if (is_running)
  {
    MsgBox, 48, Already Running, Another instance of this script is already running. This script will now exit.
    ExitApp
  }
  RegWrite, REG_DWORD, HKCU, Software\SingleInstanceScript, is_running, 1
  OnExit, delete_key
}
return

delete_key:
RegDelete, HKCU, Software\SingleInstanceScript
ExitApp


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: July 30th, 2011, 9:52 pm 
That seems to work. Thanks.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: August 2nd, 2011, 12:40 am 
BTW, %0% doesn't work when assigning to an object element.

Code:
oParam := Object()
oParam.hasparams = %0%

if oParam.hasparams
   msgbox True
else
   msgbox False


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: August 2nd, 2011, 4:31 am 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7503
Location: Australia
Objects are supported only in expressions.
Code:
oParam.hasparams := %false% ; false=0


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 24th, 2012, 8:11 pm 
Offline

Joined: January 29th, 2009, 9:50 pm
Posts: 483
Location: Belgium
for a compiled script you can use:
Code:
#SingleInstance off                           ; We handle instances ourselves
SingleInstance:=true   ; you can read this from a ini file
if SingleInstance
   ForceSingleInstance()
return
esc::exitapp    ; just for testing
ForceSingleInstance() {   
   Process, Exist,%A_ScriptName%               ; this allways gets the pid from the 1 instance in the ErrorLevel
   FirstInstancePID:=ErrorLevel               ; store the pid of the instance
   if (FirstInstancePID=DllCall("GetCurrentProcessId"))   ; if the first instance is this script
      return                              ; Return
   else {
         winshow,ahk_pid %FirstInstancePID% ahk_class AutoHotkeyGUI         ; show the window if hidden, you can remove this line
      winactivate,ahk_pid %FirstInstancePID% ahk_class AutoHotkeyGUI      ; Activate the first instance , you can remove this line
      exitapp                              ; we have a return for the first instance so exit the app
      }
   }

_________________
Stopwatch emdkplayer
the code i post falls under the: WTFYW-WTFPL license


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: February 13th, 2012, 6:45 am 
Offline

Joined: April 19th, 2011, 4:55 am
Posts: 298
Lexikos wrote:
Here's another method, compatible with AutoHotkey Basic:
Code:
DetectHiddenWindows On ; List all running instances of this script:
WinGet instances, List, %A_ScriptFullPath% ahk_class AutoHotkey
if (instances > 1) { ; There are 2 or more instances of this script.
    this_pid := DllCall("GetCurrentProcessId"),  closed := 0
    Loop % instances { ; For each instance,
        WinGet pid, PID, % "ahk_id " instances%A_Index%
        if (pid != this_pid) { ; If it's not THIS instance,
            WinClose % "ahk_id " instances%A_Index% ; close it.
            closed += 1
        }
    }
    MsgBox Closed %closed% instance of this script.
}
#Persistent ; Don't exit automatically for this test.
#SingleInstance Off ; Allow new instances to start.

I could simplify slightly, removing DllCall and instead comparing instances%A_Index% to A_ScriptHwnd, but then it would require AutoHotkey_L v1.1.01. :)


How could I change this so that it closes every AHK script EXCEPT itself and one SPECIFIED other script?


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC [ DST ]


Who is online

Users browsing this forum: batto, Bing [Bot], JSLover and 60 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group