Is it possible to 'Pin to start menu' using Inno Setup?

前端 未结 3 1855
轮回少年
轮回少年 2020-12-06 07:04

I\'m using the excellent Inno Setup installer and I notice that some Applications (often from Microsoft) get installed with their launch icon already highly visible (\'pinne

相关标签:
3条回答
  • 2020-12-06 07:19

    There's a reason there's no programmatic way to pin things to the taskbar/start menu. In my experience, I have seen the start menu highlight newly-created shortcuts, and that's designed to handle exactly this situation. When you see a newly-installed program show up on the start menu, it's probably because of that algorithm and not because the installer placed it there.

    That said, if a new shortcut does not appear highlighted, it may be because the installer extracts a pre-existing shortcut and preserves an old timestamp on it, rather than using the API function to create a shortcut in the start menu.

    0 讨论(0)
  • 2020-12-06 07:20

    It is possible to pin programs, but not officially. Based on a code posted in this thread (which uses the same way as described in the article linked by @Mark Redman) I wrote the following:

    [Code]
    #ifdef UNICODE
      #define AW "W"
    #else
      #define AW "A"
    #endif
    
    const
      // these constants are not defined in Windows
      SHELL32_STRING_ID_PIN_TO_TASKBAR = 5386;
      SHELL32_STRING_ID_PIN_TO_STARTMENU = 5381;
      SHELL32_STRING_ID_UNPIN_FROM_TASKBAR = 5387;
      SHELL32_STRING_ID_UNPIN_FROM_STARTMENU = 5382;
    
    type
      HINSTANCE = THandle;
      HMODULE = HINSTANCE;
    
      TPinDest = (
        pdTaskbar,
        pdStartMenu
      );
    
    function LoadLibrary(lpFileName: string): HMODULE;
      external 'LoadLibrary{#AW}@kernel32.dll stdcall';
    function FreeLibrary(hModule: HMODULE): BOOL;
      external 'FreeLibrary@kernel32.dll stdcall';
    function LoadString(hInstance: HINSTANCE; uID: UINT;
      lpBuffer: string; nBufferMax: Integer): Integer;
      external 'LoadString{#AW}@user32.dll stdcall';
    
    function TryGetVerbName(ID: UINT; out VerbName: string): Boolean;
    var
      Buffer: string;
      BufLen: Integer;
      Handle: HMODULE;
    begin
      Result := False;
    
      Handle := LoadLibrary(ExpandConstant('{sys}\Shell32.dll'));
      if Handle <> 0 then
      try
        SetLength(Buffer, 255);
        BufLen := LoadString(Handle, ID, Buffer, Length(Buffer));
    
        if BufLen <> 0 then
        begin
          Result := True;
          VerbName := Copy(Buffer, 1, BufLen);
        end;
      finally
        FreeLibrary(Handle);
      end;
    end;
    
    function ExecVerb(const FileName, VerbName: string): Boolean;
    var
      I: Integer;
      Shell: Variant;
      Folder: Variant;
      FolderItem: Variant;
    begin
      Result := False;
    
      Shell := CreateOleObject('Shell.Application');
      Folder := Shell.NameSpace(ExtractFilePath(FileName));
      FolderItem := Folder.ParseName(ExtractFileName(FileName));
    
      for I := 1 to FolderItem.Verbs.Count do
      begin
        if FolderItem.Verbs.Item(I).Name = VerbName then
        begin
          FolderItem.Verbs.Item(I).DoIt;
          Result := True;
          Exit;
        end;
      end;  
    end;
    
    function PinAppTo(const FileName: string; PinDest: TPinDest): Boolean;
    var
      ResStrID: UINT;
      VerbName: string;
    begin
      case PinDest of
        pdTaskbar: ResStrID := SHELL32_STRING_ID_PIN_TO_TASKBAR;
        pdStartMenu: ResStrID := SHELL32_STRING_ID_PIN_TO_STARTMENU;
      end;
      Result := TryGetVerbName(ResStrID, VerbName) and ExecVerb(FileName, VerbName);
    end;
    
    function UnpinAppFrom(const FileName: string; PinDest: TPinDest): Boolean;
    var
      ResStrID: UINT;
      VerbName: string;
    begin
      case PinDest of
        pdTaskbar: ResStrID := SHELL32_STRING_ID_UNPIN_FROM_TASKBAR;
        pdStartMenu: ResStrID := SHELL32_STRING_ID_UNPIN_FROM_STARTMENU;
      end;
      Result := TryGetVerbName(ResStrID, VerbName) and ExecVerb(FileName, VerbName);
    end;
    

    The above code first reads the caption of the menu item for pinning or unpinning applications from the string table of the Shell32.dll library. Then connects to the Windows Shell, and for the target app. path creates the Folder object, then obtains the FolderItem object and on this object iterates all the available verbs and checks if their name matches to the one read from the Shell32.dll library string table. If so, it invokes the verb item action by calling the DoIt method and exits the iteration.

    Here is a possible usage of the above code, for pinning:

    if PinAppTo(ExpandConstant('{sys}\calc.exe'), pdTaskbar) then
      MsgBox('Calc has been pinned to the taskbar.', mbInformation, MB_OK);
    if PinAppTo(ExpandConstant('{sys}\calc.exe'), pdStartMenu) then
      MsgBox('Calc has been pinned to the start menu.', mbInformation, MB_OK);
    

    And for unpinning:

    if UnpinAppFrom(ExpandConstant('{sys}\calc.exe'), pdTaskbar) then
      MsgBox('Calc is not pinned to the taskbar anymore.', mbInformation, MB_OK);
    if UnpinAppFrom(ExpandConstant('{sys}\calc.exe'), pdStartMenu) then
      MsgBox('Calc is not pinned to the start menu anymore.', mbInformation, MB_OK);
    

    Please note that even though this code works on Windows 7 (and taskbar pinning also on Windows 8.1 where I've tested it), it is really hacky way, since there is no official way to programatically pin programs to taskbar, nor start menu. That's what the users should do by their own choice.

    0 讨论(0)
  • 2020-12-06 07:34

    Have a look at: http://blogs.technet.com/deploymentguys/archive/2009/04/08/pin-items-to-the-start-menu-or-windows-7-taskbar-via-script.aspx

    0 讨论(0)
提交回复
热议问题