Using Win32 functions GlobalFindAtom and GlobalAddAtom

Everything else that doesn't fall into one of the other PB categories.
kwag
User
User
Posts: 35
Joined: Thu Jul 17, 2003 10:03 pm
Contact:

Using Win32 functions GlobalFindAtom and GlobalAddAtom

Post by kwag »

I am trying to use the functions GlobalFindAtom_ and GlobalAddAtom_
I can't get GlobalFindAtom_ to work, no matter what I try :!:
Are these Win32 functions "non-functional" in PureBasic :?:
I believe the introduction mentions "The Win32 API is fully supported"
So how can these functions be used :?:
I am trying to use them, so I can detect an instance of the same application in memory, and avoid running it more than once.

Any help with this appreciated,
-Karl
newbie
Enthusiast
Enthusiast
Posts: 296
Joined: Tue Jul 29, 2003 5:47 pm
Location: FRANCE
Contact:

Post by newbie »

In the FAQ there is this solution :

viewtopic.php?p=24945

may be it can help.
kwag
User
User
Posts: 35
Joined: Thu Jul 17, 2003 10:03 pm
Contact:

Post by kwag »

Thanks newbie :mrgreen:
Working like charm :cool:

Code: Select all

; These two lines prevent this app from being run more than once. 
; You must put these lines at the start of your app's code (obviously). 
MutexID=CreateMutex_(0,1,"YourAppName") : MutexError=GetLastError_() 
If MutexID=0 Or MutexError<>0 : ReleaseMutex_(MutexID) : CloseHandle_(MutexID) : End : EndIf 
; 
; Your app's code now goes here, until quitting time, which executes the next line. 
; 
CloseHandle_(MutexID) : End 
But I still wonder why I can't use those Win32 functions :roll:

-Karl
User avatar
Paul
PureBasic Expert
PureBasic Expert
Posts: 1285
Joined: Fri Apr 25, 2003 4:34 pm
Location: Canada
Contact:

Post by Paul »

Atom functions work find here...

Code: Select all

Atom=GlobalAddAtom_("Test")
Debug Atom
 
 
Buffer$=Space(256)
GlobalGetAtomName_(Atom,@Buffer$,Len(Buffer$))
Debug PeekS(Buffer$)
 
 
FindAtom=GlobalFindAtom_("Test")
If FindAtom=Atom
  Debug "Found Atom"
EndIf
But for what you want to do, you want to use Mutex (as mentioned above) and not Atom.
Image Image
kwag
User
User
Posts: 35
Joined: Thu Jul 17, 2003 10:03 pm
Contact:

Post by kwag »

Hi Paul,

I wasn't comparing the result of GlobalAddAtom and GlobalFindAtom :oops:
I was comparing the result of GlobalFindAtom to 0 or a value, assuming true or false return :oops: :twisted:
The Atom solution is more elegant than the Mutex solution ;)

Thanhs :D
-Karl
Randy Walker
Addict
Addict
Posts: 1109
Joined: Sun Jul 25, 2004 4:21 pm
Location: USoA

Post by Randy Walker »

kwag wrote: The Atom solution is more elegant than the Mutex solution ;)
Thanhs :D
-Karl
Hi Paul/Karl,

Pardon me. I'm a novice/newcomer here and this is an old topic, but I have to agree with Karl. I used a method similar to the mutex approach and gave that up because global atoms can not only help manage instance control, they can also be used as flags allowing two or more programs to communicate.

The approach is not only simple (keep in mind I am a part time novice), it is far more simple than messing with DDE client/server -IF- your needs are not so complex. Currently I'm juggling about 20 different global atoms between four different programs to manage various tasks. This method is also MS safe, but be sure to proof out your control logic and add necessary code so one program doesn't make your other program get out of sync, crash, etc.

I just got here and waiting for the passord on my purchase so I can start translating code. When I do, I will come back and post some examples here if anyone is interested.

BTW Paul, Thanks for the example.
- - - - - - - - - - - - - - - -
Randy
I *never* claimed to be a programmer.
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

..

Post by NoahPhense »

Here is my lib.. only has two functions:
Download here: mutex_lib.zip

As for using the win32 stuff here it is..

Code: Select all

; mutex example
MutexID = CreateMutex_(0, 1, "whatever you want - usually app name")
MutexError = GetLastError_()
If MutexID = 0 Or MutexError <> 0
  ReleaseMutex_(MutexID)
  CloseHandle_(MutexID)
  End
EndIf


OpenConsole()

PrintN("press a key")
Repeat:Delay(1):Until Inkey()<>""

CloseConsole()



