Source code of Windows XP (NT5)
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.

1177 lines
24 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. cwabobj.cpp
  5. Abstract:
  6. Interface to the windows address book.
  7. Environment:
  8. Fax send wizard
  9. Revision History:
  10. 10/23/97 -GeorgeJe-
  11. Created it.
  12. mm/dd/yy -author-
  13. description
  14. --*/
  15. #include <windows.h>
  16. #include <prsht.h>
  17. #include <tchar.h>
  18. #include <wab.h>
  19. #include "faxui.h"
  20. #include "cwabobj.h"
  21. static
  22. LPWSTR
  23. DupUnicodeString(
  24. LPWSTR pStr
  25. );
  26. static
  27. LPWSTR
  28. DupStringAnsiToUnicode(
  29. LPSTR pAnsiStr
  30. );
  31. static
  32. LPSPropValue
  33. FindProp(
  34. LPSPropValue rgprop,
  35. ULONG cprop,
  36. ULONG ulPropTag
  37. );
  38. static
  39. AddRecipient(
  40. PRECIPIENT *ppNewRecip,
  41. LPWSTR DisplayName,
  42. LPWSTR FaxNumber
  43. );
  44. static SizedSPropTagArray(5, sPropTags) =
  45. {
  46. 5,
  47. {
  48. PR_DISPLAY_NAME_A,
  49. PR_PRIMARY_FAX_NUMBER_A,
  50. PR_HOME_FAX_NUMBER_A,
  51. PR_BUSINESS_FAX_NUMBER_A,
  52. PR_OBJECT_TYPE
  53. }
  54. };
  55. CWabObj::CWabObj(
  56. HINSTANCE hInstance
  57. )
  58. /*++
  59. Routine Description:
  60. Constructor for CWabObj class
  61. Arguments:
  62. hInstance - Instance handle
  63. Return Value:
  64. NONE
  65. --*/
  66. {
  67. m_Initialized = FALSE;
  68. m_lpAdrList = NULL;
  69. m_hInstance = hInstance;
  70. }
  71. BOOL
  72. CWabObj::Initialize(
  73. VOID
  74. )
  75. /*++
  76. Routine Description:
  77. intialization function for CWabObj class
  78. Arguments:
  79. NONE
  80. Return Value:
  81. TRUE if the object is initialized successfully, else FALSE
  82. --*/
  83. {
  84. TCHAR szDllPath[MAX_PATH];
  85. HKEY hKey = NULL;
  86. LONG rVal;
  87. DWORD dwType;
  88. DWORD cbData = MAX_PATH * sizeof(TCHAR);
  89. HRESULT hr;
  90. PCTSTR szDefaultPath = TEXT("%CommonProgramFiles%\\System\\wab32.dll");
  91. m_Initialized = TRUE;
  92. //
  93. // get the path to wab32.dll
  94. //
  95. rVal = RegOpenKeyEx(
  96. HKEY_LOCAL_MACHINE,
  97. REGVAL_WABPATH,
  98. 0,
  99. KEY_READ,
  100. &hKey
  101. );
  102. if (rVal == ERROR_SUCCESS) {
  103. rVal = RegQueryValueEx(
  104. hKey,
  105. TEXT(""),
  106. NULL,
  107. &dwType,
  108. (LPBYTE) szDllPath,
  109. &cbData
  110. );
  111. RegCloseKey( hKey );
  112. }
  113. if (rVal != ERROR_SUCCESS) {
  114. ExpandEnvironmentStrings(szDefaultPath,szDllPath,sizeof(szDllPath)/sizeof(TCHAR));
  115. }
  116. m_hWab = LoadLibrary( szDllPath );
  117. if (m_hWab != NULL) {
  118. m_lpWabOpen = (LPWABOPEN) GetProcAddress( m_hWab , "WABOpen" );
  119. } else {
  120. m_lpWabOpen = (LPWABOPEN) NULL;
  121. }
  122. if (m_lpWabOpen == NULL) {
  123. hr = E_FAIL;
  124. goto exit;
  125. }
  126. //
  127. // open the wab
  128. //
  129. hr = m_lpWabOpen( &m_lpAdrBook, &m_lpWABObject, 0, 0 );
  130. exit:
  131. if (HR_FAILED(hr)) {
  132. m_lpAdrBook = NULL;
  133. m_lpWABObject = NULL;
  134. m_Initialized = FALSE;
  135. if (m_hWab != NULL) {
  136. FreeLibrary( m_hWab );
  137. }
  138. m_hWab = NULL;
  139. }
  140. return(m_Initialized);
  141. }
  142. CWabObj::~CWabObj()
  143. /*++
  144. Routine Description:
  145. Destructor for CWabObj class
  146. Arguments:
  147. NONE
  148. Return Value:
  149. NONE
  150. --*/
  151. {
  152. if (m_lpAdrBook) {
  153. m_lpAdrBook->Release();
  154. }
  155. if (m_lpWABObject) {
  156. m_lpWABObject->Release();
  157. }
  158. if ( m_hWab ) {
  159. FreeLibrary( m_hWab );
  160. }
  161. }
  162. BOOL
  163. CWabObj::Address(
  164. HWND hWnd,
  165. PRECIPIENT pRecipients,
  166. PRECIPIENT * ppNewRecip
  167. )
  168. /*++
  169. Routine Description:
  170. Bring up the address book UI. Prepopulate the to box with the entries in
  171. pRecipient. Return the modified entries in ppNewRecip.
  172. Arguments:
  173. hWnd - window handle to parent window
  174. pRecipients - list of recipients to look up
  175. ppNewRecipients - list of new/modified recipients
  176. Return Value:
  177. TRUE if all recipients had a fax number.
  178. FALSE if one or more of them didn't.
  179. --*/
  180. {
  181. ADRPARM AdrParms = { 0 };
  182. LPADRLIST tmp;
  183. HRESULT hr;
  184. DWORD i;
  185. DWORD nRecips;
  186. PRECIPIENT tmpRecipient;
  187. ULONG DestComps[3] = { MAPI_TO, MAPI_CC, MAPI_BCC };
  188. DWORD cDropped;
  189. nRecips = 0;
  190. tmpRecipient = pRecipients;
  191. m_hWnd = hWnd;
  192. m_PickNumber = 0;
  193. //
  194. // count recipients and set up initial address list
  195. //
  196. while (tmpRecipient) {
  197. nRecips++;
  198. tmpRecipient = (PRECIPIENT) tmpRecipient->pNext;
  199. }
  200. if (nRecips > 0) {
  201. hr = m_lpWABObject->AllocateBuffer( CbNewADRLIST( nRecips ), (LPVOID *) &m_lpAdrList );
  202. m_lpAdrList->cEntries = nRecips;
  203. } else {
  204. m_lpAdrList = NULL;
  205. }
  206. for (i = 0, tmpRecipient = pRecipients; i < nRecips; i++, tmpRecipient = (PRECIPIENT) tmpRecipient->pNext) {
  207. LPADRENTRY lpAdrEntry = &m_lpAdrList->aEntries[i];
  208. lpAdrEntry->cValues = 3;
  209. hr = m_lpWABObject->AllocateBuffer( sizeof( SPropValue ) * 3, (LPVOID *) &lpAdrEntry->rgPropVals );
  210. ZeroMemory( lpAdrEntry->rgPropVals, sizeof( SPropValue ) * 3 );
  211. lpAdrEntry->rgPropVals[0].ulPropTag = PR_DISPLAY_NAME_A;
  212. lpAdrEntry->rgPropVals[0].Value.lpszA = DupStringUnicodeToAnsi( lpAdrEntry->rgPropVals, tmpRecipient->pName );
  213. lpAdrEntry->rgPropVals[1].ulPropTag = PR_RECIPIENT_TYPE;
  214. lpAdrEntry->rgPropVals[1].Value.l = MAPI_TO;
  215. lpAdrEntry->rgPropVals[2].ulPropTag = PR_PRIMARY_FAX_NUMBER_A;
  216. lpAdrEntry->rgPropVals[2].Value.lpszA = DupStringUnicodeToAnsi( lpAdrEntry->rgPropVals, tmpRecipient->pAddress );
  217. }
  218. tmp = m_lpAdrList;
  219. AdrParms.cDestFields = 1;
  220. AdrParms.ulFlags = DIALOG_MODAL;
  221. AdrParms.nDestFieldFocus = 0;
  222. AdrParms.lpulDestComps = DestComps;
  223. AdrParms.lpszCaption = TEXT( "" );
  224. //
  225. // Bring up the address book UI
  226. //
  227. hr = m_lpAdrBook->Address(
  228. (ULONG *) &hWnd,
  229. &AdrParms,
  230. &m_lpAdrList
  231. );
  232. if (FAILED (hr) || !m_lpAdrList || m_lpAdrList->cEntries == 0) {
  233. //
  234. // in this case the user pressed cancel, so we skip resolving any of our addresses that aren't listed in the
  235. // WAB
  236. //
  237. cDropped = 0;
  238. goto skipresolve;
  239. }
  240. //
  241. // Resolve names
  242. //
  243. hr = m_lpAdrBook->ResolveName ((ULONG_PTR)hWnd, 0, NULL, m_lpAdrList);
  244. skipresolve:
  245. tmp = m_lpAdrList;
  246. if (m_lpAdrList) {
  247. for (i = cDropped = 0; i < m_lpAdrList->cEntries; i++) {
  248. LPADRENTRY lpAdrEntry = &m_lpAdrList->aEntries[i];
  249. if (!InterpretAddress( lpAdrEntry->rgPropVals, lpAdrEntry->cValues, ppNewRecip )){
  250. cDropped++;
  251. }
  252. }
  253. //
  254. // Clean up
  255. //
  256. for (ULONG iEntry = 0; iEntry < m_lpAdrList->cEntries; ++iEntry)
  257. {
  258. if(m_lpAdrList->aEntries[iEntry].rgPropVals)
  259. m_lpWABObject->FreeBuffer(m_lpAdrList->aEntries[iEntry].rgPropVals);
  260. }
  261. m_lpWABObject->FreeBuffer(m_lpAdrList);
  262. m_lpAdrList = NULL;
  263. }
  264. m_hWnd = NULL;
  265. return cDropped == 0;
  266. }
  267. BOOL
  268. CWabObj::InterpretAddress(
  269. LPSPropValue SPropVal,
  270. ULONG cValues,
  271. PRECIPIENT *ppNewRecip
  272. )
  273. /*++
  274. Routine Description:
  275. Interpret the address book entry represented by SPropVal.
  276. Arguments:
  277. SPropVal - Property values for address book entry.
  278. cValues - number of property values
  279. ppNewRecip - new recipient list
  280. Return Value:
  281. TRUE if all of the entries have a fax number.
  282. FALSE otherwise.
  283. --*/
  284. {
  285. LPSPropValue lpSPropVal;
  286. LPWSTR FaxNumber, DisplayName;
  287. BOOL rVal = FALSE;
  288. //
  289. // get the object type
  290. //
  291. lpSPropVal = FindProp( SPropVal, cValues, PR_OBJECT_TYPE );
  292. if (lpSPropVal) {
  293. //
  294. // If the object is a mail user, get the fax numbers and add the recipient
  295. // to the list. If the object is a distribtion list, process it.
  296. //
  297. switch (lpSPropVal->Value.l) {
  298. case MAPI_MAILUSER:
  299. if(GetRecipientInfo( SPropVal, cValues, &FaxNumber, &DisplayName )) {
  300. AddRecipient( ppNewRecip, DisplayName, FaxNumber );
  301. rVal = TRUE;
  302. }
  303. break;
  304. case MAPI_DISTLIST:
  305. rVal = InterpretDistList( SPropVal, cValues, ppNewRecip );
  306. }
  307. return rVal;
  308. } else {
  309. //
  310. // If there is no object type then this is valid entry that we queried on that went unresolved.
  311. // We know that there is a fax number so add it.
  312. //
  313. if(GetRecipientInfo( SPropVal, cValues, &FaxNumber, &DisplayName )) {
  314. AddRecipient( ppNewRecip, DisplayName, FaxNumber );
  315. rVal = TRUE;
  316. }
  317. }
  318. return rVal;
  319. }
  320. BOOL
  321. CWabObj::InterpretDistList(
  322. LPSPropValue SPropVal,
  323. ULONG cValues,
  324. PRECIPIENT * ppNewRecip
  325. )
  326. /*++
  327. Routine Description:
  328. Process a distribution list.
  329. Arguments:
  330. SPropVal - Property values for distribution list.
  331. cValues - Number of properties.
  332. ppNewRecip - New recipient list.
  333. Return Value:
  334. TRUE if all of the entries have a fax number.
  335. FALSE otherwise.
  336. --*/
  337. #define EXIT_IF_FAILED(hr) { if (FAILED(hr)) goto ExitDistList; }
  338. {
  339. LPSPropValue lpPropVals;
  340. LPSRowSet pRows = NULL;
  341. LPDISTLIST lpMailDistList = NULL;
  342. LPMAPITABLE pMapiTable = NULL;
  343. ULONG ulObjType, cRows;
  344. HRESULT hr;
  345. BOOL rVal = FALSE;
  346. lpPropVals = FindProp( SPropVal, cValues, PR_ENTRYID );
  347. if (lpPropVals) {
  348. LPENTRYID lpEntryId = (LPENTRYID) lpPropVals->Value.bin.lpb;
  349. DWORD cbEntryId = lpPropVals->Value.bin.cb;
  350. //
  351. // Open the recipient entry
  352. //
  353. hr = m_lpAdrBook->OpenEntry(
  354. cbEntryId,
  355. lpEntryId,
  356. (LPCIID) NULL,
  357. 0,
  358. &ulObjType,
  359. (LPUNKNOWN *) &lpMailDistList
  360. );
  361. EXIT_IF_FAILED( hr );
  362. //
  363. // Get the contents table of the address entry
  364. //
  365. hr = lpMailDistList->GetContentsTable(
  366. MAPI_DEFERRED_ERRORS,
  367. &pMapiTable
  368. );
  369. EXIT_IF_FAILED(hr);
  370. //
  371. // Limit the query to only the properties we're interested in
  372. //
  373. hr = pMapiTable->SetColumns((LPSPropTagArray) &sPropTags, 0);
  374. EXIT_IF_FAILED(hr);
  375. //
  376. // Get the total number of rows
  377. //
  378. hr = pMapiTable->GetRowCount(0, &cRows);
  379. EXIT_IF_FAILED(hr);
  380. //
  381. // Get the individual entries of the distribution list
  382. //
  383. hr = pMapiTable->SeekRow(BOOKMARK_BEGINNING, 0, NULL);
  384. EXIT_IF_FAILED(hr);
  385. hr = pMapiTable->QueryRows(cRows, 0, &pRows);
  386. EXIT_IF_FAILED(hr);
  387. hr = S_OK;
  388. if (pRows && pRows->cRows) {
  389. //
  390. // Handle each entry of the distribution list in turn:
  391. // for simple entries, call InterpretAddress
  392. // for embedded distribution list, call this function recursively
  393. //
  394. for (cRows = 0; cRows < pRows->cRows; cRows++) {
  395. LPSPropValue lpProps = pRows->aRow[cRows].lpProps;
  396. ULONG cRowValues = pRows->aRow[cRows].cValues;
  397. lpPropVals = FindProp( lpProps, cRowValues, PR_OBJECT_TYPE );
  398. if (lpPropVals) {
  399. switch (lpPropVals->Value.l) {
  400. case MAPI_MAILUSER:
  401. rVal = InterpretAddress( lpProps, cRowValues, ppNewRecip );
  402. break;
  403. case MAPI_DISTLIST:
  404. rVal = InterpretDistList( lpProps, cRowValues, ppNewRecip );
  405. }
  406. }
  407. }
  408. }
  409. }
  410. ExitDistList:
  411. //
  412. // Perform necessary clean up before returning to caller
  413. //
  414. if (pRows) {
  415. for (cRows = 0; cRows < pRows->cRows; cRows++) {
  416. m_lpWABObject->FreeBuffer(pRows->aRow[cRows].lpProps);
  417. }
  418. m_lpWABObject->FreeBuffer(pRows);
  419. }
  420. if (pMapiTable)
  421. pMapiTable->Release();
  422. if (lpMailDistList)
  423. lpMailDistList->Release();
  424. return rVal;
  425. }
  426. INT_PTR
  427. CALLBACK
  428. ChooseFaxNumberDlgProc(
  429. HWND hDlg,
  430. UINT uMsg,
  431. WPARAM wParam,
  432. LPARAM lParam
  433. )
  434. /*++
  435. Routine Description:
  436. Dialog proc for choose fax number dialog.
  437. Arguments:
  438. lParam - pointer to PickFax structure.
  439. Return Value:
  440. Control id of selection.
  441. --*/
  442. {
  443. PPICKFAX pPickFax = (PPICKFAX) lParam;
  444. TCHAR buffer[MAX_TITLE_LEN];
  445. switch (uMsg) {
  446. case WM_INITDIALOG:
  447. SetDlgItemText(hDlg, IDC_DISPLAY_NAME, pPickFax->DisplayName);
  448. buffer[0] = 0;
  449. GetDlgItemText(hDlg, IDC_BUSINESS_FAX, buffer, MAX_TITLE_LEN);
  450. _tcscat(buffer, pPickFax->BusinessFax);
  451. SetDlgItemText(hDlg, IDC_BUSINESS_FAX, buffer);
  452. buffer[0] = 0;
  453. GetDlgItemText(hDlg, IDC_HOME_FAX, buffer, MAX_TITLE_LEN);
  454. _tcscat(buffer, pPickFax->HomeFax);
  455. SetDlgItemText(hDlg, IDC_HOME_FAX, buffer);
  456. CheckDlgButton(hDlg, IDC_BUSINESS_FAX, BST_CHECKED);
  457. return TRUE;
  458. case WM_COMMAND:
  459. switch(LOWORD( wParam )){
  460. case IDOK:
  461. if (IsDlgButtonChecked(hDlg, IDC_BUSINESS_FAX) == BST_CHECKED) {
  462. if (IsDlgButtonChecked(hDlg, IDC_ALWAYS_OPTION) == BST_CHECKED) {
  463. EndDialog(hDlg, IDC_ALLBUS);
  464. }
  465. else {
  466. EndDialog(hDlg, IDC_BUSINESS_FAX);
  467. }
  468. }
  469. else if (IsDlgButtonChecked(hDlg, IDC_HOME_FAX) == BST_CHECKED) {
  470. if (IsDlgButtonChecked(hDlg, IDC_ALWAYS_OPTION) == BST_CHECKED) {
  471. EndDialog(hDlg, IDC_ALLHOME);
  472. }
  473. else {
  474. EndDialog(hDlg, IDC_HOME_FAX);
  475. }
  476. }
  477. break;;
  478. }
  479. break;
  480. default:
  481. return FALSE;
  482. }
  483. return FALSE;
  484. }
  485. #define StrPropOk( strprop ) ((strprop) && (strprop)->Value.lpszA && *(strprop)->Value.lpszA)
  486. BOOL
  487. CWabObj::GetRecipientInfo(
  488. LPSPropValue SPropVals,
  489. ULONG cValues,
  490. LPWSTR * FaxNumber,
  491. LPWSTR * DisplayName
  492. )
  493. /*++
  494. Routine Description:
  495. Get the fax number and display name properties.
  496. Arguments:
  497. SPropVal - Property values for distribution list.
  498. cValues - Number of properties.
  499. FaxNumber - pointer to pointer to string to hold the fax number.
  500. DisplayName - pointer to pointer to string to hold the display name.
  501. Return Value:
  502. TRUE if there is a fax number and display name.
  503. FALSE otherwise.
  504. --*/
  505. {
  506. LPSPropValue lpPropVals;
  507. LPSPropValue lpPropArray;
  508. BOOL Result = FALSE;
  509. PICKFAX PickFax = { 0 };
  510. *FaxNumber = *DisplayName = NULL;
  511. //
  512. // Get the entryid and open the entry.
  513. //
  514. lpPropVals = FindProp( SPropVals, cValues, PR_ENTRYID );
  515. if (lpPropVals) {
  516. ULONG lpulObjType;
  517. LPMAILUSER lpMailUser = NULL;
  518. LPENTRYID lpEntryId = (LPENTRYID) lpPropVals->Value.bin.lpb;
  519. DWORD cbEntryId = lpPropVals->Value.bin.cb;
  520. HRESULT hr;
  521. ULONG countValues;
  522. hr = m_lpAdrBook->OpenEntry(
  523. cbEntryId,
  524. lpEntryId,
  525. (LPCIID) NULL,
  526. 0,
  527. &lpulObjType,
  528. (LPUNKNOWN *) &lpMailUser
  529. );
  530. if (HR_SUCCEEDED(hr)) {
  531. //
  532. // Get the properties.
  533. //
  534. hr = ((IMailUser *) lpMailUser)->GetProps( (LPSPropTagArray) &sPropTags, 0, &countValues, &lpPropArray );
  535. if (HR_SUCCEEDED(hr)) {
  536. lpPropVals = FindProp( lpPropArray, countValues, PR_BUSINESS_FAX_NUMBER_A );
  537. if (StrPropOk( lpPropVals )) {
  538. PickFax.BusinessFax = DupStringAnsiToUnicode( lpPropVals->Value.lpszA );
  539. }
  540. lpPropVals = FindProp( lpPropArray, countValues, PR_HOME_FAX_NUMBER_A );
  541. if (StrPropOk( lpPropVals )) {
  542. PickFax.HomeFax = DupStringAnsiToUnicode( lpPropVals->Value.lpszA );
  543. }
  544. lpPropVals = FindProp( lpPropArray, countValues, PR_DISPLAY_NAME_A );
  545. if (StrPropOk( lpPropVals )) {
  546. *DisplayName = PickFax.DisplayName = DupStringAnsiToUnicode( lpPropVals->Value.lpszA );
  547. }
  548. //
  549. // If there are two fax numbers, ask the user to pick one.
  550. //
  551. if (PickFax.BusinessFax && PickFax.HomeFax) {
  552. int dlgResult;
  553. if (m_PickNumber != 0) {
  554. dlgResult = m_PickNumber;
  555. } else {
  556. dlgResult = (int)DialogBoxParam(
  557. (HINSTANCE) m_hInstance,
  558. MAKEINTRESOURCE( IDD_CHOOSE_FAXNUMBER ),
  559. m_hWnd,
  560. ChooseFaxNumberDlgProc,
  561. (LPARAM) &PickFax
  562. );
  563. }
  564. switch( dlgResult ) {
  565. case IDC_ALLBUS:
  566. m_PickNumber = IDC_BUSINESS_FAX;
  567. // fall through
  568. case IDC_BUSINESS_FAX:
  569. MemFree( PickFax.HomeFax );
  570. *FaxNumber = PickFax.BusinessFax;
  571. break;
  572. case IDC_ALLHOME:
  573. m_PickNumber = IDC_HOME_FAX;
  574. // fall through
  575. case IDC_HOME_FAX:
  576. MemFree( PickFax.BusinessFax );
  577. *FaxNumber = PickFax.HomeFax;
  578. break;
  579. }
  580. } else if (PickFax.BusinessFax) {
  581. *FaxNumber = PickFax.BusinessFax;
  582. } else if (PickFax.HomeFax) {
  583. *FaxNumber = PickFax.HomeFax;
  584. }
  585. }
  586. m_lpWABObject->FreeBuffer( lpPropArray );
  587. }
  588. if (lpMailUser) {
  589. lpMailUser->Release();
  590. }
  591. } else {
  592. // If there is no entryid, then this is a valid entry that we queried on that went unresolved
  593. // add if anyway. In this case we know that PR_PRIMARY_FAX_NUMBER_A and PR_DISPLAY_NAME_A will be
  594. // present.
  595. lpPropVals = FindProp( SPropVals, cValues, PR_PRIMARY_FAX_NUMBER_A );
  596. if (lpPropVals) {
  597. *FaxNumber = DupStringAnsiToUnicode( lpPropVals->Value.lpszA );
  598. }
  599. lpPropVals = FindProp( SPropVals, cValues, PR_DISPLAY_NAME_A );
  600. if (lpPropVals) {
  601. *DisplayName = DupStringAnsiToUnicode( lpPropVals->Value.lpszA );
  602. }
  603. }
  604. if (FaxNumber && DisplayName) {
  605. return (*FaxNumber != 0 && *DisplayName != 0);
  606. } else {
  607. return FALSE;
  608. }
  609. }
  610. LPSPropValue
  611. FindProp(
  612. LPSPropValue rgprop,
  613. ULONG cprop,
  614. ULONG ulPropTag
  615. )
  616. /*++
  617. Routine Description:
  618. Searches for a given property tag in a propset. If the given
  619. property tag has type PT_UNSPECIFIED, matches only on the
  620. property ID; otherwise, matches on the entire tag.
  621. Arguments:
  622. rgprop - Property values.
  623. cprop - Number of properties.
  624. ulPropTag - Property to search for.
  625. Return Value:
  626. Pointer to property desired property value or NULL.
  627. --*/
  628. {
  629. BOOL f = PROP_TYPE(ulPropTag) == PT_UNSPECIFIED;
  630. LPSPropValue pprop = rgprop;
  631. if (!cprop || !rgprop)
  632. return NULL;
  633. while (cprop--)
  634. {
  635. if (pprop->ulPropTag == ulPropTag ||
  636. (f && PROP_ID(pprop->ulPropTag) == PROP_ID(ulPropTag)))
  637. return pprop;
  638. ++pprop;
  639. }
  640. return NULL;
  641. }
  642. LPSTR
  643. CWabObj::DupStringUnicodeToAnsi(
  644. LPVOID lpObject,
  645. LPWSTR pUnicodeStr
  646. )
  647. /*++
  648. Routine Description:
  649. Convert a Unicode string to a multi-byte string
  650. Arguments:
  651. pUnicodeStr - Pointer to the Unicode string to be duplicated
  652. Return Value:
  653. Pointer to the duplicated multi-byte string
  654. NOTE:
  655. This is only need because the WAB is not Unicode enabled on NT.
  656. This uses the WAB memory allocator so it must be freed with FreeBuffer.
  657. --*/
  658. {
  659. INT nChar;
  660. LPSTR pAnsiStr;
  661. //
  662. // Figure out how much memory to allocate for the multi-byte string
  663. //
  664. if (! (nChar = WideCharToMultiByte(CP_ACP, 0, pUnicodeStr, -1, NULL, 0, NULL, NULL)) ||
  665. ! HR_SUCCEEDED( m_lpWABObject->AllocateMore( nChar, lpObject, (LPVOID *) &pAnsiStr )))
  666. {
  667. return NULL;
  668. }
  669. //
  670. // Convert Unicode string to multi-byte string
  671. //
  672. WideCharToMultiByte(CP_ACP, 0, pUnicodeStr, -1, pAnsiStr, nChar, NULL, NULL);
  673. return pAnsiStr;
  674. }
  675. LPWSTR
  676. DupStringAnsiToUnicode(
  677. LPSTR pAnsiStr
  678. )
  679. /*++
  680. Routine Description:
  681. Convert a multi-byte string to a Unicode string
  682. Arguments:
  683. pAnsiStr - Pointer to the Ansi string to be duplicated
  684. Return Value:
  685. Pointer to the duplicated Unicode string
  686. NOTE:
  687. This is only need because MAPI is not Unicode enabled on NT.
  688. This routine uses MemAlloc to allocate memory so the caller needs
  689. to use MemFree.
  690. --*/
  691. {
  692. INT nChar;
  693. LPWSTR pUnicodeStr;
  694. //
  695. // Figure out how much memory to allocate for the Unicode string
  696. //
  697. if (! (nChar = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pAnsiStr, -1, NULL, 0)) ||
  698. ! ( pUnicodeStr = (LPWSTR) MemAlloc( nChar * sizeof(WCHAR) ) ))
  699. {
  700. return NULL;
  701. }
  702. //
  703. // Convert Unicode string to multi-byte string
  704. //
  705. MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pAnsiStr, -1, pUnicodeStr, nChar);
  706. return pUnicodeStr;
  707. }
  708. LPWSTR
  709. DupUnicodeString(
  710. LPWSTR pStr
  711. )
  712. /*++
  713. Routine Description:
  714. Duplicate a Unicode string.
  715. Arguments:
  716. pStr - pointer to string to duplicate.
  717. Return Value:
  718. pointer to duplicated string.
  719. --*/
  720. {
  721. LPWSTR NewStr;
  722. NewStr = (LPWSTR) MemAlloc( (wcslen( pStr ) + 1) * sizeof (WCHAR));
  723. wcscpy( NewStr, pStr );
  724. return NewStr;
  725. }
  726. AddRecipient(
  727. PRECIPIENT *ppNewRecip,
  728. LPWSTR DisplayName,
  729. LPWSTR FaxNumber
  730. )
  731. /*++
  732. Routine Description:
  733. Add a recipient to the recipient list.
  734. Arguments:
  735. ppNewRecip - pointer to pointer to list to add item to.
  736. DisplayName - recipient name.
  737. FaxNumber - recipient fax number.
  738. Return Value:
  739. NA
  740. --*/
  741. {
  742. PRECIPIENT NewRecip;
  743. NewRecip = (PRECIPIENT) MemAllocZ( sizeof( RECIPIENT ) );
  744. if (NewRecip) {
  745. NewRecip->pName = DisplayName;
  746. NewRecip->pAddress = FaxNumber;
  747. NewRecip->pNext = (LPVOID) *ppNewRecip;
  748. *ppNewRecip = NewRecip;
  749. }
  750. return 0;
  751. }
  752. extern "C"
  753. BOOL
  754. CallWabAddress(
  755. HWND hDlg,
  756. PUSERMEM pUserMem,
  757. PRECIPIENT * ppNewRecipient
  758. )
  759. /*++
  760. Routine Description:
  761. C wrapper for CWabObj->Address
  762. Arguments:
  763. hDlg - parent window handle.
  764. pUserMem - pointer to USERMEM structure
  765. ppNewRecipient - list to add new recipients to.
  766. Return Value:
  767. TRUE if all of the entries have a fax number.
  768. FALSE otherwise.
  769. --*/
  770. {
  771. LPWABOBJ lpCWabObj = (LPWABOBJ) pUserMem->lpWabInit;
  772. return lpCWabObj->Address(
  773. hDlg,
  774. pUserMem->pRecipients,
  775. ppNewRecipient
  776. );
  777. }
  778. extern "C"
  779. LPVOID
  780. InitializeWAB(
  781. HINSTANCE hInstance
  782. )
  783. /*++
  784. Routine Description:
  785. Initialize the WAB.
  786. Arguments:
  787. hInstance - instance handle.
  788. Return Value:
  789. NONE
  790. --*/
  791. {
  792. LPWABOBJ lpWabObj = new CWabObj( hInstance );
  793. if (lpWabObj) {
  794. if (!lpWabObj->Initialize()) {
  795. delete (lpWabObj);
  796. lpWabObj = NULL;
  797. }
  798. }
  799. return (LPVOID) lpWabObj;
  800. }
  801. extern "C"
  802. VOID
  803. UnInitializeWAB(
  804. LPVOID lpVoid
  805. )
  806. /*++
  807. Routine Description:
  808. UnInitialize the WAB.
  809. Arguments:
  810. NONE
  811. Return Value:
  812. NONE
  813. --*/
  814. {
  815. LPWABOBJ lpWabObj = (LPWABOBJ) lpVoid;
  816. delete lpWabObj;
  817. }