Sandeep Kumar
Sandeep Kumar

Reputation: 105

Retrieving the LPARAM with an item in treectrl using CTreeCtrl

I have to add a list of sub keys recursively to an item in a Tree control. I am using InsertItem as shown below. I am attaching the path of this element so that i can retrieve when clicked on the tree control.I am able to add the value but not able to retrieve it.

void CMyDlg::FillTreeWithRegistryKeysEx(CString sPath, HTREEITEM hItem)
{
    CString sRegKey = sPath.Left(sPath.Find(_T("\\")));
    sPath = sPath.Mid((sPath.Find(_T("\\")) + 1));
    sPath = CleanRegistryKey(sPath);

    int nKeyCount;
    CString  sSubKey = _T("");
    HKEY handle = GetHkey(sRegKey);
    HTREEITEM hReItem = NULL;
    HKEY phkey;

    std::vector<CString> sSubFolders;

    if (RegOpenKeyEx(handle, sPath, 0, KEY_ALL_ACCESS, &phkey) == ERROR_SUCCESS)
        sSubFolders = EnumRegistryKey(phkey);

    nKeyCount = sSubFolders.size();

    for (int nIndex = 0; nIndex < nKeyCount; nIndex++)
    {
        sSubKey = sPath + _T("\\") +sSubFolders.at(nIndex);
        hReItem = m_cTreeCtrl.InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_STATE, sSubFolders.at(nIndex), 
                                        icoClosedFolder, icoOpenFolder, 0, 0, (LPARAM)(LPCTSTR)sSubKey, hItem, TVI_LAST);

        FillTreeWithRegistryKeys(handle, sSubKey, hReItem);
    }
    RegCloseKey(phkey);
}


While retrieving the string is always blank.

void CMyDlg::OnTvnSelchangedTree(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);

    LPARAM lp = pNMTreeView->itemNew.lParam;
    CString sKey = (LPCTSTR)lp;
}


what is going wrong? 

Upvotes: 1

Views: 1051

Answers (2)

Barmak Shemirani
Barmak Shemirani

Reputation: 31669

As pointed out in previous answer, you are using LPARAM to point to a string which is destroyed when the function exits. The solution is store the strings in permanent storage. There are many ways to do this. One option is to use CStringArray member data:

class CMyDlg : public CDialog
{
    CStringArray m_strings;
    ...
};
  • Store the registry keys in m_strings.
  • Add the tree item with InsertItem, this returns HTREEITEM.
  • Use tree.SetItemData to match the tree item with an index in m_strings
  • Use tree.GetItemData to retrieve that index

Example:

BOOL CMyDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    ...
    m_strings.RemoveAll();
    addKey(L"SOFTWARE\\Microsoft\\Internet Explorer", tree.GetRootItem());
    return TRUE;
}

void CMyDlg::addKey(CString path, HTREEITEM parent)
{
    CRegKey rg;
    if (ERROR_SUCCESS != rg.Open(HKEY_CURRENT_USER, path))
        return;
    for (int i = 0;; i++)
    {
        wchar_t buf[300];
        DWORD bufsize = 300;
        if (rg.EnumKey(i, buf, &bufsize) != ERROR_SUCCESS) break;
        HTREEITEM hitem = tree.InsertItem(buf, parent);
        CString subkey = path + L"\\" + buf;
        m_strings.Add(subkey);
        tree.SetItemData(hitem, m_strings.GetCount() - 1);
        addKey(subkey, hitem);
    }
}

void CMyDlg::OnTvnSelchangedTree(NMHDR *pNMHDR, LRESULT *pResult)
{
    HTREEITEM hitem = tree.GetSelectedItem();
    if (!hitem) return;
    int i = tree.GetItemData(hitem);
    if (i >= 0 && i < m_strings.GetCount())
        SetWindowText(m_strings[i]);
}

Upvotes: 1

byteptr
byteptr

Reputation: 1385

The application-defined LPARAM passed to InsertItem is a string object that goes out of scope once the function completes not to mention it is replaced with each loop iteration with a new string. I don't think that is going to work.

The TreeView control however allocates its own copy of the text, so you are safe to fill in the pszText member with local buffers as it appears you are doing.

Upvotes: 2

Related Questions