The usual way to do it is to assemble it yourself using the path of the exe returned from GetModuleFileName(NULL, ...) as a starting point. I use this:

Code:
#include <windows.h>
#include <string>
#include <cassert>

typedef std::basic_string<TCHAR> tstring;

enum GMPP_Flag
{
    GMPP_FULL_PATH,
    GMPP_DIRECTORY_ONLY,
    GMPP_FILE_ONLY
};

tstring GetModulePathPart(HMODULE hMod, GMPP_Flag op)
{
    DWORD bufferSize = MAX_PATH;
    tstring filePath(bufferSize, 0);
    DWORD writtenSize = 0;
    for(;;)
    {
        writtenSize = GetModuleFileName(hMod, &filePath[0], bufferSize);
        if(writtenSize == bufferSize)
        {
            filePath.resize(bufferSize *= 2);
        }
        else if(!writtenSize)
        {
            return tstring();
        }
        else break;
    }
    filePath.resize(writtenSize);
    if(op != GMPP_FULL_PATH)
    {
        tstring::size_type where = filePath.find_last_of(TEXT("\\/"));
        if(where == tstring::npos)
        {
            where = 0;
        }
        // skip over the slash as we want it on the dir name, but not on the file name
        else ++where;
        if(op == GMPP_FILE_ONLY)
        {
            filePath = filePath.substr(where);
        }
        else
        {
            filePath.erase(where);
        }   
    }
    return filePath;
}

tstring BuildAbsolutePath(LPCTSTR addendum)
{
    tstring appDir(GetModulePathPart(NULL, GMPP_DIRECTORY_ONLY));
    assert(!appDir.empty());
    return appDir + addendum;
}