This would break most "legacy" apps (anything written before Vista), so to prevent that, they're run in XP compatibility mode. Through a process called virtualization, writes to protected resources are redirected by the operating system to somewhere else. For example, trying to write to a file in C:\Program Files\Some Folder causes that file to be created or updated in C:\Users\username\AppData\Local\VirtualStore\Program Files\Some Folder instead.
While it's great that Microsoft prevents our applications from breaking, this really just a short-term solution. It's better to revisit where your data is stored and use one of the preferred locations, such as C:\ProgramData for global settings and C:\Users\username\AppData\Local for user-specific data. The problem is that your shouldn't used a hard-coded location for these paths, especially if some users are on Vista and some on XP. Instead, use Windows API functions to determine those locations.
SpecialFolders.PRG is a wrapper for these functions. It returns the appropriate values regardless of whether the application is running in Vista or XP. See the comments in the header for a description of what parameters to pass. This code doesn't handle all special folders, only the more common ones, but it could easily be updated to support other folders as well.
* Program: SpecialFolders.PRG
* Purpose: Determine the path to the specified special folder
* Author: Doug Hennig
* Last revision: 01/24/2007
* Parameters: tuFolder - the folder to get the path for. Specify
* the CSIDL value of the desired folder (which can
* be obtained from:
* or use one of the following strings:
* "AppData": application-specific data
* "CommonAppData": application data for all users
* "Desktop": the user's Desktop
* "LocalAppData": data for local (nonroaming)
* "Personal": the My Documents folder
* Returns: The path for the specified folder or blank if the
* folder wasn't found
* Environment in: None
* Environment out: Error 11 occurs if tuFolder isn't specified
* Notes: This code was adapted from:
* Support for other CSIDLs can easily be added
local lcPath, ;
* Define the CSIDLs for the different folders.
#define CSIDL_APPDATA 0x1A
* Application-specific data:
* XP: C:\Documents and Settings\username\Application Data
* Vista: C:\Users\username\AppData\Roaming
#define CSIDL_COMMON_APPDATA 0x23
* Application data for all users:
* XP: C:\Documents and Settings\All Users\Application Data
* Vista: C:\ProgramData
#define CSIDL_DESKTOPDIRECTORY 0x10
* The user's Desktop:
* XP: C:\Documents and Settings\username\Desktop
* Vista: C:\Users\username\Desktop
#define CSIDL_LOCAL_APPDATA 0x1C
* Data for local (nonroaming) applications:
* XP: C:\Documents and Settings\username\Local Settings\Application Data
* Vista: C:\Users\username\AppData\Local
#define CSIDL_PERSONAL 0x05
* The My Documents folder:
* XP: C:\Documents and Settings\username\My Documents
* Vista: C:\Users\username\Documents
* Define some other constants.
#define ERR_ARGUMENT_INVALID 11
#define MAX_PATH 260
#define NOERROR 0
#define SUCCESS 1
* Test the parameter.
* If it's numeric, assume it's a valid CSIDL; if not, the API function will
* return a blank string.
case vartype(tuFolder) = 'N'
lnFolder = tuFolder
* An invalid data type or empty folder name was passed.
case vartype(tuFolder) <> 'C' or empty(tuFolder)
* If a string was passed, convert it to the appropriate CSIDL.
lcFolder = upper(tuFolder)
case lcFolder = 'APPDATA'
lnFolder = CSIDL_APPDATA
case lcFolder = 'COMMONAPPDATA'
lnFolder = CSIDL_COMMON_APPDATA
case lcFolder = 'DESKTOP'
lnFolder = CSIDL_DESKTOPDIRECTORY
case lcFolder = 'LOCALAPPDATA'
lnFolder = CSIDL_LOCAL_APPDATA
case lcFolder = 'PERSONAL'
lnFolder = CSIDL_PERSONAL
* Declare the API functions we need.
declare long SHGetSpecialFolderLocation in shell32 long hWnd, long nFolder, ;
long @ ppidl
declare long SHGetPathFromIDList in shell32 long Pidl, string @ pszPath
declare CoTaskMemFree in ole32 long pvoid
* Initialize the variables the API functions will update.
lcPath = space(MAX_PATH)
lnPidl = 0
* Get the path of the specified folder.
lnPidlFound = SHGetSpecialFolderLocation(0, lnFolder, @lnPidl)
if lnPidlFound = NOERROR
lnFolderFound = SHGetPathFromIDList(lnPidl, @lcPath)
if lnFolderFound = SUCCESS
lcPath = left(lcPath, at(chr(0), lcPath) - 1)
endif lnFolderFound = SUCCESS
endif lnPidlFound = NOERROR
lcPath = alltrim(lcPath)