FLDPICK.CPP
//========================================================================= 
// FldPick.CPP 
// 
// Copyright (C) 1986-1996.  Microsoft Corp.  All Rights Reserved. 
//  
// 
// Purpose: 
//    Implements the folder picker dialog. 
 
//========================================================================= 
 
 
#include "stdafx.h" 
#include "PostSmpl.h" 
#include "PostData.h" 
#include "FldPick.h" 
 
 
 
#include <initguid.h> 
#define USES_IID_IMAPIFolder 
#define USES_IID_IMsgStore 
#include <mapiguid.h> 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
  
SizedSPropTagArray(3, sptaFolderBrowse) = { 3, { PR_OBJECT_TYPE, 
                                                    PR_ENTRYID, 
                                                    PR_DISPLAY_NAME } }; 
 
///////////////////////////////////////////////////////////////////////////// 
// CFolderPicker dialog 
 
 
CFolderPicker::CFolderPicker(CWnd* pParent /*=NULL*/) 
: CDialog(CFolderPicker::IDD, pParent) 
{ 
//{{AFX_DATA_INIT(CFolderPicker) 
//}}AFX_DATA_INIT 
} 
 
 
void CFolderPicker::DoDataExchange(CDataExchange* pDX) 
{ 
CDialog::DoDataExchange(pDX); 
//{{AFX_DATA_MAP(CFolderPicker) 
DDX_Control(pDX, IDOK, m_ok); 
DDX_Control(pDX, IDCANCEL, m_cancel); 
DDX_Control(pDX, IDC_TREEVIEW, m_TreeCtrl); 
//}}AFX_DATA_MAP 
} 
 
 
BEGIN_MESSAGE_MAP(CFolderPicker, CDialog) 
//{{AFX_MSG_MAP(CFolderPicker) 
ON_NOTIFY(TVN_ITEMEXPANDING, IDC_TREEVIEW, OnItemexpandingTreeview) 
ON_NOTIFY(TVN_GETDISPINFO, IDC_TREEVIEW, OnGetdispinfoTreeview) 
ON_NOTIFY(TVN_SELCHANGED, IDC_TREEVIEW, OnSelchangedTreeview) 
ON_NOTIFY(TVN_DELETEITEM, IDC_TREEVIEW, OnDeleteitemTreeview) 
//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CFolderPicker message handlers 
 
void CFolderPicker::OnOK()  
{ 
// Add extra validation here 
   GetSelectedFolder(&PostData.m_lpTempFld); 
   CDialog::OnOK(); 
} 
 
void CFolderPicker::OnCancel()  
{ 
// Add extra cleanup here 
CDialog::OnCancel(); 
} 
 
 
 
BOOL CFolderPicker::OnInitDialog()  
{ 
CDialog::OnInitDialog(); 
 
// Add extra initialization here 
m_TreeCtrl.SetImageList(&PostData.m_obImageListExchange, TVSIL_NORMAL); 
 
AddTreeViewItems(); 
 
return TRUE;  // return TRUE unless you set the focus to a control 
              // EXCEPTION: OCX Property Pages should return FALSE 
} 
 
 
BOOL CFolderPicker::AddTreeViewItems() 
{ 
HTREEITEM hTRoot = NULL; 
SMailID *pMailID = NULL; 
SCODEsc       = S_OK; 
 
sc = CreateMailID(MAPI_SESSION, 0, NULL, "Microsoft Exchange\0", &pMailID); 
if (sc == S_OK) 
{ 
 
// First add the root item 
hTRoot = AddOneItem ((HTREEITEM)TVI_ROOT, pMailID->lpszDisplayName,  
(HTREEITEM)NULL, iimlExchange, (DWORD)pMailID); 
 
m_TreeCtrl.Expand(hTRoot, TVE_EXPAND); 
m_TreeCtrl.Select(hTRoot, TVGN_CARET); 
} 
 
return TRUE; 
} 
 
 
// This function fills out the TV_ITEM and TV_INSERTSTRUCT structures  
// and adds the item to the tree view control. 
 
