TVNODE.CPP
/////////////////////////////////////////////////////////////////////// 
// 
//  TVNODE.CPP 
// 
// 
//  Copyright 1986-1996 Microsoft Corporation. All Rights Reserved. 
/////////////////////////////////////////////////////////////////////// 
 
 
#define STRICT 
#include <windows.h> 
#include <commctrl.h> 
#include <mapix.h> 
#include <mapiutil.h> 
#include <mapidbg.h> 
#include "lasterr.h" 
#include "tvdlg.h" 
 
 
LPSTR g_szNoFolderName = "<No Name>"; 
 
// 
//  CTVNode::CTVNode 
// 
CTVNode::CTVNode(LPSPropValue pval, ULONG cProps, LPMDB pmdb) 
{ 
    Assert(cProps == nhtProps); 
    Assert(pval); 
 
    m_pval = pval; 
 
    m_htiMe = NULL; 
         
    m_fKidsLoaded = FALSE; 
 
    m_pfld = NULL; 
 
    m_pNext = NULL; 
 
    m_pmdb = pmdb; 
    if(pmdb) 
        pmdb->AddRef(); 
 
} 
 
// 
//  CTVNode::~CTVNode 
// 
CTVNode::~CTVNode() 
{ 
    MAPIFreeBuffer(m_pval); 
    UlRelease(m_pfld); 
    UlRelease(m_pmdb); 
} 
 
 
// 
//  CTVNode::HrExpand 
// 
//  Put all kids of the given folder in the tree control 
// 
HRESULT CTVNode::HrExpand(CChsFldDlg * pCFDlg) 
{ 
    HRESULT hr; 
    LPMAPITABLE ptblHier = NULL; 
    LPSRowSet pRowSet = NULL; 
    UINT ind; 
     
    static SSortOrderSet sosName; 
 
    sosName.cSorts = 1; 
    sosName.cCategories = 0; 
    sosName.cExpanded = 0; 
    sosName.aSort[0].ulPropTag = PR_DISPLAY_NAME; 
    sosName.aSort[0].ulOrder = TABLE_SORT_ASCEND; 
 
 
    Assert(m_htiMe); 
     
    if(m_fKidsLoaded || !m_pval[iSubfldrs].Value.b) 
        return hrSuccess; 
 
    if(!m_pmdb) 
    { 
    // this node corresponds to the top level of a message store which has 
    // not been opend yet. 
    // m_pval[iEID] contains entry ID of the message store 
    //  
        hr = HrOpenMDB(pCFDlg); 
        if(FAILED(hr)) 
            goto err; 
    } 
     
    Assert(m_pmdb);      
     
    if(!m_pfld) 
    { 
        hr = HrOpenFolder(pCFDlg); 
        if(FAILED(hr)) 
            goto err; 
    } 
 
    Assert(m_pfld);  
     
    hr = m_pfld->GetHierarchyTable(MAPI_DEFERRED_ERRORS, &ptblHier); 
    if(HR_FAILED(hr)) 
    { 
        pCFDlg->m_lsterr.HrSetLastError(hr, m_pfld); 
        pCFDlg->m_lsterr.ShowError(pCFDlg->hwDialog()); 
         
        goto err; 
    } 
 
    hr = HrQueryAllRows(ptblHier, (LPSPropTagArray)&spthtProps, NULL, &sosName, 
                        0, &pRowSet); 
    if(HR_FAILED(hr)) 
        goto err; 
 
    if(0 == pRowSet->cRows) 
    { 
        m_pval[iSubfldrs].Value.b = FALSE; 
        goto err; 
    } 
 
    for(ind = 0; ind < pRowSet->cRows; ++ind) 
    { 
        LPSPropValue pval = pRowSet->aRow[ind].lpProps; 
         
        Assert(pRowSet->aRow[ind].cValues == nhtProps); 
        Assert(pval[iEID].ulPropTag == PR_ENTRYID); 
        Assert(pval[iDispName].ulPropTag == PR_DISPLAY_NAME); 
        Assert(pval[iSubfldrs].ulPropTag == PR_SUBFOLDERS); 
 
        LPTVNODE pNode = NULL; 
 
        hr = pCFDlg->HrCreateNode(pval, nhtProps, m_pmdb, &pNode); 
        if(hr) 
            goto err; 
     
        //this row will be freed in ~CTVNode 
        pRowSet->aRow[ind].cValues = 0; 
        pRowSet->aRow[ind].lpProps = NULL; 
 
        HTREEITEM hItem; 
         
        hItem = AddOneItem(m_htiMe,  TVI_LAST, pCFDlg->IndClsdFld(), 
                            pCFDlg->IndOpenFld(), pCFDlg->hwTreeCtl(), pNode, 
                            pval[iSubfldrs].Value.b? 1: 0); 
        if(!hItem) 
        { 
            hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); 
            goto err; 
        } 
             
    } 
 
    m_fKidsLoaded = TRUE; 
 
