Pregunta

My idea is to offer the user the choice of installing the application either in {localappdata} or {commonappdata}, and that part works fine. However, I'm using custom Inno Setup skinning support, which requires a couple functions to get loaded during installation/uninstallation.

I have a DefaultAppDataFolder(): String function which returns the folder that the user chose (either common or local appdata one), and it works fine during installation. However, when I try to uninstall the app, it throws following error right upon execution:

Script error: Could not call proc

You can see that in the DefaultAppDataFolder() function I'm getting the uninstall directory in a bit shady way, extracting the file directory twice from the {UninstallExe} constant, maybe there is a better way to retrieve this?

Here is my script:

#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;
¿Fue útil?

Solución

The error you got is not related to the uninstaller; you can narrow the problem down to this:

[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;

From the above script it seems that you cannot use scripted constants for imported DLL file names. And even delayed loading didn't workaround this limit. But for your case you can use just {app} path since your library is actually there (if I get your intention right):

...
procedure LoadVCLStyleU(VClStyleFile: string);
  external 'LoadVCLStyleW@{app}\VclStylesInno.dll stdcall uninstallonly';
procedure UnLoadVCLStylesU;
  external 'UnLoadVCLStyles@{app}\VclStylesInno.dll stdcall uninstallonly';
...
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top