ReleaseMutex_(MutexID)
CloseHandle_(MutexID)

End
- np
Randy Walker
Addict
Addict
Posts: 1109
Joined: Sun Jul 25, 2004 4:21 pm
Location: USoA

Post by Randy Walker »

Read the first post after this code for instructions before you run these sample programs. This is program 1 of 2:

Code: Select all

;This section MUST go at very start of your program!
;
; ------ "Prevent multiple instances" ------ Prg1
Global GA101$,GA201$,GA202$,GA203$,GA204$
GA101$="flag101"+Chr(0) ;Progarm 1 Active
GA202$="flag202"+Chr(0) ;Program 2 downloading
GA203$="flag203"+Chr(0) ;Program 2 processing data
GA204$="flag204"+Chr(0) ;Update installation request
;Debug "TESTING FOR ATOM"
Atom = GlobalFindAtom_(GA101$)  ; Compare Low Word Only
;Debug Hex(Atom & $FFFF)  ;  Absent=0  ;  Present>0
If Atom & $FFFF ;Terminate here if "flag101" atom exists
  Atom=GlobalDeleteAtom_(Atom) 
  ;Debug "Prg1 - Abort this instance!" 
  End       ; Only 1 Instance Allowed!!!
Else
  Atom = GlobalAddAtom_(GA101$) 
