////////////////////////////////////////////////////////////////////////////
//
// CHSFLD.CPP
//
//
// Copyright 1986-1996 Microsoft Corporation. All Rights Reserved.
///////////////////////////////////////////////////////////////////////
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <mapix.h>
#include <mapiutil.h>
#include <mapidbg.h>
#include "chsfld.h"
#include "lasterr.h"
#include "tvdlg.h"
#include "resource.h"
#include "tvstack.h"
#define cImageHeight 16
#define cImageWidth 16
#define cImages 4
//globals
LPSTR g_szAllStores = "All Message Stores";
LPSTR g_szModuleName = "Choose Folder Dialog";
//functions used only in this file
BOOL CALLBACK
ChsFldDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
HRESULT HrGetNewName(HINSTANCE hInst, HWND hwParent, LPSTR * pszNewName);
BOOL CALLBACK
NewNameDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
//
// HrPickFolder
//
//
STDAPI
HrPickFolder(HINSTANCE hInst, HWND hWnd, LPMAPISESSION pses, LPMAPIFOLDER * ppfld,
LPMDB *ppmdb, ULONG * pcb, LPBYTE * ppb)
{
HRESULT hr;
//Assert(hInst);
if((hWnd && !IsWindow(hWnd)) || (!pses) || (!ppfld) || (!ppmdb))
{
DebugTraceResult(HrPickFolder, E_INVALIDARG);
return E_INVALIDARG;
}
if(pcb && IsBadWritePtr(pcb, sizeof(ULONG)))
{
DebugTraceArg(HrPickFolder, "pcb not writable");
return E_INVALIDARG;
}
if(pcb && (*pcb & 0x3))
{
DebugTraceArg(HrPickFolder, "pcb not multiple of 4");
return E_INVALIDARG;
}
if(ppb && IsBadWritePtr(ppb, sizeof(LPBYTE)))
{
DebugTraceArg(HrPickFolder, "ppb not writable");
return E_INVALIDARG;
}
if(ppb && pcb && IsBadWritePtr(*ppb, *pcb))
{
DebugTraceArg(HrPickFolder, "*pcb or *ppb");
return E_INVALIDARG;
}
//////////////////////////////////////////////////////////////////////
// if you incorporate this code into you app, remove this and pass in
// the right hInst
// Start remove
hInst = GetModuleHandle("chsfld32.dll");
if(!hInst)
{
DebugTrace("GetModuleHandel failed\n");
DebugTraceResult(HrPickFolder, E_FAIL);
return E_FAIL;
}
// End remove
///////////////////////////////////////////////////////////////////////
//ULONG cb = 0;
//LPBYTE pb = NULL;
CChsFldDlg PickDlg(pses, hInst, pcb, ppb);
InitCommonControls();
hr = PickDlg.HrPick(MAKEINTRESOURCE(IDD_CFDIALOG), hWnd,
(DLGPROC)ChsFldDlgProc, ppfld, ppmdb);
/* if(SUCCEEDED(hr))
{
(*ppfld)->Release();
(*ppmdb)->Release();
}
CChsFldDlg PickDlg1(pses, hInst, pcb, ppb);
hr = PickDlg1.HrPick(MAKEINTRESOURCE(IDD_CFDIALOG), hWnd,
(DLGPROC)ChsFldDlgProc, ppfld, ppmdb);*/
// if(!hr)
// MAPIFreeBuffer(pb);
DebugTraceResult(HrPickFolder, hr);
return hr;
}
//
// CChsFldDlg::CChsFldDlg
//
inline
CChsFldDlg::CChsFldDlg(LPMAPISESSION pses, HINSTANCE hInst, ULONG * pcb,
LPBYTE * ppb) : m_lsterr(g_szModuleName)
{
Assert(pses);
Assert(hInst);
m_pses = pses;
pses->AddRef();
m_hr = hrSuccess;
m_pfld = NULL;
m_pmdb = NULL;
m_hiRoot = NULL;
m_hInst = hInst;
m_hIml = NULL;
m_hDlg = NULL;
m_hwTreeCtl = NULL;
m_pcbState = pcb;
m_ppbState = ppb;
}
//
// CChsFldDlg::~CChsFldDlg
//
CChsFldDlg::~CChsFldDlg()
{
UlRelease(m_pses);
UlRelease(m_pfld);
UlRelease(m_pmdb);
if(m_hIml)
ImageList_Destroy(m_hIml);
}
//
// CChsFldDlg::SetFolder
//
// Store the folder chosen by the user
//
inline void CChsFldDlg::SetFolder(LPMAPIFOLDER pfld, LPMDB pmdb)
{
UlRelease(m_pfld);
m_pfld = pfld;
if(pfld)
pfld->AddRef();
UlRelease(m_pmdb);
m_pmdb = pmdb;
if(pmdb)
pmdb->AddRef();
}
//
// CChsFldDlg::HrPick
//
// The outmost method.
//
HRESULT CChsFldDlg::HrPick(LPCTSTR lpTemplateName, HWND hWnd,
DLGPROC pfnDlgProc, LPMAPIFOLDER * ppfld, LPMDB *ppmdb)
{
if(-1 == DialogBoxParam(m_hInst, lpTemplateName, hWnd, pfnDlgProc, (LPARAM) this))
{
DebugTraceSc(CChsDldDlg::HrPick, MAPI_E_NOT_ENOUGH_MEMORY);
return MAPI_E_NOT_ENOUGH_MEMORY;
}
//m_hr is set inside the dialog
if(HR_SUCCEEDED(m_hr))
{
Assert(m_pfld);
m_pfld->AddRef();
*ppfld = m_pfld;
Assert(m_pmdb);
m_pmdb->AddRef();
*ppmdb = m_pmdb;
}
return m_hr;
}
//
// CChsFldDlg::HrInitTree
//
// Called from WM_INITDIALOG. Opens all message stores in the profile and
// puts the IPM subtrees in the tree control
//
HRESULT CChsFldDlg::HrInitTree(HWND hDlg, HWND hwTreeCtl)
{
HRESULT hr;
LPSPropValue pval = NULL;
LPTVNODE pNode = NULL;
HTREEITEM hiRoot = NULL;
HICON hIcon = NULL;
Assert(hDlg);
Assert(hwTreeCtl);
m_hwTreeCtl = hwTreeCtl;
m_hDlg = hDlg;
//
// Set up the image list
//
m_hIml = ImageList_Create(cImageWidth, cImageHeight, ILC_MASK,
cImages, 0);
if(!m_hIml)
{
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto err;
}
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_ALLSTORES));
m_iIconAllStores = ImageList_AddIcon(m_hIml, hIcon);
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_ROOTFLD));
m_iIconRootFld = ImageList_AddIcon(m_hIml, hIcon);
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_OPENFLD));
m_iIconOpenFld = ImageList_AddIcon(m_hIml, hIcon);
hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_CLSDFLD));
m_iIconClsdFld = ImageList_AddIcon(m_hIml, hIcon);
if(ImageList_GetImageCount(m_hIml) < cImages)
{
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto err;
}
TreeView_SetImageList(hwTreeCtl, m_hIml, TVSIL_NORMAL);
//
// create the root tree node
// (fake a GetProps)
//
hr = MAPIAllocateBuffer(nhtProps * sizeof(SPropValue),
(LPVOID *)&pval);
if(hr)
{
m_lsterr.HrSetLastError(hr);
m_lsterr.ShowError(hDlg);
goto err;
}
ZeroMemory(pval, nhtProps * sizeof(SPropValue));
//Set proptags to make CNode constructor happy
pval[iEID].ulPropTag = PR_ENTRYID;
pval[iDispName].ulPropTag = PR_DISPLAY_NAME;
pval[iDispName].Value.lpszA = g_szAllStores;
pval[iSubfldrs].ulPropTag = PR_SUBFOLDERS;
hr = HrCreateNode(pval, nhtProps, NULL, &pNode);
if(hr)
goto err;
Assert(pNode);
pval = NULL; //will be freed in ~CTVNode
hiRoot = AddOneItem(NULL, TVI_ROOT, m_iIconAllStores, m_iIconAllStores,
hwTreeCtl, pNode, 1);
if(!hiRoot)
{
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto err;
}
pNode->SetKidsLoaded(TRUE);
m_hiRoot = hiRoot;
//
// Put the IPM subtrees of all the message stores in
//
hr = HrLoadRoots();
if(HR_FAILED(hr))
goto err;
(void)HrRestoreTreeState();
err:
MAPIFreeBuffer(pval);
DebugTraceResult(CChsFldDlg::HrInitTree, hr);
return hr;
}
//
// CChsFldDlg::HrLoadRoots
//
HRESULT CChsFldDlg::HrLoadRoots(void)
{
HRESULT hr;
LPMAPITABLE ptblMStrs = NULL;
UINT ind;
LPSRowSet pRows = NULL;
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;
//Get Message Store Table
hr = m_pses->GetMsgStoresTable(0, &ptblMStrs);
if(hr)
{
m_lsterr.HrSetLastError(hr, m_pses);
m_lsterr.ShowError(m_hDlg);
goto err;
}
//For each msg store insert a node corresponding to PR_IPM_SUBTREE
hr = HrQueryAllRows(ptblMStrs, (LPSPropTagArray) &spthtProps, NULL,
&sosName, 0, &pRows);
if(HR_FAILED(hr))
goto err;
if(0 == pRows->cRows) //$ No stores
{
MessageBox(m_hDlg,
"No message stores in the profile",
g_szModuleName,
MB_OK);
hr = E_FAIL;
}
for(ind = 0; ind < pRows->cRows; ++ind)
{
LPSPropValue pval = pRows->aRow[ind].lpProps;
Assert(pRows->aRow[ind].cValues == nhtProps);
Assert(pval[iEID].ulPropTag == PR_ENTRYID);
pval[iSubfldrs].ulPropTag = PR_SUBFOLDERS;
pval[iSubfldrs].Value.b = TRUE;
//pval is consumed by this function
hr = HrInsertRoot(pval);
pRows->aRow[ind].cValues = 0;
pRows->aRow[ind].lpProps = NULL;
if(FAILED(hr))
goto err;
}
err:
FreeProws(pRows);
UlRelease(ptblMStrs);
DebugTraceResult(CChsFldDlg::HrLoadRoots, hr);
return hr;
}
//
// CChsFldDlg::HrInsertRoot
//
// Put the IPM subtree of the msg store in the tree control
// pval is consumed
//
HRESULT CChsFldDlg::HrInsertRoot(LPSPropValue pval)
{
HRESULT hr;
HTREEITEM hItem;
Assert(m_hiRoot);
LPTVNODE pNode = NULL;
hr = HrCreateNode(pval, nhtProps, NULL, &pNode);
if(hr)
{
MAPIFreeBuffer(pval);
goto err;
}
Assert(pNode);
pval = NULL;
hItem = AddOneItem(m_hiRoot, TVI_LAST, m_iIconRootFld, m_iIconRootFld,
m_hwTreeCtl, pNode, 1);
if(!hItem)
{
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto err;
}
err:
DebugTraceResult(CChsFldDlg::HrInsertRoots, hr);
return hr;
}
//
// CChsFldDlg::HrSaveTreeState
//
// Save expand - collapse state of the tree control
//
HRESULT CChsFldDlg::HrSaveTreeState(void)
{
HRESULT hr;
if(!m_pcbState || !m_ppbState)
return hrSuccess;
MAPIFreeBuffer(*m_ppbState);
*m_ppbState = NULL;
*m_pcbState = 0;
hr = HrSaveTreeStateEx(FALSE, m_pcbState, NULL);
if(hr)
goto err;
DebugTrace("ChsFld: size of state data: %ld\n", *m_pcbState);
hr = HrSaveTreeStateEx(TRUE, m_pcbState, m_ppbState);
err:
DebugTraceResult(CChsFldDlg::HrSaveTreeState, hr);
return hr;
}
//
// CChsFldDlg::HrSaveTreeStateEx
//
// Save expand - collapse state of the tree control
//
HRESULT CChsFldDlg::HrSaveTreeStateEx(BOOL fWrite, ULONG * pcb, LPBYTE * ppb)
{
HRESULT hr = hrSuccess;
CTIStack tiStack;
HTREEITEM hti;
LPBYTE pb = NULL;
LPBYTE pBuffer = NULL;
LONG iLevel;
if(fWrite)
{
if(*pcb == 0)
{
*ppb = NULL;
return hrSuccess;
}
else
{
hr = MAPIAllocateBuffer(*pcb, (LPVOID *) &pBuffer);
if (hr)
{
*pcb = 0;
return hr;
}
pb = pBuffer;
}
}
hti = TreeView_GetRoot(m_hwTreeCtl);
iLevel = 0;
tiStack.Push(NULL);
while(hti)
{
Assert(iLevel >= 0);
while(hti)
{
TV_ITEM tvi;
tvi.hItem = hti;
tvi.mask = TVIF_STATE | TVIF_PARAM;
tvi.lParam = 0;
tvi.state = 0;
tvi.stateMask = TVIS_EXPANDED;
if(!TreeView_GetItem(m_hwTreeCtl, &tvi))
{
hr = E_FAIL;
goto err;
}
if(tvi.state & TVIS_EXPANDED)
{
HTREEITEM htiChild = TreeView_GetChild(m_hwTreeCtl, hti);
if(htiChild)
{
LPTVNODE pNode = (LPTVNODE) tvi.lParam;
Assert(pNode);
pNode->Write(fWrite, iLevel, &pb);
HTREEITEM htiNextSibl = TreeView_GetNextSibling(m_hwTreeCtl, hti);
tiStack.Push(htiNextSibl);
hti = htiChild;
++iLevel;
continue;
}
}
hti = TreeView_GetNextSibling(m_hwTreeCtl, hti);
}
do
{
hti = tiStack.Pop();
--iLevel;
}while(!tiStack.IsEmpty() && hti == NULL);
}
Assert(iLevel == -1);
*pcb = pb - pBuffer;
if(pBuffer)
*ppb = pBuffer;
err:
DebugTraceResult(CChsFldDlg::HrSaveTreeStateEx, hr);
return hr;
}
inline LONG GetLevel(LPBYTE * ppb)
{
LONG level = *((LONG *) *ppb);
*ppb += sizeof(LONG);
return level;
}
inline ULONG GetCb(LPBYTE * ppb)
{
ULONG cb = *((ULONG *) *ppb);
*ppb += sizeof(ULONG);
return cb;
}
HTREEITEM HtiFindChild(HWND hwTreeCtl, HTREEITEM hti, ULONG cb,
LPENTRYID pbEID, CChsFldDlg *pCFDlg, LPTVNODE *ppNode)
{
HRESULT hr;
HTREEITEM htiChild;
htiChild = TreeView_GetChild(hwTreeCtl, hti);
while(htiChild)
{
TV_ITEM tvi;
tvi.hItem = htiChild;
tvi.mask = TVIF_PARAM;
tvi.lParam = 0;
if(!TreeView_GetItem(hwTreeCtl, &tvi))
return NULL;
LPTVNODE pNode = (LPTVNODE) tvi.lParam;
Assert(pNode);
ULONG ulMatch = 0;
hr = pCFDlg->Session()->CompareEntryIDs(cb, pbEID,
pNode->m_pval[iEID].Value.bin.cb,
(LPENTRYID)pNode->m_pval[iEID].Value.bin.lpb,
0, &ulMatch);
if(SUCCEEDED(hr))
{
if(ulMatch)
{
*ppNode = pNode;
return htiChild;
}
}
htiChild = TreeView_GetNextSibling(hwTreeCtl, htiChild);
}
return htiChild;
}
//
// CChsFldDlg::HrRestoreTreeState
//
HRESULT CChsFldDlg::HrRestoreTreeState(void)
{
HRESULT hr = hrSuccess;
LPBYTE pb;
LPBYTE pbMax;
CTIStack tiStack;
HTREEITEM hti;
LONG iLevel = 0;
BOOL fNodeMissing = FALSE;
if(!m_pcbState || *m_pcbState == 0)
return hrSuccess;
try //protect ourself from callers who mess with the state data
{
Assert(m_hwTreeCtl);
Assert(m_ppbState);
pb = *m_ppbState;
pbMax = pb + *m_pcbState;
hti = TreeView_GetRoot(m_hwTreeCtl);
iLevel = GetLevel(&pb);
Assert(iLevel == 0);
TreeView_Expand(m_hwTreeCtl, hti, TVE_EXPAND);
while(hti)
{
if(pb >= pbMax)
break; //done
LONG iNewLevel = GetLevel(&pb);
if(iNewLevel <= iLevel)
{
do
{
hti = tiStack.Pop();
--iLevel;
}while(iLevel >= iNewLevel);
Assert(hti);
}
if(iNewLevel > iLevel)
{
if(!fNodeMissing)
Assert(iNewLevel == iLevel + 1);
ULONG cbEID = GetCb(&pb);
LPENTRYID pbEID = (LPENTRYID)pb;
pb += Align4(cbEID);
if(iNewLevel != iLevel +1)
continue;
LPTVNODE pNodeChild = NULL;
HTREEITEM htiChild = HtiFindChild(m_hwTreeCtl, hti, cbEID, pbEID,
this, &pNodeChild);
if(htiChild)
{
fNodeMissing = FALSE;
hr = pNodeChild->HrExpand(this);
if(FAILED(hr))
goto err;
TreeView_Expand(m_hwTreeCtl, htiChild, TVE_EXPAND);
tiStack.Push(hti);
hti = htiChild;
++iLevel;
continue;
}
else
{
//Assert(FALSE); //$ handle
fNodeMissing = TRUE;
}
}
/*else
{
do
{
hti = tiStack.Pop();
--iLevel;
}while(iLevel >= iNewLevel);
}*/
}
}
catch(...)
{
DebugTrace("chsfld: Exception caught in HrRestoreTreeState\n");
hr = E_FAIL;
}
err:
/*MAPIFreeBuffer(*m_ppbState);
*m_ppbState = NULL;
*m_pcbState = 0;*/
DebugTraceResult(CChsFldDlg::HrRestoreTreeState, hr);
return hr;
}
//////////////////////////////////////////////////////////////////////////
// CTVNodeFactory
//
// CTVNodeFactory::CTVNodeFactory
//
inline CTVNodeFactory::CTVNodeFactory()
{
m_pHead = NULL;
}
//
// CTVNodeFactory::~CTVNodeFactory
//
// Destroy all created CTVNode s
CTVNodeFactory::~CTVNodeFactory()
{
while(m_pHead)
{
LPTVNODE ptemp = m_pHead;
m_pHead = m_pHead->m_pNext;
delete ptemp;
}
}
//
// CTVNodeFactory::HrCreateNode
//
// All instances of CTVNode are created through this method
//
HRESULT CTVNodeFactory::HrCreateNode(LPSPropValue pval, ULONG cVals, LPMDB pmdb,
LPTVNODE * pptvNode)
{
HRESULT hr = hrSuccess;
LPTVNODE pNode = new CTVNode(pval, cVals, pmdb);
if(!pNode)
{
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto err;
}
Insert(pNode);
*pptvNode = pNode;
err:
DebugTraceResult(CTVNodeFactory::HrCreateNode, hr);
return hr;
}
//
// CTVNodeFactory::Insert
//
// Store all created CTVNode s so that we can destroy them when we are done
//
void CTVNodeFactory::Insert(LPTVNODE pNode)
{
pNode->m_pNext = m_pHead;
m_pHead = pNode;
}
//
// ChsFldDlgProc
//
// Dialog proc for the choose folder dialog
//
// Controls:
// IDOK "OK"
// IDCANCEL "Cancel"
// IDC_NEWFLD "New Folder"
//
BOOL CALLBACK
ChsFldDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
HRESULT hr;
CChsFldDlg * pCDlg = NULL;
HWND hwTreeCtl = NULL;
int wmId;
int wmEvent;
HTREEITEM hti = NULL;
TV_ITEM tvi;
switch(msg)
{
case WM_INITDIALOG:
Assert(lParam);
pCDlg = (CChsFldDlg *)lParam;
hwTreeCtl = GetDlgItem(hDlg, IDC_TREEVIEW);
Assert(hwTreeCtl);
hr = pCDlg->HrInitTree(hDlg, hwTreeCtl);
if(HR_FAILED(hr))
{
pCDlg->SetError(hr);
EndDialog(hDlg, 1);
break;
}
SetWindowLong(hDlg, DWL_USER, (LONG)pCDlg);
break;
case WM_COMMAND:
wmId = GET_WM_COMMAND_ID(wParam, lParam);
wmEvent = GET_WM_COMMAND_CMD(wParam, lParam);
hwTreeCtl = GetDlgItem(hDlg, IDC_TREEVIEW);
Assert(hwTreeCtl);
pCDlg = (CChsFldDlg *)GetWindowLong(hDlg, DWL_USER);
Assert(pCDlg);
switch(wmId)
{
case IDOK:
switch (wmEvent)
{
case BN_CLICKED:
hti = TreeView_GetSelection(hwTreeCtl);
AssertSz(hti, "No Selection?");
tvi.hItem = hti;
tvi.mask = TVIF_PARAM;
if(TreeView_GetItem(hwTreeCtl, &tvi))
{
LPTVNODE pNode = (LPTVNODE)tvi.lParam;
Assert(pNode);
LPMAPIFOLDER pfld = NULL;
LPMDB pmdb = NULL;
hr = pNode->HrGetFolder(pCDlg, &pfld, &pmdb);
if(HR_SUCCEEDED(hr))
{
pCDlg->SetFolder(pfld, pmdb);
pfld->Release();
pmdb->Release();
hr = pCDlg->HrSaveTreeState();
}
else
{
pCDlg->SetError(hr);
}
}
else
{
pCDlg->SetError(E_FAIL);
}
EndDialog(hDlg, TRUE);
break;
default:
return FALSE;
}
break;
case IDC_NEWFLD:
switch(wmEvent)
{
case BN_CLICKED:
hti = TreeView_GetSelection(hwTreeCtl);
AssertSz(hti, "No Selection?");
tvi.hItem = hti;
tvi.mask = TVIF_PARAM;
if(TreeView_GetItem(hwTreeCtl, &tvi))
{
LPTVNODE pNode = (LPTVNODE)tvi.lParam;
Assert(pNode);
LPSTR szName = NULL;
do
{
hr = HrGetNewName(pCDlg->hInst(), hDlg, &szName);
if(HR_SUCCEEDED(hr))
{
hr = pNode->HrNewFolder(pCDlg, szName);
}
}while(hr == MAPI_E_COLLISION);
MAPIFreeBuffer(szName);
szName = NULL;
}
SetFocus(hwTreeCtl);
break;
default:
return FALSE;
}
break;
case IDCANCEL:
switch(wmEvent)
{
case BN_CLICKED:
pCDlg->SetError(MAPI_E_USER_CANCEL);
EndDialog(hDlg, TRUE);
break;
default:
return FALSE;
}
break;
}
break;
case WM_NOTIFY:
switch( ((LPNMHDR)lParam)->code)
{
case TVN_ITEMEXPANDING:
{
Assert(((LPNMHDR)lParam)->idFrom == IDC_TREEVIEW);
NM_TREEVIEW * ptntv = (NM_TREEVIEW *)lParam;
if(ptntv->action != TVE_EXPAND)
return FALSE;
//
// If the kids of this node are not loaded, load'em
LPTVNODE pNode = (LPTVNODE)ptntv->itemNew.lParam;
Assert(pNode);
hwTreeCtl = ((LPNMHDR)lParam)->hwndFrom;
pCDlg = (CChsFldDlg *)GetWindowLong(hDlg, DWL_USER);
//Assert(pCDlg);
hr = pNode->HrExpand(pCDlg);
if(HR_FAILED(hr))
{
return TRUE;
}
return FALSE;
}
break;
case TVN_GETDISPINFO:
{
Assert(((LPNMHDR)lParam)->idFrom == IDC_TREEVIEW);
//
// we don't give folder names to the tree control (to save space)
// when it wants to display an item, it asks us for the name
//
TV_DISPINFO * pdi = (TV_DISPINFO *)lParam;
if(pdi->item.mask & TVIF_TEXT)
{
pdi->item.pszText = ((LPTVNODE)pdi->item.lParam)->GetName();
return TRUE;
}
else
{
return FALSE;
}
}
break;
case TVN_SELCHANGED:
//
//Enable "OK" and "New Folder" buttons only if it is not the
//root node
//
{Assert(((LPNMHDR)lParam)->idFrom == IDC_TREEVIEW);
NM_TREEVIEW *ptntv = (NM_TREEVIEW *)lParam;
pCDlg = (CChsFldDlg *)GetWindowLong(hDlg, DWL_USER);
Assert(pCDlg);
EnableWindow(GetDlgItem(hDlg, IDOK),
!pCDlg->IsTreeRoot(ptntv->itemNew.hItem));
EnableWindow(GetDlgItem(hDlg, IDC_NEWFLD),
!pCDlg->IsTreeRoot(ptntv->itemNew.hItem));
break;
}
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
//
// AddOneItem
//
// Add a node to the tree control
//
HTREEITEM AddOneItem( HTREEITEM hParent, HTREEITEM hInsAfter,
int iImage, int iImageSel, HWND hwndTree, LPTVNODE pNode, int cKids)
{
HTREEITEM hItem;
TV_INSERTSTRUCT tvIns;
tvIns.item.mask = TVIF_CHILDREN | TVIF_PARAM |TVIF_TEXT |
TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tvIns.item.pszText = LPSTR_TEXTCALLBACK;
tvIns.item.cchTextMax = 0;
tvIns.item.lParam = (LPARAM)pNode;
tvIns.item.cChildren = cKids;
tvIns.item.iImage = iImage;
tvIns.item.iSelectedImage = iImageSel;
tvIns.hInsertAfter = hInsAfter;
tvIns.hParent = hParent;
// Insert the item into the tree.
hItem = TreeView_InsertItem(hwndTree, &tvIns);
pNode->SetHandle(hItem);
return (hItem);
}
//
// HrGetNewName
//
// Display dialog asking the user for a new folder name
//
// If *pszNewName is not NULL, it has to be a string allocated with
// MAPIAllocateBuffer. It will be displayed in the dialog.
// The returned string has to be freed with MAPIFreeBuffer.
//
HRESULT HrGetNewName(HINSTANCE hInst, HWND hwParent, LPSTR * pszNewName)
{
Assert(pszNewName);
int nRes = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_NEWNAME), hwParent,
NewNameDlgProc, (LPARAM)pszNewName);
if(nRes == 1)
{
return hrSuccess;
}
else
{
DebugTraceSc(HrGetNewName, E_FAIL);
return E_FAIL;
}
}
//
// NewNameDlgProc
//
// Dlg proc for the "New Name" dialog;
// If user chooses OK, return 1 from EndDialog.
//
BOOL CALLBACK
NewNameDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
int wmId;
int wmEvent;
switch(msg)
{
case WM_INITDIALOG:
{
Assert(lParam);
LPSTR * pszName = (LPSTR *)lParam;
if(*pszName)
{
SetWindowText(GetDlgItem(hDlg, IDC_NAME), *pszName);
MAPIFreeBuffer(*pszName);
*pszName = NULL;
}
SetWindowLong(hDlg, DWL_USER, (LONG)lParam);
SetFocus(GetDlgItem(hDlg, IDC_NAME));
return FALSE;
}
break;
case WM_COMMAND:
wmId = GET_WM_COMMAND_ID(wParam, lParam);
wmEvent = GET_WM_COMMAND_CMD(wParam, lParam);
switch(wmId)
{
case IDOK:
switch (wmEvent)
{
case BN_CLICKED:
{
HWND hwName = GetDlgItem(hDlg, IDC_NAME);
int cb = Edit_GetTextLength(hwName);
Assert(cb); //OK is disabled when edit control is empty
LPSTR szName = NULL;
if(!MAPIAllocateBuffer(cb + 1, (LPVOID *)&szName))
{
GetWindowText(hwName, szName, cb+1);
LPSTR * pszName = (LPSTR *)GetWindowLong(hDlg, DWL_USER);
*pszName = szName;
EndDialog(hDlg, 1);
}
else
{
EndDialog(hDlg, FALSE);
break;
}
}
break;
default:
return FALSE;
}
break;
case IDCANCEL:
switch (wmEvent)
{
case BN_CLICKED:
EndDialog(hDlg, FALSE);
break;
default:
return FALSE;
}
break;
case IDC_NAME:
switch(wmEvent)
{
case EN_CHANGE:
Assert((HWND)lParam == GetDlgItem(hDlg, IDC_NAME));
EnableWindow(GetDlgItem(hDlg, IDOK),
Edit_GetTextLength((HWND)lParam));
break;
default:
return FALSE;
}
break;
}
default:
return FALSE;
}
return TRUE;
}