The Unofficial Macro Scheduler Puzzler of the Week 5
Moderators: JRL, Dorian (MJT support)
The Unofficial Macro Scheduler Puzzler of the Week 5
This weeks puzzler is all about tidiness.
There are multiple examples on this forum showing how to prevent a script or executable from running twice by testing to see that a program with the same name is already running, then closing the newly started program.
However, its a puzzler how one would compose a program to prevent that program from running twice by testing to see that a program with the same name is already running, then close the original program and let the newly started program continue running.
In other words, write a program that you run as instance A, when you start instance B of the same program instance A is closed and instance B continues. When instance C is started, instance B is closed and instance C continues. Etc. Etc. Thus, functionally, there is only a fraction of a second when there is more than one copy of the program running.
Make sense? Sound easy?... Maybe it is. 20 rep points and bragging rights to the cleanest shortest method submitted by next Friday.
There are multiple examples on this forum showing how to prevent a script or executable from running twice by testing to see that a program with the same name is already running, then closing the newly started program.
However, its a puzzler how one would compose a program to prevent that program from running twice by testing to see that a program with the same name is already running, then close the original program and let the newly started program continue running.
In other words, write a program that you run as instance A, when you start instance B of the same program instance A is closed and instance B continues. When instance C is started, instance B is closed and instance C continues. Etc. Etc. Thus, functionally, there is only a fraction of a second when there is more than one copy of the program running.
Make sense? Sound easy?... Maybe it is. 20 rep points and bragging rights to the cleanest shortest method submitted by next Friday.
Professor JRL,
Please evalute my humble code:
Thanks.
Please evalute my humble code:
Code: Select all
// POI=program of interest
Let>poi=abc.exe
ProcessExist>%poi%,r
If>r=True
KillProcess>%poi%
Endif
Run>%poi%
- Grovkillen
- Automation Wizard
- Posts: 1132
- Joined: Fri Aug 10, 2012 2:38 pm
- Location: Bräcke, Sweden
- Contact:
Hello!
I would make sure that the process I want to kill isn't my current process. So, I would need to kill the process using PID (process id) instead of only the name "app_name.exe".
Here's my solution:
I open 10 Notepad just to demonstrate the consept. I then get my current PID using a Kernel32 function. After that I call for every process named the same as my current app, the result is put to the clipboard and then RegExed into an array. After that all but the current process is killed one by one...
The wanted RegEx pattern seems not to be supported by MS but if it did work this is how it's built up:
REGEX_PATTERN=(?<=%APP_TITLE%\.exe[\s]*)[0-9]{3,5}
Explained:
( : start of match
?<= : tell to start "capture" after match is found
%APP_TITLE%\.exe : what to match (exact match of "Notepad.exe" " . " is any character in RegEx " \. " indicate that the " . " should be matched as a dot)
[\s]* : \s indicates that none printed character should be match (i.e. the spaces between the process name and the PID). the " * " make sure to find 0 to infinite number of none printed characters.
) : end of match
below is what to capture
[0-9] : this tells that only numbers 0 to 9 should be captured
{3,5} : this tells that capture 3 to 5 characters, discard the other (shorter or longer strings of numbers)
Super trick
cmd /c Tasklist /FI "Imagename eq %APP_TITLE%.exe" | clip
The " | clip " at the end of any cmd will put the output to the clipboard. Super handy if you ask me!
EDIT: I have found that the MS RegEx flavor is Perl 5.10 and the " * " is not compatable with Perl RegEx. In order to fix this I need to know how many none printed characters it is between the app title and the PID. In the case with "notepad.exe" this is 19. The RegEx pattern should then say:
REGEX_PATTERN=(?<=%APP_TITLE%\.exe[\s]{19})[0-9]{3,5}
I would make sure that the process I want to kill isn't my current process. So, I would need to kill the process using PID (process id) instead of only the name "app_name.exe".
Here's my solution:
Code: Select all
//Set example to Notepad just to demonstrate the idea
Let>APP_TITLE=Notepad
//Open a bunch of Notepads to close
Let>k=0
Repeat>k
Let>k=k+1
RunProgram>%APP_TITLE%.exe
Until>k=10
//Determine what your current process id (PID) is and all other id with the same app title = already running = need to be killed
LibFunc>Kernel32,GetCurrentProcessId,CURRENT_PROCESS_ID
//Get the other PID (" | clip " at the end of the cmd line is used to put outpot to clipboard...)
Let>RP_WAIT=1
RunProgram>cmd /c Tasklist /FI "Imagename eq %APP_TITLE%.exe" | clip
GetClipBoard>CLIPBOARD,0
//RegEx the result... MS seems to lack some RegEx logics (see comments below). I wish it didn't since that would help me find the correct values with more precision
Let>REGEX_PATTERN=[0-9]{4,5}
//Below doesn't work... I'm not sure why but the " (?<=%APP_TITLE%\.exe[\s]*) " would be nice to use in order to be sure that only the PID is collected and NOT the Memory useage...
//Let>REGEX_PATTERN=(?<=%APP_TITLE%\.exe[\s]*)[0-9]{3,5}
RegEx>%REGEX_PATTERN%,%CLIPBOARD%,0,ARRAY_TO_CLOSE,NUM_MATCHES,0,,
//Kill all other running running processes (with the same app title)
Let>k=0
Repeat>k
Let>k=k+1
If>ARRAY_TO_CLOSE_%k%=%CURRENT_PROCESS_ID%
//Do not kill process...
Else>
KillProcess>ARRAY_TO_CLOSE_%k%
Endif>
Until>k=NUM_MATCHES
The wanted RegEx pattern seems not to be supported by MS but if it did work this is how it's built up:
REGEX_PATTERN=(?<=%APP_TITLE%\.exe[\s]*)[0-9]{3,5}
Explained:
( : start of match
?<= : tell to start "capture" after match is found
%APP_TITLE%\.exe : what to match (exact match of "Notepad.exe" " . " is any character in RegEx " \. " indicate that the " . " should be matched as a dot)
[\s]* : \s indicates that none printed character should be match (i.e. the spaces between the process name and the PID). the " * " make sure to find 0 to infinite number of none printed characters.
) : end of match
below is what to capture
[0-9] : this tells that only numbers 0 to 9 should be captured
{3,5} : this tells that capture 3 to 5 characters, discard the other (shorter or longer strings of numbers)
Super trick
cmd /c Tasklist /FI "Imagename eq %APP_TITLE%.exe" | clip
The " | clip " at the end of any cmd will put the output to the clipboard. Super handy if you ask me!

