Basic Univers
; Permet de savoir combien de fois un programme ou exécutable est lancé

#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
 
  DefType.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() )
   
  EndIf
 
  ProcedureReturn #PB_ProcessPureBasicEvents
EndProcedure

; the only once running program
If OpenWindow(0, 0, 0, 320, 280, #PB_Window_SystemMenu|#PB_Window_ScreenCentered, "Instance") And CreateGadgetList(WindowID())
 
  ; gadgets to get the result of the custom message
  TextGadget(0, 10, 10, 300, 20, "No custom message received")
  StringGadget(1, 10, 40, 300, 230, "", #PB_String_MultiLine|#PB_String_ReadOnly)
 
  ; without this line, nothing is possible
  SetWindowCallback( @WindowCallback() )
 
  Repeat
    ; enjoy
  Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf