/*-------------------------------------------------------------- * * * ui_addr.c - contains stuff for showing the :Address UI * * * * * * * --------------------------------------------------------------*/ #include "_apipch.h" extern HINSTANCE ghCommCtrlDLLInst; #define SET_UNICODE_STR(lp1,lp2,lpAdrParms) if(lpAdrParms->ulFlags & MAPI_UNICODE)\ lp1 = (LPWSTR)lp2; \ else \ lp1 = ConvertAtoW((LPSTR)lp2); \ #define FREE_UNICODE_STR(lp1,lp2) if(lp1 != lp2) LocalFreeAndNull(&lp1); typedef struct _AddressParms { LPADRBOOK lpIAB; //Stores a pointer to the ADRBOOK object LPADRPARM lpAdrParms; //AdrParms structure passed into Address LPADRLIST *lppAdrList; //AdrList of input names HANDLE hPropertyStore; //pointer to the property store int DialogState; //Identifies the ongoing function LPRECIPIENT_INFO lpContentsList;//Contains a list of entries in the contents structure LPRECIPIENT_INFO lpListTo; //Entries in the To Well LPRECIPIENT_INFO lpListCC; //Entries in the CC well LPRECIPIENT_INFO lpListBCC; //Entries in the BCC well SORT_INFO SortInfo; //Contains current sort info int nContextID; //identifies which list view called the context menu BOOL bDontRefresh; //Used to ensure that nothing refreshes during modal operations BOOL bLDAPinProgress; HCURSOR hWaitCur; int nRetVal; LPMAPIADVISESINK lpAdviseSink; ULONG ulAdviseConnection; BOOL bDeferNotification; // Used to defer next notification request HWND hDlg; HWND hWndAddr; } ADDRESS_PARMS, *LPADDRESS_PARMS; enum _lppAdrListReturnedProps { propPR_DISPLAY_NAME, propPR_ENTRYID, propPR_RECIPIENT_TYPE, TOTAL_ADRLIST_PROPS }; static DWORD rgAddrHelpIDs[] = { IDC_ADDRBK_EDIT_QUICKFIND, IDH_WAB_PICK_RECIP_TYPE_NAME, IDC_ADDRBK_STATIC_CONTENTS, IDH_WAB_PICK_RECIP_NAME_LIST, IDC_ADDRBK_LIST_ADDRESSES, IDH_WAB_PICK_RECIP_NAME_LIST, IDC_ADDRBK_BUTTON_PROPS, IDH_WAB_PICK_RECIP_NAME_PROPERTIES, IDC_ADDRBK_BUTTON_NEW, IDH_WAB_PICK_RECIP_NAME_NEW, IDC_ADDRBK_BUTTON_TO, IDH_WAB_PICK_RECIP_NAME_TO_BUTTON, IDC_ADDRBK_BUTTON_CC, IDH_WAB_PICK_RECIP_NAME_CC_BUTTON, IDC_ADDRBK_BUTTON_BCC, IDH_WAB_PICK_RECIP_NAME_BCC_BUTTON, IDC_ADDRBK_LIST_TO, IDH_WAB_PICK_RECIP_NAME_TO_LIST, IDC_ADDRBK_LIST_CC, IDH_WAB_PICK_RECIP_NAME_CC_LIST, IDC_ADDRBK_LIST_BCC, IDH_WAB_PICK_RECIP_NAME_BCC_LIST, IDC_ADDRBK_BUTTON_DELETE, IDH_WAB_PICK_RECIP_NAME_DELETE, IDC_ADDRBK_BUTTON_NEWGROUP, IDH_WAB_PICK_RECIP_NAME_NEW_GROUP, IDC_ADDRBK_STATIC_RECIP_TITLE, IDH_WAB_COMM_GROUPBOX, IDC_ADDRBK_BUTTON_FIND, IDH_WAB_PICK_RECIP_NAME_FIND, IDC_ADDRBK_COMBO_CONT, IDH_WAB_GROUPS_CONTACTS_FOLDER, 0,0 }; // forward declarations INT_PTR CALLBACK fnAddress(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); BOOL SetAddressBookUI(HWND hDlg, LPADDRESS_PARMS lpAP); void FillListFromCurrentContainer(HWND hDlg, LPADDRESS_PARMS lpAP); BOOL FillWells(HWND hDlg, LPADRLIST lpAdrList, LPADRPARM lpAdrParms, LPRECIPIENT_INFO * lppListTo, LPRECIPIENT_INFO * lppListCC, LPRECIPIENT_INFO * lppListBCC); BOOL ListDeleteItem(HWND hDlg, int CtlID, LPRECIPIENT_INFO * lppList); BOOL ListAddItem(HWND hDlg, HWND hWndAddr, int CtlID, LPRECIPIENT_INFO * lppList, ULONG RecipientType); void UpdateLVItems(HWND hWndLV,LPTSTR lpszName); void ShowAddrBkLVProps(LPIAB lpIAB, HWND hDlg, HWND hWndAddr, LPADDRESS_PARMS lpAP, LPFILETIME lpftLast); HRESULT HrUpdateAdrListEntry( LPADRBOOK lpIAB, LPENTRYID lpEntryID, ULONG cbEntryID, ULONG ulFlags, LPADRLIST * lppAdrList); enum _AddressDialogReturnValues { ADDRESS_RESET = 0, //Blank initialization value ADDRESS_CANCEL, ADDRESS_OK, }; //$$///////////////////////////////////////////////////////////////////////////////////////// // // FillContainerCombo - Fills the container combo with container names // ///////////////////////////////////////////////////////////////////////////////////////////// void FillContainerCombo(HWND hWndCombo, LPIAB lpIAB) { ULONG iolkci, colkci; OlkContInfo *rgolkci; int nPos, nDefault=0; LPPTGDATA lpPTGData=GetThreadStoragePointer(); // Clear out the combo SendMessage(hWndCombo, CB_RESETCONTENT, 0, 0); Assert(lpIAB); EnterCriticalSection(&lpIAB->cs); if(pt_bIsWABOpenExSession || bIsWABSessionProfileAware(lpIAB)) { colkci = pt_bIsWABOpenExSession ? lpIAB->lpPropertyStore->colkci : lpIAB->cwabci; Assert(colkci); rgolkci = lpIAB->lpPropertyStore->colkci ? lpIAB->lpPropertyStore->rgolkci : lpIAB->rgwabci; Assert(rgolkci); // Add the multiple folders here for(iolkci = 0; iolkci < colkci; iolkci++) { nPos = (int) SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM) rgolkci[iolkci].lpszName); if(nPos != CB_ERR) SendMessage(hWndCombo, CB_SETITEMDATA, (WPARAM)nPos, (LPARAM) (DWORD_PTR)(iolkci==0 ? NULL : rgolkci[iolkci].lpEntryID)); if( bIsThereACurrentUser(lpIAB) && !lstrcmpi(lpIAB->lpWABCurrentUserFolder->lpFolderName, rgolkci[iolkci].lpszName) &&//folder names are unique nPos != CB_ERR) { nDefault = nPos; } } } LeaveCriticalSection(&lpIAB->cs); SendMessage(hWndCombo, CB_SETCURSEL, (WPARAM) nDefault, 0); } //$$*------------------------------------------------------------------------ //| IAddrBook::Advise::OnNotify handler //| //*------------------------------------------------------------------------ ULONG AddrAdviseOnNotify(LPVOID lpvContext, ULONG cNotif, LPNOTIFICATION lpNotif) { LPADDRESS_PARMS lpAP = (LPADDRESS_PARMS) lpvContext; DebugTrace( TEXT("+++ AddrAdviseOnNotify ===\n")); if(lpAP->bDeferNotification) { DebugTrace( TEXT("+++ Advise Defered ===\n")); lpAP->bDeferNotification = FALSE; return S_OK; } if(!lpAP->bDontRefresh) { DebugTrace( TEXT("+++ Calling FillListFromCurrentContainer ===\n")); FillListFromCurrentContainer(lpAP->hDlg, lpAP); } return S_OK; } ///////////////////////////////////////////////////////////////////////////////// // // ShowAddressUI - does some parameter checking and calls the PropertySheets // // // ///////////////////////////////////////////////////////////////////////////////// HRESULT HrShowAddressUI(IN LPADRBOOK lpIAB, IN HANDLE hPropertyStore, IN ULONG_PTR * lpulUIParam, IN LPADRPARM lpAdrParms, IN LPADRLIST *lppAdrList) { HRESULT hr = E_FAIL; //ADDRESS_PARMS AP = {0}; LPADDRESS_PARMS lpAP = NULL; TCHAR szBuf[MAX_UI_STR]; HWND hWndParent = NULL; int nRetVal = 0; int DialogState = 0; //Addref the AdrBook object to make sure it stays valid throughout .. // Remember to release before leaving ... // NOTE: Must be before any jumps to out! UlAddRef(lpIAB); // if no common control, exit if (NULL == ghCommCtrlDLLInst) { hr = ResultFromScode(MAPI_E_UNCONFIGURED); goto out; } if (lpulUIParam) hWndParent = (HWND) *lpulUIParam; if ( // Can't pick-user with wells ((lpAdrParms->ulFlags & ADDRESS_ONE) && (lpAdrParms->cDestFields != 0)) || // cDestFields has limited for tier 0.5 (lpAdrParms->cDestFields > 3) || // Cant pick user without an input lpAdrList //((lpAdrParms->ulFlags & ADDRESS_ONE) && (*lppAdrList == NULL)) || ((lpAdrParms->ulFlags & DIALOG_SDI) && (lpAdrParms->cDestFields != 0)) ) { hr = MAPI_E_INVALID_PARAMETER; goto out; } // // The possible states of this dialog box are // 1. Select recipients Wells shown, returns an AdrList of picked up entries, Cant delete entries // 2. Select a single user, No wells shown, single selection, cannot delete, must have input Adrlist // 3. Open for browsing only, multiple selection, can create delete, create, view details // Determine what the dialog state is if (lpAdrParms->cDestFields > 0) { //lpAP->DialogState = STATE_SELECT_RECIPIENTS; DialogState = STATE_SELECT_RECIPIENTS; } else if (lpAdrParms->ulFlags & ADDRESS_ONE) { DialogState = STATE_PICK_USER; } else if (lpAdrParms->ulFlags & DIALOG_MODAL) { DialogState = STATE_BROWSE_MODAL; } else if (lpAdrParms->ulFlags & DIALOG_SDI) { DialogState = STATE_BROWSE; } if (DialogState == STATE_BROWSE) { // Show the browse window and leave // HWND hWndAB = NULL; hWndAB = hCreateAddressBookWindow( lpIAB, hWndParent, lpAdrParms); if (hWndAB) { *lpulUIParam = (ULONG_PTR) hWndAB; hr = S_OK; } goto out; } lpAP = LocalAlloc(LMEM_ZEROINIT, sizeof(ADDRESS_PARMS)); if (!lpAP) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } lpAP->DialogState = DialogState; lpAP->lpIAB = lpIAB; lpAP->lpAdrParms = lpAdrParms; lpAP->lppAdrList = lppAdrList; lpAP->hPropertyStore = hPropertyStore; ReadRegistrySortInfo((LPIAB)lpIAB, &(lpAP->SortInfo)); lpAP->lpContentsList = NULL; lpAP->bDontRefresh = FALSE; lpAP->bLDAPinProgress = FALSE; lpAP->hWaitCur = NULL; HrAllocAdviseSink(&AddrAdviseOnNotify, (LPVOID) lpAP, &(lpAP->lpAdviseSink)); nRetVal = (int) DialogBoxParam( hinstMapiX, MAKEINTRESOURCE(IDD_DIALOG_ADDRESSBOOK), hWndParent, fnAddress, (LPARAM) lpAP); switch(nRetVal) { case -1: //some error occured hr = E_FAIL; break; case ADDRESS_CANCEL: hr = MAPI_E_USER_CANCEL; break; case ADDRESS_OK: default: hr = S_OK; break; } if(lpAP->lpAdviseSink) { lpAP->lpIAB->lpVtbl->Unadvise(lpAP->lpIAB, lpAP->ulAdviseConnection); lpAP->lpAdviseSink->lpVtbl->Release(lpAP->lpAdviseSink); lpAP->lpAdviseSink = NULL; lpAP->ulAdviseConnection = 0; } out: lpIAB->lpVtbl->Release(lpIAB); LocalFreeAndNull(&lpAP); return hr; } #define lpAP_lppContentsList (&(lpAP->lpContentsList)) #define lpAP_lppListTo (&(lpAP->lpListTo)) #define lpAP_lppListCC (&(lpAP->lpListCC)) #define lpAP_lppListBCC (&(lpAP->lpListBCC)) #define lpAP_bDontRefresh (lpAP->bDontRefresh) #define _hWndAddr lpAP->hWndAddr //$$///////////////////////////////////////////////////////////////////////////// // // GetCurrentComboSelection - Get the current selection from the combo // ///////////////////////////////////////////////////////////////////////////////// LPSBinary GetCurrentComboSelection(HWND hWndCombo) { int nPos = (int) SendMessage(hWndCombo, CB_GETCURSEL, 0, 0); LPSBinary lpsbCont = NULL; if(nPos == CB_ERR) nPos = 0; lpsbCont = (LPSBinary) SendMessage(hWndCombo, CB_GETITEMDATA, (WPARAM) nPos, 0); if(CB_ERR == (DWORD_PTR) lpsbCont) lpsbCont = NULL; return lpsbCont; } //$$///////////////////////////////////////////////////////////////////////////// // // FillListFromCurrentContainer - Get the selection from the combo and fill it // ///////////////////////////////////////////////////////////////////////////////// void FillListFromCurrentContainer(HWND hDlg, LPADDRESS_PARMS lpAP) { HWND hWndAddr = GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES); LPPTGDATA lpPTGData=GetThreadStoragePointer(); LPSBinary lpsbCont = NULL; if(pt_bIsWABOpenExSession || bIsWABSessionProfileAware((LPIAB)lpAP->lpIAB)) { HWND hWndCombo = GetDlgItem(hDlg, IDC_ADDRBK_COMBO_CONT); int nPos = (int) SendMessage(hWndCombo, CB_GETCURSEL, 0, 0); if(nPos != CB_ERR) { // Refill the combo in case the folder list changed FillContainerCombo(hWndCombo, (LPIAB)lpAP->lpIAB); nPos = (int) SendMessage(hWndCombo, CB_SETCURSEL, (WPARAM) nPos, 0); } lpsbCont = GetCurrentComboSelection(hWndCombo); } HrGetWABContents( hWndAddr, lpAP->lpIAB, lpsbCont, lpAP->SortInfo, lpAP_lppContentsList); } extern BOOL APIENTRY_16 fnFolderDlgProc(HWND hDlg, UINT message, UINT wParam, LPARAM lParam); ///////////////////////////////////////////////////////////////////////////////// // // fnAddress - the PropertySheet Message Handler // // // ///////////////////////////////////////////////////////////////////////////////// INT_PTR CALLBACK fnAddress(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static FILETIME ftLast = {0}; LPADDRESS_PARMS lpAP = (LPADDRESS_PARMS ) GetWindowLongPtr(hDlg,DWLP_USER); switch(message) { case WM_INITDIALOG: SetWindowLongPtr(hDlg,DWLP_USER,lParam); //Save this for future reference lpAP = (LPADDRESS_PARMS) lParam; lpAP->hWndAddr = GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES); lpAP->hDlg = hDlg; lpAP_bDontRefresh = FALSE; lpAP->nContextID = IDC_ADDRBK_LIST_ADDRESSES; SetAddressBookUI(hDlg,lpAP); // if this is a pick-user dialog, need to have the names by // first name so we can find the closest match .. if(lpAP->DialogState == STATE_PICK_USER) (lpAP->SortInfo).bSortByLastName = FALSE; FillListFromCurrentContainer(hDlg, lpAP); if (lpAP->DialogState == STATE_SELECT_RECIPIENTS) { FillWells(hDlg,*(lpAP->lppAdrList),(lpAP->lpAdrParms),lpAP_lppListTo,lpAP_lppListCC,lpAP_lppListBCC); // we want to highlight the first item in the list if (ListView_GetItemCount(_hWndAddr) > 0) LVSelectItem( _hWndAddr, 0); } else if (lpAP->DialogState == STATE_PICK_USER && *(lpAP->lppAdrList) ) { // if this is a pick user dialog, then try to match the supplied name to the // closest entry in the List Box if (ListView_GetItemCount(_hWndAddr) > 0) { LPTSTR lpszDisplayName = NULL; ULONG i; // Scan only the first entry in the lpAdrList for a display name for(i=0;i< (*(lpAP->lppAdrList))->aEntries[0].cValues;i++) { ULONG ulPropTag = PR_DISPLAY_NAME; if(!(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE)) ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_STRING8); if((*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].ulPropTag == ulPropTag) { SET_UNICODE_STR(lpszDisplayName, (*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ,lpAP->lpAdrParms); break; } } if (lpszDisplayName) { // We have Something to search for TCHAR szBuf[MAX_UI_STR]; ULONG nLen; LV_FINDINFO lvF = {0}; // Typically, we are not going to get a full match ... // Instead we want to make a partial match on disply name. // The ListViewFindItem does an exact partial match if the supplied // string matches the first few entries of an existing item // Hence, to obtain a semi-partial match, we start with the // original Display Name working our way backwards from last // character to first character until we get a match or run // out of characters. int iItemIndex = -1; nLen = lstrlen(lpszDisplayName); if (nLen >= CharSizeOf(szBuf)) nLen = CharSizeOf(szBuf)-1; lvF.flags = LVFI_PARTIAL | LVFI_STRING; while((nLen > 0) && (iItemIndex == -1)) { nLen = TruncatePos(lpszDisplayName, nLen); if (nLen==0) break; CopyMemory(szBuf, lpszDisplayName, sizeof(TCHAR)*nLen); szBuf[nLen] = '\0'; lvF.psz = szBuf; iItemIndex = ListView_FindItem(_hWndAddr,-1, &lvF); nLen--; } // Set focus to the selected item or to the first item in the list if (iItemIndex < 0) iItemIndex = 0; LVSelectItem(_hWndAddr, iItemIndex); FREE_UNICODE_STR(lpszDisplayName, (*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ); } } } if(lpAP->lpAdviseSink) { // Register for notifications lpAP->lpIAB->lpVtbl->Advise(lpAP->lpIAB, 0, NULL, fnevObjectModified, lpAP->lpAdviseSink, &lpAP->ulAdviseConnection); } if (ListView_GetSelectedCount(_hWndAddr) <= 0) LVSelectItem(_hWndAddr, 0); // if we want the user to pick something actively, we disable OK until they click on something // or do something specific .. if( lpAP->DialogState == STATE_PICK_USER ) { EnableWindow(GetDlgItem(hDlg, IDOK), FALSE); SendMessage (hDlg, DM_SETDEFID, IDCANCEL, 0); } SetFocus(GetDlgItem(hDlg,IDC_ADDRBK_EDIT_QUICKFIND)); return FALSE; // return TRUE; break; case WM_SYSCOLORCHANGE: //Forward any system changes to the list view SendMessage(_hWndAddr, message, wParam, lParam); SetColumnHeaderBmp(_hWndAddr, lpAP->SortInfo); break; case WM_HELP: WABWinHelp(((LPHELPINFO)lParam)->hItemHandle, g_szWABHelpFileName, HELP_WM_HELP, (DWORD_PTR)(LPSTR) rgAddrHelpIDs ); break; case WM_SETCURSOR: if (lpAP->bLDAPinProgress) { SetCursor(lpAP->hWaitCur); SetWindowLongPtr(hDlg, DWLP_MSGRESULT, MAKELONG(TRUE, 0)); return(TRUE); } break; case WM_COMMAND: switch(GET_WM_COMMAND_CMD(wParam,lParam)) //check the notification code { case CBN_SELCHANGE: FillListFromCurrentContainer(hDlg, lpAP); break; } switch(GET_WM_COMMAND_ID(wParam, lParam)) { default: if (lpAP->nContextID != -1) { LRESULT fRet = FALSE; lpAP_bDontRefresh = TRUE; fRet = ProcessActionCommands((LPIAB) lpAP->lpIAB,_hWndAddr, hDlg, message, wParam, lParam); lpAP_bDontRefresh = FALSE; return fRet; } break; case IDC_ADDRBK_BUTTON_DELETE: if(!lpAP->bLDAPinProgress) { lpAP->bLDAPinProgress = TRUE; lpAP_bDontRefresh = TRUE; DeleteSelectedItems(_hWndAddr, lpAP->lpIAB, lpAP->hPropertyStore, &ftLast); lpAP->bDeferNotification = TRUE; lpAP_bDontRefresh = FALSE; lpAP->bLDAPinProgress = FALSE; } break; case IDM_LVCONTEXT_DELETE: if(!lpAP->bLDAPinProgress) { lpAP->bLDAPinProgress = TRUE; switch(lpAP->nContextID) { case IDC_ADDRBK_LIST_ADDRESSES: lpAP_bDontRefresh = TRUE; DeleteSelectedItems(_hWndAddr, lpAP->lpIAB, lpAP->hPropertyStore, &ftLast); lpAP->bDeferNotification = TRUE; lpAP_bDontRefresh = FALSE; break; case IDC_ADDRBK_LIST_TO: ListDeleteItem(hDlg, IDC_ADDRBK_LIST_TO, lpAP_lppListTo); break; case IDC_ADDRBK_LIST_CC: ListDeleteItem(hDlg, IDC_ADDRBK_LIST_CC, lpAP_lppListCC); break; case IDC_ADDRBK_LIST_BCC: ListDeleteItem(hDlg, IDC_ADDRBK_LIST_BCC, lpAP_lppListBCC); break; default: break; } lpAP->bLDAPinProgress = FALSE; } break; case IDM_LVCONTEXT_COPY: lpAP_bDontRefresh = TRUE; HrCopyItemDataToClipboard(hDlg, lpAP->lpIAB, GetDlgItem(hDlg,lpAP->nContextID)); lpAP_bDontRefresh = FALSE; break; case IDM_LVCONTEXT_PROPERTIES: case IDC_ADDRBK_BUTTON_PROPS: if(!lpAP->bLDAPinProgress) { lpAP->bLDAPinProgress = TRUE; if (lpAP->nContextID != -1) { lpAP_bDontRefresh = TRUE; ShowAddrBkLVProps((LPIAB)lpAP->lpIAB, hDlg, GetDlgItem(hDlg, lpAP->nContextID), lpAP, &ftLast); lpAP->bDeferNotification = TRUE; lpAP_bDontRefresh = FALSE; } lpAP->bLDAPinProgress = FALSE; } break; /* Uncomment to enable NEW_FOLDER functionality from this dialog case IDM_LVCONTEXT_NEWFOLDER: { TCHAR sz[MAX_UI_STR]; LPTSTR lpsz = NULL; *sz = '\0'; if( IDCANCEL != DialogBoxParam( hinstMapiX, MAKEINTRESOURCE(IDD_DIALOG_FOLDER), hDlg, fnFolderDlgProc, (LPARAM) sz) && lstrlen(sz)) { // if we're here we have a valid folder name .. if(!HR_FAILED(HrCreateNewFolder((LPIAB)lpAP->lpIAB, sz, NULL, FALSE, NULL, NULL))) { int i,nTotal; HWND hWndC = GetDlgItem(hDlg, IDC_ADDRBK_COMBO_CONT); // Fill in the Combo with the container names FillContainerCombo(hWndC, (LPIAB)lpAP->lpIAB); nTotal = SendMessage(hWndC, CB_GETCOUNT, 0, 0); if(nTotal != CB_ERR) { // Find the item we just added in the combo and set the sel on it TCHAR szC[MAX_UI_STR]; for(i=0;ibLDAPinProgress) { ULONG cbEID = 0; LPENTRYID lpEID = NULL; int nID = GET_WM_COMMAND_ID(wParam, lParam); ULONG ulObjType = (nID == IDM_LVCONTEXT_NEWCONTACT || nID == IDC_ADDRBK_BUTTON_NEW) ? MAPI_MAILUSER : MAPI_DISTLIST; LPSBinary lpsbContEID = NULL; if(bIsWABSessionProfileAware((LPIAB)lpAP->lpIAB)) lpsbContEID = GetCurrentComboSelection(GetDlgItem(hDlg,IDC_ADDRBK_COMBO_CONT)); lpAP->bLDAPinProgress = TRUE; lpAP_bDontRefresh = TRUE; AddNewObjectToListViewEx( lpAP->lpIAB, _hWndAddr, NULL, NULL, lpsbContEID, ulObjType, &(lpAP->SortInfo), lpAP_lppContentsList, &ftLast, &cbEID, &lpEID); FreeBufferAndNull(&lpEID); SetFocus(_hWndAddr); lpAP->bDeferNotification = TRUE; lpAP_bDontRefresh = FALSE; lpAP->bLDAPinProgress = FALSE; } break; case IDM_LVCONTEXT_ADDWELL1: case IDC_ADDRBK_BUTTON_TO: if(!lpAP->bLDAPinProgress) { ULONG ulMapiTo = MAPI_TO; lpAP->bLDAPinProgress = TRUE; if ((lpAP->lpAdrParms->cDestFields > 0) && (lpAP->lpAdrParms->lpulDestComps)) { ulMapiTo = lpAP->lpAdrParms->lpulDestComps[0]; } if(ListAddItem(hDlg, _hWndAddr, IDC_ADDRBK_LIST_TO, lpAP_lppListTo, ulMapiTo)) SendMessage (hDlg, DM_SETDEFID, IDOK/*IDC_ADDRBK_BUTTON_OK*/, 0); lpAP->bLDAPinProgress = FALSE; } break; case IDM_LVCONTEXT_ADDWELL2: case IDC_ADDRBK_BUTTON_CC: if(!lpAP->bLDAPinProgress) { ULONG ulMapiCC = MAPI_CC; lpAP->bLDAPinProgress = TRUE; if ((lpAP->lpAdrParms->cDestFields > 0) && (lpAP->lpAdrParms->lpulDestComps)) { ulMapiCC = lpAP->lpAdrParms->lpulDestComps[1]; } if(ListAddItem(hDlg, _hWndAddr, IDC_ADDRBK_LIST_CC, lpAP_lppListCC, ulMapiCC)) SendMessage (hDlg, DM_SETDEFID, IDOK/*IDC_ADDRBK_BUTTON_OK*/, 0); lpAP->bLDAPinProgress = FALSE; } break; case IDM_LVCONTEXT_ADDWELL3: case IDC_ADDRBK_BUTTON_BCC: if(!lpAP->bLDAPinProgress) { ULONG ulMapiBCC = MAPI_BCC; lpAP->bLDAPinProgress = TRUE; if ((lpAP->lpAdrParms->cDestFields > 0) && (lpAP->lpAdrParms->lpulDestComps)) { ulMapiBCC = lpAP->lpAdrParms->lpulDestComps[2]; } if(ListAddItem(hDlg, _hWndAddr, IDC_ADDRBK_LIST_BCC, lpAP_lppListBCC, ulMapiBCC)) SendMessage (hDlg, DM_SETDEFID, IDOK/*IDC_ADDRBK_BUTTON_OK*/, 0); lpAP->bLDAPinProgress = FALSE; } break; case IDM_LVCONTEXT_FIND: case IDC_ADDRBK_BUTTON_FIND: if(!lpAP->bLDAPinProgress) { ADRPARM_FINDINFO apfi = {0}; LPADRPARM_FINDINFO lpapfi = NULL; ULONG ulOldFlags = lpAP->lpAdrParms->ulFlags; lpAP->bLDAPinProgress = TRUE; apfi.DialogState = lpAP->DialogState; if (lpAP->DialogState==STATE_SELECT_RECIPIENTS) { apfi.lpAdrParms = lpAP->lpAdrParms; apfi.lppTo = lpAP_lppListTo; apfi.lppCC = lpAP_lppListCC; apfi.lppBCC = lpAP_lppListBCC; lpapfi = &apfi; } else if (lpAP->DialogState == STATE_PICK_USER) { TCHAR sz[MAX_UI_STR]; LPTSTR lpsz = NULL; LoadString(hinstMapiX, idsPickUserSelect, sz, CharSizeOf(sz)); lpsz = (LPTSTR) sz; apfi.lpAdrParms = lpAP->lpAdrParms; apfi.lpAdrParms->cDestFields = 1; apfi.lpAdrParms->lppszDestTitles = &lpsz; // use resource apfi.lpAdrParms->ulFlags |= MAPI_UNICODE; apfi.cbEntryID = 0; apfi.lpEntryID = NULL; apfi.nRetVal = 0; lpapfi = &apfi; { // Setup the Find persistent info to show the name we are trying to resolve ULONG i; LPPTGDATA lpPTGData=GetThreadStoragePointer(); for(i=0;ilppAdrList)) { for(i=0;i<(*(lpAP->lppAdrList))->aEntries[0].cValues;i++) { ULONG ulPropTag = PR_DISPLAY_NAME; if(!(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE)) ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_STRING8); if ((*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].ulPropTag == ulPropTag) { LPTSTR lpTitle = NULL; SET_UNICODE_STR(lpTitle, (*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ,lpAP->lpAdrParms); StrCpyN(pt_LDAPsp.szData[ldspDisplayName], lpTitle, ARRAYSIZE(pt_LDAPsp.szData[ldspDisplayName])); FREE_UNICODE_STR(lpTitle, (*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ); break; } } } } } //lpAP_bDontRefresh = TRUE; HrShowSearchDialog(lpAP->lpIAB, hDlg, lpapfi, (LPLDAPURL) NULL, &(lpAP->SortInfo)); //lpAP_bDontRefresh = FALSE; lpAP->bLDAPinProgress = FALSE; // reset lpAP->lpAdrParms->ulFlags = ulOldFlags; if (lpAP->DialogState == STATE_PICK_USER) { // Reset these fake values lpAP->lpAdrParms->cDestFields = 0; lpAP->lpAdrParms->lppszDestTitles = NULL; // use resource // If the above dialog was CANCELed or CLOSEd, we dont do anything // If the above dialog was closed with the Use button, then we basically // have the person we were looking for .. we will just return that name // and EntryID because that is all we need to return if((lpapfi->nRetVal == SEARCH_USE) && lpapfi->lpEntryID && lpapfi->cbEntryID) { HCURSOR hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT)); // Prevent the user from doing anything on this window .. EnableWindow(hDlg, FALSE); // Figure out what to do here ... // We could add a hidden item to the listview, select it and send // an ok message to the dialog which would then do the needful. if(HR_FAILED(HrUpdateAdrListEntry( lpAP->lpIAB, lpapfi->lpEntryID, lpapfi->cbEntryID, (lpAP->lpAdrParms->ulFlags & MAPI_UNICODE)?MAPI_UNICODE:0, lpAP->lppAdrList))) { lpAP->nRetVal = -1; } else { lpAP->nRetVal = ADDRESS_OK; } LocalFreeAndNull(&(lpapfi->lpEntryID)); lpapfi->cbEntryID = 0; // Since we've done our processing, we'll fall thru to // the cancel dialog SetCursor(hOldCur); SendMessage (hDlg, WM_COMMAND, (WPARAM) IDC_ADDRBK_BUTTON_CANCEL, 0); } } } break; case IDC_ADDRBK_EDIT_QUICKFIND: if(!lpAP->bLDAPinProgress) { lpAP->bLDAPinProgress = TRUE; switch(HIWORD(wParam)) //check the notification code { case EN_CHANGE: //edit box changed /***/ DoLVQuickFind((HWND)lParam,_hWndAddr); /*** DoLVQuickFilter(lpAP->lpIAB, (HWND)lParam, _hWndAddr, &(lpAP->SortInfo), AB_FUZZY_FIND_NAME | AB_FUZZY_FIND_EMAIL, 1, lpAP_lppContentsList); ***/ break; } lpAP->bLDAPinProgress = FALSE; } break; case IDOK: case IDC_ADDRBK_BUTTON_OK: if(!lpAP->bLDAPinProgress) { HCURSOR hOldCur; lpAP->nRetVal = ADDRESS_OK; lpAP->hWaitCur = LoadCursor(NULL, IDC_WAIT); hOldCur = SetCursor(lpAP->hWaitCur); lpAP->bLDAPinProgress = TRUE; SetWindowLongPtr(hDlg, DWLP_MSGRESULT, MAKELONG(TRUE, 0)); //ShowWindow(hDlg, SW_HIDE); //EnableWindow(hDlg, FALSE); //SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); EnableWindow(GetDlgItem(hDlg, IDOK), FALSE); EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_FIND), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_TO), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_CC), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_BCC), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC), FALSE); EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_BCC), FALSE); EnableWindow(_hWndAddr, FALSE); // // Do TEXT("OK") stuff here and then Fall Thru to the cancel stuff // in PSN_RESET where we clean up // // if the ADDRESS_ONE flag was set we're supposed to return the // selected entry // // else if wells were displayed we return the recipients in the AdrList // // else we dont change the AdrList .. // if (lpAP->DialogState == STATE_PICK_USER) { // We have been asked to return an entry in the LpAdrList, // we dont care about recipient type - just Display Name and EntryID // First check if anything is selected at all int iItemIndex = ListView_GetNextItem(_hWndAddr,-1,LVNI_SELECTED); if (iItemIndex != -1) { LPRECIPIENT_INFO lpItem = GetItemFromLV(_hWndAddr, iItemIndex); if (lpItem) { if(HR_FAILED(HrUpdateAdrListEntry( lpAP->lpIAB, lpItem->lpEntryID, lpItem->cbEntryID, (lpAP->lpAdrParms->ulFlags & MAPI_UNICODE)?MAPI_UNICODE:0, lpAP->lppAdrList))) { lpAP->nRetVal = -1; } } } } else if ((lpAP->DialogState==STATE_SELECT_RECIPIENTS) && ((*lpAP_lppListTo)||(*lpAP_lppListCC)||(*lpAP_lppListBCC))) { // //if user selected something in the TO/CC wells, we want to return //a relevant AdrList back ... // ULONG ulcEntryCount = 0; LPRECIPIENT_INFO lpItem = NULL; // // get a count of how many elements we need to return // lpItem = (*lpAP_lppListTo); while(lpItem) { ulcEntryCount++; lpItem = lpItem->lpNext; } lpItem = (*lpAP_lppListCC); while(lpItem) { ulcEntryCount++; lpItem = lpItem->lpNext; } lpItem = (*lpAP_lppListBCC); while(lpItem) { ulcEntryCount++; lpItem = lpItem->lpNext; } if (ulcEntryCount != 0) { ULONG nIndex = 0; LPADRENTRY lpAdrEntryTemp = NULL; LPADRLIST lpAdrList = NULL; SCODE sc; BOOL bProcessingCC = FALSE; // // if there was something in the passed in AdrList, free it and // create a new list // if(!FAILED(sc = MAPIAllocateBuffer( sizeof(ADRLIST) + ulcEntryCount * sizeof(ADRENTRY), &lpAdrList))) { lpAdrList->cEntries = ulcEntryCount; nIndex = 0; // Start getting items from the TO list lpItem = (*lpAP_lppListTo); while(nIndex < ulcEntryCount) { if (lpItem == NULL) { if (bProcessingCC == FALSE) { lpItem = (*lpAP_lppListCC); bProcessingCC = TRUE; } else lpItem = (*lpAP_lppListBCC); } if (lpItem != NULL) { LPSPropValue rgProps = NULL; ULONG cValues = 0; LPSPropValue lpPropArrayNew = NULL; ULONG cValuesNew = 0; LPTSTR lpszTemp = NULL; LPVOID lpbTemp = NULL; ULONG i = 0; SCODE sc; HRESULT hr = hrSuccess; //reset hr hr = hrSuccess; // We are walking through our linked lists representing the TO and CC // selected recipients. We want to return proper set of existing props // for all the resolved users and the passed in set of props for the // unresolved user. Hence we compare to see what we can get for each // individual user. For unresolved users, the only distinctive criteria is // their display name .. we have no other information .. this is // problematic because if there are 2 entries in the input adrlist with the // same unresolved display name, even if they have difference rgPropVals // we might end up giving them identical ones back .... what to do .. // Items that have entry ids are resolved ... items that dont have entryids // are not resolved ... if (lpItem->cbEntryID != 0) { // if this was an item from the original list .. we dont really // want to mess with it irrespective of whether it is a resolved // or unresolved entry. // However, if this is a new entry, then we want to get its // minimum props from the store ... if (lpItem->ulOldAdrListEntryNumber == 0) { //resolved entry hr = HrGetPropArray(lpAP->lpIAB, (LPSPropTagArray) &ptaResolveDefaults, lpItem->cbEntryID, lpItem->lpEntryID, (lpAP->lpAdrParms->ulFlags & MAPI_UNICODE) ? MAPI_UNICODE : 0, &cValues, &rgProps); } else { rgProps = NULL; cValues = 0; } if (!HR_FAILED(hr)) { if(lpItem->ulOldAdrListEntryNumber != 0) { ULONG index = lpItem->ulOldAdrListEntryNumber - 1; //remember the increment-by-one .. // This is from the original entry list ... // We want to merge the newly generated properties with the old // original properties .. the original properties will include a // PR_RECIPIENT_TYPE (or this entry would have been rejected) sc = ScMergePropValues( (*(lpAP->lppAdrList))->aEntries[index].cValues, (*(lpAP->lppAdrList))->aEntries[index].rgPropVals, cValues, rgProps, &cValuesNew, &lpPropArrayNew); if (sc != S_OK) { // If errors then dont merge .. just take the temp set of props // in rgProps if (lpPropArrayNew) MAPIFreeBuffer(lpPropArrayNew); lpPropArrayNew = rgProps; cValuesNew = cValues; lpAP->nRetVal = -1; } else { // merged successfully, discard the temp sets of props if (rgProps) MAPIFreeBuffer(rgProps); } } else { // totally new item // we have to give it a valid PR_RECIPIENT_TYPE // so create a new one and merge it with the above props SPropValue Prop = {0}; Prop.ulPropTag = PR_RECIPIENT_TYPE; Prop.Value.l = lpItem->ulRecipientType; sc = ScMergePropValues( 1, &Prop, cValues, rgProps, &cValuesNew, &lpPropArrayNew); if (sc != S_OK) { // oops this failed if (lpPropArrayNew) MAPIFreeBuffer(lpPropArrayNew); lpPropArrayNew = NULL; lpAP->nRetVal = -1; } //free rgProps if (rgProps) MAPIFreeBuffer(rgProps); } // end have previous adr list items // [PaulHi] 2/15/99 Make sure that the new property string // values are converted to ANSI if our client is non-UNICODE. if ( !FAILED(sc) && !(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE) && lpPropArrayNew ) { sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArrayNew, cValuesNew, 0); if (FAILED(sc)) { if (lpPropArrayNew) MAPIFreeBuffer(lpPropArrayNew); lpPropArrayNew = NULL; lpAP->nRetVal = -1; } } } // end GetProps succeeded } else { // this is an unresolved entry // we need to get its original sets of props from the original AdrList if (lpItem->ulOldAdrListEntryNumber == 0) { // ouch - this kind of error shouldnt have happened DebugPrintError(( TEXT("Address: Unresolved entry has no index number!!!\n"))); lpAP->nRetVal = -1; //error code } else { ULONG cb = 0; ULONG index = lpItem->ulOldAdrListEntryNumber - 1; //remember to decrement the +1 increment cValuesNew = (*(lpAP->lppAdrList))->aEntries[index].cValues; // copy over the props from our old array into a new one if (!(FAILED(sc = ScCountProps( cValuesNew, (*(lpAP->lppAdrList))->aEntries[index].rgPropVals, &cb)))) { if (!(FAILED(sc = MAPIAllocateBuffer(cb, &lpPropArrayNew)))) { if (FAILED(sc = ScCopyProps( cValuesNew, (*(lpAP->lppAdrList))->aEntries[index].rgPropVals, lpPropArrayNew, NULL))) { DebugPrintError(( TEXT("Address: ScCopyProps fails!!!\n"))); lpAP->nRetVal = -1; } } else { lpAP->nRetVal = -1; } } else { lpAP->nRetVal = -1; } } } // At this point, if we've still got no errors, // we should have a valid lpPropArrayNew and cValuesNew which we should // be able to add to our new AdrList if (lpAP->nRetVal != -1) { lpAdrList->aEntries[nIndex].cValues = cValuesNew; lpAdrList->aEntries[nIndex].rgPropVals = lpPropArrayNew; } else { // some error if (lpPropArrayNew) { MAPIFreeBuffer(lpPropArrayNew); lpPropArrayNew = NULL; } } lpItem = lpItem->lpNext; nIndex++; } } if (*(lpAP->lppAdrList)) { FreePadrlist(*(lpAP->lppAdrList)); } *(lpAP->lppAdrList) = lpAdrList; } } } else if ((lpAP->DialogState==STATE_SELECT_RECIPIENTS) && ((*lpAP_lppListTo)==NULL) && ((*lpAP_lppListCC)==NULL) && ((*lpAP_lppListBCC)==NULL)) { // we were asked to select recipients but if these pointers are null // then the user deleted the entries in the wells and we thus dont // want to return anything. So free the lpaddrlist // and make it NULL if (*(lpAP->lppAdrList)) { // Bug 27483 - dont NULL the lpAdrList - just set cEntries to 0 ULONG iEntry = 0; for (iEntry = 0; iEntry < (*(lpAP->lppAdrList))->cEntries; iEntry++) { MAPIFreeBuffer((*(lpAP->lppAdrList))->aEntries[iEntry].rgPropVals); } (*(lpAP->lppAdrList))->cEntries = 0; } } // // Save the sort info to the registry // if(lpAP->DialogState != STATE_PICK_USER) WriteRegistrySortInfo((LPIAB)lpAP->lpIAB, lpAP->SortInfo); lpAP->bLDAPinProgress = FALSE; lpAP->hWaitCur = NULL; SetCursor(hOldCur); } // fall thru to cleanup code case IDCANCEL: case IDC_ADDRBK_BUTTON_CANCEL: if(!lpAP->bLDAPinProgress) { if ((lpAP->nRetVal != ADDRESS_OK) && // Are we falling thru from above ?? (lpAP->nRetVal != -1) ) // or did someone trigger an error above ?? { // if not .. lpAP->nRetVal = ADDRESS_CANCEL; } if ((*lpAP_lppContentsList)) ClearListView( GetDlgItem(hDlg, IDC_ADDRBK_LIST_ADDRESSES), lpAP_lppContentsList); if ((*lpAP_lppListTo)) ClearListView( GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO), lpAP_lppListTo); if ((*lpAP_lppListCC)) ClearListView( GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC), lpAP_lppListCC); if ((*lpAP_lppListBCC)) ClearListView( GetDlgItem(hDlg, IDC_ADDRBK_LIST_BCC), lpAP_lppListBCC); lpAP->bLDAPinProgress = FALSE; EndDialog(hDlg,lpAP->nRetVal); return TRUE; } break; } break; case WM_CLOSE: //treat it like a cancel button SendMessage (hDlg, WM_COMMAND, (WPARAM) IDC_ADDRBK_BUTTON_CANCEL, 0); break; case WM_CONTEXTMENU: { int id = GetDlgCtrlID((HWND)wParam); // //This call to the context menu may generate any one of several //command messages - for properties and for delete, we need to //know which List View initiated the command ... // lpAP->nContextID = id; switch(id) { case IDC_ADDRBK_LIST_ADDRESSES: if (lpAP->DialogState == STATE_BROWSE_MODAL) ShowLVContextMenu( lvDialogModalABContents, (HWND)wParam, NULL, //GetDlgItem(hDlg, IDC_ADDRBK_COMBO_SHOWNAMES), lParam, (LPVOID) lpAP->lpAdrParms, lpAP->lpIAB, NULL); else ShowLVContextMenu( lvDialogABContents, (HWND)wParam, NULL, //GetDlgItem(hDlg, IDC_ADDRBK_COMBO_SHOWNAMES), lParam, (LPVOID) lpAP->lpAdrParms, lpAP->lpIAB, NULL); break; case IDC_ADDRBK_LIST_TO: ShowLVContextMenu(lvDialogABTo,(HWND)wParam, NULL, lParam, NULL,lpAP->lpIAB, NULL); break; case IDC_ADDRBK_LIST_BCC: ShowLVContextMenu(lvDialogABCC,(HWND)wParam, NULL, lParam, NULL,lpAP->lpIAB, NULL); break; case IDC_ADDRBK_LIST_CC: ShowLVContextMenu(lvDialogABBCC,(HWND)wParam, NULL, lParam, NULL,lpAP->lpIAB, NULL); break; default: //reset it .. lpAP->nContextID = -1; WABWinHelp((HWND) wParam, g_szWABHelpFileName, HELP_CONTEXTMENU, (DWORD_PTR)(LPVOID) rgAddrHelpIDs ); break; } } break; case WM_NOTIFY: { LV_DISPINFO * pLvdi = (LV_DISPINFO *)lParam; NM_LISTVIEW * pNm = (NM_LISTVIEW *)lParam; switch((int) wParam) { case IDC_ADDRBK_LIST_TO: case IDC_ADDRBK_LIST_CC: case IDC_ADDRBK_LIST_BCC: switch(((LV_DISPINFO *)lParam)->hdr.code) { case LVN_KEYDOWN: switch(((LV_KEYDOWN FAR *) lParam)->wVKey) { case VK_DELETE: if ((int) wParam == IDC_ADDRBK_LIST_TO) ListDeleteItem(hDlg, (int) wParam, lpAP_lppListTo); else if ((int) wParam == IDC_ADDRBK_LIST_CC) ListDeleteItem(hDlg, (int) wParam, lpAP_lppListCC); else ListDeleteItem(hDlg, (int) wParam, lpAP_lppListBCC); break; } break; case NM_SETFOCUS: lpAP->nContextID = GetDlgCtrlID(((NM_LISTVIEW *)lParam)->hdr.hwndFrom); break; case NM_DBLCLK: //properties of the item ... lpAP->nContextID = GetDlgCtrlID(((NM_LISTVIEW *)lParam)->hdr.hwndFrom); SendMessage (hDlg, WM_COMMAND, (WPARAM) IDM_LVCONTEXT_PROPERTIES, 0); break; case NM_CUSTOMDRAW: return ProcessLVCustomDraw(hDlg, lParam, TRUE); break; } break; case IDC_ADDRBK_LIST_ADDRESSES: switch(pLvdi->hdr.code) { case LVN_KEYDOWN: switch(((LV_KEYDOWN FAR *) lParam)->wVKey) { case VK_DELETE: if (lpAP->DialogState == STATE_BROWSE_MODAL) SendMessage(hDlg, WM_COMMAND, IDC_ADDRBK_BUTTON_DELETE, 0); break; } break; case LVN_COLUMNCLICK: SortListViewColumn((LPIAB)lpAP->lpIAB, pNm->hdr.hwndFrom, pNm->iSubItem, &(lpAP->SortInfo), FALSE); break; case NM_CLICK: case NM_RCLICK: if(lpAP->DialogState == STATE_PICK_USER) { int iItemIndex = ListView_GetNextItem(pNm->hdr.hwndFrom,-1,LVNI_SELECTED); if (iItemIndex == -1) { //Nothing is selected .. dont let them say OK EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/),FALSE); SendMessage (hDlg, DM_SETDEFID, IDCANCEL, 0); } else { EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/),TRUE); SendMessage (hDlg, DM_SETDEFID, IDOK, 0); } } break; case NM_SETFOCUS: lpAP->nContextID = GetDlgCtrlID(pNm->hdr.hwndFrom); if(lpAP->DialogState == STATE_PICK_USER) { int iItemIndex = ListView_GetNextItem(pNm->hdr.hwndFrom,-1,LVNI_SELECTED); if (iItemIndex == -1) { //Nothing is selected .. dont let them say OK EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/),FALSE); SendMessage (hDlg, DM_SETDEFID, IDCANCEL, 0); } else { EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/),TRUE); SendMessage (hDlg, DM_SETDEFID, IDOK, 0); } } break; case NM_DBLCLK: { //if an entry is selected - do this - otherwise dont do anything int iItemIndex = ListView_GetNextItem(pNm->hdr.hwndFrom,-1,LVNI_SELECTED); if (iItemIndex == -1) break; { //DWORD dwDefId = SendMessage(hDlg, DM_GETDEFID, 0, 0); //if(dwDefId) // SendMessage(hDlg, WM_COMMAND, (WPARAM) LOWORD(dwDefId), 0); SendMessage(hDlg, WM_COMMAND, (WPARAM) IDC_ADDRBK_BUTTON_TO + lpAP->lpAdrParms->nDestFieldFocus, 0); } } break; case NM_CUSTOMDRAW: return ProcessLVCustomDraw(hDlg, lParam, TRUE); break; } break; } } break; default: if( (g_msgMSWheel && message == g_msgMSWheel) // || message == WM_MOUSEWHEEL ) { if(GetFocus() == GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO)) SendMessage(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO), message, wParam, lParam); else if(GetFocus() == GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC)) SendMessage(GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC), message, wParam, lParam); else if(GetFocus() == GetDlgItem(hDlg, IDC_ADDRBK_LIST_BCC)) SendMessage(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO), message, wParam, lParam); else SendMessage(_hWndAddr, message, wParam, lParam); } break; } return FALSE; } ///////////////////////////////////////////////////////////////////////////////// // // ListAddItem - Adds an item to the wells // // hDlg - HWND of parent // hWndAddr - HWND of source ListView from which the item will be added // CtlID - control ID of the target list view // lppList - Item list corresponding to the target list view to which this item will be appended // RecipientType - Specified recipient type to tag the new item with // ///////////////////////////////////////////////////////////////////////////////// BOOL ListAddItem(HWND hDlg, HWND hWndAddr, int CtlID, LPRECIPIENT_INFO * lppList, ULONG RecipientType) { BOOL bRet = FALSE; int iItemIndex = 0; HWND hWndList = GetDlgItem(hDlg,CtlID); iItemIndex = ListView_GetNextItem(hWndAddr,-1,LVNI_SELECTED); if (iItemIndex != -1) { int iLastIndex = 0; do { // otherwise get the entry id of this thing LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndAddr, iItemIndex); if (lpItem) { LV_ITEM lvI; LPRECIPIENT_INFO lpNew = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO)); if(!lpNew) { DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n"))); goto out; } lpNew->ulObjectType = lpItem->ulObjectType; StrCpyN(lpNew->szDisplayName, lpItem->szDisplayName, ARRAYSIZE(lpNew->szDisplayName)); StrCpyN(lpNew->szByFirstName, lpItem->szByFirstName, ARRAYSIZE(lpNew->szByFirstName)); StrCpyN(lpNew->szByLastName, lpItem->szByLastName, ARRAYSIZE(lpNew->szByLastName)); StrCpyN(lpNew->szEmailAddress, lpItem->szEmailAddress, ARRAYSIZE(lpNew->szEmailAddress)); StrCpyN(lpNew->szHomePhone, lpItem->szHomePhone, ARRAYSIZE(lpNew->szHomePhone)); StrCpyN(lpNew->szOfficePhone, lpItem->szOfficePhone, ARRAYSIZE(lpNew->szOfficePhone)); lpNew->bHasCert = lpItem->bHasCert; lpNew->ulRecipientType = RecipientType; lpNew->ulOldAdrListEntryNumber = 0; //Flag this as not from the original AdrList if (lpItem->cbEntryID) { lpNew->cbEntryID = lpItem->cbEntryID; lpNew->lpEntryID = LocalAlloc(LMEM_ZEROINIT, lpItem->cbEntryID); if(!lpNew->lpEntryID) { DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n"))); LocalFree(lpNew); goto out; } CopyMemory(lpNew->lpEntryID,lpItem->lpEntryID,lpItem->cbEntryID); } lpNew->lpNext = (*lppList); if (*lppList) (*lppList)->lpPrev = lpNew; lpNew->lpPrev = NULL; (*lppList) = lpNew; lvI.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; lvI.state = 0; lvI.stateMask = 0; lvI.iSubItem = 0; lvI.cchTextMax = MAX_DISPLAY_NAME_LENGTH; lvI.iImage = GetWABIconImage(lpNew); // now fill in the List lvI.iItem = ListView_GetItemCount(hWndList); lvI.pszText = lpNew->szDisplayName; lvI.lParam = (LPARAM) lpNew; ListView_InsertItem(hWndList, &lvI); ListView_EnsureVisible(hWndList,ListView_GetItemCount(hWndList)-1,FALSE); } iLastIndex = iItemIndex; // Get next selected item ... iItemIndex = ListView_GetNextItem(hWndAddr,iLastIndex,LVNI_SELECTED); } while (iItemIndex != -1); //SetFocus(hWndAddr); } else { ShowMessageBox(hDlg, IDS_ADDRBK_MESSAGE_NO_ITEMS_ADD, MB_ICONEXCLAMATION); goto out; } if((ListView_GetItemCount(hWndList) > 0) && (ListView_GetSelectedCount(hWndList) <= 0)) LVSelectItem(hWndList, 0); bRet = TRUE; out: return bRet; } ///////////////////////////////////////////////////////////////////////////////// // // ListDeleteItem - deletes an item from the Wells - unlike the Address COntents list we // make sure to delete it here because we want the linked lists to only have valid entries // // ///////////////////////////////////////////////////////////////////////////////// BOOL ListDeleteItem(HWND hDlg, int CtlID, LPRECIPIENT_INFO * lppList) { BOOL bRet = TRUE; LPRECIPIENT_INFO lpItem = NULL; HWND hWndAddr = GetDlgItem(hDlg,CtlID); int iItemIndex=0; iItemIndex = ListView_GetNextItem(hWndAddr,-1,LVNI_SELECTED); if (iItemIndex != -1) { int iLastItem = 0; do { // otherwise get the entry id of this thing lpItem = GetItemFromLV(hWndAddr, iItemIndex); if (lpItem) { // remove this item from our linked list of arrays // if this is the first item in the list then handle that special case too if ((*lppList) == lpItem) (*lppList) = lpItem->lpNext; if (lpItem->lpNext) lpItem->lpNext->lpPrev = lpItem->lpPrev; if (lpItem->lpPrev) lpItem->lpPrev->lpNext = lpItem->lpNext; // we need to update our display ListView_DeleteItem(hWndAddr,iItemIndex); //UpdateWindow(hWndAddr); FreeRecipItem(&lpItem); } iLastItem = iItemIndex; // Get next selected item ... iItemIndex = ListView_GetNextItem(hWndAddr,-1,LVNI_SELECTED); }while (iItemIndex != -1); // select the previous or next item ... if (iLastItem >= ListView_GetItemCount(hWndAddr)) iLastItem = ListView_GetItemCount(hWndAddr) - 1; LVSelectItem(hWndAddr, iLastItem); } SetFocus(hWndAddr); return bRet; } ///////////////////////////////////////////////////////////////////////////////// // // FillWells - Dismembers the lpAdrList to create the To and CC wells // // Scans the AdrEntry Structures in the LpAdrList, looks at PR_RECIPIENT_TYPE, // ignores entries which it cant understand ... creates a temporary linked // list of To and CC recipient lists which are used to populate the // To and CC List boxes // ///////////////////////////////////////////////////////////////////////////////// BOOL FillWells(HWND hDlg, LPADRLIST lpAdrList, LPADRPARM lpAdrParms, LPRECIPIENT_INFO * lppListTo, LPRECIPIENT_INFO * lppListCC, LPRECIPIENT_INFO * lppListBCC) { BOOL bRet = FALSE; LPRECIPIENT_INFO lpNew = NULL; LPADRENTRY lpAdrEntry = NULL; ULONG i=0,j=0,nLen=0; int index=0; LV_ITEM lvI; HWND hWndAddr = NULL; ULONG ulMapiTo = MAPI_TO; ULONG ulMapiCC = MAPI_CC; ULONG ulMapiBCC = MAPI_BCC; BOOL bUnicode = (lpAdrParms->ulFlags & MAPI_UNICODE); *lppListTo = NULL; *lppListCC = NULL; *lppListBCC = NULL; if (lpAdrList == NULL) //nothing to do { bRet = TRUE; goto out; } // // The Input AdrParms structure has a lpulDestComps field that lets the // caller specify his own recipient types. If this is missing, we are supposed // to use the default recipient types. // if ((lpAdrParms->cDestFields > 0) && (lpAdrParms->lpulDestComps)) { ULONG i=0; for (i=0;icDestFields;i++) { switch(i) { case 0: ulMapiTo = lpAdrParms->lpulDestComps[i]; break; case 1: ulMapiCC = lpAdrParms->lpulDestComps[i]; break; case 2: ulMapiBCC = lpAdrParms->lpulDestComps[i]; break; } } } for(i=0; i < lpAdrList->cEntries; i++) { lpAdrEntry = &(lpAdrList->aEntries[i]); if (lpAdrEntry->cValues != 0) { TCHAR szBuf[MAX_DISPLAY_NAME_LENGTH]; ULONG ulRecipientType = 0; ULONG ulObjectType = 0; ULONG cbEntryID = 0; BOOL bHasCert = FALSE; LPENTRYID lpEntryID = NULL; szBuf[0]='\0'; for(j=0;jcValues;j++) { ULONG ulPropTag = lpAdrEntry->rgPropVals[j].ulPropTag; if(!bUnicode && PROP_TYPE(ulPropTag) == PT_STRING8) ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_UNICODE); switch(ulPropTag) { case(PR_DISPLAY_NAME): { LPTSTR lpNameW = NULL; SET_UNICODE_STR(lpNameW, lpAdrEntry->rgPropVals[j].Value.LPSZ,lpAdrParms); nLen = CopyTruncate(szBuf, lpNameW, MAX_DISPLAY_NAME_LENGTH); FREE_UNICODE_STR(lpNameW, lpAdrEntry->rgPropVals[j].Value.LPSZ); } break; case(PR_RECIPIENT_TYPE): ulRecipientType = lpAdrEntry->rgPropVals[j].Value.l; break; case(PR_OBJECT_TYPE): ulObjectType = lpAdrEntry->rgPropVals[j].Value.l; break; case(PR_ENTRYID): cbEntryID = lpAdrEntry->rgPropVals[j].Value.bin.cb; lpEntryID = (LPENTRYID) lpAdrEntry->rgPropVals[j].Value.bin.lpb; break; case PR_USER_X509_CERTIFICATE: bHasCert = TRUE; break; } } if (lstrlen(szBuf) && ((ulRecipientType == ulMapiBCC) || (ulRecipientType == ulMapiTo) || (ulRecipientType == ulMapiCC))) { lpNew = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO)); if(!lpNew) { DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n"))); goto out; } // ***NOTE*** // Store this index number, ie 1st item in AdrList is 1, then 2, 3, so on // we do a plus 1 here because 0 value means it wasnt passed in and thus the // minimum valid value is 1 lpNew->ulOldAdrListEntryNumber = i+1; lpNew->bHasCert = bHasCert; StrCpyN(lpNew->szDisplayName,szBuf,ARRAYSIZE(lpNew->szDisplayName)); lpNew->ulRecipientType = ulRecipientType; lpNew->ulObjectType = ulObjectType; if (cbEntryID != 0) { lpNew->cbEntryID = cbEntryID; lpNew->lpEntryID = LocalAlloc(LMEM_ZEROINIT,cbEntryID); if(!lpNew->lpEntryID) { DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n"))); goto out; } CopyMemory(lpNew->lpEntryID,lpEntryID,cbEntryID); } if (ulRecipientType == ulMapiTo) { lpNew->lpNext = *lppListTo; if (*lppListTo) (*lppListTo)->lpPrev = lpNew; lpNew->lpPrev = NULL; *lppListTo = lpNew; } else if (ulRecipientType == ulMapiCC) { lpNew->lpNext = *lppListCC; if (*lppListCC) (*lppListCC)->lpPrev = lpNew; lpNew->lpPrev = NULL; *lppListCC = lpNew; } else if (ulRecipientType == ulMapiBCC) { lpNew->lpNext = *lppListBCC; if (*lppListBCC) (*lppListBCC)->lpPrev = lpNew; lpNew->lpPrev = NULL; *lppListBCC = lpNew; } } } } lvI.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; lvI.state = 0; lvI.stateMask = 0; lvI.iSubItem = 0; lvI.cchTextMax = MAX_DISPLAY_NAME_LENGTH; for(i=0;i<3;i++) { switch(i) { case 0: lpNew = *lppListTo; break; case 1: lpNew = *lppListCC; break; case 2: lpNew = *lppListBCC; break; } hWndAddr = GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO+i); index = 0; while(lpNew) { lvI.iItem = index; lvI.pszText = lpNew->szDisplayName; lvI.lParam = (LPARAM) lpNew; lvI.iImage = GetWABIconImage(lpNew); ListView_InsertItem(hWndAddr, &lvI); index++; lpNew = lpNew->lpNext; } } // We will highlight the first item in any filled list box // because basically that looks good when tabbing through them ... for(i=0;icDestFields;i++) { HWND hWndLV = GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO+i); if (ListView_GetItemCount(hWndLV) > 0) LVSelectItem(hWndLV,0); } bRet = TRUE; out: return bRet; } ///////////////////////////////////////////////////////////////////////////////// // // SetAddressBookUI - juggles the address book UI in response to various parameters // // This function will probably be more complex with each tier // // // ///////////////////////////////////////////////////////////////////////////////// BOOL SetAddressBookUI(HWND hDlg, LPADDRESS_PARMS lpAP) { BOOL bRet = FALSE; //LV_COLUMN lvC; RECT rc, rc1, rc2; POINT ptLU1,ptRB1; int nButtonsVisible = 0; int nButtonSpacing = 7; int nButtonWidth = 0; ULONG nLen = 0; TCHAR szBuf[MAX_UI_STR*4]; LPPTGDATA lpPTGData=GetThreadStoragePointer(); HWND hWndListAddresses = GetDlgItem(hDlg, IDC_ADDRBK_LIST_ADDRESSES); LPTSTR szCaption = NULL; SET_UNICODE_STR(szCaption, lpAP->lpAdrParms->lpszCaption,lpAP->lpAdrParms); if(!szCaption || !lstrlen(szCaption)) { LoadString(hinstMapiX, IDS_ADDRBK_CAPTION, szBuf, CharSizeOf(szBuf)); szCaption = szBuf; } // Set the font of all the children to the default GUI font EnumChildWindows( hDlg, SetChildDefaultGUIFont, (LPARAM) 0); if(pt_bIsWABOpenExSession || bIsWABSessionProfileAware((LPIAB)lpAP->lpIAB)) { // Fill in the Combo with the container names FillContainerCombo(GetDlgItem(hDlg, IDC_ADDRBK_COMBO_CONT), (LPIAB)lpAP->lpIAB); } else { HWND hWndCombo = GetDlgItem(hDlg, IDC_ADDRBK_COMBO_CONT); EnableWindow(hWndCombo, FALSE); ShowWindow(hWndCombo, SW_HIDE); // resize the listview to take place of the hidden combo GetWindowRect(hWndCombo,&rc2); GetWindowRect(hWndListAddresses,&rc); // //This api works for both mirrored and unmirrored windows. // MapWindowPoints(NULL, hDlg, (LPPOINT)&rc2, 2); MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2); ptLU1.x = rc2.left; ptLU1.y = rc2.top; ptRB1.x = rc.right; ptRB1.y = rc.bottom; MoveWindow(hWndListAddresses,ptLU1.x,ptLU1.y,(ptRB1.x - ptLU1.x), (ptRB1.y - ptLU1.y), TRUE); } // // There are only two states that need configuration - // Pick User - in which we have to hide the wells // and // Select Recipients, in which we have to hide the wells // as per the input criteria and resize accordingly and // also set the labels based on the input criteria // if (lpAP->DialogState == STATE_SELECT_RECIPIENTS) { SendMessage (hDlg, DM_SETDEFID, IDC_ADDRBK_BUTTON_TO, 0); // in case the nDestFieldFocus parameter is supplied, use it .. if ( (lpAP->lpAdrParms->nDestFieldFocus < lpAP->lpAdrParms->cDestFields)) { if (lpAP->lpAdrParms->nDestFieldFocus == 1) SendMessage (hDlg, DM_SETDEFID, IDC_ADDRBK_BUTTON_CC, 0); else if (lpAP->lpAdrParms->nDestFieldFocus == 2) SendMessage (hDlg, DM_SETDEFID, IDC_ADDRBK_BUTTON_BCC, 0); } } else if (lpAP->DialogState == STATE_PICK_USER) SendMessage (hDlg, DM_SETDEFID, IDOK/*IDC_ADDRBK_BUTTON_OK*/, 0); else if (lpAP->DialogState == STATE_BROWSE_MODAL) SendMessage (hDlg, DM_SETDEFID, IDC_ADDRBK_BUTTON_PROPS, 0); // Set the window caption if (szCaption) SetWindowText(hDlg,szCaption); // Set the caption over the destination wells if (lpAP->lpAdrParms->lpszDestWellsTitle) { LPWSTR lpTitle = NULL; // assumes UNICODE defined SET_UNICODE_STR(lpTitle,lpAP->lpAdrParms->lpszDestWellsTitle,lpAP->lpAdrParms); SetDlgItemText(hDlg,IDC_ADDRBK_STATIC_RECIP_TITLE,lpTitle); FREE_UNICODE_STR(lpTitle, lpAP->lpAdrParms->lpszDestWellsTitle); } if (lpAP->DialogState == STATE_PICK_USER && *(lpAP->lppAdrList) ) { ULONG i=0; LPTSTR lpszRecipName = NULL; //Get the user whose name we are trying to find for(i=0;i<(*(lpAP->lppAdrList))->aEntries[0].cValues;i++) { ULONG ulPropTag = PR_DISPLAY_NAME; if(!(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE)) ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_STRING8); if ((*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].ulPropTag == ulPropTag) { SET_UNICODE_STR(lpszRecipName,(*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ,lpAP->lpAdrParms); break; } } if(lpszRecipName) { LPTSTR lpszBuffer = NULL; TCHAR szTmp[MAX_PATH], *lpszTmp; LoadString(hinstMapiX, IDS_ADDRBK_RESOLVE_CAPTION, szBuf, CharSizeOf(szBuf)); CopyTruncate(szTmp, lpszRecipName, MAX_PATH - 1); lpszTmp = szTmp; if(FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER, szBuf, 0,0, //ignored (LPTSTR) &lpszBuffer, MAX_UI_STR, (va_list *)&lpszTmp)) { // if the display name is too long, it doesnt show up properly in the UI .. // so we will purposely limit the visible portion to 64 characters - arbitarily defined limit.. szBuf[0]='\0'; nLen = CopyTruncate(szBuf, lpszBuffer, 2 * MAX_DISPLAY_NAME_LENGTH); LocalFreeAndNull(&lpszBuffer); } //Increase the size of the static control to = what the Contents List width will be GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_CONTENTS),&rc2); GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO),&rc); // //This api working in both mirrored and unmirrored windows. // MapWindowPoints(NULL, hDlg, (LPPOINT)&rc2, 2); MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2); ptLU1.x = rc2.left; ptLU1.y = rc2.top; ptRB1.x = rc.right; ptRB1.y = rc2.bottom; MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_CONTENTS),ptLU1.x,ptLU1.y,(ptRB1.x - ptLU1.x), (ptRB1.y - ptLU1.y), TRUE); SetDlgItemText(hDlg,IDC_ADDRBK_STATIC_CONTENTS,szBuf); FREE_UNICODE_STR(lpszRecipName,(*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ); } } if (lpAP->DialogState == STATE_PICK_USER) { // If ADDRESS_ONE has been selected, then make the IDC_ADDRBK_LIST_ADDRESSES // single selection only DWORD dwStyle; dwStyle = GetWindowLong(hWndListAddresses, GWL_STYLE); SetWindowLong(hWndListAddresses, GWL_STYLE, dwStyle | LVS_SINGLESEL); } if ((lpAP->DialogState == STATE_PICK_USER)||(lpAP->DialogState == STATE_BROWSE_MODAL)) { int i = 0; // Dont show wells which means we have to do some rearranging // * Hide the wells and the To, CC, BCC buttons // * Resize the IDC_ADDRBK_LIST_ADDRESSES to fill the whole dialog // * Move the 3 buttons below it to the left side of the dialog // // Get the dimensions of the ToListBox GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO),&rc2); GetWindowRect(hWndListAddresses,&rc); // //This api works for in both mirrored and unmirrored windows. // MapWindowPoints(NULL, hDlg, (LPPOINT)&rc2, 2); MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2); ptLU1.x = rc.left; ptLU1.y = rc.top; ptRB1.x = rc2.right; ptRB1.y = rc.bottom; MoveWindow(hWndListAddresses,ptLU1.x,ptLU1.y,(ptRB1.x - ptLU1.x), (ptRB1.y - ptLU1.y), TRUE); for(i=0;i<3;i++) { ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_TO + i), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO + i), SW_HIDE); } ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_STATIC_RECIP_TITLE), SW_HIDE); // TEXT("Message Recipients") label } // other things to do // Load Headers for List box GetWindowRect(hWndListAddresses,&rc); HrInitListView(hWndListAddresses, LVS_REPORT, TRUE); GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_PROPS),&rc2); nButtonsVisible = 2; nButtonWidth = (rc2.right - rc2.left); // get the new coordinates of the 1st visible button // //This api working in both mirrored and unmirrored windows. // MapWindowPoints(NULL, hDlg, (LPPOINT)&rc2, 2); MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2); ptLU1.x = rc.left; ptLU1.y = rc2.top; ptRB1.x = ptLU1.x + nButtonWidth; ptRB1.y = rc2.bottom; MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW),ptLU1.x,ptLU1.y,nButtonWidth, (ptRB1.y - ptLU1.y), TRUE); ptLU1.x += nButtonWidth + nButtonSpacing; ptRB1.x = ptLU1.x + nButtonWidth; if (lpAP->DialogState == STATE_BROWSE_MODAL) { MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEWGROUP),ptLU1.x,ptLU1.y,nButtonWidth, (ptRB1.y - ptLU1.y), TRUE); ptLU1.x += nButtonWidth + nButtonSpacing; ptRB1.x = ptLU1.x + nButtonWidth; } else { // The NewGroup button is visible only in the DialogModalView EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_NEWGROUP), FALSE); ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_NEWGROUP), SW_HIDE); } MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_PROPS),ptLU1.x,ptLU1.y,nButtonWidth, (ptRB1.y - ptLU1.y), TRUE); ptLU1.x += nButtonWidth + nButtonSpacing; ptRB1.x = ptLU1.x + nButtonWidth; MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_DELETE),ptLU1.x,ptLU1.y,nButtonWidth, (ptRB1.y - ptLU1.y), TRUE); // The delete button is visible only in the DialogModalView if (lpAP->DialogState != STATE_BROWSE_MODAL) { EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_DELETE), FALSE); ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_DELETE), SW_HIDE); } // // We now need to customize this window if we are selecting // recipients ... // if (lpAP->DialogState == STATE_SELECT_RECIPIENTS) { // We need to see which wells are visible and // then we need to resize the buttons based on their captions // int i=0; int nLen=0; int cDF = lpAP->lpAdrParms->cDestFields; int iLeft=0,iTop=0; SIZE size={0}; ULONG MaxWidth=0; ULONG maxHeightPerLV = 0; HWND hw; HDC hdc=GetDC(hDlg); if (lpAP->lpAdrParms->lppszDestTitles) { for(i=0; i < cDF; i++) { LPTSTR lpTitle = NULL; ULONG Len = 0; SET_UNICODE_STR(lpTitle,lpAP->lpAdrParms->lppszDestTitles[i],lpAP->lpAdrParms); if(!lpTitle) continue; Len = lstrlen(lpTitle); if (Len > CharSizeOf(szBuf) - 4) { ULONG iLen = TruncatePos(lpTitle, CharSizeOf(szBuf) - 4); CopyMemory(szBuf,lpTitle,iLen*sizeof(TCHAR)); szBuf[iLen] = '\0'; } else { StrCpyN(szBuf,lpTitle,ARRAYSIZE(szBuf)); } StrCatBuff(szBuf,szArrow,ARRAYSIZE(szBuf)); if (lstrlen(szBuf) >= nLen) { nLen = lstrlen(szBuf); GetTextExtentPoint32(hdc, szBuf, nLen, &size); MaxWidth = size.cx; } // Set the new text SetDlgItemText(hDlg,IDC_ADDRBK_BUTTON_TO+i,szBuf); FREE_UNICODE_STR(lpTitle,lpAP->lpAdrParms->lppszDestTitles[i]); } } ReleaseDC(hDlg,hdc); if (MaxWidth == 0) { //get the default width GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_TO),&rc1); MaxWidth = rc1.right - rc1.left; } //Get the maximum allowable height per well GetWindowRect(hWndListAddresses,&rc); GetChildClientRect(hWndListAddresses, &rc); GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW),&rc1); GetChildClientRect(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW), &rc1); maxHeightPerLV = (rc1.bottom-rc.top - (cDF - 1)*CONTROL_SPACING)/cDF; iTop = rc.top; for(i=0;ilpIAB)) // need to move this to the same height as combo { int ht = rc2.bottom - rc2.top; rc2.bottom = rc.top - CONTROL_SPACING; rc2.top = rc2.bottom - ht; } MoveWindow(hw,iLeft,rc2.top,rc1.right-iLeft,rc2.bottom-rc2.top,FALSE); // Now we have the position and width of the list boxes .. need to get their height if (cDF!=3) //if not the default preset position, reposition { switch(cDF) { case 1: ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_CC), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC), SW_HIDE); case 2: ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_BCC), SW_HIDE); ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_BCC), SW_HIDE); break; } } for(i=0;ilpAdrParms->lpszCaption && szCaption != szBuf) LocalFreeAndNull(&szCaption); return bRet; } //$$/////////////////////////////////////////////////////////////////////////////////////////// // // UpdateLVItems .... // When we call properties on an object, its props can change ... // Since the particular user may appear in any of the 4 list views, // we have to make sure that all views are updated for that entry // /////////////////////////////////////////////////////////////////////////////////////////////// void UpdateLVItems(HWND hWndLV,LPTSTR lpszName) { // We have the handle to the list view initiating the Properties call // We know the old name to look for // // We know which item is selected - we can get its entryid and lParam // We then search all the list views for the old display name // if the old display name matches, we compare the entry id // if the entryid matches, then we update that item ... int iItemIndex = 0, iLastItemIndex = 0; LPRECIPIENT_INFO lpOriginalItem; ULONG i=0; ULONG nCount = 0; int id = 0; HWND hDlg = GetParent(hWndLV); HWND hw = NULL; LV_FINDINFO lvf={0}; if ( (ListView_GetSelectedCount(hWndLV) != 1) || (lpszName == NULL) ) { goto out; } iItemIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED); lpOriginalItem = GetItemFromLV(hWndLV, iItemIndex); if(!lpOriginalItem) goto out; // There can be upto 4 list view boxes in the view, each of which can // contain a displayed copy of this item .. // We want to go through all 4 and update all entries that match this item // Our strategy is to search for each and every item that // matches the display name - check its entry ID and if // the entry ID matches, update it ... lvf.flags = LVFI_STRING; lvf.psz = lpszName; for(i=0;i<4;i++) { switch(i) { case 0: id = IDC_ADDRBK_LIST_ADDRESSES; break; case 1: id = IDC_ADDRBK_LIST_TO; break; case 2: id = IDC_ADDRBK_LIST_CC; break; case 3: id = IDC_ADDRBK_LIST_BCC; break; } hw = GetDlgItem(hDlg,id); // if its hidden, ignore it if (!IsWindowVisible(hw)) continue; // if its empty, ignore it nCount = ListView_GetItemCount(hw); if (nCount <= 0) continue; // The contents list view wont have duplicates so ignore it if its the original if ((id == IDC_ADDRBK_LIST_ADDRESSES) && (hw == hWndLV)) continue; // see if we can find the matching items iLastItemIndex = -1; iItemIndex = ListView_FindItem(hw,iLastItemIndex,&lvf); while (iItemIndex != -1) { // inspect this item LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex); if (lpItem && (lpItem->cbEntryID != 0) && (lpOriginalItem->cbEntryID == lpItem->cbEntryID)) { if(!memcmp(lpOriginalItem->lpEntryID,lpItem->lpEntryID,lpItem->cbEntryID)) { // this is the same item ... update it if (lstrcmpi(lpItem->szDisplayName,lpOriginalItem->szDisplayName)) { ListView_SetItemText(hw,iItemIndex,colDisplayName,lpOriginalItem->szDisplayName); StrCpyN(lpItem->szDisplayName,lpOriginalItem->szDisplayName,ARRAYSIZE(lpItem->szDisplayName)); } if (lstrcmpi(lpItem->szEmailAddress,lpOriginalItem->szEmailAddress)) { ListView_SetItemText(hw,iItemIndex,colEmailAddress,lpOriginalItem->szEmailAddress); StrCpyN(lpItem->szEmailAddress,lpOriginalItem->szEmailAddress,ARRAYSIZE(lpItem->szEmailAddress)); } if (lstrcmpi(lpItem->szHomePhone,lpOriginalItem->szHomePhone)) { ListView_SetItemText(hw,iItemIndex,colHomePhone,lpOriginalItem->szHomePhone); StrCpyN(lpItem->szHomePhone,lpOriginalItem->szHomePhone,ARRAYSIZE(lpItem->szHomePhone)); } if (lstrcmpi(lpItem->szOfficePhone,lpOriginalItem->szOfficePhone)) { ListView_SetItemText(hw,iItemIndex,colOfficePhone,lpOriginalItem->szOfficePhone); StrCpyN(lpItem->szOfficePhone,lpOriginalItem->szOfficePhone,ARRAYSIZE(lpItem->szOfficePhone)); } if (lstrcmpi(lpItem->szByFirstName,lpOriginalItem->szByFirstName)) StrCpyN(lpItem->szByFirstName,lpOriginalItem->szByFirstName,ARRAYSIZE(lpItem->szByFirstName)); if (lstrcmpi(lpItem->szByLastName,lpOriginalItem->szByLastName)) StrCpyN(lpItem->szByLastName,lpOriginalItem->szByLastName,ARRAYSIZE(lpItem->szByLastName)); } } iLastItemIndex = iItemIndex; iItemIndex = ListView_FindItem(hw,iLastItemIndex,&lvf); } } out: return; } //$$/////////////////////////////////////////////////////////////////////////////////////////// // // ShowAddrBkLVProps .... // /////////////////////////////////////////////////////////////////////////////////////////////// void ShowAddrBkLVProps(LPIAB lpIAB, HWND hDlg, HWND hWndAddr,LPADDRESS_PARMS lpAP, LPFILETIME lpftLast) { // get the display name of this item TCHAR szName[MAX_DISPLAY_NAME_LENGTH]; szName[0]='\0'; if (ListView_GetSelectedCount(hWndAddr) == 1) { ListView_GetItemText( hWndAddr, ListView_GetNextItem(hWndAddr,-1,LVNI_SELECTED), 0, szName, CharSizeOf(szName)); } if( (MAPI_E_OBJECT_CHANGED == HrShowLVEntryProperties(hWndAddr, 0, lpAP->lpIAB, lpftLast)) && (szName) && (lpAP->DialogState == STATE_SELECT_RECIPIENTS) ) { // if the entry has changed and we have multiple list views visible, // we need to update all instances of the entry in all the list views // UpdateLVItems(hWndAddr,szName); SortListViewColumn(lpIAB, GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES), colDisplayName, &(lpAP->SortInfo), TRUE); } SetFocus(hWndAddr); } //$$/////////////////////////////////////////////////////////////////////////////////////////// // // HrUpdateAdrListEntry .... // // When returning from a PickUser operation, updates the // entry in the lpAdrList with the newly found item // // ulFLags 0 or MAPI_UNICODE passed down to GetProps // // Returns: Hr // /////////////////////////////////////////////////////////////////////////////////////////////// HRESULT HrUpdateAdrListEntry( LPADRBOOK lpIAB, LPENTRYID lpEntryID, ULONG cbEntryID, ULONG ulFlags, LPADRLIST * lppAdrList) { LPSPropValue rgProps = NULL; ULONG cValues = 0; LPSPropValue lpPropArrayNew = NULL; ULONG cValuesNew = 0; LPTSTR lpszTemp = NULL; LPVOID lpbTemp = NULL; ULONG i = 0; SCODE sc; HRESULT hr = E_FAIL; if (!lppAdrList || !lpEntryID || !lpIAB || !cbEntryID) goto out; hr = HrGetPropArray(lpIAB, (LPSPropTagArray) &ptaResolveDefaults, cbEntryID, lpEntryID, ulFlags, &cValues, &rgProps); if (!HR_FAILED(hr)) { if(!*lppAdrList) { // Allocate one .. LPADRLIST lpAdrList = NULL; sc = MAPIAllocateBuffer(sizeof(ADRLIST) + sizeof(ADRENTRY), &lpAdrList); if(FAILED(sc)) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } *lppAdrList = lpAdrList; (*lppAdrList)->cEntries = 1; (*lppAdrList)->aEntries[0].ulReserved1 = 0; (*lppAdrList)->aEntries[0].cValues = 0; (*lppAdrList)->aEntries[0].rgPropVals = NULL; } //Merge the new list with the old list sc = ScMergePropValues( (*lppAdrList)->aEntries[0].cValues, (*lppAdrList)->aEntries[0].rgPropVals, cValues, rgProps, &cValuesNew, &lpPropArrayNew); if (sc == S_OK) { // if OK replace the lpspropvalue array // if not we havent changed anything (*lppAdrList)->aEntries[0].cValues = cValuesNew; if((*lppAdrList)->aEntries[0].rgPropVals) MAPIFreeBuffer((*lppAdrList)->aEntries[0].rgPropVals); (*lppAdrList)->aEntries[0].rgPropVals = lpPropArrayNew; } else { // If errors Free up the allocated memory if (lpPropArrayNew) MAPIFreeBuffer(lpPropArrayNew); hr = E_FAIL; } } // we free this anyway whether the above succeeded or not if (rgProps) MAPIFreeBuffer(rgProps); out: return hr; }