HTREEITEM CFolderPicker::AddOneItem (HTREEITEM hParent, LPSTR lpszText, 
   HTREEITEM hInsAfter, int iImage, DWORD lparam) 
{ 
 
TV_INSERTSTRUCT   tvis; 
 
tvis.hParent             = hParent; 
tvis.hInsertAfter        = hInsAfter; 
tvis.item.mask           = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM | TVIF_STATE; 
tvis.item.pszText        = LPSTR_TEXTCALLBACK; 
tvis.item.cchTextMax     = 0; 
tvis.item.iImage         = I_IMAGECALLBACK; 
tvis.item.iSelectedImage = I_IMAGECALLBACK; 
tvis.item.cChildren      = I_CHILDRENCALLBACK; 
tvis.item.lParam         = (LPARAM)lparam; 
tvis.item.state          = 0; 
tvis.item.stateMask      = 0; 
 
   return m_TreeCtrl.InsertItem(&tvis); 
} 
 
 
 
//------------------------------------------------------------------------- 
// Purpose: 
//    Returns a mapi folder on the selected item in the tree view. 
// 
STDMETHODIMP CFolderPicker::GetSelectedFolder 
   ( 
   LPMAPIFOLDER*  ppfld 
   ) 
{ 
   HRESULT  hr= NOERROR; 
   SMailID* pMailID = NULL; 
 
   // Get the current tree view selection's mail id 
   pMailID = (SMailID *)m_TreeCtrl.GetItemData(m_TreeCtrl.GetSelectedItem()); 
   if( pMailID) 
   { 
hr = OpenFolder(pMailID, ppfld); 
if (FAILED(hr)) 
{ 
#ifdef _DEBUG 
afxDump << TEXT("OpenFolder() failed for "); 
afxDump << TEXT(pMailID->lpszDisplayName); 
#endif 
} 
   } 
 
   return hr; 
} 
 
