Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

825 lines
21 KiB

  1. #include "wabobject.h"
  2. enum {
  3. ieidPR_DISPLAY_NAME = 0,
  4. ieidPR_ENTRYID,
  5. ieidPR_OBJECT_TYPE,
  6. ieidMax
  7. };
  8. static const SizedSPropTagArray(ieidMax, ptaEid)=
  9. {
  10. ieidMax,
  11. {
  12. PR_DISPLAY_NAME,
  13. PR_ENTRYID,
  14. PR_OBJECT_TYPE,
  15. }
  16. };
  17. enum {
  18. iemailPR_DISPLAY_NAME = 0,
  19. iemailPR_ENTRYID,
  20. iemailPR_EMAIL_ADDRESS,
  21. iemailPR_OBJECT_TYPE,
  22. iemailMax
  23. };
  24. static const SizedSPropTagArray(iemailMax, ptaEmail)=
  25. {
  26. iemailMax,
  27. {
  28. PR_DISPLAY_NAME,
  29. PR_ENTRYID,
  30. PR_EMAIL_ADDRESS,
  31. PR_OBJECT_TYPE
  32. }
  33. };
  34. /*********************************************************************************/
  35. // contructor for CWAB object
  36. //
  37. // pszFileName - FileName of WAB file to open
  38. // if no file name is specified, opens the default
  39. //
  40. CWAB::CWAB(CString * pszFileName)
  41. {
  42. // Here we load the WAB Object and initialize it
  43. m_bInitialized = FALSE;
  44. m_lpPropArray = NULL;
  45. m_ulcValues = 0;
  46. m_hWndModelessWABWindow = NULL;
  47. {
  48. TCHAR szWABDllPath[MAX_PATH];
  49. DWORD dwType = 0;
  50. ULONG cbData = sizeof(szWABDllPath);
  51. HKEY hKey = NULL;
  52. *szWABDllPath = '\0';
  53. // First we look under the default WAB DLL path location in the
  54. // Registry.
  55. // WAB_DLL_PATH_KEY is defined in wabapi.h
  56. //
  57. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, WAB_DLL_PATH_KEY, 0, KEY_READ, &hKey))
  58. RegQueryValueEx( hKey, "", NULL, &dwType, (LPBYTE) szWABDllPath, &cbData);
  59. if(hKey) RegCloseKey(hKey);
  60. // if the Registry came up blank, we do a loadlibrary on the wab32.dll
  61. // WAB_DLL_NAME is defined in wabapi.h
  62. //
  63. m_hinstWAB = LoadLibrary( (lstrlen(szWABDllPath)) ? szWABDllPath : WAB_DLL_NAME );
  64. }
  65. if(m_hinstWAB)
  66. {
  67. // if we loaded the dll, get the entry point
  68. //
  69. m_lpfnWABOpen = (LPWABOPEN) GetProcAddress(m_hinstWAB, "WABOpen");
  70. if(m_lpfnWABOpen)
  71. {
  72. HRESULT hr = E_FAIL;
  73. WAB_PARAM wp = {0};
  74. wp.cbSize = sizeof(WAB_PARAM);
  75. wp.szFileName = (LPTSTR) (LPCTSTR) *pszFileName;
  76. // if we choose not to pass in a WAB_PARAM object,
  77. // the default WAB file will be opened up
  78. //
  79. hr = m_lpfnWABOpen(&m_lpAdrBook,&m_lpWABObject,&wp,0);
  80. if(!hr)
  81. m_bInitialized = TRUE;
  82. }
  83. }
  84. }
  85. // Destructor
  86. //
  87. CWAB::~CWAB()
  88. {
  89. if(m_SB.lpb)
  90. LocalFree(m_SB.lpb);
  91. if(m_bInitialized)
  92. {
  93. if(m_hWndModelessWABWindow)
  94. DestroyWindow(m_hWndModelessWABWindow);
  95. if(m_lpPropArray)
  96. m_lpWABObject->FreeBuffer(m_lpPropArray);
  97. if(m_lpAdrBook)
  98. m_lpAdrBook->Release();
  99. if(m_lpWABObject)
  100. m_lpWABObject->Release();
  101. if(m_hinstWAB)
  102. FreeLibrary(m_hinstWAB);
  103. }
  104. }
  105. // Opens a wab file and puts its contents into the specified list view
  106. //
  107. HRESULT CWAB::LoadWABContents(CListCtrl * pListView)
  108. {
  109. ULONG ulObjType = 0;
  110. LPMAPITABLE lpAB = NULL;
  111. LPTSTR * lppszArray=NULL;
  112. ULONG cRows = 0;
  113. LPSRowSet lpRow = NULL;
  114. LPSRowSet lpRowAB = NULL;
  115. LPABCONT lpContainer = NULL;
  116. int cNumRows = 0;
  117. int nRows=0;
  118. HRESULT hr = E_FAIL;
  119. ULONG lpcbEID;
  120. LPENTRYID lpEID = NULL;
  121. // Get the entryid of the root PAB container
  122. //
  123. hr = m_lpAdrBook->GetPAB( &lpcbEID, &lpEID);
  124. ulObjType = 0;
  125. // Open the root PAB container
  126. // This is where all the WAB contents reside
  127. //
  128. hr = m_lpAdrBook->OpenEntry(lpcbEID,
  129. (LPENTRYID)lpEID,
  130. NULL,
  131. 0,
  132. &ulObjType,
  133. (LPUNKNOWN *)&lpContainer);
  134. m_lpWABObject->FreeBuffer(lpEID);
  135. lpEID = NULL;
  136. if(HR_FAILED(hr))
  137. goto exit;
  138. // Get a contents table of all the contents in the
  139. // WABs root container
  140. //
  141. hr = lpContainer->GetContentsTable( 0,
  142. &lpAB);
  143. if(HR_FAILED(hr))
  144. goto exit;
  145. // Order the columns in the ContentsTable to conform to the
  146. // ones we want - which are mainly DisplayName, EntryID and
  147. // ObjectType
  148. // The table is gauranteed to set the columns in the order
  149. // requested
  150. //
  151. hr =lpAB->SetColumns( (LPSPropTagArray)&ptaEid, 0 );
  152. if(HR_FAILED(hr))
  153. goto exit;
  154. // Reset to the beginning of the table
  155. //
  156. hr = lpAB->SeekRow( BOOKMARK_BEGINNING, 0, NULL );
  157. if(HR_FAILED(hr))
  158. goto exit;
  159. // Read all the rows of the table one by one
  160. //
  161. do {
  162. hr = lpAB->QueryRows(1, 0, &lpRowAB);
  163. if(HR_FAILED(hr))
  164. break;
  165. if(lpRowAB)
  166. {
  167. cNumRows = lpRowAB->cRows;
  168. if (cNumRows)
  169. {
  170. LPTSTR lpsz = lpRowAB->aRow[0].lpProps[ieidPR_DISPLAY_NAME].Value.lpszA;
  171. LPENTRYID lpEID = (LPENTRYID) lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.lpb;
  172. ULONG cbEID = lpRowAB->aRow[0].lpProps[ieidPR_ENTRYID].Value.bin.cb;
  173. // There are 2 kinds of objects - the MAPI_MAILUSER contact object
  174. // and the MAPI_DISTLIST contact object
  175. // For the purposes of this sample, we will only consider MAILUSER
  176. // objects
  177. //
  178. if(lpRowAB->aRow[0].lpProps[ieidPR_OBJECT_TYPE].Value.l == MAPI_MAILUSER)
  179. {
  180. // We will now take the entry-id of each object and cache it
  181. // on the listview item representing that object. This enables
  182. // us to uniquely identify the object later if we need to
  183. //
  184. LPSBinary lpSB = NULL;
  185. m_lpWABObject->AllocateBuffer(sizeof(SBinary), (LPVOID *) &lpSB);
  186. if(lpSB)
  187. {
  188. m_lpWABObject->AllocateMore(cbEID, lpSB, (LPVOID *) &(lpSB->lpb));
  189. if(!lpSB->lpb)
  190. {
  191. m_lpWABObject->FreeBuffer(lpSB);
  192. continue;
  193. }
  194. CopyMemory(lpSB->lpb, lpEID, cbEID);
  195. lpSB->cb = cbEID;
  196. LV_ITEM lvi = {0};
  197. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  198. lvi.iItem = pListView->GetItemCount();
  199. lvi.iSubItem = 0;
  200. lvi.pszText = lpsz;
  201. lvi.lParam = (LPARAM) lpSB;
  202. // Now add this item to the list view
  203. pListView->InsertItem(&lvi);
  204. }
  205. }
  206. }
  207. FreeProws(lpRowAB );
  208. }
  209. }while ( SUCCEEDED(hr) && cNumRows && lpRowAB) ;
  210. exit:
  211. if ( lpContainer )
  212. lpContainer->Release();
  213. if ( lpAB )
  214. lpAB->Release();
  215. return hr;
  216. }
  217. // Clears the contents of the specified ListView
  218. //
  219. void CWAB::ClearWABLVContents(CListCtrl * pListView)
  220. {
  221. int i;
  222. int nCount = pListView->GetItemCount();
  223. if(nCount<=0)
  224. return;
  225. for(i=0;i<nCount;i++)
  226. {
  227. LV_ITEM lvi ={0};
  228. lvi.mask = LVIF_PARAM;
  229. lvi.iItem = i;
  230. lvi.iSubItem = 0;
  231. pListView->GetItem(&lvi);
  232. if(lvi.lParam)
  233. {
  234. LPSBinary lpSB = (LPSBinary) lvi.lParam;
  235. m_lpWABObject->FreeBuffer(lpSB);
  236. }
  237. }
  238. pListView->DeleteAllItems();
  239. }
  240. void CWAB::FreeProws(LPSRowSet prows)
  241. {
  242. ULONG irow;
  243. if (!prows)
  244. return;
  245. for (irow = 0; irow < prows->cRows; ++irow)
  246. m_lpWABObject->FreeBuffer(prows->aRow[irow].lpProps);
  247. m_lpWABObject->FreeBuffer(prows);
  248. }
  249. // When an item is selected in the listview, we
  250. // cache its entry id as a special selected item
  251. //
  252. void CWAB::SetSelection(CListCtrl * pListView)
  253. {
  254. LV_ITEM lvi = {0};
  255. // Get the Selected Item from the listview
  256. lvi.mask = LVIF_PARAM;
  257. lvi.iSubItem = 0;
  258. lvi.iItem = pListView->GetNextItem(-1, LVNI_SELECTED);
  259. if(lvi.iItem == -1)
  260. return;
  261. pListView->GetItem(&lvi);
  262. if(lvi.lParam)
  263. {
  264. LPSBinary lpSB = (LPSBinary) lvi.lParam;
  265. if(m_SB.lpb)
  266. LocalFree(m_SB.lpb);
  267. m_SB.cb = lpSB->cb;
  268. m_SB.lpb = (LPBYTE) LocalAlloc(LMEM_ZEROINIT, m_SB.cb);
  269. if(m_SB.lpb)
  270. CopyMemory(m_SB.lpb, lpSB->lpb, m_SB.cb);
  271. else
  272. m_SB.cb = 0;
  273. }
  274. }
  275. // Show details on the selected item
  276. //
  277. void CWAB::ShowSelectedItemDetails(HWND hWndParent)
  278. {
  279. HRESULT hr = S_OK;
  280. // if we have a specially cached entryid ..
  281. //
  282. if(m_SB.cb && m_SB.lpb)
  283. {
  284. HWND hWnd = NULL;
  285. LPSBinary lpSB = (LPSBinary) &m_SB;
  286. hr = m_lpAdrBook->Details( (LPULONG) &hWnd,
  287. NULL, NULL,
  288. lpSB->cb,
  289. (LPENTRYID) lpSB->lpb,
  290. NULL, NULL,
  291. NULL, 0);
  292. }
  293. return;
  294. }
  295. // Gets a SPropValue array for the selected item
  296. // This array contains all the properties for that item
  297. // though we could actually get a subset too if we
  298. // wanted to
  299. //
  300. void CWAB::GetSelectedItemPropArray()
  301. {
  302. if(m_SB.lpb && m_SB.cb)
  303. {
  304. LPMAILUSER lpMailUser = NULL;
  305. LPSBinary lpSB = (LPSBinary) &m_SB;
  306. ULONG ulObjType = 0;
  307. // Open the selected entry
  308. //
  309. m_lpAdrBook->OpenEntry(lpSB->cb,
  310. (LPENTRYID) lpSB->lpb,
  311. NULL, // interface
  312. 0, // flags
  313. &ulObjType,
  314. (LPUNKNOWN *)&lpMailUser);
  315. if(lpMailUser)
  316. {
  317. // Flush away any old array we might have cached
  318. //
  319. if(m_lpPropArray)
  320. m_lpWABObject->FreeBuffer(m_lpPropArray);
  321. m_ulcValues = 0;
  322. lpMailUser->GetProps(NULL, 0, &m_ulcValues, &m_lpPropArray);
  323. lpMailUser->Release();
  324. }
  325. }
  326. return;
  327. }
  328. // Loads the proptags for the selected entry into the
  329. // PropTags list box
  330. //
  331. void CWAB::LoadPropTags(CListBox * pList)
  332. {
  333. if(!m_ulcValues || !m_lpPropArray)
  334. return;
  335. pList->ResetContent();
  336. ULONG i;
  337. TCHAR sz[32];
  338. for(i=0;i<m_ulcValues;i++)
  339. {
  340. wsprintf(sz, "0x%.8x", m_lpPropArray[i].ulPropTag);
  341. pList->SetItemData(pList->AddString(sz), m_lpPropArray[i].ulPropTag);
  342. }
  343. pList->SetCurSel(-1);
  344. pList->SetCurSel(0);
  345. }
  346. // Sets the property value, if understandable, into the
  347. // given edit box
  348. //
  349. void CWAB::SetPropString(CEdit * pEdit, ULONG ulPropTag)
  350. {
  351. pEdit->SetWindowText("");
  352. if(!m_ulcValues || !m_lpPropArray)
  353. return;
  354. ULONG i;
  355. for(i=0;i<m_ulcValues;i++)
  356. {
  357. if(m_lpPropArray[i].ulPropTag == ulPropTag)
  358. {
  359. switch(PROP_TYPE(ulPropTag))
  360. {
  361. case PT_TSTRING:
  362. pEdit->SetWindowText(m_lpPropArray[i].Value.LPSZ);
  363. break;
  364. case PT_MV_TSTRING:
  365. {
  366. ULONG j;
  367. LPSPropValue lpProp = &(m_lpPropArray[i]);
  368. for(j=0;j<lpProp->Value.MVSZ.cValues;j++)
  369. {
  370. pEdit->ReplaceSel(lpProp->Value.MVSZ.LPPSZ[j]);
  371. pEdit->ReplaceSel("\r\n");
  372. }
  373. }
  374. break;
  375. case PT_BINARY:
  376. pEdit->SetWindowText("Binary data");
  377. break;
  378. case PT_I2:
  379. case PT_LONG:
  380. case PT_R4:
  381. case PT_DOUBLE:
  382. case PT_BOOLEAN:
  383. {
  384. TCHAR sz[256];
  385. wsprintf(sz,"%d",m_lpPropArray[i].Value.l);
  386. pEdit->SetWindowText(sz);
  387. }
  388. break;
  389. default:
  390. pEdit->SetWindowText("Unrecognized or undisplayable data");
  391. break;
  392. }
  393. break;
  394. }
  395. }
  396. }
  397. enum {
  398. icrPR_DEF_CREATE_MAILUSER = 0,
  399. icrPR_DEF_CREATE_DL,
  400. icrMax
  401. };
  402. const SizedSPropTagArray(icrMax, ptaCreate)=
  403. {
  404. icrMax,
  405. {
  406. PR_DEF_CREATE_MAILUSER,
  407. PR_DEF_CREATE_DL,
  408. }
  409. };
  410. // Gets the WABs default Template ID for MailUsers
  411. // or DistLists. These Template IDs are needed for creating
  412. // new mailusers and distlists
  413. //
  414. HRESULT CWAB::HrGetWABTemplateID(ULONG ulObjectType,
  415. ULONG * lpcbEID,
  416. LPENTRYID * lppEID)
  417. {
  418. LPABCONT lpContainer = NULL;
  419. HRESULT hr = hrSuccess;
  420. SCODE sc = ERROR_SUCCESS;
  421. ULONG ulObjType = 0;
  422. ULONG cbWABEID = 0;
  423. LPENTRYID lpWABEID = NULL;
  424. LPSPropValue lpCreateEIDs = NULL;
  425. LPSPropValue lpNewProps = NULL;
  426. ULONG cNewProps;
  427. ULONG nIndex;
  428. if ( (!m_lpAdrBook) ||
  429. ((ulObjectType != MAPI_MAILUSER) && (ulObjectType != MAPI_DISTLIST)) )
  430. {
  431. hr = MAPI_E_INVALID_PARAMETER;
  432. goto out;
  433. }
  434. *lpcbEID = 0;
  435. *lppEID = NULL;
  436. if (HR_FAILED(hr = m_lpAdrBook->GetPAB( &cbWABEID,
  437. &lpWABEID)))
  438. {
  439. goto out;
  440. }
  441. if (HR_FAILED(hr = m_lpAdrBook->OpenEntry(cbWABEID, // size of EntryID to open
  442. lpWABEID, // EntryID to open
  443. NULL, // interface
  444. 0, // flags
  445. &ulObjType,
  446. (LPUNKNOWN *)&lpContainer)))
  447. {
  448. goto out;
  449. }
  450. // Opened PAB container OK
  451. // Get us the default creation entryids
  452. if (HR_FAILED(hr = lpContainer->GetProps( (LPSPropTagArray)&ptaCreate,
  453. 0,
  454. &cNewProps,
  455. &lpCreateEIDs) ) )
  456. {
  457. goto out;
  458. }
  459. // Validate the properites
  460. if ( lpCreateEIDs[icrPR_DEF_CREATE_MAILUSER].ulPropTag != PR_DEF_CREATE_MAILUSER ||
  461. lpCreateEIDs[icrPR_DEF_CREATE_DL].ulPropTag != PR_DEF_CREATE_DL)
  462. {
  463. goto out;
  464. }
  465. if(ulObjectType == MAPI_DISTLIST)
  466. nIndex = icrPR_DEF_CREATE_DL;
  467. else
  468. nIndex = icrPR_DEF_CREATE_MAILUSER;
  469. *lpcbEID = lpCreateEIDs[nIndex].Value.bin.cb;
  470. m_lpWABObject->AllocateBuffer(*lpcbEID, (LPVOID *) lppEID);
  471. if (sc != S_OK)
  472. {
  473. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  474. goto out;
  475. }
  476. CopyMemory(*lppEID,lpCreateEIDs[nIndex].Value.bin.lpb,*lpcbEID);
  477. out:
  478. if (lpCreateEIDs)
  479. m_lpWABObject->FreeBuffer(lpCreateEIDs);
  480. if (lpContainer)
  481. lpContainer->Release();
  482. if (lpWABEID)
  483. m_lpWABObject->FreeBuffer(lpWABEID);
  484. return hr;
  485. }
  486. // Shows the NewEntry dialog to enable creating a new contact in the WAB
  487. //
  488. HRESULT CWAB::ShowNewEntryDialog(HWND hWndParent)
  489. {
  490. ULONG cbEID=0;
  491. LPENTRYID lpEID=NULL;
  492. HRESULT hr = hrSuccess;
  493. ULONG cbTplEID = 0;
  494. LPENTRYID lpTplEID = NULL;
  495. // Get the template id which is needed to create the
  496. // new object
  497. //
  498. if(HR_FAILED(hr = HrGetWABTemplateID( MAPI_MAILUSER,
  499. &cbTplEID,
  500. &lpTplEID)))
  501. {
  502. goto out;
  503. }
  504. // Display the New Entry dialog to create the new entry
  505. //
  506. if (HR_FAILED(hr = m_lpAdrBook->NewEntry( (ULONG) hWndParent,
  507. 0,
  508. 0,NULL,
  509. cbTplEID,lpTplEID,
  510. &cbEID,&lpEID)))
  511. {
  512. goto out;
  513. }
  514. out:
  515. return hr;
  516. }
  517. // Delete an entry from the WAB
  518. //
  519. HRESULT CWAB::DeleteEntry()
  520. {
  521. HRESULT hr = hrSuccess;
  522. ULONG cbWABEID = 0;
  523. LPENTRYID lpWABEID = NULL;
  524. LPABCONT lpWABCont = NULL;
  525. ULONG ulObjType;
  526. SBinaryArray SBA;
  527. hr = m_lpAdrBook->GetPAB( &cbWABEID,
  528. &lpWABEID);
  529. if(HR_FAILED(hr))
  530. goto out;
  531. hr = m_lpAdrBook->OpenEntry( cbWABEID, // size of EntryID to open
  532. lpWABEID, // EntryID to open
  533. NULL, // interface
  534. 0, // flags
  535. &ulObjType,
  536. (LPUNKNOWN *)&lpWABCont);
  537. if(HR_FAILED(hr))
  538. goto out;
  539. SBA.cValues = 1;
  540. SBA.lpbin = &m_SB;
  541. hr = lpWABCont->DeleteEntries((LPENTRYLIST) &SBA, 0);
  542. if(m_lpPropArray)
  543. m_lpWABObject->FreeBuffer(m_lpPropArray);
  544. m_lpPropArray = NULL;
  545. m_ulcValues = 0;
  546. out:
  547. if(lpWABCont)
  548. lpWABCont->Release();
  549. if(lpWABEID)
  550. m_lpWABObject->FreeBuffer(lpWABEID);
  551. return hr;
  552. }
  553. // Gets the property value for specified String property
  554. //
  555. BOOL CWAB::GetStringPropVal(HWND hWnd, ULONG ulPropTag, LPTSTR sz, ULONG cbsz)
  556. {
  557. BOOL bRet = FALSE;
  558. if(PROP_TYPE(ulPropTag) != PT_TSTRING)
  559. {
  560. MessageBox(hWnd, "This tool only supports modifying string type props right now",
  561. "Error", MB_OK | MB_ICONINFORMATION);
  562. goto out;
  563. }
  564. ULONG i;
  565. // Since we already cached the proparray for the selected
  566. // item, all we need to do is look in the cached proparray
  567. // for the requested proptag
  568. //
  569. for(i=0;i<m_ulcValues;i++)
  570. {
  571. if(m_lpPropArray[i].ulPropTag == ulPropTag)
  572. {
  573. LPTSTR lp = m_lpPropArray[i].Value.LPSZ;
  574. ULONG nLen = (ULONG) lstrlen(lp);
  575. if(nLen >= cbsz)
  576. {
  577. CopyMemory(sz, lp, cbsz-1);
  578. sz[cbsz-1]='\0';
  579. }
  580. else
  581. lstrcpy(sz,lp);
  582. break;
  583. }
  584. }
  585. bRet = TRUE;
  586. out:
  587. return bRet;
  588. }
  589. // Sets a single string property onto a mailuser object
  590. //
  591. BOOL CWAB::SetSingleStringProp(HWND hWnd, ULONG ulPropTag, LPTSTR sz)
  592. {
  593. SPropValue Prop;
  594. BOOL bRet = FALSE;
  595. if(PROP_TYPE(ulPropTag) != PT_TSTRING)
  596. {
  597. MessageBox(hWnd, "This version of the tool can only set string properties.",
  598. "Error", MB_OK | MB_ICONINFORMATION);
  599. goto out;
  600. }
  601. Prop.ulPropTag = ulPropTag;
  602. Prop.Value.LPSZ = sz;
  603. // Open the cached entry and get a mailuser object
  604. // representing that entry
  605. //
  606. if(m_SB.lpb && m_SB.cb)
  607. {
  608. LPMAILUSER lpMailUser = NULL;
  609. LPSBinary lpSB = (LPSBinary) &m_SB;
  610. ULONG ulObjType = 0;
  611. // To modify an object, make sure to specify the
  612. // MAPI_MODIFY flag otherwise the object is always
  613. // opened read-only be default
  614. //
  615. m_lpAdrBook->OpenEntry(lpSB->cb,
  616. (LPENTRYID) lpSB->lpb,
  617. NULL, // interface
  618. MAPI_MODIFY, // flags
  619. &ulObjType,
  620. (LPUNKNOWN *)&lpMailUser);
  621. if(lpMailUser)
  622. {
  623. // Knock out this prop if it exists so we can overwrite it
  624. //
  625. {
  626. SPropTagArray SPTA;
  627. SPTA.cValues = 1;
  628. SPTA.aulPropTag[0] = ulPropTag;
  629. lpMailUser->DeleteProps(&SPTA, NULL);
  630. }
  631. // Set the new property on the mailuser
  632. //
  633. if (!HR_FAILED(lpMailUser->SetProps(1, &Prop, NULL)))
  634. {
  635. // **NOTE** if you dont call SaveChanges, the
  636. // changes are not saved (duh). Also if you didnt
  637. // open the object with the MAPI_MODIFY flag, you
  638. // are likely to get an ACCESS_DENIED error
  639. //
  640. lpMailUser->SaveChanges(0);
  641. bRet = TRUE;
  642. }
  643. lpMailUser->Release();
  644. }
  645. }
  646. out:
  647. GetSelectedItemPropArray();
  648. return bRet;
  649. }
  650. void STDMETHODCALLTYPE TestDismissFunction(ULONG ulUIParam, LPVOID lpvContext)
  651. {
  652. LPDWORD lpdw = (LPDWORD) lpvContext;
  653. return;
  654. }
  655. DWORD dwContext = 77;
  656. // Shows the Address Book
  657. //
  658. void CWAB::ShowAddressBook(HWND hWnd)
  659. {
  660. ADRPARM AdrParm = {0};
  661. AdrParm.lpszCaption = "WABTool Address Book View";
  662. AdrParm.cDestFields = 0;
  663. AdrParm.ulFlags = DIALOG_SDI;
  664. AdrParm.lpvDismissContext = &dwContext;
  665. AdrParm.lpfnDismiss = &TestDismissFunction;
  666. AdrParm.lpfnABSDI = NULL;
  667. m_lpAdrBook->Address( (ULONG *) &m_hWndModelessWABWindow,
  668. &AdrParm,
  669. NULL);
  670. }