此错误通常是由于尝试写入您的应用程序自己在Program Files 下的文件夹,这对于 Vista 及更高版本(和 XP,如果您不是以管理员或 Power 身份运行)下的非管理员是不允许的用户)。
以下是为您的 .INI 文件获取正确文件夹的一些代码:
uses
Windows,
ShlObj; // For SHGetSpecialFolderPath
function GetFolderLocation(Handle: HWnd; Folder: Integer): string;
begin
Result := '';
SetLength(Result, MAX_PATH);
if not SHGetSpecialFolderPath(Handle, PChar(Result), Folder, False) then
RaiseLastOSError;
end;
我在我的应用程序中使用这些来检索非漫游配置文件文件夹,并使用在该文件夹下创建的子文件夹来存储我的应用程序数据。它是在创建TDataModule 期间设置的:
procedure TAppData.Create(Sender.TObject);
begin
// DataPath is a property of the datamodule, declared as a string
// CSIDL_LOCAL_APPDATA is the local non-roaming profile folder.
// CSIDL_APPDATA is for the local roaming profile folder, and is more typically used
DataPath := GetFolderLocation(Application.Handle, CSIDL_LOCAL_APPDATA);
DataPath := IncludeTrailingPathDelimiter(DataPath) + 'MyApp\';
end;
请参阅MSDN's documentation page,了解各种CSIDL_ 或FOLDERID_ 值的含义。 FOLDERID_ 的值类似,但仅适用于 Vista 及更高版本并与 SHGetKnownFolderIDList 一起使用。
对于那些不愿意无视 MS 关于 SHGetSpecialFolderPath 不受支持的警告的人,这里是使用 SHGetFolderPath 的 GetFolderLocation 的替代版本,这是首选:
uses
ShlObj, SHFolder, ActiveX, Windows;
function GetFolderLocation(Handle: HWnd; Folder: Integer): string;
begin
Result := '';
SetLength(Result, MAX_PATH);
if not Succeeded(SHGetFolderPath(Handle, Folder, 0, 0, PChar(Result))) then
RaiseLastOSError();
end;
最后,对于那些只使用 Vista 和更高版本的人,这里有一个使用 SHGetKnownFolderPath 的示例 - 请注意,这在 Delphi 的 XE 版本之前不可用(AFAIK-可能在 2009 年或 2010 年),你'需要使用KNOWNFOLDERID 值而不是CSIDL_,例如FOLDERID_LocalAppData:
uses
ShlObj, ActiveX, KnownFolders;
// Tested on XE2, VCL forms application, Win32 target, on Win7 64-bit Pro
function GetFolderLocation(const Folder: TGuid): string;
var
Buf: PWideChar;
begin
Result := '';
if Succeeded(SHGetKnownFolderPath(Folder, 0, 0, Buf)) then
begin
Result := Buf;
CoTaskMemFree(Buf);
end
else
RaiseLastOSError();
end;