Back to Writing

Where's the new Windows 11 context menu queries from?

Deep dive into RE'ing the new Windows 11 context menu system using IDA Pro and WinDbg.

February 7, 202615 min readWindows 11, Context Menu, Shell, Reverse Engineering

# Another slow one, yes

The original point of introducing a new menu system was to bla bla bla according to this blog. However, ...

# What happens when you right-click on item(s)

I have no idea where the right click operation is handled, where can I start from? I knew a lot happen in explorerframe.dll so I looked into that dll with IDA. Let's find a demangled symbol named *Right* in the Functions tab.

Found these two! The second one looks to be the destructor, let's looks into the first one.

src="https://i.imgur.com/1TvQu4u.png"

caption="Search result for the symbols named *Right*"

/>

As you can see, it looks like the one we should look into. Hmm, but how we can trace the calls down to the context menu manager if there is? Statically analyzing this can be a lot of work, why not use WinDbg for the runtime debugging.

Let's set breakpoints at functions named *ContextMenu* this time. The flyout itself looks to be WUX (Windows.UI.Xaml) so we also can assume it's located at somewhere in windows.ui.*.dll.

src="https://i.imgur.com/HQxqpBL.png"

caption="Xrefs of the method"

/>

Looking through these functions, what do you think is the function that loads commands for the default simple menu?

# The context menu manager

According to OleView.NET, it is implemented in Windows.UI.FileExplorer.dll, which is mainly developed for XAML in File Explorer. If I search for ContextMenu in the Names tab in IDA, yes, we find it. It's named ContextMenuPresenter.

class ContextMenuPresenter
    : IClosable
    , IInspectable
    , IOleWindow
    , IServiceProvider
    , IUnknown
    , IWeakReferenceSource
{
    // ...
}

Executive Summary

The ContextMenuPresenter class is responsible for creating and managing modern "curated" context menus in Windows File Explorer. The TryCreateMiniMenuFromClassic function serves as the primary bridge between legacy Win32 context menus and the modern XAML-based menu system. This report provides a detailed analysis of how the class initializes context menus and loads menu items from multiple sources.

Component Location

Source File: pcshell\shell\windows.ui.fileexplorer\src\ContextMenuPresenter.cpp
Header File: pcshell\shell\windows.ui.fileexplorer\src\ContextMenuPresenter.h

Class Responsibilities

The ContextMenuPresenter class is responsible for:

1. Menu Creation: Converting classic Win32 HMENU handles to modern XAML MenuFlyout items

2. Item Filtering: Removing unwanted or duplicate menu items from classic menus

3. Extension Integration: Loading and inserting app extensions into menus

4. Icon Management: Asynchronously loading menu item icons

5. Verb Management: Tracking canonical verbs and command IDs

6. Telemetry: Recording context menu usage analytics

---

Architecture: Shell View to Context Menu Presenter

Complete Call Chain from User Action

The context menu creation process follows a well-defined call chain from the shell view (DefView) to the context menu presenter:

User Right-Click Event
    
    
CDefView::DoContextMenuPopup (0x18029f6b0)
    
    
CDefView::_DoContextMenuPopup (0x1802b3204)
    
     Desktop Spotlight Path (if enabled)
        [Spotlight-specific handling]
    
     Standard Context Menu Path
        
         IContextMenu::QueryContextMenu
            Populates HMENU with classic items
        
         CDefView::DoCuratedContextMenu (0x18029f72c)
            
             CDefView::TryGetContextMenuPresenter (0x1800a56a0)
                IUnknown_QueryService  IContextMenuPresenter
            
             IContextMenuPresenter::DoContextMenu (vtable+0x20)
                 ContextMenuPresenter::DoContextMenuHelper (0x1800a9f8b)
                     [Modern XAML flyout creation]

CDefView::DoContextMenuPopup

Address: 0x18029f6b0

Size: 0x73 bytes (115 bytes)

Purpose: Public interface method for showing context menus

This is the public entry point exposed through the COM interface. Acts as a simple wrapper that validates window state before delegating to the internal implementation.

Implementation:

HRESULT CDefView::DoContextMenuPopup(
    CDefView* this,
    IUnknown* punkSite,
    unsigned int flags,
    POINT pt)
{
    HWND hwnd = *(this + 68);  // Get view window handle
    
    if (hwnd && IsWindowVisible(hwnd))
    {
        // Call internal implementation with Mode = 0 (curated)
        return CDefView::_DoContextMenuPopup(
            this - 38,           // Adjust this pointer
            punkSite,
            flags,
            pt,
            0                    // Mode: 0 = Curated menu
        );
    }
    else
    {
        return E_UNEXPECTED;     // 0x8000FFFF
    }
}

Key Validation:

  • Checks if view window exists and is visible
  • Returns `E_UNEXPECTED` if window is not ready
  • Adjusts `this` pointer for internal class layout
  • Always passes `Mode = 0` for curated menu behavior

---

CDefView::_DoContextMenuPopup

Address: 0x1802b3204

Size: 0xe0b bytes (3,595 bytes)

Purpose: Core context menu orchestration and HMENU creation

This is the massive internal implementation that handles the complete context menu creation pipeline. It's one of the most complex functions in the DefView component.

Function Signature:

HRESULT CDefView::_DoContextMenuPopup(
    CDefView* this,
    IUnknown* punkSite,
    unsigned int flags,
    POINT pt,
    int mode                    // 0 = Curated, 1 = Classic
)

High-Level Flow:

_DoContextMenuPopup
    
     1. TELEMETRY & INITIALIZATION
        Start ContextMenuCreationTest telemetry
        Check Shift key state (add 0x100 to flags if pressed)
        ETW event: Shell32_GeneratingContextMenu_Start
    
     2. DESKTOP SPOTLIGHT DETECTION
        Check Feature_DesktopSpotlightRightClickContextMenu
        Check location context == LOCATION_CONTEXT_DESKTOP (0x400)
        If Spotlight: Calculate flyout position from icon rect
        Log Spotlight telemetry
    
     3. CURATED vs CLASSIC DECISION
        Call: ShouldShowMiniMenu(flags)
        TryGetContextMenuPresenter()
        IsReadyForNewContextMenu()
        Set mode based on result
    
     4. CLASSIC MENU CREATION (IContextMenu)
        QueryInterface  IContextMenu
        Setup site if needed (CLauncherUIMode)
        CreatePopupMenu()  hMenu
        QueryInterface  IContextMenu3 (set 0x20000 flag)
        Add IDefaultFolderMenuInitialize restrictions
        SetContextMenuCapability()
        IContextMenu::QueryContextMenu(hMenu, 0, 30977, 31487, flags)
            Shell extensions populate the menu
    
     5. MERGE ADDITIONAL ITEMS
        Load "Open" menu from resources (0x104)
        SetMenuItemInfoW (custom text)
        Set shield bitmap if needed
        Shell_MergeMenus(hMenu, openMenu, ...)
        CItemsView::MergeSelectionContextMenu
        _SHPrettyMenu(hMenu)
    
     6. DARK MODE SUPPORT
        Feature_FileExplorerDarkTheme check
        AllowDarkModeContextMenu()
        SetDarkModeForWindows wrapper
    
     7. DISPATCH TO MENU TYPE
        If mode == 0 (Curated):
           DoCuratedContextMenu(pContextMenu, hMenu, flags, pt)
               [Calls ContextMenuPresenter]
       
        If mode == 1 (Classic):
            DoClassicMenu(pContextMenu, hMenu, pt, shellItems)
                [Traditional Win32 TrackPopupMenu]
    
     8. CLEANUP
         DestroyMenu(hMenu)
         Release(pContextMenu)
         ETW event: Shell32_InvokingContextMenu_Stop
         Complete telemetry test

Critical Decision Points:

Desktop Spotlight Detection:

if (Feature_DesktopSpotlightRightClickContextMenu::IsEnabled() &&
    (this->flags & 0x10000000) != 0)  // Spotlight context flag
{
    IShellItemArray* items = NULL;
    _GetItems(1, 0, IID_IShellItemArray, &items);
    
    if ((GetLocationContext(items) & 0x7FF) == 0x400)  // DESKTOP context
    {
        // Calculate Spotlight flyout position
        int itemIndex = GetItemIndex(-1, 1, 0);
        if (itemIndex != -1)
        {
            RECT rectItem;
            GetItemRect(itemIndex, &rectItem);
            
            pt = GetSpotlightFlyoutPosition(&rectItem, m_someFlag);
            
            if (Feature_DesktopSpotlightFlyoutPositionLogging::IsEnabled())
            {
                DesktopIconLayoutTelemetry::SpotlightFlyoutPositionLogging(
                    &rectItem, &pt);
            }
        }
    }
}

Curated Menu Decision:

bool shouldShowMini = ShouldShowMiniMenu(flags);
testData->shouldShowCuratedMenu = shouldShowMini;

if (shouldShowMini)
{
    IContextMenuPresenter* presenter = NULL;
    TryGetContextMenuPresenter(&presenter);
    
    if (presenter)
    {
        GUID testId = GetTestId();
        if (!presenter->IsReadyForNewContextMenu(&testId, pt))
        {
            // Presenter busy - bail out
            testData->presenterNotReady = 1;
            Complete(telemetryTest);
            return S_OK;
        }
    }
    else
    {
        mode = 1;  // Fall back to classic menu
    }
}
else
{
    mode = 1;  // Force classic menu
}

IContextMenu::QueryContextMenu Call:

// Set up parameters
UINT idCmdFirst = 30977;  // 0x7901
UINT idCmdLast = 31487;   // 0x7AFF
UINT uFlags = flags | 0x20 | 0x400;  // CMF_DEFAULTONLY | CMF_ASYNCVERBS

if (!mode)  // Curated mode
    uFlags |= 0x8000;  // CMF_CURATED flag

// Set menu restrictions for curated mode
if (!mode)
{
    IDefaultFolderMenuInitialize* pInit = NULL;
    if (pContextMenu->QueryInterface(
            IID_IDefaultFolderMenuInitialize,
            &pInit) >= 0)
    {
        pInit->SetMenuRestrictions(0x2040);
        pInit->Release();
    }
}

SetContextMenuCapability(hMenu);

// Populate menu with shell extensions
HRESULT hr = pContextMenu->QueryContextMenu(
    hMenu,
    0,              // Index to insert at
    idCmdFirst,
    idCmdLast,
    uFlags
);

Menu Item Merging:

// Load additional menu items for file selection
if (m_pShellBrowser && (flags & 0x80))  // DROPEFFECT_COPY flag
{
    ICommDlgBrowser2* pCommDlg = NULL;
    m_pShellBrowser->QueryInterface(IID_ICommDlgBrowser2, &pCommDlg);
    
    DWORD commDlgFlags = 0;
    if (pCommDlg)
        pCommDlg->GetCommDlgOptions(&commDlgFlags);
    
    if (!(commDlgFlags & 8))  // CDB2GCO_NO_OPENMENU
    {
        // Load "Open" menu from resources
        HMENU hOpenMenu = SHLoadPopupMenu(g_hinst, 0x104);
        
        if (hOpenMenu)
        {
            // Customize menu item text if needed
            if (pCommDlg)
            {
                WCHAR szText[260];
                if (pCommDlg->GetDefaultMenuText(this, szText, 260) == S_OK)
                {
                    MENUITEMINFOW mii = {0};
                    mii.cbSize = 80;
                    mii.fMask = MIIM_STRING;
                    mii.dwTypeData = szText;
                    SetMenuItemInfoW(hOpenMenu, 0, TRUE, &mii);
                }
            }
            
            // Add shield icon if needed
            if ((commDlgFlags & 0x40) && m_hShieldBitmap)
            {
                SHEnableMenuCheckMarkOrBmp(hOpenMenu);
                
                MENUITEMINFOW mii = {0};
                mii.cbSize = 80;
                mii.fMask = MIIM_BITMAP;
                mii.hbmpItem = m_hShieldBitmap;
                SetMenuItemInfoW(hOpenMenu, 0, TRUE, &mii);
                SHEnableMenuCheckMarkOrBmp(hMenu);
            }
            
            // Merge into main menu
            Shell_MergeMenus(
                hMenu,           // Target menu
                hOpenMenu,       // Source menu
                0,               // Insert position
                0x7026,          // First ID
                0xFFFFFFFF,      // Last ID
                1                // Flags
            );
            
            SetMenuDefaultItem(hMenu, 0, MF_BYPOSITION);
            DestroyMenu(hOpenMenu);
        }
    }
}

// Merge items from CItemsView
if (flags & 0x80)  // Selection context
{
    IItemsView* pItemsView = m_pItemsView;
    if (pItemsView)
    {
        pItemsView->MergeSelectionContextMenu(
            hMenu,
            mergeIndex,
            m_pidl  // Item ID list
        );
    }
}

// Apply shell menu styling
_SHPrettyMenu(hMenu);

Dark Mode Setup:

Feature_FileExplorerDarkTheme::ReportUsage(
    UsageReportingMode::ReportUsage,
    TelemetryReportingStage::InUsePhase
);

SetDarkModeForWindows* pDarkMode = NULL;
int darkModeFlags = 0;
bool allowDarkMode = false;

if (allowDarkMode)
{
    pDarkMode = new (std::nothrow) SetDarkModeForWindows();
    if (pDarkMode)
    {
        if (AllowDarkModeContextMenu(this, pDarkMode, &darkModeFlags) >= 0)
            allowDarkMode = true;
    }
}

// Store dark mode context for menu display
// (cleanup via RAII wrapper)

Final Dispatch:

// Store context menu state
m_pContextMenu = pContextMenu;
pContextMenu->AddRef();

// Set UI display flag in data object
IDataObject* pDataObj = NULL;
if (IUnknown_GetSelection(m_pContextMenu, &pDataObj) >= 0)
{
    DWORD displayed = 1;
    DataObj_SetBlobWithIndex(pDataObj, g_cfUIDisplayed, &displayed, 4);
    pDataObj->Release();
}

// ETW event
if (ETW_enabled)
    McGenEventWrite_EtwEventWriteTransfer(&Shell32_GeneratingContextMenu_Stop);

// Dispatch based on mode
if (mode == 0)  // Curated
{
    LocationContext = GetLocationContext(shellItems);
    testData->locationContextFlags = LocationContext;
    Complete(telemetryTest);
    
    DoCuratedContextMenu(pContextMenu, hMenu, flags, &pt);
}
else  // Classic
{
    LocationContext = GetLocationContext(shellItems);
    testData->locationContextFlags = LocationContext;
    Complete(telemetryTest);
    
    DoClassicMenu(pContextMenu, hMenu, &pt, shellItems);
    CleanupAfterContextMenu();
}

Exception Handling:

try
{
    // Desktop Spotlight detection and positioning
    if (Feature_DesktopSpotlightRightClickContextMenu::IsEnabled() && ...)
    {
        // ... Spotlight logic ...
    }
}
catch (...)
{
    wil::Log_CaughtException();
    // Continue with regular menu - graceful degradation
}

Key Constants:

ConstantValuePurpose
`idCmdFirst`30977 (0x7901)First command ID for shell extensions
`idCmdLast`31487 (0x7AFF)Last command ID for shell extensions
`CMF_DEFAULTONLY`0x20Only default menu items
`CMF_ASYNCVERBS`0x400Allow async verb execution
`CMF_CURATED`0x8000Request curated menu
`LOCATION_CONTEXT_DESKTOP`0x400Desktop location flag

Telemetry Points:

