Jump to content


Photo

Run a program or switch to an already running instance


  • Please log in to reply
18 replies to this topic

#1 deanhill1971

deanhill1971
  • Members
  • 58 posts

Posted 01 February 2006 - 12:19 PM

Maybe someone has already created a function like the following, but it's hard to meaningfully search the forum for "run", "switch", etc. :)

The following function will run a program or switch to it if already running. It shows a tray tip showing whether a run or switch is being done.

Also listed are examples where I've defined a bunch of Windows+Letter keys to open my favorite programs. So I just hit Win+T to always get to Total Commander. I think it is very handy.

; ===========================================================================
; Run a program or switch to it if already running.
;    Target - Program to run. E.g. Calc.exe or C:\Progs\Bobo.exe
;    WinTitle - Optional title of the window to activate.  Programs like
;       MS Outlook might have multiple windows open (main window and email
;       windows).  This parm allows activating a specific window.
; ===========================================================================
RunOrActivate(Target, WinTitle = "")
{
	; Get the filename without a path
	SplitPath, Target, TargetNameOnly

	Process, Exist, %TargetNameOnly%
	If ErrorLevel > 0
		PID = %ErrorLevel%
	Else
		Run, %Target%, , , PID

	; At least one app (Seapine TestTrack wouldn't always become the active
	; window after using Run), so we always force a window activate.
	; Activate by title if given, otherwise use PID.
	If WinTitle <> 
	{
		SetTitleMatchMode, 2
		WinWait, %WinTitle%, , 3
		TrayTip, , Activating Window Title "%WinTitle%" (%TargetNameOnly%)
		WinActivate, %WinTitle%
	}
	Else
	{
		WinWait, ahk_pid %PID%, , 3
		TrayTip, , Activating PID %PID% (%TargetNameOnly%)
		WinActivate, ahk_pid %PID%
	}


	SetTimer, RunOrActivateTrayTipOff, 1500
}

; Turn off the tray tip
RunOrActivateTrayTipOff:
	SetTimer, RunOrActivateTrayTipOff, off
	TrayTip
Return




; Example uses...
#b::RunOrActivate("C:\Program Files\Seapine\TestTrack Pro\TestTrack Pro Client.exe")
#c::RunOrActivate("control panel")
#d::RunOrActivate("cmd.exe")
#g::RunOrActivate("regedit.exe")
#i::Run, iexplore.exe
#n::RunOrActivate("uedit32.exe")

; Outlook can have multiple child windows, so specify which window to activate
#o::RunOrActivate("C:\Program Files\Microsoft Office\OFFICE11\OUTLOOK.EXE", "Microsoft Outlook")

#p::RunOrActivate("C:\Program Files\Perforce\P4Win.exe")
#q::RunOrActivate("C:\Program Files\Microsoft Visual Studio\COMMON\MSDev98\Bin\MSDEV.EXE", "Microsoft Visual")
#t::RunOrActivate("C:\Program Files\totalcmd\totalcmd.exe")
#y::RunOrActivate("wmplayer.exe")
#-::RunOrActivate("mspaint.exe")
#=::RunOrActivate("calc.exe")


#2 ahoover

ahoover
  • Members
  • 3 posts

Posted 17 February 2009 - 05:38 PM

This is a great script. I ran into one little problem when I wanted to run or activate a specific file that is open. For example, when I am editing the Autohotkey.ahk file, and other scripts in notepad, I had trouble getting it to go to the correct script I wanted. So, I added another optional input variable for the parameters to open.

; ===========================================================================
; Run a program or switch to it if already running.
;    Target - Program to run. E.g. Calc.exe or C:\Progs\Bobo.exe
;    WinTitle - Optional title of the window to activate.  Programs like
;    MS Outlook might have multiple windows open (main window and email
;    windows).  This parm allows activating a specific window.
; ===========================================================================

RunOrActivate(Target, WinTitle = "", Parameters = "")
{
   ; Get the filename without a path
   SplitPath, Target, TargetNameOnly

   Process, Exist, %TargetNameOnly%
   If ErrorLevel > 0
      PID = %ErrorLevel%
   Else
      Run, %Target% "%Parameters%", , , PID

   ; At least one app (Seapine TestTrack wouldn't always become the active
   ; window after using Run), so we always force a window activate.
   ; Activate by title if given, otherwise use PID.
   If WinTitle <> 
   {
      SetTitleMatchMode, 2
      WinWait, %WinTitle%, , 3
      TrayTip, , Activating Window Title "%WinTitle%" (%TargetNameOnly%)
      WinActivate, %WinTitle%
   }
   Else
   {
      WinWait, ahk_pid %PID%, , 3
      TrayTip, , Activating PID %PID% (%TargetNameOnly%)
      WinActivate, ahk_pid %PID%
   }


   SetTimer, RunOrActivateTrayTipOff, 1
}

