IContextMenu :: QueryContextMenu返回不相关的菜单

Asa*_*saq 12 c++ delphi winapi contextmenu windows-shell

网络连接快捷方式(以太网,Wi-Fi等)具有不同的上下文菜单,具体取决于连接状态(已连接/已断开连接).我使用以下代码(Delphi)来检索和显示此菜单.

var pidl, child: PItemIdList;
    pFolder: IShellFolder;
    pMenu: IContextMenu;
    menu: HMENU;
begin
  SHParseDisplayName(PChar('%USERPROFILE%\Desktop\eth0.lnk'), nil, pidl, 0, PDWORD(nil)^);
  SHBindToParent(pidl, IID_IShellFolder, Pointer(pFolder), child);
  CoTaskMemFree(pidl);
  pFolder.GetUIObjectOf(0, 1, child, IID_IContextMenu, nil, pMenu);
  menu := CreatePopupMenu;
  pMenu.QueryContextMenu(menu, 0, 0, $7fff, CMF_NORMAL);
  TrackPopupMenuEx(menu, TPM_LEFTBUTTON, 0, 0, Handle, nil);
  DestroyMenu(menu);
end;
Run Code Online (Sandbox Code Playgroud)

但在改变连接状态后,我不断收到旧菜单.并重新启动我的应用程序后.有时重启我的应用程序后,我得到正确的菜单.

为什么会发生以及如何解决?

操作系统:32位和64位Windows 7/8/10

C++代码:

PIDLIST_ABSOLUTE pidl;
if SUCCEEDED(SHParseDisplayName(L"%USERPROFILE%\\Desktop\\eth0.lnk", NULL, &pidl, 0, NULL))
{
  PCUITEMID_CHILD child;
  CComQIPtr<IShellFolder> pFolder;
  if SUCCEEDED(SHBindToParent(pidl, IID_IShellFolder, (void**)&pFolder, &child))
  {
    CComQIPtr<IContextMenu> pMenu;
    if SUCCEEDED(pFolder->GetUIObjectOf(0, 1, &child, IID_IContextMenu, NULL, (void**)&pMenu))
    {
      HMENU menu = CreatePopupMenu();
      if SUCCEEDED(pMenu->QueryContextMenu(menu, 0, 0, 0x7fff, CMF_NORMAL))
        TrackPopupMenuEx(menu, TPM_LEFTBUTTON, 0, 0, hWnd, NULL);
      DestroyMenu(menu);
    }
  }
  CoTaskMemFree(pidl);
}
Run Code Online (Sandbox Code Playgroud)

添加: 也许是Windows的bug.来自Internet和文件管理器(如Explorer(XYPlorer,Explorer ++等))的任何示例都存在同样的问题.现在我在Windows 10资源管理器上看到了同样的问题.如果通过拖放操作将快捷方式创建到桌面上"控制面板\所有控制面板项目\网络和共享中心\更改适配器设置\适配器名称"的网络连接,您将看到同样的问题.

小智 0

我认为该问题与缓存的网络连接快捷方式的上下文菜单信息有关,当您更改连接状态时,Windows 可能不会自动刷新缓存的信息。

您可能需要通过调用该函数 来手动刷新缓存SHChangeNotify,它会通知系统应用程序执行的事件并触发缓存刷新。
这是德尔福中的一个例子:

begin
// ... your code here ...

SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil);
end;
Run Code Online (Sandbox Code Playgroud)

在 C++ 中:

SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
Run Code Online (Sandbox Code Playgroud)

为了确保上下文菜单是最新的,请尝试SHChangeNotify在显示之前调用。