Pin to taskbar example needed that's compatible with Win10

502 views
Skip to first unread message

christianx...@intel.com

unread,
Jan 14, 2020, 4:40:04 PM1/14/20
to innosetup
Hi Guys,

I think the biggest missing feature in Inno Setup right now is the ability to pin [Icons] to the Taskbar.  Does anyone have a good Windows 10 compatible example until this functionality is added natively?  

Thanks,
Christian Blackburn, A+, Network+
Technician w/ Kelly OCG

Jernej Simončič

unread,
Jan 14, 2020, 6:29:12 PM1/14/20
to christianx.blackburn@intel.com on [innosetup]
On Tuesday, January 14, 2020, 22:40:04, christianx...@intel.com wrote:

> I think the biggest missing feature in Inno Setup right now is the ability
> to pin [Icons] to the Taskbar. Does anyone have a good Windows 10
> compatible example until this functionality is added natively?

There isn't any, because there is no support for programatic pinning -
taskbar (and Start Menu tiles) are user's area, and Microsoft
intentionally hasn't documented any other way to do pinning than for
the user to right-click something and select "Pin to taskbar".

--
< Jernej Simončič ><><><><>< https://eternallybored.org/ >

A verbal contract isn't worth the paper it's written on.
-- Goldwyn's Law of Contracts

Blackburn, ChristianX

unread,
Jan 14, 2020, 6:51:51 PM1/14/20
to inno...@googlegroups.com
Hi Jernej,

I know this is the very kind of thing Microsoft would make difficult, but Google Chrome and Mozilla Firefox have solved this. Even if it is with keyboard/mouse automation I think Inno Setup should follow suit. Chrome is debatably open source, but there's no question that Firefox is, so there's a time honored recipe sitting in their source repo somewhere. I recall reading something about an XML way for SysAdmins to accomplish this in Win 10 1607+ (or thereabouts). So Local Policy is another option.

https://docs.microsoft.com/en-us/windows/configuration/configure-windows-10-taskbar

Thanks,
Christian Blackburn, A+, Network+
Technician with Kelly OCG
916-978-1349
--
You received this message because you are subscribed to a topic in the Google Groups "innosetup" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/innosetup/oskWRaFzV1I/unsubscribe.
To unsubscribe from this group and all its topics, send an email to innosetup+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/innosetup/1748414178.20200115002909%40eternallybored.org.

El Sanchez

unread,
Feb 13, 2020, 2:15:12 AM2/13/20
to innosetup
среда, 15 января 2020 г., 0:40:04 UTC+3 пользователь christian...@intel.com написал:
I think the biggest missing feature in Inno Setup right now is the ability to pin [Icons] to the Taskbar.  Does anyone have a good Windows 10 compatible example until this functionality is added natively?

Try this:
const
  CLSID_TaskbandPin = '{90AA3A4E-1CBA-4233-B8BB-535773D48449}';
  IID_IPinnedList2 = '{BBD20037-BC0E-42F1-913F-E2936BB0EA0C}';
  IID_IPinnedList3 = '{0DD79AE2-D156-45D4-9EEB-3B549769E940}';
  CLSCTX_INPROC_SERVER = 1;
  PLMC_EXPLORER = 4;
  S_OK = 0;

type
  PItemIDList = LongWord;

  IPinnedList2 = interface(IUnknown)
    '{BBD20037-BC0E-42F1-913F-E2936BB0EA0C}'
    procedure EnumObjects; // dummy
    function Modify(unpin, pin: PItemIDList): HRESULT;
    procedure GetChangeCount; // dummy
    procedure GetPinnableInfo; // dummy
    procedure IsPinnable; // dummy
    procedure Resolve; // dummy
    function IsPinned(pidl: PItemIDList): HRESULT;
    procedure GetPinnedItem; // dummy
    procedure GetPinnedItemForAppID; // dummy
    procedure ItemChangeNotify; // dummy
    procedure UpdateForRemovedItemsAsNecessary; // dummy
  end;

  IPinnedList3 = interface(IUnknown)
    '{0DD79AE2-D156-45D4-9EEB-3B549769E940}'
    procedure EnumObjects; // dummy
    procedure GetPinnableInfo; // dummy
    procedure IsPinnable; // dummy
    procedure Resolve; // dummy
    procedure LegacyModify; // dummy
    procedure GetChangeCount; // dummy
    function IsPinned(pidl: PItemIDList): HRESULT;
    procedure GetPinnedItem; // dummy
    procedure GetAppIDForPinnedItem; // dummy
    procedure ItemChangeNotify; // dummy
    procedure UpdateForRemovedItemsAsNecessary; // dummy
    procedure PinShellLink; // dummy
    procedure GetPinnedItemForAppID; // dummy
    function Modify(unpin, pin: PItemIDList; ModifyCaller: LongWord): HRESULT;
  end;

