【问题标题】:what causes this error 'Unable to write to application file.ini'是什么导致此错误“无法写入应用程序 file.ini”
【发布时间】:2012-06-27 08:24:51
【问题描述】:

我的应用程序是在 delphi 中构建的,它可以在除 Windows 7 64 位机器之外的其他平台上完美运行。每次尝试关闭应用程序都会给我这个错误 '无法写入应用程序 file.ini'

这是我的关闭代码

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
      frmMain.close;
end;

【问题讨论】:

  • 这个代码是错误的,顺便说一句。删除frmMain,只使用Close。添加frmMain 会将其绑定到表单的单个实例,而不是处理任何实例。如果出于某种原因必须对其进行限定,请使用 Self 而不是特定的变量名。
  • OnClose 事件处理程序内部调用Close() 是错误的,因为Close() 已经在运行,所以这会创建一个无限递归循环。

标签: delphi delphi-xe2


【解决方案1】:

此错误通常是由于尝试写入您的应用程序自己在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 不受支持的警告的人,这里是使用 SHGetFolderPathGetFolderLocation 的替代版本,这是首选:

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 舞会更容易
  • @David,很好。之前的RaiseLastOSError 版本的 Delphi 使用SysErrorMessage 代替,旧代码 sn-p lib 仍然包含它(以及其他一些旧东西,如您所见)。现在已经更新了。 :-)
  • 如果您不需要支持漫游,使用CSIDL_LOCAL_APPDATA 没有任何问题。 MS 不再支持SHGetSpecialFolderPath(),请改用SHGetFolderPath()
【解决方案2】:

您不应该将 ini 文件写入程序目录。虽然它在过去工作,但从来都不是一个好的做法。

您应该将%APPDATA% 用于用户特定的应用程序数据。

您可能想阅读Best practices storing application data

【讨论】:

    猜你喜欢
    • 2020-12-24
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    • 2022-07-06
    • 1970-01-01
    • 2022-07-22
    • 1970-01-01
    • 2023-03-24
    相关资源
    最近更新 更多