我的应用程序是在delphi中构建的,并且在除Windows 7 64位机器以外的其他平台上运行完美。每个和每次尝试关闭该应用程序是给我这个错误 “无法写入应用程序file.ini”什么原因导致此错误'无法写入应用程序file.ini'
这里是我的代码以关闭
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
frmMain.close;
end;
我的应用程序是在delphi中构建的,并且在除Windows 7 64位机器以外的其他平台上运行完美。每个和每次尝试关闭该应用程序是给我这个错误 “无法写入应用程序file.ini”什么原因导致此错误'无法写入应用程序file.ini'
这里是我的代码以关闭
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
frmMain.close;
end;
你不应该INI文件写入程序目录。尽管过去一直在上工作,但它从来不是一个好的做法。
对于用户特定的应用程序数据,您应该使用%APPDATA%
。
你可能想读通过尝试写Program Files
在你的应用程序自己的文件夹,这是不允许的在Vista下非管理员和Best practices storing application data
这个错误通常是由于较高的(和XP中,如果您没有以管理员或高级用户身份运行)。
以下是获取正确的文件夹为您的.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
不被支持,下面是GetFolderLocation
可替代的形式使用SHGetFolderPath
,这是首选:
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;
由于非漫游,使用'CSIDL_LOCAL_APPDATA'将会非常不寻常。改为使用'CSIDL_APPDATA'。另外,如果您准备忽略“SHGetSpecialFolderPath”不受支持的可怕MS警告,则它更容易调用“SHGetSpecialFolderPath”,并避免PIDL跳舞! –
@大卫,很好。 Delphi的Pre-'LaiseLastOSError'版本使用'SysErrorMessage'代替它,而旧的代码片段库仍然有它(和其他一些旧东西,就像你看到的那样)。它现在已经更新了。:-) –
如果您不需要支持漫游,那么使用'CSIDL_LOCAL_APPDATA'没有任何问题。而'SHGetSpecialFolderPath()'不再被MS支持,而是使用'SHGetFolderPath()'。 –
此代码有误,顺便说一句。删除'frmMain',并使用'Close'。将frmMain添加到表单的一个实例,而不是在任何实例上工作。如果你必须**由于某种原因限定它,请使用'Self'而不是特定的变量名称。 –
因为'Close()'已经在运行,所以它在OnClose事件处理函数内部调用'Close()'是错误的,所以这会创建一个无限循环递归循环。 –