home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / dbmsg / mapi / chsfld.cli / chsfld.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-11  |  28.4 KB  |  1,238 lines

  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. //      CHSFLD.CPP
  4. //
  5. //
  6. //  Copyright 1986-1996 Microsoft Corporation. All Rights Reserved.
  7. ///////////////////////////////////////////////////////////////////////
  8.  
  9.  
  10. #define STRICT
  11. #include <windows.h>
  12. #include <windowsx.h>
  13. #include <commctrl.h>
  14. #include <mapix.h>
  15. #include <mapiutil.h>
  16. #include <mapidbg.h>
  17. #include "chsfld.h"
  18. #include "lasterr.h"
  19. #include "tvdlg.h"
  20. #include "resource.h"
  21. #include "tvstack.h"
  22.  
  23.  
  24.  
  25. #define cImageHeight    16
  26. #define cImageWidth     16
  27. #define cImages         4
  28.  
  29. //globals
  30. LPSTR g_szAllStores = "All Message Stores";
  31. LPSTR g_szModuleName = "Choose Folder Dialog";
  32.  
  33. //functions used only in this file
  34. BOOL CALLBACK
  35. ChsFldDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
  36.  
  37. HRESULT HrGetNewName(HINSTANCE hInst, HWND hwParent, LPSTR * pszNewName);
  38.  
  39. BOOL CALLBACK
  40. NewNameDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
  41.  
  42.  
  43. //
  44. //  HrPickFolder
  45. //
  46. //  
  47. STDAPI
  48. HrPickFolder(HINSTANCE hInst, HWND hWnd, LPMAPISESSION pses, LPMAPIFOLDER * ppfld,
  49.                 LPMDB *ppmdb, ULONG * pcb, LPBYTE * ppb)
  50. {
  51.     HRESULT hr;
  52.     
  53.     //Assert(hInst);
  54.     
  55.     if((hWnd && !IsWindow(hWnd)) || (!pses) || (!ppfld) || (!ppmdb))
  56.     { 
  57.         DebugTraceResult(HrPickFolder, E_INVALIDARG);
  58.         return E_INVALIDARG;
  59.     }
  60.  
  61.     if(pcb && IsBadWritePtr(pcb, sizeof(ULONG)))
  62.     {
  63.         DebugTraceArg(HrPickFolder, "pcb not writable");
  64.         return E_INVALIDARG;
  65.     }
  66.  
  67.     if(pcb && (*pcb & 0x3))
  68.     {
  69.         DebugTraceArg(HrPickFolder, "pcb not multiple of 4");
  70.         return E_INVALIDARG;
  71.     }
  72.     
  73.     if(ppb && IsBadWritePtr(ppb, sizeof(LPBYTE)))
  74.     {
  75.         DebugTraceArg(HrPickFolder, "ppb not writable");
  76.         return E_INVALIDARG;
  77.     }
  78.  
  79.     if(ppb && pcb && IsBadWritePtr(*ppb, *pcb))
  80.     {
  81.         DebugTraceArg(HrPickFolder, "*pcb or *ppb");
  82.         return E_INVALIDARG;
  83.     }
  84.  
  85.     //////////////////////////////////////////////////////////////////////
  86.     // if you incorporate this code into you app, remove this and pass in
  87.     // the right hInst
  88.     // Start remove
  89.     hInst = GetModuleHandle("chsfld32.dll");
  90.     if(!hInst)
  91.     {
  92.         DebugTrace("GetModuleHandel failed\n");
  93.         DebugTraceResult(HrPickFolder, E_FAIL);
  94.         return E_FAIL;
  95.     }
  96.     // End remove
  97.     ///////////////////////////////////////////////////////////////////////
  98.  
  99.     //ULONG cb = 0;
  100.     //LPBYTE pb = NULL;
  101.     
  102.     CChsFldDlg PickDlg(pses, hInst, pcb, ppb);
  103.  
  104.     InitCommonControls();
  105.  
  106.     hr = PickDlg.HrPick(MAKEINTRESOURCE(IDD_CFDIALOG), hWnd,
  107.                         (DLGPROC)ChsFldDlgProc, ppfld, ppmdb);
  108.  
  109. /*  if(SUCCEEDED(hr))
  110.     {
  111.         (*ppfld)->Release();
  112.         (*ppmdb)->Release();
  113.     }
  114.     
  115.     CChsFldDlg PickDlg1(pses, hInst, pcb, ppb);
  116.  
  117.     hr = PickDlg1.HrPick(MAKEINTRESOURCE(IDD_CFDIALOG), hWnd,
  118.                         (DLGPROC)ChsFldDlgProc, ppfld, ppmdb);*/
  119.  
  120. //  if(!hr)
  121.     //  MAPIFreeBuffer(pb);
  122.         
  123.     DebugTraceResult(HrPickFolder, hr);
  124.     return hr;
  125. }
  126.  
  127.  
  128. //
  129. //  CChsFldDlg::CChsFldDlg
  130. //
  131. inline
  132. CChsFldDlg::CChsFldDlg(LPMAPISESSION pses, HINSTANCE hInst, ULONG * pcb,
  133.                         LPBYTE * ppb)   : m_lsterr(g_szModuleName)
  134. {
  135.     Assert(pses);
  136.     Assert(hInst);
  137.     
  138.     m_pses = pses;
  139.     pses->AddRef();
  140.  
  141.     m_hr = hrSuccess;
  142.     m_pfld = NULL;
  143.     m_pmdb = NULL;
  144.     m_hiRoot = NULL;
  145.     m_hInst = hInst;
  146.     m_hIml = NULL;
  147.     m_hDlg = NULL;
  148.     m_hwTreeCtl = NULL;
  149.     m_pcbState = pcb;
  150.     m_ppbState = ppb;
  151. }       
  152.  
  153. //
  154. //  CChsFldDlg::~CChsFldDlg
  155. //
  156. CChsFldDlg::~CChsFldDlg()
  157. {
  158.     UlRelease(m_pses);
  159.     UlRelease(m_pfld);
  160.     UlRelease(m_pmdb);
  161.  
  162.     if(m_hIml)
  163.         ImageList_Destroy(m_hIml);
  164. }
  165.  
  166.  
  167. //
  168. //  CChsFldDlg::SetFolder
  169. //
  170. //  Store the folder chosen by the user
  171. //
  172. inline void CChsFldDlg::SetFolder(LPMAPIFOLDER pfld, LPMDB pmdb)
  173. {
  174.     UlRelease(m_pfld);
  175.  
  176.     m_pfld = pfld;
  177.     
  178.     if(pfld)
  179.         pfld->AddRef();
  180.  
  181.     UlRelease(m_pmdb);
  182.  
  183.     m_pmdb = pmdb;
  184.     if(pmdb)
  185.         pmdb->AddRef();
  186. }
  187.  
  188.  
  189. //
  190. //  CChsFldDlg::HrPick
  191. //
  192. // The outmost method.
  193. //
  194. HRESULT CChsFldDlg::HrPick(LPCTSTR lpTemplateName, HWND hWnd,
  195.                 DLGPROC pfnDlgProc, LPMAPIFOLDER * ppfld, LPMDB *ppmdb)
  196. {
  197.     if(-1 == DialogBoxParam(m_hInst, lpTemplateName, hWnd, pfnDlgProc, (LPARAM) this))
  198.     {
  199.         DebugTraceSc(CChsDldDlg::HrPick, MAPI_E_NOT_ENOUGH_MEMORY);
  200.         return MAPI_E_NOT_ENOUGH_MEMORY;
  201.     }
  202.  
  203.     //m_hr is set inside the dialog
  204.     if(HR_SUCCEEDED(m_hr))
  205.     {
  206.         Assert(m_pfld);
  207.         m_pfld->AddRef();
  208.         *ppfld = m_pfld;
  209.  
  210.         Assert(m_pmdb);
  211.         m_pmdb->AddRef();
  212.         *ppmdb = m_pmdb;
  213.     }
  214.  
  215.     return m_hr;
  216. }
  217.  
  218. //
  219. //  CChsFldDlg::HrInitTree
  220. //
  221. // Called from WM_INITDIALOG. Opens all message stores in the profile and
  222. // puts the IPM subtrees in the tree control
  223. //
  224. HRESULT CChsFldDlg::HrInitTree(HWND hDlg, HWND hwTreeCtl)
  225. {
  226.     HRESULT     hr;
  227.     LPSPropValue pval = NULL;
  228.     LPTVNODE    pNode = NULL;
  229.     HTREEITEM   hiRoot = NULL;
  230.     HICON       hIcon = NULL;
  231.     
  232.     Assert(hDlg);
  233.     Assert(hwTreeCtl);
  234.  
  235.     m_hwTreeCtl = hwTreeCtl;
  236.     m_hDlg      = hDlg;
  237.     
  238.  
  239.     //
  240.     // Set up the image list
  241.     //
  242.     m_hIml = ImageList_Create(cImageWidth, cImageHeight, ILC_MASK, 
  243.                             cImages, 0);
  244.     if(!m_hIml)
  245.     {
  246.         hr = MAPI_E_NOT_ENOUGH_MEMORY;
  247.         goto err;
  248.     }
  249.  
  250.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_ALLSTORES));
  251.     m_iIconAllStores = ImageList_AddIcon(m_hIml, hIcon);
  252.     
  253.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_ROOTFLD));
  254.     m_iIconRootFld = ImageList_AddIcon(m_hIml, hIcon);
  255.     
  256.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_OPENFLD));
  257.     m_iIconOpenFld = ImageList_AddIcon(m_hIml, hIcon);
  258.     
  259.     hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_CLSDFLD));
  260.     m_iIconClsdFld = ImageList_AddIcon(m_hIml, hIcon);
  261.  
  262.     if(ImageList_GetImageCount(m_hIml) < cImages)
  263.     {
  264.         hr = MAPI_E_NOT_ENOUGH_MEMORY;
  265.         goto err;
  266.     }
  267.  
  268.  
  269.     TreeView_SetImageList(hwTreeCtl, m_hIml, TVSIL_NORMAL);
  270.     
  271.     //
  272.     // create the root tree node
  273.     // (fake a GetProps)
  274.     //
  275.     hr = MAPIAllocateBuffer(nhtProps * sizeof(SPropValue),
  276.                         (LPVOID *)&pval);
  277.     if(hr)
  278.     {
  279.         m_lsterr.HrSetLastError(hr);
  280.         m_lsterr.ShowError(hDlg);
  281.             
  282.         goto err;
  283.     }
  284.     
  285.  
  286.     ZeroMemory(pval, nhtProps * sizeof(SPropValue));
  287.  
  288.     //Set  proptags to make CNode constructor happy
  289.     pval[iEID].ulPropTag = PR_ENTRYID;
  290.     pval[iDispName].ulPropTag = PR_DISPLAY_NAME;
  291.     pval[iDispName].Value.lpszA = g_szAllStores;
  292.     pval[iSubfldrs].ulPropTag = PR_SUBFOLDERS;
  293.  
  294.     hr = HrCreateNode(pval, nhtProps, NULL, &pNode);
  295.     if(hr)
  296.         goto err;
  297.  
  298.     Assert(pNode);
  299.     
  300.     pval = NULL; //will be freed in ~CTVNode
  301.  
  302.     hiRoot = AddOneItem(NULL, TVI_ROOT, m_iIconAllStores, m_iIconAllStores,
  303.                             hwTreeCtl, pNode, 1);
  304.     if(!hiRoot)
  305.     {
  306.         hr = MAPI_E_NOT_ENOUGH_MEMORY;
  307.         goto err;
  308.     }
  309.     
  310.     pNode->SetKidsLoaded(TRUE);
  311.     
  312.     m_hiRoot = hiRoot;
  313.     
  314.     //
  315.     //  Put the IPM subtrees of all the message stores in
  316.     //
  317.     hr = HrLoadRoots();
  318.     if(HR_FAILED(hr))
  319.         goto err;
  320.  
  321.     (void)HrRestoreTreeState();
  322.         
  323. err:
  324.     MAPIFreeBuffer(pval);
  325.  
  326.     DebugTraceResult(CChsFldDlg::HrInitTree, hr);
  327.     return hr;
  328. }
  329.  
  330.  
  331. //
  332. //  CChsFldDlg::HrLoadRoots
  333. //
  334. HRESULT CChsFldDlg::HrLoadRoots(void)
  335. {
  336.     HRESULT hr;
  337.     LPMAPITABLE ptblMStrs = NULL;
  338.     UINT ind;
  339.     LPSRowSet pRows = NULL;
  340.     static SSortOrderSet sosName;
  341.  
  342.     sosName.cSorts = 1;
  343.     sosName.cCategories = 0;
  344.     sosName.cExpanded = 0;
  345.     sosName.aSort[0].ulPropTag = PR_DISPLAY_NAME;
  346.     sosName.aSort[0].ulOrder = TABLE_SORT_ASCEND;
  347.  
  348.         
  349.     //Get Message Store Table
  350.     hr = m_pses->GetMsgStoresTable(0, &ptblMStrs);
  351.     if(hr)
  352.     {
  353.         m_lsterr.HrSetLastError(hr, m_pses);
  354.         m_lsterr.ShowError(m_hDlg);
  355.  
  356.         goto err;
  357.     }
  358.  
  359.     //For each msg store insert a node corresponding to PR_IPM_SUBTREE
  360.  
  361.     hr = HrQueryAllRows(ptblMStrs, (LPSPropTagArray) &spthtProps, NULL,
  362.                         &sosName, 0, &pRows);
  363.                         
  364.     if(HR_FAILED(hr))
  365.         goto err;
  366.  
  367.     if(0 ==  pRows->cRows)  //$ No stores
  368.     {
  369.         MessageBox(m_hDlg,
  370.                     "No message stores in the profile",
  371.                     g_szModuleName,
  372.                     MB_OK);
  373.         hr = E_FAIL;
  374.     }
  375.     
  376.     for(ind = 0; ind < pRows->cRows; ++ind)
  377.     {
  378.         LPSPropValue pval = pRows->aRow[ind].lpProps;
  379.         Assert(pRows->aRow[ind].cValues == nhtProps);
  380.         Assert(pval[iEID].ulPropTag == PR_ENTRYID);
  381.  
  382.         pval[iSubfldrs].ulPropTag = PR_SUBFOLDERS;
  383.         pval[iSubfldrs].Value.b = TRUE;
  384.  
  385.         //pval is consumed by this function
  386.         hr = HrInsertRoot(pval);
  387.         pRows->aRow[ind].cValues = 0;
  388.         pRows->aRow[ind].lpProps = NULL;
  389.         if(FAILED(hr))
  390.             goto err;
  391.         
  392.     }
  393.  
  394.     
  395.         
  396. err:
  397.     FreeProws(pRows);
  398.     UlRelease(ptblMStrs);
  399.  
  400.     DebugTraceResult(CChsFldDlg::HrLoadRoots, hr);
  401.     return hr;
  402. }
  403.  
  404. //
  405. //  CChsFldDlg::HrInsertRoot
  406. //
  407. // Put the IPM subtree of the msg store in the tree control
  408. //  pval is consumed
  409. //
  410. HRESULT CChsFldDlg::HrInsertRoot(LPSPropValue pval)
  411. {
  412.     HRESULT hr;
  413.     HTREEITEM hItem;
  414.  
  415.  
  416.     Assert(m_hiRoot);
  417.     
  418.     
  419.     LPTVNODE pNode = NULL;
  420.     hr = HrCreateNode(pval, nhtProps, NULL, &pNode);
  421.     if(hr)
  422.     {
  423.         MAPIFreeBuffer(pval);
  424.         goto err;
  425.     }
  426.  
  427.     Assert(pNode);
  428.     pval = NULL;
  429.  
  430.         
  431.     hItem = AddOneItem(m_hiRoot, TVI_LAST, m_iIconRootFld, m_iIconRootFld,
  432.                             m_hwTreeCtl, pNode, 1);
  433.     if(!hItem)
  434.     {
  435.         hr = MAPI_E_NOT_ENOUGH_MEMORY;
  436.         goto err;
  437.     }
  438.             
  439.         
  440. err:
  441.  
  442.     DebugTraceResult(CChsFldDlg::HrInsertRoots, hr);
  443.     return hr;
  444. }
  445.  
  446.  
  447. //
  448. //  CChsFldDlg::HrSaveTreeState
  449. //
  450. // Save expand - collapse state of the tree control
  451. //
  452. HRESULT CChsFldDlg::HrSaveTreeState(void)
  453. {
  454.     HRESULT hr;
  455.  
  456.     if(!m_pcbState || !m_ppbState)
  457.         return hrSuccess;
  458.  
  459.     MAPIFreeBuffer(*m_ppbState);
  460.     *m_ppbState = NULL;
  461.     *m_pcbState = 0;
  462.     
  463.     hr = HrSaveTreeStateEx(FALSE, m_pcbState, NULL);
  464.     if(hr)
  465.         goto err;
  466.  
  467.     DebugTrace("ChsFld: size of state data: %ld\n", *m_pcbState);
  468.     
  469.     hr = HrSaveTreeStateEx(TRUE, m_pcbState, m_ppbState);
  470.     
  471. err:
  472.     DebugTraceResult(CChsFldDlg::HrSaveTreeState, hr);
  473.     return hr;
  474. }
  475.  
  476. //
  477. //  CChsFldDlg::HrSaveTreeStateEx
  478. //
  479. // Save expand - collapse state of the tree control
  480. //
  481. HRESULT CChsFldDlg::HrSaveTreeStateEx(BOOL fWrite, ULONG * pcb, LPBYTE * ppb)
  482. {
  483.     HRESULT hr = hrSuccess;
  484.     CTIStack tiStack;
  485.     HTREEITEM hti;
  486.     LPBYTE pb = NULL;
  487.     LPBYTE pBuffer = NULL;
  488.     LONG iLevel;
  489.  
  490.     if(fWrite)
  491.     {
  492.         if(*pcb == 0)
  493.         {
  494.             *ppb = NULL;
  495.             return hrSuccess;
  496.         }
  497.         else
  498.         {
  499.             hr = MAPIAllocateBuffer(*pcb, (LPVOID *) &pBuffer);
  500.             if (hr)
  501.             {
  502.                 *pcb = 0;
  503.                 return hr;
  504.             }
  505.             pb = pBuffer;
  506.         }
  507.     }
  508.  
  509.     hti = TreeView_GetRoot(m_hwTreeCtl);
  510.     iLevel = 0;
  511.     tiStack.Push(NULL);
  512.  
  513.     while(hti)
  514.     {
  515.         Assert(iLevel >= 0);
  516.         
  517.         while(hti)
  518.         {
  519.             TV_ITEM tvi;
  520.             
  521.             tvi.hItem = hti;
  522.             tvi.mask = TVIF_STATE | TVIF_PARAM;
  523.             tvi.lParam = 0;
  524.             tvi.state = 0;
  525.             tvi.stateMask = TVIS_EXPANDED;
  526.  
  527.             if(!TreeView_GetItem(m_hwTreeCtl, &tvi))
  528.             {
  529.                 hr = E_FAIL;
  530.                 goto err;
  531.             }
  532.  
  533.             if(tvi.state & TVIS_EXPANDED)
  534.             {
  535.                 HTREEITEM htiChild = TreeView_GetChild(m_hwTreeCtl, hti);
  536.  
  537.                 if(htiChild)
  538.                 {
  539.                     LPTVNODE pNode = (LPTVNODE) tvi.lParam;
  540.                     Assert(pNode);
  541.  
  542.                     pNode->Write(fWrite, iLevel, &pb);
  543.  
  544.                     HTREEITEM htiNextSibl = TreeView_GetNextSibling(m_hwTreeCtl, hti);
  545.  
  546.                     tiStack.Push(htiNextSibl);
  547.  
  548.                     hti = htiChild;
  549.                     ++iLevel;
  550.  
  551.                     continue;
  552.                 }
  553.  
  554.             }
  555.  
  556.             hti = TreeView_GetNextSibling(m_hwTreeCtl, hti);
  557.         }
  558.  
  559.         do
  560.         {
  561.             hti = tiStack.Pop();
  562.             --iLevel;
  563.             
  564.         }while(!tiStack.IsEmpty() && hti == NULL);
  565.     }
  566.  
  567.     Assert(iLevel == -1);
  568.  
  569.     *pcb = pb - pBuffer;
  570.     if(pBuffer)
  571.         *ppb = pBuffer;
  572.     
  573. err:
  574.     DebugTraceResult(CChsFldDlg::HrSaveTreeStateEx, hr);
  575.     return hr;
  576. }
  577.  
  578. inline LONG GetLevel(LPBYTE * ppb)
  579. {
  580.     LONG level = *((LONG *) *ppb);
  581.  
  582.     *ppb += sizeof(LONG);
  583.  
  584.     return level;
  585. }
  586.  
  587. inline ULONG GetCb(LPBYTE * ppb)
  588. {
  589.     ULONG cb = *((ULONG *) *ppb);
  590.  
  591.     *ppb += sizeof(ULONG);
  592.  
  593.     return cb;
  594. }
  595.  
  596. HTREEITEM HtiFindChild(HWND hwTreeCtl, HTREEITEM hti, ULONG cb,
  597.                     LPENTRYID pbEID, CChsFldDlg *pCFDlg, LPTVNODE *ppNode)
  598. {
  599.     HRESULT hr;
  600.     HTREEITEM htiChild;
  601.  
  602.     htiChild = TreeView_GetChild(hwTreeCtl, hti);
  603.     
  604.     while(htiChild)
  605.     {
  606.         TV_ITEM tvi;
  607.         
  608.         tvi.hItem = htiChild;
  609.         tvi.mask = TVIF_PARAM;
  610.         tvi.lParam = 0;
  611.  
  612.         if(!TreeView_GetItem(hwTreeCtl, &tvi))
  613.             return NULL;
  614.  
  615.         LPTVNODE pNode = (LPTVNODE) tvi.lParam;
  616.         Assert(pNode);
  617.  
  618.         ULONG ulMatch = 0;
  619.         hr = pCFDlg->Session()->CompareEntryIDs(cb, pbEID,
  620.                             pNode->m_pval[iEID].Value.bin.cb,
  621.                             (LPENTRYID)pNode->m_pval[iEID].Value.bin.lpb,
  622.                             0, &ulMatch);
  623.         if(SUCCEEDED(hr))
  624.         {
  625.             if(ulMatch)
  626.             {
  627.                 *ppNode = pNode;
  628.                 return htiChild;
  629.             }
  630.         }
  631.  
  632.         htiChild = TreeView_GetNextSibling(hwTreeCtl, htiChild);
  633.     }
  634.  
  635.     return htiChild;
  636. }
  637.  
  638. //
  639. //  CChsFldDlg::HrRestoreTreeState
  640. //
  641. HRESULT CChsFldDlg::HrRestoreTreeState(void)
  642. {
  643.     HRESULT hr = hrSuccess;
  644.     LPBYTE pb;
  645.     LPBYTE pbMax;
  646.     CTIStack tiStack;
  647.     HTREEITEM hti;
  648.     LONG iLevel = 0;
  649.     BOOL fNodeMissing = FALSE;
  650.  
  651.     if(!m_pcbState  || *m_pcbState == 0)
  652.         return hrSuccess;
  653.  
  654.     try //protect ourself from callers who mess with the state data
  655.     {
  656.     Assert(m_hwTreeCtl);
  657.  
  658.     Assert(m_ppbState);
  659.     pb = *m_ppbState;
  660.  
  661.     pbMax = pb + *m_pcbState;
  662.     
  663.     hti = TreeView_GetRoot(m_hwTreeCtl);
  664.  
  665.     iLevel = GetLevel(&pb);
  666.     Assert(iLevel == 0);
  667.  
  668.     TreeView_Expand(m_hwTreeCtl, hti, TVE_EXPAND);
  669.     
  670.     while(hti)
  671.     {
  672.         if(pb >= pbMax)
  673.             break; //done
  674.             
  675.         LONG iNewLevel = GetLevel(&pb);
  676.  
  677.         if(iNewLevel <= iLevel)
  678.         {
  679.             do
  680.             {
  681.                 hti = tiStack.Pop();
  682.                 --iLevel;
  683.             }while(iLevel >= iNewLevel);
  684.  
  685.             Assert(hti);
  686.         }
  687.  
  688.         if(iNewLevel > iLevel)
  689.         {
  690.             if(!fNodeMissing)
  691.                 Assert(iNewLevel == iLevel + 1);
  692.  
  693.             ULONG cbEID = GetCb(&pb);
  694.             LPENTRYID pbEID = (LPENTRYID)pb;
  695.             pb += Align4(cbEID);
  696.  
  697.             if(iNewLevel != iLevel +1)
  698.                 continue;
  699.                 
  700.             LPTVNODE pNodeChild = NULL;
  701.             HTREEITEM htiChild = HtiFindChild(m_hwTreeCtl, hti, cbEID, pbEID,
  702.                                             this, &pNodeChild);
  703.             if(htiChild)
  704.             {
  705.                 fNodeMissing = FALSE;
  706.                 
  707.                 hr = pNodeChild->HrExpand(this);
  708.                 if(FAILED(hr))
  709.                     goto err;
  710.  
  711.                 TreeView_Expand(m_hwTreeCtl, htiChild, TVE_EXPAND);
  712.                 
  713.                 tiStack.Push(hti);
  714.  
  715.                 hti = htiChild;
  716.                 ++iLevel;
  717.  
  718.                 continue;
  719.             }
  720.             else
  721.             {
  722.                 //Assert(FALSE); //$ handle
  723.                 fNodeMissing = TRUE;
  724.             }
  725.  
  726.         }
  727.         /*else
  728.         {
  729.             do
  730.             {
  731.                 hti = tiStack.Pop();
  732.                 --iLevel;
  733.             }while(iLevel >= iNewLevel);
  734.         }*/
  735.     }
  736.     }
  737.  
  738.     catch(...)
  739.     {
  740.         DebugTrace("chsfld: Exception caught in HrRestoreTreeState\n");
  741.         hr = E_FAIL;
  742.     }
  743.     
  744. err:
  745.  
  746.     /*MAPIFreeBuffer(*m_ppbState);
  747.     *m_ppbState = NULL;
  748.     *m_pcbState = 0;*/
  749.     
  750.     
  751.     DebugTraceResult(CChsFldDlg::HrRestoreTreeState, hr);
  752.     return hr;
  753. }
  754.  
  755.  
  756. //////////////////////////////////////////////////////////////////////////
  757. // CTVNodeFactory
  758.  
  759. //
  760. //  CTVNodeFactory::CTVNodeFactory
  761. //
  762. inline CTVNodeFactory::CTVNodeFactory()
  763. {
  764.     m_pHead = NULL;
  765. }
  766.  
  767. //
  768. //  CTVNodeFactory::~CTVNodeFactory
  769. //
  770. //  Destroy all created CTVNode s
  771. CTVNodeFactory::~CTVNodeFactory()
  772. {
  773.     while(m_pHead)
  774.     {
  775.         LPTVNODE ptemp = m_pHead;
  776.  
  777.         m_pHead = m_pHead->m_pNext;
  778.  
  779.         delete ptemp;
  780.     }
  781. }
  782.  
  783.  
  784. //
  785. //  CTVNodeFactory::HrCreateNode
  786. //
  787. // All instances of CTVNode are created through this method
  788. //
  789. HRESULT CTVNodeFactory::HrCreateNode(LPSPropValue pval, ULONG cVals, LPMDB pmdb,
  790.                                         LPTVNODE * pptvNode)
  791. {
  792.     HRESULT hr = hrSuccess;
  793.  
  794.     LPTVNODE pNode = new CTVNode(pval, cVals, pmdb);
  795.     
  796.     if(!pNode)
  797.     {
  798.         hr = MAPI_E_NOT_ENOUGH_MEMORY;
  799.         goto err;
  800.     }
  801.  
  802.     Insert(pNode);
  803.  
  804.     *pptvNode = pNode;
  805.             
  806. err:
  807.  
  808.     DebugTraceResult(CTVNodeFactory::HrCreateNode, hr);
  809.     return hr;
  810. }
  811.  
  812.  
  813. //
  814. //  CTVNodeFactory::Insert
  815. //
  816. // Store all created CTVNode s so that we can destroy them when we are done
  817. //
  818. void CTVNodeFactory::Insert(LPTVNODE pNode)
  819. {
  820.     pNode->m_pNext = m_pHead;
  821.     m_pHead = pNode;
  822. }
  823.  
  824.  
  825. //
  826. //  ChsFldDlgProc
  827. //
  828. // Dialog proc for the choose folder dialog
  829. //
  830. //  Controls:
  831. //          IDOK        "OK"
  832. //          IDCANCEL    "Cancel"
  833. //          IDC_NEWFLD  "New Folder"
  834. //
  835. BOOL CALLBACK
  836. ChsFldDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  837. {
  838.     HRESULT hr;
  839.     CChsFldDlg * pCDlg = NULL;
  840.     HWND hwTreeCtl = NULL;
  841.     int wmId;
  842.     int wmEvent;
  843.     HTREEITEM hti = NULL;
  844.     TV_ITEM tvi;
  845.         
  846.     switch(msg)
  847.     {
  848.     case WM_INITDIALOG:
  849.         Assert(lParam);
  850.         pCDlg = (CChsFldDlg *)lParam;
  851.  
  852.         hwTreeCtl = GetDlgItem(hDlg, IDC_TREEVIEW);
  853.         Assert(hwTreeCtl);
  854.  
  855.         hr = pCDlg->HrInitTree(hDlg, hwTreeCtl);
  856.         if(HR_FAILED(hr))
  857.         {
  858.             pCDlg->SetError(hr);
  859.             EndDialog(hDlg, 1);
  860.             break;
  861.         }
  862.  
  863.         SetWindowLong(hDlg, DWL_USER, (LONG)pCDlg);
  864.  
  865.         break;
  866.  
  867.     case WM_COMMAND:
  868.         wmId = GET_WM_COMMAND_ID(wParam, lParam);  
  869.         wmEvent = GET_WM_COMMAND_CMD(wParam, lParam);
  870.  
  871.         hwTreeCtl = GetDlgItem(hDlg, IDC_TREEVIEW);
  872.         Assert(hwTreeCtl);
  873.  
  874.         pCDlg = (CChsFldDlg *)GetWindowLong(hDlg, DWL_USER);
  875.         Assert(pCDlg);
  876.  
  877.  
  878.         switch(wmId)
  879.         {
  880.         case IDOK:
  881.             switch (wmEvent)
  882.             {
  883.             case BN_CLICKED:
  884.                         
  885.                 hti = TreeView_GetSelection(hwTreeCtl);
  886.                 AssertSz(hti, "No Selection?");
  887.  
  888.                 tvi.hItem = hti;
  889.                 tvi.mask = TVIF_PARAM;
  890.  
  891.                 if(TreeView_GetItem(hwTreeCtl, &tvi))
  892.                 {
  893.                     LPTVNODE pNode = (LPTVNODE)tvi.lParam;
  894.                     Assert(pNode);
  895.  
  896.                     LPMAPIFOLDER pfld = NULL;
  897.                     LPMDB pmdb = NULL;
  898.  
  899.                     hr = pNode->HrGetFolder(pCDlg, &pfld, &pmdb);
  900.                     if(HR_SUCCEEDED(hr))
  901.                     {
  902.                         pCDlg->SetFolder(pfld, pmdb);
  903.                         pfld->Release();
  904.                         pmdb->Release();
  905.  
  906.                         hr = pCDlg->HrSaveTreeState();                  
  907.                     }
  908.                     else
  909.                     {
  910.                         pCDlg->SetError(hr);
  911.                     }
  912.                 }
  913.                 else
  914.                 {
  915.                     pCDlg->SetError(E_FAIL);
  916.                 }
  917.  
  918.                 EndDialog(hDlg, TRUE);
  919.  
  920.                 break;
  921.  
  922.             default:
  923.                 return FALSE;
  924.             }
  925.             break;
  926.  
  927.         case IDC_NEWFLD:
  928.             switch(wmEvent)
  929.             {
  930.             case BN_CLICKED:
  931.                 
  932.                 hti = TreeView_GetSelection(hwTreeCtl);
  933.                 AssertSz(hti, "No Selection?");
  934.  
  935.                 tvi.hItem = hti;
  936.                 tvi.mask = TVIF_PARAM;
  937.  
  938.                 if(TreeView_GetItem(hwTreeCtl, &tvi))
  939.                 {
  940.                     LPTVNODE pNode = (LPTVNODE)tvi.lParam;
  941.                     Assert(pNode);
  942.                     LPSTR szName = NULL;
  943.                     
  944.                     do
  945.                     {
  946.                         hr = HrGetNewName(pCDlg->hInst(), hDlg, &szName);
  947.                         if(HR_SUCCEEDED(hr))
  948.                         {
  949.                             hr = pNode->HrNewFolder(pCDlg, szName);
  950.                         }
  951.                     }while(hr == MAPI_E_COLLISION);
  952.  
  953.                     MAPIFreeBuffer(szName);
  954.                     szName = NULL;
  955.  
  956.                 }
  957.  
  958.                 SetFocus(hwTreeCtl);
  959.  
  960.                 break;
  961.  
  962.             default:
  963.                 return FALSE;
  964.             }
  965.             break;
  966.     
  967.         case IDCANCEL:
  968.             switch(wmEvent)
  969.             {
  970.             case BN_CLICKED:
  971.  
  972.                 pCDlg->SetError(MAPI_E_USER_CANCEL);
  973.  
  974.                 EndDialog(hDlg, TRUE);
  975.                 break;
  976.  
  977.             default:
  978.                 return FALSE;
  979.             }
  980.             break;
  981.         }
  982.         break;
  983.         
  984.     case WM_NOTIFY:
  985.         switch( ((LPNMHDR)lParam)->code)
  986.         {
  987.         case TVN_ITEMEXPANDING:
  988.             {
  989.             Assert(((LPNMHDR)lParam)->idFrom == IDC_TREEVIEW);
  990.  
  991.             NM_TREEVIEW * ptntv = (NM_TREEVIEW *)lParam;
  992.  
  993.             if(ptntv->action != TVE_EXPAND)
  994.                 return FALSE;
  995.  
  996.             //
  997.             // If the kids of this node are not loaded, load'em 
  998.             LPTVNODE pNode = (LPTVNODE)ptntv->itemNew.lParam;
  999.             Assert(pNode);
  1000.  
  1001.             hwTreeCtl = ((LPNMHDR)lParam)->hwndFrom;
  1002.             
  1003.             pCDlg = (CChsFldDlg *)GetWindowLong(hDlg, DWL_USER);
  1004.             //Assert(pCDlg);
  1005.  
  1006.             hr = pNode->HrExpand(pCDlg);  
  1007.             if(HR_FAILED(hr))
  1008.             {
  1009.                 return TRUE;
  1010.             }
  1011.                 return FALSE;
  1012.             }   
  1013.             break;
  1014.         case TVN_GETDISPINFO:
  1015.             {
  1016.             Assert(((LPNMHDR)lParam)->idFrom == IDC_TREEVIEW);
  1017.  
  1018.             //
  1019.             // we don't give folder names to the tree control (to save space)
  1020.             // when it wants to display an item, it asks us for the name
  1021.             //
  1022.             TV_DISPINFO * pdi = (TV_DISPINFO *)lParam;
  1023.  
  1024.             if(pdi->item.mask & TVIF_TEXT)
  1025.             {
  1026.                 pdi->item.pszText = ((LPTVNODE)pdi->item.lParam)->GetName();
  1027.                 return TRUE;
  1028.             }
  1029.             else
  1030.             {
  1031.                 return FALSE;
  1032.             }
  1033.             }
  1034.  
  1035.             break;
  1036.             
  1037.         case TVN_SELCHANGED:
  1038.             //
  1039.             //Enable "OK" and "New Folder" buttons only if it is not the 
  1040.             //root node
  1041.             //
  1042.             {Assert(((LPNMHDR)lParam)->idFrom == IDC_TREEVIEW);
  1043.  
  1044.             NM_TREEVIEW *ptntv = (NM_TREEVIEW *)lParam;
  1045.  
  1046.             pCDlg = (CChsFldDlg *)GetWindowLong(hDlg, DWL_USER);
  1047.             Assert(pCDlg);
  1048.     
  1049.             EnableWindow(GetDlgItem(hDlg, IDOK),
  1050.                         !pCDlg->IsTreeRoot(ptntv->itemNew.hItem));
  1051.             EnableWindow(GetDlgItem(hDlg, IDC_NEWFLD),
  1052.                         !pCDlg->IsTreeRoot(ptntv->itemNew.hItem));
  1053.             break;
  1054.             }
  1055.             
  1056.             break;
  1057.         }
  1058.         
  1059.         break;
  1060.         
  1061.     default:
  1062.         return FALSE;   
  1063.     }
  1064.     return TRUE;
  1065. }
  1066.  
  1067. //
  1068. //  AddOneItem
  1069. //
  1070. // Add a node to the tree control
  1071. //
  1072. HTREEITEM AddOneItem( HTREEITEM hParent, HTREEITEM hInsAfter, 
  1073.     int iImage, int iImageSel, HWND hwndTree, LPTVNODE pNode, int cKids)
  1074. {
  1075.     HTREEITEM hItem;
  1076.     TV_INSERTSTRUCT tvIns;
  1077.  
  1078.     tvIns.item.mask             = TVIF_CHILDREN | TVIF_PARAM |TVIF_TEXT |
  1079.                                     TVIF_IMAGE | TVIF_SELECTEDIMAGE;
  1080.     tvIns.item.pszText          = LPSTR_TEXTCALLBACK;
  1081.     tvIns.item.cchTextMax       = 0;
  1082.     tvIns.item.lParam           = (LPARAM)pNode;
  1083.     tvIns.item.cChildren        = cKids;
  1084.     tvIns.item.iImage           = iImage;
  1085.     tvIns.item.iSelectedImage   = iImageSel;
  1086.  
  1087.     tvIns.hInsertAfter = hInsAfter;
  1088.     tvIns.hParent = hParent;
  1089.     
  1090.     // Insert the item into the tree.
  1091.     hItem = TreeView_InsertItem(hwndTree, &tvIns);
  1092.  
  1093.     pNode->SetHandle(hItem);
  1094.  
  1095.     return (hItem);
  1096. }
  1097.  
  1098.  
  1099. //
  1100. //  HrGetNewName
  1101. //
  1102. //  Display dialog asking the user for a new folder name 
  1103. //
  1104. //  If *pszNewName is not NULL, it has to be a string allocated with
  1105. //  MAPIAllocateBuffer. It will be displayed in the dialog.
  1106. //  The returned string has to be freed with MAPIFreeBuffer.
  1107. //
  1108. HRESULT HrGetNewName(HINSTANCE hInst, HWND hwParent, LPSTR * pszNewName)
  1109. {
  1110.     Assert(pszNewName);
  1111.     
  1112.     int nRes = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_NEWNAME), hwParent,
  1113.                         NewNameDlgProc, (LPARAM)pszNewName);
  1114.     if(nRes == 1)
  1115.     {
  1116.         return hrSuccess;
  1117.     }
  1118.     else
  1119.     {
  1120.         DebugTraceSc(HrGetNewName, E_FAIL);
  1121.         return E_FAIL;
  1122.     }
  1123. }
  1124.  
  1125.  
  1126. //
  1127. // NewNameDlgProc
  1128. //
  1129. // Dlg proc for the "New Name" dialog;
  1130. // If user chooses OK, return 1 from EndDialog.
  1131. //
  1132. BOOL CALLBACK
  1133. NewNameDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  1134. {
  1135.     int wmId;
  1136.     int wmEvent;
  1137.  
  1138.     switch(msg)
  1139.     {
  1140.     case WM_INITDIALOG:
  1141.         {
  1142.         Assert(lParam);
  1143.  
  1144.         LPSTR * pszName = (LPSTR *)lParam;
  1145.  
  1146.         if(*pszName)
  1147.         {
  1148.             SetWindowText(GetDlgItem(hDlg, IDC_NAME), *pszName);
  1149.             MAPIFreeBuffer(*pszName);
  1150.             *pszName = NULL;
  1151.  
  1152.         }
  1153.         
  1154.         SetWindowLong(hDlg, DWL_USER, (LONG)lParam);
  1155.         SetFocus(GetDlgItem(hDlg, IDC_NAME));
  1156.         return FALSE;
  1157.         }
  1158.         break;
  1159.  
  1160.     case WM_COMMAND:
  1161.         wmId = GET_WM_COMMAND_ID(wParam, lParam);  
  1162.         wmEvent = GET_WM_COMMAND_CMD(wParam, lParam);
  1163.  
  1164.         switch(wmId)
  1165.         {
  1166.         case IDOK:
  1167.             switch (wmEvent)
  1168.             {
  1169.             case BN_CLICKED:
  1170.                 {
  1171.                 HWND hwName = GetDlgItem(hDlg, IDC_NAME);
  1172.                 
  1173.                 int cb = Edit_GetTextLength(hwName);
  1174.                 Assert(cb); //OK is disabled when edit control is empty
  1175.  
  1176.                 LPSTR szName = NULL;
  1177.                 if(!MAPIAllocateBuffer(cb + 1, (LPVOID *)&szName))
  1178.                 {
  1179.                     GetWindowText(hwName, szName, cb+1);
  1180.  
  1181.                     LPSTR * pszName = (LPSTR *)GetWindowLong(hDlg, DWL_USER);
  1182.  
  1183.                     *pszName = szName;
  1184.  
  1185.                     EndDialog(hDlg, 1);
  1186.                 }
  1187.                 else
  1188.                 {
  1189.                     EndDialog(hDlg, FALSE);
  1190.                     break;
  1191.                 }
  1192.                 }
  1193.                 break;
  1194.  
  1195.             default:
  1196.                 return FALSE;
  1197.             }
  1198.             
  1199.             break;
  1200.  
  1201.         case IDCANCEL:
  1202.             switch (wmEvent)
  1203.             {
  1204.             case BN_CLICKED:
  1205.                 EndDialog(hDlg, FALSE);
  1206.                 break;
  1207.  
  1208.             default:
  1209.                 return FALSE;
  1210.             }
  1211.             
  1212.             break;
  1213.  
  1214.         case IDC_NAME:
  1215.             switch(wmEvent)
  1216.             {
  1217.             case EN_CHANGE:
  1218.                 Assert((HWND)lParam == GetDlgItem(hDlg, IDC_NAME));
  1219.  
  1220.                 EnableWindow(GetDlgItem(hDlg, IDOK),
  1221.                             Edit_GetTextLength((HWND)lParam));
  1222.  
  1223.                 break;
  1224.  
  1225.             default:
  1226.                 return FALSE;
  1227.             }
  1228.                 
  1229.             break;
  1230.         }
  1231.     default:
  1232.         return FALSE;
  1233.     }   
  1234.         
  1235.     return TRUE;
  1236. }
  1237.  
  1238.