err: 
    UlRelease(ptblHier); 
    FreeProws(pRowSet); 
 
    DebugTraceResult(CTVNode::HrExpand, hr); 
    return hr; 
} 
 
// 
//  CTVNode::HrOpenMDB 
// 
HRESULT CTVNode::HrOpenMDB(CChsFldDlg * pCFDlg) 
{ 
    HRESULT hr; 
    LPMDB pmdb = NULL; 
    LPSPropValue pvalIPM = NULL; 
    ULONG ulObjType; 
     
    Assert(m_pval[iEID].ulPropTag == PR_ENTRYID); 
 
    DebugTrace("ChsFld: Openning Msg Store: %s\n", GetName()); 
     
    hr = pCFDlg->Session()->OpenMsgStore(0L, m_pval[iEID].Value.bin.cb, 
                                (LPENTRYID)m_pval[iEID].Value.bin.lpb, 
                                NULL, MAPI_BEST_ACCESS, &pmdb); 
    if(hr) //Display warning messages too 
    { 
        pCFDlg->m_lsterr.HrSetLastError(hr, pCFDlg->Session()); 
        pCFDlg->m_lsterr.ShowError(pCFDlg->hwDialog()); 
    } 
 
    if(HR_FAILED(hr)) 
        goto err; 
 
    hr = HrGetOneProp(pmdb, PR_IPM_SUBTREE_ENTRYID, &pvalIPM); 
    if(hr) 
    { 
        pCFDlg->m_lsterr.HrSetLastError(hr, pmdb); 
        pCFDlg->m_lsterr.ShowError(pCFDlg->hwDialog()); 
 
        goto err; 
    } 
 
    hr = pmdb->OpenEntry(pvalIPM->Value.bin.cb, 
                (LPENTRYID)pvalIPM->Value.bin.lpb, 
                NULL, MAPI_BEST_ACCESS | MAPI_DEFERRED_ERRORS, 
                 &ulObjType, (LPUNKNOWN *) &m_pfld); 
    if(HR_FAILED(hr)) 
    { 
        pCFDlg->m_lsterr.HrSetLastError(hr, pmdb); 
        pCFDlg->m_lsterr.ShowError(pCFDlg->hwDialog()); 
         
        goto err; 
    } 
     
    Assert(MAPI_FOLDER == ulObjType); 
 
/*  if(pvalIPM->Value.bin.cb > m_pval[iEID].Value.bin.cb) 
    { 
        if(hr = MAPIAllocateMore(pvalIPM->Value.bin.cb, 
                        m_pval, (LPVOID *)&m_pval[iEID].Value.bin.lpb)) 
            goto err; 
                 
    } 
 
    CopyMemory(m_pval[iEID].Value.bin.lpb, pvalIPM->Value.bin.lpb, 
                                        pvalIPM->Value.bin.cb); 
    m_pval[iEID].Value.bin.cb = pvalIPM->Value.bin.cb;*/ 
 
err: 
    if(HR_FAILED(hr)) 
    { 
        UlRelease(pmdb); 
        UlRelease(m_pfld); 
        m_pfld = NULL; 
    } 
    else 
    { 
        m_pmdb = pmdb; 
        hr = hrSuccess; //don't return warnings 
    } 
 
    MAPIFreeBuffer(pvalIPM); 
 
    DebugTraceResult(CTVNode::HrOpenMDB, hr); 
    return hr; 
} 
 
