2016-04-26 6 views
1

Folgendes funktioniert im 32-Bit-Modus, aber nicht in 64-Bit, für TVN_ITEMEXPANDING Mausklick & Tastaturereignisse.I_CHILDRENCALLBACK 64bit fehlgeschlagen

Object.h

afx_msg void OnTvnItemexpandingTreectrl(NMHDR *pNMHDR, LRESULT *pResult); 

Object.cpp

BEGIN_MESSAGE_MAP(Object, CDialogEx) 
     ON_NOTIFY(TVN_ITEMEXPANDING, IDC_TREECTRL, OnTvnItemexpandingTreectrl) 
    END_MESSAGE_MAP() 


void Object::LoadTree() 
{ 
    m_TreeCtrl1.DeleteAllItems(); 

    HTREEITEM hParentItem = TVI_ROOT; 

    std::list<OBJ>::iterator itObj = m_Obj.begin()->m_Obj.begin(); 
    for (size_t i = 0; i < m_Obj.begin()->m_Obj.size(); i++, ++itObj) 
    { 
     TVINSERTSTRUCT tvis; 
     TVITEM tvItem = { 0 }; 

     tvItem.mask = LVIF_TEXT | LVIF_PARAM | TVIF_CHILDREN | TVIF_HANDLE | TVIF_STATE; 
     tvItem.cChildren = I_CHILDRENCALLBACK; 

     tvItem.pszText = itObj->m_TreeDesc.GetBuffer(); 
     tvItem.cchTextMax = MAX_ITEMLEN; 
     tvItem.lParam = reinterpret_cast<LPARAM>(&*itObj); 
     tvis.item = tvItem; 
     tvis.hParent = TVI_ROOT; 
     tvis.hInsertAfter = TVI_LAST; 
     hParentItem = m_TreeCtrl1.InsertItem(&tvis); 
     RecurseBuildTree(itObj->m_Obj, m_TreeCtrl1, hParentItem, TVI_LAST); 
    } 

    hParentItem = m_TreeCtrl1.GetFirstVisibleItem(); 
    for (size_t i = 0; i < m_Obj.begin()->m_Obj.size(); i++) 
    { 
     HTREEITEM hNext = hParentItem; 
     OBJ *pObjNext = reinterpret_cast<OBJ*>(m_TreeCtrl1.GetItemData(hNext)); 
     m_TreeCtrl1.SetCheck(hNext, pObjNext->m_bItemDisplayed); 
     RecurseTreeSetCheck(m_TreeCtrl1, hParentItem); 
     hParentItem = m_TreeCtrl1.GetNextItem(hNext, TVGN_NEXT); 
    } 
} 


    void Object::OnTvnItemexpandingTreectrl(NMHDR *pNMHDR, LRESULT *pResult) 
    { 
     LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR); 
     *pResult = 0; 
    } 


    void ExpandTreeItem(CTreeCtrl &tree, HTREEITEM hItem, UINT nCode) 
    { 
     HTREEITEM hChild; 
     if (tree.ItemHasChildren(hItem)) 
     { 
      tree.Expand(hItem, nCode); 
      hChild = tree.GetChildItem(hItem); 

      while (hChild) 
      { 
       ExpandTreeItem(tree, hChild, nCode); 
       hChild = tree.GetNextItem(hChild, TVGN_NEXT); 
      } 
     } 
    } 


void Object::ToggleItemState(HTREEITEM hti, CTreeCtrl &treectrl, const HTREEITEM hParentNode) 
{ 
    if (hti == hParentNode) 
    { 
     const int iImage = treectrl.GetItemState(hParentNode, TVIS_STATEIMAGEMASK) >> 12; 
     OBJ *pObj = reinterpret_cast<OBJ*>(treectrl.GetItemData(hti)); 
     pObj->m_bItemDisplayed = (iImage == 1 ? 2 : 1); 
    } 
    else 
    { 
     const int iImage = treectrl.GetItemState(hParentNode, TVIS_STATEIMAGEMASK) >> 12; 
     treectrl.SetItemState(hti, INDEXTOSTATEIMAGEMASK(iImage == 1 ? 2 : 1), TVIS_STATEIMAGEMASK); 
     OBJ *pObj = reinterpret_cast<OBJ*>(treectrl.GetItemData(hti)); 
     pObj->m_bItemDisplayed = (iImage == 1 ? 2 : 1); 
    } 

    if (treectrl.ItemHasChildren(hti)) //failing in release mode for root level node. 
    { 
     HTREEITEM htiChild = treectrl.GetChildItem(hti); 

     if (htiChild) 
      ToggleItemState(htiChild, treectrl, hParentNode); 
     else 
      return; 
     HTREEITEM htiSibling = treectrl.GetNextSiblingItem(htiChild); 
     while (htiSibling) 
     { 
      ToggleItemState(htiSibling, treectrl, hParentNode); 
      htiSibling = treectrl.GetNextSiblingItem(htiSibling); 
     } 
    } 
} 

Beobachtungen:

Es folgt in 64-Bit-Freigabemodus versagt aber nur für root node:

if (treectrl.ItemHasChildren(hti)) 

I-Taste, die ExpandTreeItem manuell() aufrufen können & tree.Expand() ruft OnTvnItemexpandingTreectrl(), aber in 64-Bit-Modus Maus & Tastatur ruft nicht TVN_ITEMEXPANDING, für andere Veranstaltungen es funktioniert gut.

Ich vermute, dass es etwas zu tun mit der Initialisierung von

TVINSERTSTRUCT tvis; 
    TVITEM tvItem = { 0 }; 

wissen kann, aber nicht wirklich das, was ich suche.