1. ContextMenuCreationTest: Tracks menu creation performance

2. Shell32_GeneratingContextMenu_Start/Stop: ETW events

3. DesktopSpotlightIconRightClicked: Spotlight interaction

4. SpotlightFlyoutPositionLogging: Position debugging

5. DesktopSpotlightRejuvenatedFlyout: Feature usage

---

CDefView::DoCuratedContextMenu

Address: 0x18029f72c

Size: 0x337 bytes (823 bytes)

Purpose: Bridge between DefView and ContextMenuPresenter for curated menus

This function is the critical bridge that connects the shell view's classic HMENU to the modern ContextMenuPresenter's XAML flyout.

Function Signature:

void CDefView::DoCuratedContextMenu(
    CDefView* this,
    IContextMenu* pContextMenu,
    HMENU hMenu,
    unsigned int flags,
    POINT* ppt
)

Execution Flow:

DoCuratedContextMenu
    
     1. GET SHELL ITEMS
        _GetItems(1, 0, IID_IShellItemArray, &items)
        GetLocationContext(items)  locationContext
    
     2. ACQUIRE CONTEXT MENU PRESENTER
        TryGetContextMenuPresenter(&presenter)
        If NULL: Throw E_FAIL (0x80004005)
        Store current focus: m_hWndFocus = GetFocus()
    
     3. SET PRESENTER FLAGS
        If (this->flags & 0x100): presenter->flags |= 0x8
        If (screenReaderEnabled): presenter->flags |= 0x1
        If (Spotlight + Desktop): presenter->flags |= 0x10
    
     4. CALL CONTEXTMENUPRESENTER::DOCONTEXTMENU
        Get vtable: vtable = *presenter
        Get method: fn = vtable[0x20]  // 4th virtual method
       
        Parameters:
           rcx = presenter (this)
           rdx = locationContext
           r8 = CDefView* (callback context)
           r9 = POINT (cursor position)
          
           Stack parameters:
              hMenu (classic menu handle)
              flags (menu flags)
              testId (telemetry GUID)
              pContextMenu
              idCmdFirst = 30977
              idCmdLast = 31487
              hasIdMap = 1
              pIdMap = &c_DefViewIDMAP
              (more params)
          
           Call via CFG: _guard_dispatch_icall(fn)
       
        If FAILED: Throw_Hr()
    
     5. CONDITIONAL SECONDARY CALLS
       
        If (Spotlight && Desktop):
           Destroy classic menu: hMenu = NULL
           Get vtable[0x28]  DoContextMenuWithClassicMenu
           Call with alt flags + extensions
       
        If (hasOptionalPresenter):
           hMenu = NULL
           Get vtable[0x28]
           Call DoContextMenu variant
       
        Else:
            hMenu = NULL
            Get vtable[0x28]
            Standard DoContextMenu call
    
     6. EXCEPTION HANDLING
         catch(...):
            Log_CaughtException()
            testData->curatedMenuException = 1
            Complete(telemetryTest)
            DoExpandedContextMenu (fallback)
        
         Release(presenter)

Detailed Analysis:

Getting the Presenter:

IContextMenuPresenter* presenter = NULL;
TryGetContextMenuPresenter(&presenter);

if (!presenter)
{
    wil::Throw_Hr(
        E_FAIL,
        "shell\\SrcPkg\\FileExplorer\\DefView\\src\\DefView.cpp",
        Line 2127
    );
}

TryGetContextMenuPresenter Implementation (0x1800a56a0):

ComPtr<IContextMenuPresenter> CDefView::TryGetContextMenuPresenter()
{
    ComPtr<IContextMenuPresenter> result;
    
    // Query for presenter service from shell browser
    HRESULT hr = IUnknown_QueryService(
        m_pShellBrowser,  // Service provider
        &SID_ContextMenuPresenter,  // GUID_b306c5b1_b4f2_473c_b6ff_701b246ce2d2
        &IID_IContextMenuPresenter, // GUID_37a472f7_63cf_4ccf_a88b_5231a3c7d8b6
        &result
    );
    
    // Handle expected failure codes
    if (hr == CLASS_E_CLASSNOTAVAILABLE ||  // -2147221164 (0x80040154)
        hr == E_NOINTERFACE ||                // -2147467259 (0x80004002)
        hr == E_NOTIMPL ||                    // -2147467263 (0x80004001)
        hr == ERROR_MOD_NOT_FOUND)            // -2147024770 (0x8007007E)
    {
        // Mark in telemetry that presenter was not available
        auto testData = EnsureTestData();
        testData->contextMenuPresenterNotAvailable = 1;
    }
    
    return result;
}

The Critical Call to ContextMenuPresenter::DoContextMenu:

Looking at the assembly at 0x18029f82f - 0x18029f8a0:

; Get the presenter pointer
18029f82f  mov     r10, [rsp+0E8h+var_50]     ; r10 = IContextMenuPresenter*

; Load vtable
18029f837  mov     rax, [r10]                  ; rax = vtable pointer

; Load function pointer at vtable+0x20 (4th virtual method)
18029f83a  mov     r11, [rax+20h]             ; r11 = vtable[4]

; Prepare parameters
18029f892  mov     r9, [r14]                   ; r9 = &POINT
18029f895  mov     r8, rbx                     ; r8 = CDefView* (this)
18029f898  mov     edx, edi                    ; edx = locationContext
18029f89a  mov     rcx, r10                    ; rcx = presenter (this)

; Stack parameters already set up above
; ...

; Make the CFG-protected call
18029f89d  mov     rax, r11                    ; Load function pointer
18029f8a0  call    _guard_dispatch_icall$thunk ; CFG validated indirect call

Vtable Layout Analysis:

// IContextMenuPresenter vtable layout (x64)
0x00: QueryInterface
0x08: AddRef
0x10: Release
0x18: (method 3)
0x20: DoContextMenu  Called here (vtable+0x20)
0x28: DoContextMenuWithClassicMenu (variant method)

Full Parameter Marshaling:

// From the assembly and decompiled code:
HRESULT hr = presenter->DoContextMenu(
    // rcx: this pointer (presenter)
    locationContext,                   // rdx: LOCATION_CONTEXT_FLAGS
    (CDefView*)this,                   // r8: callback context
    *ppt,                              // r9: POINT structure
    
    // Stack parameters (pushed right-to-left):
    hMenu,                             // Classic menu handle
    presenter->flags,                  // Flags set above
    &testId,                           // Telemetry test GUID
    pContextMenu,                      // IContextMenu interface
    30977,                             // idCmdFirst
    31487,                             // idCmdLast
    1,                                 // hasIdMap
    &c_DefViewIDMAP,                   // Command ID mapping table
    &testId,                           // Test ID again
    NULL                               // Reserved
);

Spotlight Special Case:

if (Feature_DesktopSpotlightIconHoverAndSingleClick::IsEnabled() &&
    (locationContext & 0x7FF) == 0x400 &&  // DESKTOP context
    m_spotlightEnabled)
{
    // Desktop Spotlight gets special handling
    presenter->flags |= 0x10;  // Spotlight flag
    
    // Destroy classic menu - Spotlight doesn't use it
    hMenu = NULL;
    
    // Call different vtable method at offset 0x28
    // This method handles Spotlight-specific XAML extension loading
    presenter->DoContextMenuWithClassicMenu(
        hMenu,
        presenter->flags,
        &testId,
        pContextMenu,
        30977,
        31487,
        1,
        &c_DefViewIDMAP,
        &testId,
        NULL
    );
}

Exception Handling and Fallback:

try
{
    // ... Call presenter ...
}
catch (...)
{
    wil::Log_CaughtException();
    
    // Mark failure in telemetry
    auto testData = GetTestData();
    testData->curatedMenuException = 1;
    
    // Complete telemetry test
    Complete(telemetryTest);
    
    // Fall back to expanded context menu (classic Win32)
    DoExpandedContextMenu(
        *ppt,
        flags >> 7,  // Extract high byte
        NULL,
        NULL,
        NULL
    );
}

Key Data Structure: c_DefViewIDMAP

// Command ID mapping table for DefView
const struct QITAB c_DefViewIDMAP[] = {
    // Maps command IDs to interface offsets
    // Used by ContextMenuPresenter to route commands back to DefView
    // ...
};

Integration Points:

1. Service Query: Uses IUnknown_QueryService to locate presenter

2. Vtable Dispatch: CFG-protected indirect call through vtable

3. Parameter Passing: Mix of register and stack parameters (x64 calling convention)

4. Exception Safety: Try/catch with graceful fallback to classic menu

5. Telemetry Integration: TIP test framework tracks success/failure

---

Context Menu Entry Points

The context menu creation process begins with one of two entry points, depending on whether the user is interacting with Desktop Spotlight or regular file/folder items.

Entry Point Decision Tree

User Right-Click
    
     Is Desktop Spotlight Context?
        Feature Flag: DesktopSpotlightRightClickContextMenu
            Enabled + Spotlight Active
               ShowSpotlightContextMenu (0x1800b21d0)
                   Loads XAML extension
                   DesktopSpotlightHost::ShowXamlFlyout
           
            Disabled or Not Spotlight
                DoContextMenuHelper (0x1800a9f8b)
    
     Regular File/Folder Context
         DoContextMenuHelper (0x1800a9f8b)
             Initialize telemetry
             Query browser services  
             Decision: Spotlight vs Curated Menu
             [Main Flow - See Next Section]

ShowSpotlightContextMenu

Address: 0x1800b21d0

Size: 0x329 bytes (809 bytes)

This function handles the special case of Desktop Spotlight right-click menus, which use a completely separate XAML extension instead of the standard curated menu.

Purpose:

  • Loads the Desktop Spotlight XAML extension dynamically
  • Creates a flyout UI specifically for Spotlight interactions
  • Bypasses the standard context menu creation entirely

Key Steps:

void ShowSpotlightContextMenu(ContextMenuPresenter* this, TipTest* tipTest)
{
    // 1. Load the Spotlight XAML extension
    hstring category = L"com.microsoft.windows.extensions.xaml.desktopspotlight";
    auto xamlExtensions = XamlExtensions::GetForCategory(category);
    
    if (!xamlExtensions)
        throw E_FAIL; // Extension not found
    
    // 2. Create the flyout host
    hstring hostName = L"DesktopSpotlightFlyoutHost";
    hstring contentName = L"DesktopSpotlight";
    
    IInspectable flyoutObject;
    xamlExtensions.CreateForPackageFullName(
        &flyoutObject, 
        contentName, 
        hostName
    );
    
    // 3. Query for IFlyout interface
    IFlyout flyout;
    flyoutObject->QueryInterface(IID_IFlyout, &flyout);
    
    // 4. Convert to FlyoutBase and store
    FlyoutBase flyoutBase = flyout.as<FlyoutBase>();
    m_xamlFlyout = flyoutBase;
    
    if (!m_xamlFlyout)
        throw E_FAIL;
    
    // 5. Register event handlers
    auto weakThis = get_weak();
    
    // Closed event handler
    m_xamlFlyout.Closed([weakThis](auto sender, auto args) {
        if (auto strongThis = weakThis.get())
            strongThis->OnSpotlightFlyoutClosed();
    });
    
    // Opened event handler  
    m_xamlFlyout.Opened([weakThis](auto sender, auto args) {
        if (auto strongThis = weakThis.get())
            strongThis->OnSpotlightFlyoutOpened();
    });
    
    // 6. Show the flyout via DesktopSpotlightHost
    CuratedContextMenuTelemetry::CuratedContextMenu_ShowMenu();
    
    tipTest.operator=(m_contextMenuCreationTest);
    
    DesktopSpotlightHost::ShowXamlFlyout(
        m_spotlightHost,
        m_xamlFlyout,
        m_parentWindow,
        m_invokePoint
    );
}

Important Notes:

  • This is a completely separate code path from the standard context menu
  • Only activated when Desktop Spotlight feature flag is enabled
  • Uses AppExtension system to load XAML UI dynamically
  • Package name: `com.microsoft.windows.extensions.xaml.desktopspotlight`
  • No classic menu filtering - entirely modern UI

---

DoContextMenuHelper - Main Orchestration

Address: 0x1800a9f8b

Size: 0x678 bytes (1,656 bytes)

Purpose: Main orchestration function that coordinates context menu creation

This is the primary entry point for standard file/folder context menus. It orchestrates the entire menu creation pipeline from initialization through display.

Function Signature

void ContextMenuPresenter::DoContextMenuHelper(
    ContextMenuPresenter* this,
    HMENU hClassicMenu,           // [in] Classic context menu from shell extensions
    TipTest* tipTest              // [in/out] Telemetry test data
)

Where `hClassicMenu` Comes From

The hClassicMenu passed into DoContextMenuHelper (and then into TryCreateMiniMenuFromClassic) is created by the caller of ContextMenuPresenter::DoContextMenu, not inside ContextMenuPresenter itself.

Evidence in binary:

  • `ContextMenuPresenter::DoContextMenu` (0x180053500) receives `HMENU a2` and immediately stores it in a member `wil::unique_any_t` without creating it.
  • The presenter never calls `CreatePopupMenu` in `DoContextMenu` or `DoContextMenuHelper`.

Observed call chain (in this binary):

FileExplorerFolderViewController::ShowContextMenuForSelection / ShowContextMenuForBackground
     IListControlHost2::ShowContextMenu... (vtable call)
         ContextMenuPresenter::DoContextMenu(HMENU hClassicMenu, flags, invokePoint)
             ContextMenuPresenter::DoContextMenuHelper(hClassicMenu, tipTest)
                 TryCreateMiniMenuFromClassic(&hMenu, hClassicMenu)

Creation point (classic menu):

The HMENU itself is produced by the shell context menu host using the classic Win32 flow:

1. CreatePopupMenu() creates the base menu.

2. IContextMenu::QueryContextMenu() (plus IContextMenu2/3 hooks) populates it.

3. That populated HMENU is then handed to ContextMenuPresenter::DoContextMenu.

The concrete function that calls QueryContextMenu is part of the list control host / shell context menu host, not in ContextMenuPresenter.

High-Level Flow

