Jean-Marc, all,

following our earlier discussion, I attach a little test code to show what I think we need to produce robust code on Windows. The attached code should compile on all flavours of Windows >= Win95 and should behave gracefully on older versions for which GetLongPathName is just a stub.

I propose to post this sample off to Luis Rivera and get him to try it out on Win95/Win98 but I'd of course welcome any sanity checks and comments from you first.

Angus (the one of questionable moral character :-P)

$ g++ -I$HOME/lyx/13x/boost -o trial trial.cpp
$ ./trial
Temp dir is C:/Documents and Settings/Angus/Local Settings/Temp/
#include <boost/assert.hpp>

#include <iostream>
#include <string>
#include <vector>

/*
 * MinGW's version of winver.h contains this comment:
 *
 * If you need Win32 API features newer the Win95 and WinNT then you must
 * define WINVER before including windows.h or any other method of including
 * the windef.h header.
 *
 * GetLongPathNameA requires WINVER == 0x0500.
 *
 * It doesn't matter if the Windows version is older than this because the
 * function will compile but will fail at run time. See
 * 
http://msdn.microsoft.com/library/en-us/mslu/winprog/microsoft_layer_for_unicode_apis_with_limited_support.asp
 */
# if defined(__MINGW32__)
#  define WINVER 0x0500
# endif

#include <windows.h>

using std::string;
using std::vector;


namespace {

string const subst(string const & a,
                   string const & oldstr, string const & newstr)
{
        BOOST_ASSERT(!oldstr.empty());

        string lstr(a);
        string::size_type i = 0;
        string::size_type const olen = oldstr.length();
        while ((i = lstr.find(oldstr, i)) != string::npos) {
                lstr.replace(i, olen, newstr);
                i += newstr.length(); // We need to be sure that we dont
                // use the same i over and over again.
        }
        return lstr;
}


namespace os {

string const internal_path(string const &p)
{
        string const short_path = subst(p, "\\", "/");

        vector<char> long_path(PATH_MAX);
        DWORD result = GetLongPathName(short_path.c_str(),
                                       &long_path[0], long_path.size());

        if (result > long_path.size()) {
                long_path.resize(result);
                result = GetLongPathName(short_path.c_str(),
                                         &long_path[0], long_path.size());
                BOOST_ASSERT(result <= long_path.size());
        }

        return (result == 0) ? short_path : &long_path[0];
}

} // namespace os


string const get_temp_dir()
{
        // Typical example: C:/TEMP/.
        char path[PATH_MAX];
        DWORD const result = GetTempPath(PATH_MAX, path);
        BOOST_ASSERT(result > 0 && result <= PATH_MAX);
        return os::internal_path(path);
}

} // namespace anon


int main()
{
        string const temp_dir = get_temp_dir();
        std::cout << "Temp dir is " << temp_dir << std::endl;
        return 0;
}

Reply via email to