function getWindowsCSIDLPath(CSIDL,cPath,cDisplayMessages,cCreateFolder) // // Method to return the path for a windows folder CSIDL. // // This function was written to more fully support Vista than the current // function GetWindowsFolders() in the dUFLP file miscapi.prg. // // Vista replaced the windows CSIDL values with KNOWNFOLDERID values and // replaced the API SHGetFolderPath() with the API SHGetKnownFolderPath(). // The windows special folders and their meaning were also modified and // SHGetFolderPath() is now a wrapper for SHGetKnownFolderPath() and CSIDL // values are mapped to KNOWNFOLDERID values. // // Vista also allows users or administrators to redirect a known folder to // a location that suits their needs. // // This is achieved by calling IKnownFolderManager::Redirect, which sets the // "current" value of the folder associated with the SHGFP_TYPE_CURRENT flag. // The default value of the folder, which is the location of the folder if a // user or administrator had not redirected it elsewhere, is retrieved by // specifying the SHGFP_TYPE_DEFAULT flag. // // For more detailed explanation see the following URL: // // http://msdn2.microsoft.com/en-us/library/bb762181(VS.85).aspx // // Author: Andrew Shimmin // Date: 4-Jan-2008 // Version: 0.0.0.1 // // Usage: // // Inputs: // // CSIDL = CSIDL value or string of windows folder [required] [default - none] // cPath = "CurrentPath" or "DefaultPath" [optional] [default - "CurrentPath"] // cDisplayMessages = "DisplayMessages" to display errors [optional] [default - no messages displayed] // cCreateFolder = "CreateFolder" to create the windows // folder if it does not already exist [optional] [default - does not create the folder] // // The function's input arguments can be in any order but string arguments MUST following the following rules: // // A CSIDL value string like "CSIDL_COMMON_APPDATA" MUST begin with "CSIDL_". // All other string arguments MUST be as defined above. // // Outputs: // // The function will return the CSIDL value folder path or an empty() // string on an error. // // Examples: // // cFolderPath = GetWindowsCSIDLPath([CSIDL_COMMON_APPDATA]) // ?cFolderPath // // cFolderPath = GetWindowsCSIDLPath([CSIDL_COMMON_APPDATA],[DefaultPath],[cDisplayMessages]) // ?cFolderPath // // CSIDL_COMMON_APPDATA = 35 // cFolderPath = GetWindowsCSIDLPath([cDisplayMessages],CSIDL_COMMON_APPDATA) // ?cFolderPath // // Notes: // // Some CSIDL values return a "received an unexpected return from SHGetFolderPath()" error. // I have not been able to fathom why as the SHGetFolderPath() call return overflows dBPlus' // numeric data type. Maybe some else knows what is happening. I do not need the folder paths // for CSIDL values that return this error. // local lError,nArgCount,lCSIDLTypeIsName,lFolderCSIDL,lDisplayMessages,; lCreate,lCurrentPath,lDefaultPath,lFolder,cFolderPath lError = false // assume no error nArgCount = 0 // assume no arguments lCSIDLTypeIsName = true // assume folder CSIDL name provided lFolderCSIDL = false // assume no CSIDL argument lDisplayMessages = false // assume no displayMessage argument lCreateFolder = false // assume no createFolder argument lCurrentPath = false // assume no currentPath argument lDefaultPath = false // assume no defaultPath argument lFolder = false // assume folder CISDL not found private nNameCount,aCSIDLNames,aCSIDLValues,cNamesKey,cValuesKey,Arg,; nResult,sBuffer,nFolder,aFolderNames,cKey,cExact,nFolder,cFolder,; cCSIDLFolderPath nNameCount = 0 // reset folder CSIDL names count cNamesKey = [] // reset aCSIDLNames key cValuesKey = [] // reset aCSIDLValues key nFolder = -1 // reset folder CSIDL number cFolder = [] // reset folder CSIDL string cCSIDLFolderPath = [] // reset return folder CSIDL path // create CSIDL names array aCSIDLNames = new AssocArray() aCSIDLNames.instanceId = program() aCSIDLNames["CSIDL_ADMINTOOLS"] = 48 aCSIDLNames["CSIDL_ALTSTARTUP"] = 29 aCSIDLNames["CSIDL_APPDATA"] = 26 aCSIDLNames["CSIDL_BITBUCKET"] = 10 aCSIDLNames["CSIDL_CDBURN_AREA"] = 59 aCSIDLNames["CSIDL_COMMON_ADMINTOOLS"] = 47 aCSIDLNames["CSIDL_COMMON_ALTSTARTUP"] = 30 aCSIDLNames["CSIDL_COMMON_APPDATA"] = 35 aCSIDLNames["CSIDL_COMMON_DESKTOPDIRECTORY"] = 25 aCSIDLNames["CSIDL_COMMON_DOCUMENTS"] = 46 aCSIDLNames["CSIDL_COMMON_FAVORITES"] = 31 aCSIDLNames["CSIDL_COMMON_MUSIC"] = 53 aCSIDLNames["CSIDL_COMMON_PICTURES"] = 54 aCSIDLNames["CSIDL_COMMON_PROGRAMS"] = 23 aCSIDLNames["CSIDL_COMMON_STARTMENU"] = 22 aCSIDLNames["CSIDL_COMMON_STARTUP"] = 24 aCSIDLNames["CSIDL_COMMON_TEMPLATES"] = 45 aCSIDLNames["CSIDL_COMMON_VIDEO"] = 55 aCSIDLNames["CSIDL_COMPUTERSNEARME"] = 61 aCSIDLNames["CSIDL_CONNECTIONS"] = 49 aCSIDLNames["CSIDL_CONTROLS"] = 3 aCSIDLNames["CSIDL_COOKIES"] = 33 aCSIDLNames["CSIDL_DESKTOP"] = 0 aCSIDLNames["CSIDL_DESKTOPDIRECTORY"] = 16 aCSIDLNames["CSIDL_DRIVES"] = 17 aCSIDLNames["CSIDL_FAVOURITES"] = 6 aCSIDLNames["CSIDL_FONTS"] = 20 aCSIDLNames["CSIDL_HISTORY"] = 34 aCSIDLNames["CSIDL_INTERNET"] = 1 aCSIDLNames["CSIDL_INTERNET_CACHE"] = 32 aCSIDLNames["CSIDL_LOCAL_APPDATA"] = 28 aCSIDLNames["CSIDL_MYDOCUMENTS"] = 5 // was 12 - replaced with CSIDL_PERSONAL aCSIDLNames["CSIDL_MYMUSIC"] = 13 aCSIDLNames["CSIDL_MYPICTURES"] = 39 aCSIDLNames["CSIDL_MYVIDEO"] = 14 aCSIDLNames["CSIDL_NETHOOD"] = 19 aCSIDLNames["CSIDL_NETWORK"] = 18 aCSIDLNames["CSIDL_PERSONAL"] = 5 aCSIDLNames["CSIDL_PRINTERS"] = 4 aCSIDLNames["CSIDL_PRINTHOOD"] = 27 aCSIDLNames["CSIDL_PROFILE"] = 40 aCSIDLNames["CSIDL_PROGRAM_FILES"] = 38 aCSIDLNames["CSIDL_PROGRAM_FILESX86"] = 42 aCSIDLNames["CSIDL_PROGRAM_FILES_COMMON"] = 43 aCSIDLNames["CSIDL_PROGRAM_FILES_COMMONX86"] = 44 aCSIDLNames["CSIDL_PROGRAMS"] = 2 aCSIDLNames["CSIDL_RECENT"] = 8 aCSIDLNames["CSIDL_SENDTO"] = 9 aCSIDLNames["CSIDL_STARTMENU"] = 11 aCSIDLNames["CSIDL_STARTUP"] = 7 aCSIDLNames["CSIDL_SYSTEM"] = 37 aCSIDLNames["CSIDL_SYSTEMX86"] = 41 aCSIDLNames["CSIDL_TEMPLATES"] = 21 aCSIDLNames["CSIDL_WINDOWS"] = 36 // transpose CSIDL names array to get CSIDL values array aCSIDLValues = new AssocArray() aCSIDLValues.instanceId = program() cNamesKey = aCSIDLNames.firstKey for n = 1 to aCSIDLNames.count() cValuesKey = ltrim(str(aCSIDLNames[cNamesKey])) aCSIDLValues[cValuesKey] = cNamesKey cNamesKey = aCSIDLNames.nextKey(cNamesKey) endfor // parse arguments // // The arguments can be in any order in the function call and if they include // the cDisplayMessages, cCreateFolder, cCurrentPath or cDefaultPath arguments // these MUST be the same character string (case insensitive) as specified // in the case Statusments below. // // The folder CSIDL argument can be either a string or a numeric value. When // the folder CSIDL argument is a string value it MUST be preceded by "CSIDL_". if argcount() > 0 // any arguments? for nArgCount = 1 to argcount() // parse them arg = argvector(nArgCount) // public for type() do case case type([arg]) == "C" do case case upper(arg) == [DISPLAYMESSAGES] // show messages lDisplayMessages = true case upper(arg) == [CREATEFOLDER] // create folder lCreateFolder = true case upper(arg) == [CURRENTPATH] // current path lCurrentPath = true case upper(arg) == [DEFAULTPATH] // default path lDefaultPath = true otherwise // folder CSIDL string if upper(left(arg,6)) == [CSIDL_] // folder CSIDL string? lFolderCSIDL = true // set folder CSIDL provided lCSIDLTypeIsName = true // set folder CSIDL type lFolder = aCSIDLNames.isKey(upper(trim(arg))) // set folder CSIDL found cFolder = trim(arg) // set folder CSIDL string nFolder = iif(lFolder,aCSIDLNames[upper(cFolder)],-1) // set folder CSIDL value endif endcase otherwise // folder CSIDL number if type([arg]) == [N] // folder CSIDL value? lFolderCSIDL = true // set folder CSIDL provided lCSIDLTypeIsName = false // set folder CSIDL type lFolder = aCSIDLValues.isKey(ltrim(str(arg))) // set folder CSIDL found nFolder = arg // set folder CSIDL value cFolder = iif(lFolder,aCSIDLValues[ltrim(str(nFolder))],[]) // set folder CSIDL string endif endcase next endif // process CSIDL value if lFolder // valid CSIDL? // initialise the API if type([SHGetFolderPath]) # [FP] extern clong SHGetFolderPath(clong,clong,clong,clong,cstring) shfolder.dll from [SHGetFolderPathA] endif #define CSIDL_FLAG_CREATE (0x8000) #define SHGFP_TYPE_CURRENT (0x0) #define SHGFP_TYPE_DEFAULT (0x1) #define S_OK (0x0) #define S_FALSE (0x1) #define E_INVALIDARG (0x80070057) do case case lCurrentPath dwFlags = SHGFP_TYPE_CURRENT // set for current path case lDefaultPath dwFlags = SHGFP_TYPE_DEFAULT // set for default path otherwise dwFlags = SHGFP_TYPE_CURRENT // default current path endcase sBuffer = space(260) // 260 (not 255) is the Microsoft max path size // get CSIDL value path nResult = iif(lCreateFolder,SHGetFolderPath(null,nFolder+CSIDL_FLAG_CREATE,0,dwFlags,sBuffer),; SHGetFolderPath(null,nFolder,0,dwFlags,sBuffer)) // get folder CSIDL path do case // check return case nResult = S_OK // the folder CSIDL is valid and the folder does exist case nResult = S_FALSE // the folder CSIDL is valid but the folder does not exist if lDisplayMessages msgbox([The folder CSIDL]+c2Lines+; "[ "+iif(lCSIDLTypeIsName,cFolder,ltrim(str(nFolder)))+" ]"+c2Lines+; [is valid BUT the folder does NOT exist.],program(),16) lError = true endif case nResult = E_INVALIDARG // the folder CSIDL is invalid if lDisplayMessages msgbox([The folder CSIDL]+c2Lines+; "[ "+iif(lCSIDLTypeIsName,cFolder,ltrim(str(nFolder)))+" ]"+c2Lines+; [is invalid.],program(),16) lError = true endif otherwise // unexpected return if lDisplayMessages msgbox([The folder CSIDL]+c2Lines+; "[ "+iif(lCSIDLTypeIsName,cFolder,ltrim(str(nFolder)))+" ]"+c2Lines+; [received an unexpected return from SHGetFolderPath().],program(),16) lError = true endif endcase else if lFolderCSIDL // folder CSIDL provided? msgbox([The folder CSIDL]+c2Lines+; "[ "+iif(lCSIDLTypeIsName,cFolder,ltrim(str(nFolder)))+" ]"+c2Lines+; [is invalid.],program(),16) else msgbox([Folder CSIDL value or string argument missing.],program(),16) endif lError = true endif // finish if lError if .not.class::IsDbaseRuntime() // ide active? nReply = msgbox([An eror has occurred. Do you wish to debug it?],program(),32+4) if nReply = 6 set step on endif endif endif release object aCSIDLNames aCISDLnames = [] release object aCSIDLValues aCSIDLValues = [] if lFolder // folder CSIDL provided? cCSIDLFolderPath = iif(lError,[],trim(sBuffer)) // return folder CSIDL path endif cFolderPath = cCSIDLFolderPath release nNameCount,aCSIDLNames,aCSIDLValues,cNamesKey,cValuesKey,Arg,; nResult,sBuffer,nFolder,aFolderNames,cKey,cExact,nFolder,cFolder,; cCSIDLFolderPath return (cFolderPath)