DoContextMenuHelper
    
     1. INITIALIZATION PHASE
        Start telemetry watch_errors
        Mark ContextMenuCreationTest as started
        Transition flyout state to "Creating"
        Query IServiceProvider for browser services
            Get SID_STopLevelBrowser
            Get frame/window information
    
     2. FEATURE FLAG DECISION
        Check: DesktopSpotlightRightClickContextMenu flag
           If Spotlight context
               Report DesktopSpotlightRejuvenatedFlyout usage
               If location_context == LOCATION_CONTEXT_DESKTOP (0x400)
                  If Spotlight enabled for this presenter
                      ShowSpotlightControl()
                      RETURN EARLY
              
               Otherwise: Fall through to curated menu
       
        Regular Context Menu Flow
            Report DesktopSpotlightRejuvenatedFlyout usage
    
     3. MENU CREATION PHASE
        Set next menu ID counter to 32000 (0x7D00)
        Create temporary HMENU: hMenu = NULL
       
        Call: TryCreateMiniMenuFromClassic(&hMenu, hClassicMenu)
           [Filters and creates curated menu - See dedicated section]
       
        Mark in telemetry: miniMenuCreated = true
       
        If GetMenuItemCount(hMenu) > 0
            Mark in telemetry: hasContextMenuItems = true
            Store menu: swap(m_curatedMenu, hMenu)
    
     4. TELEMETRY SETUP
        Create ContextMenuSelectionTest data
        Start timing for selection test
        Store in m_contextMenuSelectionTest
        Record location_context flags
    
     5. XAML MENU CREATION (if enabled)
        If Spotlight extensions enabled
          
           Get IFileExplorerContextMenuExtension2
          
           CreateMenuItems(m_curatedMenu)
              Convert HMENU to IIterable<MenuItem>
          
           CreateMicrosoftUIXamlControlsPrimitivesMenu(menuItems)
              Creates CommandBarFlyout
          
           Cast to FlyoutBase
              Store in m_xamlFlyout
          
           Query for ICommandBarFlyout interface
          
           RegisterTappedOnShowMoreOptions()
              Register handler for "Show more options" button
          
           Set flyout state = FlyoutState::ShowingXaml (3)
          
           Register Closed event handler
              Lambda captures weak_ptr<this>
              Calls OnFlyoutClosed when menu dismissed
          
           Register Opened event handler
              Lambda captures weak_ptr<this>  
              Calls OnFlyoutOpened when menu shown
          
           Get strong reference: get_strong()
          
           Update telemetry: m_contextMenuCreationTest = tipTest
          
           Call telemetry: CuratedContextMenu_ShowMenu()
          
           ContextMenuHost::ShowXamlFlyout()
               Parameters:
                  m_contextMenuHost (host window)
                  m_xamlFlyout (flyout to show)
                  m_parentWindow (parent HWND)
                  m_invokePoint (screen coordinates)
              
               [Shows XAML flyout on screen]
       
        Destroy temporary HMENU if still exists
    
     6. CLEANUP & EXCEPTION HANDLING
         Release service provider interface
         Destroy test watcher
         Exception handlers at multiple points:
             ShowSpotlightControl exceptions
                Log exception, record in telemetry
                Fall back to regular menu
            
             ShowXamlFlyout exceptions
                 Log exception
                 Complete selection test
                 Cancel current flyout

Detailed Phase Analysis

#### Phase 1: Initialization

// Initialize telemetry tracking
TipTestWatcher<ContextMenuCreationTest> watcher;
tip_test::watch_errors(tipTest, &watcher);

// Mark that context menu creation has started
auto testData = tipTest.operator->();
testData->contextMenuCreationStarted = true;

// Transition state machine
TransitionFlyoutState(FlyoutState::Creating); // State = 1

// Query browser services for window/frame information
IServiceProvider* pServiceProvider = m_site;
IShellBrowser* pBrowser = nullptr;

HRESULT hr = IUnknown_QueryService(
    pServiceProvider,
    SID_STopLevelBrowser,
    IID_IShellBrowser,
    &pBrowser
);

if (SUCCEEDED(hr))
{
    // Get frame and window handles
    pBrowser->QueryInterface(IID_IShellFrame, &m_frame);
    pBrowser->GetWindow(&m_parentWindow);
}
else
{
    // Log warning but continue
    wil::Log_Hr(hr, "Failed to get IShellBrowser");
}

Key Points:

  • Telemetry tracking begins immediately
  • State machine transitions: `Idle` → `Creating`
  • Browser services provide parent window context
  • Failures are logged but don't abort the process

#### Phase 2: Feature Flag Decision

// Check if Desktop Spotlight menu should be shown
if (wil::Feature_DesktopSpotlightRightClickContextMenu::IsEnabled())
{
    if (m_isSpotlightContext)  // Set by caller
    {
        // Report usage of rejuvenated flyout feature
        wil::Feature_DesktopSpotlightRejuvenatedFlyout::ReportUsage(
            UsageReportingMode::ReportUsage,
            TelemetryReportingStage::InUsePhase
        );
        
        // Check location context
        LOCATION_CONTEXT_FLAGS flags = m_locationContextFlags;
        
        if ((flags & 0x7FF) == LOCATION_CONTEXT_DESKTOP &&
            m_spotlightEnabled)
        {
            try
            {
                // Show Spotlight-specific menu
                ShowSpotlightControl(tipTest);
                return; // EARLY EXIT
            }
            catch (...)
            {
                // Log exception
                int hr = wil::ResultFromCaughtException();
                testData->spotlightControlException = hr;
                
                Log("ShowSpotlightControl exception: %d", hr);
                
                // Fall through to standard menu
            }
        }
    }
}
else
{
    // Feature disabled - report and use standard flow
    wil::Feature_DesktopSpotlightRejuvenatedFlyout::ReportUsage(
        UsageReportingMode::ReportUsage,
        TelemetryReportingStage::InUsePhase
    );
}

Decision Factors:

1. Feature Flag: Feature_DesktopSpotlightRightClickContextMenu must be enabled

2. Context Type: m_isSpotlightContext flag set during initialization

3. Location: Must be desktop context (LOCATION_CONTEXT_DESKTOP = 0x400)

4. Spotlight State: m_spotlightEnabled must be true

Exception Handling:

  • If ShowSpotlightControl throws, exception is caught
  • Error is logged to telemetry
  • Flow continues to standard curated menu (graceful fallback)

#### Phase 3: Menu Creation

// Reset menu ID counter to start of range
_InterlockedExchange(&m_nextMenuId, 32000); // 0x7D00

// Create curated menu from classic menu
HMENU hMenu = nullptr;
TryCreateMiniMenuFromClassic(&hMenu, hClassicMenu);
// [Details in dedicated TryCreateMiniMenuFromClassic section]

// Mark in telemetry
testData->miniMenuCreated = true;

// Check if menu has any items
if (GetMenuItemCount(hMenu) > 0)
{
    // Mark success in telemetry
    testData->hasContextMenuItems = true;
    
    // Store the menu handle
    // Uses wil::unique_any_t for RAII cleanup
    m_curatedMenu.swap(hMenu);
    
    hMenu = m_curatedMenu.get();
}

Menu ID Assignment:

  • Range starts at `32000` (0x7D00)
  • Upper limit is `32255` (0x7DFF) - checked during insertion
  • Each menu item gets sequential ID via `_InterlockedExchangeAdd`
  • IDs used to map back to VerbInfo structures for command routing

#### Phase 4: Telemetry Setup

// Create selection test data
winrt::com_ptr<TipTestData<ContextMenuSelectionTest>> selectionTest;
selectionTest = tip_test::ensure_data();

// Start timing
selectionTest->timestamp.start();

// Store in member variable
m_contextMenuSelectionTest = selectionTest;

// Record context flags
selectionTest->locationContextFlags = m_locationContextFlags;

Telemetry Captured:

  • Selection start time
  • Location context flags
  • User interactions with menu
  • Final selection or dismissal
  • Performance metrics

#### Phase 5: XAML Menu Creation

This is the most complex phase, creating the modern XAML UI:

if (m_spotlightEnabled)
{
    // 1. Get the context menu extension interface
    IFileExplorerContextMenuExtension2* pExtension = nullptr;
    TryGetContextMenuExtension2(&pExtension);
    
    // 2. Convert HMENU to XAML MenuItem collection
    IIterable<MenuItem> menuItems;
    CreateMenuItems(hMenu, &menuItems);
    
    // 3. Create XAML menu flyout
    IInspectable menuUIElement;
    pExtension->CreateMicrosoftUIXamlControlsPrimitivesMenu(
        menuItems,
        &menuUIElement
    );
    
    // 4. Cast to FlyoutBase
    FlyoutBase flyout = menuUIElement.as<FlyoutBase>();
    m_xamlFlyout = flyout;
    
    // 5. Query for CommandBarFlyout interface (optional)
    ICommandBarFlyout* pCommandBarFlyout = nullptr;
    if (m_xamlFlyout)
    {
        m_xamlFlyout->QueryInterface(
            IID_ICommandBarFlyout,
            &pCommandBarFlyout
        );
    }
    
    // 6. Register "Show more options" handler
    RegisterTappedOnShowMoreOptions(pCommandBarFlyout);
    
    // 7. Update state
    m_flyoutState = FlyoutState::ShowingXaml; // = 3
    
    // 8. Register Closed event
    auto weakThis = get_weak();
    
    event_token closedToken = m_xamlFlyout.Closed(
        [weakThis](auto sender, auto args) 
        {
            if (auto strong = weakThis.get())
            {
                strong->OnFlyoutClosed();
            }
        }
    );
    m_flyoutClosedRevoker = closedToken;
    
    // 9. Register Opened event
    event_token openedToken = m_xamlFlyout.Opened(
        [weakThis](auto sender, auto args)
        {
            if (auto strong = weakThis.get())
            {
                strong->OnFlyoutOpened();
            }
        }
    );
    m_flyoutOpenedRevoker = openedToken;
    
    // 10. Get strong reference for callback
    winrt::com_ptr<ContextMenuPresenter> strong;
    get_strong(&strong);
    
    // 11. Record telemetry
    CuratedContextMenu_ShowMenu();
    m_contextMenuCreationTest = tipTest;
    
    // 12. Show the flyout
    try
    {
        ContextMenuHost::ShowXamlFlyout(
            m_contextMenuHost,        // Host control
            m_xamlFlyout,             // Flyout to show
            m_parentWindow,           // Parent HWND
            m_invokePoint             // Screen coordinates
        );
    }
    catch (...)
    {
        // Log exception but don't crash
        wil::Log_CaughtException();
        
        // Update telemetry
        auto selTest = tip_test::ensure_data(m_contextMenuSelectionTest);
        // ... record exception ...
        
        // Complete test and cancel
        tip_test::complete(m_contextMenuSelectionTest);
        CancelCurrentFlyout(CancelReason::Exception);
    }
}

Event Handler Pattern:

  • Uses `weak_ptr` to avoid circular references
  • Lambda captures weak pointer
  • Checks if object still exists before calling methods
  • Event tokens stored in member variables for cleanup

Error Recovery:

  • ShowXamlFlyout exceptions are caught
  • Telemetry updated with error information
  • Flyout is cancelled gracefully
  • No crash or hang - degrades gracefully

State Management

FlyoutState Enum:

enum FlyoutState
{
    Idle = 0,
    Creating = 1,
    WaitingForAsync = 2,
    ShowingXaml = 3,
    ShowingWin32 = 4,
    Dismissed = 5
};

State Transitions in DoContextMenuHelper:

Idle (0)
   [TransitionFlyoutState called]
Creating (1)
   [Menu created]
ShowingXaml (3)
   [User interacts/dismisses]
Dismissed (5)

Error Handling Strategy

The function has 3 levels of exception handling:

Level 1: ShowSpotlightControl Exceptions

try {
    ShowSpotlightControl(tipTest);
    return;
}
catch (...) {
    Log_CaughtException();
    testData->spotlightException = wil::ResultFromCaughtException();
    // Continue to standard menu
}

Level 2: ShowXamlFlyout Exceptions

try {
    ContextMenuHost::ShowXamlFlyout(...);
}
catch (...) {
    Log_CaughtException();
    // Record in telemetry
    tip_test::complete(m_contextMenuSelectionTest);
    CancelCurrentFlyout(CancelReason::Exception);
}

Level 3: Outer Exception Handler

  • Catches any unhandled exceptions
  • Ensures cleanup of resources
  • Prevents crashes during menu display

Performance Considerations

Menu ID Counter:

  • Uses `_InterlockedExchange` and `_InterlockedExchangeAdd`
  • Thread-safe atomic operations
  • Prevents ID collisions in multi-threaded scenarios

Reference Counting:

  • Weak pointers prevent circular references
  • Strong pointers only obtained when needed
  • Event handler lifetime managed via event_token revokers

Resource Management:

  • RAII wrappers (`wil::unique_any_t`) for HMENU
  • Automatic cleanup on exception or early return
  • Event tokens stored for proper unregistration

Integration Points

Called By:

  • Public interface methods (e.g., `IContextMenuPresenter::Show`)
  • Window message handlers
  • Shell hook callbacks

Calls To:

  • `TryCreateMiniMenuFromClassic` - Menu filtering and creation
  • `CreateMenuItems` - HMENU to XAML conversion
  • `ContextMenuHost::ShowXamlFlyout` - Display management
  • `ShowSpotlightControl` - Special Spotlight UI
  • Various telemetry functions

---

TryCreateMiniMenuFromClassic Function

Function Signature

HMENU* ContextMenuPresenter::TryCreateMiniMenuFromClassic(
    ContextMenuPresenter* this,
    HMENU* phMenu,    // [out] Receives the created popup menu
    HMENU hMenu       // [in]  Source classic menu to filter
)

Location

Address: 0x180031818

Size: 0x128 bytes (296 bytes)

Purpose

Creates a "mini menu" (curated context menu) from a classic Win32 context menu by filtering, copying, and enhancing menu items.

Execution Flow

TryCreateMiniMenuFromClassic
    
     FilterClassicMenu         // Filter and copy menu items
       
        CreatePopupMenu       // Create new menu
        GetCanonicalVerbsAndIndices  // Map verbs to indices
        Loop through MenuItem collection
           Check if item is separator
           Check if canonical verb exists
           GetMenuItemInfo   // Get item properties
           CopyMenuItem      // Copy to new menu
        Return filtered menu
    
     GetMenuDefaultItem         // Find default item in source
    
     Copy default item if needed
    
     InsertAppExtensionsIntoMiniMenu  // Add app extensions
       
        GetAssociationElements // Get file associations
        GetProgIdsFromAssociationElements
        ShouldAddCloudProviderVerbs
       
        AddCloudProviderVerbs  // Add cloud provider items
       
        Loop through ProgIDs
           GetExtensions     // Get extensions for ProgID
           Loop through extensions
              Build app extension map
              GetVerbsForApp
           InsertAppExtensionIntoMiniMenu
       
        Process featured/cloud provider extensions
    
     Insert separator
    
     _SHPrettyMenu             // Apply shell menu styling

Pseudo-Code Implementation

HMENU* TryCreateMiniMenuFromClassic(HMENU* phMenu, HMENU hMenu)
{
    *phMenu = NULL;
    
    // Step 1: Filter the classic menu
    FilterClassicMenu(this, phMenu, hMenu);
    
    if (*phMenu)
    {
        // Step 2: Copy default menu item if it exists
        UINT defaultIndex = GetMenuDefaultItem(hMenu, TRUE, 0);
        UINT newDefaultIndex = GetMenuDefaultItem(*phMenu, TRUE, 0);
        
        if (defaultIndex != -1 && newDefaultIndex == -1)
        {
            CopyMenuItem(this, hMenu, defaultIndex, *phMenu, 0, NULL);
        }
        
        // Step 3: Insert app extensions
        if (InsertAppExtensionsIntoMiniMenu(this, *phMenu))
        {
            // Insert separator before extensions
            MENUITEMINFOW mi = {0};
            mi.cbSize = 80;
            mi.fMask = MIIM_FTYPE | MIIM_STATE;
            mi.fType = MFT_SEPARATOR;
            
            InsertMenuItemW(*phMenu, 0x7C30, FALSE, &mi);
        }
        
        // Step 4: Apply shell menu styling
        _SHPrettyMenu(*phMenu);
    }
    
    return phMenu;
}

---

Menu Item Sources

The context menu items come from multiple sources, loaded and merged in a specific order:

1. Classic Context Menu Items (IContextMenu)

Source: Legacy shell extensions implementing IContextMenu interface

Loading Process:

  • Queries the classic context menu via `GetMenuItemInfoW`
  • Extracts menu item properties (text, icon, state, ID)
  • Maps canonical verb names to menu item indices
  • Filters based on verb configuration

Key Functions:

  • `FilterClassicMenu` (0x180053b3e)
  • `GetCanonicalVerbsAndIndices` (0x1800107e5)
  • `CreateMenuItems` (0x180011bbf)

