Installation 如何在卸载期间获取安装路径?

Installation 如何在卸载期间获取安装路径?,installation,inno-setup,Installation,Inno Setup,我的想法是让用户可以选择在{localappdata}或{commonappdata}中安装应用程序,这部分工作正常。但是,我使用的是自定义Inno设置蒙皮支持,这需要在安装/卸载期间加载一些函数 我有一个DefaultAppDataFolder():String函数,它返回用户选择的文件夹(公共或本地appdata one),并且在安装过程中工作正常。但是,当我尝试卸载应用程序时,它会在执行时立即抛出以下错误: 脚本错误:无法调用proc 您可以看到,在DefaultAppDataFolder

我的想法是让用户可以选择在
{localappdata}
{commonappdata}
中安装应用程序,这部分工作正常。但是,我使用的是自定义Inno设置蒙皮支持,这需要在安装/卸载期间加载一些函数

我有一个
DefaultAppDataFolder():String
函数,它返回用户选择的文件夹(公共或本地appdata one),并且在安装过程中工作正常。但是,当我尝试卸载应用程序时,它会在执行时立即抛出以下错误:

脚本错误:无法调用proc

您可以看到,在
DefaultAppDataFolder()
函数中,我以一种有点隐蔽的方式获取卸载目录,从
{UninstallExe}
常量中两次提取文件目录,也许有更好的方法来检索它

这是我的剧本:

#define ApplicationName "MyApp"
#define ApplicationExe "app.exe"
#define ApplicationInstanceMutex "APPMUTEX"
#define InstallerFilename "install_app"
#define SkinName "Carbon.vsf"