; Turn off the tray tip
RunOrActivateTrayTipOff:
   SetTimer, RunOrActivateTrayTipOff, off
   TrayTip
Return

;example to run or activate the specific script, "Autohotkey"
^!+a::RunorActivate("notepad.exe", "AutoHotkey", "C:\Documents and Settings\ahoover.autotool\My Documents\AutoHotkey.ahk")


#3 Laszlo

Laszlo
  • Fellows
  • 4713 posts

Posted 18 February 2009 - 12:19 AM

You don't have to turn off TrayTip: it disappears by itself at most after 30 sec.

#4 s.newave

s.newave
  • Members
  • 6 posts

Posted 12 March 2009 - 09:40 PM

Really great script although i am trying to add a feature whereby if the the window is active and focused and the hotkey is pressed again then another instance of that target is launched. For example sometimes i prefer to launch another firefox browser window instead of using the same one so i would hit the hotkey to activate/launch firefox and then hit it again to launch a second window etc.. Should be very simple although with ahk and cant get this to work:

; ===========================================================================
; Run a program or switch to it if already running.
;    Target - Program to run. E.g. Calc.exe or C:\Progs\Bobo.exe
;    WinTitle - Optional title of the window to activate.  Programs like
;    MS Outlook might have multiple windows open (main window and email
;    windows).  This parm allows activating a specific window.
; ===========================================================================

RunOrActivate(Target, WinTitle = "", Parameters = "")
{
   ; Get the filename without a path
   SplitPath, Target, TargetNameOnly
	 
    IfWinActive, %WinTitle%
     {
     Run %Target%
     Return
     }
	 
   Process, Exist, %TargetNameOnly%
   If ErrorLevel > 0
      PID = %ErrorLevel%
   Else
      Run, %Target% "%Parameters%", , , PID

   ; At least one app (Seapine TestTrack wouldn't always become the active
   ; window after using Run), so we always force a window activate.
   ; Activate by title if given, otherwise use PID.
   If WinTitle <>
   {
      SetTitleMatchMode, 2
      WinWait, %WinTitle%, , 3
      ;TrayTip, , Activating Window Title "%WinTitle%" (%TargetNameOnly%)
      WinActivate, %WinTitle%
   }
   Else
   {
      WinWait, ahk_pid %PID%, , 3
      ;TrayTip, , Activating PID %PID% (%TargetNameOnly%)
      WinActivate, ahk_pid %PID%
   }


   ;SetTimer, RunOrActivateTrayTipOff, 1
}

; Turn off the tray tip
RunOrActivateTrayTipOff:
   SetTimer, RunOrActivateTrayTipOff, off
   TrayTip
Return

;example to run or activate the specific script, "Autohotkey"
;^!+a::RunorActivate("notepad.exe", "AutoHotkey", "C:\Documents and Settings\ahoover.autotool\My Documents\AutoHotkey.ahk")
#;::RunOrActivate("C:\Program Files\Mozilla Firefox\firefox.exe", "Mozilla Firefox", "")

Any ideas?

#5 greynite

greynite
  • Members
  • 40 posts

Posted 01 April 2009 - 05:07 PM

SetTitleMatchMode, 2

is your bugaboo. It's set down in line 15 or so -- set it instead before your IfWinActive

Cheers,
Shawn

#6 s.newave

s.newave
  • Members
  • 6 posts

Posted 01 April 2009 - 05:38 PM

That was it. Thx!!

#7 sanitizer

sanitizer
  • Members
  • 8 posts

Posted 19 September 2009 - 04:30 AM

hi, i want to launch "my document" so i want to put like:

runoractivate(%A_MyDocuments%)

but it gives me error

Run, %Target% "Parameters%",,,PID

I don't want to use the long path because I thought on using on another computer.

Thanks

#8 sanitizer

sanitizer
  • Members
  • 8 posts

Posted 19 September 2009 - 05:10 AM

nah nervermind...

i used

Run %A_MyDocuments%

instead.

#9 widow

widow
  • Guests

Posted 27 September 2009 - 07:53 PM