2. App Extensions (Modern UWP/AppX)

Source: Windows::Internal::FileExplorerAppExtension API

Loading Process:

1. Get file associations for selected items via GetAssociationElements

2. Extract ProgIDs from association elements

3. Query app extensions for each ProgID using GetExtensions

4. Build app extension map with verb information

5. Asynchronously load menu items for each extension

Key Functions:

  • `InsertAppExtensionsIntoMiniMenu` (0x180031f7a)
  • `InsertAppExtensionIntoMiniMenu` (0x18000e744)
  • `LoadMenuItemAsync` (0x180059fea)
  • `LoadGroupMenuItemForAppAsync` (0x180055eb6)

Extension Types:

  • File type handlers
  • Cloud storage providers
  • Share targets
  • Quick actions

3. Cloud Provider Verbs

Source: Cloud storage provider extensions

Loading Process:

  • Checks if cloud provider verbs should be added via `ShouldAddCloudProviderVerbs`
  • Calls `AddCloudProviderVerbs` (0x1800152f9) to enumerate cloud operations
  • Creates verb elements for cloud-specific actions
  • Merges with app extension map

Special Handling:

  • Featured cloud provider gets priority placement
  • Can create grouped submenu for multiple cloud operations

4. Command Store Commands

Source: IExplorerCommand-based commands from Command Store

Loading Process:

  • Matches canonical verb names against VerbConfig entries
  • Queries `GetCommandStoreCommand` (0x1800162e1)
  • Validates command state via `IExplorerCommand::GetState`
  • Creates menu item from command properties

Key Functions:

  • `TryCreateMenuItemFromVerbConfig` (0x18005fc7e)
  • `GetCommandStoreCommand` (0x1800162e1)
  • `TryGetMenuItemInfoFromExplorerCommand` (0x18005fa51)

5. Canonical Verbs

Canonical Verbs Checked:

These are standard file operations with well-known verb names:

static const VerbConfig s_VerbConfigs[] = {
    { L"open", IDC_OPEN, IDS_OPEN, ... },
    { L"edit", IDC_EDIT, IDS_EDIT, ... },
    { L"print", IDC_PRINT, IDS_PRINT, ... },
    { L"opencontaining", IDC_OPENCONTAINING, IDS_OPENCONTAINING, ... },
    { L"delete", IDC_DELETE, IDS_DELETE, ... },
    { L"rename", IDC_RENAME, IDS_RENAME, ... },
    { L"properties", IDC_PROPERTIES, IDS_PROPERTIES, ... },
    { L"cut", IDC_CUT, IDS_CUT, ... },
    { L"copy", IDC_COPY, IDS_COPY, ... },
    { L"paste", IDC_PASTE, IDS_PASTE, ... },
    // ... more verbs
};

---

Detailed Function Analysis

FilterClassicMenu

Address: 0x180053b3e

Purpose: Filters a classic menu and copies allowed items to a new menu

Algorithm:

1. Create new popup menu
2. Get canonical verbs and their indices from source menu
3. For each item in the MenuItem collection:
   a. Check if item is "_separator_"  append separator
   b. Try to find canonical verb in hash map
   c. If found:
      - Get menu item info
      - Try to get override from VerbConfig
      - Copy menu item to new menu
   d. If not found:
      - Check against VerbConfig array
      - If valid, create menu item from verb config
4. Return filtered menu

Key Data Structures:

  • `unordered_map` - Maps canonical verb names to menu indices
  • `VerbConfig` array - Configuration for known verbs
  • `MenuItem` collection - XAML menu item objects

InsertAppExtensionsIntoMiniMenu

Address: 0x180031f7a

Size: 0x973 bytes (2,419 bytes)

Purpose: Inserts app extension menu items into the mini menu

Complex Algorithm:

1. Get association elements for selected items
2. Extract ProgIDs if cloud provider verbs are needed
3. Initialize data structures:
   - map<hstring, AppExtensionElement> - Extension info map
   - unordered_multimap<hstring, VerbElement> - Verb map
4. Try to add cloud provider verbs
5. For each ProgID:
   a. Get extensions via FileExplorerAppExtension API
   b. For each extension:
      - Get app info (name, icon)
      - Build AppExtensionElement entry
      - Call AddVerbsForAppExtension to populate verb map
6. Process featured cloud provider extension (if any):
   - Get verbs for the featured app
   - Call InsertAppExtensionIntoMiniMenu to insert
7. Insert separator
8. Loop through remaining extensions in map:
   - Get verbs for each app
   - Insert into mini menu
   - Check ID limit (0x7DFF)
9. Return count of inserted items

Error Handling:

  • Logs caught exceptions but continues processing
  • Checks menu ID limit to prevent overflow
  • Uses feature flags for performance optimizations

InsertAppExtensionIntoMiniMenu

Address: 0x18000e744

Purpose: Inserts a single app extension into the menu

Behavior Based on Verb Count:

Single Verb:

if (verbCount == 1)
{
    // Insert directly without submenu
    TryInsertMenuItemForAppExtension(hMenu, extension.guid, extension.displayName);
    return 1;
}

Multiple Verbs:

if (verbCount > 1)
{
    HMENU hSubMenu = CreatePopupMenu();
    
    // Create parent menu item
    MENUITEMINFOW mi = {0};
    mi.wID = InterlockedIncrement(&nextMenuId);
    mi.dwTypeData = extension.name;
    mi.hSubMenu = hSubMenu;
    
    if (extension.hasIcon)
    {
        // Load icon asynchronously
        LoadGroupMenuItemForAppAsync(...);
    }
    else
    {
        // Insert verbs directly as submenu items
        for (auto& verb : extension.verbs)
        {
            TryInsertMenuItemForAppExtension(hSubMenu, verb.guid, verb.name);
        }
        
        SetMenuItemIcon(extension.name, &mi, verbInfo);
    }
    
    InsertMenuItemW(hMenu, 0x7C30, FALSE, &mi);
}

CopyMenuItem

Address: 0x18000eaba

Purpose: Copies a menu item from one menu to another with icon support

Process:

1. Get menu item info via GetMenuItemInfoW
   - Flags: MIIM_STRING | MIIM_CHECKMARKS | MIIM_SUBMENU | ...
2. Insert menu item into destination menu
3. If icon stream is provided:
   - Call SetHMenuItemIconAsync to load icon asynchronously
   - Add async operation to tracking vector
4. Return menu item ID

Async Pattern:

  • Icons are loaded asynchronously to avoid blocking UI
  • Uses `IAsyncAction` from WinRT
  • Operations tracked in vector for cancellation

GetCanonicalVerbsAndIndices

Address: 0x1800107e5

Purpose: Builds a map of canonical verb names to menu item indices

Algorithm:

void GetCanonicalVerbsAndIndices(HMENU hMenu, 
    unordered_map<wstring, int>& verbMap)
{
    verbMap.clear();
    
    int menuItemCount = GetMenuItemCount(hMenu);
    int validIndex = 0;
    
    for (int i = 0; i < menuItemCount; i++)
    {
        MENUITEMINFOW mi = {0};
        mi.cbSize = sizeof(mi);
        mi.fMask = MIIM_FTYPE | MIIM_STATE;
        GetMenuItemInfoW(hMenu, i, TRUE, &mi);
        
        // Skip separators
        if ((mi.fType & MFT_SEPARATOR) == 0)
        {
            // Get canonical verb for this menu item
            wstring verb;
            if (TryGetCanonicalVerb(mi.wID, &verb) && !verb.empty())
            {
                verbMap[verb] = validIndex;
            }
            validIndex++;
        }
    }
}

Where canonical verbs are stored:

  • Transient map (per-filter pass): `FilterClassicMenu` builds a local `unordered_map` (via `GetCanonicalVerbsAndIndices`) to map canonical verb → classic menu index. This is a temporary map used only during filtering.
  • Persistent mapping (per presenter instance): When a menu item is copied into the curated menu, `FilterClassicMenu` inserts `menuId → canonical verb` into a member hash map inside `ContextMenuPresenter` (seen as `std::_Hash<...>::_Try_emplace` on `(char*)this + 440` in the decompile). This is used later for command invocation and telemetry.

---

Data Structures

AppExtensionElement

struct AppExtensionElement
{
    winrt::hstring appName;              // Display name of the app
    winrt::hstring appId;                // App package ID
    IRandomAccessStreamReference icon;   // Icon stream reference
    GUID extensionGuid;                  // Extension GUID
};

VerbElement

struct VerbElement
{
    winrt::hstring verbName;             // Verb name (e.g., "Open with")
    winrt::hstring targetName;           // Target display name
    GUID commandGuid;                    // Command GUID
    IRandomAccessStreamReference icon;   // Icon stream
};

VerbInfo

struct VerbInfo
{
    UINT menuId;                         // Menu item ID
    winrt::hstring verbName;             // Canonical verb name
    winrt::hstring displayName;          // Display string
    IExplorerCommand* pCommand;          // Command object
    IRandomAccessStreamReference icon;   // Icon stream
    bool hasIcon;                        // Icon availability flag
    // ... additional fields
};

VerbConfig

struct VerbConfig
{
    const wchar_t* pszCanonicalName;     // Canonical verb name
    UINT commandId;                      // Command ID constant
    UINT stringResourceId;               // String resource ID
    function<bool(IShellItemArray*)> shouldShow; // Visibility predicate
    // ... additional configuration
};

Hash Maps Used

Canonical Verb Map:

unordered_map<wstring, int> canonicalVerbMap;
// Key: Canonical verb name (e.g., "open", "edit")
// Value: Menu item index in classic menu

App Extension Map:

map<hstring, AppExtensionElement> extensionMap;
// Key: App name/identifier
// Value: App extension information

Verb Multimap:

unordered_multimap<hstring, VerbElement> verbMap;
// Key: App identifier
// Value: Verb information (one app can have multiple verbs)

---

Async Loading Mechanism

Overview

Menu item icons and some properties are loaded asynchronously to prevent UI blocking during context menu creation.

Async Functions

LoadMenuItemAsync (0x180059fea)

  • Loads individual menu item asynchronously
  • Sets menu item properties when data arrives
  • Updates icon bitmap
  • Size: 0x57b8 bytes (22,456 bytes) - very large coroutine

LoadGroupMenuItemForAppAsync (0x180055eb6)

  • Loads grouped menu item for app with multiple verbs
  • Creates submenu structure
  • Size: 0x3504 bytes (13,572 bytes)

SetHMenuItemIconAsync

  • Asynchronously loads and sets icon for HMENU item
  • Uses `IRandomAccessStreamReference::OpenReadAsync`
  • Converts stream to bitmap and applies to menu

Coroutine Pattern

The functions use C++/WinRT coroutines with $_ResumeCoro$1 suffix:

IAsyncAction LoadMenuItemAsync(
    hstring appName,
    GUID extensionGuid,
    HMENU hMenu,
    UINT menuId)
{
    // Coroutine body
    co_await GetAppExtensionInfo(extensionGuid);
    co_await LoadIconStream();
    
    // Update menu item on UI thread
    MENUITEMINFOW mi = {0};
    mi.cbSize = sizeof(mi);
    mi.fMask = MIIM_STRING | MIIM_BITMAP;
    mi.dwTypeData = displayName.c_str();
    mi.hbmpItem = iconBitmap;
    
    SetMenuItemInfoW(hMenu, menuId, FALSE, &mi);
}

Async Operation Tracking

// Vector of active async operations
vector<IAsyncAction> m_asyncOperations;

// Add operation
m_asyncOperations.push_back(LoadMenuItemAsync(...));

// Operations can be cancelled when menu is dismissed

---

Key Findings

1. Two-Tier Entry Point Architecture

The context menu system uses two distinct entry points:

DoContextMenuHelper (0x1800a9f8b) - Main orchestration function

  • Handles 99% of context menu scenarios
  • Coordinates telemetry, menu creation, and UI display
  • 1,656 bytes of compiled code - highly complex
  • Implements graceful fallbacks on errors

ShowSpotlightContextMenu (0x1800b21d0) - Spotlight-specific path

  • Completely separate code path for Desktop Spotlight
  • Loads XAML extension dynamically
  • Only activated with specific feature flag
  • Bypasses standard filtering entirely

This dual-path architecture provides:

  • Isolation - Spotlight features don't impact standard menus
  • Flexibility - Can evolve independently
  • Safety - Failures in Spotlight fall back to standard menu

2. Sophisticated State Machine

DoContextMenuHelper implements a 6-state flyout state machine:

Idle (0)  Creating (1)  WaitingForAsync (2)  ShowingXaml (3)  Dismissed (5)
                                                   
             ShowingWin32 (4)

State Transitions:

  • `Idle` → `Creating`: When DoContextMenuHelper starts
  • `Creating` → `ShowingXaml`: After XAML flyout creation succeeds
  • `Creating` → `ShowingWin32`: Fallback for non-XAML scenarios
  • `Creating` → `WaitingForAsync`: When waiting for async operations
  • `Any State` → `Dismissed`: User closes menu or error occurs

Purpose:

  • Prevents race conditions during async menu creation
  • Ensures proper cleanup on early dismissal
  • Enables telemetry tracking of menu lifecycle
  • Guards against re-entrant calls

3. Multi-Source Menu Construction

The context menu is built from a union of multiple sources:

  • Classic extensions provide compatibility with legacy handlers
  • App extensions enable modern UWP app integration
  • Cloud providers add cloud-specific operations
  • Command store provides consistent command implementation

2. Filtering and Curation

Not all classic menu items appear in the mini menu:

  • Items must have canonical verb names OR appear in VerbConfig
  • Duplicate entries are removed
  • Separators are preserved but not counted
  • Items can be overridden by Command Store entries

3. Asynchronous Icon Loading

Icons are loaded asynchronously to improve performance:

  • Menu appears immediately with text
  • Icons populate as they load
  • Prevents blocking on slow icon providers
  • Operations tracked for cancellation

4. Extensibility Architecture

The system is designed for extensibility:

  • New verb configs can be added via VerbConfig array
  • App extensions are discovered dynamically via AppExtension API
  • Cloud providers can register as featured provider
  • Command Store provides command definition separation

5. Menu ID Management

Menu IDs are carefully managed:

  • Each ContextMenuPresenter instance maintains a counter
  • IDs are assigned sequentially starting from base value
  • Maximum ID is 0x7DFF (checked to prevent overflow)
  • IDs map back to VerbInfo structures for invocation

6. Telemetry and Diagnostics

The class includes telemetry support:

  • `CuratedContextMenu_AppInfo` events log app extension usage
  • Menu creation events are logged
  • Error conditions are logged but don't block menu creation
  • TIP (Test in Production) framework integration

7. Feature Flags

Multiple Windows feature flags control behavior:

  • `Feature_Servicing_FEStateRepoVerbsCacheReducedLocking`
  • `Feature_53343352` (for ExplorerCommand info retrieval method)
  • `Feature_ContextMenuEnumVerbConfigSubCommands`

These allow A/B testing and gradual rollout of changes.

8. High Complexity Functions

Some functions are exceptionally large:

  • `CreateMenuItems`: 3,637 bytes of compiled code
  • `InsertAppExtensionsIntoMiniMenu`: 2,419 bytes
  • `LoadMenuItemAsync`: 22,456 bytes (coroutine state machine)
  • `FilterClassicMenu`: 1,194 bytes

This suggests complex state management and error handling.

9. Exception Handling