// 
//  CTVNode::HrOpenFolder 
// 
HRESULT CTVNode::HrOpenFolder(CChsFldDlg * pCFDlg) 
{ 
    HRESULT hr; 
    ULONG ulObjType; 
 
    Assert(m_pval[iEID].ulPropTag == PR_ENTRYID); 
    Assert(m_pmdb); 
     
    // MAPI_MODIFY flag affects only IMAPIProp interface of the object. 
    // It does not guarantee permission to create subfolders. 
    hr = m_pmdb->OpenEntry(m_pval[iEID].Value.bin.cb, 
                (LPENTRYID)m_pval[iEID].Value.bin.lpb, 
                NULL, MAPI_BEST_ACCESS | MAPI_DEFERRED_ERRORS, 
                 &ulObjType, (LPUNKNOWN *) &m_pfld); 
    if(HR_FAILED(hr)) 
    { 
        pCFDlg->m_lsterr.HrSetLastError(hr, m_pmdb); 
        pCFDlg->m_lsterr.ShowError(pCFDlg->hwDialog()); 
         
        goto err; 
    } 
     
    Assert(MAPI_FOLDER == ulObjType); 
err: 
 
    DebugTraceResult(CTVNode::HrOpenFolder, hr); 
    return hr; 
 
} 
 