EDIT: I have found that the MS RegEx flavor is Perl 5.10 and the " * " is not compatable with Perl RegEx. In order to fix this I need to know how many none printed characters it is between the app title and the PID. In the case with "notepad.exe" this is 19. The RegEx pattern should then say:
REGEX_PATTERN=(?<=%APP_TITLE%\.exe[\s]{19})[0-9]{3,5}
Wow... woke up this morning to two puzzler responses. I'm going to need to fix a cup of tea and study these....
@armsys,
Short and sweet but unfortunately I don't see how this will work properly unless your program is named something other than "abc.exe" which defeats the puzzlement. When we run the program named "abc.exe", line five, KillProcess>, will kill all instances of "abc.exe" which includes the currently running program. "abc.exe" will never reach line seven to start the program back up again.
@Grovkillen,
You have demonstrated a method to kill multiple processes, but you did not provide a program that manages its own occurrences. I do feel you are on the right track.
P.S. I like clip too. Though I don't think it was available until Vista? or maybe Win7. In any case its not available in WinXP. But it was available in Windows server software as far back as NT so you could copy the executable over to XP and use it.
@armsys,
Short and sweet but unfortunately I don't see how this will work properly unless your program is named something other than "abc.exe" which defeats the puzzlement. When we run the program named "abc.exe", line five, KillProcess>, will kill all instances of "abc.exe" which includes the currently running program. "abc.exe" will never reach line seven to start the program back up again.
@Grovkillen,
You have demonstrated a method to kill multiple processes, but you did not provide a program that manages its own occurrences. I do feel you are on the right track.
P.S. I like clip too. Though I don't think it was available until Vista? or maybe Win7. In any case its not available in WinXP. But it was available in Windows server software as far back as NT so you could copy the executable over to XP and use it.
JRL,
Thanks for your sweet words. How about the folloing code:
Thanks for your sweet words. How about the folloing code:
Code: Select all
// POI=program of interest
Let>poi=abc.exe
ProcessExist>%poi%,r
If>r=True
KillProcess>%poi%
WaitProcessTerminated>%poi%
Endif
ProcessExist>%poi%,r
If>r=False
Run>%poi%
Endif
Here is my method.
Edited: Shortened script from 15 to 13 lines.
Edited: Shortened script from 15 to 13 lines.
Code: Select all
IfWindowOpen>~!My App Is Running!~
CloseWindow>~!My App Is Running!~
Endif
Dialog>Dialog100
Caption=~!My App Is Running!~
EndDialog>Dialog100
AddDialogHandler>Dialog100,,OnClose,ExitScript
Label>ActionLoop
Wait>0.1
Goto>ActionLoop
SRT>ExitScript
Exit>1
END>ExitScript
Last edited by Rain on Mon Oct 14, 2013 2:15 pm, edited 1 time in total.
@armsys,
Exactly the same issue. If the value of variable "poi" is the name of your program, ProcessExist>%poi%,r will always test "True", then the KillProcess line will always put an end to the program's process. Its exactly the same as putting in an Exit>.
This concept is flawed. Some form of excluding the current process will be required.
@Rain,
Good job! It works and meets the criteria.
@everone else
Any other ideas?
Exactly the same issue. If the value of variable "poi" is the name of your program, ProcessExist>%poi%,r will always test "True", then the KillProcess line will always put an end to the program's process. Its exactly the same as putting in an Exit>.
This concept is flawed. Some form of excluding the current process will be required.
@Rain,
Good job! It works and meets the criteria.
@everone else
Any other ideas?
- Grovkillen
- Automation Wizard
- Posts: 1132
- Joined: Fri Aug 10, 2012 2:38 pm
- Location: Bräcke, Sweden
- Contact:
Here's an updated script, compile as "Puzzler5.exe" and try to make it break...
@Rain: good job!
@Rain: good job!

