While looking into communication between processes, I wrote the routine SetMutex()
which is quite simple but very effective, and I thought it is worth sharing ...

The routine can be used to signal the execution of a command, routine or process
which then may be monitored by any other process.

The demo program lets you create and monitor lots of named Mutexes.
At start it launches a second instances but additional ones can be loaded at any time.

Keep in mind that a Mutex can only be destroyed in the program where it was created
- by CloseHandle() or by terminating the program.
In this demo the BackSpace key closes only the last handle that was created locally.

The demo has been compiled under PB/CC 5.01. I would assume that it works with PB/Win,
if the #CONSOLE OFF is left out.

Gert Voland.


Code:
' SetMutex.bas

' Compiler:     PBCC 5.01
' OS:           Windows XP
' Author:       Gert Voland
' Date:         20. Apr. 2009

#COMPILE EXE "SetMutex_Test.exe"
#DIM ALL
#CONSOLE OFF

#INCLUDE "Win32Api.inc"

$ProgName = "SetMutex_Test.exe"

'---------------------------------------------------------------

FUNCTION PBMAIN () AS LONG

    LOCAL x$, y$, lasty$, txt$
    LOCAL ret, last     AS LONG
    LOCAL hGW, hDC      AS DWORD
    LOCAL hFont         AS LONG
    LOCAL i, ist        AS LONG
    LOCAL pID           AS DWORD

    ' Use it here for flagging this test program
    IF SetMutex($ProgName, 0) = 0 THEN                  ' Check
        ' It does not exist yet -> create it
        SetMutex($ProgName, 1)                          ' Create
        txt$ = "First instance of " + $ProgName
        pID = SHELL($ProgName, 1)                       ' Start two more instances of this program
    ELSE
        ' It is already loaded
        txt$ = "Another instance of " + $ProgName       ' Note: This does not get updated when the first instance terminates
    END IF

    IF pID > 0 THEN
        GRAPHIC WINDOW txt$, 10,  10,  280, 500 TO hGW
    ELSE
        GRAPHIC WINDOW txt$, 310,  10,  280, 500 TO hGW
    END IF
    GRAPHIC ATTACH hGW, 0, REDRAW

    FONT NEW "Courier New", 9 TO hFont
    GRAPHIC SET FONT hFont

    ' Use it here to create, check and destroy more Mutexes
    DO
        GRAPHIC GET DC TO hDC
        IF hDC = 0 THEN EXIT LOOP                               ' In case GW has been closed externally

        SLEEP 0                                                 ' Allow some CPU to other processes
        GRAPHIC CLEAR                                           ' Always start at top
        GRAPHIC PRINT " Press the following keys for testing:
        GRAPHIC PRINT
        GRAPHIC PRINT " Create: A - Z  Destroy: BS  Quit: Esc"

        GRAPHIC INSTAT TO ist
        IF ISTRUE ist THEN
            GRAPHIC INKEY$ TO x$
            x$ = UCASE$(x$)
        ELSE
            x$ = ""
        END IF

        SELECT CASE x$
            CASE "A" TO "Z"
                y$ = "Mutex_" + x$
                ret = SetMutex(y$, 1)                               ' Create Mutex
                IF ret > 0 THEN
                    last = ret                                      ' Mutex did not exist yet - it is the last one being created
                    lasty$ = y$                                     ' Remember the last one
                END IF

            CASE $BS                                                ' Only close the handle created last!
                IF last > 0 THEN
                    CloseHandle(last)
                    last = 0                                        ' Forget the last one
                    lasty$ = ""
                END IF

            CASE $ESC
                EXIT LOOP

        END SELECT

        GRAPHIC PRINT

        FOR i = ASC("A") TO ASC("Z")
            y$ = "Mutex_" + CHR$(i)
            ret = SetMutex(y$)                                  ' Check Mutex

            GRAPHIC PRINT " "; y$; "   ";
            SELECT CASE ret
                CASE 0
                    GRAPHIC PRINT "---"

                CASE -1
                    IF y$ = lasty$ THEN
                        GRAPHIC PRINT "last handle created :"; USING$(" ####", last)
                    ELSE
                        GRAPHIC PRINT "exists"
                    END IF

            END SELECT
        NEXT i

        GRAPHIC REDRAW
    LOOP

    GRAPHIC WINDOW END

END FUNCTION

'---------------------------------------------------------------

FUNCTION SetMutex(BYVAL szMutexName AS ASCIIZ * 64, OPT BYVAL createMx AS LONG) AS LONG
' #INCLUDE "Win32API.inc"    ' needed
'
' Purpose:  Test if a command/routine/program has been activated by means of a named Mutex.
'
' Usage:
' (1) The first call of  SetMutex("MutexName", 1)  creates a Mutex and returns the create-handle.
'     It may be kept for possibly using  CloseHandle() later.
'
' (2) When a Mutex is checked (in whichever program) by  SetMutex("MutexName", 0)  an OpenMutex is executed.
'     The open-handle gets closed again. Thus, the creating program is the only one to keep the Mutex handle.
'     Almost any type of activity can be monitored this way, e.g. if a program is loaded,
'     or if part of a program is active (or done), etc.
'
' (3) Optionally one can destroy the Mutex using  CloseHandle(create-handle)  in the program where it was created.
'     Still, when the creating program terminates, the Mutex object gets destroyed in any case.
'
' (4) Limitation: A non-creating program cannot find out which program created the Mutex.
'                 For that, more inter-process communication is needed.
'
' Input:    szMutexName         :  Name of the Mutex to be created or checked (here limited to 63 characters)
'           createMx (optional) :  1 => Create the Mutex,  0 => Check the Mutex
'
' Output:   FUNCTION = 0        :  Mutex does not exist
'                    = > 0      :  = Handle hMutex after creating Mutex
'                    = -1       :  Mutex exists

    LOCAL hMutex    AS LONG     ' Create-handle of Mutex

    IF createMx = 0 THEN
        ' Check existence. Do not create a new handle, though.
        hMutex = OpenMutex(BYVAL %MUTEX_ALL_ACCESS, BYVAL 0, szMutexName)
        IF hMutex = 0 THEN
            ' No need to close a handle; there is none.
            FUNCTION = 0                                        ' Mutex does not exist
        ELSE
            ' Close the open-handle
            CloseHandle(hMutex)
            FUNCTION = -1                                       ' Mutex exists
        END IF
    ELSE
        ' Create a Mutex
        hMutex = CreateMutex(BYVAL 0, BYVAL 1, szMutexName)
        IF GetLastError = %ERROR_ALREADY_EXISTS THEN
            ' Close this handle in order to keep only the first create-handle
            CloseHandle hMutex
            FUNCTION = -1                                       ' Mutex exists
        ELSE
            ' Do not close the create-handle. The calling program is the only one to "keep" the handle
            FUNCTION = hMutex                                   ' Return the Mutex create-handle
        END IF
    END IF

END FUNCTION    ' SetMutex

'---------------------------------------------------------------

Attached are .bas and .exe.