I found this in my collection of assembler source's. Dont know if you want it
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;                                          1Run (1 IMPORT in compiled exe)     

;Assembled with MASM32.

;

.386

.model flat,stdcall

option casemap:none



 include \masm32\include\windows.inc

 include \masm32\macros\macros.asm

 INCX user32 , kernel32

 include genmacro.inc



sSEH STRUCT

	OrgEsp            DD ?

	OrgEbp            DD ?

	SaveEip           DD ?

sSEH ENDS



MIN_KERNEL_SEARCH_BASE      EQU 070000000h

MAX_API_STRING_LENGTH       EQU 150

MUTEX_ALL_ACCESS            EQU 1F0001h

CREATE_DEFAULT_ERROR_MODE   EQU 04000000h



.CONST

;szGetCommandLineA      DB "GetCommandLineA",0

szCreateProcessA         DB "CreateProcessA",0

szOpenMutexA             DB "OpenMutexA",0

szCreateMutexA           DB "CreateMutexA",0

szGetStartupInfoA        DB "GetStartupInfoA",0

szLoadLibrary            DB "LoadLibraryA",0

szGetProcAddress         DB "GetProcAddress",0

szExitProcess            DB "ExitProcess",0



szUser32                 DB "user32",0

szMessageBox             DB "MessageBoxA",0



.data

DATAFOR General Use

;_GetCommandLineA             DD NULL

_CreateProcessA              DD NULL

_OpenMutexA                  DD NULL

_CreateMutexA                DD NULL

_GetStartupInfoA             DD NULL

_LoadLibrary                 DD NULL

_GetProcAddress              DD NULL

_ExitProcess                 DD NULL

_MessageBox                  DD NULL



SEH                          sSEH   <NULL>

dwKernelBase                 DD NULL

dwUserBase                   DD NULL



paramCount                   DD NULL

paramPtr                     DD NULL

usageString     DB  "1RUN <applicationame> [application command line parameters]",10,0



.data?

RUNTIMEDATA for General Use

hInstance       DD      ?

commandLinePtr  LPSTR   ?



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DATAFOR multiple instance blocking ;;;;;;;;;;;;;;;;;;

mutexAttributes SECURITY_ATTRIBUTES <sizeof SECURITY_ATTRIBUTES,NULL,TRUE>



;        CODE START              ;

.code

	; -- PEID SAYS: Ding Boy's PE-lock Phantasm v1.0 / v1.1  --

      @@: 

      db 055h,057h,056h,052h,051h,053h,066h,081h,0C3h,0EBh,002h,\    ; FAKE 'OEP'

         0EBh,0FCh,066h,081h,0C3h,0EBh,002h,0EBh,0FCh,\

         088h,088h,088h,088h,088h,088h                               ; {POP EAX}*6

      ret 4

      nops 5

main: 

	ASSUME FS : NOTHING

      PUSH [ESP]

	CALL GetKernelBase

	 OR   EAX, EAX

	 JZ   @B

	MOV  dwKernelBase, EAX



START_SEH RETURN_HOME           ; ---- START SEH FRAME ---



        ;---- Why not make it look like a normal prog? ----



@@: wcall GetCommandLineA

     mov commandLinePtr,EAX

SHUT_SEH                        ; ---- STOP SEH FRAME ---



    call splitCommandLine

    mov paramCount, eax

    push eax