The code uses Windows Internal Library (WIL) for exception handling:

  • Exceptions are caught and logged but don't crash the menu
  • `wil::details::in1diag3::Log_CaughtException` logs errors
  • Failed menu items are skipped rather than failing entire menu

10. Shell Integration

Deep integration with Windows Shell:

  • Uses `IShellItemArray` for file selection context
  • Calls `_SHPrettyMenu` for shell-standard menu styling
  • Integrates with shell associations system
  • Supports `IContextMenu` and `IExplorerCommand` interfaces

13. Reference Counting and Lifetime Management

Weak Pointer Pattern:

auto weakThis = get_weak();
m_xamlFlyout.Closed([weakThis](auto sender, auto args) {
    if (auto strong = weakThis.get())
        strong->OnFlyoutClosed();
});

Purpose:

  • Prevents circular references between flyout and presenter
  • Event handlers don't keep presenter alive
  • Safe cleanup when menu dismissed
  • Avoids memory leaks

Event Token Management:

  • `m_flyoutClosedRevoker` stores event token
  • Automatically unregisters on destruction
  • RAII pattern ensures cleanup
  • Even if exception occurs

---

Conclusions

The context menu system in Windows File Explorer is a multi-layered architecture that seamlessly bridges classic Win32 components with modern XAML-based UI. The analysis reveals several key design patterns:

Architectural Layers

Layer 1: Shell View (CDefView)

  • Entry point from user interaction
  • Validates window state and context
  • Creates classic HMENU via IContextMenu::QueryContextMenu
  • Decides between curated and classic menu modes
  • Manages shell extension integration

Layer 2: Bridge Layer (DoCuratedContextMenu)

  • Obtains IContextMenuPresenter via service query
  • Marshals parameters from Win32 to presenter interface
  • Handles exception recovery and fallback
  • Maintains telemetry throughout the pipeline

Layer 3: Presenter Layer (ContextMenuPresenter)

  • Filters and curates classic menu items
  • Augments with modern app extensions
  • Converts HMENU to XAML MenuFlyout
  • Manages asynchronous operations
  • Handles Desktop Spotlight special cases

Key Design Principles

The implementation demonstrates several sophisticated design principles:

1. Graceful Degradation

- Multiple fallback paths ensure menu always appears

- Classic menu available if curated fails

- Exception handling at every layer

- Telemetry tracks all failure points

2. Performance Optimization

- Asynchronous icon loading prevents UI blocking

- Menu appears immediately, populates progressively

- Parallel operations where possible

- CFG-protected indirect calls for security

3. Backward Compatibility

- Full support for IContextMenu, IContextMenu2, IContextMenu3

- Classic menu items preserved and filtered

- Shell extensions continue to work

- Command ID mapping maintains routing

4. Forward Extensibility

- App extension framework for modern apps

- Cloud provider verb integration

- Feature flags enable gradual rollout

- XAML-based UI allows rich experiences

5. Observability

- Comprehensive telemetry (TIP framework)

- ETW events for performance analysis

- Detailed error logging

- Feature usage tracking

Critical Functions

CDefView::_DoContextMenuPopup (3,595 bytes)

  • Largest, most complex function in the pipeline
  • Orchestrates entire menu creation process
  • Handles Desktop Spotlight special cases
  • Creates and populates classic HMENU
  • Decides curated vs classic routing

ContextMenuPresenter::DoContextMenuHelper (1,656 bytes)

  • Main presenter orchestration
  • Implements state machine for flyout lifecycle
  • Converts HMENU to XAML flyout
  • Manages async operations
  • Handles multiple entry points (standard + Spotlight)

TryCreateMiniMenuFromClassic (296 bytes)

  • Compact but critical filtering function
  • Applies verb configurations
  • Integrates app extensions
  • Maintains separation of concerns

Menu Item Sources

The final context menu is a curated union from multiple sources:

1. Classic Shell Extensions (IContextMenu)

- Legacy handlers registered in registry

- Filtered by canonical verb configuration

- Maintains compatibility with existing software

2. App Extensions (Windows.Internal.FileExplorerAppExtension)

- Modern UWP/AppX integrations

- Dynamically discovered via AppExtension API

- Supports async loading and icons

3. Cloud Provider Verbs

- Special handling for cloud storage providers

- Featured provider gets priority placement

- Supports grouped submenus

4. Command Store Commands (IExplorerCommand)

- Provides consistent command implementations

- Can override classic menu items

- Supports state-based visibility

5. Built-in Shell Commands

- DefView's own menu items (Open, etc.)

- Merged via Shell_MergeMenus

- Applied via _SHPrettyMenu for consistent styling

Technology Integration

COM/WinRT Bridge:

  • Seamless interop between Win32 COM and WinRT
  • ComPtr/winrt::com_ptr for RAII lifetime management
  • CFG (Control Flow Guard) for security
  • Exception translation between layers

Telemetry Systems:

  • TIP (Test in Production) framework
  • ETW (Event Tracing for Windows)
  • Feature flag usage tracking
  • Performance metrics throughout

Feature Management:

  • WIL (Windows Implementation Library) feature flags
  • A/B testing support via FeatureImpl
  • Usage reporting for gradual rollout
  • Runtime enable/disable without rebuilds

Future Extensibility

The architecture enables several future enhancements:

  • Richer XAML UI: Flyout can support complex controls
  • Dynamic Filtering: Context-aware verb visibility
  • Cloud Integration: Enhanced cloud provider experiences
  • AI/ML: Predictive verb ordering and suggestions
  • Async Commands: Long-running operations with progress

This architecture allows Windows to present a curated, modern context menu experience while maintaining compatibility with decades of existing shell extensions and providing a clear path forward for modern app integration.

---

Appendix: Function Address Reference

Function NameAddressSizePurpose
**Shell View (CDefView)**
DoContextMenuPopup0x18029f6b00x73Public COM interface entry point
_DoContextMenuPopup0x1802b32040xe0bInternal implementation - HMENU creation
DoCuratedContextMenu0x18029f72c0x337Bridge to ContextMenuPresenter
TryGetContextMenuPresenter0x1800a56a00xc7Service query for presenter interface
**ContextMenuPresenter Entry Points**
DoContextMenuHelper0x1800a9f8b0x678Main orchestration function
ShowSpotlightContextMenu0x1800b21d00x329Spotlight-specific menu
**Menu Creation**
TryCreateMiniMenuFromClassic0x1800318180x128Main entry point for mini menu creation
FilterClassicMenu0x180053b3e0x4aaFilters classic menu items
InsertAppExtensionsIntoMiniMenu0x180031f7a0x973Inserts app extensions
InsertAppExtensionIntoMiniMenu0x18000e7440x3a6Inserts single app extension
CreateMenuItems0x180011bbf0xe35Creates MenuItem collection
CopyMenuItem0x18000eaba0x186Copies menu item with icon
CopyClassicMenu0x180048e840xb1Copies entire classic menu
GetCanonicalVerbsAndIndices0x1800107e50x183Maps verbs to indices
TryInsertMenuItemForAppExtension0x18001b0a10x1adInserts single extension item
TryCreateMenuItemFromVerbConfig0x18005fc7e0x360Creates item from verb config
**Async Operations**
LoadMenuItemAsync0x180059fea0x57b8Async menu item loading
LoadGroupMenuItemForAppAsync0x180055eb60x3504Async group item loading
**Support Functions**
GetCommandStoreCommand0x1800162e10xe5Gets command from store
AddCloudProviderVerbs0x1800152f90x681Adds cloud provider verbs
UpdateXamlMenuItem0x180012e0d0x5a5Updates XAML menu item

---

Complete Flow Summary

Full Call Chain

User Right-Clicks on Item
    
    
CDefView::DoContextMenuPopup (0x18029f6b0)
     - Validate window is visible
     - Return E_UNEXPECTED if not ready
    
CDefView::_DoContextMenuPopup (0x1802b3204)
     - Initialize telemetry (ContextMenuCreationTest)
     - Check Desktop Spotlight feature flags
     - Decide: Curated vs Classic menu mode
     - CreatePopupMenu()  hMenu
     - IContextMenu::QueryContextMenu(hMenu, 0, 30977, 31487, flags)
        Shell extensions populate the classic menu
     - Merge additional items (Open menu, etc.)
     - Apply dark mode settings
     - SetContextMenuCapability()
    

 CDefView::DoCuratedContextMenu (0x18029f72c)                 
 [If curated mode selected]                                   
                                                               
  TryGetContextMenuPresenter (0x1800a56a0)                 
     IUnknown_QueryService(SID_ContextMenuPresenter)     
         IContextMenuPresenter interface                    
                                                              
  GetLocationContext(shellItems)  locationContext         
                                                              
  Set presenter flags:                                     
     If shift key: flags |= 0x8                           
     If screen reader: flags |= 0x1                       
     If Spotlight+Desktop: flags |= 0x10                  
                                                              
  Call IContextMenuPresenter::DoContextMenu                
      vtable[0x20](locationContext, this, pt, ...)         
         - Parameters: hMenu, flags, testId, pContextMenu      
         - CFG-protected indirect call                         

    
    

 DoContextMenuHelper (0x1800a9f8b)                  
                                                    
    
  1. Initialize Telemetry & State               
    
                                                   
    
  2. Check Desktop Spotlight Feature            
      If Enabled + Spotlight Context         
         ShowSpotlightContextMenu           
             RETURN (separate flow)         
      Else: Continue                         
    
                                                   
    
  3. TryCreateMiniMenuFromClassic            
     (0x180031818)                               
     
                                                    
     
  4. If menu has items:                          
      CreateMenuItems (HMENUXAML)           
      Create XAML Flyout                     
      Register Event Handlers                
      ShowXamlFlyout                         
     
 
                                                       
    Detailed Breakdown of Step 3 
                    
                    

 TryCreateMiniMenuFromClassic (0x180031818)             
                                                         
    
  A. FilterClassicMenu (0x180053b3e)                 
      Create new popup menu                       
      GetCanonicalVerbsAndIndices                 
      For each MenuItem in collection:            
         Check if canonical verb exists          
         GetMenuItemInfo from classic menu       
         Check VerbConfig overrides              
         CopyMenuItem to new menu                
      Return filtered menu                        
    
                                                        
    
  B. Check/Copy Default Menu Item                    
      GetMenuDefaultItem from source              
      GetMenuDefaultItem from filtered            
      Copy if source has one but filtered doesn't  
    
                                                        
    
  C. InsertAppExtensionsIntoMiniMenu (0x180031f7a)   
      GetAssociationElements                      
      GetProgIdsFromAssociationElements           
      ShouldAddCloudProviderVerbs?                
         AddCloudProviderVerbs                   
      For each ProgID:                            
         GetExtensions (FileExplorerAppExt)      
         Build AppExtensionElement map           
         GetVerbsForApp                          
      Process featured cloud provider             
         InsertAppExtensionIntoMiniMenu          
      For remaining extensions:                   
          InsertAppExtensionIntoMiniMenu          
              If 1 verb: Insert directly          
              If multiple: Create submenu         
                  LoadGroupMenuItemForAppAsync    
    
                                                        
    
  D. Insert Separator                                 
    
                                                        
    
  E. _SHPrettyMenu (Apply shell styling)              
    
                                                        
              [Return menu]                              

                    
                    
            Back to DoContextMenuHelper
                    
                    

 CreateMenuItems (0x180011bbf)                          
 - Converts HMENU to IIterable<MenuItem>                
 - Creates XAML MenuItem objects                        
 - Preserves structure (submenus, separators)           
 - Registers event handlers for each item               

                    
                    

 ContextMenuHost::ShowXamlFlyout                        
 - Positions flyout at cursor                           
 - Manages XAML island lifecycle                        
 - Handles input routing                                
 - Theme/DPI awareness                                  

                    
                    
            Menu Displayed to User

Data Flow

Classic IContextMenu
    
     Shell Extensions populate HMENU
        Classic menu items (Win32)
    
    
FilterClassicMenu
    
     Canonical verb filtering
     VerbConfig matching
     Selected items copied
    
    
Filtered HMENU
    
    
InsertAppExtensionsIntoMiniMenu
    
     File associations  ProgIDs
     ProgIDs  App Extensions
     App Extensions  Verb Elements
     Verb Elements  Menu Items
    
    
Augmented HMENU (Curated Menu)
    
    
CreateMenuItems
    
     HMENU  MenuItem collection
     Text, icons, state preserved
     Event handlers attached
    
    
IIterable<MenuItem>
    
    
CreateMicrosoftUIXamlControlsPrimitivesMenu
    
     CommandBarFlyout (XAML)
    
    
ShowXamlFlyout
    
     Displayed to user

Timing and Synchronization

Synchronous Operations:

  • DoContextMenuHelper initialization
  • TryCreateMiniMenuFromClassic
  • FilterClassicMenu
  • GetCanonicalVerbsAndIndices
  • Menu handle operations (Win32 APIs)

Asynchronous Operations:

  • LoadMenuItemAsync (for app extension icons)
  • LoadGroupMenuItemForAppAsync (for grouped items)
  • SetHMenuItemIconAsync (for icon loading)

Critical Timing:

T=0ms    : User right-click
T=0-20ms : DoContextMenuHelper starts, telemetry init
T=20-50ms: TryCreateMiniMenuFromClassic filters menu
T=50-100ms: InsertAppExtensionsIntoMiniMenu queries extensions
T=100-150ms: CreateMenuItems converts to XAML
T=150-200ms: ShowXamlFlyout displays menu
T=200ms+ : Async icon loads complete (menu already visible)

Icons Load Asynchronously:

  • Menu appears with text immediately
  • Icons populate as they become available
  • No blocking on slow icon providers
  • Background threads handle bitmap decoding

---

CDefView::_CreateSelectionContextMenu

Address: 0x1801e1a3c

Size: 0xa4 bytes (164 bytes)

Purpose: Wrapper function for querying context menus for selected items

This is a compact wrapper function that bridges the legacy Win32 IContextMenu mechanism with the modern curated menu system for *selected items* specifically.

Function Signature

HRESULT CDefView::_CreateSelectionContextMenu(
    CDefView* this,
    int flags,                      // 0 or 0x80000001
    const GUID* riid,               // Interface ID (IID_IContextMenu)
    void** ppv                      // [out] Returned interface
)

Location in Call Hierarchy

This function is called from multiple contexts:

User Right-Click on Selected Items
    
     GetItemObject(this, 1, IID_IContextMenu, &ppv)
        _CreateSelectionContextMenu(this, 0, IID_IContextMenu, &ppv)
    
     DoSelectionContextMenu(pt, mode)
        _CreateSelectionContextMenu(this, 0, IID_IContextMenu_0, &pContextMenu)
           
            SetWaitCursor()
            _DoContextMenuPopup(pContextMenu, 0x90, pt, mode)
               [Displays menu with classic or curated path]
            RestoreCursor()
    
     _OnInitMenuPopup / _ExplorerCommand
         [Other selection-based operations]

Decompiled Implementation

