Update the Windows setup script

Update the Windows setup script

; Script generated by the Inno Script Studio Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{2EF654FA-68EC-4AEE-AA11-5BBF2395098D}
AppName=MoonDeploy
AppVersion=3.0
AppPublisher=Gianluca Costa
AppPublisherURL=https://github.com/giancosta86/moondeploy
AppSupportURL=https://github.com/giancosta86/moondeploy
AppUpdatesURL=https://github.com/giancosta86/moondeploy
DefaultDirName=C:\MoonDeploy
DefaultGroupName=MoonDeploy
DisableProgramGroupPage=yes
LicenseFile=..\LICENSE
OutputBaseFilename=MoonDeploy-setup
Compression=lzma
SolidCompression=yes
ChangesAssociations=True
WizardImageFile=SideImage.bmp
WizardSmallImageFile=SmallImage.bmp
AppCopyright=Copyright  2015-2016 Gianluca Costa
UninstallDisplayIcon={app}\moondeploy.ico
ArchitecturesInstallIn64BitMode=x64 ia64

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Files]
Source: "..\build\windows\moondeployw.exe"; DestDir: "{app}"; Flags: 64bit
Source: "..\build\windows\moondeploy.exe"; DestDir: "{app}"; Flags: 64bit
Source: "..\build\windows\moondeploy.ico"; DestDir: "{app}"
Source: "..\build\windows\moondeploy.png"; DestDir: "{app}"
Source: "..\moondeploy.glade"; DestDir: "{app}"

[Registry]
Root: HKCR; SubKey: ".moondeploy"; ValueType: string; ValueData: "MoonDeploy Application"; Flags: uninsdeletekey
Root: HKCR; SubKey: "MoonDeploy Application"; ValueType: string; ValueData: "MoonDeploy application"; Flags: uninsdeletekey
Root: HKCR; SubKey: "MoonDeploy Application\Shell\Open\Command"; ValueType: string; ValueData: """{app}\moondeployw.exe"" ""%1"""; Flags: uninsdeletekey
Root: HKCR; Subkey: "MoonDeploy Application\DefaultIcon"; ValueType: string; ValueData: "{app}\moondeploy.ico,0"; Flags: uninsdeletevalue

; Script generated by the Inno Script Studio Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{2EF654FA-68EC-4AEE-AA11-5BBF2395098D}
AppName=MoonDeploy
AppVersion=2.0
AppPublisher=Gianluca Costa
AppPublisherURL=https://github.com/giancosta86/moondeploy
AppSupportURL=https://github.com/giancosta86/moondeploy
AppUpdatesURL=https://github.com/giancosta86/moondeploy
DefaultDirName=C:\MoonDeploy
DefaultGroupName=MoonDeploy
DisableProgramGroupPage=yes
LicenseFile=..\LICENSE
OutputBaseFilename=MoonDeploy-setup
Compression=lzma
SolidCompression=yes
ChangesAssociations=True
WizardImageFile=SideImage.bmp
WizardSmallImageFile=SmallImage.bmp
AppCopyright=Copyright  2015-2016 Gianluca Costa
UninstallDisplayIcon={app}\moondeploy.ico
ArchitecturesInstallIn64BitMode=x64 ia64

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Files]
Source: "..\build\windows\moondeployw.exe"; DestDir: "{app}"; Flags: 64bit
Source: "..\build\windows\moondeploy.exe"; DestDir: "{app}"; Flags: 64bit
Source: "..\build\windows\moondeploy.ico"; DestDir: "{app}"
Source: "..\build\windows\moondeploy.png"; DestDir: "{app}"
Source: "..\moondeploy.glade"; DestDir: "{app}"

[Registry]
Root: HKCR; SubKey: ".moondeploy"; ValueType: string; ValueData: "MoonDeploy Application"; Flags: uninsdeletekey
Root: HKCR; SubKey: "MoonDeploy Application"; ValueType: string; ValueData: "MoonDeploy application"; Flags: uninsdeletekey
Root: HKCR; SubKey: "MoonDeploy Application\Shell\Open\Command"; ValueType: string; ValueData: """{app}\moondeployw.exe"" ""%1"""; Flags: uninsdeletekey
Root: HKCR; Subkey: "MoonDeploy Application\DefaultIcon"; ValueType: string; ValueData: "{app}\moondeploy.ico,0"; Flags: uninsdeletevalue


Only use wmic now that XP is not supported

[Code]

const
  SID_START = 'S-1-5-21-';

type
  TUserDataRec = record
    User      : String;
    Folder    : String;
    Caption   : String;
    Delete    : Boolean;
    Local     : Boolean;
  end;

type
  TUserFolderRec = record
    User      : String;
    Home      : String;
    Cache     : String;
  end;

type
  TUserDataList = array of TUserDataRec;

type
  TUserProfileRec = record
    User      : String;
    Profile   : String;
  end;

type
  TUserProfileList = array of TUserProfileRec;

type
  TDataForm = record
    Main: TSetupForm;
    ListBox: TNewCheckListBox;
  end;

var
  GUserForm: TDataForm;

const
  DELETE_NONE = 0;
  DELETE_LOCAL = 1;
  DELETE_ALL = 2;

function DeleteData(HParent: HWND; DirList: String; Silent: Boolean): Boolean;
  external 'DeleteData@{app}\{#DllData} stdcall delayload uninstallonly';

function GetResult(StrBuf: String; BufCount: DWord): DWord;
  external 'GetResult@{app}\{#DllData} stdcall delayload uninstallonly';

procedure UserDataDelete; forward;
function UserDataGet(Status: Integer): TUserDataList; forward;
procedure UserDataGetAll(const User: String; var List: TUserDataList); forward;
function UserGetAccounts(var Accounts: TUserProfileList): Boolean; forward;
function UserGetProfile(const Sid: String; var Path: String): Boolean; forward;
procedure UserAddProfileRec(const User, Profile: String; var Accounts: TUserProfileList); forward;
procedure UserAddDataItem(User, Folder, Caption: String; Local: Boolean; var List: TUserDataList); forward;
procedure UserAddDataRec(Rec: TUserFolderRec; var List: TUserDataList); forward;
function UserGetFolderPrefix(const Folder: String; var Prefix: String): Boolean; forward;
procedure UserDeleteData(List: TUserDataList; const DllData: String); forward;
function UserDataSelect(Status: Integer; var List: TUserDataList): Boolean; forward;
procedure UserDataCreateForm(Status: Integer; var Form: TDataForm); forward;
procedure UserCheckboxClick(Sender: TObject); forward;
function UserGetDelete: Integer; forward;

procedure UserDataDelete;
var
  List: TUserDataList;
  DllData: String;
  Status: Integer;

begin

  {The main function, must be called from Uninstall step usUninstall,
  otherwise the dll and app dir will not be deleted}

  DllData := ExpandConstant('{app}\{#DllData}');
  Status := UserGetDelete();

  try

    List := UserDataGet(Status);

    if UninstallSilent or UserDataSelect(Status, List) then
      UserDeleteData(List, DllData);

  finally
    {Important to unload dll, or it will not be deleted}
    UnloadDLL(DllData);
  end;

end;

function UserDataGet(Status: Integer): TUserDataList;
var
  Rec: TUserFolderRec;
  I: Integer;

