Click here to Skip to main content
15,881,424 members
Articles / Programming Languages / C++

Windows ATOM API Wrapper

Rate me:
Please Sign up or sign in to vote.
3.57/5 (4 votes)
12 May 2007MIT1 min read 36.6K   10   8
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.

C++
// 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:

C++
#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


Written By
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.
Previous role involved Enterprise Content Management on Win32.
Most recently worked on managing secure code example development for an online secure code training product.
securecodewarrior.com

Comments and Discussions

 
QuestionWrong value after assignment? Pin
ehaerim10-Mar-09 9:27
ehaerim10-Mar-09 9:27 
AnswerRe: Wrong value after assignment? Pin
David 'dex' Schwartz17-Mar-09 2:06
David 'dex' Schwartz17-Mar-09 2:06 
GeneralRe: Wrong value after assignment? Pin
ehaerim17-Mar-09 3:40
ehaerim17-Mar-09 3:40 
GeneralRe: Wrong value after assignment? Pin
David 'dex' Schwartz17-Mar-09 23:46
David 'dex' Schwartz17-Mar-09 23:46 
GeneralRe: Wrong value after assignment? Pin
David 'dex' Schwartz18-Mar-09 0:27
David 'dex' Schwartz18-Mar-09 0:27 
GeneralAn oldie Pin
Hans Dietrich12-May-07 10:19
mentorHans Dietrich12-May-07 10:19 
AnswerRe: An oldie [modified] Pin
David 'dex' Schwartz12-May-07 18:41
David 'dex' Schwartz12-May-07 18:41 
AnswerRe: An oldie Pin
David 'dex' Schwartz12-May-07 18:46
David 'dex' Schwartz12-May-07 18:46 

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

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