From dc0266c88ed148d8e59aa0dbe4057b86ac64f709 Mon Sep 17 00:00:00 2001 From: ge0rdi Date: Sat, 28 Jul 2018 20:20:44 +0200 Subject: [PATCH] Cleanup of the accessibility COM objects (#53) Fixed issue related to the cleanup of the accessibility COM objects that may cause Explorer to crash. Submitted by Ivo Beltchev. Fixes #53 --- .../ClassicStartMenuDLL/MenuContainer.cpp | 41 +++++++++++++++++-- .../ClassicStartMenuDLL/MenuContainer.h | 12 +++++- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/ClassicStartSrc/ClassicStartMenu/ClassicStartMenuDLL/MenuContainer.cpp b/ClassicStartSrc/ClassicStartMenu/ClassicStartMenuDLL/MenuContainer.cpp index 4a2733a..f269ace 100644 --- a/ClassicStartSrc/ClassicStartMenu/ClassicStartMenuDLL/MenuContainer.cpp +++ b/ClassicStartSrc/ClassicStartMenu/ClassicStartMenuDLL/MenuContainer.cpp @@ -4426,13 +4426,28 @@ LRESULT CMenuContainer::OnCreate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& if (m_Options&CONTAINER_SEARCH) s_SearchMenu=m_hWnd; s_HotPos=GetMessagePos(); + m_pAccessible=NULL; if (GetSettingBool(L"EnableAccessibility")) { - m_pAccessible=new CMenuAccessible(this); + if (SUCCEEDED(m_pAccessibleContext.CoCreateInstance(CLSID_ContextSwitcher))) + { + CreateAccessibleData createData={this}; + ComCallData callData={}; + callData.pUserDefined=&createData; + if (SUCCEEDED(m_pAccessibleContext->ContextCallback(CreateAccessible,&callData,IID_IAccessible,4,NULL))) + { + if (FAILED(CoGetInterfaceAndReleaseStream(createData.pStream,IID_IAccessible,(void**)&m_pAccessible))) + { + m_pAccessibleContext=NULL; + } + } + else + { + m_pAccessibleContext=NULL; + } + } NotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART,m_hWnd,OBJID_CLIENT,CHILDID_SELF); } - else - m_pAccessible=NULL; m_pDropTargetProxy=new CDropTargetProxy(this); RegisterDragDrop(m_hWnd,m_pDropTargetProxy); if (!m_bSubMenu && s_pFrameworkInputPane) @@ -4441,6 +4456,23 @@ LRESULT CMenuContainer::OnCreate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& return 0; } +HRESULT __stdcall CMenuContainer::CreateAccessible( ComCallData *pData ) +{ + CreateAccessibleData *pCreateData=(CreateAccessibleData*)pData->pUserDefined; + CComPtr pAccessible=new CMenuAccessible(pCreateData->pMenu); + HRESULT hr=CoMarshalInterThreadInterfaceInStream(IID_IAccessible,pAccessible,&pCreateData->pStream); + if (FAILED(hr)) + { + pAccessible->Reset(); + } + return hr; +} + +HRESULT __stdcall CMenuContainer::ReleaseAccessible( ComCallData *pData ) +{ + return CoDisconnectContext(INFINITE); +} + bool CMenuContainer::GetItemRect( int index, RECT &rc ) { if (index>=0 && index<(int)m_Items.size()) @@ -6111,7 +6143,8 @@ LRESULT CMenuContainer::OnDestroy( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL if (m_pAccessible) { NotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND,m_hWnd,OBJID_CLIENT,CHILDID_SELF); - m_pAccessible->Reset(); + m_pAccessibleContext->ContextCallback(ReleaseAccessible,NULL,IID_IAccessible,4,NULL); + m_pAccessibleContext=NULL; m_pAccessible=NULL; } if (m_pDropTargetHelper && m_pDragObject) diff --git a/ClassicStartSrc/ClassicStartMenu/ClassicStartMenuDLL/MenuContainer.h b/ClassicStartSrc/ClassicStartMenu/ClassicStartMenuDLL/MenuContainer.h index 0dcce95..a97cc31 100644 --- a/ClassicStartSrc/ClassicStartMenu/ClassicStartMenuDLL/MenuContainer.h +++ b/ClassicStartSrc/ClassicStartMenu/ClassicStartMenuDLL/MenuContainer.h @@ -12,6 +12,7 @@ #include "TouchHelper.h" #include #include +#include //#define PREVENT_CLOSING // define this to prevent the menu from closing when it is deactivated (useful for debugging) //#define REPEAT_ITEMS 10 // define this to repeat each menu item (useful to simulate large menus) @@ -628,7 +629,8 @@ private: CAbsolutePidl m_Path2[2]; CComPtr m_pDropFolder[2]; // the primary folder (used only as a drop target) CComPtr m_pShellView; // keep the view alive because some buggy namespace extensions clean up if there is no view - CComPtr m_pAccessible; + CComPtr m_pAccessibleContext; + CComPtr m_pAccessible; CComPtr m_pDropTargetProxy; DWORD m_InputCookie; std::vector m_ColumnOffsets; @@ -983,6 +985,14 @@ private: }; static void CloseSubMenus( int flags, CMenuContainer *pAfter ); + struct CreateAccessibleData + { + CMenuContainer *pMenu; + IStream *pStream; + }; + static HRESULT __stdcall CreateAccessible( ComCallData *pData ); + static HRESULT __stdcall ReleaseAccessible( ComCallData *pData ); + // To control the placement of the start menu, send ClassicStartMenu.StartMenuMsg message right after the start menu is created but before it is displayed // The lParam must point to StartMenuParams // monitorRect - the entire area available to the start menu (sub-menus will use it). It is usually the monitor area but can be less if the Desktop app is docked in Win8