Click here to Skip to main content
11,718,016 members (81,923 online)
Click here to Skip to main content

Windows ATOM API Wrapper

, 12 May 2007 MIT 22.8K 9
Rate this:
Please Sign up or sign in to vote.
Wrapper classes for all of the Windows ATOM API functions, both Local and Global

Introduction

I had the need to use the GlobalAddAtom and GlobalDeleteAtom functions and read in the MSDN description that the caller must remember to match the calls to these routines.

Whenever I read comments like that, I immediately think RAII. So here are the wrappers for those routines and all the rest as a bonus.

Background

My usage of these wrappers required a specific breaking of these rules, but I won't bore you with the details of my project. These wrapper classes handled the special case easily.

Using the Code

To use any of the wrapper classes, you may either call the static functions directly, declare a typedef of the particular kind you require, or simply use the base types as is.

The following code demonstrates all of the above described use cases and gives a hint as to the reason I wanted to break the rules outline in the MSDN regarding matching up pairs of those calls.

// AtomTest.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include "win32Atom.hpp"

typedef win32::IntegerAtom<win32::GlobalAtom>    GlobalIntegerAtom;

int main(int argc, CHAR* argv[])
{
    static TCHAR const* atomName = _T("AtomTest");
    static unsigned short int intAtomNum = 254;
    win32::GlobalAtom ga;
    
    if (argc > 1) {
        GlobalIntegerAtom gia(intAtomNum);

        switch (toupper(argv[1][0]))
        {
        case _T('A'):
            ga.Increment(atomName);
            if (ga) {
                _tprintf(_T("Added %s\n"), atomName);
            }
            else {
                _tprintf(_T("Failed to add %s\n"), atomName);
            }
            break;
        case _T('D'):
            ga = win32::GlobalAtom::Find(atomName);
            if (ga) {
                ga.Decrement();
                if (!ga) {
                    _tprintf(_T("Deleted %s\n"), atomName);
                }
                else {
                    _tprintf(_T("Failed to delete %s\n"), atomName);
                }
            }
            else {
                _tprintf(_T("%s not found\n"), atomName);
            }
            break;
        case _T('F'):
            if (win32::GlobalAtom::Find(atomName)) {
                _tprintf(_T("Found %s\n"), atomName);
            }
            else {
                _tprintf(_T("%s not found\n"), atomName);
            }
            break;
        case _T('I'):
            if (gia.Find(intAtomNum)) {
                _tprintf(_T("Found integer atom\n"));
            }
            else {
                _tprintf(_T("Integer atom not found\n"));
            }
            if (++gia) {
                _tprintf(_T("Added integer atom\n"));
            }
            if (GlobalIntegerAtom::Find(intAtomNum)) {
                _tprintf(_T("Found integer atom\n"));
            }
            else {
                _tprintf(_T("Integer atom not found\n"));
            }
            if (--gia) {
                _tprintf(_T("Deleted integer atom\n"));
            }
            else {
                _tprintf(_T("Failed to delete integer atom\n"));
            }
            break;
        }
    }
    return 0;
}

Here is the win32Atom.hpp file in its entirety:

#if !defined(WIN32ATOM_HPP)
 /~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// win32Atom.hpp
//
// Windows ATOM API functions wrapper classes.
//
// LocalAtom    : Atoms local to the process
// GlobalAtom    : Atoms persist for the duration of the login session
// StringAtom<AtomType>        : String atoms
// IntegerAtom<AtomType>    : Integer atoms. Can neither be created nor destroyed
//    AtomType is either LocalAtom or GlobalAtom
//
// Author: David 'dex' Schwartz
// dex at ieee dot org
// 2007.05.12
//
// Free to copy, use, modify and distribute.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <windows.h>
#include <stdexcept>
#include <TCHAR.H>

namespace win32 {

class LocalAtom
{
private:
    ATOM mAtom;

public:
    LocalAtom(LocalAtom const& that)
        : mAtom(that.mAtom)
    {}

    LocalAtom(ATOM a = 0)
        : mAtom(a)
    {}

    ATOM Increment()
    {
        std::basic_string<TCHAR> atomName;
        UINT len = GetName(mAtom, atomName);
        return Increment(atomName.c_str());
    }