HRESULT __fastcall CDefView::_CreateSelectionContextMenu(
    CDefView *this,
    int a2,                         // 0 or 0x80000001
    const struct _GUID *a3,         // IID
    void **ppv)
{
    int Items;
    struct IContextMenu *pContextMenu;

    *ppv = 0;                       // Clear output
    pContextMenu = 0;

    // a2 determines which items to get:
    // If a2 != 0: use 0x80000001 (SVGIO_FLAG_VIEWORDER)
    // If a2 == 0: use 1 (SVGIO_SELECTION)
    Items = CDefView::_GetItems(
        this,
        a2 != 0 ? 0x80000001 : 1,  // Selection type
        1,                          // Get as single object
        &IID_IContextMenu_0,       // Request IContextMenu interface
        &pContextMenu              // [out] Menu object
    );

    if (Items >= 0)  // Success
    {
        // Try to modify the context menu
        // (e.g., add shell folder view extensions)
        Items = CDefView::_TryModifyMenu(
            this,
            pContextMenu,
            0,                      // a3: unused
            a3,                     // Request interface (IID_IContextMenu)
            ppv                     // [out] Result
        );

        // Release the context menu object
        (pContextMenu->lpVtbl->Release)(pContextMenu);
    }

    return Items;  // Return HRESULT
}

Assembly Analysis

The assembly reveals important parameter manipulation:

; Parameter handling
1801e1a69  neg     edx                ; Negate a2 (flags parameter)
1801e1a6b  sbb     edx, edx           ; SBB: if borrow, edx = -1, else 0
1801e1a7a  and     edx, 80000000h     ; Mask to 0x80000000
1801e1a87  add     edx, r8d           ; Add 1 (r8d contains 1)

This implements the conditional logic:

  • If `a2 == 0`: EDX becomes `0 + 1 = 1` (SVGIO_SELECTION)
  • If `a2 != 0`: EDX becomes `0x80000000 + 1 = 0x80000001` (SVGIO_FLAG_VIEWORDER)

Parameter Meanings:

ParameterValueMeaning
`SVGIO_SELECTION`1Get currently selected items
`SVGIO_FLAG_VIEWORDER`0x80000000Selection in view order (not used here with OR)
`SVGIO_ALLASSTRING`0x80000001Combined: get selection, return as string

Called Functions

#### CDefView::_GetItems (Core Selection Logic)

HRESULT CDefView::_GetItems(
    unsigned int svgio,             // Selection type
    int fMultiple,                  // 1 = single object
    const GUID& riid,              // Interface requested
    void** ppv)                    // [out] Result

Behavior:

  • `svgio = 1`: Gets currently selected items in the folder view
  • `svgio = 0x80000001`: Gets items in view order (used for certain contexts)
  • Returns as single object: Aggregates items into one IContextMenu if multiple selected
  • If only 1 item selected: Direct IContextMenu from that item
  • If multiple items selected: Composite menu from all selections

Result:

  • Returns `IContextMenu` interface for the selected item(s)
  • This menu is not yet populated - it's just the interface
  • Menu population happens later via `IContextMenu::QueryContextMenu`

#### CDefView::_TryModifyMenu (Extension Support)

HRESULT CDefView::_TryModifyMenu(
    IContextMenu* pContextMenu,
    int a3,                         // Unused (0)
    const GUID* riid,              // Requested interface
    void** ppv)                    // [out] Result

Purpose: Apply shell folder view context menu extensions via IShellFolderViewCM

Algorithm:

HRESULT hr = IUnknown_QueryService(
    m_pShellBrowser,
    &SID_SShellFolderViewCM,      // Service ID
    &GUID_SShellFolderViewCM,     // Interface ID
    &pFolderViewCM                // [out] Extension interface
);

if (FAILED(hr))
    // Fall back to direct QueryInterface
    return pContextMenu->QueryInterface(riid, ppv);

// Get single item for context
IDataObject* pDataObj = NULL;
if (a3 == 0)  // Selection context (not root)
{
    CDefView::GetItemObject(
        this,
        1,                    // Single item
        &IID_IDataObject,    // Request data object
        &pDataObj            // [out] Data object
    );
}

// Initialize the extension
IShellExtInit_Initialize(
    pFolderViewCM,
    m_pidlRoot,         // Current folder pidl
    pDataObj,           // Selected item data
    NULL                // HKEY reserved
);

// Get modified menu
hr = pFolderViewCM->GetContextMenu(
    pContextMenu,       // Original menu
    &pModifiedMenu      // [out] Modified menu
);

if (SUCCEEDED(hr))
{
    // Query for requested interface
    return pModifiedMenu->QueryInterface(riid, ppv);
}

Extension Interfaces:

  • `IID_SShellFolderViewCM`: Service ID for folder view context menu extensions
  • `GUID_SShellFolderViewCM`: Interface GUID
  • Extensions can modify menu items before display

Call Flow in DoSelectionContextMenu

This is where _CreateSelectionContextMenu is primarily used:

HRESULT CDefView::DoSelectionContextMenu(
    POINT* ppt,
    FileExplorerContextMenu::Mode mode)
{
    // Auto wait cursor during menu creation
    CAutoWaitCursor waitCursor;

    // Get context menu for selected items
    IContextMenu* pContextMenu = NULL;
    CDefView::_CreateSelectionContextMenu(
        this,
        0,                      // Get selected items
        &IID_IContextMenu_0,
        &pContextMenu
    );

    if (pContextMenu)
    {
        // Show the context menu
        // This will either use:
        // - Curated mode: DoCuratedContextMenu() → XAML flyout
        // - Classic mode: DoClassicMenu() → TrackPopupMenu()
        HRESULT hr = CDefView::_DoContextMenuPopup(
            pContextMenu,
            0x90,               // Flags: DROPEFFECT_COPY | other
            *ppt,               // Cursor position
            mode                // 0 = auto, 1 = force classic
        );

        // Release menu object
        pContextMenu->Release();
        
        return hr;
    }

    return E_FAIL;
}

Key Observations:

1. Wait Cursor: Shows busy cursor while getting items

2. Single Selection vs Multiple: Function handles both transparently

3. Mode Selection: Caller decides if showing curated or classic menu

4. Flag 0x90: DROPEFFECT_COPY | 0x10 indicates selection context

5. Exception Safety: RAII cursor cleanup

Parameter Decoding

The cryptic a2 parameter uses sign extension and masking:

// Visual C++ compiler optimization for conditional:
if (a2 != 0)
    flags = 0x80000001;  // SVGIO_FLAG_VIEWORDER
else
    flags = 1;           // SVGIO_SELECTION

// Compiled as:
neg     edx              // EDX = -flags (two's complement)
sbb     edx, edx         // If borrow (sign bit set): EDX = -1, else EDX = 0
and     edx, 0x80000000  // Mask: EDX = 0 or 0x80000000
add     edx, 1           // Add 1: result is 1 or 0x80000001

Error Handling

The function handles failures gracefully:

// _GetItems returned error
if (Items < 0)
    return Items;  // Propagate error

// _TryModifyMenu handled error internally
// (returns default if extension unavailable)

Possible return values:

  • `S_OK` (0): Success - menu created
  • `E_NOINTERFACE`: Interface not available
  • `E_FAIL`: General failure
  • Other COM errors from shell extension host

Security Considerations

CFG (Control Flow Guard) Protection:

  • Vtable calls through `pContextMenu->lpVtbl->Release` are CFG-protected
  • Ensures only legitimate virtual functions called
  • Prevents return-oriented programming attacks

Data Validation:

  • Input pointers validated implicitly by COM
  • Output pointer (`ppv`) cleared before use
  • Exception safety via RAII cleanup

Usage Patterns

Pattern 1: Simple Menu Query

void* pMenu;
_CreateSelectionContextMenu(this, 0, &IID_IContextMenu, &pMenu);
// Use pMenu...
((IContextMenu*)pMenu)->Release();

Pattern 2: Bulk Operations

// Get menu for all selected items
_CreateSelectionContextMenu(this, 0x80000001, &IID_IContextMenu, &pMenu);
// Perform operation on all items simultaneously

Pattern 3: Interface Discovery

void* pInterface;
GUID riid = { /* some interface */ };
_CreateSelectionContextMenu(this, 0, &riid, &pInterface);
// pInterface points to requested COM interface for selection

Integration with Curated Menu System

The flow when selecting items:

1. User right-clicks  OnContextMenu event
2. CDefView detects SVGIO_SELECTION context
3. Calls _CreateSelectionContextMenu()
4. Gets IContextMenu for selected item(s)
5. Passes to DoSelectionContextMenu()
6. Checks if curated menu should be shown
7. DoCuratedContextMenu()  ContextMenuPresenter::DoContextMenu()
8. TryCreateMiniMenuFromClassic() filters items
9. InsertAppExtensionsIntoMiniMenu() adds modern verbs
10. XAML flyout created and displayed

Integration Points:

  • Provides classic menu for curating
  • Maintains backward compatibility with IContextMenu
  • Supports shell extensions via IShellFolderViewCM
  • Telemetry tracking via telemetry test framework

---

IContextMenu Creation Based on Object Type

Overview

When users interact with the file system, DefView needs to determine which IContextMenu to create based on the context type: is the user clicking on a *selected item*, the *background (empty space)*, or something else? This section analyzes the type-based routing system that dispatches menu creation.

GetItemObject - Main Type Dispatcher

Address: 0x180100120

Size: 0x30f bytes (783 bytes)

Purpose: Central dispatcher that routes IContextMenu creation based on object type

This is the primary routing function that determines which specific IContextMenu creation path to use. It examines the context type and delegates to the appropriate handler.

Function Signature

HRESULT __fastcall CDefView::GetItemObject(
    CDefView *this,
    int a2,                         // Context type (encoded in low bits)
    const struct _GUID *a3,         // Requested interface ID
    void **a4)                      // [out] Returned interface pointer

Parameter Encoding: Context Type Bits

The a2 parameter encodes the context type in its low 4 bits:

Value (a2 & 0xF)MeaningContextRouting
`0x0`**Background**Empty space / desktop background`_CBackgrndMenu_CreateInstance`
`0x1`**Selection**One or more selected items`_CreateSelectionContextMenu`
`0x2`**Multiple Items**Batch operation on items`_CreateSelectionContextMenu`
Other(reserved)Not currently usedFallback handling

Detection Pattern (from assembly):

mov     eax, a2                     ; eax = context parameter
and     eax, 0xF                    ; eax = eax & 0xF (extract low 4 bits)
cmp     eax, 1                      ; Compare with 0x1 (selection)
jne     .background_context         ; If not equal, handle as background

Decision Tree

GetItemObject(a2, riid, &ppv)
    
     Extract context type: a2 & 0xF
    
     If (a2 & 0xF) == 0x0: BACKGROUND CONTEXT
       
        GUID Comparison Chain
            If riid == IID_IContextMenu
               _CBackgrndMenu_CreateInstance(...)
           
            Else if riid == IID_IContextMenu2
               _CBackgrndMenu_CreateInstance(...)
                   QueryInterface  IContextMenu2
           
            Else if riid == IID_IContextMenu3
               _CBackgrndMenu_CreateInstance(...)
                   QueryInterface  IContextMenu3
           
            Else if riid == IID_IDispatch
               Create automation object
                   Return IDispatch interface
           
            Else if riid == IID_IPersistHistory
               Create history object
                   Return IPersistHistory interface
           
            Else
                Return E_NOINTERFACE
    
     Else if (a2 & 0xF) == 0x1: SELECTION CONTEXT
        
         _CreateSelectionContextMenu(...)
             Handles IContextMenu* versions
             May also handle IDispatch/other interfaces

Decompiled Implementation

The decompiled code shows the complete routing logic:

HRESULT __fastcall CDefView::GetItemObject(
    CDefView *this,
    int a2,
    const struct _GUID *a3,
    void **a4)
{
    const GUID *v4;
    const GUID *v5;
    int v6;
    __int64 v7;
    __int64 v8;
    __int64 v9;
    __int64 v10;
    __int64 v11;
    __int64 v12;
    __int64 v13;
    const GUID *v14;
    const GUID *riid_a3;

    *a4 = 0;  // Clear output pointer

    // ***CRITICAL: Check context type***
    if ((a2 & 0xF) != 0)  // Selection or other context
    {
        // ***SELECTION CONTEXT ROUTING***
        // Delegate to selection-specific handler
        return CDefView::_CreateSelectionContextMenu(
            this,
            0,                      // flags
            a3,                     // Requested interface
            a4);                    // [out] Result
    }
    
    // ***BACKGROUND CONTEXT ROUTING***
    // User clicked on empty space / background
    
    // Prepare for type checking below
    v4 = a3;
    v5 = a3;  // v5 = requested interface GUID
    v6 = 0;
    
    // ***IID_IContextMenu CHECK***
    if (QISearch_0(&IID_IContextMenu, a3) == 0)
    {
        // Requested interface is IContextMenu
        return _CBackgrndMenu_CreateInstance(
            this,
            0,                      // flags
            a3,
            a4);                    // [out] ppv
    }

    // ***IID_IContextMenu2 CHECK***
    if (QISearch_0(&IID_IContextMenu2, a3) == 0)
    {
        // Requested interface is IContextMenu2
        return _CBackgrndMenu_CreateInstance(
            this,
            0,
            a3,
            a4);
    }

    // ***IID_IContextMenu3 CHECK***
    if (QISearch_0(&IID_IContextMenu3, a3) == 0)
    {
        // Requested interface is IContextMenu3
        return _CBackgrndMenu_CreateInstance(
            this,
            0,
            a3,
            a4);
    }

    // ***IID_IDispatch CHECK*** (for automation)
    if (QISearch_0(&IID_IDispatch, a3) == 0)
    {
        // Create automation dispatch wrapper
        // This allows scripts to interact with the context
        return SHCoCreateInstance(
            NULL,
            &g_ClassID_Automation,
            NULL,
            a3,
            a4);
    }

    // ***IID_IPersistHistory CHECK*** (navigation history)
    if (QISearch_0(&IID_IPersistHistory, a3) == 0)
    {
        // Return the DefView itself as history object
        return CDefView_QueryInterface(
            this + 130,             // IPersistHistory offset in vtable
            a3,
            a4);
    }

    // ***DEFAULT: Unsupported interface***
    return E_NOINTERFACE;  // 0x80004002
}

Key Assembly Insights

The low-bit extraction for context detection:

18010012d  mov     r8d, edx            ; r8d = a2 (context parameter)
18010133   and     r8d, 0xF            ; r8d = a2 & 0xF (extract type)
1801013d   cmp     r8d, 1              ; Compare with 0x1
1801014e   jne     .background         ; If != 0x1, process background
18010150   call    _CreateSelectionContextMenu  ; Selection path
180101c5 .background:
180101ca   call    _CBackgrndMenu_CreateInstance ; Background path

This demonstrates:

  • Efficient bit extraction using `and r8d, 0xF`
  • Quick comparison with `cmp r8d, 1`
  • Conditional branching for two paths
  • Only two main context types are actively processed

Type Checks Via QISearch

The function uses QISearch_0 for GUID comparisons:

// Pseudocode for QISearch_0
int QISearch_0(const GUID* guid1, const GUID* guid2)
{
    // Compare 128-bit GUIDs byte-by-byte
    // Returns 0 if equal, non-zero if different
    if (*guid1 == *guid2)
        return 0;  // Match
    else
        return 1;  // No match
}

Comparison Order:

1. IContextMenu (most common)

2. IContextMenu2 (has callbacks)

3. IContextMenu3 (extended version)

4. IDispatch (for automation)

5. IPersistHistory (for navigation)

This ordering prioritizes frequently-requested interfaces for performance.

Background Context: _CBackgrndMenu_CreateInstance

Address: 0x180100438

Size: 0x190 bytes (400 bytes)

Purpose: Creates IContextMenu for background (empty space) right-clicks

When the user clicks on empty space in the folder view, this function orchestrates the creation of a context menu specific to the background area.

Function Signature

