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.

2455 lines
71 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. /* File: mapisend.cpp
  3. Description: Implements the most basic MAPI email client to send a message
  4. to one or more recipients. All operations are done without UI.
  5. classes: CMapiSession
  6. CMapiRecipients
  7. CMapiMessage
  8. CMapiMessageBody
  9. MAPI
  10. Revision History:
  11. Date Description Programmer
  12. -------- --------------------------------------------------- ----------
  13. 06/18/97 Initial creation. BrianAu
  14. 06/22/97 Added class MAPI. BrianAu
  15. */
  16. ///////////////////////////////////////////////////////////////////////////////
  17. #include "precomp.hxx"
  18. #pragma hdrstop
  19. #include "mapisend.h"
  20. //
  21. // Global MAPI object to provide dynamic linking to MAPI32.DLL.
  22. // All MAPI32.DLL functions are called through this object.
  23. //
  24. MAPI MAPI32;
  25. //
  26. // How many entries we grow the recipients list by when it is enlarged.
  27. //
  28. #ifdef DEBUG
  29. //
  30. // For debugging and development, stress the list-growth code by making
  31. // it extend the list each time a recipient is added.
  32. //
  33. UINT CMapiRecipients::m_cGrowIncr = 1;
  34. #else // !DEBUG
  35. //
  36. // For production builds, fix the growth increment at 3. 3 is arbitrary
  37. // but is probably a good conservative guess. Want to avoid
  38. // list growth in the typical scenario.
  39. //
  40. // 1 for the quota user.
  41. // 1 for the volume administrator.
  42. // 1 for the user's manager (? probably not)
  43. //
  44. // Note that the list growth code always runs at least once because
  45. // we use it to create the initial list.
  46. //
  47. UINT CMapiRecipients::m_cGrowIncr = 3;
  48. #endif // DEBUG
  49. ///////////////////////////////////////////////////////////////////////////////
  50. /* Function: CMapiRecipients::CMapiRecipients
  51. Description: Constructor.
  52. Arguments: None.
  53. Returns: Nothing.
  54. Revision History:
  55. Date Description Programmer
  56. -------- --------------------------------------------------- ----------
  57. 06/18/97 Initial creation. BrianAu
  58. */
  59. ///////////////////////////////////////////////////////////////////////////////
  60. CMapiRecipients::CMapiRecipients(
  61. BOOL bUnicode
  62. ) : m_pal(NULL),
  63. m_bUnicode(bUnicode),
  64. m_cMaxEntries(0)
  65. {
  66. }
  67. ///////////////////////////////////////////////////////////////////////////////
  68. /* Function: CMapiRecipients::~CMapiRecipients
  69. Description: Destructor.
  70. Frees the MAPI address list.
  71. Arguments: None.
  72. Returns: Nothing.
  73. Revision History:
  74. Date Description Programmer
  75. -------- --------------------------------------------------- ----------
  76. 06/18/97 Initial creation. BrianAu
  77. */
  78. ///////////////////////////////////////////////////////////////////////////////
  79. CMapiRecipients::~CMapiRecipients(
  80. VOID
  81. )
  82. {
  83. if (NULL != m_pal)
  84. {
  85. MAPI32.FreePadrlist(m_pal);
  86. }
  87. }
  88. CMapiRecipients::CMapiRecipients(
  89. const CMapiRecipients& rhs
  90. ) : m_pal(NULL),
  91. m_bUnicode(FALSE),
  92. m_cMaxEntries(0)
  93. {
  94. #ifdef UNICODE
  95. m_bUnicode = TRUE;
  96. #endif
  97. *this = rhs;
  98. }
  99. ///////////////////////////////////////////////////////////////////////////////
  100. /* Function: CMapiRecipients::operator = (const CMapiRecipients& rhs)
  101. Description: Assignment copy.
  102. Arguments:
  103. rhs - Reference to source recipient list.
  104. Returns: Reference to destination recipient list.
  105. Revision History:
  106. Date Description Programmer
  107. -------- --------------------------------------------------- ----------
  108. 06/18/97 Initial creation. BrianAu
  109. */
  110. ///////////////////////////////////////////////////////////////////////////////
  111. CMapiRecipients&
  112. CMapiRecipients::operator = (
  113. const CMapiRecipients& rhs
  114. )
  115. {
  116. if (this != &rhs)
  117. {
  118. BOOL bConvertStrings = m_bUnicode != rhs.m_bUnicode;
  119. //
  120. // Delete the current address list.
  121. //
  122. if (NULL != m_pal)
  123. {
  124. MAPI32.FreePadrlist(m_pal);
  125. m_pal = NULL;
  126. }
  127. //
  128. // Copy the Max entry count.
  129. //
  130. // NOTE: We DO NOT copy the m_bUnicode attribute.
  131. // This attribute stays with the object for life.
  132. //
  133. m_cMaxEntries = rhs.m_cMaxEntries;
  134. if (NULL != rhs.m_pal)
  135. {
  136. HRESULT hr = E_FAIL;
  137. UINT cb;
  138. cb = sizeof(ADRLIST) + ((m_cMaxEntries - 1) * sizeof(ADRENTRY));
  139. hr = MAPI32.AllocateBuffer(cb, (LPVOID *)&m_pal);
  140. if (SUCCEEDED(hr))
  141. {
  142. ZeroMemory(m_pal, cb); // Note: m_pal->cEntries is init'd to 0.
  143. if (NULL != m_pal)
  144. {
  145. for (UINT i = 0; i < rhs.m_pal->cEntries && SUCCEEDED(hr); i++)
  146. {
  147. hr = CopyAdrListEntry(m_pal->aEntries[i],
  148. rhs.m_pal->aEntries[i],
  149. bConvertStrings);
  150. if (SUCCEEDED(hr))
  151. {
  152. m_pal->cEntries++;
  153. }
  154. }
  155. }
  156. }
  157. if (FAILED(hr))
  158. {
  159. //
  160. // Something went wrong. Leave the object in an empty state.
  161. //
  162. if (NULL != m_pal)
  163. MAPI32.FreePadrlist(m_pal);
  164. m_pal = NULL;
  165. m_cMaxEntries = 0;
  166. }
  167. }
  168. }
  169. return *this;
  170. }
  171. ///////////////////////////////////////////////////////////////////////////////
  172. /* Function: CMapiRecipients::Count
  173. Description: Returns the count of valid entries in the address list.
  174. Arguments: None.
  175. Returns: Count of entries.
  176. Revision History:
  177. Date Description Programmer
  178. -------- --------------------------------------------------- ----------
  179. 06/18/97 Initial creation. BrianAu
  180. */
  181. ///////////////////////////////////////////////////////////////////////////////
  182. INT
  183. CMapiRecipients::Count(
  184. VOID
  185. ) const
  186. {
  187. return m_pal ? m_pal->cEntries : 0;
  188. }
  189. ///////////////////////////////////////////////////////////////////////////////
  190. /* Function: CMapiRecipients::AddRecipient
  191. Description: Adds a new recipient/recipient-type pair to the address list.
  192. Arguments:
  193. pszEmailName - Name of recipient typically used as an email destination.
  194. dwType - Recipient type. Can be one of the following:
  195. MAPI_ORIG
  196. MAPI_TO
  197. MAPI_CC
  198. MAPI_BCC
  199. Returns:
  200. Revision History:
  201. Date Description Programmer
  202. -------- --------------------------------------------------- ----------
  203. 06/18/97 Initial creation. BrianAu
  204. */
  205. ///////////////////////////////////////////////////////////////////////////////
  206. HRESULT
  207. CMapiRecipients::AddRecipient(
  208. LPCTSTR pszEmailName,
  209. DWORD dwType
  210. )
  211. {
  212. HRESULT hr = NO_ERROR;
  213. if (NULL == m_pal || m_pal->cEntries == m_cMaxEntries)
  214. {
  215. //
  216. // Either we're just starting up (no list created yet),
  217. // or the current list is full. Grow the list.
  218. //
  219. hr = Grow(m_cGrowIncr);
  220. }
  221. if (SUCCEEDED(hr) && NULL != m_pal)
  222. {
  223. UINT cb;
  224. INT i = m_pal->cEntries++;
  225. m_pal->aEntries[i].ulReserved1 = 0;
  226. m_pal->aEntries[i].cValues = 2;
  227. //
  228. // Allocate the SPropValue buffer for this new entry.
  229. // Our entries have 2 values (name and type).
  230. // Caller must call IAddrBook::ResolveName() to get the remaining
  231. // recipient information.
  232. //
  233. cb = sizeof(SPropValue) * m_pal->aEntries[i].cValues;
  234. hr = MAPI32.AllocateBuffer(cb, (LPVOID *)&m_pal->aEntries[i].rgPropVals);
  235. if (SUCCEEDED(hr))
  236. {
  237. ZeroMemory(m_pal->aEntries[i].rgPropVals, cb);
  238. //
  239. // Allocate the buffer for the recipient email name string.
  240. //
  241. hr = MAPI32.AllocateMore((lstrlen(pszEmailName)+1) * sizeof(TCHAR),
  242. (LPVOID)m_pal->aEntries[i].rgPropVals,
  243. (LPVOID *)&m_pal->aEntries[i].rgPropVals[0].Value.LPSZ);
  244. if (SUCCEEDED(hr))
  245. {
  246. //
  247. // Store the recipient email name string.
  248. //
  249. m_pal->aEntries[i].rgPropVals[0].ulPropTag = PR_DISPLAY_NAME;
  250. lstrcpy(m_pal->aEntries[i].rgPropVals[0].Value.LPSZ, pszEmailName);
  251. //
  252. // Store the recipient type (i.e. MAPI_TO, MAPI_CC etc).
  253. //
  254. m_pal->aEntries[i].rgPropVals[1].ulPropTag = PR_RECIPIENT_TYPE;
  255. m_pal->aEntries[i].rgPropVals[1].Value.l = dwType;
  256. }
  257. }
  258. }
  259. return hr;
  260. }
  261. ///////////////////////////////////////////////////////////////////////////////
  262. /* Function: CMapiRecipients::Grow
  263. Description: Increases the size of the address list, preserving any
  264. existing list entries.
  265. Arguments:
  266. cGrowIncr - Number of entries to grow the list by.
  267. Returns:
  268. Revision History:
  269. Date Description Programmer
  270. -------- --------------------------------------------------- ----------
  271. 06/18/97 Initial creation. BrianAu
  272. */
  273. ///////////////////////////////////////////////////////////////////////////////
  274. HRESULT
  275. CMapiRecipients::Grow(
  276. UINT cGrowIncr
  277. )
  278. {
  279. HRESULT hr = E_FAIL;
  280. LPADRLIST m_palNew = NULL;
  281. UINT cb;
  282. //
  283. // Allocate the new buffer m_cGrowIncr entries larger than the
  284. // current buffer. The (-1) is because the declaration of ADRLIST already
  285. // includes one entry.
  286. //
  287. cb = sizeof(ADRLIST) + ((m_cMaxEntries + cGrowIncr - 1) * sizeof(ADRENTRY));
  288. hr = MAPI32.AllocateBuffer(cb, (LPVOID *)&m_palNew);
  289. if (SUCCEEDED(hr))
  290. {
  291. ZeroMemory(m_palNew, cb); // Note: m_palNew->cEntries is init'd to 0.
  292. if (NULL != m_pal)
  293. {
  294. //
  295. // We have an existing address list.
  296. // Copy it to the new list buffer.
  297. // If we fail the copy of an entry, we abort the loop and m_palNew->cEntries
  298. // accurately reflects how many valid entries we have.
  299. //
  300. for (UINT i = 0; i < m_pal->cEntries && SUCCEEDED(hr); i++)
  301. {
  302. hr = CopyAdrListEntry(m_palNew->aEntries[i], m_pal->aEntries[i], FALSE);
  303. if (SUCCEEDED(hr))
  304. {
  305. m_palNew->cEntries++;
  306. }
  307. }
  308. }
  309. }
  310. if (SUCCEEDED(hr))
  311. {
  312. //
  313. // Delete the original list (if it exists) and store the
  314. // address of the new list in m_pal.
  315. //
  316. LPADRLIST palOrig = m_pal;
  317. m_pal = m_palNew;
  318. if (NULL != palOrig)
  319. MAPI32.FreePadrlist(palOrig);
  320. m_cMaxEntries += cGrowIncr;
  321. }
  322. else
  323. {
  324. //
  325. // Something went wrong. Just delete the new list and keep the old one
  326. // the way it was.
  327. //
  328. if (NULL != m_palNew)
  329. MAPI32.FreePadrlist(m_palNew);
  330. }
  331. return hr;
  332. }
  333. ///////////////////////////////////////////////////////////////////////////////
  334. /* Function: CMapiRecipients::CopyAdrListEntry
  335. Description: Copies a single list entry from one entry structure to another.
  336. All entry-type-specific issues are addressed.
  337. Arguments:
  338. Dest - Reference to destination entry structure.
  339. Src - Reference to source entry structure.
  340. Returns:
  341. Revision History:
  342. Date Description Programmer
  343. -------- --------------------------------------------------- ----------
  344. 06/18/97 Initial creation. BrianAu
  345. */
  346. ///////////////////////////////////////////////////////////////////////////////
  347. HRESULT
  348. CMapiRecipients::CopyAdrListEntry(
  349. ADRENTRY& Dest,
  350. ADRENTRY& Src,
  351. BOOL bConvertStrings
  352. )
  353. {
  354. HRESULT hr;
  355. UINT cb = 0;
  356. //
  357. // Allocate buffer for the new entry and it's property values.
  358. //
  359. cb = sizeof(SPropValue) * Src.cValues;
  360. hr = MAPI32.AllocateBuffer(cb, (LPVOID *)&Dest.rgPropVals);
  361. if (SUCCEEDED(hr))
  362. {
  363. ZeroMemory(Dest.rgPropVals, cb);
  364. Dest.cValues = 0;
  365. //
  366. // Copy each of the values.
  367. // If we fail the copy of a value, we abort the loop and Dest.cValues
  368. // accurately reflects how many valid prop values we have.
  369. //
  370. for (UINT i = 0; i < Src.cValues && SUCCEEDED(hr); i++)
  371. {
  372. hr = CopySPropVal((LPVOID)Dest.rgPropVals, // Base for new allocations
  373. Dest.rgPropVals[i], // Destination SPropVal
  374. Src.rgPropVals[i], // Source SPropVal
  375. bConvertStrings);
  376. if (SUCCEEDED(hr))
  377. {
  378. Dest.cValues++;
  379. }
  380. }
  381. }
  382. return hr;
  383. }
  384. ///////////////////////////////////////////////////////////////////////////////
  385. /* Function: CMapiRecipients::CopySPropVal
  386. Description: Copies a single property value from one SPropValue object
  387. to another. Used by CopyAdrListEntry to copy the individual properties
  388. belonging to an entry.
  389. Arguments:
  390. pvBaseAlloc - Pointer to use as the "lpObject" argument in a call
  391. to MAPIAllocateMore() if memory must be reallocated during
  392. the copy process.
  393. Dest - Reference to destination property value structure.
  394. Src - Reference to source property value structure.
  395. Returns:
  396. Revision History:
  397. Date Description Programmer
  398. -------- --------------------------------------------------- ----------
  399. 06/18/97 Initial creation. BrianAu
  400. */
  401. ///////////////////////////////////////////////////////////////////////////////
  402. HRESULT
  403. CMapiRecipients::CopySPropVal(
  404. LPVOID pvBaseAlloc,
  405. SPropValue& Dest,
  406. SPropValue& Src,
  407. BOOL bConvertStrings
  408. )
  409. {
  410. HRESULT hr = NO_ERROR;
  411. BOOL bCopyTag = TRUE;
  412. //
  413. // Copy method varies depending on property type.
  414. //
  415. switch(PROP_TYPE(Src.ulPropTag))
  416. {
  417. case PT_I2:
  418. Dest.Value.i = Src.Value.i;
  419. break;
  420. case PT_LONG:
  421. Dest.Value.l = Src.Value.l;
  422. break;
  423. case PT_R4:
  424. Dest.Value.flt = Src.Value.flt;
  425. break;
  426. case PT_DOUBLE:
  427. Dest.Value.dbl = Src.Value.dbl;
  428. break;
  429. case PT_BOOLEAN:
  430. Dest.Value.b = Src.Value.b;
  431. break;
  432. case PT_CURRENCY:
  433. Dest.Value.cur = Src.Value.cur;
  434. break;
  435. case PT_APPTIME:
  436. Dest.Value.at = Src.Value.at;
  437. break;
  438. case PT_SYSTIME:
  439. Dest.Value.ft = Src.Value.ft;
  440. break;
  441. case PT_I8:
  442. Dest.Value.li = Src.Value.li;
  443. break;
  444. case PT_ERROR:
  445. Dest.Value.err = Src.Value.err;
  446. break;
  447. case PT_NULL:
  448. case PT_OBJECT:
  449. Dest.Value.x = Src.Value.x;
  450. break;
  451. case PT_STRING8:
  452. if (bConvertStrings && m_bUnicode)
  453. {
  454. //
  455. // The recipients list is unicode, the source is ANSI
  456. // and we're supposed to convert strings. That means
  457. // we need to convert from Ansi to Unicode.
  458. //
  459. hr = CopySPropValString(pvBaseAlloc,
  460. &Dest.Value.lpszW,
  461. Src.Value.lpszA);
  462. Dest.ulPropTag = PROP_TAG(PT_UNICODE, PROP_ID(Src.ulPropTag));
  463. bCopyTag = FALSE;
  464. }
  465. else
  466. {
  467. //
  468. // No conversion required. Just a straight copy.
  469. //
  470. hr = CopyVarLengthSPropVal(pvBaseAlloc,
  471. (LPVOID *)&Dest.Value.lpszA,
  472. Src.Value.lpszA,
  473. (lstrlenA(Src.Value.lpszA)+1) * sizeof(char));
  474. }
  475. break;
  476. case PT_UNICODE:
  477. if (bConvertStrings && !m_bUnicode)
  478. {
  479. //
  480. // The recipients list is Ansi, the source is Unicode
  481. // and we're supposed to convert strings. That means
  482. // we need to convert from Unicode to Ansi.
  483. //
  484. hr = CopySPropValString(pvBaseAlloc,
  485. &Dest.Value.lpszA,
  486. Src.Value.lpszW);
  487. Dest.ulPropTag = PROP_TAG(PT_STRING8, PROP_ID(Src.ulPropTag));
  488. bCopyTag = FALSE;
  489. }
  490. else
  491. {
  492. //
  493. // No conversion required. Just a straight copy.
  494. //
  495. hr = CopyVarLengthSPropVal(pvBaseAlloc,
  496. (LPVOID *)&Dest.Value.lpszW,
  497. Src.Value.lpszW,
  498. (lstrlenW(Src.Value.lpszW)+1) * sizeof(WCHAR));
  499. }
  500. break;
  501. case PT_BINARY:
  502. hr = CopyVarLengthSPropVal(pvBaseAlloc,
  503. (LPVOID *)&Dest.Value.bin.lpb,
  504. Src.Value.bin.lpb,
  505. Src.Value.bin.cb);
  506. break;
  507. case PT_CLSID:
  508. hr = CopyVarLengthSPropVal(pvBaseAlloc,
  509. (LPVOID *)&Dest.Value.lpguid,
  510. Src.Value.lpguid,
  511. sizeof(*(Src.Value.lpguid)));
  512. break;
  513. default:
  514. //
  515. // FEATURE: Assert here so we know if we should be handling
  516. // some other property type.
  517. //
  518. hr = E_FAIL;
  519. break;
  520. }
  521. if (SUCCEEDED(hr))
  522. {
  523. //
  524. // Copy the common stuff.
  525. //
  526. Dest.dwAlignPad = Src.dwAlignPad;
  527. if (bCopyTag)
  528. {
  529. Dest.ulPropTag = Src.ulPropTag;
  530. }
  531. }
  532. return hr;
  533. }
  534. ///////////////////////////////////////////////////////////////////////////////
  535. /* Function: CMapiRecipients::CopyVarLengthSPropVal
  536. Description: Copies a single variable-length property value item from
  537. one location in memory to another. Memory for the destination is
  538. automatically allocated. This function is used to copy prop values
  539. of types STRING, BINARY etc.
  540. Arguments:
  541. pvBaseAlloc - Pointer to use as the "lpObject" argument in a call
  542. to MAPIAllocateMore().
  543. ppvDest - Address of pointer variable to receive the address of
  544. the newly allocated buffer.
  545. pvSrc - Address of source buffer.
  546. cb - Number of bytes to copy from pvSrc to *ppvDest.
  547. Returns:
  548. Revision History:
  549. Date Description Programmer
  550. -------- --------------------------------------------------- ----------
  551. 06/18/97 Initial creation. BrianAu
  552. */
  553. ///////////////////////////////////////////////////////////////////////////////
  554. HRESULT
  555. CMapiRecipients::CopyVarLengthSPropVal(
  556. LPVOID pvBaseAlloc,
  557. LPVOID *ppvDest,
  558. LPVOID pvSrc,
  559. INT cb
  560. )
  561. {
  562. HRESULT hr;
  563. hr = MAPI32.AllocateMore(cb, pvBaseAlloc, ppvDest);
  564. if (SUCCEEDED(hr))
  565. {
  566. CopyMemory(*ppvDest, pvSrc, cb);
  567. }
  568. return hr;
  569. }
  570. ///////////////////////////////////////////////////////////////////////////////
  571. /* Function: CMapiRecipients::CopySPropValString (ANSI -> UNICODE)
  572. Description: Copies a string property value item from one location
  573. to another; performing ANSI/UNICODE translations as required.
  574. Arguments:
  575. pvBaseAlloc - Pointer to use as the "lpObject" argument in a call
  576. to MAPIAllocateMore().
  577. ppszDestW - Address of pointer variable to receive the address of
  578. the newly wide character buffer.
  579. pszSrcA - Address of ANSI source buffer.
  580. Returns:
  581. Revision History:
  582. Date Description Programmer
  583. -------- --------------------------------------------------- ----------
  584. 06/18/97 Initial creation. BrianAu
  585. */
  586. ///////////////////////////////////////////////////////////////////////////////
  587. HRESULT
  588. CMapiRecipients::CopySPropValString(
  589. LPVOID pvBaseAlloc,
  590. LPWSTR *ppszDestW,
  591. LPCSTR pszSrcA
  592. )
  593. {
  594. HRESULT hr;
  595. INT cchW = MultiByteToWideChar(CP_ACP,
  596. 0,
  597. pszSrcA,
  598. -1,
  599. NULL,
  600. 0);
  601. hr = MAPI32.AllocateMore(cchW * sizeof(WCHAR), pvBaseAlloc, (LPVOID *)ppszDestW);
  602. if (SUCCEEDED(hr))
  603. {
  604. MultiByteToWideChar(CP_ACP,
  605. 0,
  606. pszSrcA,
  607. -1,
  608. *ppszDestW,
  609. cchW);
  610. }
  611. return hr;
  612. }
  613. ///////////////////////////////////////////////////////////////////////////////
  614. /* Function: CMapiRecipients::CopySPropValString (UNICODE -> ANSI)
  615. Description: Copies a string property value item from one location
  616. to another; performing ANSI/UNICODE translations as required.
  617. Arguments:
  618. pvBaseAlloc - Pointer to use as the "lpObject" argument in a call
  619. to MAPIAllocateMore().
  620. ppszDestA - Address of pointer variable to receive the address of
  621. the newly ANSI character buffer.
  622. pszSrcW - Address of UNICODE source buffer.
  623. Returns:
  624. Revision History:
  625. Date Description Programmer
  626. -------- --------------------------------------------------- ----------
  627. 06/18/97 Initial creation. BrianAu
  628. */
  629. ///////////////////////////////////////////////////////////////////////////////
  630. HRESULT
  631. CMapiRecipients::CopySPropValString(
  632. LPVOID pvBaseAlloc,
  633. LPSTR *ppszDestA,
  634. LPCWSTR pszSrcW
  635. )
  636. {
  637. HRESULT hr;
  638. INT cchA = WideCharToMultiByte(CP_ACP,
  639. 0,
  640. pszSrcW,
  641. -1,
  642. NULL,
  643. 0,
  644. NULL, NULL);
  645. hr = MAPI32.AllocateMore(cchA * sizeof(CHAR), pvBaseAlloc, (LPVOID *)ppszDestA);
  646. if (SUCCEEDED(hr))
  647. {
  648. WideCharToMultiByte(CP_ACP,
  649. 0,
  650. pszSrcW,
  651. -1,
  652. *ppszDestA,
  653. cchA,
  654. NULL, NULL);
  655. }
  656. return hr;
  657. }
  658. ///////////////////////////////////////////////////////////////////////////////
  659. /* Function: CMapiSession::CMapiSession
  660. Description: Constructor.
  661. Arguments: None.
  662. Returns:
  663. Revision History:
  664. Date Description Programmer
  665. -------- --------------------------------------------------- ----------
  666. 06/18/97 Initial creation. BrianAu
  667. */
  668. ///////////////////////////////////////////////////////////////////////////////
  669. CMapiSession::CMapiSession(
  670. VOID
  671. ) : m_pSession(NULL),
  672. m_pDefMsgStore(NULL),
  673. m_pOutBoxFolder(NULL),
  674. m_bMapiInitialized(FALSE)
  675. {
  676. }
  677. ///////////////////////////////////////////////////////////////////////////////
  678. /* Function: CMapiSession::CMapiSession
  679. Description: Constructor. Initializes MAPI.
  680. Arguments: None.
  681. Returns:
  682. Revision History:
  683. Date Description Programmer
  684. -------- --------------------------------------------------- ----------
  685. 06/18/97 Initial creation. BrianAu
  686. */
  687. ///////////////////////////////////////////////////////////////////////////////
  688. CMapiSession::~CMapiSession(
  689. VOID
  690. )
  691. {
  692. if (NULL != m_pOutBoxFolder)
  693. {
  694. m_pOutBoxFolder->Release();
  695. }
  696. if (NULL != m_pDefMsgStore)
  697. {
  698. m_pDefMsgStore->Release();
  699. }
  700. if (NULL != m_pSession)
  701. {
  702. m_pSession->Release();
  703. }
  704. if (m_bMapiInitialized)
  705. {
  706. //
  707. // If MAPI was initialized, uninitialize it.
  708. //
  709. MAPI32.Uninitialize();
  710. //
  711. // Unload MAPI32.DLL.
  712. //
  713. MAPI32.Unload();
  714. }
  715. }
  716. ///////////////////////////////////////////////////////////////////////////////
  717. /* Function: CMapiSession::Initialize
  718. Description: Initializes the session object by:
  719. 1. Initializing MAPI if neccessary,
  720. 2. Logging on to create the MAPI session object.
  721. 3. Open the default msg store.
  722. 4. Open the outbox folder in the default msg store.
  723. Arguments: None.
  724. Returns:
  725. Revision History:
  726. Date Description Programmer
  727. -------- --------------------------------------------------- ----------
  728. 06/18/97 Initial creation. BrianAu
  729. */
  730. ///////////////////////////////////////////////////////////////////////////////
  731. HRESULT
  732. CMapiSession::Initialize(
  733. VOID
  734. )
  735. {
  736. HRESULT hr = NO_ERROR;
  737. if (!m_bMapiInitialized)
  738. {
  739. //
  740. // Load MAPI32.DLL.
  741. //
  742. MAPI32.Load();
  743. //
  744. // Initialize MAPI if it hasn't been initialized.
  745. //
  746. hr = MAPI32.Initialize(NULL);
  747. if (SUCCEEDED(hr))
  748. {
  749. //
  750. // Remember that MAPI has been initialized.
  751. //
  752. m_bMapiInitialized = TRUE;
  753. }
  754. }
  755. if (m_bMapiInitialized)
  756. {
  757. //
  758. // Attempt logon only if MAPI has been initialized.
  759. //
  760. DWORD dwLogonFlags = MAPI_TIMEOUT_SHORT | MAPI_USE_DEFAULT | MAPI_EXTENDED | MAPI_ALLOW_OTHERS;
  761. #ifdef UNICODE
  762. dwLogonFlags |= MAPI_UNICODE;
  763. #endif
  764. if (NULL != m_pSession)
  765. {
  766. //
  767. // Release any previously-held session interface ptr.
  768. //
  769. m_pSession->Release();
  770. m_pSession = NULL;
  771. }
  772. hr = MAPI32.LogonEx(0, // Hwnd for any UI.
  773. NULL, // Profile name.
  774. NULL, // Password.
  775. dwLogonFlags, // Flags
  776. &m_pSession); // Session obj ptr (out).
  777. if (SUCCEEDED(hr))
  778. {
  779. ReportErrorsReturned(hr);
  780. //
  781. // We're logged on. Open the default msg store and out box folder.
  782. //
  783. hr = OpenDefMsgStore();
  784. if (SUCCEEDED(hr))
  785. {
  786. hr = OpenOutBoxFolder();
  787. }
  788. }
  789. }
  790. return hr;
  791. }
  792. ///////////////////////////////////////////////////////////////////////////////
  793. /* Function: CMapiSession::OpenDefMsgStore
  794. Description: Opens the session's default message store.
  795. Stores the resulting IMsgStore ptr in m_pDefMsgStore.
  796. Arguments: None.
  797. Returns:
  798. Revision History:
  799. Date Description Programmer
  800. -------- --------------------------------------------------- ----------
  801. 06/18/97 Initial creation. BrianAu
  802. */
  803. ///////////////////////////////////////////////////////////////////////////////
  804. HRESULT
  805. CMapiSession::OpenDefMsgStore(
  806. VOID
  807. )
  808. {
  809. HRESULT hr = E_FAIL;
  810. SPropValue spv;
  811. SizedSPropTagArray(2, sptCols) = {2, PR_ENTRYID, PR_DEFAULT_STORE};
  812. SRestriction sres;
  813. if (NULL != m_pSession)
  814. {
  815. LPMAPITABLE pTable;
  816. hr = m_pSession->GetMsgStoresTable(0, &pTable);
  817. ReportErrorsReturned(hr);
  818. if (SUCCEEDED(hr))
  819. {
  820. //
  821. // Find the entry ID for the default store in the session's
  822. // msg stores table.
  823. //
  824. LPSRowSet pRow = NULL;
  825. sres.rt = RES_PROPERTY;
  826. sres.res.resProperty.relop = RELOP_EQ;
  827. sres.res.resProperty.ulPropTag = PR_DEFAULT_STORE;
  828. sres.res.resProperty.lpProp = &spv;
  829. spv.ulPropTag = PR_DEFAULT_STORE;
  830. spv.Value.b = TRUE;
  831. hr = MAPI32.HrQueryAllRows(pTable, // Table ptr.
  832. (LPSPropTagArray)&sptCols, // Column set
  833. &sres, // Row restrictions
  834. NULL, // Sort order set
  835. 0, // All rows.
  836. &pRow); // Resulting row set (out)
  837. ReportErrorsReturned(hr);
  838. if (SUCCEEDED(hr))
  839. {
  840. SBinary sbEID = {0, NULL};
  841. if (NULL != pRow &&
  842. 0 != pRow->cRows &&
  843. 0 != pRow->aRow[0].cValues &&
  844. PR_ENTRYID == pRow->aRow[0].lpProps[0].ulPropTag)
  845. {
  846. sbEID = pRow->aRow[0].lpProps[0].Value.bin;
  847. //
  848. // Found the ID. Now open the store.
  849. //
  850. if (NULL != m_pDefMsgStore)
  851. {
  852. //
  853. // Release any previously-held store interface ptr.
  854. //
  855. m_pDefMsgStore->Release();
  856. m_pDefMsgStore = NULL;
  857. }
  858. hr = m_pSession->OpenMsgStore(0, // Hwnd for any UI
  859. sbEID.cb, // Entry ID size.
  860. (LPENTRYID)sbEID.lpb, // Entry ID ptr.
  861. NULL, // Use Std iface.
  862. MAPI_BEST_ACCESS, // read/write access
  863. &m_pDefMsgStore); // Store ptr (out)
  864. ReportErrorsReturned(hr);
  865. }
  866. else
  867. {
  868. hr = MAPI_E_NOT_FOUND;
  869. }
  870. MAPI32.FreeProws(pRow);
  871. }
  872. pTable->Release();
  873. }
  874. }
  875. return hr;
  876. }
  877. ///////////////////////////////////////////////////////////////////////////////
  878. /* Function: CMapiSession::GetSessionUser
  879. Description: Returns the address properties for the session user.
  880. Arguments: None.
  881. Returns:
  882. Revision History:
  883. Date Description Programmer
  884. -------- --------------------------------------------------- ----------
  885. 06/18/97 Initial creation. BrianAu
  886. */
  887. ///////////////////////////////////////////////////////////////////////////////
  888. HRESULT
  889. CMapiSession::GetSessionUser(
  890. LPSPropValue *ppProps,
  891. ULONG *pcbProps
  892. )
  893. {
  894. HRESULT hr = E_FAIL;
  895. if (NULL != m_pSession)
  896. {
  897. ULONG cbEID = 0;
  898. LPENTRYID lpEID = NULL;
  899. //
  900. // Get the "identity" of the session.
  901. // In general, this is the user's entry ID.
  902. //
  903. hr = m_pSession->QueryIdentity(&cbEID, &lpEID);
  904. if (SUCCEEDED(hr))
  905. {
  906. LPADRBOOK pAddrBook = NULL;
  907. hr = GetAddressBook(&pAddrBook);
  908. if (SUCCEEDED(hr))
  909. {
  910. ULONG ulObjType = 0;
  911. IMAPIProp *pMailUser = NULL;
  912. //
  913. // Open the user's entry in the address book.
  914. //
  915. hr = pAddrBook->OpenEntry(cbEID,
  916. lpEID,
  917. NULL,
  918. 0,
  919. &ulObjType,
  920. (LPUNKNOWN *)&pMailUser);
  921. if (SUCCEEDED(hr))
  922. {
  923. ULONG ulFlags = 0;
  924. ULONG cProps = 0;
  925. #ifdef UNICODE
  926. //
  927. // For unicode builds, we want UNICODE property strings.
  928. //
  929. ulFlags |= MAPI_UNICODE;
  930. #endif
  931. SizedSPropTagArray(5, tags) = { 5, PR_ADDRTYPE,
  932. PR_DISPLAY_NAME,
  933. PR_EMAIL_ADDRESS,
  934. PR_ENTRYID,
  935. PR_SEARCH_KEY };
  936. //
  937. // Retrieve the user properties and return them to
  938. // the caller.
  939. //
  940. hr = pMailUser->GetProps((LPSPropTagArray)&tags, // Prop tags
  941. ulFlags,
  942. pcbProps, // Prop cnt (out)
  943. ppProps); // Prop ptr (out)
  944. ReportErrorsReturned(hr);
  945. pMailUser->Release();
  946. }
  947. pAddrBook->Release();
  948. }
  949. MAPI32.FreeBuffer(lpEID);
  950. }
  951. }
  952. return hr;
  953. }
  954. ///////////////////////////////////////////////////////////////////////////////
  955. /* Function: CMapiSession::OpenOutBoxFolder
  956. Description: Opens the outbox folder in the default message store.
  957. Stores the resulting IMAPIFolder ptr in m_pOutBoxFolder.
  958. Arguments: None.
  959. Returns:
  960. Revision History:
  961. Date Description Programmer
  962. -------- --------------------------------------------------- ----------
  963. 06/18/97 Initial creation. BrianAu
  964. */
  965. ///////////////////////////////////////////////////////////////////////////////
  966. HRESULT
  967. CMapiSession::OpenOutBoxFolder(
  968. VOID
  969. )
  970. {
  971. HRESULT hr = E_FAIL;
  972. if (NULL != m_pSession && NULL != m_pDefMsgStore)
  973. {
  974. LPSPropValue pProps = NULL;
  975. ULONG ulObjType;
  976. ULONG cProps;
  977. ULONG ulFlags = 0;
  978. #ifdef UNICODE
  979. //
  980. // For unicode builds, we want UNICODE property strings.
  981. //
  982. ulFlags |= MAPI_UNICODE;
  983. #endif
  984. SizedSPropTagArray(1, sptFolders) = { 1, PR_IPM_OUTBOX_ENTRYID };
  985. //
  986. // Retrieve the entry ID for the outbox in the default msg store.
  987. //
  988. hr = m_pDefMsgStore->GetProps((LPSPropTagArray)&sptFolders, // Prop tags
  989. ulFlags,
  990. &cProps, // Prop cnt (out)
  991. &pProps); // Prop ptr (out)
  992. ReportErrorsReturned(hr);
  993. if (SUCCEEDED(hr))
  994. {
  995. if (0 != cProps && NULL != pProps)
  996. {
  997. if (pProps[0].ulPropTag == sptFolders.aulPropTag[0])
  998. {
  999. //
  1000. // Get the MAPI folder interface ptr for the outbox folder.
  1001. //
  1002. if (NULL != m_pOutBoxFolder)
  1003. {
  1004. //
  1005. // Release any previously-held outbox interface ptr.
  1006. //
  1007. m_pOutBoxFolder->Release();
  1008. m_pOutBoxFolder = NULL;
  1009. }
  1010. hr = m_pSession->OpenEntry(pProps[0].Value.bin.cb,
  1011. (LPENTRYID)pProps[0].Value.bin.lpb,
  1012. NULL,
  1013. MAPI_MODIFY,
  1014. &ulObjType,
  1015. (LPUNKNOWN *)&m_pOutBoxFolder);
  1016. ReportErrorsReturned(hr);
  1017. }
  1018. else
  1019. {
  1020. hr = MAPI_E_NOT_FOUND;
  1021. }
  1022. MAPI32.FreeBuffer(pProps);
  1023. }
  1024. }
  1025. }
  1026. return hr;
  1027. }
  1028. ///////////////////////////////////////////////////////////////////////////////
  1029. /* Function: CMapiSession::Send
  1030. Description: Sends a message to a list of recipients. There are 3
  1031. versions that allow simple and complex formatting of the
  1032. message body:
  1033. 1. First version lets you pass in simple text strings for the
  1034. subject and body text. This is the simplest way to send a
  1035. short, simple message.
  1036. 2. Second version lets you pass in the subject as a simple text
  1037. string but then lets you create a complex message body as
  1038. a CMapiMessageBody object. This probably won't get used much.
  1039. 3. The third version lets you create a CMapiMessage object
  1040. containing subject line and body text. This is the method
  1041. to use if you want to create a message with complex formatting.
  1042. Sending a message with CMapiSession::Send ensures that the
  1043. recipient list contains fully resolved names. If you send
  1044. a message with CMapiMessage::Send, you must resolve the names
  1045. before the Send call is made.
  1046. Arguments:
  1047. pAdrList - Address of MAPI ADRLIST structure containing the
  1048. list of recipient addresses. It is assumed that
  1049. the list contains unresolved recipients but this is not a
  1050. requirement.
  1051. pszSubject - Address of subject line text.
  1052. pszBody - Address of msg body text.
  1053. body - Reference to CMapiMessageBody object containing the message text.
  1054. msg - Reference to CMapiMessage object containing the subject line
  1055. and message body text.
  1056. Returns:
  1057. Revision History:
  1058. Date Description Programmer
  1059. -------- --------------------------------------------------- ----------
  1060. 06/18/97 Initial creation. BrianAu
  1061. */
  1062. ///////////////////////////////////////////////////////////////////////////////
  1063. //
  1064. // Simplest form. Just give an address list, subject line and body
  1065. // text string.
  1066. //
  1067. HRESULT
  1068. CMapiSession::Send(
  1069. LPADRLIST pAdrList,
  1070. LPCTSTR pszSubject,
  1071. LPCTSTR pszBody
  1072. )
  1073. {
  1074. HRESULT hr;
  1075. //
  1076. // Create a local CMapiMessage object with the given subject
  1077. // line and body text. Then just send it.
  1078. //
  1079. CMapiMessage msg(m_pOutBoxFolder);
  1080. hr = msg.SetSubject(pszSubject);
  1081. if (SUCCEEDED(hr))
  1082. {
  1083. hr = msg.Append(pszBody);
  1084. if (SUCCEEDED(hr))
  1085. {
  1086. hr = Send(pAdrList, msg);
  1087. }
  1088. }
  1089. return hr;
  1090. }
  1091. //
  1092. // If you already have a CMapiMessageBody object created with text, this is the
  1093. // version you want to use.
  1094. //
  1095. HRESULT
  1096. CMapiSession::Send(
  1097. LPADRLIST pAdrList,
  1098. LPCTSTR pszSubject,
  1099. CMapiMessageBody& body
  1100. )
  1101. {
  1102. //
  1103. // Create a local CMapiMessage object with the given subject
  1104. // line and body text. Then just send it.
  1105. //
  1106. CMapiMessage msg(m_pOutBoxFolder, body, pszSubject);
  1107. return Send(pAdrList, msg);
  1108. }
  1109. //
  1110. // If you already have a CMapiMessage object create with subject line
  1111. // and body text, use this. The other versions of Send() eventually
  1112. // call this one.
  1113. //
  1114. HRESULT
  1115. CMapiSession::Send(
  1116. LPADRLIST pAdrList,
  1117. CMapiMessage& msg
  1118. )
  1119. {
  1120. HRESULT hr = E_FAIL;
  1121. hr = ResolveAddresses(pAdrList);
  1122. if (SUCCEEDED(hr))
  1123. {
  1124. hr = msg.Send(pAdrList);
  1125. DebugMsg(DM_ERROR, TEXT("CMapiSession::Send, Result = 0x%08X"), hr);
  1126. }
  1127. return hr;
  1128. }
  1129. ///////////////////////////////////////////////////////////////////////////////
  1130. /* Function: CMapiSession::GetAddressBook
  1131. Description: Returns the session's address book pointer.
  1132. Arguments:
  1133. ppAdrBook - Address of pointer variable to receive pointer value.
  1134. Returns:
  1135. Revision History:
  1136. Date Description Programmer
  1137. -------- --------------------------------------------------- ----------
  1138. 06/18/97 Initial creation. BrianAu
  1139. */
  1140. ///////////////////////////////////////////////////////////////////////////////
  1141. HRESULT
  1142. CMapiSession::GetAddressBook(
  1143. LPADRBOOK *ppAdrBook
  1144. )
  1145. {
  1146. HRESULT hr = E_POINTER;
  1147. if (NULL != m_pSession && NULL != ppAdrBook)
  1148. {
  1149. hr = m_pSession->OpenAddressBook(0, // Hwnd for UI
  1150. NULL, // Use std interface
  1151. AB_NO_DIALOG, // No UI.
  1152. ppAdrBook); // Book ptr (out)
  1153. ReportErrorsReturned(hr);
  1154. }
  1155. return hr;
  1156. }
  1157. ///////////////////////////////////////////////////////////////////////////////
  1158. /* Function: CMapiSession::ReportErrorsReturned [static]
  1159. Description: When a MAPI function returns MAPI_W_ERRORS_RETURNED,
  1160. error information can be obtained by calling IMapiSession::GetLastError.
  1161. This function encapsulates the necessary behavior to get this error
  1162. information and dump it to the debugger. An option to write a
  1163. warning/error to the system event log is planned.
  1164. Arguments:
  1165. hr - HRESULT containing the error code.
  1166. bLogEvent [optional] - If True, write an event to the system event
  1167. log. This option is not in place yet.
  1168. Returns: Nothing.
  1169. Revision History:
  1170. Date Description Programmer
  1171. -------- --------------------------------------------------- ----------
  1172. 06/16/97 Initial creation. BrianAu
  1173. */
  1174. ///////////////////////////////////////////////////////////////////////////////
  1175. VOID
  1176. CMapiSession::ReportErrorsReturned(
  1177. HRESULT hr,
  1178. BOOL bLogEvent // Unused at this time.
  1179. )
  1180. {
  1181. if (MAPI_W_ERRORS_RETURNED == hr)
  1182. {
  1183. LPMAPIERROR pMapiErrors = NULL;
  1184. DWORD dwFlags = 0;
  1185. #ifdef UNICODE
  1186. dwFlags |= MAPI_UNICODE;
  1187. #endif
  1188. hr = m_pSession->GetLastError(hr, dwFlags, &pMapiErrors);
  1189. if (S_OK == hr)
  1190. {
  1191. if (NULL != pMapiErrors)
  1192. {
  1193. DebugMsg(DM_ERROR, TEXT("MAPI returned errors.\n"));
  1194. DebugMsg(DM_ERROR, TEXT("\tVersion.......: %d"), pMapiErrors->ulVersion);
  1195. DebugMsg(DM_ERROR, TEXT("\tComponent.....: %s"), pMapiErrors->lpszComponent ?
  1196. pMapiErrors->lpszComponent :
  1197. TEXT("Not Provided"));
  1198. DebugMsg(DM_ERROR, TEXT("\tError.........: %s"), pMapiErrors->lpszError ?
  1199. pMapiErrors->lpszError :
  1200. TEXT("Not Provided"));
  1201. DebugMsg(DM_ERROR, TEXT("\tContext.......: %d"), pMapiErrors->ulContext);
  1202. DebugMsg(DM_ERROR, TEXT("\tLowLevel Error: %d\n"), pMapiErrors->ulLowLevelError);
  1203. if (bLogEvent)
  1204. {
  1205. //
  1206. // Open event log and write error?
  1207. //
  1208. }
  1209. MAPI32.FreeBuffer(pMapiErrors);
  1210. }
  1211. }
  1212. }
  1213. }
  1214. ///////////////////////////////////////////////////////////////////////////////
  1215. /* Function: CMapiSession::GetOutBoxFolder
  1216. Description: Returns the session's outbox folder pointer.
  1217. Arguments:
  1218. ppOutBoxFolder - Address of pointer variable to receive pointer value.
  1219. Returns:
  1220. Revision History:
  1221. Date Description Programmer
  1222. -------- --------------------------------------------------- ----------
  1223. 06/18/97 Initial creation. BrianAu
  1224. */
  1225. ///////////////////////////////////////////////////////////////////////////////
  1226. HRESULT
  1227. CMapiSession::GetOutBoxFolder(
  1228. LPMAPIFOLDER *ppOutBoxFolder
  1229. )
  1230. {
  1231. HRESULT hr = E_POINTER;
  1232. if (NULL != m_pOutBoxFolder && NULL != ppOutBoxFolder)
  1233. {
  1234. *ppOutBoxFolder = m_pOutBoxFolder;
  1235. (*ppOutBoxFolder)->AddRef();
  1236. hr = NO_ERROR;
  1237. }
  1238. return hr;
  1239. }
  1240. ///////////////////////////////////////////////////////////////////////////////
  1241. /* Function: CMapiSession::ResolveAddresses
  1242. Description: Resolves names in an address list.
  1243. Arguments:
  1244. pAdrList - Pointer to the address list to be resolved.
  1245. Returns:
  1246. Revision History:
  1247. Date Description Programmer
  1248. -------- --------------------------------------------------- ----------
  1249. 06/18/97 Initial creation. BrianAu
  1250. */
  1251. ///////////////////////////////////////////////////////////////////////////////
  1252. HRESULT
  1253. CMapiSession::ResolveAddresses(
  1254. LPADRLIST pAdrList
  1255. )
  1256. {
  1257. HRESULT hr;
  1258. LPADRBOOK pAdrBook = NULL;
  1259. hr = GetAddressBook(&pAdrBook);
  1260. if (SUCCEEDED(hr))
  1261. {
  1262. hr = pAdrBook->ResolveName(0, // Hwnd for UI
  1263. 0, // Flags (no UI).
  1264. NULL, // Dlg title (none).
  1265. pAdrList); // ADRLIST ptr
  1266. ReportErrorsReturned(hr);
  1267. pAdrBook->Release();
  1268. }
  1269. return hr;
  1270. }
  1271. ///////////////////////////////////////////////////////////////////////////////
  1272. /* Function: CMapiMessageBody::CMapiMessageBody
  1273. Description: Constructors.
  1274. Arguments:
  1275. rhs - Reference to source CMapiMessageBody object in copy ctor.
  1276. Returns: Nothing.
  1277. Revision History:
  1278. Date Description Programmer
  1279. -------- --------------------------------------------------- ----------
  1280. 06/18/97 Initial creation. BrianAu
  1281. */
  1282. ///////////////////////////////////////////////////////////////////////////////
  1283. CMapiMessageBody::CMapiMessageBody(
  1284. VOID
  1285. ) : m_pStg(NULL),
  1286. m_pStm(NULL)
  1287. {
  1288. CommonConstruct();
  1289. }
  1290. CMapiMessageBody::CMapiMessageBody(
  1291. const CMapiMessageBody& rhs
  1292. ) : m_pStg(NULL),
  1293. m_pStm(NULL)
  1294. {
  1295. CommonConstruct();
  1296. *this = rhs;
  1297. }
  1298. ///////////////////////////////////////////////////////////////////////////////
  1299. /* Function: CMapiMessageBody::~CMapiMessageBody
  1300. Description: Destructor.
  1301. Arguments: None.
  1302. Returns: Nothing.
  1303. Revision History:
  1304. Date Description Programmer
  1305. -------- --------------------------------------------------- ----------
  1306. 06/18/97 Initial creation. BrianAu
  1307. */
  1308. ///////////////////////////////////////////////////////////////////////////////
  1309. CMapiMessageBody::~CMapiMessageBody(
  1310. VOID
  1311. )
  1312. {
  1313. if (NULL != m_pStm)
  1314. {
  1315. m_pStm->Release();
  1316. }
  1317. if (NULL != m_pStg)
  1318. {
  1319. m_pStg->Release();
  1320. }
  1321. }
  1322. ///////////////////////////////////////////////////////////////////////////////
  1323. /* Function: CMapiMessageBody::operator =
  1324. Description: Assignment operator.
  1325. Arguments:
  1326. rhs - Reference to source CMapiMessageBody object.
  1327. Returns: Reference to *this.
  1328. Revision History:
  1329. Date Description Programmer
  1330. -------- --------------------------------------------------- ----------
  1331. 06/18/97 Initial creation. BrianAu
  1332. */
  1333. ///////////////////////////////////////////////////////////////////////////////
  1334. CMapiMessageBody&
  1335. CMapiMessageBody::operator = (
  1336. const CMapiMessageBody& rhs
  1337. )
  1338. {
  1339. if (this != &rhs)
  1340. {
  1341. if (NULL != m_pStm && NULL != rhs.m_pStm)
  1342. {
  1343. HRESULT hr;
  1344. LPSTREAM pStmClone;
  1345. //
  1346. // Create a clone of the source stream so that we don't alter
  1347. // the source's seek ptr.
  1348. //
  1349. hr = rhs.m_pStm->Clone(&pStmClone);
  1350. if (SUCCEEDED(hr))
  1351. {
  1352. ULARGE_INTEGER ulSize = {0, 0};
  1353. LARGE_INTEGER lSeek = {0, 0};
  1354. //
  1355. // Reset the source stream seek ptr to the beginnging.
  1356. //
  1357. pStmClone->Seek(lSeek, STREAM_SEEK_SET, NULL);
  1358. //
  1359. // Truncate the destination stream to clear it.
  1360. //
  1361. m_pStm->SetSize(ulSize);
  1362. //
  1363. // Copy all of the source stream to the dest stream.
  1364. //
  1365. ulSize.LowPart = 0xFFFFFFFF;
  1366. hr = pStmClone->CopyTo(m_pStm, // Destination stream.
  1367. ulSize, // Write all bytes.
  1368. NULL, // pcbRead
  1369. NULL); // pcbWritten
  1370. pStmClone->Release();
  1371. }
  1372. }
  1373. }
  1374. return *this;
  1375. }
  1376. ///////////////////////////////////////////////////////////////////////////////
  1377. /* Function: CMapiMessageBody::CommonConstruct
  1378. Description: Performs operations common to all forms of constructors.
  1379. 1. Creates Storage object.
  1380. 2. Creates Stream "MSGBODY" in storage.
  1381. Arguments: None.
  1382. Returns:
  1383. Revision History:
  1384. Date Description Programmer
  1385. -------- --------------------------------------------------- ----------
  1386. 06/18/97 Initial creation. BrianAu
  1387. */
  1388. ///////////////////////////////////////////////////////////////////////////////
  1389. HRESULT
  1390. CMapiMessageBody::CommonConstruct(
  1391. VOID
  1392. )
  1393. {
  1394. HRESULT hr;
  1395. DWORD grfMode = STGM_DIRECT | STGM_READWRITE |
  1396. STGM_CREATE | STGM_SHARE_EXCLUSIVE;
  1397. //
  1398. // Create the output doc file.
  1399. //
  1400. hr = StgCreateDocfile(NULL, // Temp file with unique name.
  1401. grfMode, // Access flags.
  1402. 0, // Reserved
  1403. &m_pStg); // Stg ptr (out)
  1404. if (SUCCEEDED(hr))
  1405. {
  1406. //
  1407. // Create the stream in the doc file.
  1408. //
  1409. hr = m_pStg->CreateStream(L"MSGBODY", // Stream name.
  1410. grfMode, // Access flags.
  1411. 0, // Reserved.
  1412. 0, // Reserved.
  1413. &m_pStm); // Stream ptr (out)
  1414. }
  1415. return hr;
  1416. }
  1417. ///////////////////////////////////////////////////////////////////////////////
  1418. /* Function: CMapiMessageBody::Append
  1419. Description: Appends text to the msg body stream. Two versions are
  1420. provided. One accepts a nul-terminated format string while the other
  1421. accepts the resource ID for a string resource. Both formats allow
  1422. variable replacement arguments for replaceable arguments in the
  1423. format strings (i.e. %1, %2 etc.)
  1424. Arguments:
  1425. hInst - Module instance handle for string/message resource.
  1426. pszFmt - Address of format string.
  1427. idFmt - ID of format resource string. May be a string or message
  1428. resource.
  1429. Returns:
  1430. Revision History:
  1431. Date Description Programmer
  1432. -------- --------------------------------------------------- ----------
  1433. 06/18/97 Initial creation. BrianAu
  1434. */
  1435. ///////////////////////////////////////////////////////////////////////////////
  1436. HRESULT
  1437. CMapiMessageBody::Append(
  1438. LPCTSTR pszFmt,
  1439. ...
  1440. )
  1441. {
  1442. HRESULT hr;
  1443. va_list args;
  1444. va_start(args, pszFmt);
  1445. hr = Append(pszFmt, &args);
  1446. va_end(args);
  1447. return hr;
  1448. }
  1449. HRESULT
  1450. CMapiMessageBody::Append(
  1451. LPCTSTR pszFmt,
  1452. va_list *pargs
  1453. )
  1454. {
  1455. HRESULT hr = E_POINTER;
  1456. if (NULL != m_pStm)
  1457. {
  1458. CString str;
  1459. if (str.Format(pszFmt, pargs))
  1460. {
  1461. hr = m_pStm->Write((LPCTSTR)str, str.LengthBytes(), NULL);
  1462. }
  1463. }
  1464. return hr;
  1465. }
  1466. HRESULT
  1467. CMapiMessageBody::Append(
  1468. HINSTANCE hInst,
  1469. UINT idFmt,
  1470. ...
  1471. )
  1472. {
  1473. HRESULT hr;
  1474. va_list(args);
  1475. va_start(args, idFmt);
  1476. hr = Append(hInst, idFmt, &args);
  1477. va_end(args);
  1478. return hr;
  1479. }
  1480. HRESULT
  1481. CMapiMessageBody::Append(
  1482. HINSTANCE hInst,
  1483. UINT idFmt,
  1484. va_list *pargs
  1485. )
  1486. {
  1487. HRESULT hr = E_POINTER;
  1488. if (NULL != m_pStm)
  1489. {
  1490. CString str;
  1491. if (str.Format(hInst, idFmt, pargs))
  1492. {
  1493. hr = m_pStm->Write((LPCTSTR)str, str.LengthBytes(), NULL);
  1494. }
  1495. }
  1496. return hr;
  1497. }
  1498. ///////////////////////////////////////////////////////////////////////////////
  1499. /* Function: CMapiMessage::CMapiMessage
  1500. Description: Constructors.
  1501. Arguments:
  1502. pFolder - Address of LPMAPIFOLDER object in which the message is
  1503. to be created.
  1504. body - Reference to a CMapiMessageBody object containing text for the
  1505. body of the message.
  1506. pszSubject [optional] - Address of message subject line string.
  1507. Returns: Nothing.
  1508. Revision History:
  1509. Date Description Programmer
  1510. -------- --------------------------------------------------- ----------
  1511. 06/18/97 Initial creation. BrianAu
  1512. */
  1513. ///////////////////////////////////////////////////////////////////////////////
  1514. CMapiMessage::CMapiMessage(
  1515. LPMAPIFOLDER pFolder
  1516. ) : m_pMsg(NULL)
  1517. {
  1518. CommonConstruct(pFolder);
  1519. }
  1520. CMapiMessage::CMapiMessage(
  1521. LPMAPIFOLDER pFolder,
  1522. CMapiMessageBody& body,
  1523. LPCTSTR pszSubject /* optional */
  1524. ) : m_pMsg(NULL),
  1525. m_body(body)
  1526. {
  1527. CommonConstruct(pFolder);
  1528. if (NULL != pszSubject)
  1529. {
  1530. SetSubject(pszSubject);
  1531. }
  1532. }
  1533. ///////////////////////////////////////////////////////////////////////////////
  1534. /* Function: CMapiMessage::~CMapiMessage
  1535. Description: Destructor.
  1536. Arguments: None.
  1537. Returns:
  1538. Revision History:
  1539. Date Description Programmer
  1540. -------- --------------------------------------------------- ----------
  1541. 06/18/97 Initial creation. BrianAu
  1542. */
  1543. ///////////////////////////////////////////////////////////////////////////////
  1544. CMapiMessage::~CMapiMessage(
  1545. VOID
  1546. )
  1547. {
  1548. if (NULL != m_pMsg)
  1549. {
  1550. m_pMsg->Release();
  1551. }
  1552. }
  1553. ///////////////////////////////////////////////////////////////////////////////
  1554. /* Function: CMapiMessage::CommonConstruct
  1555. Description: Performs operations common to all forms of constructors.
  1556. 1. Creates the MAPI message object.
  1557. 2. Sets the DELETE_AFTER_SUBMIT property (common to all messages).
  1558. Arguments:
  1559. pFolder - Address of LPMAPIFOLDER object in which the message is
  1560. to be created.
  1561. Returns:
  1562. Revision History:
  1563. Date Description Programmer
  1564. -------- --------------------------------------------------- ----------
  1565. 06/18/97 Initial creation. BrianAu
  1566. */
  1567. ///////////////////////////////////////////////////////////////////////////////
  1568. HRESULT
  1569. CMapiMessage::CommonConstruct(
  1570. LPMAPIFOLDER pFolder
  1571. )
  1572. {
  1573. HRESULT hr = E_POINTER;
  1574. if (NULL != pFolder)
  1575. {
  1576. hr = pFolder->CreateMessage(NULL, 0, &m_pMsg);
  1577. if (SUCCEEDED(hr))
  1578. {
  1579. //
  1580. // Don't want sent message hanging around in users's outbox.
  1581. //
  1582. SPropValue rgProp[1];
  1583. rgProp[0].ulPropTag = PR_DELETE_AFTER_SUBMIT;
  1584. rgProp[0].Value.b = TRUE;
  1585. hr = m_pMsg->SetProps(ARRAYSIZE(rgProp), rgProp, NULL);
  1586. }
  1587. }
  1588. return hr;
  1589. }
  1590. HRESULT
  1591. CMapiMessage::SetProps(
  1592. ULONG cValues,
  1593. LPSPropValue lpPropArray,
  1594. LPSPropProblemArray *lppProblems
  1595. )
  1596. {
  1597. HRESULT hr = E_UNEXPECTED;
  1598. if (NULL != m_pMsg)
  1599. {
  1600. hr = m_pMsg->SetProps(cValues, lpPropArray, lppProblems);
  1601. }
  1602. return hr;
  1603. }
  1604. HRESULT
  1605. CMapiMessage::SaveChanges(
  1606. ULONG ulFlags
  1607. )
  1608. {
  1609. HRESULT hr = E_UNEXPECTED;
  1610. if (NULL != m_pMsg)
  1611. {
  1612. hr = m_pMsg->SaveChanges(ulFlags);
  1613. }
  1614. return hr;
  1615. }
  1616. ///////////////////////////////////////////////////////////////////////////////
  1617. /* Function: CMapiMessage::SetSubject
  1618. Description: Sets the PR_SUBJECT property of the message.
  1619. Arguments:
  1620. pszSubject - Address of new subject string.
  1621. Returns:
  1622. Revision History:
  1623. Date Description Programmer
  1624. -------- --------------------------------------------------- ----------
  1625. 06/18/97 Initial creation. BrianAu
  1626. */
  1627. ///////////////////////////////////////////////////////////////////////////////
  1628. HRESULT
  1629. CMapiMessage::SetSubject(
  1630. LPCTSTR pszSubject
  1631. )
  1632. {
  1633. HRESULT hr = E_POINTER;
  1634. if (NULL != m_pMsg)
  1635. {
  1636. //
  1637. // Set the msg subject text property.
  1638. //
  1639. SPropValue spvProp;
  1640. spvProp.ulPropTag = PR_SUBJECT;
  1641. spvProp.Value.LPSZ = (LPTSTR)pszSubject;
  1642. hr = m_pMsg->SetProps(1, &spvProp, NULL);
  1643. }
  1644. return hr;
  1645. }
  1646. ///////////////////////////////////////////////////////////////////////////////
  1647. /* Function: CMapiMessage::SetRecipients
  1648. Description: Sets the recipients for the message. It is assumed that
  1649. the recipients in pAdrList have been resolved.
  1650. Arguments:
  1651. pAdrList - Address of MAPI address list containing resolved addresses.
  1652. Returns:
  1653. Revision History:
  1654. Date Description Programmer
  1655. -------- --------------------------------------------------- ----------
  1656. 06/18/97 Initial creation. BrianAu
  1657. */
  1658. ///////////////////////////////////////////////////////////////////////////////
  1659. HRESULT
  1660. CMapiMessage::SetRecipients(
  1661. LPADRLIST pAdrList
  1662. )
  1663. {
  1664. HRESULT hr = E_POINTER;
  1665. if (NULL != m_pMsg)
  1666. {
  1667. hr = m_pMsg->ModifyRecipients(0, pAdrList);
  1668. }
  1669. return hr;
  1670. }
  1671. ///////////////////////////////////////////////////////////////////////////////
  1672. /* Function: CMapiMessage::Send
  1673. Description: Sends the message to a list of recipients.
  1674. Arguments:
  1675. pAdrList [optional] - Address of MAPI address list containing
  1676. resolved addresses. If this argument is NULL, the caller must
  1677. call SetRecipients before calling Send.
  1678. Returns:
  1679. Revision History:
  1680. Date Description Programmer
  1681. -------- --------------------------------------------------- ----------
  1682. 06/18/97 Initial creation. BrianAu
  1683. */
  1684. ///////////////////////////////////////////////////////////////////////////////
  1685. HRESULT
  1686. CMapiMessage::Send(
  1687. LPADRLIST pAdrList /* optional */
  1688. )
  1689. {
  1690. HRESULT hr = E_POINTER;
  1691. if (NULL != m_pMsg)
  1692. {
  1693. hr = NO_ERROR;
  1694. if (NULL != pAdrList)
  1695. {
  1696. //
  1697. // If there's an address list, set the recipients.
  1698. // If not, the caller must call SetRecipients before calling Send().
  1699. // Otherwise, there will be no recipients to send it to.
  1700. //
  1701. hr = SetRecipients(pAdrList);
  1702. }
  1703. if (SUCCEEDED(hr))
  1704. {
  1705. LPSTREAM pPropStream;
  1706. hr = m_pMsg->OpenProperty(PR_BODY,
  1707. &IID_IStream,
  1708. STGM_READWRITE | STGM_DIRECT,
  1709. MAPI_CREATE | MAPI_MODIFY,
  1710. (LPUNKNOWN *)&pPropStream);
  1711. if (S_OK == hr)
  1712. {
  1713. LPSTREAM pMsgBodyStm = (LPSTREAM)m_body;
  1714. LPSTREAM pMsgBodyStmClone;
  1715. //
  1716. // Clone the body stream so that we don't alter it's seek ptr.
  1717. //
  1718. hr = pMsgBodyStm->Clone(&pMsgBodyStmClone);
  1719. if (SUCCEEDED(hr))
  1720. {
  1721. ULARGE_INTEGER ulSize = {0xFFFFFFFF, 0};
  1722. LARGE_INTEGER lSeek = {0, 0};
  1723. //
  1724. // Copy the msg body stream to the PR_BODY property.
  1725. //
  1726. pMsgBodyStmClone->Seek(lSeek, STREAM_SEEK_SET, NULL);
  1727. pMsgBodyStmClone->CopyTo(pPropStream, ulSize, NULL, NULL);
  1728. pPropStream->Commit(STGC_DEFAULT);
  1729. //
  1730. // Release temp streams.
  1731. //
  1732. pPropStream->Release();
  1733. pMsgBodyStmClone->Release();
  1734. //
  1735. // Send it!
  1736. // Note: Calling SaveChanges() is not required if the message
  1737. // is being sent immediately.
  1738. //
  1739. hr = m_pMsg->SubmitMessage(FORCE_SUBMIT);
  1740. }
  1741. }
  1742. }
  1743. }
  1744. return hr;
  1745. }
  1746. ///////////////////////////////////////////////////////////////////////////////
  1747. /* Function: CMapiMessage::Append
  1748. Description: Appends text to the msg body stream. Two versions are
  1749. provided. One accepts a nul-terminated format string while the other
  1750. accepts the resource ID for a string resource. Both formats allow
  1751. variable replacement arguments for replaceable arguments in the
  1752. format strings (i.e. %1, %2 etc.)
  1753. Arguments:
  1754. hInst - Module instance handle for string/message resource.
  1755. pszFmt - Address of format string.
  1756. idFmt - ID of format resource string. May be a string or message
  1757. resource.
  1758. Returns:
  1759. Revision History:
  1760. Date Description Programmer
  1761. -------- --------------------------------------------------- ----------
  1762. 06/18/97 Initial creation. BrianAu
  1763. */
  1764. ///////////////////////////////////////////////////////////////////////////////
  1765. HRESULT
  1766. CMapiMessage::Append(
  1767. LPCTSTR pszFmt,
  1768. ...
  1769. )
  1770. {
  1771. HRESULT hr;
  1772. va_list args;
  1773. va_start(args, pszFmt);
  1774. hr = m_body.Append(pszFmt, &args);
  1775. va_end(args);
  1776. return hr;
  1777. }
  1778. HRESULT
  1779. CMapiMessage::Append(
  1780. HINSTANCE hInst,
  1781. UINT idFmt,
  1782. ...
  1783. )
  1784. {
  1785. HRESULT hr;
  1786. va_list(args);
  1787. va_start(args, idFmt);
  1788. hr = m_body.Append(hInst, idFmt, &args);
  1789. va_end(args);
  1790. return hr;
  1791. }
  1792. //
  1793. // Static members of class MAPI.
  1794. //
  1795. LONG MAPI::m_cLoadCount;
  1796. HINSTANCE MAPI::m_hmodMAPI;
  1797. LPMAPIINITIALIZE MAPI::m_pfnInitialize;
  1798. LPMAPILOGONEX MAPI::m_pfnLogonEx;
  1799. LPMAPIUNINITIALIZE MAPI::m_pfnUninitialize;
  1800. LPMAPIALLOCATEBUFFER MAPI::m_pfnAllocateBuffer;
  1801. LPMAPIALLOCATEMORE MAPI::m_pfnAllocateMore;
  1802. LPMAPIFREEBUFFER MAPI::m_pfnFreeBuffer;
  1803. LPMAPIHRQUERYALLROWS MAPI::m_pfnHrQueryAllRows;
  1804. LPMAPIFREEPADRLIST MAPI::m_pfnFreePadrlist;
  1805. LPMAPIFREEPROWS MAPI::m_pfnFreeProws;
  1806. ///////////////////////////////////////////////////////////////////////////////
  1807. /* Function: MAPI::MAPI
  1808. Description: Constructor.
  1809. Arguments: None.
  1810. Returns:
  1811. Revision History:
  1812. Date Description Programmer
  1813. -------- --------------------------------------------------- ----------
  1814. 06/22/97 Initial creation. BrianAu
  1815. */
  1816. ///////////////////////////////////////////////////////////////////////////////
  1817. MAPI::MAPI(
  1818. VOID
  1819. )
  1820. {
  1821. }
  1822. ///////////////////////////////////////////////////////////////////////////////
  1823. /* Function: MAPI::~MAPI
  1824. Description: Destructor. Ensures MAPI32.DLL is unloaded.
  1825. Arguments: None.
  1826. Returns:
  1827. Revision History:
  1828. Date Description Programmer
  1829. -------- --------------------------------------------------- ----------
  1830. 06/22/97 Initial creation. BrianAu
  1831. */
  1832. ///////////////////////////////////////////////////////////////////////////////
  1833. MAPI::~MAPI(
  1834. VOID
  1835. )
  1836. {
  1837. //
  1838. // m_cLoadCount should be 0 at this point if calls to Load() and
  1839. // Unload() are balanced.
  1840. //
  1841. ASSERT(0 == m_cLoadCount);
  1842. if (0 < m_cLoadCount)
  1843. {
  1844. //
  1845. // Calls to Load() and Unload() are not balanced due to programmer
  1846. // error or maybe an exception preventing a call to Unload().
  1847. // This will force Unload to call FreeLibrary().
  1848. //
  1849. m_cLoadCount = 1;
  1850. }
  1851. Unload();
  1852. }
  1853. ///////////////////////////////////////////////////////////////////////////////
  1854. /* Function: MAPI::Load
  1855. Description: Load MAPI32.DLL and call GetProcAddress for all of the
  1856. MAPI32 functions we're interested in using. Maintains a reference
  1857. count so redundant calls to LoadLibrary are avoided.
  1858. Arguments: None.
  1859. Returns:
  1860. Revision History:
  1861. Date Description Programmer
  1862. -------- --------------------------------------------------- ----------
  1863. 06/22/97 Initial creation. BrianAu
  1864. */
  1865. ///////////////////////////////////////////////////////////////////////////////
  1866. HRESULT
  1867. MAPI::Load(
  1868. VOID
  1869. )
  1870. {
  1871. Assert(0 <= m_cLoadCount);
  1872. if (0 == m_cLoadCount++)
  1873. {
  1874. m_hmodMAPI = ::LoadLibrary(TEXT("MAPI32.DLL"));
  1875. if (NULL != m_hmodMAPI)
  1876. {
  1877. m_pfnInitialize = (LPMAPIINITIALIZE) ::GetProcAddress(m_hmodMAPI, "MAPIInitialize");
  1878. m_pfnLogonEx = (LPMAPILOGONEX) ::GetProcAddress(m_hmodMAPI, "MAPILogonEx");
  1879. m_pfnUninitialize = (LPMAPIUNINITIALIZE) ::GetProcAddress(m_hmodMAPI, "MAPIUninitialize");
  1880. m_pfnAllocateBuffer = (LPMAPIALLOCATEBUFFER)::GetProcAddress(m_hmodMAPI, "MAPIAllocateBuffer");
  1881. m_pfnAllocateMore = (LPMAPIALLOCATEMORE) ::GetProcAddress(m_hmodMAPI, "MAPIAllocateMore");
  1882. m_pfnFreeBuffer = (LPMAPIFREEBUFFER) ::GetProcAddress(m_hmodMAPI, "MAPIFreeBuffer");
  1883. m_pfnHrQueryAllRows = (LPMAPIHRQUERYALLROWS)::GetProcAddress(m_hmodMAPI, "HrQueryAllRows@24");
  1884. m_pfnFreePadrlist = (LPMAPIFREEPADRLIST) ::GetProcAddress(m_hmodMAPI, "FreePadrlist@4");
  1885. m_pfnFreeProws = (LPMAPIFREEPROWS) ::GetProcAddress(m_hmodMAPI, "FreeProws@4");
  1886. }
  1887. }
  1888. return (NULL != m_hmodMAPI) ? NO_ERROR : E_FAIL;
  1889. }
  1890. ///////////////////////////////////////////////////////////////////////////////
  1891. /* Function: MAPI::Unload
  1892. Description: Unloads MAPI32.DLL if the reference count drops to 0. If
  1893. the library is unloaded, all of the function pointers are
  1894. set to NULL.
  1895. Arguments: None.
  1896. Returns:
  1897. Revision History:
  1898. Date Description Programmer
  1899. -------- --------------------------------------------------- ----------
  1900. 06/22/97 Initial creation. BrianAu
  1901. */
  1902. ///////////////////////////////////////////////////////////////////////////////
  1903. VOID
  1904. MAPI::Unload(
  1905. VOID
  1906. )
  1907. {
  1908. ASSERT(0 < m_cLoadCount);
  1909. if (0 == --m_cLoadCount)
  1910. {
  1911. if (NULL != m_hmodMAPI)
  1912. {
  1913. ::FreeLibrary(m_hmodMAPI);
  1914. m_hmodMAPI = NULL;
  1915. }
  1916. m_pfnInitialize = NULL;
  1917. m_pfnLogonEx = NULL;
  1918. m_pfnUninitialize = NULL;
  1919. m_pfnAllocateBuffer = NULL;
  1920. m_pfnAllocateMore = NULL;
  1921. m_pfnFreeBuffer = NULL;
  1922. m_pfnHrQueryAllRows = NULL;
  1923. m_pfnFreePadrlist = NULL;
  1924. m_pfnFreeProws = NULL;
  1925. }
  1926. }
  1927. ///////////////////////////////////////////////////////////////////////////////
  1928. // The remaining MAPI::XXXX functions are merely simple wrappers around the
  1929. // corresponding functions in MAPI32.DLL.
  1930. // See the MAPI SDK for information concerning their use.
  1931. ///////////////////////////////////////////////////////////////////////////////
  1932. HRESULT
  1933. MAPI::LogonEx(
  1934. ULONG ulUIParam,
  1935. LPTSTR lpszProfileName,
  1936. LPTSTR lpszPassword,
  1937. FLAGS flFlags,
  1938. LPMAPISESSION FAR * lppSession
  1939. )
  1940. {
  1941. ASSERT(NULL != m_pfnLogonEx);
  1942. if (NULL != m_pfnLogonEx)
  1943. return (*m_pfnLogonEx)(ulUIParam, lpszProfileName, lpszPassword, flFlags, lppSession);
  1944. else
  1945. return E_POINTER;
  1946. }
  1947. HRESULT
  1948. MAPI::Initialize(
  1949. LPVOID lpMapiInit
  1950. )
  1951. {
  1952. ASSERT(NULL != m_pfnInitialize);
  1953. if (NULL != m_pfnInitialize)
  1954. return (*m_pfnInitialize)(lpMapiInit);
  1955. else
  1956. return E_POINTER;
  1957. }
  1958. VOID
  1959. MAPI::Uninitialize(
  1960. VOID
  1961. )
  1962. {
  1963. ASSERT(NULL != m_pfnUninitialize);
  1964. if (NULL != m_pfnUninitialize)
  1965. (*m_pfnUninitialize)();
  1966. }
  1967. SCODE
  1968. MAPI::AllocateBuffer(
  1969. ULONG cbSize,
  1970. LPVOID FAR * lppBuffer
  1971. )
  1972. {
  1973. ASSERT(NULL != m_pfnAllocateBuffer);
  1974. if (NULL != m_pfnAllocateBuffer)
  1975. return (*m_pfnAllocateBuffer)(cbSize, lppBuffer);
  1976. else
  1977. return E_POINTER;
  1978. }
  1979. SCODE
  1980. MAPI::AllocateMore(
  1981. ULONG cbSize,
  1982. LPVOID lpObject,
  1983. LPVOID FAR * lppBuffer
  1984. )
  1985. {
  1986. ASSERT(NULL != m_pfnAllocateMore);
  1987. if (NULL != m_pfnAllocateMore)
  1988. return (*m_pfnAllocateMore)(cbSize, lpObject, lppBuffer);
  1989. else
  1990. return E_POINTER;
  1991. }
  1992. ULONG
  1993. MAPI::FreeBuffer(
  1994. LPVOID lpBuffer
  1995. )
  1996. {
  1997. ASSERT(NULL != m_pfnFreeBuffer);
  1998. if (NULL != m_pfnFreeBuffer)
  1999. return (*m_pfnFreeBuffer)(lpBuffer);
  2000. else
  2001. return (ULONG)E_POINTER;
  2002. }
  2003. HRESULT
  2004. MAPI::HrQueryAllRows(
  2005. LPMAPITABLE lpTable,
  2006. LPSPropTagArray lpPropTags,
  2007. LPSRestriction lpRestriction,
  2008. LPSSortOrderSet lpSortOrderSet,
  2009. LONG crowsMax,
  2010. LPSRowSet FAR *lppRows
  2011. )
  2012. {
  2013. ASSERT(NULL != m_pfnHrQueryAllRows);
  2014. if (NULL != m_pfnHrQueryAllRows)
  2015. return (*m_pfnHrQueryAllRows)(lpTable,
  2016. lpPropTags,
  2017. lpRestriction,
  2018. lpSortOrderSet,
  2019. crowsMax,
  2020. lppRows);
  2021. else
  2022. return E_POINTER;
  2023. }
  2024. VOID
  2025. MAPI::FreePadrlist(
  2026. LPADRLIST lpAdrList
  2027. )
  2028. {
  2029. ASSERT(NULL != m_pfnFreePadrlist);
  2030. if (NULL != m_pfnFreePadrlist)
  2031. (*m_pfnFreePadrlist)(lpAdrList);
  2032. }
  2033. VOID
  2034. MAPI::FreeProws(
  2035. LPSRowSet lpRows
  2036. )
  2037. {
  2038. ASSERT(NULL != m_pfnFreeProws);
  2039. if (NULL != m_pfnFreeProws)
  2040. (*m_pfnFreeProws)(lpRows);
  2041. }