CHKAPPDBG:                      ; --- (LAJM #1) ---

        mov     eax,fs:[30h]    ; pointer to PEB

        movzx   eax,byte ptr [eax+2h]

        or      al,al

        jz      @f

        RET

     mov  eax,dword ptr fs:[20h]          ; #2

     or   eax,eax

     jNz   @f

     



@@:  ;---- GET SOME KERNEL API ADDRESSES  -----

LOAD_UP_API szLoadLibrary,       _LoadLibrary,      dwKernelBase

LOAD_UP_API szGetProcAddress,    _GetProcAddress,   dwKernelBase

;LOAD_UP_API szGetCommandLineA,   _GetCommandLineA,  dwKernelBase

LOAD_UP_API szCreateProcessA,    _CreateProcessA,   dwKernelBase

LOAD_UP_API szOpenMutexA,        _OpenMutexA,       dwKernelBase

LOAD_UP_API szCreateMutexA,      _CreateMutexA,     dwKernelBase

LOAD_UP_API szGetStartupInfoA,   _GetStartupInfoA,  dwKernelBase

LOAD_UP_API szExitProcess,       _ExitProcess,      dwKernelBase



	;---- LOAD USER32.DLL ----

mycall _LoadLibrary,OFFSET szUser32

    OR EAX,EAX

    JZ   QUIT

    MOV  dwUserBase, EAX

	;---- GET SOME MORE API ADDRESSES ----

LOAD_UP_API szMessageBox,       _MessageBox,      dwUserBase

;____

    ;

    ; Check for previous instance.

    ;

   mycall _OpenMutexA, MUTEX_ALL_ACCESS,FALSE, commandLinePtr



    .if eax != NULL ;another instance is already running

        jmp endme

    .endif

    ;

    ; Create Mutex to let other One Run instances know you're already here.

    ;

   mycall _CreateMutexA, offset mutexAttributes, TRUE, commandLinePtr

    pop eax

    .if eax !=0

        mycall WinMain, hInstance,NULL,commandLinePtr, SW_SHOWDEFAULT

    .else

        szText LmTitle2,"1RUN USAGE!"

        mycall _MessageBox ,NULL,offset  usageString, OFFSET LmTitle2, MB_OK

    .endif

endme:

              xor eax,eax

QUIT: SHUT_SEH

RETURN_HOME: mycall _ExitProcess,NULL       ; LEAVE IT!

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:dword ;;;;;;;;

        RUNTIMEDATA for start up info ;;

        startUp STARTUPINFO <>



        RESUMECODE

        mycall _GetStartupInfoA, offset startUp



        RUNTIMEDATA for proc info ;;;;;;

        unusedProcInfo PROCESS_INFORMATION <>



        RESUMECODE

          mycall _CreateProcessA, NULL, paramPtr, NULL, NULL, TRUE, \

                         CREATE_DEFAULT_ERROR_MODE, NULL, NULL, offset startUp,\

                         offset unusedProcInfo

        .if eax==FALSE

          mycall _MessageBox ,NULL, OFFSET usageString, NULL, MB_OK \

                        or MB_APPLMODAL or MB_ICONWARNING

        .endif

        returnzero

WinMain endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

splitCommandLine: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DATAFOR splitCommandLine

paramListPtr dd NULL

RESUMECODE

    push ebx

    push esi    

    xor edx,edx  ;clear parameter counter

    mov esi,commandLinePtr

   call skipSpacesAndTabs

     mov bl, ' '

    .if byte ptr [esi] == '"'

        mov bl,'"'

        inc esi

    .endif

    mov commandLinePtr, esi

   call findChar

    .if byte ptr [esi] == 0 

        jmp commandLineSplit

    .endif

     mov byte ptr [esi], 0

    inc esi

   call skipSpacesAndTabs

    .if byte ptr [esi] == 0

        jmp commandLineSplit

    .endif

     mov edx, 1

     mov paramPtr, esi

commandLineSplit:

pop esi

pop ebx

mov eax, edx

ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

skipSpacesAndTabs: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        lodsb

        cmp al,' '

        je skipSpacesAndTabs

        cmp al, 9

        je skipSpacesAndTabs

    dec esi

ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

findChar: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    lodsb

    cmp al, 0

    je findCharDone

    cmp al, bl

    jne findChar

findCharDone:

    dec esi

    ret

INCLUDE KERN_SHIT.ASM

end main





#10 Guests

  • Guests

Posted 29 September 2009 - 03:22 PM

Can this be used to run batch files instead of exe programs as well?

#11 Meetloaf

Meetloaf
  • Members
  • 46 posts

Posted 13 August 2010 - 05:44 AM

I want to thank you for this GEM! It is especially useful when running older applications.

For me, it's MoffSoftCalculator, kept throwing me an error about an instance already running. I said to myself...I wonder if there's an AHK remedy for that?

...voila

Thanks again!

#12 medusa

medusa
  • Guests

Posted 06 January 2011 - 05:50 PM

Thanks for this script! It's very useful to me.

I'm brand new to auto hot key, so please forgive me if this question has already been answered.

I would like a modified version of this script that will switch between multiple open instances if the hotkey is pressed again. For example, suppose you have 2 firefox instances open. Pressing the hotkey once will switch to one of the instances, and pressing it again will switch to the next one. Does this exist, or is there an easy way to modify this script to do it?

#13 comvox

comvox
  • Members
  • 137 posts

Posted 07 January 2011 - 03:20 AM

I would like a modified version of this script that will switch between multiple open instances if the hotkey is pressed again. For example, suppose you have 2 firefox instances open. Pressing the hotkey once will switch to one of the instances, and pressing it again will switch to the next one. Does this exist, or is there an easy way to modify this script to do it?


The WinActivateBottom command is made to order for this. It is described as

Same as WinActivate except that it activates the bottommost (least recently active) matching window rather than the topmost.

See http://www.autohotke...ivateBottom.htm.

For example, if you want to rotate between several different instances of wordpad, one could have something like the following somewhere in one's script (use the hotkey you want)

^!x::
If Instr(Title,"WordPad")>0
      WinActivateBottom, WordPad
Return

This type of thing could be integrated with the other code. One could have something like the following:

SetTitleMatchMode,2
^!x::
WinGetActiveTitle, Title

If Instr(Title,"WordPad")>0
      WinActivateBottom, WordPad
Else
      RunOrActivate("WordPad.exe","WordPad")
Return

; Then the coding for the RunOrActivate function, taken from the earlier postings.

RunOrActivate(Target, WinTitle = "") 
{ 
   ; Get the filename without a path 
   SplitPath, Target, TargetNameOnly 

   Process, Exist, %TargetNameOnly% 
   If ErrorLevel > 0 
      PID = %ErrorLevel% 
   Else 
      Run, %Target%, , , PID 

   ; At least one app (Seapine TestTrack wouldn't always become the active 
   ; window after using Run), so we always force a window activate. 
   ; Activate by title if given, otherwise use PID. 
   If WinTitle <> 
   { 
      SetTitleMatchMode, 2 
      WinWait, %WinTitle%, , 3 
      TrayTip, , Activating Window Title "%WinTitle%" (%TargetNameOnly%) 
      WinActivate, %WinTitle% 
   } 
   Else 
   { 
      WinWait, ahk_pid %PID%, , 3 
      TrayTip, , Activating PID %PID% (%TargetNameOnly%) 
      WinActivate, ahk_pid %PID% 
   } 


   SetTimer, RunOrActivateTrayTipOff, 1500 
} 

; Turn off the tray tip 
RunOrActivateTrayTipOff: 
   SetTimer, RunOrActivateTrayTipOff, off 
   TrayTip 
Return


#14 medusa

medusa
  • Guests

Posted 25 January 2011 - 10:42 PM

Thanks so much for the helpful suggestions! Thanks to your pointers I am figuring this out.

I have a couple questions I haven't sorted out yet:

1. When a program is running and shows an icon in the notification area but doesn't have a window, my script doesn't open up a window for it. (This is in Windows, in case that wasn't obvious.) For example, Skype and Truecrypt spend much of their time running without windows, just with notification icons. Is there a way to make my script open up a window in this case?

2. I would like some of my shortcuts to open or switch to a windows explorer window for a specific folder path. What do I need to learn to add this?

3. My script seems to break the default behavior of Windows Key-L, to lock the screen. I haven't set Win-L to be something else in my script; if I turn off autohotkey I get Win-L working to lock the screen again. Any suggestions?

Here's my modified code, which seems to mostly work. I made a change to do the switching based on the ClassID because using the PID alone doesn't work (when there are multiple processes of the same program running).
RunActivateOrSwitch(Target, WinTitle = "")
{
   ; Get the filename without a path
   SplitPath, Target, TargetNameOnly

   ; Process returns the PID of a matching process exists, or 0 otherwise
   Process, Exist, %TargetNameOnly%
   ; Get the PID and the class if the process is already running
   If ErrorLevel > 0
   {
      PID = %ErrorLevel%
      WinGetClass, ClassID, ahk_pid %PID%
   }
   ; Run the program if the process is not already running
   Else
      Run, %Target%, , , PID

   ; At least one app  wouldn't always become the active
   ; window after using Run, so we always force a window activate.
   ; Activate by title if given, otherwise use class ID. Activating by class ID 
   ; appears more robust for switching than using PID.
   If WinTitle <>
   {
      SetTitleMatchMode, 2
      WinWait, %WinTitle%, , 3
      IfWinActive, %WinTitle%
	WinActivateBottom, %WinTitle%
      Else
	WinActivate, %WinTitle%
   }
   Else
   {
      WinWait, ahk_class %ClassID%, , 3
      IfWinActive, ahk_class %ClassID%
           WinActivateBottom, ahk_class %ClassID%
      Else
	WinActivate, ahk_class %ClassID%
   }
}


#15 medusa

medusa
  • Guests

Posted 08 March 2011 - 10:12 PM

I still haven't figured out the answers to these questions I posted in January. If anyone has suggestions, I would love to hear them.