Global Atom UDFs - sharing data between applications in memory

Started by ....IFICantBYTE, November 29, 2015, 10:14:49 PM

Previous topic - Next topic

....IFICantBYTE

Here are a few basic UDFs that allow you to create, find, read and delete shared "Atoms" in memory between applications... see:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms649053(v=vs.85).aspx

The atoms will persist after the application has closed (unless deliberately deleted), but will be gone on a reboot.

For example,
Try making 2 scripts and create an Atom in one with something like:
GlobalAddAtom("testing123")
and run it.

then in the other, use:
Atom = GlobalFindAtom("testing123")
Message("Find",Atom)
Message("GetName",GlobalGetAtomName(Atom))

.... and it should find and display the text associated with the atom you made in the first script!
It's a good idea to read the notes in the UDFs and online about Atoms and about subsequent adds and deletes.

Code (winbatch) Select
;Each call to GlobalAddAtom should have a corresponding call to GlobalDeleteAtom.
;Do not call GlobalDeleteAtom more times than you call GlobalAddAtom, or you may delete the atom while other clients are using it.
;Applications using Dynamic Data Exchange (DDE) should follow the rules on global atom management to prevent leaks and premature deletion.
#DefineFunction  GlobalAddAtom(Name)
    Kernel32=DllLoad(StrCat(DirWindows(1),"Kernel32.DLL"))
    Ret = DllCall(Kernel32,long:"GlobalAddAtomA",lpstr:Name)
    DllFree(Kernel32)
    Return Ret
#EndFunction

#DefineFunction  GlobalFindAtom(Name)
    Kernel32=DllLoad(StrCat(DirWindows(1),"Kernel32.DLL"))
    Ret = DllCall(Kernel32,long:"GlobalFindAtomA",lpstr:Name)
    DllFree(Kernel32)
    Return Ret
#EndFunction

#DefineFunction  GlobalDeleteAtom(Atom)
    Kernel32=DllLoad(StrCat(DirWindows(1),"Kernel32.DLL"))
    Ret = DllCall(Kernel32,long:"GlobalDeleteAtom",long:Atom);(Always returns 0)
    ;To determine whether the function has failed, call SetLastError with ERROR_SUCCESS before calling GlobalDeleteAtom, then call GetLastError.
    ;If the last error code is still ERROR_SUCCESS, GlobalDeleteAtom has succeeded.
    DllFree(Kernel32)
    Return Ret ; Always 0
#EndFunction

#DefineFunction  GlobalGetAtomName(Atom)
    Kernel32=DllLoad(StrCat(DirWindows(1),"Kernel32.DLL"))
    Name = BinaryAlloc(256)
    BinaryEODSet(Name,0)
    Len = DllCall(Kernel32,long:"GlobalGetAtomNameA",long:Atom,lpbinary:Name,long:256)
    BinaryEODSet(Name,Len+1)
    DllFree(Kernel32)
    Ret = BinaryPeekStr(Name,0,Len)
    BinaryFree(Name)
    Return Ret
#EndFunction



Regards,
....IFICantBYTE

Nothing sucks more than that moment during an argument when you realize you're wrong. :)

JTaylor

Looks interesting and, potentially, very useful.  Thanks.

Jim

kdmoyers

So atoms are like little variables that have no contents -- the only information carried is the fact that it exists, or does not exist.  Do I have that right?
-K

EDIT: I found this reference:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms649053(v=vs.85).aspx
The mind is everything; What you think, you become.

....IFICantBYTE

I guess that's about right... umm.. that's the same link I had in my original post, but no worries... it's got a lot of info there and definitely should be read if you are going to use Atoms in your projects.

Basically as far as I understand it...
There is a global (for each logon session) store of Atoms (a hash table) and it used by underlying system routines to store, swap and manage info between threads etc. ... it is available to all applications running in that session.. it is not private.
It is a finite resource though and you shouldn't go storing thousands of Atoms in there.
There are String (max 255 characters in length) and Numeric Atoms.... read the info on the use of numeric atom numbers and the string representations of them eg: "#1234" - a bit confusing, and I prefer sticking to string Atoms myself.

Also note that each Atom reference can be incremented or decremented by subsequent calls to Add or Delete a specific Atom, so for example, if you Add it twice, you need to Delete it twice before it's gone.
I have used the ANSI functions, but there are Wide (Unicode) versions too - easy to change the UDFs if you want to.

Apart from the Global Atoms table, each application also has its own private one that is independent and available only to that application... you could easily make your own UDFs for those functions based on these.

Again, read the MS docs.


 
Regards,
....IFICantBYTE

Nothing sucks more than that moment during an argument when you realize you're wrong. :)

kdmoyers

The mind is everything; What you think, you become.

td

Use the atom API with care.  Atoms are used by several OS subsystems and the OS will get very unhappy, if you don't play nice.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

DAG_P6

Quote from: td on December 03, 2015, 08:01:47 AM
Use the atom API with care.  Atoms are used by several OS subsystems and the OS will get very unhappy, if you don't play nice.

In particular, as I recall, DDE makes extensive use of global atoms.

However, if you take care to verify that an atom that you want to use doesn't exist before you create it, and manage your own reference counts, so that your add and delete counts are always equal, they should be safe to use. I discovered global atoms in 1997, when I needed a way to pass information between 16 and 32 bit processes, for which it worked extremely well. For example, I would put a string in the global atom table, then pass its numeric ID to the 16 bit process, which would retrieve and delete the atom. This technique provided me with a very effective way for the 16 bit process to signal that it was done, by deleting the atom passed to it by the 32 bit process.

I'm happy to see that another old-timer has posted his atom UDFs, because I have thought several times that I should post mine.
David A. Gray
You are more important than any technology.

td

Atoms are used by more significant systems than just DDE.   They are a shared resource used by the OS kernel in ways that are not even visible to user mode programmers.   
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

DAG_P6

Quote from: td on December 07, 2015, 06:36:11 AM
Atoms are used by more significant systems than just DDE.   They are a shared resource used by the OS kernel in ways that are not even visible to user mode programmers.

I was aware of that, too. I mentioned DDE solely as an example that should be relatively familiar to most.

Moreover, the critical take-away is that, since I did my own reference counting, my use of the global atom table shouldn't interfere with whatever Windows has stashed there.
David A. Gray
You are more important than any technology.

td

While both WinBatch and a few extenders use atoms, system device drivers and other processes also  make use of atoms.  Also note that I said use with care not don't use at all. In other words, seemingly correctly coded implementations can lead to out sized problems if an apparently 'trivial' bug exists in the implementation. 
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

DAG_P6

Quote from: td on December 14, 2015, 07:09:56 AM
While both WinBatch and a few extenders use atoms, system device drivers and other processes also  make use of atoms.  Also note that I said use with care not don't use at all. In other words, seemingly correctly coded implementations can lead to out sized problems if an apparently 'trivial' bug exists in the implementation.

Hence, the reason that my code went to great pains to see to it that its atoms had unique values, and were carefully reference counted.
David A. Gray
You are more important than any technology.