//------------------------------------------------------------------------- 
// Purpose: 
//    Add rows from a mapi table to the tree view. 
// 
STDMETHODIMP CFolderPicker::AddRows 
   ( 
   HTREEITEM   hitemParent, 
   LPMAPITABLE pmt 
   ) 
{ 
   HRESULT     hr  = NOERROR; 
   BOOL        fDone          = FALSE; 
   HTREEITEM   hitem          = TVI_FIRST; 
   LPSRowSet   prws           = NULL; 
   ULONG       cRowsTotal     = 0; 
   CONST UINT  cRowsBatch     = 256; 
   CONST UINT  cWanted        = 3; 
   UINT        cFound         = 0; 
   ULONG       ulType         = 0; 
   ULONG       cbeid          = 0; 
   LPENTRYID   peid           = NULL; 
   LPTSTR      pszDisplayName = NULL; 
   SMailID*    pMailID        = NULL; 
   SMailID*    pParentMailID  = NULL; 
 
   // Set the columns to those needed for folder browsing 
   if (SUCCEEDED(hr = pmt->SetColumns((LPSPropTagArray)&sptaFolderBrowse, 0))) 
   { 
      // Get all of the table's rows 
      while (!fDone && 
             SUCCEEDED(hr = pmt->QueryRows(cRowsBatch, 0, &prws)) && 
             prws) 
      { 
         if (prws->cRows > 0) 
         { 
            cRowsTotal += prws->cRows; 
            // Add them to the tree 
            for (ULONG iRow = 0; iRow < prws->cRows; iRow++) 
            { 
               cFound = 0; 
               // Get the appropriate values from the columns 
               for (ULONG iCol = 0; iCol < prws->aRow[iRow].cValues; iCol++) 
               { 
                  if (PR_OBJECT_TYPE == prws->aRow[iRow].lpProps[iCol].ulPropTag) 
                  { 
                     ulType = (ULONG)prws->aRow[iRow].lpProps[iCol].Value.l; 
                     cFound++; 
                  } 
                  else if (PR_ENTRYID == prws->aRow[iRow].lpProps[iCol].ulPropTag) 
                  { 
                     cbeid = prws->aRow[iRow].lpProps[iCol].Value.bin.cb; 
                     peid  = (LPENTRYID)prws->aRow[iRow].lpProps[iCol].Value.bin.lpb; 
                     cFound++; 
                  } 
                  else if (PR_DISPLAY_NAME == prws->aRow[iRow].lpProps[iCol].ulPropTag) 
                  { 
                     pszDisplayName = prws->aRow[iRow].lpProps[iCol].Value.LPSZ; 
                     cFound++; 
                  } 
               } 
 
               // if we found all of them... 
               if (cFound == cWanted) 
               { 
                  // Create a mail id and add it to the tree 
                  if (SUCCEEDED(CreateMailID(ulType, cbeid, peid, pszDisplayName, &pMailID))) 
                  { 
                     hitem = AddOneItem(hitemParent, pszDisplayName, hitem, iimlExchange, (DWORD)pMailID); 
ASSERT(hitem); 
  
                  } 
               } // if (cFound == cWanted) 
 
            } // for (iRow 
         } 
         else 
         { 
            fDone = TRUE; 
         } 
 
         FreeProws(prws); 
      } // while 
 
         // Set the children count on the parent item now that we know it 
         //m_TreeCtrl.SetItemChildCount(hitemParent, cRowsTotal); 
TV_ITEM  tvi; 
tvi.mask      = TVIF_HANDLE | TVIF_CHILDREN; 
tvi.hItem     = hitemParent; 
tvi.cChildren = cRowsTotal; 
m_TreeCtrl.SetItem(&tvi); 
   } 
 
   return hr; 
} 
 
 
//------------------------------------------------------------------------- 
// Purpose: 
//    Fill the tree view from the "root" of exchange. 
// 
STDMETHODIMP CFolderPicker::TvmtFromRoot 
   ( 
   HTREEITEM   hitemParent 
   ) 
{ 
   HRESULT     hr  = NOERROR; 
   LPMAPITABLE pmt = NULL; 
 
   if (SUCCEEDED(hr = PostData.m_lpSession->GetMsgStoresTable(0, &pmt))) 
   { 
      hr = AddRows(hitemParent, pmt); 
      pmt->Release(); 
   } 
 
   return hr; 
} 
 
 
//------------------------------------------------------------------------- 
// Purpose: 
//    Fill the tree view from a folder. 
// 
STDMETHODIMP CFolderPicker::TvmtFromFolder 
   ( 
   HTREEITEM      hitemParent, 
   LPMAPIFOLDER   pfld 
   ) 
{ 
   HRESULT        hr   = NOERROR; 
   LPMAPITABLE    pmt  = NULL; 
 
   // Get the folder hierarchy table 
   if (SUCCEEDED(hr = pfld->GetHierarchyTable(MAPI_DEFERRED_ERRORS, &pmt))) 
   { 
      hr = AddRows(hitemParent, pmt); 
      pmt->Release(); 
   } 
 
   return hr; 
} 
 
 
//------------------------------------------------------------------------- 
// Purpose: 
//    Expand a tree view item. 
// 
STDMETHODIMP CFolderPicker::FirstTimeExpand 
   ( 
   HTREEITEM  hitem, 
   SMailID*   pMailID 
   ) 
{ 
   HRESULT  hr= NOERROR; 
 
   if (MAPI_SESSION == pMailID->ulType) 
   { 
      hr = TvmtFromRoot(hitem); 
   } 
   else 
   { 
      LPMAPIFOLDER   pfld; 
 
      if (SUCCEEDED(hr = OpenFolder(pMailID, &pfld))) 
      { 
         hr = TvmtFromFolder(hitem, pfld); 
         pfld->Release(); 
      } 
    } 
 
   return hr; 
} 
//------------------------------------------------------------------------- 
// Purpose: 
//    Creates a *simple* pidl. 
// 
// static 
STDMETHODIMP CFolderPicker::CreateMailID 
   ( 
   ULONG          ulType,           // IN:  one of MAPI_SESSION, MAPI_STORE, or MAPI_FOLDER 
   ULONG          cbEntryID,        // IN:  count of bytes in entry ID 
   LPENTRYID      lpEntryID,        // IN:  entry ID 
   LPCTSTR        lpszDisplayName,  // IN:  display name of item 
   SMailID**      ppob              // OUT: pointer to resulting object 
   ) 
{ 
  SCODE sc= S_OK; 
  
// Allocate space for the 
sc = MAPIAllocateBuffer( sizeof(SMailID), (LPVOID *)ppob); 
    if (FAILED(sc)) 
{ 
#ifdef _DEBUG 
afxDump << TEXT("CreateMailID(): MAPIAllocateBuffer failed"); 
#endif 
goto CleanUp;   // Allocate space for the 
} 
 
(*ppob)->cbEntryID = cbEntryID; 
(*ppob)->ulType   = ulType; 
(*ppob)->lpEntryID  = NULL; 
(*ppob)->lpszDisplayName   = NULL; 
 
sc = MAPIAllocateMore(cbEntryID, (LPVOID)*ppob, (LPVOID*)&((*ppob)->lpEntryID)); 
if (FAILED(sc)) 
{ 
#ifdef _DEBUG 
afxDump << TEXT("CreateMailID(): MAPIAllocateMore failed"); 
#endif 
goto CleanUp;   // Allocate space for the 
} 
 
CopyMemory((*ppob)->lpEntryID, lpEntryID, cbEntryID); 
 
sc = MAPIAllocateMore(lstrlen(lpszDisplayName)+1, (LPVOID)*ppob, (LPVOID*)&((*ppob)->lpszDisplayName)); 
if (FAILED(sc)) 
{ 
#ifdef _DEBUG 
afxDump << TEXT("CreateMailID(): MAPIAllocateMore failed"); 
#endif 
goto CleanUp;   // Allocate space for the 
} 
 
lstrcpy((*ppob)->lpszDisplayName, lpszDisplayName); 
 
 
CleanUp: 
return(sc); 
 
} 
 
