how to run the program only once (windows)
Posted: Mon Oct 24, 2005 5:09 pm
Code updated For 5.20+
No mutex
No semaphore
No file
Because if the program crash it won't be destroyed and you won't be able to relaunch the program (it happens with the PureBasic IDE but i doesn't crash since it's no more a beta
)
It works with windows 98 AND windows XP (don't know for 95/ME/2000/2k3)
Create executable and try to run several instances of the program at the same time
Dri 
No mutex
No semaphore
No file
Because if the program crash it won't be destroyed and you won't be able to relaunch the program (it happens with the PureBasic IDE but i doesn't crash since it's no more a beta

It works with windows 98 AND windows XP (don't know for 95/ME/2000/2k3)
Create executable and try to run several instances of the program at the same time

Code: Select all
#TH32CS_SNAPHEAPLIST = %0001
#TH32CS_SNAPPROCESS = %0010
#TH32CS_SNAPTHREAD = %0100
#TH32CS_SNAPMODULE = %1000
#TH32CS_SNAPALL = %1111
; Structure PROCESSENTRY32
; dwSize.l
; cntUsage.l
; th32ProcessID.l
; *th32DefaultHeapID.l
; th32ModuleID.l
; cntThreads.l
; th32ParentProcessID.l
; pcPriClassBase.l
; dwFlags.l
; szExeFile.b[#MAX_PATH]
; th32MemoryBase.l
; th32AccessKey.l
; EndStructure
DataSection
Instance_Buffer:
Data.l 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Data.l 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Data.l 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Data.l 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Data.l 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Data.l 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
End_Instance_Buffer:
EndDataSection
Global MainInstance.l
Procedure.l CountProcesses(ExeFile.s)
Protected Count.l, Proc32.PROCESSENTRY32, Temp.s
Protected Kernel32ID.l, PSapiID.l, SnapshotID.l
ExeFile = LCase(ExeFile)
Proc32\dwSize = SizeOf(PROCESSENTRY32)
Kernel32ID = OpenLibrary(#PB_Default, "kernel32.dll")
If Kernel32ID
PSapiID = OpenLibrary(#PB_Default, "psapi.dll")
SnapshotID = CallFunction(Kernel32ID, "CreateToolhelp32Snapshot", #TH32CS_SNAPPROCESS, #Null)
If SnapshotID
If CallFunction(Kernel32ID, "Process32First", SnapshotID, Proc32)
Repeat
If PSapiID
ProcessID = OpenProcess_(#PROCESS_QUERY_INFORMATION|#PROCESS_VM_READ, #False, Proc32\th32ProcessID)
Temp = Space(#MAX_PATH)
CallFunction(PSapiID, "GetModuleFileNameExA", ProcessID, #Null, @Temp, #MAX_PATH)
Temp = Trim(Temp)
CloseHandle_(ProcessID)
Else
Temp = PeekS(@Proc32\szExeFile, #MAX_PATH)
EndIf
If LCase(Temp) = ExeFile
If Count = 0
MainInstance = Proc32\th32ProcessID
EndIf
Count + 1
EndIf
Until CallFunction(Kernel32ID, "Process32Next", SnapshotID, Proc32) = #False
EndIf
CloseHandle_(SnapshotID)
EndIf
CloseLibrary(PSapiID)
CloseLibrary(Kernel32ID)
EndIf
ProcedureReturn Count
EndProcedure
Procedure.s GetExeFile()
Protected Location.s
Location = Space(#MAX_PATH)
GetModuleFileName_(#Null, Location, #MAX_PATH)
ProcedureReturn location
EndProcedure
Procedure.l WriteMainInstanceBuffer(Length.l)
Protected Write.l, ProcessID.l
If Length > 0 And Length <= (?End_Instance_Buffer - ?Instance_Buffer)
ProcessID = OpenProcess_(#PROCESS_ALL_ACCESS, #False, MainInstance)
If ProcessID
Write = WriteProcessMemory_(ProcessID, ?Instance_Buffer, ?Instance_Buffer, Length, #Null)
CloseHandle_(ProcessID)
EndIf
EndIf
ProcedureReturn Write
EndProcedure
;-example
;create or get a custom message
Global WM_MYAPPCUSTOMMESSAGE
WM_MYAPPCUSTOMMESSAGE = RegisterWindowMessage_("my_app_custom_message")
;check for existing process
If CountProcesses( GetExeFile() ) > 1
Define.s param, params
;get all params in a new line
Repeat
param = ProgramParameter()
If params
params + #CRLF$
EndIf
params + param
Until param = #NULL$
If params
;send the string to the buffer
PokeS(?Instance_Buffer, params)
WriteMainInstanceBuffer(Len(params))
;send the custom message
SendMessage_(#HWND_BROADCAST, WM_MYAPPCUSTOMMESSAGE, "GET_PARAMS", Len(params))
Else
;send a 'no param' message
SendMessage_(#HWND_BROADCAST, WM_MYAPPCUSTOMMESSAGE, "NO_PARAMS", 0)
EndIf
;only one instance so just end
End
EndIf
;here starts the "MainInstance" program
;this var is used for small stats ^^
Global nMessages
;procedure where you receive the custom message
Procedure WindowCallback(WindowID.l, Message.l, wParam.l, lParam.l)
If Message = WM_MYAPPCUSTOMMESSAGE
nMessages + 1
CustomMessage.s = PeekS(wParam)
;get the program parameter if any
If CustomMessage = "GET_PARAMS"
Text.s = "Here is a new custom message :" + #CRLF$ + PeekS(?Instance_Buffer, lParam)
ElseIf CustomMessage = "NO_PARAMS"
Text.s = "Here is a 'no param' message !" + #CRLF$
EndIf
;update gadgets' text
Text = GetGadgetText(1) + Text
SetGadgetText(1, Text)
SetGadgetText(0, "Custom messages : " + Str(nMessages))
SetForegroundWindow_( WindowID(0) )
EndIf
ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure
;the only once running program
If OpenWindow(0,0,0,320,280,"Instance",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
;gadgets to get the result of the custom message
TextGadget (0,10,10,300, 20,"No custom message received")
EditorGadget(1,10,40,300,230,#PB_String_ReadOnly)
;without this line, nothing is possible
SetWindowCallback( @WindowCallback() )
Repeat
;enjoy
Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