function CoCreateInstance(rclsid: TCLSID; pUnkOuter: LongWord;
  dwClsContext: DWORD; riid: TIID; out ppv: IUnknown): HRESULT; external 'CoCreate...@ole32.dll stdcall';
function ILCreateFromPath(const pszPath: string): PItemIDList; external 'ILCreate...@shell32.dll stdcall';
procedure ILFree(pidl: PItemIDList); external 'ILF...@shell32.dll stdcall';

function PinToTaskbar(const AFilename: string; AIsPin: Boolean): Boolean;
// AFilename : full path to executable file
// AIsPin....: False - unpin from TaskBar, True - pin to TaskBar
var
  LPIDL: PItemIDList;
  LUnk: IUnknown;
  LPinnedList2: IPinnedList2;
  LPinnedList3: IPinnedList3;
  LShellApp: Variant;
  LVerb: string;
begin
  Result := False;
  if FileExists(AFilename) and
    (GetWindowsVersion > $06010000) then
  try
    LPIDL := ILCreateFromPath(AFilename);
    try
      { Windows 10 (build 1809) and above. }
      OleCheck(CoCreateInstance(StringToGUID(CLSID_TaskbandPin), 0,
        CLSCTX_INPROC_SERVER, StringToGUID(IID_IPinnedList3), LUnk));
      LPinnedList3 := LUnk as IPinnedList3;
    except
      try
        { Windows 7, 8, 8.1 if IPinnedList2 supported. }
        OleCheck(CoCreateInstance(StringToGUID(CLSID_TaskbandPin), 0,
          CLSCTX_INPROC_SERVER, StringToGUID(IID_IPinnedList2), LUnk));
        LPinnedList2 := LUnk as IPinnedList2;
      except
        { Windows 10 (build 1809) and below. }
        LShellApp := CreateOleObject('Shell.Application');
      end;
    end;
    if AIsPin then  // pin
    begin
      if LPinnedList3 <> nil then
      begin
        Result := LPinnedList3.IsPinned(LPIDL) <> S_OK;
        if Result then
          OleCheck(LPinnedList3.Modify(0, LPIDL, PLMC_EXPLORER));
      end
      else if LPinnedList2 <> nil then
      begin
        Result := LPinnedList2.IsPinned(LPIDL) <> S_OK;
        if Result then
          OleCheck(LPinnedList2.Modify(0, LPIDL));
      end else
        LVerb := 'taskbarpin';
    end else        // unpin
    begin
      if LPinnedList3 <> nil then
      begin
        Result := LPinnedList3.IsPinned(LPIDL) = S_OK;
        if Result then
          OleCheck(LPinnedList3.Modify(LPIDL, 0, PLMC_EXPLORER));
      end
      else if LPinnedList2 <> nil then
      begin
        Result := LPinnedList2.IsPinned(LPIDL) = S_OK;
        if Result then
          OleCheck(LPinnedList2.Modify(LPIDL, 0));
      end else
        LVerb := 'taskbarunpin';
    end;
    if LVerb <> '' then
      LShellApp.Windows.Item.Document.Application
        .NameSpace(ExtractFileDir(AFilename))
        .ParseName(ExtractFileName(AFilename)).InvokeVerb(LVerb);
  except
    Result := False;
    ShowExceptionMessage;
  finally
    ILFree(LPIDL);
  end;
end;

Blackburn, ChristianX

unread,
Feb 13, 2020, 2:17:33 PM2/13/20
to inno...@googlegroups.com

Hi El Sanchez,

 

Thank you very much I’ll give your example a try.  I super love how there are three different ways to do it based on what version of Windows you’re running.  Way to maintain a consistent platform Microsoft 😉

 

Thanks,

Christian Blackburn, A+, Network+

Technician with Kelly OCG

916-978-1349

 