begin

  {Add current user as first item}
  Rec.User := GetUserNameString;
  Rec.Home := ExpandConstant('{userappdata}\Composer');
  Rec.Cache := ExpandConstant('{localappdata}\Composer');
  UserAddDataRec(Rec, Result);

  if IsAdminInstallMode then
    UserDataGetAll(Rec.User, Result);

  for I := 0 to GetArrayLength(Result) - 1 do
  begin

    case Status of
      DELETE_NONE: Result[I].Delete := False;
      DELETE_LOCAL: Result[I].Delete := Result[I].Local;
      DELETE_ALL: Result[I].Delete := True;
    end;

  end;

end;

procedure UserDataGetAll(const User: String; var List: TUserDataList);
var
  HomeSuffix: String;
  CacheSuffix: String;
  Accounts: TUserProfileList;
  I: Integer;
  SafeDir: String;
  SystemDir: String;
  Rec: TUserFolderRec;

begin

  {We use Windows wmi as this is a reliable way to get the correct
  user name for each local account}

  if UserGetFolderPrefix('AppData', HomeSuffix) then
    HomeSuffix := AddBackslash(HomeSuffix) + 'Composer'
  else
    Exit;

  if UserGetFolderPrefix('Local AppData', CacheSuffix) then
    CacheSuffix := AddBackslash(CacheSuffix) + 'Composer'
  else
    Exit;

  if not UserGetAccounts(Accounts) then
    Exit;

  SystemDir := AnsiLowercase(GetSystemDir());

  {Check profile paths and add suffixes}
  for I := 0 to GetArrayLength(Accounts) - 1 do
  begin

    {Ignore current user - first item in List}
    if CompareText(User, Accounts[I].User) = 0 then
      Continue;

    SafeDir := NormalizePath(Accounts[I].Profile);

    if (SafeDir = '') or (Pos('\\',SafeDir) = 1) or (Pos(SystemDir, AnsiLowercase(SafeDir)) = 1) then
      Continue;

    Rec.User := Accounts[I].User;
    Rec.Home := AddBackslash(SafeDir) + HomeSuffix;
    Rec.Cache := AddBackslash(SafeDir) + CacheSuffix;
    UserAddDataRec(Rec, List);

  end;

end;

function UserGetAccounts(var Accounts: TUserProfileList): Boolean;
var
  Cmd: String;
  Dir: String;
  Output: String;
  Params: String;
  ExitCode: Longint;
  SList: TStringList;
  Line: String;
  I: Integer;
  P: Integer;
  Sid: String;
  User: String;
  Profile: String;

begin

  Result := False;

  Cmd := ExpandConstant('{cmd}');
  Dir := ExpandConstant('{tmp}');
  Output := Dir + '\result.txt';

  Params := Format('/c "%s %s > %s"', ['wmic', 'USERACCOUNT GET Name,SID,Disabled', ArgCmd(Output)]);
  Debug('Calling cmd.exe with params: ' + Params);

  if not (Exec(Cmd, Params, Dir, 0, ewWaitUntilTerminated, ExitCode)) or (ExitCode <> 0) then
    Exit;

  {We use TStringList because this handles the BOM produced in the output file}
  SList := TStringList.Create();

  try

    SList.LoadFromFile(Output);

    {Format is always: Disabled (TRUE/FALSE) tab UserName tab SID, for example:
    FALSE    Fred    S-1-5-21-2053653857-3368111017-1490883677-1002}

    for I := 0 to SList.Count - 1 do
    begin

      Line := Trim(SList.Strings[I]);

      {Check and strip FALSE (ie not disabled)}
      if Pos('FALSE', Line) = 1 then
        Line := TrimLeft(Copy(Line, 6, MaxInt))
      else
        Continue;

      {Check for relevant SID}
      P := Pos(SID_START, Line);

      if P > 0 then
      begin

        Sid := Copy(Line, P, MaxInt);
        User := TrimRight(Copy(Line, 1, P - 1));

        if UserGetProfile(Sid, Profile) then
          UserAddProfileRec(User, Profile, Accounts);

      end;

    end;

  finally
    SList.Free;
  end;

  Result := GetArrayLength(Accounts) > 0;

end;

function UserGetProfile(const Sid: String; var Path: String): Boolean;
var
  SubKey: String;

begin

  Result := False;
  Path := '';

  SubKey := 'Software\Microsoft\Windows NT\CurrentVersion\ProfileList\' + Sid;

  if RegQueryStringValue(HKLM, SubKey, 'ProfileImagePath', Path) then
    Result := True;

end;

procedure UserAddProfileRec(const User, Profile: String; var Accounts: TUserProfileList);
var
  Index: Integer;

begin

  Index := GetArrayLength(Accounts);
  SetArrayLength(Accounts, Index + 1);
  Accounts[Index].User := User;
  Accounts[Index].Profile := Profile;

end;

procedure UserAddDataItem(User, Folder, Caption: String; Local: Boolean; var List: TUserDataList);
var
  Index: Integer;

begin

  Index := GetArrayLength(List);
  SetArrayLength(List, Index + 1);
  List[Index].User := User;
  List[Index].Folder := Folder;
  List[Index].Caption := Caption;
  List[Index].Local := Local;

end;

procedure UserAddDataRec(Rec: TUserFolderRec; var List: TUserDataList);
var
  User: String;
  Caption: String;
  Local: Boolean;

begin

  if DirExists(Rec.Cache) then
  begin
    User := Rec.User + ': local';
    Caption := 'cache';
    Local := True;
    UserAddDataItem(User, Rec.Cache, Caption, Local, List);
  end;

  if DirExists(Rec.Home) then
  begin
    User := Rec.User + ': roaming';
    Caption := 'config';
    Local := False;

    if DirExists(Rec.Home + '\vendor') then
      Caption := Caption + ', bin';

    UserAddDataItem(User, Rec.Home, Caption, Local, List);
  end;

end;

function UserGetFolderPrefix(const Folder: String; var Prefix: String): Boolean;
var
  SubKey: String;
  Profile: String;