EndIf 
;
;      ------ "Resume Normal Code" ------ Prg1
;     (Initialize your variables, windows, etc.)
;
;
If OpenWindow(0, 300,300, 600, 240, #PB_Window_SystemMenu, "")
  If CreateGadgetList(WindowID()) 
    WstatusLine=TextGadget(0,10,220,220,25,"Watch here and run Prg2") 
    ;
    ; First thing before entering main loop - Add Prg1 flag!
    ; Always test first before "Adding" Atoms!!
    Atom = GlobalFindAtom_(GA101$)
    If (Atom & $FFFF) = 0    ; KEEP "flag101" up!!!
      Atom = GlobalAddAtom_(GA101$) 
    EndIf
    ;
    Repeat; ------ "Main Event Handling loop" ------ Prg1
      ; Use Prg2 atoms as flags to update the status bar here.
      Atom = GlobalFindAtom_(GA202$)    ;Check for Pgr2 "flag202"
      If Atom & $FFFF
        SetGadgetText(0,"Downloading new data.") ; Respond to "flag202" atom
        While Atom & $FFFF
          Atom=GlobalDeleteAtom_(Atom) 
          Atom = GlobalFindAtom_(GA202$)
        Wend 
      EndIf
      Atom = GlobalFindAtom_(GA203$)    ;Check for Pgr2 "flag203"
      If Atom & $FFFF
        SetGadgetText(0,"Processing new data.") ; Respond to "flag203" atom
        While Atom & $FFFF
          Atom=GlobalDeleteAtom_(Atom) 
          Atom = GlobalFindAtom_(GA203$)
        Wend 
      EndIf
      Atom = GlobalFindAtom_(GA204$)    ;Check for Pgr2 "flag204"
      If Atom & $FFFF
        SetGadgetText(0,"Updating installation - Please wait...") ; Respond to "flag204" atom
        While Atom & $FFFF
          Atom=GlobalDeleteAtom_(Atom) 
          Atom = GlobalFindAtom_(GA204$)
        Wend
        Delay(4000) ; (delay for demo only)
        Break  ; optional exit for demo purposes
      EndIf
      ; -----------------------------------------------
      ;
      Event = WindowEvent()
      ;         (Enter your own event checking here)
      ;
      Delay(20)
      ; -----------------------------------------------
    Until Event = #PB_Event_CloseWindow
  EndIf
EndIf
;
;
; ------ "Cleanup for program termination" ------ Prg1
;
;           (Your main clean up here)
; 
;Debug "DELETING ATOM"
Atom = GlobalFindAtom_(GA101$) ; Always test first!!
;Debug Hex(Atom & $FFFF)
If Atom & $FFFF   ;Terminate here if "flag101" atom exists
  Atom=GlobalDeleteAtom_(Atom) 
  ;Debug "Terminate here" 
EndIf 
;
CloseWindow(0)
End  ; Cleanup complete ; close Prg1
- - - - - - - - - - - - - - - -
Randy
I *never* claimed to be a programmer.
Randy Walker
Addict
Addict
Posts: 1109
Joined: Sun Jul 25, 2004 4:21 pm
Location: USoA

Post by Randy Walker »

This code must be use with code in previous post. Read the first post after this code for instructions before you run these sample programs. This is program 2 of 2

Code: Select all

;This first section MUST go at very start of program (Prg2)!
;
; ------ "Prevent multiple instances" ------ Prg2
Global GA101$,GA201$,GA202$,GA203$,GA204$
GA101$="flag201"+Chr(0)    ;Prg1 Active
GA201$="flag201"+Chr(0)    ;Prg2 Active
GA202$="flag202"+Chr(0)    ;Prg2 downloading
GA203$="flag203"+Chr(0)    ;Prg2 processing data
GA204$="flag204"+Chr(0)    ;Prg2 updating
;Debug "TESTING FOR Prg2 ATOM"
Atom = GlobalFindAtom_(GA201$)  ; Compare Low Word ONLY!!
;Debug Hex(Atom & $FFFF)  ;  Absent=0  ;  Present>0
If Atom & $FFFF   ;Terminate here if "flag101" atom exists
  ;Debug "Prg2 - Abort this instance!" 
  End ; Only 1 Instance Allowed!!!
Else              ;Otherwise, raise "flag201" immediately
  Atom = GlobalAddAtom_(GA201$)
EndIf 
; ----------------------------------------------------
;
;
;        ------ Resume Main Code -----   Prg2
;     (Initialize your variables, windows, etc.)
;
;
; ----------------------------------------------------
;      ------ "Atoms Signal Prg1 with Prg2 Progress -----   Prg2
;Differnt atoms used to signal different stages of Prg2 progress.
Atom = GlobalFindAtom_(GA202$)  ;Test for "flag202" atom
If (Atom & $FFFF) = 0
  Atom = GlobalAddAtom_(GA202$) ; Downloading - Notify Prg1
  Debug "one"
EndIf
;           "perform download" (sample task)
;
;
Delay(4000) ; (simulates processing time)
;
Atom = GlobalFindAtom_(GA203$)  ;Test for "flag203" atom
If (Atom & $FFFF) = 0
  Atom = GlobalAddAtom_(GA203$) ; Processing - Notify Prg1
  Debug "two"
EndIf
;           "perform processing" (sample task)
;
;
Delay(4000) ; (simulates processing time)
;
Atom = GlobalFindAtom_(GA204$)  ;Test for "flag204" atom
If (Atom & $FFFF) = 0
  Atom = GlobalAddAtom_(GA204$) ; Updating - Notify Prg1
  Debug "three"
EndIf
;             "perform update" (sample task)
;
;
Delay(4000) ; (simulates processing time)
; ----------------------------------------------------
;
;
;
; ------ "Cleanup for program termination" ------ Prg2
; Do whatever cleanup you need and then delete Prg2 Atom last.
Atom = GlobalFindAtom_(GA201$)
While Atom & $FFFF
  Atom=GlobalDeleteAtom_(Atom) 
  Atom = GlobalFindAtom_(GA201$)
Wend 
;
Debug "done"
End  ; Cleanup complete ; Terminate Prg2
- - - - - - - - - - - - - - - -
Randy
I *never* claimed to be a programmer.
Randy Walker
Addict
Addict
Posts: 1109
Joined: Sun Jul 25, 2004 4:21 pm
Location: USoA

Post by Randy Walker »

The two sample programs above are designed to work together, but compile and run them separately.
Prg1 represents the main program. (RUN THIS PROGRAM FIRST)
Prg2 signals it's progress to Prg1 using global atoms.

Several things to note here:

1. Additional code at the top of each sample insures only one instance for each program.

2. I terminate my atom string using a null byte according to MS spec:
GA$ = "flag101" + Chr(0)
and I also use global variables so I can control atoms inside procedures.

3. Using global atoms as flags really requires only 3 instructions.
Atom = GlobalFindAtom_(GA$)
Atom = GlobalAddAtom_(GA$)
Atom = GlobalDeleteAtom_(Atom)

4. Atoms can accumalate so extra code has been added to prevent program failures.

5. These demo programs only illustrate how a text field can be updated by another program. The same strategy can be used to control program execution between the two (or more) programs. The actual intention for atoms is beyond me, but I've learned I can use them as glogal flags to allow my apps to negotiate fixed tasks and messaging. Global atoms can be seen system wide by any app that knows where to look. Its your code so you know where to look.
- - - - - - - - - - - - - - - -
Randy
I *never* claimed to be a programmer.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6172
Joined: Sat May 17, 2003 11:31 am
Contact:

Post by blueznl »

randy, strings always terminate with a null in purebasic
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB - upgrade incoming...)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Henrik
Enthusiast
Enthusiast
Posts: 404
Joined: Sat Apr 26, 2003 5:08 pm
Location: Denmark

