permissionsinno-setupdesktopshortcut-filewindows-shortcut

Create individual shortcuts on all desktops of all users in Inno Setup


I'm creating a shortcut on users desktop with Inno Setup:

Name: "{commondesktop}\Setup"; Filename: "{app}\Setup.exe"; WorkingDir: "{pf}\Program"; IconFilename: "{app}\Setup.ico"

But users, with no admin rights, cannot delete this Shortcut, how to grant permissions to regular users, to delete this icon? Icon should be created on every user's desktop, but user should have permission to delete it.


Solution

  • The {commondesktop} shortcut is shared on a common desktop. So there's only one copy of the shortcut.

    If you allow the users to delete, when one user deletes the icon, it's deleted for every other user. That's why regular users are not allowed to modify/delete shared shortcuts.

    While you can grant a delete permission to all users to that shortcut, this is not what you should do.


    If each machine is used by one user only, install the icon to userdesktop, not commondestop. But that works only if that user (not Administrator) actually runs the installer. For a general discussion about this problem, see Installing application for currently logged in user from Inno Setup installer running as Administrator.

    There's no easy way to install the icons to all desktops. You have to use Pascal Scripting and iterate all profiles.

    Easy way is to iterate subfolders of C:\Users, creating a shortcut in Desktop subfolder of each user's subfolder:

    procedure CurStepChanged(CurStep: TSetupStep);
    var
      UsersPath: string;
      CommonDesktopShortPath: string;
      DesktopPath: string;
      ShortcutPath: string;
      FindRec: TFindRec;
      ShortcutsCount: Integer;
    begin
      // Once the files are installed
      if CurStep = ssPostInstall then
      begin
        Log('Creating shortcuts');
        // Assuming the common users root (typically C:\Users) is two level up
        // from the current user desktop folder
        UsersPath :=
          AddBackslash(ExtractFilePath(RemoveBackslash(ExtractFilePath(
            RemoveBackslash(ExpandConstant('{userdesktop}'))))));
        Log(Format('Users root [%s]', [UsersPath]));
        CommonDesktopShortPath := GetShortName(ExpandConstant('{commondesktop}'));
        Log(Format('Common desktop [%s]', [CommonDesktopShortPath]));
    
        ShortcutsCount := 0;
    
        // Iterate all users
        if FindFirst(UsersPath + '*', FindRec) then
        begin
          try
            repeat
              // Just directories, not interested in files
              if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0 then
              begin
                // Check if there is a Desktop subfolder
                DesktopPath := UsersPath + FindRec.Name + '\Desktop';
                if DirExists(DesktopPath) then
                begin
                  if CompareText(
                       CommonDesktopShortPath, GetShortName(DesktopPath)) = 0 then
                  begin
                    Log(Format('Skipping common desktop [%s]', [DesktopPath]));
                  end
                    else
                  begin
                    ShortcutPath := DesktopPath + '\My Program.lnk';
                    Log(Format(
                      'Found desktop folder for user [%s], creating shortcut [%s]', [
                      FindRec.Name, ShortcutPath]));
                    try
                      ShortcutPath := CreateShellLink(
                        ShortcutPath, 'My Program',
                        ExpandConstant('{app}\MyProg.exe'), '',
                        ExpandConstant('{app}'), '', 0, SW_SHOWNORMAL);
                      Log(Format('Shortcut [%s] created', [ShortcutPath]));
                      Inc(ShortcutsCount);
                    except
                      Log(Format('Failed to create shortcut: %s', [
                        GetExceptionMessage]));
                    end;
                  end;
                end;
              end;
            until not FindNext(FindRec);
          finally
            FindClose(FindRec);
          end;
    
          Log(Format('%d shortcuts created', [ShortcutsCount]));
        end
          else
        begin
          Log(Format('Error listing [%s]', [UsersPath]));
        end;
      end;
    end;
    

    The code will work only, if the desktops are local and in common locations.

    If you need a more robust solution, you can iterate profiles listed in

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList
    

    Or use a WMI query like:

    SELECT * FROM Win32_UserAccount WHERE localAccount = true and disabled = false
    

    See Query list of Windows accounts in Inno Setup.