    ATOM Increment(LPCTSTR atomName)
    {
        ATOM a = Find(atomName);
        if (a != mAtom)
        {
            Decrement();
        }
        mAtom = Add(atomName);
        return mAtom;
    }

    ATOM Decrement()
    {
        if (mAtom)
        {
            mAtom = ::DeleteAtom(mAtom);
        }
        return mAtom;
    }

    operator bool() const
    {
        return mAtom != 0;
    }

    operator ATOM() const
    {
        return mAtom;
    }

    LocalAtom& operator=(LocalAtom const that)
    {
        if (this != &that)
        {
            mAtom = that.mAtom;
        }
        return *this;
    }

    LocalAtom& operator=(ATOM const a)
    {
        mAtom = a;
        return *this;
    }

    static UINT GetName(ATOM const a, std::basic_string<TCHAR>& atomName)
    {
        TCHAR name[256];
        UINT len = ::GetAtomName(a, name, sizeof(name)/sizeof(TCHAR));
        atomName.assign(name, len);
        return len;
    }

    static ATOM Find(LPCTSTR atomName)
    {
        return ::FindAtom(atomName);
    }

    static ATOM Add(LPCTSTR atomName)
    {
        ATOM a = 0;
        if (atomName)
        {
            a = ::AddAtom(atomName);
        }
        return a;
    }

    // Number of hash buckets to use in local atom table
    static bool Initialise(DWORD n)
    {
        BOOL ok = ::InitAtomTable(n);
        return FALSE != ok;
    }
};

class GlobalAtom
{
private:
    ATOM mAtom;

public:
    GlobalAtom(ATOM a = 0)
        : mAtom(a)
    {}

    GlobalAtom(GlobalAtom const& that)
        : mAtom(that.mAtom)
    {}

    ATOM Increment()
    {
        std::basic_string<TCHAR> atomName;
        UINT len = GetName(mAtom, atomName);
        return Increment(atomName.c_str());
    }

    ATOM Increment(LPCTSTR atomName)
    {
        ATOM a = Find(atomName);
        if (a != mAtom)
        {
            Decrement();
        }
        mAtom = Add(atomName);
        return mAtom;
    }

    ATOM Decrement()
    {
        if (mAtom)
        {
            mAtom = ::GlobalDeleteAtom(mAtom);
        }
        return mAtom;
    }

    operator bool() const
    {
        return mAtom != 0;
    }

    operator ATOM() const
    {
        return mAtom;
    }

    GlobalAtom& operator=(GlobalAtom const that)
    {
        if (this != &that)
        {
            mAtom = that.mAtom;
        }
        return *this;
    }
    
    GlobalAtom& operator=(ATOM const a)
    {
        mAtom = a;
        return *this;
    }

    static UINT GetName(ATOM const a, std::basic_string<TCHAR>& atomName)
    {
        TCHAR name[256];
        UINT len = ::GlobalGetAtomName(a, name, sizeof(name)/sizeof(TCHAR));
        atomName.assign(name, len);
        return len;
    }

    static ATOM Find(LPCTSTR atomName)
    {
        return ::GlobalFindAtom(atomName);
    }

    static ATOM Add(LPCTSTR atomName)
    {
        ATOM a = 0;
        if (atomName)
        {
            a = ::GlobalAddAtom(atomName);
        }
        return a;
    }
};

template <typename AtomType>
class StringAtom : public AtomType
{
private:
    std::basic_string<TCHAR> mAtomName;

public:
    StringAtom(LPCTSTR atomName = NULL)
        : mAtomName(atomName ? atomName : _T(""))
    {
        if (atomName && !mAtomName.empty())
        {
            Increment(mAtomName.c_str());
        }
    }

    ~StringAtom()
    {
        Decrement();
    }

    std::basic_string<TCHAR>& Name()
    {
        if (mAtom && mAtomName.empty())
        {
            AtomType::GetName(mAtom, mAtomName);
        }
        return mAtomName;
    }

    StringAtom& operator++()
    {
        if (!mAtomName.empty())
        {
            mAtomName = AtomType::Increment(mAtomName.c_str());
        }
        return *this;
    }