HRESULT __fastcall CDefView::_CBackgrndMenu_CreateInstance(
    CDefView *this,
    int a2,                         // flags (unused: 0)
    const struct _GUID *a3,         // Requested interface (IID_IContextMenu*)
    void **a4)                      // [out] Returned interface

Implementation

HRESULT __fastcall CDefView::_CBackgrndMenu_CreateInstance(
    CDefView *this,
    int a2,
    const struct _GUID *a3,
    void **a4)
{
    HMENU hBackgroundHMENU;
    IBindCtx *pBindCtx;
    IContextMenu *pFolderContextMenu;
    void *pContextMenuArray;
    int v8;

    *a4 = 0;  // Clear output

    // ***STEP 1: CREATE BACKGROUND HMENU***
    hBackgroundHMENU = CDefView::_Create_BackgrndHMENU(
        this,
        0,                          // uPosition
        a3,                         // a3 (interface request, unused)
        &pBindCtx);                 // [out] Bind context

    if (!hBackgroundHMENU)
        return E_OUTOFMEMORY;       // 0x8007000E

    // ***STEP 2: GET PARENT FOLDER'S ICONTEXTMENU***
    // The parent folder (e.g., C:\Users) also has a context menu
    // We need to merge the background menu with the parent's menu
    
    // Get parent folder IContextMenu from cached member (offset +87)
    pFolderContextMenu = *(IContextMenu**)(this + 87);  // Member at offset 87

    // ***STEP 3: CREATE MENU WRAPPER***
    // CContextMenuOnContextMenuArray merges two context menus
    pContextMenuArray = operator_new(0xD8);  // Allocate wrapper object
    
    if (!pContextMenuArray)
    {
        DestroyMenu(hBackgroundHMENU);
        return E_OUTOFMEMORY;
    }

    // ***STEP 4: INITIALIZE MERGER WITH TWO MENUS***
    // Array pattern: [BackgroundHMENU, ParentFolderMenu]
    CContextMenuOnContextMenuArray::CContextMenuOnContextMenuArray(
        pContextMenuArray,
        2,                          // Number of menus to merge
        hBackgroundHMENU,           // First: Background HMENU
        pFolderContextMenu);        // Second: Parent folder menu

    // ***STEP 5: APPLY FOLDER VIEW EXTENSIONS***
    // Allow IShellFolderViewCM to modify the menu
    CDefView::_TryModifyMenu(
        this,
        pContextMenuArray,          // The merged menu
        1,                          // a3 = 1 (background context flag)
        a3,                         // Requested interface
        a4);                        // [out] Result

    // If _TryModifyMenu succeeded, ppv is filled
    // Otherwise, fall through to return error

    return v8;  // Return from _TryModifyMenu
}

Background HMENU Creation: _Create_BackgrndHMENU

Address: 0x180100754

Size: 0x3b9 bytes (953 bytes)

Purpose: Creates the HMENU that represents the background context menu

This function creates the actual Win32 HMENU that represents all possible operations available when right-clicking the background (empty space) in a folder view.

Implementation Overview

HRESULT __fastcall CDefView::_Create_BackgrndHMENU(
    CDefView *this,
    UINT uPosition,                 // Submenu extraction position (usually 0)
    const struct _GUID *a3,         // Unused parameter
    void **a4)                      // [out] Bind context
{
    HMENU hMenu;
    int result;

    *a4 = 0;  // Clear output

    // ***STEP 1: LOAD MENU TEMPLATE FROM RESOURCES***
    // Resource ID 0xD7 = POPUP_DDM_BACKGROUNDPOPUP
    hMenu = SHLoadPopupMenu(g_hinst, 0xD7);
    
    if (!hMenu)
        return E_OUTOFMEMORY;

    // ***STEP 2: INITIALIZE EDIT COMMANDS***
    // Add Cut/Copy/Paste/Delete commands
    // Parameters:
    // - 0: Start from beginning
    // - hMenu: Target menu handle  
    // - 28672 (0x7000): Command ID base for standard commands
    // - this+97: Clipboard owner
    // - 1: Enable edit operations
    // - this+77: Data source
    Def_InitEditCommands(0, hMenu, 28672, *(this + 97), 1u, *(this + 77));

    // ***STEP 3: CONDITIONAL VIEW MENU ITEMS***
    // this+216 contains view mode flags (0x10000000 = some mode bit)
    if ((*(this + 216) & 0x10000000) != 0)
    {
        // ***MODERN VIEW MODE***
        // Delete obsolete menu item
        DeleteMenu(hMenu, 0x7033u, 0);

        // Configure View submenu
        MENUITEMINFOW mii = {0};
        mii.cbSize = 80;
        mii.fMask = 4;                           // MIIM_SUBMENU
        
        GetMenuItemInfoW(hMenu, 0x7002u, 0, &mii);  // Get submenu
        
        HMENU hSubMenu = mii.hSubMenu;
        if (hSubMenu)
        {
            // Remove obsolete view modes
            DeleteMenu(hSubMenu, 0x704Bu, 0);    // List view obsolete
            DeleteMenu(hSubMenu, 0x704Cu, 0);    // Details view obsolete
            DeleteMenu(hSubMenu, 0x704Du, 0);    // Small icons obsolete
            DeleteMenu(hSubMenu, 0x7051u, 0);   // Tile view
            DeleteMenu(hSubMenu, 0x7052u, 0);   // Extra large icons

            // Check current view mode
            CDefView::_CheckCurrentViewMenuItem(this, hSubMenu);

            // Load resource string for current sort order
            wchar_t* pSortText = NULL;
            TResourceStringAllocCopyEx<unsigned short*>(
                g_hinst,
                0x79B5u,                         // Resource string ID
                v9,
                ResourceStringAllocCopyExLocalAlloc,
                lpNewItem,
                &pSortText);

            // Update sort menu item
            if (pSortText)
            {
                ModifyMenuW(hSubMenu, 0x7071u, 0, 0x7071u, pSortText);
                LocalFree(pSortText);
            }

            // Similar for other string resources
            // ...and check for classic shell restrictions

            if (!SHRestricted(REST_CLASSICSHELL))
            {
                // Load and merge classic shell menu
                HMENU hClassicMenu = SHLoadMenuPopup(g_hinst, 218);
                
                if (hClassicMenu)
                {
                    // Get shell settings (e.g., show hidden files)
                    SHELLSTATE shellState = {0};
                    SHGetSetSettings(&shellState, 0x4000u, 0);

                    // Update menu based on settings
                    if ((shellState & 0x1000) == 0)
                        CheckMenuItem(hClassicMenu, 0x7402u, 8u);

                    // Merge classic menu items
                    Shell_MergeMenus(
                        hSubMenu,                // Target menu
                        hClassicMenu,            // Source menu
                        0xFFFFFFFF,             // Insert position (-1 = end)
                        0,                      // Start ID
                        0xFFFFFFFF,             // End ID
                        3);                     // Merge flags

                    DestroyMenu(hClassicMenu);
                }
            }
        }
    }
    else
    {
        // ***CLASSIC VIEW MODE***
        DeleteMenu(hMenu, 0x7033u, 0);  // Delete modern-only item
        
        // Apply lambda-based extensions
        // [Details in actual implementation]
    }

    // ***STEP 4: INITIALIZE VIEW MENU***
    CDefView::_InitViewMenu(this, hMenu);

    // ***STEP 5: EXTRACT SUBMENU IF REQUESTED***
    if (uPosition)  // Non-zero position specified
    {
        // Get submenu at the specified position
        MENUITEMINFOW mii = {0};
        mii.cbSize = 80;
        mii.fMask = 4;  // MIIM_SUBMENU
        
        GetMenuItemInfoW(hMenu, uPosition, 0, &mii);
        
        HMENU hSubMenu = mii.hSubMenu;
        RemoveMenu(hMenu, uPosition, 0);
        DestroyMenu(hMenu);
        
        hMenu = hSubMenu;  // Return submenu instead
    }

    // ***STEP 6: WRAP IN CDVBackgroundHMENU***
    // Create special wrapper that tracks menu item state
    return Create_CDVBackgroundHMENU(
        hMenu,                      // The HMENU to wrap
        *(this + 87),               // Parent folder context
        this,                       // DefView context
        a3,                         // Requested interface (unused)
        a4);                        // [out] Wrapped menu
}

Menu Resource Template (0xD7)

The background menu is loaded from resource ID 0xD7:

BACKGROUND_MENU (ID: 0xD7)
 Edit Menu (0x7002)
   Undo (0x7001)
   Cut (0x7003)
   Copy (0x7004)
   Paste (0x7005)
   Separator
   Delete (0x7006)

 View Menu (0x7020)
   View Modes
     List (0x704B)
     Details (0x704C)
     Icons (0x704D)
     ...
   Separator
   Sort By
     Name (0x7071)
     Date (0x7074)
     ...
   Group By
      ...

 Refresh (0x7030)
 Separator
 New (0x7033) [Modern only]
 Personalize (0x7024) [Modern only]
 Separator
 Undo/Redo (0x7001)
 Properties (0x7025)

Data Structure: CContextMenuOnContextMenuArray

This object merges two context menus:

struct CContextMenuOnContextMenuArray
{
    // VTable pointer (IContextMenu interface)
    void** lpVtbl;                   // Offset 0x0
    
    // Reference count
    LONG refCount;                   // Offset 0x8
    
    // Array of IContextMenu pointers
    IContextMenu** ppContextMenus;   // Offset 0x10
    
    // Number of menus in array
    ULONG cMenus;                    // Offset 0x18
    
    // Cached state for each menu
    struct {
        UINT uFlags;                 // Flags from QueryContextMenu
        UINT idCmdFirst;            // First command ID
        UINT idCmdLast;             // Last command ID  
    } menuState[2];                  // Space for 2 menus
    
    // Total size: 0xD8 bytes (216 bytes)
};

How it works:

// When IContextMenu::QueryContextMenu is called on the merger:
// 1. Call QueryContextMenu on first menu (BackgroundHMENU)
// 2. Call QueryContextMenu on second menu (Parent folder menu)
// 3. Merge the resulting HMENUs via Shell_MergeMenus
// 4. Return merged HMENU to caller

// When a command is invoked:
// 1. Check which menu owns the command ID
// 2. Route to that menu's IContextMenu::InvokeCommand

Flow Diagram: Background Menu Creation

User Right-Clicks Empty Space
    
     CDefView::_DoContextMenuPopup(...)
       
        GetItemObject(this, a2=0x0, IID_IContextMenu, &ppv)
           
            Check: (a2 & 0xF) == 0 ? YES
           
            Route to _CBackgrndMenu_CreateInstance
    
     _CBackgrndMenu_CreateInstance (0x180100438)
       
        Step 1: _Create_BackgrndHMENU
          
           SHLoadPopupMenu(g_hinst, 0xD7)
              Load background menu template from resources
          
           Def_InitEditCommands
              Add Cut/Copy/Paste/Delete
          
           Check view mode: (*(this+216) & 0x10000000)
              If modern: Delete old mode items, check current
                 May load classic shell menu
                     Shell_MergeMenus (merge into View submenu)
             
              If classic: Apply lambda extensions
          
           _InitViewMenu
              Initialize view-related menu items
          
           Create_CDVBackgroundHMENU (wrapper)
              Wraps HMENU with state tracking
          
           Return wrapped menu
       
        Step 2: Get parent folder's IContextMenu
           *(this + 87)  Cached parent menu
       
        Step 3: Create CContextMenuOnContextMenuArray
           Allocate 0xD8 bytes
           Initialize with [BackgroundHMENU, ParentMenu]
       
        Step 4: _TryModifyMenu (extend via IShellFolderViewCM)
           Query IShellFolderViewCM service
           Allow extensions to modify menu
           Return modified IContextMenu
       
        Return merged IContextMenu interface
    
     Returned to _DoContextMenuPopup for display
         DoCuratedContextMenu  XAML flyout
         Or DoClassicMenu  TrackPopupMenu

Selection Context Routing

When the user clicks on a selected item instead of empty space:

if ((a2 & 0xF) == 0x1)  // Selection context
{
    return CDefView::_CreateSelectionContextMenu(
        this,
        0,
        a3,                         // Requested interface
        a4);                        // [out] Result
}

_CreateSelectionContextMenu (analyzed in previous section):

  • Gets the selected item(s)
  • Queries their IContextMenu
  • Applies shell folder view extensions
  • Returns the configured menu

Key Differences: Selection vs Background

AspectSelection ContextBackground Context
**Entry Function**`_CreateSelectionContextMenu``_CBackgrndMenu_CreateInstance`
**Context Type Bit**`a2 & 0xF == 0x1``a2 & 0xF == 0x0`
**HMENU Source**From selected item's IContextMenuFrom resource template (0xD7)
**Menu Items**Item-specific operationsView-level operations
**Parent Menu**Not mergedMerged with parent folder
**Typical Items**Open, Edit, Delete, PropertiesCut, Copy, Paste, View, Refresh
**Shell Extensions**Via IContextMenuVia IShellFolderViewCM
**Automation Support**IDispatch if item supports itIDispatch wrapper

Memory and Performance

Stack Usage:

// Local variables in GetItemObject
const GUID* v4, v5;
int v6;
__int64 v7-v13;                    // ~110 bytes on stack

Allocation Patterns:

  • `CContextMenuOnContextMenuArray`: Heap allocation (0xD8 bytes)
  • HMENU handles: Windows Manager resources (not heap)
  • Temporary strings: Stack or local allocation

Performance Characteristics:

  • Fast path (background): ~5-10ms (resource load + SetUp)
  • Selection path: Depends on shell extensions (10-50ms typical)
  • GUID comparisons: 128-bit equality check (very fast)
  • No async operations at this layer (async happens later in filtering)

Error Conditions

GetItemObject Error Handling:

// If riid is not supported
return E_NOINTERFACE;  // 0x80004002

// If context type is invalid
return E_INVALIDARG;   // 0x80070057

// If HMENU creation fails  
return E_OUTOFMEMORY;  // 0x8007000E

Graceful Degradation:

  • Selection context falls back to item's implementation
  • Background context has built-in fallback menu
  • Shell extensions errors don't crash the menu
  • Missing resources use hardcoded fallback

Integration with Curated Menu System

The IContextMenu created here flows into the curated menu pipeline:

1. GetItemObject() creates IContextMenu
    For selection: Item's native menu
    For background: Merged BackgroundHMENU + parent menu

2. IContextMenu::QueryContextMenu() populates an HMENU
    Shell extensions add their items
    Result cached for display

3. CDefView::_DoContextMenuPopup receives the HMENU
    Passes to DoCuratedContextMenu

4. DoCuratedContextMenu sends to ContextMenuPresenter
    DoContextMenuHelper receives the HMENU

5. TryCreateMiniMenuFromClassic filters and curates it
    Produces the final curated menu

6. CreateMenuItems converts HMENU to XAML
    Produces MenuItem collection

7. ShowXamlFlyout displays the XAML flyout
    User sees the curated menu

Security Considerations

COM Interface Validation:

  • GUID comparisons protect against type confusion
  • QISearch validates interface requests
  • No unchecked casting

Menu ID Ranges:

  • Background items use 0x7000+ range
  • Shell extensions use 32000+ range (0x7D00+)
  • Prevents command ID collisions

Resource Integrity:

  • Menu templates come from trusted resources
  • SHLoadPopupMenu validates resource handles
  • SHLoadMenuPopup protects against resource attacks

Future Extensions