// 
//  CTVNode::HrGetFolder 
// 
//  return folder interface for the node 
HRESULT CTVNode::HrGetFolder(CChsFldDlg * pCFDlg, 
                            LPMAPIFOLDER * ppfld, LPMDB *ppmdb) 
{ 
    HRESULT hr = hrSuccess; 
     
    Assert(pCFDlg); 
    Assert(ppfld); 
    Assert(ppmdb); 
 
 
    if(!m_pmdb) 
    { 
        hr = HrOpenMDB(pCFDlg); 
        if(FAILED(hr)) 
            goto err; 
    } 
    Assert(m_pmdb); 
     
    if(!m_pfld) 
    { 
        Assert(!m_fKidsLoaded); 
         
        hr = HrOpenFolder(pCFDlg); 
        if(FAILED(hr)) 
            goto err; 
 
    } 
    Assert(m_pfld); 
 
    *ppfld = m_pfld; 
    m_pfld->AddRef(); 
 
    m_pmdb->AddRef(); 
    *ppmdb = m_pmdb;             
 
err: 
 
    DebugTraceResult(CTVNode::HrGetFolder, hr); 
    return hr; 
} 
 
 
// 
//  CTVNode::HrNewFolder 
// 
// Create subfolder szFldName 
// 
HRESULT CTVNode::HrNewFolder(CChsFldDlg * pCFDlg, 
                                     LPSTR szFldName) 
{ 
    HRESULT hr; 
    LPMAPIFOLDER pfldNew = NULL; 
    LPTVNODE pNode = NULL; 
    LPSPropValue pval = NULL; 
    HTREEITEM hItem; 
 
    Assert(szFldName); 
    Assert(pCFDlg); 
     
 
    if(!m_pmdb) 
    { 
        hr = HrOpenMDB(pCFDlg); 
        if(FAILED(hr)) 
            goto err; 
    } 
 
    Assert(m_pmdb); 
     
    if(!m_pfld) 
    { 
        hr = HrOpenFolder(pCFDlg); 
        if(FAILED(hr)) 
            goto err; 
    } 
 
    Assert(m_pmdb); 
     
    hr = m_pfld->CreateFolder(FOLDER_GENERIC, szFldName, NULL, 
                                NULL, 0, &pfldNew); 
    if(HR_FAILED(hr)) 
    { 
        pCFDlg->m_lsterr.HrSetLastError(hr, m_pfld); 
        pCFDlg->m_lsterr.ShowError(pCFDlg->hwDialog()); 
 
        goto err; 
    } 
 
    if(!m_pval[iSubfldrs].Value.b) 
    { 
        m_pval[iSubfldrs].Value.b = TRUE; 
 
        TV_ITEM tvI; 
 
        tvI.hItem           = m_htiMe; 
        tvI.mask            = TVIF_CHILDREN; 
        tvI.cChildren       = 1; 
 
        TreeView_SetItem(pCFDlg->hwTreeCtl(), &tvI); 
    } 
 
    if(m_fKidsLoaded) 
    { 
        hr = MAPIAllocateBuffer(sizeof(SPropValue)* nhtProps, (LPVOID *)&pval); 
        if(hr) 
            goto err; 
 
        ZeroMemory(pval, sizeof(SPropValue) * nhtProps ); 
 
        pval[iEID].ulPropTag = PR_ENTRYID; 
        pval[iDispName].ulPropTag = PR_DISPLAY_NAME; 
        pval[iSubfldrs].ulPropTag = PR_SUBFOLDERS; 
 
        pval[iSubfldrs].Value.b = FALSE; 
 
        int cb = lstrlen(szFldName) + 1; 
        hr = MAPIAllocateMore(cb, pval, (LPVOID *)&pval[iDispName].Value.lpszA); 
        if(hr)  
            goto err; 
 
        lstrcpy(pval[iDispName].Value.lpszA, szFldName); 
 
        hr = pCFDlg->HrCreateNode(pval, nhtProps, m_pmdb, &pNode); 
        if(HR_FAILED(hr)) 
            goto err; 
 
        pval = NULL; 
 
        hItem = AddOneItem(m_htiMe,  TVI_SORT, pCFDlg->IndClsdFld(), 
                        pCFDlg->IndOpenFld(), pCFDlg->hwTreeCtl(), pNode, 0); 
        if(!hItem) 
        { 
            hr = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY); 
            goto err; 
        } 
             
        pNode->m_pfld = pfldNew; 
        pfldNew = NULL; 
         
    } 
 
err: 
    MAPIFreeBuffer(pval); 
    UlRelease(pfldNew); 
 
    DebugTraceResult(CTVNode::HrNewFolder, hr); 
    return hr; 
} 
 
// 
//  CTVNode::Write 
// 
// Used in CChsFldDlg::HrSaveTreeState 
void CTVNode::Write(BOOL fWrite, LONG iLevel, LPBYTE * ppb) 
{ 
    if(fWrite) 
        *((LONG *)*ppb) = iLevel; 
    *ppb += sizeof(LONG); 
 
    if(iLevel != 0) 
    { 
        ULONG cb = m_pval[iEID].Value.bin.cb; 
         
        if(fWrite) 
            *((ULONG *)*ppb) = cb; 
        *ppb += sizeof(ULONG); 
 
        if(fWrite) 
            CopyMemory(*ppb, m_pval[iEID].Value.bin.lpb, cb); 
        *ppb += Align4(cb); 
    } 
    else 
    { 
        Assert(m_pval[iDispName].Value.lpszA == g_szAllStores); 
    } 
 
} 
 
LPVOID CTVNode::operator new( size_t cb ) 
{ 
    LPVOID pv; 
 
    if ( MAPIAllocateBuffer( (ULONG)cb, &pv ) ) 
        pv = NULL; 
 
    return pv;  
} 
 
void CTVNode::operator delete( LPVOID pv ) 
{ 
    MAPIFreeBuffer( pv ); 
}