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