The architecture supports:

  • New context types via `a2` bit patterns
  • Custom GUID handling for new interfaces
  • Extended menu merging (>2 menus)
  • Async menu item loading (not currently used at this layer)

---

_GetContextMenuFromObjectCollection - Factory Pattern Routing

Address: 0x1802b46b0

Size: 0xe6 bytes (230 bytes)

Purpose: Creates IContextMenu for collections of items using a modern factory pattern

This function handles a different code path for context menu creation compared to GetItemObject. Instead of examining individual selections, this function operates on collections of objects via IObjectCollection, enabling more flexible batch operations and multi-item menus.

Function Signature

HRESULT __fastcall CDefView::_GetContextMenuFromObjectCollection(
    CDefView *this,
    struct IObjectCollection *a2,   // Collection of items
    struct _GUID *a3,               // Requested interface (riid)
    void **a4)                      // [out] Returned interface

High-Level Algorithm

_GetContextMenuFromObjectCollection(IObjectCollection pCollection, riid, &ppv)
    
     TRY: Query this+75 for IContextMenuFactory
    
     IF IContextMenuFactory available (SUCCESS PATH):
       
        Step 1: Convert IObjectCollection  IShellItemArray
           _GetShellItemArrayFromObjectCollection(pCollection, &shellItemArray)
       
        Step 2: Call factory method (vtable+0x18)
           IContextMenuFactory::CreateContextMenu(
              this+86,            // Parameter 1 (purpose unknown, cached data?)
              shellItemArray,     // Parameter 2 (the items)
              0,                  // Parameter 3 (reserved)
              riid,               // Parameter 4 (requested interface)
              &ppv)               // Parameter 5 (output)
       
        Return result
    
     ELSE: IContextMenuFactory NOT available (FALLBACK PATH)
        
         Step 1: Extract child IDs from collection
            _GetUIObjectFromItemArray(
               pCollection,        // Items collection
               0,                  // a3 parameter
               riid,               // Requested interface
               &ppv)               // Output
        
         Return result

Decompiled Implementation

HRESULT __fastcall CDefView::_GetContextMenuFromObjectCollection(
    CDefView *this,
    struct IObjectCollection *a2,
    struct _GUID *a3,
    void **a4)
{
    int result;
    void *pShellItemArray;
    ComPtr<IContextMenuFactory> pFactory;

    *a4 = 0;  // Clear output
    pFactory = NULL;

    // ***STEP 1: TRY TO ACQUIRE ICONTEXTMENUFACTORY***
    // Query member at offset +75 (likely a service provider or cached object)
    // for the IContextMenuFactory interface
    
    if ((***(this + 75))(*(this + 75), &IID_IContextMenuFactory, &pFactory) < 0)
    {
        // ***FACTORY NOT AVAILABLE: USE FALLBACK***
        // If factory QueryInterface fails, fall back to legacy path
        result = CDefView::_GetUIObjectFromItemArray(
            this,
            a2,                    // Item collection
            0,                     // a3 parameter
            a3,                    // Requested interface
            a4);                   // [out] Result
    }
    else
    {
        // ***FACTORY AVAILABLE: USE MODERN PATH***
        pShellItemArray = NULL;

        // ***STEP 2: CONVERT IOBJECTCOLLECTION TO ISHELLITEMARRAY***
        result = CDefView::_GetShellItemArrayFromObjectCollection(
            this,
            a2,                    // Input: IObjectCollection
            &IID_IShellItemArray,  // Interface to query for
            &pShellItemArray);     // [out] Resulting IShellItemArray

        if (result >= 0)  // Success
        {
            // ***STEP 3: CALL FACTORY METHOD***
            // Vtable offset +0x18 = 3rd method (after QueryInterface, AddRef, Release)
            
            // Get factory vtable
            IContextMenuFactory **ppVtable = *(IContextMenuFactory**)pFactory;
            
            // Call factory method at offset 0x18 (3rd virtual method)
            result = (*ppVtable[3])(
                pFactory,           // this
                *(this + 86),       // Parameter 1: Some cached data from DefView
                pShellItemArray,    // Parameter 2: The items
                0,                  // Parameter 3: Reserved
                a3,                 // Parameter 4: Requested interface
                a4);                // Parameter 5: Output
        }

        // Release the shell item array
        if (pShellItemArray)
            pShellItemArray->Release();
    }

    // Release factory COM object via RAII
    pFactory.reset();

    return result;
}

Key Member Variables

Based on assembly analysis:

OffsetPurposeUsage
`+75` (0x4B)Query provider for IContextMenuFactoryQueryInterface target
`+86` (0x56)Cached context data (HWND? pointer?)Passed to factory method
`+2B0` (0x2B0)Additional factory parameterLoaded at factory call site

Code Path Comparisons

AspectGetItemObject_GetContextMenuFromObjectCollection
**Entry Point**CDefView methodCDefView method
**Input**Context type bits (a2 & 0xF)IObjectCollection interface
**Routing**Selection vs Background bitsFactory availability
**Primary Path**Direct handler functionsIContextMenuFactory pattern
**Fallback Path**E_NOINTERFACE_GetUIObjectFromItemArray
**Usage**Individual selectionsMulti-item collections

_GetShellItemArrayFromObjectCollection - Collection Conversion

Address: 0x1800a4764

Size: 0xb7 bytes (183 bytes)

Purpose: Converts generic IObjectCollection to the shell's IShellItemArray

HRESULT CDefView::_GetShellItemArrayFromObjectCollection(
    CDefView *this,
    struct IObjectCollection *a2,
    const struct _GUID *a3,        // IID_IShellItemArray
    void **a4)                     // [out] Result
{
    unsigned int result;
    void *pArrayAsObj;             // Temporary for interface casting
    
    *a4 = 0;  // Clear output

    // ***STEP 1: TRY DIRECT CAST***
    // Check if the IObjectCollection already has a special GUID interface
    // (likely IShellItemArray wrapped in IObjectCollection)
    
    if (a2->QueryInterface(
        &GUID_7465aad4_d469_4305_9c0f_a4403853f4e6,  // Internal GUID for array wrapper
        &pArrayAsObj) < 0)  // Failed - not pre-wrapped
    {
        // ***FALLBACK: USE CREATION FUNCTION***
        // Create IShellItemArray from raw IObjectCollection
        result = CreateItemArrayFromObjectArray(
            *(this + 75),          // Context/service provider
            a2,                    // Collection to convert
            a3,                    // Interface to request
            a4);                   // [out] Result
    }
    else
    {
        // ***SUCCESS: CAST WORKED***
        // The array was already wrapped - call its method (vtable+0x18)
        result = (*(*pArrayAsObj + 0x18))(
            pArrayAsObj,
            *(this + 75),          // Context/service provider
            a3,                    // Interface to request
            a4);                   // [out] Result
        
        // Release temporary reference
        if (pArrayAsObj)
            pArrayAsObj->Release();
    }

    return result;
}

Key Insight: This function attempts two strategies:

1. Fast path: Check if IObjectCollection already wraps an IShellItemArray via a special internal GUID

2. Slow path: Create a new IShellItemArray from the raw collection if needed

_GetUIObjectFromItemArray - Legacy Fallback

Address: 0x180171e60

Size: 0x10e bytes (270 bytes)

Purpose: Creates UI objects from item arrays using the older shell API

This is the fallback path when IContextMenuFactory is unavailable:

HRESULT CDefView::_GetUIObjectFromItemArray(
    CDefView *this,
    struct IObjectCollection *a2,
    int a3,                        // Flags or selector
    struct _GUID *a4,              // Requested interface
    void **a5)                     // [out] Result
{
    int result;
    DPA hdpa;                      // Dynamic Pointer Array of IChildId objects
    unsigned int itemCount;        // Number of items
    void *pItemIds;                // Array of item identifiers (PIDLs)

    itemCount = 0;
    pItemIds = NULL;
    hdpa = NULL;

    // ***STEP 1: EXTRACT ITEM IDENTIFIERS FROM COLLECTION***
    // Convert IObjectCollection → array of child IDs (PIDLs/IChildIds)
    
    result = CDefView::_GetChildIdArrayFromItemArray(
        this,
        a2,                        // Collection to extract from
        &hdpa,                     // [out] Dynamic pointer array
        &itemCount,                // [out] Item count
        &pItemIds);                // [out] Array of identifier pointers

    if (result >= 0)  // Success
    {
        // ***STEP 2: INVOKE SHELL API GETUILOBJECT***
        // Call the shell's GetUIObject API (vtable method at offset 0x50)
        // this+75 = provider object with vtable
        
        result = (*(**(this + 75) + 0x50))(
            *(this + 75),          // Provider/context object
            *(this + 86),          // HWND or context handle
            itemCount,             // Number of items
            pItemIds,              // Array of PIDLs
            a4,                    // Requested interface
            0,                     // Reserved
            a5);                   // [out] Result

        // ***STEP 3: CONDITIONAL DATA POINT SETTING***
        // If we got an IDataObject and a3 flag is set:
        if (result >= 0 && IID_IDataObject == *a4 && a3)
        {
            // Associate mouse coordinates with the data object
            _SetPoints(this, itemCount, pItemIds, *a5);
        }

        // Clean up temporary array
        CoTaskMemFree(pItemIds);
    }

    // ***STEP 4: CLEANUP DPA***
    if (hdpa)
    {
        // Release all IChildId objects in the array
        DPA_DestroyCallback(hdpa, DPA_ReleaseCB<IChildId>, 0);
        DPA_Destroy(hdpa);
    }

    return result;
}

Key Steps:

1. Extract child ID array (PIDLs) from collection

2. Call shell's GetUIObject with the item IDs

3. Associate mouse points if dealing with IDataObject

4. Clean up DPA and temporary data

Member Variable Analysis

From cross-referencing the assembly:

// At offset +75 (0x4B):
// Likely: IShellBrowser* or IServiceProvider
// Used for: QueryInterface(IContextMenuFactory)
//           Stored result passed to factory creation functions

// At offset +86 (0x56):
// Likely: HWND or context handle
// Used for: First parameter to factory methods
//           First parameter to GetUIObject

// At offset +2B0 (0x2B0):
// Purpose: Unknown, loaded in assembly but not used in decompile
// Access pattern: Conditional parameter loading

Call Chain: From Collection to Menu

Here's the complete flow when dealing with object collections:

User Right-Clicks on Selection
    
     Multiple items selected
        
         Create IObjectCollection from selected items
            IObjectCollection = {item1, item2, ..., itemN}
        
         _GetContextMenuFromObjectCollection(pCollection, IID_IContextMenu, &ppv)
            
             TRY: Query this+75 for IContextMenuFactory
            
             IF Factory Available:
               
                _GetShellItemArrayFromObjectCollection
                  
                   Try: Query by GUID_7465aad4_d469_4305_9c0f_a4403853f4e6
                      If success: Already-wrapped array, call method
                  
                   Else: CreateItemArrayFromObjectArray
                       Create new IShellItemArray from collection
               
                Call IContextMenuFactory::CreateContextMenu
                   Modern multi-item context menu creation
               
                Return result
            
             ELSE: Factory Not Available
                
                 _GetUIObjectFromItemArray (Fallback)
                   
                    _GetChildIdArrayFromItemArray
                       Extract PIDLs from collection
                   
                    Call shell GetUIObject with PIDL array
                       Legacy shell API path
                   
                    Return result
                
                 Return fallback result
            
    Result: IContextMenu interface for multiple items

Memory Layout: CDefView Member Access

struct CDefView {
    // ... members ...
    
    /* +0x4B (75) */  IShellBrowser* pShellBrowser;  // Used for factory queries
    
    // ... members ...
    
    /* +0x56 (86) */  HWND hwndView;                 // Passed to factory/GetUIObject
    
    // ... members ...
    
    /* +0x2B0 (688) */ (unknown context data)
};

Error Handling Strategy

Multi-Level Fallback:

Level 1: IContextMenuFactory available
     (if fails)
Level 2: CreateItemArrayFromObjectArray
     (if fails)
Level 3: Legacy GetUIObject path
     (if fails)
Return error with context preserved

This provides graceful degradation:

  • Modern factory-based path for newer systems
  • Shell API fallback for compatibility
  • Multiple error recovery points
  • No data loss if retrieval fails

Performance Characteristics

Time Complexity:

  • Fast path (cached array): O(1) - single method call
  • Moderate path (array creation): O(n) - iterate collection items
  • Legacy path (GetUIObject): O(n log n) - PIDL extraction + shell call

Memory Usage:

  • Factory path: ~100-200 bytes (temporary COM pointers)
  • Fallback path: O(n) - DPA allocation for n items

Integration with Main Context Menu Flow

This function fits into the broader system:

CDefView::_DoContextMenuPopup
    
     Determine context type
     Get items as collection via IObjectCollection
    
     Call _GetContextMenuFromObjectCollection
        Returns IContextMenu for collection
    
     Pass IContextMenu to DoCuratedContextMenu
     Call IContextMenu::QueryContextMenu
    
     Proceed to TryCreateMiniMenuFromClassic
         Filter and curate the menu

Comparison with GetItemObject

FunctionPurposePath
**GetItemObject**Route by context type bitsSelection vs Background
**_GetContextMenuFromObjectCollection**Create menu for collectionFactory vs Legacy
**GetItemObject**Fast, bit-based dispatchDirect handler selection
**_GetContextMenuFromObjectCollection**Flexible collection handlingMulti-strategy fallback

Key Design Patterns

1. Factory Pattern:

  • Delegate menu creation to IContextMenuFactory
  • Allows extensibility without modifying CDefView
  • Modern path for new functionality

2. Strategy Pattern:

  • Try preferred method (factory)
  • Fall back to legacy method if needed
  • Choose strategy based on availability

3. Adapter Pattern:

  • _GetShellItemArrayFromObjectCollection adapts IObjectCollection to IShellItemArray
  • Allows code reuse with different input types

4. DPA (Dynamic Pointer Array):

  • Efficient array management for variable-sized collections
  • Automatic cleanup via DPA_DestroyCallback
  • RAII pattern for resource safety

Security Considerations

Data Flow Validation:

  • Item collections are validated before use
  • PIDLs extracted under error handling
  • Interface queries protected by RAII COM pointers

Interface Type Checking:

  • GUID comparisons ensure correct interface types
  • No unsafe casts on com pointers
  • QueryInterface validates availability

Memory Safety:

  • All allocations use CoTaskMemFree (proper cleanup)
  • DPA cleanup guaranteed via callback pattern
  • No raw pointer manipulations

Relationship to Curated Menu System

This function creates the initial raw IContextMenu that gets passed up to:

_GetContextMenuFromObjectCollection
     (returns IContextMenu)
_DoContextMenuPopup
     (IContextMenu::QueryContextMenu populates HMENU)
DoCuratedContextMenu
     (receives populated HMENU)
ContextMenuPresenter::DoContextMenuHelper
     (receives HMENU)
TryCreateMiniMenuFromClassic
     (filters and curates)
XAML flyout

Usage Scenarios

When this function is called:

1. Multi-item selection: User selects multiple files, right-clicks

- Creates collection of selected items

- Calls this function to build multi-item context menu

2. Batch operations: Drag-drop multiple items

- Collection represents dropped items

- Menu shows operations valid for all items

3. Advanced selections: Ctrl+click selections

- Mixed file types in collection

- Factory determines valid operations

When GetItemObject is called instead:

1. Single item click: Single file right-click

2. Background click: Empty space right-click

3. Folder context: Right-click on folder itself

---

End of Analysis