2012-06-27 54 views
1

我的应用程序是在delphi中构建的,并且在除Windows 7 64位机器以外的其他平台上运行完美。每个和每次尝试关闭该应用程序是给我这个错误 “无法写入应用程序file.ini”什么原因导致此错误'无法写入应用程序file.ini'

这里是我的代码以关闭

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

此代码有误,顺便说一句。删除'frmMain',并使用'Close'。将frmMain添加到表单的一个实例,而不是在任何实例上工作。如果你必须**由于某种原因限定它,请使用'Self'而不是特定的变量名称。 –

+1

因为'Close()'已经在运行,所以它在OnClose事件处理函数内部调用'Close()'是错误的,所以这会创建一个无限循环递归循环。 –

回答

4

你不应该INI文件写入程序目录。尽管过去一直在上工作,但它从来不是一个好的做法。

对于用户特定的应用程序数据,您应该使用%APPDATA%

你可能想读通过尝试写Program Files在你的应用程序自己的文件夹,这是不允许的在Vista下非管理员和Best practices storing application data

9

这个错误通常是由于较高的(和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; 
+3

由于非漫游,使用'CSIDL_LOCAL_APPDATA'将会非常不寻常。改为使用'CSIDL_APPDATA'。另外,如果您准备忽略“SHGetSpecialFolderPath”不受支持的可怕MS警告,则它更容易调用“SHGetSpecialFolderPath”,并避免PIDL跳舞! –

+0

@大卫,很好。 Delphi的Pre-'LaiseLastOSError'版本使用'SysErrorMessage'代替它,而旧的代码片段库仍然有它(和其他一些旧东西,就像你看到的那样)。它现在已经更新了。:-) –

+0

如果您不需要支持漫游,那么使用'CSIDL_LOCAL_APPDATA'没有任何问题。而'SHGetSpecialFolderPath()'不再被MS支持,而是使用'SHGetFolderPath()'。 –

相关问题