This script forces the app to be singleinstance.
It handles other instances, passes the data and closses them.
1. It activates the window of the first instance when a second instance is opened.
2. It passes the commandline from the second instance to the first one.
3. it handles commandline from the first instance
4. It handles Files dropped on the GUI
Code:
#SingleInstance off ; We handle instances ourselves
if !A_iscompiled {
msgbox,you need to compile this to test, this is for a real app, not for a script
exitapp
}
ForceSingleInstance() ; force single instance ourselve
gosub,ParseCommandLine1Instance ; check the commandline
Gui, show ,w600 h50,thegui ; show a gui to see if it activates when we open a second instance
Return
ForceSingleInstance() {
global ; make commandlineparrameters accesable
local FirstInstancePID ; this is the only var used in the first instance, so i make it local
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,OnMessage(0x4A,"Receive_WM_COPYDATA") ; set the function that Get's the Commandline from 2... instances
else { ; if not the first instance(2 instance or 3 ...)
winshow,ahk_pid %FirstInstancePID% ahk_class AutoHotkeyGUI ; show the first window if hidden
winactivate,ahk_pid %FirstInstancePID% ahk_class AutoHotkeyGUI ; Activate the first window
IfEqual,0,0,ExitApp ; Exit the second istance when ,no Parameter is passed
Loop,%0% ; Loop all commandlineitems
args .= args ? "`n" %A_Index% : %A_Index% ; put them in the string, sepporated by a newline
Send_WM_COPYDATA(args,"ahk_pid" FirstInstancePID) ; send the arguments to the first instance
exitapp ; exit the second istance
}
}
Send_WM_COPYDATA(StringToSend,TargetScriptTitle) { ; from the manual, onmessage (customized by me)
VarSetCapacity(CopyDataStruct, 3*A_PtrSize, 0) ; Set up the structure's memory area.
SizeInBytes := (StrLen(StringToSend) + 1) * (A_IsUnicode ? 2 : 1)
NumPut(SizeInBytes, CopyDataStruct, A_PtrSize) ; OS requires that this be done.
NumPut(&StringToSend, CopyDataStruct, 2*A_PtrSize) ; Set lpData to point to the string itself.
A_OldDHW := A_DetectHiddenWindows ; store the curent setting for DetectHiddenWindows
DetectHiddenWindows, On ; to detect our own hidden window
SendMessage, 0x4a, 0, &CopyDataStruct,, %TargetScriptTitle% ; 0x4a is WM_COPYDATA. Must use Send not Post.
DetectHiddenWindows,%A_OldDHW% ; restore the old setting for DetectHiddenWindows
return ErrorLevel ; Return SendMessage's reply back to our caller.
}
Receive_WM_COPYDATA(wParam,lParam,Msg,hWnd ) { ; Function to handle WM_COPYDATA Message(the messages send by other instances)
global args ; make the arguments accesable to the rest of the script
A_OldDHW := A_DetectHiddenWindows ; store the curent setting for DetectHiddenWindows
DetectHiddenWindows, On ; to detect our own hidden window
WinGet, PPath, ProcessPath, ahk_id %hWnd% ; Get the path of the app that send the message
DetectHiddenWindows,%A_OldDHW% ; restore the old setting for DetectHiddenWindows
IfNotEqual,PPath,%A_ScriptFullPath%,Return,0 ; if the message is not from the second instance(the same app),Return
args := StrGet(NumGet( lParam + 8 )) ; Get the arguments
Gosub,ParseCommandLine2Instance ; call our label
Return,1 ; as to reply with a TRUE to Caller, ASAP
}
ParseCommandLine1Instance:
if (A_ThisLabel="ParseCommandLine1Instance") { ; Check if we called for parsecommandline
_0_:= 0 ; reset the array
Loop,%0% ; Loop all commandlineitems
_0_ := A_Index ,_%A_Index%_ := %A_Index% ; Increase the nr ofitems and Store this line in the next array element.
}
GuiDropFiles: ; note no return the script continues ; Catch all files droped on the application
if (A_ThisLabel="GuiDropFiles") { ; check if it is this label that was called
_0_:= 0 ; reset the array
Loop,parse, A_GuiEvent, `n ; Converting the drop files to array
_0_:=A_Index,_%A_Index%_:=A_LoopField ; Increase the nr ofitems and Store this line in the next array element.
}
ParseCommandLine2Instance: ; note no return the script continues
If (A_ThisLabel="ParseCommandLine2Instance") { ; check if it is this label that was called
_0_:= 0
Loop,parse, args, `n ; Converting the argument files to array
_0_:=A_Index,_%A_Index%_:=A_LoopField ; Increase the nr ofitems and Store this line in the next array element.
}
Loop, %_0_%
Msgbox,% A_ThisLabel ": " _%A_Index%_ ; show all arguments
Return ; this is the return for all 3 labels
GuiEscape: ; pres escape when the gui is active to hide the gui
GuiClose:
Gui, hide
Return
The
simple version (window activation only)
feel free to comment