You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取Windows Defender扫描右键菜单项的图标?

Shell上下文菜单转WPF ContextMenu时部分项图标无法获取

我正尝试将通过IContextMenu.QueryContextMenu()获取的HMENU转换为WPF的ContextMenu,以便使用自定义样式替代原生Windows菜单样式。大部分功能正常,但“使用Windows Defender扫描...”和谷歌云盘的“同步或备份此文件夹”这两个项,通过GetMenuItemInfo()获取的MENUITEMINFO结构中未返回图标,其他项的图标均可正常获取。我也查看了MIIM_DATA,但未找到相关内容。

编辑补充:这些项并非自绘。我已将TrackPopupMenuEx()与WndProc挂钩,检查消息流后未发现WM_DRAWITEM或WM_MEASUREITEM消息。

相关代码

Public Function GetContextMenu(items As IEnumerable(Of Item)) As ContextMenu
    Dim pidls(items.Count - 1) As IntPtr
    Dim lastpidls(items.Count - 1) As IntPtr

    For i = 0 To items.Count - 1
        Functions.SHGetIDListFromObject(Marshal.GetIUnknownForObject(items(i).ShellItem2), pidls(i))
        lastpidls(i) = Functions.ILFindLastID(pidls(i))
    Next

    Dim ptr As IntPtr
    Me.ShellFolder.GetUIObjectOf(IntPtr.Zero, lastpidls.Length, lastpidls, GetType(IContextMenu).GUID, 0, ptr)
    Dim contextMenu As IContextMenu = Marshal.GetTypedObjectForIUnknown(ptr, GetType(IContextMenu))

    Marshal.QueryInterface(ptr, GetType(IContextMenu2).GUID, ptr)
    Dim contextMenu2 As IContextMenu2, contextMenu3 As IContextMenu3
    If Not ptr = IntPtr.Zero Then
        contextMenu2 = CType(Marshal.GetObjectForIUnknown(ptr), IContextMenu2)
    End If
    Marshal.QueryInterface(ptr, GetType(IContextMenu3).GUID, ptr)
    If Not ptr = IntPtr.Zero Then
        contextMenu3 = CType(Marshal.GetObjectForIUnknown(ptr), IContextMenu3)
    End If

    Dim hMenu As IntPtr = Functions.CreatePopupMenu()
    contextMenu.QueryContextMenu(hMenu, 0, 0, UInt32.MaxValue, CMF.CMF_NORMAL Or CMF.CMF_EXTENDEDVERBS)
    If _firstContextMenuCall Then
        ' somehow very first call doesn't return all items
        Functions.DestroyMenu(hMenu)
        hMenu = Functions.CreatePopupMenu()
        contextMenu.QueryContextMenu(hMenu, 0, 0, UInt32.MaxValue, CMF.CMF_NORMAL Or CMF.CMF_EXTENDEDVERBS)
    End If

    Dim getMenu As Func(Of IntPtr, List(Of Control)) =
        Function(hMenu2 As IntPtr) As List(Of Control)
            If Not contextMenu2 Is Nothing Then
                contextMenu2.HandleMenuMsg(WM.INITMENUPOPUP, hMenu2, IntPtr.Zero)
            End If
            If Not contextMenu3 Is Nothing Then
                Dim ptr2 As IntPtr
                contextMenu3.HandleMenuMsg2(WM.INITMENUPOPUP, hMenu2, IntPtr.Zero, ptr2)
            End If

            Dim result As List(Of Control) = New List(Of Control)()

            For i = 0 To Functions.GetMenuItemCount(hMenu2) - 1
                Dim mii As MENUITEMINFO
                mii.cbSize = CUInt(Marshal.SizeOf(mii))
                mii.fMask = MIIM.MIIM_STRING
                mii.dwTypeData = New String(" "c, 2048)
                mii.cch = mii.dwTypeData.Length
                Functions.GetMenuItemInfo(hMenu2, i, True, mii)
                Dim header As String = mii.dwTypeData.Substring(0, mii.cch)

                mii.fMask = MIIM.MIIM_BITMAP Or MIIM.MIIM_SUBMENU Or MIIM.MIIM_FTYPE
                Functions.GetMenuItemInfo(hMenu2, i, True, mii)

                Dim bitmapSource As BitmapSource
                If Not IntPtr.Zero.Equals(mii.hbmpItem) Then
                    bitmapSource = Interop.Imaging.CreateBitmapSourceFromHBitmap(mii.hbmpItem, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions())
                Else
                    bitmapSource = Nothing
                End If

                If mii.fType = MFT.SEPARATOR Then
                    result.Add(New Separator())
                Else
                    Dim menuItem As MenuItem = New MenuItem() With {
                        .Header = header.Replace("&", "_"),
                        .Icon = New Image() With {.Source = bitmapSource}
                    }

                    If mii.hSubMenu Then
                        Dim subMenu As List(Of Control) = getMenu(mii.hSubMenu)
                        For Each subMenuItem In subMenu
                            menuItem.Items.Add(subMenuItem)
                        Next
                    End If

                    result.Add(menuItem)
                End If
            Next

            Return result
        End Function

    Dim result2 As List(Of Control) = getMenu(hMenu)

    Dim menuResult As ContextMenu = New ContextMenu()
    For Each item In result2
        menuResult.Items.Add(item)
    Next

    Functions.DestroyMenu(hMenu)

    Return menuResult
End Function

内容的提问来源于stack exchange,提问作者miss programmer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 05:43:19