Lassen Sie mich wissen, wenn ich mehr Code schreiben muss.

Danke

+0

Scannen durch den Code Ich sehe 'm_TreeDesc.GetBuffer()' aber es gibt keine 'ReleaseBuffer()' –

+0

ReleaseBuffer wird nicht benötigt, weil die Länge nicht ändert ...Die Dokumentation sagt uns dies zu tun, aber die Implantation zeigt, dass dies nur benötigt wird, wenn sich die Länge ändert. (Und das ist seit MFC 1.0 der Fall) Also ja, es sollte getan werden, und Nein, es ist kein möglicher Grund für einen Fehler. – xMRi

Antwort

0

denken, dass ich die Ursache gefunden haben:

tvItem.cChildren = I_CHILDRENCALLBACK; //<<failing in 64bit mode. 
    //Upto 0xFFFFFFFE works ok but not -1? 

Nach minimalem Code das Problem zu replizieren verwendet werden kann:

//header 
struct ItemData 
{ 
    CString Name; 
    int  Value; 

    CString ToString() const 
    { 
     CString str; 
     str.Format(_T("%s = %d"), Name, Value); 
     return str; 
    } 
}; 


CTreeCtrl m_tree; 
std::vector<ItemData*> m_data; 


//source 
void CTreeSortDemoDlg::DoDataExchange(CDataExchange* pDX) 
{ 
    CDialog::DoDataExchange(pDX); 
    DDX_Control(pDX, IDC_TREE, m_tree); 
} 

void CTreeSortDemoDlg::GenerateTreeContent() 
{ 
    ItemData* data1 = new ItemData; 
    data1->Value = 3; 
    data1->Name.Format(_T("%c%c"), 'P', data1->Value); 
    m_data.push_back(data1); 
    m_data.push_back(data1); 

    ItemData* data2 = new ItemData; 
    data2->Value = 3; 
    data2->Name.Format(_T("%c%c"), 'P', data2->Value); 
    m_data.push_back(data2); 
    m_data.push_back(data2); 

    HTREEITEM hParentItem = TVI_ROOT; 

    TVINSERTSTRUCT tvis; 
    TVITEM tvItem = { 0 }; 

    tvItem.mask = LVIF_TEXT | LVIF_PARAM | TVIF_CHILDREN | TVIF_HANDLE | TVIF_STATE; 
    tvItem.cChildren = I_CHILDRENCALLBACK; //<<failing in 64bit mode. 1 works ok? 

    tvItem.pszText = L"Parent"; 
    tvItem.cchTextMax = MAX_PATH; 
    tvItem.lParam = reinterpret_cast<LPARAM>(&m_data); 
    tvis.item = tvItem; 
    tvis.hParent = TVI_ROOT; 
    tvis.hInsertAfter = TVI_LAST; 
    hParentItem = m_tree.InsertItem(&tvis); 

    ////// 
    TVINSERTSTRUCT tvis2; 
    TVITEM tvItem2 = { 0 }; 
    std::vector<ItemData*>::iterator itData = m_data.begin(); 

    tvItem2.mask = LVIF_TEXT | LVIF_PARAM | TVIF_HANDLE | TVIF_STATE; 
    tvItem2.cChildren = 0; 
    tvItem2.pszText = L"child"; 
    tvItem2.cchTextMax = MAX_PATH; 
    tvItem2.lParam = reinterpret_cast<LPARAM>(&itData); 
    tvis2.item = tvItem2; 

    tvis2.hParent = hParentItem; 
    tvis2.hInsertAfter = TVI_LAST; 
    HTREEITEM hItemThis = m_tree.InsertItem(&tvis2); 
} 

EDIT:

Wenn I_CHILDRENCALLBACK sein Bei der Baumgenerierung muss dann auch TVN_GETDISPINFO verwendet werden, dh

ON_NOTIFY(TVN_GETDISPINFO, IDC_TREE, OnGetdispinfoTreectrl) 


void CTreeSortDemoDlg::OnGetdispinfoTreectrl(NMHDR *pNMHDR, LRESULT *pResult) 
{ 
    LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR); 
    TVITEM* pItem = &(pTVDispInfo)->item; 

    ItemData *pData = reinterpret_cast<ItemData*>(pItem->lParam); 

    if (pItem->mask & TVIF_CHILDREN) 
    { 
     if (pData != NULL) 
     { 
      pItem->cChildren = I_CHILDRENCALLBACK; 
     } 
    } 
} 

Odd immer noch, wie Verhalten sich zeigt.

0

Ist die Lösung einfach das Design der Nachricht?

Hier ein Zitat in der Dokumentation bilden TVM_EXPAND

Wenn ein Element zuerst durch eine TVM_EXPAND Nachricht erweitert wird, erzeugt die Aktion TVN_ITEMEXPANDING und TVN_ITEMEXPANDED Benachrichtigungscodes und der TVIS_EXPANDEDONCE Staatsflagge des Elements gesetzt. Solange dieses Status-Flag gesetzt bleibt, erzeugen nachfolgende TVM_EXPAND-Nachrichten keine TVN_ITEMEXPANDING- oder TVN_ITEMEXPANDED-Benachrichtigungen. Um das Statusflag TVIS_EXPANDEDONCE zurückzusetzen, müssen Sie eine TVM_EXPAND-Nachricht mit den gesetzten Flags TVE_COLLAPSE und TVE_COLLAPSERESET senden. Der Versuch, TVIS_EXPANDEDONCE explizit einzustellen, führt zu unvorhersehbarem Verhalten.

+0

Wäre dies der Fall, hätten nicht beide 32 und 64 Bit das gleiche Problem? – ReturnVoid