From eb7ffe2cdc077fd17b1fd8ef72f03d4b96f13c4e Mon Sep 17 00:00:00 2001 From: Justin Marshall Date: Mon, 18 May 2026 14:15:34 -0700 Subject: [PATCH] Fixed crash bug in new decl editor. --- neo/engine/tools/decl/DialogDeclBrowser.cpp | 114 ++++++++++---------- 1 file changed, 59 insertions(+), 55 deletions(-) diff --git a/neo/engine/tools/decl/DialogDeclBrowser.cpp b/neo/engine/tools/decl/DialogDeclBrowser.cpp index ab054a4e..aad90342 100644 --- a/neo/engine/tools/decl/DialogDeclBrowser.cpp +++ b/neo/engine/tools/decl/DialogDeclBrowser.cpp @@ -32,6 +32,7 @@ If you have questions concerning this license or the applicable additional terms #include "../radiant/qe3.h" #include "DialogDeclBrowser.h" #include "../radiant/InspectorDialog.h" +#include #ifdef ID_DEBUG_MEMORY #undef new @@ -76,6 +77,10 @@ static const UINT IDC_DECLBROWSER_CHILD_EDITOR = 0x5C0B; static const char *DECL_BROWSER_DARK_FIELD_OLDPROC = "IceTech.DeclBrowser.DarkFieldOldProc"; +#ifndef TVS_NOTOOLTIPS +#define TVS_NOTOOLTIPS 0x0080 +#endif + toolTip_t DialogDeclBrowser::toolTips[] = { { IDC_DECLBROWSER_CHILD_TREE, "declaration browser" }, { IDC_DECLBROWSER_CHILD_FIND_NAME, "search for declarations with matching name, supports *, ? and [abc...]" }, @@ -268,7 +273,6 @@ int DialogDeclBrowser::OnCreate( LPCREATESTRUCT lpCreateStruct ) { } CreateChildControls(); - EnableToolTips( TRUE ); ApplyDarkTheme(); PopulateTypeCombo(); InitBaseDeclTree(); @@ -291,8 +295,8 @@ void DialogDeclBrowser::CreateChildControls( void ) { DWORD editStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL; DWORD buttonStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON; - declTree.Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS, r, this, IDC_DECLBROWSER_CHILD_TREE ); - baseDeclTree.Create( WS_CHILD | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS, r, this, IDC_DECLBROWSER_CHILD_BASE_TREE ); + declTree.Create( WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS, r, this, IDC_DECLBROWSER_CHILD_TREE ); + baseDeclTree.Create( WS_CHILD | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_NOTOOLTIPS, r, this, IDC_DECLBROWSER_CHILD_BASE_TREE ); findNameStatic.Create( "Name", staticStyle, r, this ); findTextStatic.Create( "Text", staticStyle, r, this ); @@ -380,9 +384,11 @@ void DialogDeclBrowser::ApplyDarkTheme( void ) { for( HWND child = ::GetWindow( GetSafeHwnd(), GW_CHILD ); child != NULL; child = ::GetWindow( child, GW_HWNDNEXT ) ) { DeclBrowserApplyNativeDarkTheme( child ); - if ( DeclBrowserIsClass( child, "Edit" ) || DeclBrowserIsClass( child, "SysTreeView32" ) || DeclBrowserIsClass( child, "ComboBox" ) ) { + if ( DeclBrowserIsClass( child, "Edit" ) ) { + DeclBrowserRemoveClientEdge( child ); + } else if ( DeclBrowserIsClass( child, "SysTreeView32" ) || DeclBrowserIsClass( child, "ComboBox" ) ) { + // Keep tree/combo controls native-subclass free; the tree owns its tooltip path. DeclBrowserRemoveClientEdge( child ); - DeclBrowserSubclassField( child ); } } @@ -394,42 +400,16 @@ void DialogDeclBrowser::ApplyDarkTheme( void ) { } BOOL DialogDeclBrowser::OnToolTipNotify( UINT id, NMHDR *pNMHDR, LRESULT *pResult ) { - if ( pNMHDR->hwndFrom == declTree.GetSafeHwnd() ) { - CString toolTip; - const idDecl *decl = GetDeclFromTreeItem( (HTREEITEM)pNMHDR->idFrom ); - if ( !decl ) { - return FALSE; - } - toolTip = va( "%s, line: %d", decl->GetFileName(), decl->GetLineNum() ); + if ( pResult ) { + *pResult = 0; + } - TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR; - TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR; -#ifndef _UNICODE - if( pNMHDR->code == TTN_NEEDTEXTA ) { - delete m_pchTip; - m_pchTip = new char[toolTip.GetLength() + 2]; - lstrcpyn( m_pchTip, toolTip, toolTip.GetLength() + 1 ); - pTTTA->lpszText = (LPSTR)m_pchTip; - } else { - delete m_pwchTip; - m_pwchTip = new WCHAR[toolTip.GetLength() + 2]; - _mbstowcsz( m_pwchTip, toolTip, toolTip.GetLength() + 1 ); - pTTTW->lpszText = (WCHAR*)m_pwchTip; - } -#else - if( pNMHDR->code == TTN_NEEDTEXTA ) { - delete m_pchTip; - m_pchTip = new char[toolTip.GetLength() + 2]; - _wcstombsz( m_pchTip, toolTip, toolTip.GetLength() + 1 ); - pTTTA->lpszText = (LPSTR)m_pchTip; - } else { - delete m_pwchTip; - m_pwchTip = new WCHAR[toolTip.GetLength() + 2]; - lstrcpyn( m_pwchTip, toolTip, toolTip.GetLength() + 1 ); - pTTTW->lpszText = (WCHAR*)m_pwchTip; - } -#endif - return TRUE; + // CPathTreeCtrl already owns its per-item tooltip forwarding. Calling + // TreeView APIs from inside the forwarded TTN_NEEDTEXT path can re-enter + // comctl32 and hang the docked inspector, so the docked browser only uses + // static control tooltips here. + if ( pNMHDR && pNMHDR->hwndFrom == declTree.GetSafeHwnd() ) { + return FALSE; } return DefaultOnToolTipNotify( toolTips, id, pNMHDR, pResult ); @@ -650,22 +630,37 @@ void DialogDeclBrowser::GetDeclName( HTREEITEM item, idStr &typeName, idStr &dec } const idDecl *DialogDeclBrowser::GetDeclFromTreeItem( HTREEITEM item ) const { - int id, index; - declType_t type; - - if ( !item || declTree.GetChildItem( item ) ) { + if ( !item || !declTree.GetSafeHwnd() ) { return NULL; } - id = declTree.GetItemData( item ); - type = GetTypeFromId( id ); - index = GetIndexFromId( id ); + TVITEM tvItem; + memset( &tvItem, 0, sizeof( tvItem ) ); + tvItem.mask = TVIF_PARAM | TVIF_CHILDREN; + tvItem.hItem = item; - if ( type < 0 || type >= declManager->GetNumDeclTypes() ) { + if ( !::SendMessage( declTree.GetSafeHwnd(), TVM_GETITEM, 0, (LPARAM)&tvItem ) ) { return NULL; } - return declManager->DeclByIndex( type, index, false ); + if ( tvItem.cChildren != 0 ) { + return NULL; + } + + const int id = (int)tvItem.lParam; + declType_t type = GetTypeFromId( id ); + const int index = GetIndexFromId( id ); + + if ( type < 0 || type >= declManager->GetNumDeclTypes() || index < 0 || index >= declManager->GetNumDecls( type ) ) { + return NULL; + } + + const idDecl *decl = declManager->DeclByIndex( type, index, false ); + if ( !decl || decl->GetType() != type || decl->Index() != index ) { + return NULL; + } + + return decl; } const idDecl *DialogDeclBrowser::GetSelectedDecl( void ) const { @@ -680,14 +675,23 @@ bool DialogDeclBrowser::CompareDecl( HTREEITEM item, const char *name ) const { } if ( findTextString.Length() ) { - int id, index; - declType_t type; + TVITEM tvItem; + memset( &tvItem, 0, sizeof( tvItem ) ); + tvItem.mask = TVIF_PARAM | TVIF_CHILDREN; + tvItem.hItem = item; - id = declTree.GetItemData( item ); - type = GetTypeFromId( id ); - index = GetIndexFromId( id ); + if ( !baseDeclTree.GetSafeHwnd() || !::SendMessage( baseDeclTree.GetSafeHwnd(), TVM_GETITEM, 0, (LPARAM)&tvItem ) ) { + return false; + } + if ( tvItem.cChildren != 0 ) { + return false; + } - if ( type < 0 || type >= declManager->GetNumDeclTypes() ) { + const int id = (int)tvItem.lParam; + declType_t type = GetTypeFromId( id ); + const int index = GetIndexFromId( id ); + + if ( type < 0 || type >= declManager->GetNumDeclTypes() || index < 0 || index >= declManager->GetNumDecls( type ) ) { return false; }