【问题标题】:Unpin app from taskbar, startmenu using Inno Setup使用 Inno Setup 从任务栏、开始菜单取消固定应用
【发布时间】:2014-07-27 16:31:09
【问题描述】:

我正在使用面向 XP、Win7、8 的 Inno Setup 开发安装程序。我需要将应用程序图标固定到任务栏和开始菜单。到目前为止,我已经能够做到这一点。

现在,当用户卸载此程序时,固定的项目应该被取消固定。我还没有设法解决这个问题。

请指导。

【问题讨论】:

  • 您说过您可以将图标固定到任务栏和开始菜单。如何 ?我要求提出相应的反向行动。此外,据我所知,你不能以编程方式固定图标,所以你所说的让我很惊讶......
  • 我以此为参考。 wincert.net/forum/topic/…

标签: inno-setup


【解决方案1】:

您说过您使用了来自this link 的函数。我假设来自this post

procedure zylPinAppToTaskbar(strPath, strApp: string);  
var  
  vShell, vFolder, vFolderItem, vItemVerbs: Variant;  
  vPath, vApp: Variant;
  i: Integer;
  sItem: String;
  h: LongInt;
  szPinName: String;
  filenameEnd : Integer;
  filename    : String;
  strEnd    : String;
begin 
  SetLength(szPinName, 255);
  h := LoadLibrary(ExpandConstant('{sys}\Shell32.dll'));
  LoadString(h, 5386, szPinName, 255);
  FreeLibrary(h);
  strEnd := #0;
  filenameEnd := Pos(strEnd, szPinName);
  filename := Copy(szPinName, 1, filenameEnd - 1);
  if (Length(filename) > 0) then  //WinXp or lower, no pin taskbar function
  begin
    vShell := CreateOleObject('Shell.Application');
    vPath := strPath;
    vFolder := vShell.NameSpace(vPath);
    vApp := strApp;
    vFolderItem := vFolder.ParseName(vApp);
    vItemVerbs := vFolderItem.Verbs;

  for i := 1 to vItemVerbs.Count do
  begin
    sItem := vItemVerbs.Item(i).Name;

    if (sItem = filename) then
    begin
      // 63 63 72 75 6E 2E 63 6F 6D
      vItemVerbs.Item(i).DoIt;
      break;
     end;
    end;
  end;
end;

这真的很老套(我不会依赖它)。现在让我们关注它的实际作用。该函数加载Shell32.dll 库并从其字符串表中读取属于将此程序固定到任务栏 功能的弹出菜单项的标题(并将其存储到filename 变量中)。然后它连接到 Shell 并为传递的文件夹路径(vFolder 变量)创建 Folder 对象。对于这个文件夹对象,它会创建FolderItem 对象(vFolderItem 变量)并在这个对象上迭代所有可用的动词(vItemVerbs 变量)并检查Name 是否与从Shell32.dll 库中读取的相匹配.如果找到,它会通过DoIt 方法调用操作并中断迭代。

现在,如果您知道上面的代码做了什么,您可以猜测执行取消固定操作所需要做的唯一事情就是找到该功能的弹出菜单项的标题。我查看了Shell32.dll 库的字符串表,Unpin this program from taskbar 字符串的 ID 为 5387,因此修改上述取消固定函数的唯一方法是更改​​此行:

// this magical 5386 value is the ID of the "Pin this program to taskbar"
// popup menu caption string in the Shell32.dll string table
LoadString(h, 5386, szPinName, 255);

到这里:

// this magical 5387 value is the ID of the "Unpin this program from taskbar"
// popup menu caption string in the Shell32.dll string table
LoadString(h, 5387, szPinName, 255);

但我不推荐这种方式。没有将程序固定到任务栏的官方方法,因为这是保留给用户决定的。


作为奖励,我为上述代码编写了以下包装器:

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

及其可能的用途,用于固定:

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

对于取消固定:

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

【讨论】:

  • 感谢您的解释!真的很需要。 :)
【解决方案2】:

我能够做到。这是从开始菜单和任务栏固定和取消固定的代码。

oShell := CreateOleObject('Shell.Application');
objFolder := oShell.Namespace(ExpandConstant('{localappdata}\My_Path'));
objFolderItem := objFolder.ParseName('MyApp.exe');
colVerbs := objFolderItem.Verbs();
for i := 0 to colverbs.count() do
begin
   VerbName := lowercase(colverbs.item(i).name);
   StringChangeEx(VerbName,'&','',true);
   if (CompareText(Verbname, 'Pin to Start Menu') = 0) then
     colverbs.item(i).DoIt
   if (CompareText(Verbname, 'Pin to Taskbar') = 0) then
     colverbs.item(i).DoIt
end;

在取消固定时将比较字符串更改为“从开始菜单取消固定”和“从任务栏取消固定”。

【讨论】:

  • 这在非英语 Windows 上不起作用。例如,在我的系统中,那些名为 "Připnout na hlavní panel""Připnout k nabídce Start" 的菜单固定项。如您所见,它们都不符合您的模式。从 Shell32.dll 字符串表中读取这些标题在该代码中占有一席之地。
  • 你说得对。我很高兴它运行起来,迫不及待地想发布它! :P
  • 所以我真的破坏了你的心情。作为补偿,我为你写了一些更通用的代码:-)
  • 非常感谢通用代码!不,我的心情没有被宠坏..我看到了你的回答,我看到了我的(新手)回答......我被自己逗乐了......!! :)
  • @TLama 在某些版本的 Window 8.1 下,该字符串似乎不再位于 Shell32.exe 中。我不确定他们现在到底在哪里。
猜你喜欢
  • 2012-10-08
  • 1970-01-01
  • 2018-05-14
  • 1970-01-01
  • 2018-06-05
  • 1970-01-01
  • 2019-08-28
  • 1970-01-01
相关资源
最近更新 更多