From: inno...@googlegroups.com <inno...@googlegroups.com> On Behalf Of El Sanchez
Sent: Wednesday, February 12, 2020 11:15 PM
To: innosetup <inno...@googlegroups.com>
Subject: Re: Pin to taskbar example needed that's compatible with Win10

 

среда, 15 января 2020 г., 0:40:04 UTC+3 пользователь christian...@intel.com написал:

--

You received this message because you are subscribed to a topic in the Google Groups "innosetup" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/innosetup/oskWRaFzV1I/unsubscribe.
To unsubscribe from this group and all its topics, send an email to innosetup+...@googlegroups.com.

Jernej Simončič

unread,
Feb 13, 2020, 4:00:03 PM2/13/20
to Blackburn, ChristianX on [innosetup]
On Thursday, February 13, 2020, 20:17:10, Blackburn, ChristianX wrote:

> Thank you very much I’ll give your example a try. I super love how
> there are three different ways to do it based on what version of
> Windows you’re running. Way to maintain a consistent platform Microsoft 😉.

That's because automatically pinning programs is user-hostile, and
Microsoft will hopefully change this several more times to prevent
self-important developers from crapping on the taskbar.

--
< Jernej Simončič ><><><><>< https://eternallybored.org/ >

Justice always prevails... three times out of seven.
-- Alley's Axiom

Luís César Zanetti

unread,
Feb 15, 2020, 11:04:45 PM2/15/20
to innosetup
Thank you very much for the code.
It was very useful for me too.

I would like to know if you don't have a similar code that allows you to fix it in the Start menu (Windows 10) using this same interface method?

Thanks!

El Sanchez

unread,
Feb 20, 2020, 9:38:20 AM2/20/20
to innosetup
I would like to know if you don't have a similar code that allows you to fix it in the Start menu (Windows 10) using this same interface method?
 
function PinToStartMenu(const AFilename: string; AIsPin: Boolean): Boolean;
// AFilename : full path to exe- or lnk-file
// AIsPin    : False - unpin from StartMenu, True - pin to StartMenu
var
  LShellApp, LFolderItem: Variant;
  LVerb, LnkName: string;
begin
  Result := False;
  if not FileExists(AFilename) then Exit;
  try
    LShellApp := CreateOleObject('Shell.Application');
    LFolderItem := LShellApp.Windows.Item.Document.Application
      .NameSpace(ExtractFileDir(AFilename))
      .ParseName(ExtractFileName(AFilename));
    { Below Windows 8. }
    if GetWindowsVersion < $06020000 then
    begin
      if AIsPin then
        LVerb := 'startpin' else
        LVerb := 'startunpin';
      LFolderItem.InvokeVerb(LVerb);
      Result := True;
    end else
    { Windows 8 and above. }
    begin
      if not LFolderItem.IsLink then
      begin
        LnkName := LFolderItem.ExtendedProperty('FileDescription');
        if LnkName = '' then
          LnkName := ExtractFileName(AFilename);
        LnkName := ExpandConstant('{commonprograms}\') + ChangeFileExt(LnkName, '.lnk');
        if AIsPin then
          Result := not FileExists(LnkName) and
            FileExists(CreateShellLink(LnkName, '', AFilename, '', '', '', 0, SW_SHOWNORMAL))
        else
          Result := DeleteFile(LnkName);
      end else
      begin
        LnkName := ExpandConstant('{commonprograms}\') + ExtractFileName(LFolderItem.Path);
        if AIsPin then
          Result := not FileExists(LnkName) and
            FileCopy(LFolderItem.Path, LnkName, False)
        else
          Result := DeleteFile(LnkName);
      end;
    end;
  except
    ShowExceptionMessage;
  end;
end;
P.S. In PinToTaskbar code read { Windows 10 (build 1809) and below. } as { Below Windows 10 (build 1809) fallback. }

Luís César Zanetti

unread,
Feb 20, 2020, 9:32:42 PM2/20/20
to inno...@googlegroups.com
This code works, but does not fix in the "Start" menu.
It pinned to the "Recently Added" item group.
I needed a code to fix in the "Start" blocks as it is done using the command shown in the attached image.


Still, thanks. Thank you!

--
You received this message because you are subscribed to the Google Groups "innosetup" group.
To unsubscribe from this group and stop receiving emails from it, send an email to innosetup+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/innosetup/c757b136-3c72-4835-a776-fde451ec70b5%40googlegroups.com.
snap955.jpg
Reply all
Reply to author
Forward
0 new messages