o Now Events are used (Events and Mutexes behave the same in respect to being created and opened).
o The function has been split into SetStaticEvent() and GetStaticEvent().
o Another addition is the detection of name conflicts (return value = -2).
The two routines are still very simple and effective for flagging inter-process events.
The method is also quite safe, because only the program that has created an event object keeps the handle.
If the user "forgets" to close the handle, and thus does not destroy the Event object, it gets killed automatically, when the process terminates.
Note that there is no "event signaling"; the mere existence of an Event object is being used.
Attached are also the PB/CC-compiled .exe files of StaticEvent_Test.bas and UseEventNameSpace.bas.
The latter one occupies a few Event names by Mutexes. The program should be started before or during execution of the event tests.
Best regards,
Gert Voland.
Code:
' StaticEvent_Test.bas ' Compiler: PBCC 5.01 ' OS: Windows XP ' Author: Gert Voland ' Date: 27. Apr. 2009 #COMPILE EXE "StaticEvent_Test.exe" #DIM ALL #BREAK ON #CONSOLE OFF #INCLUDE "Win32Api.inc" $ProgName = "StaticEvent_Test.exe" '--------------------------------------------------------------- FUNCTION PBMAIN () AS LONG LOCAL x$, y$, txt$ LOCAL hGW, hDC AS DWORD LOCAL hFont AS LONG LOCAL i, ist AS LONG LOCAL hProg AS LONG LOCAL pID AS DWORD LOCAL imin, imax AS LONG LOCAL ret, hBS AS LONG imin = ASC("A") imax = ASC("Z") DIM hcreated(imin TO imax) AS LONG ' Use it here for flagging this test program IF GetStaticEvent($ProgName) = 0 THEN ' Check ' It does not exist yet -> create it hProg = SetStaticEvent($ProgName) ' Create txt$ = "First instance of " + $ProgName pID = SHELL($ProgName, 1) ' Start the first instance of this program ELSE ' Program is already loaded txt$ = "Another instance of " + $ProgName ' Second instance. 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 several Events 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$ = "Event_" + x$ ret = SetStaticEvent(y$) ' Create Event IF ret > 0 THEN hcreated(ASC(x$)) = ret ' Store create handle END IF CASE $BS ' Close handles from _Z backwards ... FOR i = imax TO imin STEP -1 hBS = hcreated(i) IF hBS > 0 THEN CloseHandle(hBS) hcreated(i) = 0 EXIT FOR END IF NEXT i CASE $ESC EXIT LOOP END SELECT GRAPHIC PRINT FOR i = ASC("A") TO ASC("Z") y$ = "Event_" + CHR$(i) GRAPHIC PRINT " "; y$; " "; ' Check if locally created IF hcreated(i) > 0 THEN GRAPHIC PRINT "locally created: ";hcreated(i) ITERATE FOR END IF ' Check if events exists ret = GetStaticEvent(y$) ' Check Event SELECT CASE ret CASE 0 GRAPHIC PRINT "---" CASE -1 GRAPHIC PRINT "exists" CASE -2 GRAPHIC PRINT "name not available" END SELECT NEXT i GRAPHIC REDRAW LOOP CloseHandle(hProg) ' This is pc (programmatically correct) GRAPHIC WINDOW END END FUNCTION '--------------------------------------------------------------- FUNCTION SetStaticEvent(BYVAL szEventName AS ASCIIZ * 64) AS LONG ' #INCLUDE "Win32API.inc" ' needed ' ' Purpose: Create a static Event ' ' Method: The mechanism of Window's named Events is used to create and check the status of an Event. ' Therefore it can be used as a system-wide flag that can be monitored by any process. ' Only the existence of an Event is used. Since there is no call to any wait function, the signaling ' state of the Events does not matter and the use of SetEvent() and ResetEvent() has no effect. ' ' Usage: ' (1) The first call of SetStaticEvent("EventName") creates an Event and returns the create-handle. ' This handle may be kept for executing CloseHandle() later. A second call with same name returns -1 (Event exists). ' ' (2) When an Event is checked (in whichever program) by GetStaticEvent("EventName") an OpenEvent() is executed. ' The open-handle gets closed again. Thus, the creating program is the only one to keep the Event handle. ' ' (3) CloseHandle(create-handle) has to be used in the program where it was created to destroy the Event. ' When the creating program terminates, all Event objects created this way get destroyed in any case. ' ' Input: szEventName : Name of the Event to be created (here limited to 63 characters) ' ' Output: FUNCTION = > 0 : = Handle hEvent after creating Event ' = -1 : Event exists ' = -2 : Event not created due to name conflict LOCAL hEvent AS LONG ' Create-handle of Event hEvent = CreateEvent($NUL, 1, 1, szEventName) ' Manual reset = 1, Event is signaled SELECT CASE LONG GetLastError CASE %ERROR_ALREADY_EXISTS ' Close this handle in order to keep only the first create-handle CloseHandle hEvent FUNCTION = -1 ' Event exists CASE %ERROR_INVALID_HANDLE ' Name exist already FUNCTION = -2 ' Event not created due to name conflict CASE ELSE ' Do not close the create-handle. The calling program is the only one to keep the handle FUNCTION = hEvent ' Return the Event create-handle END SELECT END FUNCTION ' SetStaticEvent '--------------------------------------------------------------- FUNCTION GetStaticEvent(BYVAL szEventName AS ASCIIZ * 64) AS LONG ' #INCLUDE "Win32API.inc" ' needed ' ' Purpose: Check if an Event exists ' ' Method and Usage: See SetStaticEvent() ' ' Input: szEventName : Name of the Event to be checked (here limited to 63 characters) ' ' Output: FUNCTION = 0 : Event does not exist ' = -1 : Event exists ' = -2 : Event not checked due to name conflict LOCAL hEvent AS LONG ' Create-handle of Event hEvent = OpenEvent(%Event_ALL_ACCESS, 0, szEventName) IF hEvent = 0 THEN IF GetLastError = %ERROR_INVALID_HANDLE THEN FUNCTION = -2 ' Event object not opened due to name conflict ELSE ' No need to close a handle; there is none. FUNCTION = 0 ' Event does not exist END IF ELSE ' Close the open-handle CloseHandle(hEvent) FUNCTION = -1 ' Event exist END IF END FUNCTION ' GetStaticEvent '---------------------------------------------------------------
Program to cover some Event names by using Mutexes:
Code:
' UseEventNameSpace.bas ' Compiler: PBCC 5.01 ' OS: Windows XP ' Author: Gert Voland ' Date: 27. Apr. 2009 #COMPILE EXE "UseEventNameSpace.exe" #DIM ALL #BREAK ON #CONSOLE ON #INCLUDE "Win32Api.inc" '--------------------------------------------------------------- FUNCTION PBMAIN () AS LONG LOCAL hMutex AS LONG CONSOLE SET SCREEN 10, 35 PRINT " Create Mutexes with Event names" PRINT hMutex = CreateMutex(BYVAL 0, BYVAL 1, "Event_M") PRINT " Event_M created as Mutex"; hMutex hMutex = CreateMutex(BYVAL 0, BYVAL 1, "Event_U") PRINT " Event_U created as Mutex"; hMutex hMutex = CreateMutex(BYVAL 0, BYVAL 1, "Event_T") PRINT " Event_T created as Mutex"; hMutex hMutex = CreateMutex(BYVAL 0, BYVAL 1, "Event_E") PRINT " Event_E created as Mutex"; hMutex hMutex = CreateMutex(BYVAL 0, BYVAL 1, "Event_X") PRINT " Event_X created as Mutex"; hMutex PRINT PRINT " ... any key to finish"; WAITKEY$ END FUNCTION '---------------------------------------------------------------