Post by Henrik »

Cool exambles and nice info, thanx Randy 8)

Best regards
Henrik.
Randy Walker
Addict
Addict
Posts: 1109
Joined: Sun Jul 25, 2004 4:21 pm
Location: USoA

Re: Using Win32 functions GlobalFindAtom and GlobalAddAtom

Post by Randy Walker »

kwag wrote:I can't get GlobalFindAtom_ to work, no matter what I try :!:
Are these Win32 functions "non-functional" in PureBasic :?:
@kwag
It is very important to note: You must mask the return for each global atom function with $FFFF to compare only the low word. I stumbled on this one myself because my old Basic masked for me. I also strongly suggest extra code to prevent atoms from accumalating... say from a program crash that is unrelated to your atom manipulations.

@Bluenzl
Do you mean PureBasic "automatically" appends a null byte to strings? I got the impression it did, but wasn't sure.

@Henrick
Thanks! Threads were unavailable to me before so my alternative was multiple apps working together in the background. Threads don't look like they would require atoms and I see advantages in both strategies. For the moment I will stick to mutiple apps.
- - - - - - - - - - - - - - - -
Randy
I *never* claimed to be a programmer.
GreenGiant
Enthusiast
Enthusiast
Posts: 252
Joined: Fri Feb 20, 2004 5:43 pm

Post by GreenGiant »

Randy, I think if you're communicating between two applications then user defined messages are normally the way to go. For one thing this means you are only processing the messages, not constantly checking atom states. It'd also removes synchronisation issues I think. Anyway, I've wirtten a couple of little example programs to show you what I mean. Listening program:

Code: Select all

Global usermessage.l

Procedure Callback(WindowID, Message, wParam, lParam)
  Result = #PB_ProcessPureBasicEvents
  If Message=usermessage
    SetGadgetText(1,"Button "+Str(wParam))
  EndIf
  
  ProcedureReturn Result
EndProcedure

OpenWindow(0,0,0,200,70,#PB_Window_ScreenCentered | #PB_Window_SystemMenu,"Listening program")
CreateGadgetList(WindowID(0))
Frame3DGadget(0,5,5,190,60,"Last pressed button:")
StringGadget(1,10,20,180,40,"No buttons pressed yet",#PB_String_ReadOnly | #PB_String_Multiline | #ES_AUTOVSCROLL | #WS_VSCROLL | #ESB_DISABLE_LEFT| #ESB_DISABLE_RIGHT)

usermessage=RegisterWindowMessage_("comm")

SetWindowCallback(@Callback())

Repeat
ev=WaitWindowEvent()
  If ev=#PB_Event_CloseWindow
    quit=#True
  EndIf
  
Until Quit=#True
And then a 'speaking' program.

Code: Select all

OpenWindow(0,0,0,160,60,#PB_Window_ScreenCentered | #PB_Window_SystemMenu,"Speaking program")
CreateGadgetList(WindowID(0))
ButtonGadget(1,10,10,40,40,"1")
ButtonGadget(2,60,10,40,40,"2")
ButtonGadget(3,110,10,40,40,"3")

usermessage=RegisterWindowMessage_("comm")

Repeat
ev=WaitWindowEvent()
  If ev=#PB_Event_CloseWindow
    quit=#True
  EndIf
  
  If ev=#PB_Event_Gadget
    gad=EventGadgetID()
    listener=FindWindow_(0,"Listening program")
    If listener
      SendMessage_(listener,usermessage,gad,0)
    EndIf 
  EndIf
  
Until Quit=#True
Using this method you can safely communicate between as many programs as you like. Hope this is of some use to someone.

Edit: In case anyone's wondering why I need all those flags on the string gadget, I dont. I just started off with some other code that I adapted for this example.
Randy Walker
Addict
Addict
Posts: 1109
Joined: Sun Jul 25, 2004 4:21 pm
Location: USoA

Post by Randy Walker »

GreenGiant wrote:Randy, I think if you're communicating between two applications then user defined messages are normally the way to go.
This is an excellent alternative!... if it works. I will have to test it out further. I noticed you are using FindWindow, which I found to be unreliable in some vesions of Windows, and the reason I say... if it works. Could be FindWindow failed on me previously because of a deficiency in my old Basic... don't know. Atoms always work reliably though. One guru friend suggested that FindWindow "is" unreliable and so EnumerateWindows should be used for this operation.

Also, I can't see that it applies here exactly, but MS warns against one app messaging directly to another app as it could interfere with normal message handling.
- - - - - - - - - - - - - - - -
Randy
I *never* claimed to be a programmer.
Post Reply