[Setup]                                                                               
AppName={#ApplicationName}
AppVerName={#ApplicationName}
DefaultDirName={code:DefaultAppDataFolder}
DefaultGroupName={#ApplicationName}
UninstallFilesDir={code:DefaultAppDataFolder}\uninstall
UninstallDisplayName={#ApplicationName}
Compression=lzma2     
SolidCompression=yes
OutputDir=.\
DisableDirPage=yes
OutputBaseFilename={#InstallerFilename}
UninstallDisplayIcon={code:DefaultAppDataFolder}\{#ApplicationExe}
DisableProgramGroupPage=yes
AppMutex={#ApplicationInstanceMutex}
WizardImageFile=installer_images\installer-1.bmp
WizardSmallImageFile=installer_images\installer-2.bmp

[Files]
Source: "skins\VclStylesInno.dll"; DestDir: "{code:DefaultAppDataFolder}"; Flags: uninsneveruninstall ignoreversion
Source: "skins\{#SkinName}"; DestDir: "{code:DefaultAppDataFolder}"; Flags: ignoreversion
Source: "root_files\*.*"; DestDir: "{code:DefaultAppDataFolder}"; Flags: ignoreversion
Source: "client_files\*.*"; DestDir: "{code:DefaultAppDataFolder}"; Flags: ignoreversion
Source: "ssl_libs\*.*"; DestDir: "{code:DefaultAppDataFolder}"; Flags: ignoreversion

[Icons]
Name: "{group}\{#ApplicationName}"; Filename: "{code:DefaultAppDataFolder}\{#ApplicationExe}"; WorkingDir: "{code:DefaultAppDataFolder}"
Name: "{group}\Uninstall"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#ApplicationName}"; Filename: "{code:DefaultAppDataFolder}\{#ApplicationExe}"; Tasks: desktopicon

[Run]
Filename: "{code:DefaultAppDataFolder}\{#ApplicationExe}"; Description: "Launch {#ApplicationName}"; Flags: postinstall nowait runascurrentuser

[Tasks]
Name: commondir; Description: "&All users"; GroupDescription: "Install For:"; Flags: exclusive
Name: localdir; Description: "&Current user"; GroupDescription: "Install For:"; Flags: exclusive unchecked
Name: desktopicon; Description: "Create a &desktop icon"

[Code]
procedure LoadVCLStyleS(VClStyleFile: String); external 'LoadVCLStyleW@files:VclStylesInno.dll stdcall setuponly';
procedure UnLoadVCLStylesS; external 'UnLoadVCLStyles@files:VclStylesInno.dll stdcall setuponly';

procedure LoadVCLStyleU(VClStyleFile: String); external 'LoadVCLStyleW@{code:DefaultAppDataFolder}\VclStylesInno.dll stdcall uninstallonly';
procedure UnLoadVCLStylesU; external 'UnLoadVCLStyles@{code:DefaultAppDataFolder}\VclStylesInno.dll stdcall uninstallonly';

var
  ApplicationUninstalled: Boolean;
  WizardInitialized: Boolean;

function InitializeSetup(): Boolean;
var
  C1: Integer;
begin
  ExtractTemporaryFile('{#SkinName}');
  LoadVCLStyleS(ExpandConstant('{tmp}\{#SkinName}'));
  result := TRUE;
end;

procedure InitializeWizard();
begin
  WizardInitialized := TRUE;
end;

procedure DeinitializeSetup();
begin
  UnLoadVCLStylesS;
end;

function InitializeUninstall(): Boolean;
begin
  LoadVCLStyleU(ExpandConstant('{code:DefaultAppDataFolder}\{#SkinName}'));
  result := TRUE;
end;

procedure InitializeUninstallProgressForm();
begin
  ApplicationUninstalled := TRUE;
end;

procedure DeinitializeUninstall();
begin
  UnLoadVCLStylesU;
  UnloadDLL(ExpandConstant('{code:DefaultAppDataFolder}\VclStylesInno.dll'));

  if ApplicationUninstalled then
  begin
    DeleteFile(ExpandConstant('{code:DefaultAppDataFolder}\VclStylesInno.dll'));
    RemoveDir(ExpandConstant('{code:DefaultAppDataFolder}'));
  end;
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
  mres: integer;
begin
  case CurUninstallStep of
    usPostUninstall: begin
      mres := MsgBox('Do you want to delete user data?', mbConfirmation, MB_YESNO or MB_DEFBUTTON2)
      if mres = IDYES then
      begin   
        DelTree(ExpandConstant('{localappdata}\{#ApplicationName}'), TRUE, TRUE, TRUE);
        DelTree(ExpandConstant('{userappdata}\{#ApplicationName}'), TRUE, TRUE, TRUE);
      end;
    end;  
  end;
end;

function DefaultAppDataFolder(Param: String): String;
begin
  if IsUninstaller then
    result := ExtractFileDir(ExtractFileDir(ExpandConstant('{uninstallexe}')))
  else
    if (WizardInitialized) and
       (IsTaskSelected('localdir')) then
      result := ExpandConstant('{localappdata}') + '\Programs\{#ApplicationName}'
    else
      result := ExpandConstant('{commonappdata}') + '\Programs\{#ApplicationName}';
end;

您得到的错误与卸载程序无关;您可以将问题缩小到以下范围:

[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName=My Program

[Code]
procedure DoSomething;
  external 'DoSomething@{code:GetLibPath}\MyLib.dll stdcall setuponly';

function GetLibPath(Value: string): string;
begin
  Result := 'C:\ValidPathToLib';
end;
从上面的脚本来看,似乎无法对导入的DLL文件名使用脚本常量。即使延迟加载也不能绕过这个限制。但是对于您的情况,您可以只使用
{app}
路径,因为您的库实际上在那里(如果我理解您的意图正确的话):


是的,你就在那里。但是,只有在
{commonappdata}
dir中安装应用程序时,此选项才有效,而在
{localappdata}
dir中安装应用程序时,此选项不起作用。当我运行卸载程序时,它说:“无法导入dll:C:\ProgramData\Programs\App\VclStylesInno.dll”,这意味着由于某种原因,
{App}
总是引用
{commonappdata}
目录。我把MsgBox()放在DefaultAppDataFolder()中,它看起来在出错之前还没有执行,所以我不知道它是从哪里得到这个目录的??有趣的是,即使我选择将它安装到{localappdata}目录,它也会创建一个空白的{commonappdata}\Programs\App目录。对我来说,重建项目非常困难。但我会从重构脚本开始;e、 g.
DefaultAppDataFolder
功能被过度使用。我个人使用它只是为了设置
DefaultDirName
指令值,在所有其他(可能的)地方使用just
{app}
。由于我跳过了DirPage,我相信{app}只在安装程序/卸载程序开始时初始化一次,并且它指向{commonappdata}目录。所以我不能真正使用{app},但我们现在离解决方案越来越近了,我想我需要在任务表单之后更改DefaultDir变量(WizardForm.DirEdit.Text),对吗?然而,这并不能解决卸载问题。是的,这就解决了问题。我在PrepareToInstall()回调中设置了WizardForm.DirEdit.Text,即使对于卸载程序,它也可以完美地工作。以下是完整的脚本:。谢谢你为我指明了正确的方向!如果您编辑您的答案来解释这一点,我也会接受它,因此它可以作为进一步读者的有用参考。您应该安装到
{userpf}
。在
{commonappdata}
{localappdata}
之间进行选择是不明智的。对,
{userpf}
似乎等同于
{localappdata}\程序
。但如果我想给用户一个选项来为系统上的所有用户安装应用程序呢?然后你给他们一个单独的安装程序。不能在一个脚本中同时完成这两件事,因为它们需要不同的权限级别。
...
procedure LoadVCLStyleU(VClStyleFile: string);
  external 'LoadVCLStyleW@{app}\VclStylesInno.dll stdcall uninstallonly';
procedure UnLoadVCLStylesU;
  external 'UnLoadVCLStyles@{app}\VclStylesInno.dll stdcall uninstallonly';
...