STDMETHODIMP CFolderPicker::OpenFolder(SMailID *pMailID, LPMAPIFOLDER *ppfld) 
{ 
    
   HRESULT        hr= NOERROR; 
   LPSPropValue   pval= NULL; 
   ULONG          ulObjType = 0; 
  
       
   if (MAPI_STORE == pMailID->ulType) 
   { 
      // Open the store. (only if not already open) 
  LPMDB lpMDB = NULL; 
      if (SUCCEEDED(hr = PostData.OpenMsgStore(pMailID->cbEntryID, pMailID->lpEntryID, &lpMDB))) 
      { 
         // Open the IPM subtree as a folder. 
         if (SUCCEEDED(hr = HrGetOneProp(lpMDB, PR_IPM_SUBTREE_ENTRYID, &pval))) 
         { 
            hr = PostData.m_lpSession->OpenEntry(pval->Value.bin.cb, 
                                          (LPENTRYID)pval->Value.bin.lpb, 
                                          &IID_IMAPIFolder, 
                                          MAPI_MODIFY | MAPI_DEFERRED_ERRORS, 
                                          &ulObjType, 
                                          (LPUNKNOWN*)ppfld); 
 
          
            MAPIFreeBuffer(pval); 
         } 
          
       } 
   } 
   else if (MAPI_FOLDER == pMailID->ulType) 
   { 
             // Open the folder. 
            hr = PostData.m_lpSession->OpenEntry(pMailID->cbEntryID, 
                                          pMailID->lpEntryID, 
                                          &IID_IMAPIFolder, 
                                          MAPI_MODIFY | MAPI_DEFERRED_ERRORS, 
                                          &ulObjType, 
                                          (LPUNKNOWN*)ppfld); 
   } 
          
   return hr; 
} 
 
 
void CFolderPicker::OnItemexpandingTreeview(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR; 
// Add your control notification handler code here 
// Provide display info 
   
   // An item is expanding, 
      SMailID*       pMailID  = (SMailID*)pnmtv->itemNew.lParam; 
 
if ((TVE_COLLAPSE == pnmtv->action) || (TVE_COLLAPSERESET == pnmtv->action)) 
    { 
if (pMailID->lpEntryID == NULL) 
        { 
            // prevent tree view from collapsing the root 
            pnmtv->itemNew.mask  = TVIF_HANDLE | TVIF_STATE; 
            pnmtv->itemNew.state = TVIS_EXPANDED; 
            pnmtv->itemNew.stateMask = TVIS_EXPANDED; 
         } 
} 
else if ((TVE_EXPAND == pnmtv->action) && !(pnmtv->itemNew.state & TVIS_EXPANDEDONCE)) 
{ 
         if (FAILED(FirstTimeExpand(pnmtv->itemNew.hItem, pMailID))) 
 { 
#ifdef _DEBUG 
afxDump << TEXT("FirstTimeExpand() failed for "); 
afxDump << TEXT(pMailID->lpszDisplayName); 
#endif 
 } 
}       
        
*pResult = 0; 
} 
 
