OK here's the C++ which does:
a) See if the OS is Vista and above (which we have some BMax equivalent for above via James) b) load in a Vista specific dll symbol c) get the FOLDERID_SavedGames path.
And if the above fail because it's XP then it uses CSIDL_LOCAL_APPDATA although using just CSIDL_APPDATA (which points at the roaming folder) would also be fine.
What I'd love some help with is converting this code (or the bits which load in the Vista dll symobol and get the path) because I already have this code that works in XP:
' -----------------------------------------------------------------------------
' ccGetSpecialFolder: Returns a special Windows folder
' By Dave Kirk
' -----------------------------------------------------------------------------
?win32
Extern "win32"
Function SHGetPathFromIDList(pidList%, lpBuffer:Byte Ptr)
Function SHGetSpecialFolderLocation(hwndOwner%, nFolder%, pIdl:Byte Ptr)
End Extern
'For use with ccGetSpecialFolder
Const CSIDL_DESKTOP% = $0
Const CSIDL_INTERNET% = $1
Const CSIDL_PROGRAMS% = $2
Const CSIDL_CONTROLS% = $3
Const CSIDL_PRINTERS% = $4
Const CSIDL_PERSONAL% = $5
Const CSIDL_FAVORITES% = $6
Const CSIDL_STARTUP% = $7
Const CSIDL_RECENT% = $8
Const CSIDL_SENDTO% = $9
Const CSIDL_BITBUCKET% = $A
Const CSIDL_STARTMENU% = $B
Const CSIDL_DESKTOPDIRECTORY% = $10
Const CSIDL_DRIVES% = $11
Const CSIDL_NETWORK% = $12
Const CSIDL_NETHOOD% = $13
Const CSIDL_FONTS% = $14
Const CSIDL_TEMPLATES% = $15
Const CSIDL_COMMON_STARTMENU% = $16
Const CSIDL_COMMON_PROGRAMS% = $17
Const CSIDL_COMMON_STARTUP% = $18
Const CSIDL_COMMON_DESKTOPDIRECTORY% = $19
Const CSIDL_APPDATA% = $1A
Const CSIDL_PRINTHOOD% = $1B
Const CSIDL_LOCAL_APPDATA% = $1C
Const CSIDL_ALTSTARTUP% = $1D
Const CSIDL_COMMON_ALTSTARTUP% = $1E
Const CSIDL_COMMON_FAVORITES% = $1F
Const CSIDL_INTERNET_CACHE% = $20
Const CSIDL_COOKIES% = $21
Const CSIDL_HISTORY% = $22
Const CSIDL_COMMON_APPDATA% = $23
?
Function ccGetSpecialFolder:String(folder_id%)
?win32
Local idl:TBank = CreateBank (8)
Local pathbank:TBank = CreateBank (260)
If SHGetSpecialFolderLocation(0,folder_id,BankBuf(idl)) = 0
SHGetPathFromIDList PeekInt( idl,0), BankBuf(pathbank)
Return String.FromCString(pathbank.Buf()) + "\"
EndIf
?
Return ""
End Function
Anyway here's the C++ code. Anyone feeling helpful? Thanks in advance :-)
#include <string>
#include <cassert>
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#include <shlobj.h>
#include <Shellapi.h>
// Check if Vista is supported
bool SupportsVistaFunctionality()
{
OSVERSIONINFO versionInfo;
ZeroMemory(&versionInfo, sizeof(OSVERSIONINFO));
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&versionInfo);
return versionInfo.dwMajorVersion >= 6;
}
// Declare function pointers to be dynamically-loaded
typedef HRESULT (WINAPI* tSHGetKnownFolderPath)(const GUID& rfid, DWORD dwFlags, HANDLE hToken, PWSTR* ppszPath);
static tSHGetKnownFolderPath GetKnownFolderPath = 0;
static bool s_loadedVistaFuncs = false;
// Dynamically-load the Vista-specific symbol (prevents DLL-crash on XP machines)
void LoadVistaFunctions()
{
static HINSTANCE s_Shell32DLLInst = LoadLibrary(TEXT("Shell32.dll"));
GetKnownFolderPath = (tSHGetKnownFolderPath)GetProcAddress(s_Shell32DLLInst, "SHGetKnownFolderPath");
assert(GetKnownFolderPath); // If we don't find this function, something is fundamentally wrong
s_loadedVistaFuncs = true;
}
// Get the final saved-games path
std::string GetSavedGamesPath()
{
std::string path;
if(SupportsVistaFunctionality())
{
if(!s_loadedVistaFuncs)
LoadVistaFunctions();
char rootPath[MAX_PATH];
PWSTR uniRootPath;
HRESULT ret = GetKnownFolderPath(FOLDERID_SavedGames, 0, 0, &uniRootPath);
wcstombs(rootPath, uniRootPath, MAX_PATH);
CoTaskMemFree(uniRootPath);
if(ret == S_OK)
path = &rootPath[0];
}
else
{
char tempPath[MAX_PATH];
// If you compile with the unicode character set, you have to do some conversion here.
if (SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, tempPath) == S_OK) // Others recommended CSIDL_APPDATA, but I think CSIDL_LOCAL_APPDATA is a better fit.
{
path = tempPath;
}
}
return path;
}
int main(int argv, char** argc)
{
std::string path = GetSavedGamesPath();
assert(path != ""); // NOTE: Once you put in your own XP logic, this should never happen
path = path + "/Retro City Rampage";
printf("%s\n", path.c_str());
return 0;
}
Last edited 2012
|