begin

  Result := False;
  Prefix := '';

  SubKey := '.DEFAULT\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders';

  if not RegQueryStringValue(HKEY_USERS, SubKey, Folder, Prefix) then
    Exit;

  Profile := '%USERPROFILE%';

  if Pos(Profile, Prefix) <> 1 then
    Exit;

  Prefix := Copy(Prefix, Length(Profile) + 1, MaxInt);
  StringChangeEx(Prefix, '/', '\', True);
  Result := Prefix <> '';

end;

procedure UserDeleteData(List: TUserDataList; const DllData: String);
var
  Data: String;
  I: Integer;
  CharCount: DWord;
  InfoList: TStringList;

begin

  for I := 0 to GetArrayLength(List) - 1 do
  begin

    if List[I].Delete then
      Data := Data + List[I].Folder + ';';

  end;

  if Data = '' then
    Exit;

  Debug('Calling dll: ' + DllData);
  DeleteData(UninstallProgressForm.Handle, Data, UninstallSilent);

  CharCount := 0;
  CharCount := GetResult(Data, CharCount);
  SetLength(Data, CharCount);

  if GetResult(Data, CharCount) <> CharCount then
    Exit;

  Data := TrimRight(Data);
  StringChangeEx(Data, ';', #13, True);

  InfoList := TStringList.Create;

  try
    InfoList.Text := Data;

    for I := 0 to InfoList.Count - 1 do
      Debug(InfoList.Strings[I]);

  finally
    InfoList.Free;
  end;

  {Update uninstall form so it repaints}
  Sleep(10);
  UninstallProgressForm.Update;

end;

function UserDataSelect(Status: Integer; var List: TUserDataList): Boolean;
var
  I: Integer;
  Index: Integer;

begin

  Result := False;

  if GetArrayLength(List) = 0 then
  begin
    Debug('No user data found');
    Exit;
  end;

  {Create the form}
  UserDataCreateForm(Status, GUserForm);

  try

    {Populate the listbox}
    for I := 0 to GetArrayLength(List) - 1 do
    begin
      GUserForm.ListBox.AddCheckBox(List[I].User, List[I].Caption, 0,
        List[I].Delete, True, False, False, TObject(I));
    end;

    {Show the form}
    GUserForm.Main.ShowModal();

    {Transfer checked items to Delete field}
    for I := 0 to GUserForm.ListBox.Items.Count - 1 do
    begin

      Index := Integer(GUserForm.ListBox.ItemObject[I]);
      List[Index].Delete := GUserForm.ListBox.Checked[I];

      if GUserForm.ListBox.Checked[I] then
        Result := True;

    end;

    if Result then
      Debug('User chose to delete data')
    else
      Debug('User chose not to delete data');

  finally
    GUserForm.Main.Free();
  end;

end;

procedure UserDataCreateForm(Status: Integer; var Form: TDataForm);
var
  Left: Integer;
  Width: Integer;
  Text: TNewStaticText;
  Checkbox: TNewCheckbox;
  OkButton: TButton;

begin

  Form.Main := CreateCustomForm();
  Form.Main.Font.Size := 9;

  Form.Main.ClientWidth := ScaleX(380);
  Form.Main.ClientHeight := ScaleY(255);
  Form.Main.Caption := 'Delete User Data';
  Form.Main.FlipSizeAndCenterIfNeeded(True, UninstallProgressForm, False);

  Left := ScaleX(20);
  Width := Form.Main.ClientWidth - (Left * 2);

  Text := TNewStaticText.Create(Form.Main);
  Text.Top := ScaleY(16);
  Text.Parent := Form.Main;
  Text.Left := Left;
  Text.Width := Width;
  Text.AutoSize := True;
  Text.WordWrap := True;
  Text.Caption := 'Please select the user data you want to delete.';

  Form.ListBox := TNewCheckListBox.Create(Form.Main);
  Form.ListBox.Top := Text.Top + Text.Height + ScaleY(10);
  Form.ListBox.Parent := Form.Main;
  Form.ListBox.Left := Left;
  Form.ListBox.Width := Width;
  Form.ListBox.Height := ScaleY(148);

  Checkbox := TNewCheckbox.Create(Form.Main);
  Checkbox.Top := Form.ListBox.Top + Form.ListBox.Height + ScaleY(6);
  Checkbox.Left := Left;
  Checkbox.Parent := Form.Main;
  Checkbox.Caption := 'Select All';
  Checkbox.Checked := Status = DELETE_ALL;
  Checkbox.OnClick := @UserCheckboxClick;

  OkButton := TButton.Create(Form.Main);
  OkButton.Parent := Form.Main;
  OkButton.Width := ScaleX(75);
  OkButton.Height := ScaleY(23);
  OkButton.Left := Form.Main.ClientWidth - (ScaleX(75) + Left);
  OkButton.Top := Form.Main.ClientHeight - ScaleY(23 + 16);
  OkButton.Caption := '&OK';
  OkButton.ModalResult := mrOk;
  OKButton.Default := True;

  Form.Main.ActiveControl := OkButton;

end;

procedure UserCheckboxClick(Sender: TObject);
var
  Checkbox: TNewCheckbox;
  I: Integer;

begin

  Checkbox := Sender as TNewCheckbox;

  for I := 0 to GUserForm.ListBox.Items.Count - 1 do
    GUserForm.ListBox.Checked[I] := Checkbox.Checked;

end;

function UserGetDelete: Integer;
var
  Param: String;

begin

  Result := DELETE_NONE;
  Param := ExpandConstant('{param:delete}');

  if CompareText(Param, 'local') = 0 then
    Result := DELETE_LOCAL
  else if CompareText(Param, 'all') = 0 then
    Result := DELETE_ALL;

end;

[Code]

const
  SID_START = 'S-1-5-21-';

type
  TUserDataRec = record
    User      : String;
    Folder    : String;
    Caption   : String;
    Delete    : Boolean;
    Local     : Boolean;
  end;

type
  TUserFolderRec = record
    User      : String;
    Home      : String;
    Cache     : String;
  end;

type
  TUserDataList = array of TUserDataRec;

type
  TUserProfileRec = record
    User      : String;
    Profile   : String;
  end;

type
  TUserProfileList = array of TUserProfileRec;

type
  TDataForm = record
    Main: TSetupForm;
    ListBox: TNewCheckListBox;
  end;

var
  GUserForm: TDataForm;

const
  DELETE_NONE = 0;
  DELETE_LOCAL = 1;
  DELETE_ALL = 2;

function DeleteData(HParent: HWND; DirList: String; Silent: Boolean): Boolean;
  external 'DeleteData@{app}\{#DllData} stdcall delayload uninstallonly';

function GetResult(StrBuf: String; BufCount: DWord): DWord;
  external 'GetResult@{app}\{#DllData} stdcall delayload uninstallonly';

procedure UserDataDelete; forward;
function UserDataGet(Status: Integer): TUserDataList; forward;
procedure UserDataGetAll(const User: String; var List: TUserDataList); forward;
function UserGetAccountsWmi(var Accounts: TUserProfileList): Boolean; forward;
function UserGetAccountsReg(var Accounts: TUserProfileList): Boolean; forward;
function UserGetProfile(const Sid: String; var Path: String): Boolean; forward;
procedure UserAddProfileRec(const User, Profile: String; var Accounts: TUserProfileList); forward;
procedure UserAddDataItem(User, Folder, Caption: String; Local: Boolean; var List: TUserDataList); forward;
procedure UserAddDataRec(Rec: TUserFolderRec; var List: TUserDataList); forward;
function UserGetFolderPrefix(const Folder: String; var Prefix: String): Boolean; forward;
procedure UserDeleteData(List: TUserDataList; const DllData: String); forward;
function UserDataSelect(Status: Integer; var List: TUserDataList): Boolean; forward;
procedure UserDataCreateForm(Status: Integer; var Form: TDataForm); forward;
procedure UserCheckboxClick(Sender: TObject); forward;
function UserGetDelete: Integer; forward;

procedure UserDataDelete;
var
  List: TUserDataList;
  DllData: String;
  Status: Integer;

begin

  {The main function, must be called from Uninstall step usUninstall,
  otherwise the dll and app dir will not be deleted}

  DllData := ExpandConstant('{app}\{#DllData}');
  Status := UserGetDelete();

  try

    List := UserDataGet(Status);

    if UninstallSilent or UserDataSelect(Status, List) then
      UserDeleteData(List, DllData);

  finally
    {Important to unload dll, or it will not be deleted}
    UnloadDLL(DllData);
  end;

end;

function UserDataGet(Status: Integer): TUserDataList;
var
  Rec: TUserFolderRec;
  I: Integer;

begin

  {Add current user as first item}
  Rec.User := GetUserNameString;
  Rec.Home := ExpandConstant('{userappdata}\Composer');
  Rec.Cache := ExpandConstant('{localappdata}\Composer');
  UserAddDataRec(Rec, Result);

  if IsAdminInstallMode then
    UserDataGetAll(Rec.User, Result);

  for I := 0 to GetArrayLength(Result) - 1 do
  begin

    case Status of
      DELETE_NONE: Result[I].Delete := False;
      DELETE_LOCAL: Result[I].Delete := Result[I].Local;
      DELETE_ALL: Result[I].Delete := True;
    end;

  end;

end;

procedure UserDataGetAll(const User: String; var List: TUserDataList);
var
  HomeSuffix: String;
  CacheSuffix: String;
  Accounts: TUserProfileList;
  I: Integer;
  SafeDir: String;
  SystemDir: String;
  Rec: TUserFolderRec;

begin

  {We use Windows wmi as this is a reliable way to get the correct user name
  for each local account. If this is not available (it is missing from XP Home),
  we fallback to using the registry.}

  if UserGetFolderPrefix('AppData', HomeSuffix) then
    HomeSuffix := AddBackslash(HomeSuffix) + 'Composer'
  else
    Exit;

  if UserGetFolderPrefix('Local AppData', CacheSuffix) then
    CacheSuffix := AddBackslash(CacheSuffix) + 'Composer'
  else
    Exit;

  if not (UserGetAccountsWmi(Accounts) or UserGetAccountsReg(Accounts)) then
    Exit;

  SystemDir := AnsiLowercase(GetSystemDir());

  {Check profile paths and add suffixes}
  for I := 0 to GetArrayLength(Accounts) - 1 do
  begin

    {Ignore current user - first item in List}
    if CompareText(User, Accounts[I].User) = 0 then
      Continue;

    SafeDir := NormalizePath(Accounts[I].Profile);

    if (SafeDir = '') or (Pos('\\',SafeDir) = 1) or (Pos(SystemDir, AnsiLowercase(SafeDir)) = 1) then
      Continue;

    Rec.User := Accounts[I].User;
    Rec.Home := AddBackslash(SafeDir) + HomeSuffix;
    Rec.Cache := AddBackslash(SafeDir) + CacheSuffix;
    UserAddDataRec(Rec, List);

  end;

end;

function UserGetAccountsWmi(var Accounts: TUserProfileList): Boolean;
var
  Cmd: String;
  Dir: String;
  Output: String;
  Params: String;
  ExitCode: Longint;
  SList: TStringList;
  Line: String;
  I: Integer;
  P: Integer;
  Sid: String;
  User: String;
  Profile: String;

begin

  Result := False;

  Cmd := ExpandConstant('{cmd}');
  Dir := ExpandConstant('{tmp}');
  Output := Dir + '\result.txt';

  Params := Format('/c "%s %s > %s"', ['wmic', 'USERACCOUNT GET Name,SID,Disabled', ArgCmd(Output)]);
  Debug('Calling cmd.exe with params: ' + Params);

  if not (Exec(Cmd, Params, Dir, 0, ewWaitUntilTerminated, ExitCode)) or (ExitCode <> 0) then
    Exit;

  {We use TStringList because this handles the BOM produced in the output file}
  SList := TStringList.Create();

  try

    SList.LoadFromFile(Output);

    {Format is always: Disabled (TRUE/FALSE) tab UserName tab SID, for example:
    FALSE    Fred    S-1-5-21-2053653857-3368111017-1490883677-1002}

    for I := 0 to SList.Count - 1 do
    begin

      Line := Trim(SList.Strings[I]);

      {Check and strip FALSE (ie not disabled)}
      if Pos('FALSE', Line) = 1 then
        Line := TrimLeft(Copy(Line, 6, MaxInt))
      else
        Continue;

      {Check for relevant SID}
      P := Pos(SID_START, Line);

      if P > 0 then
      begin

        Sid := Copy(Line, P, MaxInt);
        User := TrimRight(Copy(Line, 1, P - 1));

        if UserGetProfile(Sid, Profile) then
          UserAddProfileRec(User, Profile, Accounts);

      end;

    end;

  finally
    SList.Free;
  end;

  Result := GetArrayLength(Accounts) > 0;

end;

function UserGetAccountsReg(var Accounts: TUserProfileList): Boolean;
var
  SubKey: String;
  Sids: TArrayofString;
  I: Integer;
  Profile: String;

begin

  Result := False;

  SubKey := 'Software\Microsoft\Windows NT\CurrentVersion\ProfileList'

  if not RegGetSubkeyNames(HKLM, SubKey, Sids) then
    Exit;

  for I := 0 to GetArrayLength(Sids) - 1 do
  begin

    if Pos(SID_START, Sids[I]) <> 0 then
    begin

      if UserGetProfile(Sids[I], Profile) then
        UserAddProfileRec(ExtractFileName(Profile), Profile, Accounts);

    end;

  end;

  Result := GetArrayLength(Accounts) > 0;

end;

function UserGetProfile(const Sid: String; var Path: String): Boolean;
var
  SubKey: String;

begin

  Result := False;
  Path := '';

  SubKey := 'Software\Microsoft\Windows NT\CurrentVersion\ProfileList\' + Sid;

  if RegQueryStringValue(HKLM, SubKey, 'ProfileImagePath', Path) then
    Result := True;

end;

procedure UserAddProfileRec(const User, Profile: String; var Accounts: TUserProfileList);
var
  Index: Integer;

begin

  Index := GetArrayLength(Accounts);
  SetArrayLength(Accounts, Index + 1);
  Accounts[Index].User := User;
  Accounts[Index].Profile := Profile;

end;

procedure UserAddDataItem(User, Folder, Caption: String; Local: Boolean; var List: TUserDataList);
var
  Index: Integer;

begin

  Index := GetArrayLength(List);
  SetArrayLength(List, Index + 1);
  List[Index].User := User;
  List[Index].Folder := Folder;
  List[Index].Caption := Caption;
  List[Index].Local := Local;

end;

procedure UserAddDataRec(Rec: TUserFolderRec; var List: TUserDataList);
var
  User: String;
  Caption: String;
  Local: Boolean;

begin

  if DirExists(Rec.Cache) then
  begin
    User := Rec.User + ': local';
    Caption := 'cache';
    Local := True;
    UserAddDataItem(User, Rec.Cache, Caption, Local, List);
  end;

  if DirExists(Rec.Home) then
  begin
    User := Rec.User + ': roaming';
    Caption := 'config';
    Local := False;

    if DirExists(Rec.Home + '\vendor') then
      Caption := Caption + ', bin';

    UserAddDataItem(User, Rec.Home, Caption, Local, List);
  end;

end;

function UserGetFolderPrefix(const Folder: String; var Prefix: String): Boolean;
var
  SubKey: String;
  Profile: String;

begin

  Result := False;
  Prefix := '';

  SubKey := '.DEFAULT\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders';

  if not RegQueryStringValue(HKEY_USERS, SubKey, Folder, Prefix) then
    Exit;

  Profile := '%USERPROFILE%';

  if Pos(Profile, Prefix) <> 1 then
    Exit;

  Prefix := Copy(Prefix, Length(Profile) + 1, MaxInt);
  StringChangeEx(Prefix, '/', '\', True);
  Result := Prefix <> '';

end;

procedure UserDeleteData(List: TUserDataList; const DllData: String);
var
  Data: String;
  I: Integer;
  CharCount: DWord;
  InfoList: TStringList;

begin

  for I := 0 to GetArrayLength(List) - 1 do
  begin

    if List[I].Delete then
      Data := Data + List[I].Folder + ';';

  end;

  if Data = '' then
    Exit;

  Debug('Calling dll: ' + DllData);
  DeleteData(UninstallProgressForm.Handle, Data, UninstallSilent);

  CharCount := 0;
  CharCount := GetResult(Data, CharCount);
  SetLength(Data, CharCount);

  if GetResult(Data, CharCount) <> CharCount then
    Exit;

  Data := TrimRight(Data);
  StringChangeEx(Data, ';', #13, True);

  InfoList := TStringList.Create;

  try
    InfoList.Text := Data;

    for I := 0 to InfoList.Count - 1 do
      Debug(InfoList.Strings[I]);

  finally
    InfoList.Free;
  end;

  {Update uninstall form so it repaints}
  Sleep(10);
  UninstallProgressForm.Update;

end;

function UserDataSelect(Status: Integer; var List: TUserDataList): Boolean;
var
  I: Integer;
  Index: Integer;

begin

  Result := False;

  if GetArrayLength(List) = 0 then
  begin
    Debug('No user data found');
    Exit;
  end;

  {Create the form}
  UserDataCreateForm(Status, GUserForm);

  try

    {Populate the listbox}
    for I := 0 to GetArrayLength(List) - 1 do
    begin
      GUserForm.ListBox.AddCheckBox(List[I].User, List[I].Caption, 0,
        List[I].Delete, True, False, False, TObject(I));
    end;

    {Show the form}
    GUserForm.Main.ShowModal();

    {Transfer checked items to Delete field}
    for I := 0 to GUserForm.ListBox.Items.Count - 1 do
    begin

      Index := Integer(GUserForm.ListBox.ItemObject[I]);
      List[Index].Delete := GUserForm.ListBox.Checked[I];

      if GUserForm.ListBox.Checked[I] then
        Result := True;

    end;

    if Result then
      Debug('User chose to delete data')
    else
      Debug('User chose not to delete data');

  finally
    GUserForm.Main.Free();
  end;

end;

procedure UserDataCreateForm(Status: Integer; var Form: TDataForm);
var
  Left: Integer;
  Width: Integer;
  Text: TNewStaticText;
  Checkbox: TNewCheckbox;
  OkButton: TButton;

begin

  Form.Main := CreateCustomForm();
  Form.Main.Font.Size := 9;

  Form.Main.ClientWidth := ScaleX(380);
  Form.Main.ClientHeight := ScaleY(255);
  Form.Main.Caption := 'Delete User Data';
  Form.Main.FlipSizeAndCenterIfNeeded(True, UninstallProgressForm, False);

  Left := ScaleX(20);
  Width := Form.Main.ClientWidth - (Left * 2);

  Text := TNewStaticText.Create(Form.Main);
  Text.Top := ScaleY(16);
  Text.Parent := Form.Main;
  Text.Left := Left;
  Text.Width := Width;
  Text.AutoSize := True;
  Text.WordWrap := True;
  Text.Caption := 'Please select the user data you want to delete.';

  Form.ListBox := TNewCheckListBox.Create(Form.Main);
  Form.ListBox.Top := Text.Top + Text.Height + ScaleY(10);
  Form.ListBox.Parent := Form.Main;
  Form.ListBox.Left := Left;
  Form.ListBox.Width := Width;
  Form.ListBox.Height := ScaleY(148);

  Checkbox := TNewCheckbox.Create(Form.Main);
  Checkbox.Top := Form.ListBox.Top + Form.ListBox.Height + ScaleY(6);
  Checkbox.Left := Left;
  Checkbox.Parent := Form.Main;
  Checkbox.Caption := 'Select All';
  Checkbox.Checked := Status = DELETE_ALL;
  Checkbox.OnClick := @UserCheckboxClick;

  OkButton := TButton.Create(Form.Main);
  OkButton.Parent := Form.Main;
  OkButton.Width := ScaleX(75);
  OkButton.Height := ScaleY(23);
  OkButton.Left := Form.Main.ClientWidth - (ScaleX(75) + Left);
  OkButton.Top := Form.Main.ClientHeight - ScaleY(23 + 16);
  OkButton.Caption := '&OK';
  OkButton.ModalResult := mrOk;
  OKButton.Default := True;

  Form.Main.ActiveControl := OkButton;

end;

procedure UserCheckboxClick(Sender: TObject);
var
  Checkbox: TNewCheckbox;
  I: Integer;

begin

  Checkbox := Sender as TNewCheckbox;

  for I := 0 to GUserForm.ListBox.Items.Count - 1 do
    GUserForm.ListBox.Checked[I] := Checkbox.Checked;

end;

function UserGetDelete: Integer;
var
  Param: String;

begin

  Result := DELETE_NONE;
  Param := ExpandConstant('{param:delete}');

  if CompareText(Param, 'local') = 0 then
    Result := DELETE_LOCAL
  else if CompareText(Param, 'all') = 0 then
    Result := DELETE_ALL;

end;


Updated InnoSetup script for new dependencies locations.

;
;   This file is part of Poedit (http://www.poedit.net)
;
;   Copyright (C) 1999-2010 Vaclav Slavik
;
;   Permission is hereby granted, free of charge, to any person obtaining a
;   copy of this software and associated documentation files (the "Software"),
;   to deal in the Software without restriction, including without limitation
;   the rights to use, copy, modify, merge, publish, distribute, sublicense,
;   and/or sell copies of the Software, and to permit persons to whom the
;   Software is furnished to do so, subject to the following conditions:
;
;   The above copyright notice and this permission notice shall be included in
;   all copies or substantial portions of the Software.
;
;   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
;   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;   DEALINGS IN THE SOFTWARE.
;
;   $Id$
;
;   Inno Setup installer script
;

#define VERSION          "1.4.6"
#define VERSION_FULL     "1.4.6"

; FIXME: extract this from manifest file somehow?
#define CRT_VERSION      "8.0.50727.762"
#define CRT_HASH1        "1fc8b3b9a1e18e3b"
#define CRT_HASH2        "6b128700"
#define ASSEMBLY         "x86_Microsoft.VC80.CRT_" + CRT_HASH1 + "_" + CRT_VERSION + "_x-ww_" + CRT_HASH2
#define WINDIR           GetEnv("WINDIR")

#include "poedit-locale-files.iss"

[Setup]
OutputBaseFilename=poedit-{#VERSION_FULL}-setup
AppName=Poedit
AppVerName=Poedit {#VERSION_FULL}

PrivilegesRequired=none
ChangesAssociations=true
AlwaysShowComponentsList=true
SourceDir=..
DefaultDirName={pf}\Poedit
DefaultGroupName=Poedit
AllowNoIcons=true
LicenseFile=COPYING
OutputDir=.
InfoAfterFile=
Compression=lzma/ultra
WindowShowCaption=true
WindowStartMaximized=false
FlatComponentsList=true
WindowResizable=true
SolidCompression=true
ShowLanguageDialog=no
AllowUNCPath=true
InternalCompressLevel=ultra
AppID={{68EB2C37-083A-4303-B5D8-41FA67E50B8F}
VersionInfoVersion={#VERSION}
VersionInfoTextVersion={#VERSION_FULL}
AppCopyright= 1999-2010 Vaclav Slavik
AppPublisher=Vaclav Slavik
AppSupportURL=http://www.poedit.net/support.php
AppUpdatesURL=http://www.poedit.net/download.php
AppVersion={#VERSION_FULL}
AppContact=poedit-users@lists.sourceforge.net
UninstallDisplayIcon={app}\bin\poedit.exe
UninstallDisplayName=Poedit
MinVersion=0,5.0.2195
WizardSmallImageFile=icons\win32\installer_wizard_image.bmp
AppPublisherURL=http://www.poedit.net/

[LangOptions]
; make the installer use standard (WinXP, ...) fonts
DialogFontName=Tahoma
DialogFontSize=8

[Files]
Source: win32\Release\poedit.exe; DestDir: {app}\bin; DestName: poedit.exe; Components: core
Source: deps\gettext\COPYING; DestDir: {app}\doc; Components: docs; DestName: GNU_Gettext_COPYING.txt
Source: deps\bin-gettext\bin\xgettext.exe; DestDir: {app}\bin; Components: core
Source: deps\bin-gettext\bin\msgmerge.exe; DestDir: {app}\bin; Components: core
Source: deps\bin-gettext\bin\msgunfmt.exe; DestDir: {app}\bin; Components: core
Source: deps\bin-gettext\bin\msgfmt.exe; DestDir: {app}\bin; Components: core
Source: deps\bin-gettext\bin\msgcat.exe; DestDir: {app}\bin; Components: core
Source: deps\bin-gettext\bin\*.dll; DestDir: {app}\bin; Components: core
Source: deps\db\build_windows\Win32\Release\libdb*.dll; DestDir: {app}\bin; Components: core
Source: deps\winsparkle\WinSparkle.dll; DestDir: {app}\bin; Components: core
Source: README; DestDir: {app}\doc; DestName: readme.txt; Components: docs
Source: docs\chm\poedit.chm; DestDir: {app}\share\poedit\help\en; Components: docs
Source: docs\chm\gettext.chm; DestDir: {app}\share\poedit\help\en\gettext; Components: docs
Source: docs\chm\poedit-hr.chm; DestDir: {app}\share\poedit\help\hr; Components: i18n
Source: COPYING; DestDir: {app}\doc; DestName: copying.txt; Components: docs
Source: NEWS; DestDir: {app}\doc; DestName: news.txt; Components: docs
Source: icons\ui\*.png; DestDir: {app}\share\poedit\icons; Components: core
Source: icons\win32\xp\*.ico; DestDir: {app}\share\poedit\icons; Components: core; OnlyBelowVersion: 0,6.0.6000
Source: icons\win32\vista\*.ico; DestDir: {app}\share\poedit\icons; Components: core; MinVersion: 0,6.0.6000
Source: {#WINDIR}\WinSxS\Manifests\{#ASSEMBLY}.manifest; DestDir: {app}\bin; Components: core; DestName: Microsoft.VC80.CRT.manifest
Source: {#WINDIR}\WinSxS\{#ASSEMBLY}\*.dll; DestDir: {app}\bin; Components: core
#emit LocaleFiles

[InstallDelete]
; delete files from previous versions that are no longer needed (and in case of
; poedit.exe.manifest, actually harmful):
Name: {app}\bin\poedit.exe.manifest; Type: files; Components: core
Name: {app}\bin\gettextlib.dll; Type: files; Components: core
Name: {app}\bin\gettextsrc.dll; Type: files; Components: core
Name: {app}\bin\iconv.dll; Type: files; Components: core
Name: {app}\bin\intl.dll; Type: files; Components: core
Name: {app}\bin\mingwm10.dll; Type: files; Components: core

[Registry]
Root: HKCR; SubKey: .po; ValueType: string; ValueData: GettextFile; Flags: uninsdeletekey noerror
Root: HKCR; SubKey: GettextFile; ValueType: string; ValueData: Gettext message catalog; Flags: uninsdeletekey noerror
Root: HKCR; SubKey: GettextFile\Shell\Open\Command; ValueType: string; ValueData: """{app}\bin\poedit.exe"" ""%1"""; Flags: uninsdeletevalue noerror
Root: HKCR; Subkey: GettextFile\DefaultIcon; ValueType: string; ValueData: {app}\share\poedit\icons\poedit-translation-generic.ico; Flags: uninsdeletekey noerror
Root: HKCU; Subkey: Software\Vaclav Slavik; Flags: uninsdeletekeyifempty dontcreatekey
Root: HKCU; Subkey: Software\Vaclav Slavik\poedit; Flags: uninsdeletekey dontcreatekey

[Icons]
Name: {group}\Poedit; Filename: {app}\bin\poedit.exe; WorkingDir: {app}; IconIndex: 0
Name: {group}\Readme; Filename: {app}\doc\readme.txt; IconIndex: 0

[Run]
Filename: {app}\doc\readme.txt; Description: View readme.txt; Flags: shellexec postinstall unchecked; Components: docs
Filename: {app}\bin\poedit.exe; WorkingDir: {app}; Description: Run Poedit now; Flags: postinstall unchecked nowait

[_ISTool]
UseAbsolutePaths=false

[Dirs]
Name: {app}\bin; Components: core
Name: {app}\doc; Components: docs
Name: {app}\share; Components: core
Name: {app}\share\locale; Components: i18n
Name: {app}\share\poedit; Components: core
Name: {app}\share\poedit\icons; Components: core
Name: {app}\share\poedit\help; Components: docs
Name: {app}\share\poedit\help\en; Components: docs
Name: {app}\share\poedit\help\en\gettext; Components: docs
Name: {app}\share\poedit\help\hr; Components: docs

[Components]
Name: core; Description: Core files; Flags: fixed; Types: custom compact full
Name: docs; Description: Documentation; Types: custom compact full
Name: i18n; Description: Localization files for the UI; Types: full

[Messages]
BeveledLabel=http://www.poedit.net

;
;   This file is part of Poedit (http://www.poedit.net)
;
;   Copyright (C) 1999-2008 Vaclav Slavik
;
;   Permission is hereby granted, free of charge, to any person obtaining a
;   copy of this software and associated documentation files (the "Software"),
;   to deal in the Software without restriction, including without limitation
;   the rights to use, copy, modify, merge, publish, distribute, sublicense,
;   and/or sell copies of the Software, and to permit persons to whom the
;   Software is furnished to do so, subject to the following conditions:
;
;   The above copyright notice and this permission notice shall be included in
;   all copies or substantial portions of the Software.
;
;   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
;   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
;   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;   DEALINGS IN THE SOFTWARE.
;
;   $Id$
;
;   Inno Setup installer script
;

#define VERSION          "1.4.6"
#define VERSION_FULL     "1.4.6"

; FIXME: extract this from manifest file somehow?
#define CRT_VERSION      "8.0.50727.762"
#define CRT_HASH1        "1fc8b3b9a1e18e3b"
#define CRT_HASH2        "6b128700"
#define ASSEMBLY         "x86_Microsoft.VC80.CRT_" + CRT_HASH1 + "_" + CRT_VERSION + "_x-ww_" + CRT_HASH2
#define WINDIR           GetEnv("WINDIR")

#include "poedit-locale-files.iss"

[Setup]
OutputBaseFilename=poedit-{#VERSION_FULL}-setup
AppName=Poedit
AppVerName=Poedit {#VERSION_FULL}

PrivilegesRequired=none
ChangesAssociations=true
AlwaysShowComponentsList=true
SourceDir=..
DefaultDirName={pf}\Poedit
DefaultGroupName=Poedit
AllowNoIcons=true
LicenseFile=COPYING
OutputDir=.
InfoAfterFile=
Compression=lzma/ultra
WindowShowCaption=true
WindowStartMaximized=false
FlatComponentsList=true
WindowResizable=true
SolidCompression=true
ShowLanguageDialog=no
AllowUNCPath=true
InternalCompressLevel=ultra
AppID={{68EB2C37-083A-4303-B5D8-41FA67E50B8F}
VersionInfoVersion={#VERSION}
VersionInfoTextVersion={#VERSION_FULL}
AppCopyright= 1999-2010 Vaclav Slavik
AppPublisher=Vaclav Slavik
AppSupportURL=http://www.poedit.net/support.php
AppUpdatesURL=http://www.poedit.net/download.php
AppVersion={#VERSION_FULL}
AppContact=poedit-users@lists.sourceforge.net
UninstallDisplayIcon={app}\bin\poedit.exe
UninstallDisplayName=Poedit
MinVersion=0,4.0.1381
WizardSmallImageFile=icons\win32\installer_wizard_image.bmp

[LangOptions]
; make the installer use standard (WinXP, ...) fonts
DialogFontName=Tahoma
DialogFontSize=8

[Files]
Source: win32\poedit.exe; DestDir: {app}\bin; DestName: poedit.exe; Components: core
Source: deps\gettext\COPYING; DestDir: {app}\doc; Components: docs; DestName: GNU_Gettext_COPYING.txt
Source: deps\gettext\xgettext.exe; DestDir: {app}\bin; Components: core
Source: deps\gettext\msgmerge.exe; DestDir: {app}\bin; Components: core
Source: deps\gettext\msgunfmt.exe; DestDir: {app}\bin; Components: core
Source: deps\gettext\msgfmt.exe; DestDir: {app}\bin; Components: core
Source: deps\gettext\msgcat.exe; DestDir: {app}\bin; Components: core
Source: deps\gettext\libintl-*.dll; DestDir: {app}\bin; Components: core
Source: deps\gettext\libgettextlib-*.dll; DestDir: {app}\bin; Components: core
Source: deps\gettext\libgettextsrc-*.dll; DestDir: {app}\bin; Components: core
Source: deps\gettext\libcharset-*.dll; DestDir: {app}\bin; Components: core
Source: deps\gettext\libiconv-*.dll; DestDir: {app}\bin; Components: core
Source: deps\gettext\mingwm10.dll; DestDir: {app}\bin; Components: core
Source: deps\gettext\pthreadGC2.dll; DestDir: {app}\bin; Components: core
Source: deps\winsparkle\WinSparkle.dll; DestDir: {app}\bin; Components: core
Source: README; DestDir: {app}\doc; DestName: readme.txt; Components: docs
Source: docs\chm\poedit.chm; DestDir: {app}\share\poedit\help\en; Components: docs
Source: docs\chm\gettext.chm; DestDir: {app}\share\poedit\help\en\gettext; Components: docs
Source: docs\chm\poedit-hr.chm; DestDir: {app}\share\poedit\help\hr; Components: i18n
Source: COPYING; DestDir: {app}\doc; DestName: copying.txt; Components: docs
Source: NEWS; DestDir: {app}\doc; DestName: news.txt; Components: docs
Source: icons\ui\*.png; DestDir: {app}\share\poedit\icons; Components: core
Source: icons\win32\xp\*.ico; DestDir: {app}\share\poedit\icons; Components: core; OnlyBelowVersion: 0,6.0.6000
Source: icons\win32\vista\*.ico; DestDir: {app}\share\poedit\icons; Components: core; MinVersion: 0,6.0.6000
Source: {#WINDIR}\WinSxS\Manifests\{#ASSEMBLY}.manifest; DestDir: {app}\bin; Components: core; DestName: Microsoft.VC80.CRT.manifest
Source: {#WINDIR}\WinSxS\{#ASSEMBLY}\*.dll; DestDir: {app}\bin; Components: core
#emit LocaleFiles

[InstallDelete]
; delete files from previous versions that are no longer needed (and in case of
; poedit.exe.manifest, actually harmful):
Name: {app}\bin\poedit.exe.manifest; Type: files; Components: core
Name: {app}\bin\gettextlib.dll; Type: files; Components: core
Name: {app}\bin\gettextsrc.dll; Type: files; Components: core
Name: {app}\bin\iconv.dll; Type: files; Components: core
Name: {app}\bin\intl.dll; Type: files; Components: core
Name: {app}\bin\mingwm10.dll; Type: files; Components: core

[Registry]
Root: HKCR; SubKey: .po; ValueType: string; ValueData: GettextFile; Flags: uninsdeletekey noerror
Root: HKCR; SubKey: GettextFile; ValueType: string; ValueData: Gettext message catalog; Flags: uninsdeletekey noerror
Root: HKCR; SubKey: GettextFile\Shell\Open\Command; ValueType: string; ValueData: """{app}\bin\poedit.exe"" ""%1"""; Flags: uninsdeletevalue noerror
Root: HKCR; Subkey: GettextFile\DefaultIcon; ValueType: string; ValueData: {app}\share\poedit\icons\poedit-translation-generic.ico; Flags: uninsdeletekey noerror
Root: HKCU; Subkey: Software\Vaclav Slavik; Flags: uninsdeletekeyifempty dontcreatekey
Root: HKCU; Subkey: Software\Vaclav Slavik\poedit; Flags: uninsdeletekey dontcreatekey

[Icons]
Name: {group}\Poedit; Filename: {app}\bin\poedit.exe; WorkingDir: {app}; IconIndex: 0
Name: {group}\Readme; Filename: {app}\doc\readme.txt; IconIndex: 0

[Run]
Filename: {app}\doc\readme.txt; Description: View readme.txt; Flags: shellexec postinstall unchecked; Components: docs
Filename: {app}\bin\poedit.exe; WorkingDir: {app}; Description: Run Poedit now; Flags: postinstall unchecked nowait

[_ISTool]
UseAbsolutePaths=false

[Dirs]
Name: {app}\bin; Components: core
Name: {app}\doc; Components: docs
Name: {app}\share; Components: core
Name: {app}\share\locale; Components: i18n
Name: {app}\share\poedit; Components: core
Name: {app}\share\poedit\icons; Components: core
Name: {app}\share\poedit\help; Components: docs
Name: {app}\share\poedit\help\en; Components: docs
Name: {app}\share\poedit\help\en\gettext; Components: docs
Name: {app}\share\poedit\help\hr; Components: docs

[Components]
Name: core; Description: Core files; Flags: fixed; Types: custom compact full
Name: docs; Description: Documentation; Types: custom compact full
Name: i18n; Description: Localization files for the UI; Types: full

[Messages]
BeveledLabel=http://www.poedit.net


Version number needs to be bumped here as well.

; Basic setup script for the Inno Setep installer builder.  For more
; information on the free installer builder, see www.jrsoftware.org.
;
; This script was contributed by Tim Peters.
; The current version is used with Inno Setup 2.0.19.

[Setup]
AppName=expat
AppId=expat
AppVersion=1.95.4
AppVerName=expat 1.95.4
AppCopyright=Copyright  1998-2002 Thai Open Source Software Center, Clark Cooper, and the Expat maintainers
DefaultDirName={sd}\Expat-1.95.4
AppPublisher=The Expat Developers
AppPublisherURL=http://www.libexpat.org/
AppSupportURL=http://www.libexpat.org/
AppUpdatesURL=http://www.libexpat.org/
UninstallDisplayName=Expat XML Parser (version 1.95.4)
UninstallFilesDir={app}\Uninstall

Compression=bzip/9
SourceDir=..
OutputDir=win32
DisableStartupPrompt=yes
AllowNoIcons=yes
DisableProgramGroupPage=yes
DisableReadyPage=yes

[Files]
CopyMode: alwaysoverwrite; Source: xmlwf\Release\*.exe; DestDir: "{app}"
CopyMode: alwaysoverwrite; Source: win32\MANIFEST.txt;  DestDir: "{app}"
CopyMode: alwaysoverwrite; Source: Changes;             DestDir: "{app}"; DestName: Changes.txt
CopyMode: alwaysoverwrite; Source: COPYING;             DestDir: "{app}"; DestName: COPYING.txt
CopyMode: alwaysoverwrite; Source: README;              DestDir: "{app}"; DestName: README.txt
CopyMode: alwaysoverwrite; Source: doc\*.html;          DestDir: "{app}\Doc"
CopyMode: alwaysoverwrite; Source: doc\*.css;           DestDir: "{app}\Doc"
CopyMode: alwaysoverwrite; Source: lib\Release\*.dll;   DestDir: "{app}\Libs"
CopyMode: alwaysoverwrite; Source: lib\Release\*.lib;   DestDir: "{app}\Libs"
CopyMode: alwaysoverwrite; Source: lib\Release-w\*.dll; DestDir: "{app}\Libs"
CopyMode: alwaysoverwrite; Source: lib\Release-w\*.lib; DestDir: "{app}\Libs"
CopyMode: alwaysoverwrite; Source: expat.dsw;           DestDir: "{app}\Source"
CopyMode: alwaysoverwrite; Source: lib\*.c;             DestDir: "{app}\Source\lib"
CopyMode: alwaysoverwrite; Source: lib\*.h;             DestDir: "{app}\Source\lib"
CopyMode: alwaysoverwrite; Source: lib\*.dsp;           DestDir: "{app}\Source\lib"
CopyMode: alwaysoverwrite; Source: examples\*.c;        DestDir: "{app}\Source\examples"
CopyMode: alwaysoverwrite; Source: examples\*.dsp;      DestDir: "{app}\Source\examples"
CopyMode: alwaysoverwrite; Source: tests\*.c;           DestDir: "{app}\Source\tests"
CopyMode: alwaysoverwrite; Source: tests\*.h;           DestDir: "{app}\Source\tests"
CopyMode: alwaysoverwrite; Source: tests\README.txt;    DestDir: "{app}\Source\tests"
CopyMode: alwaysoverwrite; Source: xmlwf\*.c*;          DestDir: "{app}\Source\xmlwf"
CopyMode: alwaysoverwrite; Source: xmlwf\*.h;           DestDir: "{app}\Source\xmlwf"
CopyMode: alwaysoverwrite; Source: xmlwf\*.dsp;         DestDir: "{app}\Source\xmlwf"

[Messages]
WelcomeLabel1=Welcome to the Expat XML Parser Setup Wizard
WelcomeLabel2=This will install [name/ver] on your computer.%n%nExpat is an XML parser with a C-language API, and is primarily made available to allow developers to build applications which use XML using a portable API and fast implementation.%n%nIt is strongly recommended that you close all other applications you have running before continuing. This will help prevent any conflicts during the installation process.

; Basic setup script for the Inno Setep installer builder.  For more
; information on the free installer builder, see www.jrsoftware.org.
;
; This script was contributed by Tim Peters.
; The current version is used with Inno Setup 2.0.19.

[Setup]
AppName=expat
AppId=expat
AppVersion=1.95.3
AppVerName=expat 1.95.3
AppCopyright=Copyright  1998-2002 Thai Open Source Software Center, Clark Cooper, and the Expat maintainers
DefaultDirName={sd}\Expat-1.95.3
AppPublisher=The Expat Developers
AppPublisherURL=http://www.libexpat.org/
AppSupportURL=http://www.libexpat.org/
AppUpdatesURL=http://www.libexpat.org/
UninstallDisplayName=Expat XML Parser (version 1.95.3)
UninstallFilesDir={app}\Uninstall

Compression=bzip/9
SourceDir=..
OutputDir=win32
DisableStartupPrompt=yes
AllowNoIcons=yes
DisableProgramGroupPage=yes
DisableReadyPage=yes

[Files]
CopyMode: alwaysoverwrite; Source: xmlwf\Release\*.exe; DestDir: "{app}"
CopyMode: alwaysoverwrite; Source: win32\MANIFEST.txt;  DestDir: "{app}"
CopyMode: alwaysoverwrite; Source: Changes;             DestDir: "{app}"; DestName: Changes.txt
CopyMode: alwaysoverwrite; Source: COPYING;             DestDir: "{app}"; DestName: COPYING.txt
CopyMode: alwaysoverwrite; Source: README;              DestDir: "{app}"; DestName: README.txt
CopyMode: alwaysoverwrite; Source: doc\*.html;          DestDir: "{app}\Doc"
CopyMode: alwaysoverwrite; Source: doc\*.css;           DestDir: "{app}\Doc"
CopyMode: alwaysoverwrite; Source: lib\Release\*.dll;   DestDir: "{app}\Libs"
CopyMode: alwaysoverwrite; Source: lib\Release\*.lib;   DestDir: "{app}\Libs"
CopyMode: alwaysoverwrite; Source: lib\Release-w\*.dll; DestDir: "{app}\Libs"
CopyMode: alwaysoverwrite; Source: lib\Release-w\*.lib; DestDir: "{app}\Libs"
CopyMode: alwaysoverwrite; Source: expat.dsw;           DestDir: "{app}\Source"
CopyMode: alwaysoverwrite; Source: lib\*.c;             DestDir: "{app}\Source\lib"
CopyMode: alwaysoverwrite; Source: lib\*.h;             DestDir: "{app}\Source\lib"
CopyMode: alwaysoverwrite; Source: lib\*.dsp;           DestDir: "{app}\Source\lib"
CopyMode: alwaysoverwrite; Source: examples\*.c;        DestDir: "{app}\Source\examples"
CopyMode: alwaysoverwrite; Source: examples\*.dsp;      DestDir: "{app}\Source\examples"
CopyMode: alwaysoverwrite; Source: tests\*.c;           DestDir: "{app}\Source\tests"
CopyMode: alwaysoverwrite; Source: tests\*.h;           DestDir: "{app}\Source\tests"
CopyMode: alwaysoverwrite; Source: tests\README.txt;    DestDir: "{app}\Source\tests"
CopyMode: alwaysoverwrite; Source: xmlwf\*.c*;          DestDir: "{app}\Source\xmlwf"
CopyMode: alwaysoverwrite; Source: xmlwf\*.h;           DestDir: "{app}\Source\xmlwf"
CopyMode: alwaysoverwrite; Source: xmlwf\*.dsp;         DestDir: "{app}\Source\xmlwf"

[Messages]
WelcomeLabel1=Welcome to the Expat XML Parser Setup Wizard
WelcomeLabel2=This will install [name/ver] on your computer.%n%nExpat is an XML parser with a C-language API, and is primarily made available to allow developers to build applications which use XML using a portable API and fast implementation.%n%nIt is strongly recommended that you close all other applications you have running before continuing. This will help prevent any conflicts during the installation process.