void CFolderPicker::OnGetdispinfoTreeview(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
TV_DISPINFO* pDispInfo = (TV_DISPINFO*)pNMHDR; 
// Add your control notification handler code here 
// Provide display info 
   
     SMailID*       pMailID = (SMailID*)pDispInfo->item.lParam; 
 
      if (pMailID) 
      { 
         // Set up the display text 
         if (pDispInfo->item.mask & TVIF_TEXT) 
         { 
            pDispInfo->item.pszText    = (LPTSTR)pMailID->lpszDisplayName; 
            pDispInfo->item.cchTextMax = lstrlen(pDispInfo->item.pszText); 
         } 
 
         // Set up the images to use 
         if (pDispInfo->item.mask & TVIF_IMAGE) 
         { 
            INT   iImage; 
            INT   iSelectedImage; 
 
            iImage = MapTypeToExchangeImageListIndex(pMailID->ulType, &iSelectedImage); 
 
            if ((pDispInfo->item.mask & TVIF_STATE) && (pDispInfo->item.state & TVIS_EXPANDED)) 
            { 
               pDispInfo->item.iImage = iSelectedImage; 
            } 
            else 
            { 
               pDispInfo->item.iImage = iImage; 
            } 
            pDispInfo->item.iSelectedImage = iSelectedImage; 
         } 
 
         // Set up the count of children 
         if (pDispInfo->item.mask & TVIF_CHILDREN) 
         { 
            pDispInfo->item.cChildren = I_CHILDRENCALLBACK; 
         } 
      } 
 
  *pResult = 0; 
} 
 
 
void CFolderPicker::OnSelchangedTreeview(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR; 
// Add your control notification handler code here 
// Enable or disable buttons as appropriate due to the selection 
               
SMailID*       pMailID  = (SMailID*)pnmtv->itemNew.lParam; 
 
    if (MAPI_SESSION != pMailID->ulType) 
    { 
        m_ok.EnableWindow(TRUE); 
    } 
    else 
    { 
        m_ok.EnableWindow(FALSE); 
    } 
 
*pResult = 0; 
} 
 
//------------------------------------------------------------------------- 
// Purpose: 
//    Get the image list index corresponding to a MAPI object type. 
// 
INT CFolderPicker::MapTypeToExchangeImageListIndex 
   ( 
   ULONG ulType, 
   INT*  piSelectedImage 
   ) 
{ 
   INT iImage = iimlFolder; 
    
   if (MAPI_SESSION == ulType) 
   { 
iImage           = iimlExchange; 
*piSelectedImage = iimlExchangeOpen; 
   } 
   else if (MAPI_STORE == ulType) 
   { 
iImage           = iimlMdb; 
*piSelectedImage = iimlMdbOpen; 
   } 
   else if (MAPI_FOLDER == ulType) 
   { 
iImage           = iimlFolder; 
*piSelectedImage = iimlFolderOpen; 
   } 
   else 
   { 
#ifdef _DEBUG 
    afxDump << TEXT("MapTypeToExchangeImageListIndex: Incorrect ulType"); 
#endif 
iImage = iimlFolder; 
*piSelectedImage = iimlFolder; 
} 
   
   return iImage; 
} 
 
 
 
void CFolderPicker::OnDeleteitemTreeview(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
NM_TREEVIEW* pnmtv = (NM_TREEVIEW*)pNMHDR; 
// Add your control notification handler code here 
// Delete our user data 
    SMailID*       pMailID = (SMailID *)pnmtv->itemOld.lParam; 
 
MAPIFreeBuffer((LPVOID)pMailID); 
 
*pResult = 0; 
}