Code: Select all
//Name of app
Let>APP_TITLE=Puzzler5
Dialog>Dialog1
object Dialog1: TForm
Left = 247
Top = 96
HelpContext = 5000
BorderIcons = [biSystemMenu]
Caption = 'CustomDialog'
ClientHeight = 93
ClientWidth = 623
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = True
ShowHint = True
OnTaskBar = False
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 8
Top = 16
Width = 125
Height = 57
Alignment = taCenter
Caption = 'Label1'
Font.Charset = ANSI_CHARSET
Font.Color = clBlack
Font.Height = -48
Font.Name = 'Arial Narrow'
Font.Style = [fsBold]
ParentFont = False
end
end
EndDialog>Dialog1
SetDialogProperty>Dialog1,Label1,Caption,I'M THE ONLY APP RUNNING :)
AddDialogHandler>Dialog1,,OnClose,EXIT_APP
//Determine what your current process id (PID) is
LibFunc>Kernel32,GetCurrentProcessId,CURRENT_PROCESS_ID
SetDialogProperty>Dialog1,,Caption,%APP_TITLE% (PID: %CURRENT_PROCESS_ID%)
//Get the other PID (" | clip " at the end of the cmd line is used to put outpot to clipboard...)
Let>RP_WAIT=1
RunProgram>cmd /c Tasklist /FI "Imagename eq %APP_TITLE%.exe" | clip
GetClipBoard>CLIPBOARD,0
//RegEx the result...
Let>REGEX_PATTERN=(?<=[\s]{5})[0-9]{3,5}
RegEx>%REGEX_PATTERN%,%CLIPBOARD%,0,ARRAY_TO_CLOSE,NUM_MATCHES,0,,
Show>Dialog1
If>NUM_MATCHES>1
//Kill all other running running processes (with the same app title)
Let>k=0
Repeat>k
Let>k=k+1
If>ARRAY_TO_CLOSE_%k%=%CURRENT_PROCESS_ID%
//Do not kill process...
Else>
//This text will unlikely be seen but anyways...
SetDialogProperty>Dialog1,Label1,Caption,CLOSING OLD APP
KillProcess>ARRAY_TO_CLOSE_%k%
SetDialogProperty>Dialog1,Label1,Caption,I'M THE ONLY APP RUNNING :)
Endif>
Until>k=NUM_MATCHES
Endif>
Label>WAIT_FOR_AWHILE
Wait>0.02
GoTo>WAIT_FOR_AWHILE
SRT>EXIT_APP
Exit>0
END>EXIT_APP
CRUD! OOPS. It appears Rain already did this. I wasn't paying attention very well. This entry is INVALID. Sorry.
GREAT IDEA, Rain. Plus I didn't think of gutting the dialog. So Rain would still have won.
Rain,
Did you steal my idea before I thought of it? Shame. Shame. Shame.
************************************************************
ORIGINAL POST / BUT INVALID
It's meeeee. Hello.
I'm sure Friday already came and went. But just for fun, this is what I thought of. JRL and I spoke of this M.O. some time back.
Do you remember JRL?
Anyway, check it out. Would this have qualified or did I miss something?
Actually, I believe the idea was JRL's for another application that we were then asked not to discuss on the forum. (The Three Musketeers)
PepsiHog
GREAT IDEA, Rain. Plus I didn't think of gutting the dialog. So Rain would still have won.
Rain,
Did you steal my idea before I thought of it? Shame. Shame. Shame.