    StringAtom& operator--()
    {
        ATOM ret = 0;
        if (AtomType::operator bool())
        {
            ret = AtomType::Decrement();
        }
        return *this;
    }
};

template <typename AtomType>
class IntegerAtom : public AtomType
{
private:
    unsigned short int mAtomInt;

public:
    IntegerAtom(unsigned short int n)
        : mAtomInt(n)
    {
        if (mAtomInt < MAXINTATOM)
        {
            Increment(MAKEINTATOM(mAtomInt));
        }
        else
        {
            throw std::range_error(std::string("Integer atom greater than 0xBFFF"));
        }
    }

    ~IntegerAtom()
    {}

    IntegerAtom& operator++()
    {
        return *this;    // Has no meaning for integer atoms
    }

    IntegerAtom& operator--()
    {
        return *this;    // Has no meaning for integer atoms
    }

    UINT Name(std::basic_string<TCHAR>& atomName)
    {
        UINT len = 0;
        if (mAtom)
        {
            len = AtomType::GetName(mAtom, atomName);
        }
        return len;
    }

    operator bool() const
    {
        return AtomType::operator bool();
    }

    static ATOM Find(unsigned short int n)
    {
        return AtomType::Find(MAKEINTATOM(n));
    }
};

} // namespace win32

//typedef win32::StringAtom<win32::GlobalAtom>    GlobalStringAtom;
//typedef win32::IntegerAtom<win32::GlobalAtom>    GlobalIntegerAtom;

#endif // WIN32ATOM_HPP

Points of Interest

The code throws a std::range_error for integer atoms higher than the maximum value allowed.

I have provided increment and decrement operators for both string and integer atom types. Even though the integer ones don't do anything, they act as a form of documentation.

History

  • 12th May, 2007: Version 1.0

License

This article, along with any associated source code and files, is licensed under The MIT License

Share

About the Author

David 'dex' Schwartz
Team Leader
Australia Australia
Developing various kinds of software using C/C++ since 1984 or so. Started out writing 8086 asm for direct screen i/o and mouse handling etc.
Used several other languages eg. Java, Python, Clipper/dBase, FORTRAN 77, Natural ADABAS, Unix scripting, etc.
My current work involves Enterprise Content Management on Win32.

You may also be interested in...

Comments and Discussions

 
QuestionWrong value after assignment? Pin
ehaerim10-Mar-09 9:27
memberehaerim10-Mar-09 9:27 
AnswerRe: Wrong value after assignment? Pin
David 'dex' Schwartz17-Mar-09 2:06
memberDavid 'dex' Schwartz17-Mar-09 2:06 
GeneralRe: Wrong value after assignment? Pin
ehaerim17-Mar-09 3:40
memberehaerim17-Mar-09 3:40 
GeneralRe: Wrong value after assignment? Pin
David 'dex' Schwartz17-Mar-09 23:46
memberDavid 'dex' Schwartz17-Mar-09 23:46 
GeneralRe: Wrong value after assignment? Pin
David 'dex' Schwartz18-Mar-09 0:27
memberDavid 'dex' Schwartz18-Mar-09 0:27 
GeneralAn oldie Pin
Hans Dietrich12-May-07 10:19
mvpHans Dietrich12-May-07 10:19 
AnswerRe: An oldie [modified] Pin
David 'dex' Schwartz12-May-07 18:41
memberDavid 'dex' Schwartz12-May-07 18:41 
Hans.
The only things I could find similar were the mAtom member the default and copy constructors, bool conversion and the assignment operator. The rest use routines specific to the local or global atom tables.
Introducing another layer of inheritance just doesn't seem justified, especially when doing so would tend to imply the two types of ATOM are somehow interchangeable, which they most definitely are not.
You are free to argue the case though, if you feel the need Smile | :)






-- modified at 0:48 Sunday 13th May, 2007

Keep it simple
dex

AnswerRe: An oldie Pin
David 'dex' Schwartz12-May-07 18:46
memberDavid 'dex' Schwartz12-May-07 18:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150901.1 | Last Updated 12 May 2007
Article Copyright 2007 by David 'dex' Schwartz
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid