0x5bfa.dev

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

Deep dive into RE'ing the overview of the new Windows 11 home folder with IDA Pro

0x5bfa2026/02/07Updated on 2026/02/08

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.

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.

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
idCmdFirst30977 (0x7901)First command ID for shell extensions
idCmdLast31487 (0x7AFF)Last command ID for shell extensions
CMF_DEFAULTONLY0x20Only default menu items
CMF_ASYNCVERBS0x400Allow async verb execution
CMF_CURATED0x8000Request curated menu
LOCATION_CONTEXT_DESKTOP0x400Desktop 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: IdleCreating
  • 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;
}

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<wstring, int> - 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<wstring, int> (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:

  • IdleCreating: When DoContextMenuHelper starts
  • CreatingShowingXaml: After XAML flyout creation succeeds
  • CreatingShowingWin32: Fallback for non-XAML scenarios
  • CreatingWaitingForAsync: When waiting for async operations
  • Any StateDismissed: 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

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 (HMENU→XAML)       │   │ │
│ │    └─► 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_SELECTION1Get currently selected items
SVGIO_FLAG_VIEWORDER0x80000000Selection in view order (not used here with OR)
SVGIO_ALLASSTRING0x80000001Combined: 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
0x0BackgroundEmpty space / desktop background_CBackgrndMenu_CreateInstance
0x1SelectionOne or more selected items_CreateSelectionContextMenu
0x2Multiple ItemsBatch 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
}

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 Bita2 & 0xF == 0x1a2 & 0xF == 0x0
HMENU SourceFrom selected item's IContextMenuFrom resource template (0xD7)
Menu ItemsItem-specific operationsView-level operations
Parent MenuNot mergedMerged with parent folder
Typical ItemsOpen, Edit, Delete, PropertiesCut, Copy, Paste, View, Refresh
Shell ExtensionsVia IContextMenuVia IShellFolderViewCM
Automation SupportIDispatch 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 PointCDefView methodCDefView method
InputContext type bits (a2 & 0xF)IObjectCollection interface
RoutingSelection vs Background bitsFactory availability
Primary PathDirect handler functionsIContextMenuFactory pattern
Fallback PathE_NOINTERFACE_GetUIObjectFromItemArray
UsageIndividual 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
GetItemObjectRoute by context type bitsSelection vs Background
_GetContextMenuFromObjectCollectionCreate menu for collectionFactory vs Legacy
GetItemObjectFast, bit-based dispatchDirect handler selection
_GetContextMenuFromObjectCollectionFlexible 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