************************************************************
ORIGINAL POST / BUT INVALID
It's meeeee. Hello.
I'm sure Friday already came and went. But just for fun, this is what I thought of. JRL and I spoke of this M.O. some time back.
Do you remember JRL?
Anyway, check it out. Would this have qualified or did I miss something?
Code: Select all
GetWindowHandle>Program Name Here*,winhan
let>win_usehandle=1
IfWindowOpen>%winhan%
CloseWindow>winhan
endif
Dialog>Dialog1
object Dialog1: TForm
Left = 251
Top = 104
HelpContext = 5000
BorderIcons = [biSystemMenu]
Caption = 'Program Name Here'
ClientHeight = 27
ClientWidth = 115
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = True
ShowHint = True
OnTaskBar = False
PixelsPerInch = 96
TextHeight = 13
end
EndDialog>Dialog1
AddDialogHandler>Dialog1,,OnClose,DoExit
....Do something.....
let>NeverEnding=0
While>NeverEnding=0
// This would be the "Do Something" part.
// Does not really need to be a loop.
// Could be anything.
EndWhile
srt>DoExit
mdl>New Instance Running...GoodBye.
exit
END>DoExit
PepsiHog
Windows 7
PepsiHog. Yep! I drink LOTS of Pepsi (still..in 2024) AND enjoy programming. (That's my little piece of heaven!)
The immensity of the scope of possibilities within Macro Scheduler pushes the user beyond just macros!
PepsiHog. Yep! I drink LOTS of Pepsi (still..in 2024) AND enjoy programming. (That's my little piece of heaven!)
The immensity of the scope of possibilities within Macro Scheduler pushes the user beyond just macros!
Hello again,
So far as I can tell this will work perfectly. Did I do something that's not allowed?
Only 12 lines of code.
See if it works,
PepsiHog
So far as I can tell this will work perfectly. Did I do something that's not allowed?
Code: Select all
TimeStamp>%Temp_Dir%\Stop.txt,
OnEvent>File_Exists,%Temp_Dir%\Stop.txt,0,RemoveFile
OnEvent>File_Exists,%Temp_Dir%\Stop.txt,0,
OnEvent>File_Exists,%Temp_Dir%\Stop.txt,0,DoExit
// Do Something Here............
While>NeverEnding<>1
EndWhile
srt>RemoveFile
DeleteFile>%Temp_Dir%\Stop.txt
END>RemoveFile
srt>DoExit
exit
END>DoExit
See if it works,
PepsiHog
Windows 7
PepsiHog. Yep! I drink LOTS of Pepsi (still..in 2024) AND enjoy programming. (That's my little piece of heaven!)
The immensity of the scope of possibilities within Macro Scheduler pushes the user beyond just macros!
PepsiHog. Yep! I drink LOTS of Pepsi (still..in 2024) AND enjoy programming. (That's my little piece of heaven!)
The immensity of the scope of possibilities within Macro Scheduler pushes the user beyond just macros!
@PepsiHog
Your concept is good. I had to make a small mod to make it work on my computer.
PepsiHog's script rearranged for line counting clarity and slightly modified.
@Rain and PepsiHog,
Even though I had to take liberties with PepsiHog's to make it work for me, I think the concept is good. Both scripts have the same number of lines so I think I'm going to split the points and call you both winners.
Congrats to both of you.
Rain's script rearranged for line counting clarity.
Edit - Fixed the error I made in Rain's script. Sorry Rain. Can't even imagine how I did that, might make a good puzzler if it could be explained.
Your concept is good. I had to make a small mod to make it work on my computer.
PepsiHog's script rearranged for line counting clarity and slightly modified.
Code: Select all
TimeStamp>%Temp_Dir%\Stop.txt,
OnEvent>File_Exists,%Temp_Dir%\Stop.txt,0,RemoveFile
Wait>0.1
OnEvent>File_Exists,%Temp_Dir%\Stop.txt,0,DoExit
srt>RemoveFile
DeleteFile>%Temp_Dir%\Stop.txt
END>RemoveFile
srt>DoExit
exit
END>DoExit
Label>Loop
Wait>0.01
Goto>Loop
@Rain and PepsiHog,
Even though I had to take liberties with PepsiHog's to make it work for me, I think the concept is good. Both scripts have the same number of lines so I think I'm going to split the points and call you both winners.
Congrats to both of you.
Rain's script rearranged for line counting clarity.
Code: Select all
IfWindowOpen>~!My App Is Running!~
CloseWindow>~!My App Is Running!~
EndIf
Dialog>Dialog100
Caption=~!My App Is Running!~
EndDialog>Dialog100
AddDialogHandler>Dialog100,,OnClose,ExitScript
SRT>ExitScript
Exit>1
END>ExitScript
Label>Loop
Wait>0.01
Goto>Loop
Edit - Fixed the error I made in Rain's script. Sorry Rain. Can't even imagine how I did that, might make a good puzzler if it could be explained.
Last edited by JRL on Sun Oct 20, 2013 1:09 am, edited 1 time in total.