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.

1563 lines
52 KiB

  1. /***********************************************************************
  2. *
  3. * MUTIL.C
  4. *
  5. * Windows AB Mapi Utility functions
  6. *
  7. * Copyright 1992 - 1996 Microsoft Corporation. All Rights Reserved.
  8. *
  9. * Revision History:
  10. *
  11. * When Who What
  12. * -------- ------------------ ---------------------------------------
  13. * 11.13.95 Bruce Kelley Created
  14. *
  15. ***********************************************************************/
  16. //#include <_apipch.h>
  17. #include <wab.h>
  18. #include "mutil.h"
  19. #define _WAB_MUTIL_C
  20. #ifdef DEBUG
  21. PUCHAR PropTagName(ULONG ulPropTag);
  22. const TCHAR szNULL[] = "";
  23. #endif
  24. #if defined (_MIPS_) || defined (_ALPHA_) || defined (_PPC_)
  25. #define AlignProp(_cb) Align8(_cb)
  26. #else
  27. #define AlignProp(_cb) (_cb)
  28. #endif
  29. #define ALIGN_RISC 8
  30. #define ALIGN_X86 1
  31. //#define LPULONG unsigned long*
  32. extern LPWABOBJECT lpWABObject; //Global handle to session
  33. /***************************************************************************
  34. Name : RemoveDuplicateProps
  35. Purpose : Removes duplicate properties from an SPropValue array.
  36. Parameters: lpcProps -> input/output: number of properties in lpProps
  37. lpProps -> input/output: prop array to remove dups from.
  38. Returns : none
  39. Comment : Gives preference to earlier properties.
  40. ***************************************************************************/
  41. void RemoveDuplicateProps(LPULONG lpcProps, LPSPropValue lpProps) {
  42. ULONG i, j;
  43. ULONG cProps = *lpcProps;
  44. for (i = 0; i < cProps; i++) {
  45. for (j = i + 1; j < cProps; j++) {
  46. if (PROP_ID(lpProps[i].ulPropTag) == PROP_ID(lpProps[j].ulPropTag)) {
  47. // If j is PT_ERROR, use i, else use j.
  48. if (lpProps[j].ulPropTag != PR_NULL) {
  49. if (PROP_TYPE(lpProps[j].ulPropTag) != PT_ERROR) {
  50. // Replace i's propvalue with j's. Nuke j's entry.
  51. lpProps[i] = lpProps[j];
  52. }
  53. lpProps[j].ulPropTag = PR_NULL;
  54. }
  55. }
  56. }
  57. }
  58. // Now, squeeze out all the PR_NULLs.
  59. for (i = 0; i < cProps; i++) {
  60. if (lpProps[i].ulPropTag == PR_NULL) {
  61. // Move the array down
  62. cProps--;
  63. if (cProps > i) {
  64. MoveMemory(&lpProps[i], // dest
  65. &lpProps[i + 1], // src
  66. (cProps - i) * sizeof(SPropValue));
  67. i--; // Redo this row... it's new!
  68. }
  69. }
  70. }
  71. *lpcProps = cProps;
  72. }
  73. /***************************************************************************
  74. Name : ScMergePropValues
  75. Purpose : Merge two SPropValue arrays
  76. Parameters: cProps1 = count of properties in lpSource1
  77. lpSource1 -> 1st source SPropValue array
  78. cProps2 = count of properties in lpSource2
  79. lpSource2 -> 2nd source SPropValue array
  80. lpcPropsDest -> returned number of properties
  81. lppDest -> Returned destination SPropValue array. This
  82. buffer will be allocated using AllocateBuffer and is the
  83. responsibility of the caller on return.
  84. Returns : SCODE
  85. Comment : Gives preference to Source2 over Source1 in case of collisions.
  86. ***************************************************************************/
  87. SCODE ScMergePropValues(ULONG cProps1, LPSPropValue lpSource1,
  88. ULONG cProps2, LPSPropValue lpSource2, LPULONG lpcPropsDest, LPSPropValue * lppDest) {
  89. ULONG cb1, cb2, cb, cProps, i, cbT, cbMV;
  90. SCODE sc = SUCCESS_SUCCESS;
  91. LPSPropValue pprop, lpDestReturn = NULL;
  92. __UPV upv;
  93. LPBYTE pb; // moving pointer for property data
  94. int iValue;
  95. DebugProperties(lpSource1, cProps1, "Source 1");
  96. DebugProperties(lpSource2, cProps2, "Source 2");
  97. // How big do I need to make the destination buffer?
  98. // Just add the sizes of the two together to get an upper limit.
  99. // This is close enough, though not optimal (consider overlap).
  100. if (sc = ScCountProps(cProps1, lpSource1, &cb1)) {
  101. goto exit;
  102. }
  103. if (sc = ScCountProps(cProps2, lpSource2, &cb2)) {
  104. goto exit;
  105. }
  106. cProps = cProps1 + cProps2;
  107. cb = cb1 + cb2;
  108. if (sc = MAPIAllocateBuffer(cb, (void **)&lpDestReturn)) {
  109. goto exit;
  110. }
  111. // MAPISetBufferName(lpDestReturn, "WAB: lpDestReturn in ScMergePropValues");
  112. // Copy each source property array to the destination
  113. memcpy(lpDestReturn, lpSource1, cProps1 * sizeof(SPropValue));
  114. memcpy(&lpDestReturn[cProps1], lpSource2, cProps2 * sizeof(SPropValue));
  115. // Remove duplicates
  116. RemoveDuplicateProps(&cProps, lpDestReturn);
  117. // Fixup the pointers.
  118. pb = (LPBYTE)&(lpDestReturn[cProps]); // point past the prop array
  119. for (pprop = lpDestReturn, i = cProps; i--; ++pprop) {
  120. // Tricky: common code after the switch increments pb and cb
  121. // by the amount copied. If no increment is necessary, the case
  122. // uses 'continue' rather than 'break' to exit the switch, thus
  123. // skipping the increment -- AND any other code which may be
  124. // added after the switch.
  125. switch (PROP_TYPE(pprop->ulPropTag)) {
  126. default:
  127. DebugTrace("ScMergePropValues: Unknown property type %s (index %d)\n",
  128. SzDecodeUlPropTag(pprop->ulPropTag), pprop - lpDestReturn);
  129. sc = E_INVALIDARG;
  130. goto exit;
  131. case PT_I2:
  132. case PT_LONG:
  133. case PT_R4:
  134. case PT_APPTIME:
  135. case PT_DOUBLE:
  136. case PT_BOOLEAN:
  137. case PT_CURRENCY:
  138. case PT_SYSTIME:
  139. case PT_I8:
  140. case PT_ERROR:
  141. case PT_OBJECT:
  142. case PT_NULL:
  143. continue; // nothing to add
  144. case PT_CLSID:
  145. cbT = sizeof(GUID);
  146. MemCopy(pb, (LPBYTE)pprop->Value.lpguid, cbT);
  147. pprop->Value.lpguid = (LPGUID)pb;
  148. break;
  149. case PT_BINARY:
  150. cbT = (UINT)pprop->Value.bin.cb;
  151. MemCopy(pb, pprop->Value.bin.lpb, cbT);
  152. pprop->Value.bin.lpb = pb;
  153. break;
  154. case PT_STRING8:
  155. cbT = lstrlenA( pprop->Value.lpszA ) + 1;
  156. MemCopy(pb, pprop->Value.lpszA, cbT);
  157. pprop->Value.lpszA = (LPSTR)pb;
  158. break;
  159. case PT_UNICODE:
  160. cbT = (lstrlenW( pprop->Value.lpszW ) + 1) * sizeof(WCHAR);
  161. MemCopy(pb, pprop->Value.lpszW, cbT);
  162. pprop->Value.lpszW = (LPWSTR)pb;
  163. break;
  164. case PT_MV_I2:
  165. cbT = (UINT)pprop->Value.MVi.cValues * sizeof(short int);
  166. MemCopy(pb, pprop->Value.MVi.lpi, cbT);
  167. pprop->Value.MVi.lpi = (short int FAR *)pb;
  168. break;
  169. case PT_MV_LONG:
  170. cbT = (UINT)pprop->Value.MVl.cValues * sizeof(LONG);
  171. MemCopy(pb, pprop->Value.MVl.lpl, cbT);
  172. pprop->Value.MVl.lpl = (LONG FAR *)pb;
  173. break;
  174. case PT_MV_R4:
  175. cbT = (UINT)pprop->Value.MVflt.cValues * sizeof(float);
  176. MemCopy(pb, pprop->Value.MVflt.lpflt, cbT);
  177. pprop->Value.MVflt.lpflt = (float FAR *)pb;
  178. break;
  179. case PT_MV_APPTIME:
  180. cbT = (UINT)pprop->Value.MVat.cValues * sizeof(double);
  181. MemCopy(pb, pprop->Value.MVat.lpat, cbT);
  182. pprop->Value.MVat.lpat = (double FAR *)pb;
  183. break;
  184. case PT_MV_DOUBLE:
  185. cbT = (UINT)pprop->Value.MVdbl.cValues * sizeof(double);
  186. MemCopy(pb, pprop->Value.MVdbl.lpdbl, cbT);
  187. pprop->Value.MVdbl.lpdbl = (double FAR *)pb;
  188. break;
  189. case PT_MV_CURRENCY:
  190. cbT = (UINT)pprop->Value.MVcur.cValues * sizeof(CURRENCY);
  191. MemCopy(pb, pprop->Value.MVcur.lpcur, cbT);
  192. pprop->Value.MVcur.lpcur = (CURRENCY FAR *)pb;
  193. break;
  194. case PT_MV_SYSTIME:
  195. cbT = (UINT)pprop->Value.MVft.cValues * sizeof(FILETIME);
  196. MemCopy(pb, pprop->Value.MVft.lpft, cbT);
  197. pprop->Value.MVft.lpft = (FILETIME FAR *)pb;
  198. break;
  199. case PT_MV_CLSID:
  200. cbT = (UINT)pprop->Value.MVguid.cValues * sizeof(GUID);
  201. MemCopy(pb, pprop->Value.MVguid.lpguid, cbT);
  202. pprop->Value.MVguid.lpguid = (GUID FAR *)pb;
  203. break;
  204. case PT_MV_I8:
  205. cbT = (UINT)pprop->Value.MVli.cValues * sizeof(LARGE_INTEGER);
  206. MemCopy(pb, pprop->Value.MVli.lpli, cbT);
  207. pprop->Value.MVli.lpli = (LARGE_INTEGER FAR *)pb;
  208. break;
  209. case PT_MV_BINARY:
  210. upv = pprop->Value;
  211. pprop->Value.MVbin.lpbin = (SBinary *)pb;
  212. cbMV = upv.MVbin.cValues * sizeof(SBinary);
  213. pb += cbMV;
  214. cb += cbMV;
  215. for (iValue = 0; (ULONG)iValue < upv.MVbin.cValues; iValue++) {
  216. pprop->Value.MVbin.lpbin[iValue].lpb = pb;
  217. cbT = (UINT)upv.MVbin.lpbin[iValue].cb;
  218. pprop->Value.MVbin.lpbin[iValue].cb = (ULONG)cbT;
  219. MemCopy(pb, upv.MVbin.lpbin[iValue].lpb, cbT);
  220. cbT = AlignProp(cbT);
  221. cb += cbT;
  222. pb += cbT;
  223. }
  224. continue; // already updated, don't do it again
  225. case PT_MV_STRING8:
  226. upv = pprop->Value;
  227. pprop->Value.MVszA.lppszA = (LPSTR *)pb;
  228. cbMV = upv.MVszA.cValues * sizeof(LPSTR);
  229. pb += cbMV;
  230. cb += cbMV;
  231. for (iValue = 0; (ULONG)iValue < upv.MVszA.cValues; iValue++) {
  232. pprop->Value.MVszA.lppszA[iValue] = (LPSTR)pb;
  233. cbT = lstrlenA(upv.MVszA.lppszA[iValue]) + 1;
  234. MemCopy(pb, upv.MVszA.lppszA[iValue], cbT);
  235. pb += cbT;
  236. cb += cbT;
  237. }
  238. cbT = (UINT)AlignProp(cb);
  239. pb += cbT - cb;
  240. cb = cbT;
  241. continue; // already updated, don't do it again
  242. case PT_MV_UNICODE:
  243. upv = pprop->Value;
  244. pprop->Value.MVszW.lppszW = (LPWSTR *)pb;
  245. cbMV = upv.MVszW.cValues * sizeof(LPWSTR);
  246. pb += cbMV;
  247. cb += cbMV;
  248. for (iValue = 0; (ULONG)iValue < upv.MVszW.cValues; iValue++) {
  249. pprop->Value.MVszW.lppszW[iValue] = (LPWSTR)pb;
  250. cbT = (lstrlenW(upv.MVszW.lppszW[iValue]) + 1)
  251. * sizeof(WCHAR);
  252. MemCopy(pb, upv.MVszW.lppszW[iValue], cbT);
  253. pb += cbT;
  254. cb += cbT;
  255. }
  256. cbT = (UINT)AlignProp(cb);
  257. pb += cbT - cb;
  258. cb = cbT;
  259. continue; // already updated, don't do it again
  260. }
  261. // Advance pointer and total count by the amount copied
  262. cbT = AlignProp(cbT);
  263. pb += cbT;
  264. cb += cbT;
  265. }
  266. exit:
  267. // In case of error, free the memory.
  268. if (sc && lpDestReturn) {
  269. MAPIFreeBuffer(lpDestReturn);
  270. *lppDest = NULL;
  271. } else if (lpDestReturn) {
  272. *lppDest = lpDestReturn;
  273. *lpcPropsDest = cProps;
  274. DebugProperties(lpDestReturn, cProps, "Destination");
  275. } // else just return the error
  276. return(sc);
  277. }
  278. #ifdef OLD_STUFF
  279. /***************************************************************************
  280. Name : AddPropToMVPBin
  281. Purpose : Add a property to a multi-valued binary property in a prop array
  282. Parameters: lpaProps -> array of properties
  283. cProps = number of props in lpaProps
  284. uPropTag = property tag for MVP
  285. index = index in lpaProps of MVP
  286. lpNew -> new data
  287. cbNew = size of lpbNew
  288. Returns : HRESULT
  289. Comment : Find the size of the existing MVP
  290. Add in the size of the new entry
  291. allocate new space
  292. copy old to new
  293. free old
  294. copy new entry
  295. point prop array lpbin the new space
  296. increment cValues
  297. Note: The new MVP memory is AllocMore'd onto the lpaProps
  298. allocation. We will unlink the pointer to the old MVP array,
  299. but this will be cleaned up when the prop array is freed.
  300. ***************************************************************************/
  301. HRESULT AddPropToMVPBin(
  302. LPSPropValue lpaProps,
  303. DWORD cProps,
  304. DWORD index,
  305. LPVOID lpNew,
  306. ULONG cbNew) {
  307. SBinaryArray * lprgsbOld = NULL;
  308. SBinaryArray * lprgsbNew = NULL;
  309. LPSBinary lpsbOld = NULL;
  310. LPSBinary lpsbNew = NULL;
  311. ULONG cbMVP = 0;
  312. ULONG cExisting = 0;
  313. LPBYTE lpNewTemp = NULL;
  314. HRESULT hResult = hrSuccess;
  315. SCODE sc = SUCCESS_SUCCESS;
  316. ULONG i;
  317. // Find the size of any existing MVP entries
  318. if (PROP_ERROR(lpaProps[index])) {
  319. // Un-ERROR the property tag
  320. lpaProps[index].ulPropTag = PROP_TAG(PT_MV_BINARY, PROP_ID(lpaProps[index].ulPropTag));
  321. } else {
  322. // point to the structure in the prop array.
  323. lprgsbOld = &(lpaProps[index].Value.MVbin);
  324. lpsbOld = lprgsbOld->lpbin;
  325. cExisting = lprgsbOld->cValues;
  326. cbMVP = cExisting * sizeof(SBinary);
  327. }
  328. // cbMVP now contains the current size of the MVP
  329. cbMVP += sizeof(SBinary); // room in the MVP for another Sbin
  330. // Allocate room for new MVP
  331. if (sc = MAPIAllocateMore(cbMVP, lpaProps, (LPVOID)&lpsbNew)) {
  332. AwDebugError(("AddPropToMVPBin allocation (%u) failed %x\n", cbMVP, sc));
  333. hResult = ResultFromScode(sc);
  334. return(hResult);
  335. }
  336. // If there are properties there already, copy them to our new MVP
  337. for (i = 0; i < cExisting; i++) {
  338. // Copy this property value to the MVP
  339. lpsbNew[i].cb = lpsbOld[i].cb;
  340. lpsbNew[i].lpb = lpsbOld[i].lpb;
  341. }
  342. // Add the new property value
  343. // Allocate room for it
  344. if (sc = MAPIAllocateMore(cbNew, lpaProps, (LPVOID)&(lpsbNew[i].lpb))) {
  345. AwDebugError(("AddPropToMVPBin allocation (%u) failed %x\n", cbNew, sc));
  346. hResult = ResultFromScode(sc);
  347. return(hResult);
  348. }
  349. lpsbNew[i].cb = cbNew;
  350. CopyMemory(lpsbNew[i].lpb, lpNew, cbNew);
  351. lpaProps[index].Value.MVbin.lpbin = lpsbNew;
  352. lpaProps[index].Value.MVbin.cValues = cExisting + 1;
  353. return(hResult);
  354. }
  355. /***************************************************************************
  356. Name : AddPropToMVPString
  357. Purpose : Add a property to a multi-valued binary property in a prop array
  358. Parameters: lpaProps -> array of properties
  359. cProps = number of props in lpaProps
  360. uPropTag = property tag for MVP
  361. index = index in lpaProps of MVP
  362. lpszNew -> new data string
  363. Returns : HRESULT
  364. Comment : Find the size of the existing MVP
  365. Add in the size of the new entry
  366. allocate new space
  367. copy old to new
  368. free old
  369. copy new entry
  370. point prop array LPSZ to the new space
  371. increment cValues
  372. Note: The new MVP memory is AllocMore'd onto the lpaProps
  373. allocation. We will unlink the pointer to the old MVP array,
  374. but this will be cleaned up when the prop array is freed.
  375. ***************************************************************************/
  376. HRESULT AddPropToMVPString(
  377. LPSPropValue lpaProps,
  378. DWORD cProps,
  379. DWORD index,
  380. LPTSTR lpszNew) {
  381. SStringArray * lprgszOld = NULL; // old SString array
  382. LPTSTR * lppszNew = NULL; // new prop array
  383. LPTSTR * lppszOld = NULL; // old prop array
  384. ULONG cbMVP = 0;
  385. ULONG cExisting = 0;
  386. LPBYTE lpNewTemp = NULL;
  387. HRESULT hResult = hrSuccess;
  388. SCODE sc = SUCCESS_SUCCESS;
  389. ULONG i;
  390. ULONG cbNew;
  391. if (lpszNew) {
  392. cbNew = lstrlen(lpszNew) + 1;
  393. } else {
  394. cbNew = 0;
  395. }
  396. // Find the size of any existing MVP entries
  397. if (PROP_ERROR(lpaProps[index])) {
  398. // Un-ERROR the property tag
  399. lpaProps[index].ulPropTag = PROP_TAG(PT_MV_TSTRING, PROP_ID(lpaProps[index].ulPropTag));
  400. } else {
  401. // point to the structure in the prop array.
  402. lprgszOld = &(lpaProps[index].Value.MVSZ);
  403. lppszOld = lprgszOld->LPPSZ;
  404. cExisting = lprgszOld->cValues;
  405. cbMVP = cExisting * sizeof(LPTSTR);
  406. }
  407. // cbMVP now contains the current size of the MVP
  408. cbMVP += sizeof(LPTSTR); // room in the MVP for another string pointer
  409. // Allocate room for new MVP array
  410. if (sc = MAPIAllocateMore(cbMVP, lpaProps, (LPVOID)&lppszNew)) {
  411. AwDebugError(("AddPropToMVPString allocation (%u) failed %x\n", cbMVP, sc));
  412. hResult = ResultFromScode(sc);
  413. return(hResult);
  414. }
  415. // If there are properties there already, copy them to our new MVP
  416. for (i = 0; i < cExisting; i++) {
  417. // Copy this property value to the MVP
  418. lppszNew[i] = lppszOld[i];
  419. }
  420. // Add the new property value
  421. // Allocate room for it
  422. if (cbNew) {
  423. if (sc = MAPIAllocateMore(cbNew, lpaProps, (LPVOID)&(lppszNew[i]))) {
  424. AwDebugError(("AddPropToMVPBin allocation (%u) failed %x\n", cbNew, sc));
  425. hResult = ResultFromScode(sc);
  426. return(hResult);
  427. }
  428. lstrcpy(lppszNew[i], lpszNew);
  429. lpaProps[index].Value.MVSZ.LPPSZ= lppszNew;
  430. lpaProps[index].Value.MVSZ.cValues = cExisting + 1;
  431. } else {
  432. lppszNew[i] = NULL;
  433. }
  434. return(hResult);
  435. }
  436. #endif // OLD_STUFF
  437. /***************************************************************************
  438. Name : FreeBufferAndNull
  439. Purpose : Frees a MAPI buffer and NULLs the pointer
  440. Parameters: lppv = pointer to buffer pointer to free
  441. Returns : void
  442. Comment : Remember to pass in the pointer to the pointer. The
  443. compiler is not smart enough to tell if you are doing this
  444. right or not, but you will know at runtime!
  445. BUGBUG: Make this fastcall!
  446. ***************************************************************************/
  447. void __fastcall FreeBufferAndNull(LPVOID * lppv) {
  448. if (lppv) {
  449. if (*lppv) {
  450. SCODE sc;
  451. if (sc = MAPIFreeBuffer(*lppv)) {
  452. DebugTrace("MAPIFreeBuffer(%x) -> %s\n", *lppv, SzDecodeScode(sc));
  453. }
  454. *lppv = NULL;
  455. }
  456. }
  457. }
  458. /***************************************************************************
  459. Name : ReleaseAndNull
  460. Purpose : Releases an object and NULLs the pointer
  461. Parameters: lppv = pointer to pointer to object to release
  462. Returns : void
  463. Comment : Remember to pass in the pointer to the pointer. The
  464. compiler is not smart enough to tell if you are doing this
  465. right or not, but you will know at runtime!
  466. BUGBUG: Make this fastcall!
  467. ***************************************************************************/
  468. void __fastcall ReleaseAndNull(LPVOID * lppv) {
  469. LPUNKNOWN * lppunk = (LPUNKNOWN *)lppv;
  470. if (lppunk) {
  471. if (*lppunk) {
  472. HRESULT hResult;
  473. if (hResult = (*lppunk)->lpVtbl->Release(*lppunk)) {
  474. DebugTrace("Release(%x) -> %s\n", *lppunk, SzDecodeScode(GetScode(hResult)));
  475. }
  476. *lppunk = NULL;
  477. }
  478. }
  479. }
  480. #ifdef OLD_STUFF
  481. /***************************************************************************
  482. Name : MergeProblemArrays
  483. Purpose : Merge a problem array into another
  484. Parameters: lpPaDest -> destination problem array
  485. lpPaSource -> source problem array
  486. cDestMax = total number of problem slots in lpPaDest. This
  487. includes those in use (lpPaDest->cProblem) and those not
  488. yet in use.
  489. Returns : none
  490. Comment :
  491. ***************************************************************************/
  492. void MergeProblemArrays(LPSPropProblemArray lpPaDest,
  493. LPSPropProblemArray lpPaSource, ULONG cDestMax) {
  494. ULONG i, j;
  495. ULONG cDest;
  496. ULONG cDestRemaining;
  497. cDest = lpPaDest->cProblem;
  498. cDestRemaining = cDestMax - cDest;
  499. // Loop through the source problems, copying the non-duplicates into dest
  500. for (i = 0; i < lpPaSource->cProblem; i++) {
  501. // Search the Dest problem array for the same property
  502. for (j = 0; j < cDest; j++) {
  503. // should just compare PROP_IDs here, since we may be overwriting
  504. // some of the proptypes with PT_NULL elsewhere.
  505. if (PROP_ID(lpPaSource->aProblem[i].ulPropTag) == PROP_ID(lpPaDest->aProblem[j].ulPropTag)) {
  506. break; // Found a match, don't copy this one. Move along.
  507. }
  508. }
  509. if (j == lpPaDest->cProblem) {
  510. Assert(cDestRemaining);
  511. if (cDestRemaining) {
  512. // No matches, copy this problem from Source to Dest
  513. lpPaDest->aProblem[lpPaDest->cProblem++] = lpPaSource->aProblem[i];
  514. cDestRemaining--;
  515. } else {
  516. AwDebugError(("MergeProblemArrays ran out of problem slots!\n"));
  517. }
  518. }
  519. }
  520. }
  521. /***************************************************************************
  522. Name : MapObjectNamedProps
  523. Purpose : Map the named properties WAB cares about into the object.
  524. Parameters: lpmp -> IMAPIProp object
  525. lppPropTags -> returned array of property tags. Note: Must
  526. be MAPIFreeBuffer'd by caller.
  527. Returns : none
  528. Comment : What a pain in the butt!
  529. We could conceivably improve performance here by caching the
  530. returned table and comparing the object's PR_MAPPING_SIGNATURE
  531. against the cache.
  532. ***************************************************************************/
  533. HRESULT MapObjectNamedProps(LPMAPIPROP lpmp, LPSPropTagArray * lppPropTags) {
  534. static GUID guidWABProps = { /* efa29030-364e-11cf-a49b-00aa0047faa4 */
  535. 0xefa29030,
  536. 0x364e,
  537. 0x11cf,
  538. {0xa4, 0x9b, 0x00, 0xaa, 0x00, 0x47, 0xfa, 0xa4}
  539. };
  540. ULONG i;
  541. LPMAPINAMEID lppmnid[eMaxNameIDs] = {NULL};
  542. MAPINAMEID rgmnid[eMaxNameIDs] = {0};
  543. HRESULT hResult = hrSuccess;
  544. // Loop through each property, setting up the NAME ID structures
  545. for (i = 0; i < eMaxNameIDs; i++) {
  546. rgmnid[i].lpguid = &guidWABProps;
  547. rgmnid[i].ulKind = MNID_STRING; // Unicode String
  548. rgmnid[i].Kind.lpwstrName = rgPropNames[i];
  549. lppmnid[i] = &rgmnid[i];
  550. }
  551. if (hResult = lpmp->lpVtbl->GetIDsFromNames(lpmp,
  552. eMaxNameIDs, // how many?
  553. lppmnid,
  554. MAPI_CREATE, // create them if they don't already exist
  555. lppPropTags)) {
  556. if (HR_FAILED(hResult)) {
  557. AwDebugError(("GetIDsFromNames -> %s\n", SzDecodeScode(GetScode(hResult))));
  558. goto exit;
  559. } else {
  560. DebugTrace("GetIDsFromNames -> %s\n", SzDecodeScode(GetScode(hResult)));
  561. }
  562. }
  563. Assert((*lppPropTags)->cValues == eMaxNameIDs);
  564. AwDebugTrace(("PropTag\t\tType\tProp Name\n"));
  565. // Loop through the property tags, filling in their property types.
  566. for (i = 0; i < eMaxNameIDs; i++) {
  567. (*lppPropTags)->aulPropTag[i] = CHANGE_PROP_TYPE((*lppPropTags)->aulPropTag[i],
  568. PROP_TYPE(rgulNamedPropTags[i]));
  569. #ifdef DEBUG
  570. {
  571. TCHAR szBuffer[257];
  572. WideCharToMultiByte(CP_ACP, 0, rgPropNames[i], -1, szBuffer, 257, NULL, NULL);
  573. AwDebugTrace(("%08x\t%s\t%s\n", (*lppPropTags)->aulPropTag[i],
  574. PropTypeString(PROP_TYPE((*lppPropTags)->aulPropTag[i])), szBuffer));
  575. }
  576. #endif
  577. }
  578. exit:
  579. return(hResult);
  580. }
  581. /***************************************************************************
  582. Name : PreparePropTagArray
  583. Purpose : Prepare a prop tag array by replacing placeholder props tags
  584. with their named property tags.
  585. Parameters: ptaStatic = static property tag array (input)
  586. pptaReturn -> returned prop tag array (output)
  587. pptaNamedProps -> returned array of named property tags
  588. Three possibilities here:
  589. + NULL pointer: no input PTA or output named
  590. props PTA is returned. This is less efficient since
  591. it must call MAPI to get the named props array.
  592. + good pointer to NULL pointer: no input PTA, but
  593. will return a good PTA of named props which can
  594. be used in later calls on this object for faster
  595. operation.
  596. + good pointer to good pointer. Use the input PTA instead
  597. of calling MAPI to map props. Returned contents must
  598. be freed with MAPIFreeBuffer.
  599. lpObject = object that the properties apply to. Required if
  600. no input *pptaNamedProps is supplied, otherwise, NULL.
  601. Returns : HRESULT
  602. Comment :
  603. ***************************************************************************/
  604. HRESULT PreparePropTagArray(LPSPropTagArray ptaStatic, LPSPropTagArray * pptaReturn,
  605. LPSPropTagArray * pptaNamedProps, LPMAPIPROP lpObject) {
  606. HRESULT hResult = hrSuccess;
  607. ULONG cbpta;
  608. LPSPropTagArray ptaTemp = NULL;
  609. LPSPropTagArray ptaNamedProps;
  610. ULONG i;
  611. if (pptaNamedProps) {
  612. // input Named Props PTA
  613. ptaNamedProps = *pptaNamedProps;
  614. } else {
  615. ptaNamedProps = NULL;
  616. }
  617. if (! ptaNamedProps) {
  618. if (! lpObject) {
  619. AwDebugError(("PreoparePropTagArray both lpObject and ptaNamedProps are NULL\n"));
  620. hResult = ResultFromScode(E_INVALIDARG);
  621. goto exit;
  622. }
  623. // Map the property names into the object
  624. if (hResult = MapObjectNamedProps(lpObject, &ptaTemp)) {
  625. AwDebugError(("PreoparePropTagArray both lpObject and ptaNamedProps are NULL\n"));
  626. goto exit;
  627. }
  628. }
  629. if (pptaReturn) {
  630. // Allocate a return pta
  631. cbpta = sizeof(SPropTagArray) + ptaStatic->cValues * sizeof(ULONG);
  632. if ((*pptaReturn = WABAlloc(cbpta)) == NULL) {
  633. AwDebugError(("PreparePropTagArray WABAlloc(%u) failed\n", cbpta));
  634. hResult = ResultFromScode(E_OUTOFMEMORY);
  635. goto exit;
  636. }
  637. (*pptaReturn)->cValues = ptaStatic->cValues;
  638. // Walk through the ptaStatic looking for named property placeholders.
  639. for (i = 0; i < ptaStatic->cValues; i++) {
  640. if (IS_PLACEHOLDER(ptaStatic->aulPropTag[i])) {
  641. // Found a placeholder. Turn it into a true property tag
  642. Assert(PLACEHOLDER_INDEX(ptaStatic->aulPropTag[i]) < ptaNamedProps->cValues);
  643. (*pptaReturn)->aulPropTag[i] =
  644. ptaNamedProps->aulPropTag[PLACEHOLDER_INDEX(ptaStatic->aulPropTag[i])];
  645. } else {
  646. (*pptaReturn)->aulPropTag[i] = ptaStatic->aulPropTag[i];
  647. }
  648. }
  649. }
  650. exit:
  651. if (hResult || ! pptaNamedProps) {
  652. FreeBufferAndNull(&ptaTemp);
  653. } else {
  654. // Client is responsible for freeing this.
  655. *pptaNamedProps = ptaNamedProps;
  656. }
  657. return(hResult);
  658. }
  659. /***************************************************************************
  660. Name : OpenCreateProperty
  661. Purpose : Open an interface on a property or create if non-existent.
  662. Parameters: lpmp -> IMAPIProp object to open prop on
  663. ulPropTag = property tag to open
  664. lpciid -> interface identifier
  665. ulInterfaceOptions = interface specific flags
  666. ulFlags = MAPI_MODIFY?
  667. lppunk -> return the object here
  668. Returns : HRESULT
  669. Comment : Caller is responsible for Release'ing the returned object.
  670. ***************************************************************************/
  671. HRESULT OpenCreateProperty(LPMAPIPROP lpmp,
  672. ULONG ulPropTag,
  673. LPCIID lpciid,
  674. ULONG ulInterfaceOptions,
  675. ULONG ulFlags,
  676. LPUNKNOWN * lppunk) {
  677. HRESULT hResult;
  678. if (hResult = lpmp->lpVtbl->OpenProperty(
  679. lpmp,
  680. ulPropTag,
  681. lpciid,
  682. ulInterfaceOptions,
  683. ulFlags,
  684. (LPUNKNOWN *)lppunk)) {
  685. AwDebugTrace(("OpenCreateProperty:OpenProperty(%s)-> %s\n", PropTagName(ulPropTag), SzDecodeScode(GetScode(hResult))));
  686. // property doesn't exist... try to create it
  687. if (hResult = lpmp->lpVtbl->OpenProperty(
  688. lpmp,
  689. ulPropTag,
  690. lpciid,
  691. ulInterfaceOptions,
  692. MAPI_CREATE | ulFlags,
  693. (LPUNKNOWN *)lppunk)) {
  694. AwDebugTrace(("OpenCreateProperty:OpenProperty(%s, MAPI_CREATE)-> %s\n", PropTagName(ulPropTag), SzDecodeScode(GetScode(hResult))));
  695. }
  696. }
  697. return(hResult);
  698. }
  699. #endif // OLD_STUFF
  700. #ifdef DEBUG
  701. /***************************************************************************
  702. Name : PropTypeString
  703. Purpose : Map a proptype to a string
  704. Parameters: ulPropType = property type to map
  705. Returns : string pointer to name of prop type
  706. Comment :
  707. ***************************************************************************/
  708. LPTSTR PropTypeString(ULONG ulPropType) {
  709. switch (ulPropType) {
  710. case PT_UNSPECIFIED:
  711. return("PT_UNSPECIFIED");
  712. case PT_NULL:
  713. return("PT_NULL ");
  714. case PT_I2:
  715. return("PT_I2 ");
  716. case PT_LONG:
  717. return("PT_LONG ");
  718. case PT_R4:
  719. return("PT_R4 ");
  720. case PT_DOUBLE:
  721. return("PT_DOUBLE ");
  722. case PT_CURRENCY:
  723. return("PT_CURRENCY ");
  724. case PT_APPTIME:
  725. return("PT_APPTIME ");
  726. case PT_ERROR:
  727. return("PT_ERROR ");
  728. case PT_BOOLEAN:
  729. return("PT_BOOLEAN ");
  730. case PT_OBJECT:
  731. return("PT_OBJECT ");
  732. case PT_I8:
  733. return("PT_I8 ");
  734. case PT_STRING8:
  735. return("PT_STRING8 ");
  736. case PT_UNICODE:
  737. return("PT_UNICODE ");
  738. case PT_SYSTIME:
  739. return("PT_SYSTIME ");
  740. case PT_CLSID:
  741. return("PT_CLSID ");
  742. case PT_BINARY:
  743. return("PT_BINARY ");
  744. case PT_MV_I2:
  745. return("PT_MV_I2 ");
  746. case PT_MV_LONG:
  747. return("PT_MV_LONG ");
  748. case PT_MV_R4:
  749. return("PT_MV_R4 ");
  750. case PT_MV_DOUBLE:
  751. return("PT_MV_DOUBLE ");
  752. case PT_MV_CURRENCY:
  753. return("PT_MV_CURRENCY");
  754. case PT_MV_APPTIME:
  755. return("PT_MV_APPTIME ");
  756. case PT_MV_SYSTIME:
  757. return("PT_MV_SYSTIME ");
  758. case PT_MV_STRING8:
  759. return("PT_MV_STRING8 ");
  760. case PT_MV_BINARY:
  761. return("PT_MV_BINARY ");
  762. case PT_MV_UNICODE:
  763. return("PT_MV_UNICODE ");
  764. case PT_MV_CLSID:
  765. return("PT_MV_CLSID ");
  766. case PT_MV_I8:
  767. return("PT_MV_I8 ");
  768. default:
  769. return(" <unknown> ");
  770. }
  771. }
  772. /***************************************************************************
  773. Name : TraceMVPStrings
  774. Purpose : Debug trace a multivalued string property value
  775. Parameters: lpszCaption = caption string
  776. PropValue = property value to dump
  777. Returns : none
  778. Comment :
  779. ***************************************************************************/
  780. void _TraceMVPStrings(LPTSTR lpszCaption, SPropValue PropValue) {
  781. ULONG i;
  782. DebugTrace("-----------------------------------------------------\n");
  783. DebugTrace("%s", lpszCaption);
  784. switch (PROP_TYPE(PropValue.ulPropTag)) {
  785. case PT_ERROR:
  786. DebugTrace("Error value %s\n", SzDecodeScode(PropValue.Value.err));
  787. break;
  788. case PT_MV_TSTRING:
  789. DebugTrace("%u values\n", PropValue.Value.MVSZ.cValues);
  790. if (PropValue.Value.MVSZ.cValues) {
  791. DebugTrace("- - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
  792. for (i = 0; i < PropValue.Value.MVSZ.cValues; i++) {
  793. DebugTrace("%u: \"%s\"\n", i, PropValue.Value.MVSZ.LPPSZ[i]);
  794. }
  795. DebugTrace("- - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
  796. }
  797. break;
  798. default:
  799. DebugTrace("TraceMVPStrings got incorrect property type %u for tag %x\n",
  800. PROP_TYPE(PropValue.ulPropTag), PropValue.ulPropTag);
  801. break;
  802. }
  803. }
  804. /***************************************************************************
  805. Name : DebugBinary
  806. Purpose : Debug dump an array of bytes
  807. Parameters: cb = number of bytes to dump
  808. lpb -> bytes to dump
  809. Returns : none
  810. Comment :
  811. ***************************************************************************/
  812. #define DEBUG_NUM_BINARY_LINES 2
  813. VOID DebugBinary(UINT cb, LPBYTE lpb) {
  814. UINT cbLines = 0;
  815. #if (DEBUG_NUM_BINARY_LINES != 0)
  816. UINT cbi;
  817. while (cb && cbLines < DEBUG_NUM_BINARY_LINES) {
  818. cbi = min(cb, 16);
  819. cb -= cbi;
  820. switch (cbi) {
  821. case 16:
  822. DebugTrace("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
  823. lpb[0], lpb[1], lpb[2], lpb[3], lpb[4], lpb[5], lpb[6], lpb[7],
  824. lpb[8], lpb[9], lpb[10], lpb[11], lpb[12], lpb[13], lpb[14],
  825. lpb[15]);
  826. break;
  827. case 1:
  828. DebugTrace("%02x\n", lpb[0]);
  829. break;
  830. case 2:
  831. DebugTrace("%02x %02x\n", lpb[0], lpb[1]);
  832. break;
  833. case 3:
  834. DebugTrace("%02x %02x %02x\n", lpb[0], lpb[1], lpb[2]);
  835. break;
  836. case 4:
  837. DebugTrace("%02x %02x %02x %02x\n", lpb[0], lpb[1], lpb[2], lpb[3]);
  838. break;
  839. case 5:
  840. DebugTrace("%02x %02x %02x %02x %02x\n", lpb[0], lpb[1], lpb[2], lpb[3],
  841. lpb[4]);
  842. break;
  843. case 6:
  844. DebugTrace("%02x %02x %02x %02x %02x %02x\n",
  845. lpb[0], lpb[1], lpb[2], lpb[3], lpb[4], lpb[5]);
  846. break;
  847. case 7:
  848. DebugTrace("%02x %02x %02x %02x %02x %02x %02x\n",
  849. lpb[0], lpb[1], lpb[2], lpb[3], lpb[4], lpb[5], lpb[6]);
  850. break;
  851. case 8:
  852. DebugTrace("%02x %02x %02x %02x %02x %02x %02x %02x\n",
  853. lpb[0], lpb[1], lpb[2], lpb[3], lpb[4], lpb[5], lpb[6], lpb[7]);
  854. break;
  855. case 9:
  856. DebugTrace("%02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
  857. lpb[0], lpb[1], lpb[2], lpb[3], lpb[4], lpb[5], lpb[6], lpb[7],
  858. lpb[8]);
  859. break;
  860. case 10:
  861. DebugTrace("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
  862. lpb[0], lpb[1], lpb[2], lpb[3], lpb[4], lpb[5], lpb[6], lpb[7],
  863. lpb[8], lpb[9]);
  864. break;
  865. case 11:
  866. DebugTrace("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
  867. lpb[0], lpb[1], lpb[2], lpb[3], lpb[4], lpb[5], lpb[6], lpb[7],
  868. lpb[8], lpb[9], lpb[10]);
  869. break;
  870. case 12:
  871. DebugTrace("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
  872. lpb[0], lpb[1], lpb[2], lpb[3], lpb[4], lpb[5], lpb[6], lpb[7],
  873. lpb[8], lpb[9], lpb[10], lpb[11]);
  874. break;
  875. case 13:
  876. DebugTrace("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
  877. lpb[0], lpb[1], lpb[2], lpb[3], lpb[4], lpb[5], lpb[6], lpb[7],
  878. lpb[8], lpb[9], lpb[10], lpb[11], lpb[12]);
  879. break;
  880. case 14:
  881. DebugTrace("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
  882. lpb[0], lpb[1], lpb[2], lpb[3], lpb[4], lpb[5], lpb[6], lpb[7],
  883. lpb[8], lpb[9], lpb[10], lpb[11], lpb[12], lpb[13]);
  884. break;
  885. case 15:
  886. DebugTrace("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
  887. lpb[0], lpb[1], lpb[2], lpb[3], lpb[4], lpb[5], lpb[6], lpb[7],
  888. lpb[8], lpb[9], lpb[10], lpb[11], lpb[12], lpb[13], lpb[14]);
  889. break;
  890. }
  891. lpb += cbi;
  892. cbLines++;
  893. }
  894. if (cb) {
  895. DebugTrace("<etc.>\n"); //
  896. }
  897. #endif
  898. }
  899. #define RETURN_PROP_CASE(pt) case PROP_ID(pt): return(#pt)
  900. /***************************************************************************
  901. Name : PropTagName
  902. Purpose : Associate a name with a property tag
  903. Parameters: ulPropTag = property tag
  904. Returns : none
  905. Comment : Add new Property ID's as they become known
  906. ***************************************************************************/
  907. PUCHAR PropTagName(ULONG ulPropTag) {
  908. static UCHAR szPropTag[35]; // see string on default
  909. switch (PROP_ID(ulPropTag)) {
  910. RETURN_PROP_CASE(PR_INITIALS);
  911. RETURN_PROP_CASE(PR_SURNAME);
  912. RETURN_PROP_CASE(PR_TITLE);
  913. RETURN_PROP_CASE(PR_TELEX_NUMBER);
  914. RETURN_PROP_CASE(PR_GIVEN_NAME);
  915. RETURN_PROP_CASE(PR_PRIMARY_TELEPHONE_NUMBER);
  916. RETURN_PROP_CASE(PR_PRIMARY_FAX_NUMBER);
  917. RETURN_PROP_CASE(PR_POSTAL_CODE);
  918. RETURN_PROP_CASE(PR_POSTAL_ADDRESS);
  919. RETURN_PROP_CASE(PR_POST_OFFICE_BOX);
  920. RETURN_PROP_CASE(PR_PAGER_TELEPHONE_NUMBER);
  921. RETURN_PROP_CASE(PR_OTHER_TELEPHONE_NUMBER);
  922. RETURN_PROP_CASE(PR_ORGANIZATIONAL_ID_NUMBER);
  923. RETURN_PROP_CASE(PR_OFFICE_LOCATION);
  924. RETURN_PROP_CASE(PR_LOCATION);
  925. RETURN_PROP_CASE(PR_LOCALITY);
  926. RETURN_PROP_CASE(PR_ISDN_NUMBER);
  927. RETURN_PROP_CASE(PR_GOVERNMENT_ID_NUMBER);
  928. RETURN_PROP_CASE(PR_GENERATION);
  929. RETURN_PROP_CASE(PR_DEPARTMENT_NAME);
  930. RETURN_PROP_CASE(PR_COUNTRY);
  931. RETURN_PROP_CASE(PR_COMPANY_NAME);
  932. RETURN_PROP_CASE(PR_COMMENT);
  933. RETURN_PROP_CASE(PR_CELLULAR_TELEPHONE_NUMBER);
  934. RETURN_PROP_CASE(PR_CAR_TELEPHONE_NUMBER);
  935. RETURN_PROP_CASE(PR_CALLBACK_TELEPHONE_NUMBER);
  936. RETURN_PROP_CASE(PR_BUSINESS2_TELEPHONE_NUMBER);
  937. RETURN_PROP_CASE(PR_BUSINESS_TELEPHONE_NUMBER);
  938. RETURN_PROP_CASE(PR_BUSINESS_FAX_NUMBER);
  939. RETURN_PROP_CASE(PR_ASSISTANT_TELEPHONE_NUMBER);
  940. RETURN_PROP_CASE(PR_ASSISTANT);
  941. RETURN_PROP_CASE(PR_ACCOUNT);
  942. RETURN_PROP_CASE(PR_TEMPLATEID);
  943. RETURN_PROP_CASE(PR_DETAILS_TABLE);
  944. RETURN_PROP_CASE(PR_SEARCH_KEY);
  945. RETURN_PROP_CASE(PR_LAST_MODIFICATION_TIME);
  946. RETURN_PROP_CASE(PR_CREATION_TIME);
  947. RETURN_PROP_CASE(PR_ENTRYID);
  948. RETURN_PROP_CASE(PR_RECORD_KEY);
  949. RETURN_PROP_CASE(PR_MAPPING_SIGNATURE);
  950. RETURN_PROP_CASE(PR_OBJECT_TYPE);
  951. RETURN_PROP_CASE(PR_ROWID);
  952. RETURN_PROP_CASE(PR_ADDRTYPE);
  953. RETURN_PROP_CASE(PR_DISPLAY_NAME);
  954. RETURN_PROP_CASE(PR_EMAIL_ADDRESS);
  955. RETURN_PROP_CASE(PR_DEPTH);
  956. RETURN_PROP_CASE(PR_ROW_TYPE);
  957. RETURN_PROP_CASE(PR_RADIO_TELEPHONE_NUMBER);
  958. RETURN_PROP_CASE(PR_HOME_TELEPHONE_NUMBER);
  959. RETURN_PROP_CASE(PR_INSTANCE_KEY);
  960. RETURN_PROP_CASE(PR_DISPLAY_TYPE);
  961. RETURN_PROP_CASE(PR_RECIPIENT_TYPE);
  962. default:
  963. wsprintf(szPropTag, "Unknown property tag 0x%x",
  964. PROP_ID(ulPropTag));
  965. return(szPropTag);
  966. }
  967. }
  968. /***************************************************************************
  969. Name : DebugPropTagArray
  970. Purpose : Displays MAPI property tags from a counted array
  971. Parameters: lpPropArray -> property array
  972. pszObject -> object string (ie "Message", "Recipient", etc)
  973. Returns : none
  974. Comment :
  975. ***************************************************************************/
  976. void _DebugPropTagArray(LPSPropTagArray lpPropArray, PUCHAR pszObject) {
  977. DWORD i;
  978. PUCHAR lpType;
  979. if (lpPropArray == NULL) {
  980. DebugTrace("Empty %s property tag array.\n", pszObject ? pszObject : szNULL);
  981. return;
  982. }
  983. DebugTrace("=======================================\n");
  984. DebugTrace("+ Enumerating %u %s property tags:\n", lpPropArray->cValues,
  985. pszObject ? pszObject : szNULL);
  986. for (i = 0; i < lpPropArray->cValues ; i++) {
  987. DebugTrace("---------------------------------------\n");
  988. #if FALSE
  989. DebugTrace("PropTag:0x%08x, ID:0x%04x, PT:0x%04x\n",
  990. lpPropArray->aulPropTag[i],
  991. lpPropArray->aulPropTag[i] >> 16,
  992. lpPropArray->aulPropTag[i] & 0xffff);
  993. #endif
  994. switch (lpPropArray->aulPropTag[i] & 0xffff) {
  995. case PT_STRING8:
  996. lpType = "STRING8";
  997. break;
  998. case PT_LONG:
  999. lpType = "LONG";
  1000. break;
  1001. case PT_I2:
  1002. lpType = "I2";
  1003. break;
  1004. case PT_ERROR:
  1005. lpType = "ERROR";
  1006. break;
  1007. case PT_BOOLEAN:
  1008. lpType = "BOOLEAN";
  1009. break;
  1010. case PT_R4:
  1011. lpType = "R4";
  1012. break;
  1013. case PT_DOUBLE:
  1014. lpType = "DOUBLE";
  1015. break;
  1016. case PT_CURRENCY:
  1017. lpType = "CURRENCY";
  1018. break;
  1019. case PT_APPTIME:
  1020. lpType = "APPTIME";
  1021. break;
  1022. case PT_SYSTIME:
  1023. lpType = "SYSTIME";
  1024. break;
  1025. case PT_UNICODE:
  1026. lpType = "UNICODE";
  1027. break;
  1028. case PT_CLSID:
  1029. lpType = "CLSID";
  1030. break;
  1031. case PT_BINARY:
  1032. lpType = "BINARY";
  1033. break;
  1034. case PT_I8:
  1035. lpType = "PT_I8";
  1036. break;
  1037. case PT_MV_I2:
  1038. lpType = "MV_I2";
  1039. break;
  1040. case PT_MV_LONG:
  1041. lpType = "MV_LONG";
  1042. break;
  1043. case PT_MV_R4:
  1044. lpType = "MV_R4";
  1045. break;
  1046. case PT_MV_DOUBLE:
  1047. lpType = "MV_DOUBLE";
  1048. break;
  1049. case PT_MV_CURRENCY:
  1050. lpType = "MV_CURRENCY";
  1051. break;
  1052. case PT_MV_APPTIME:
  1053. lpType = "MV_APPTIME";
  1054. break;
  1055. case PT_MV_SYSTIME:
  1056. lpType = "MV_SYSTIME";
  1057. break;
  1058. case PT_MV_BINARY:
  1059. lpType = "MV_BINARY";
  1060. break;
  1061. case PT_MV_STRING8:
  1062. lpType = "MV_STRING8";
  1063. break;
  1064. case PT_MV_UNICODE:
  1065. lpType = "MV_UNICODE";
  1066. break;
  1067. case PT_MV_CLSID:
  1068. lpType = "MV_CLSID";
  1069. break;
  1070. case PT_MV_I8:
  1071. lpType = "MV_I8";
  1072. break;
  1073. case PT_NULL:
  1074. lpType = "NULL";
  1075. break;
  1076. case PT_OBJECT:
  1077. lpType = "OBJECT";
  1078. break;
  1079. default:
  1080. DebugTrace("<Unknown Property Type>");
  1081. break;
  1082. }
  1083. DebugTrace("%s\t%s\n", PropTagName(lpPropArray->aulPropTag[i]), lpType);
  1084. }
  1085. }
  1086. /***************************************************************************
  1087. Name : DebugProperties
  1088. Purpose : Displays MAPI properties in a property list
  1089. Parameters: lpProps -> property list
  1090. cProps = count of properties
  1091. pszObject -> object string (ie "Message", "Recipient", etc)
  1092. Returns : none
  1093. Comment : Add new Property ID's as they become known
  1094. ***************************************************************************/
  1095. void _DebugProperties(LPSPropValue lpProps, DWORD cProps, PUCHAR pszObject) {
  1096. DWORD i;
  1097. DebugTrace("=======================================\n");
  1098. DebugTrace("+ Enumerating %u %s properties:\n", cProps,
  1099. pszObject ? pszObject : szNULL);
  1100. for (i = 0; i < cProps ; i++) {
  1101. DebugTrace("---------------------------------------\n");
  1102. #if FALSE
  1103. DebugTrace("PropTag:0x%08x, ID:0x%04x, PT:0x%04x\n",
  1104. lpProps[i].ulPropTag,
  1105. lpProps[i].ulPropTag >> 16,
  1106. lpProps[i].ulPropTag & 0xffff);
  1107. #endif
  1108. DebugTrace("%s\n", PropTagName(lpProps[i].ulPropTag));
  1109. switch (lpProps[i].ulPropTag & 0xffff) {
  1110. case PT_STRING8:
  1111. if (lstrlen(lpProps[i].Value.lpszA) < 1024) {
  1112. DebugTrace("STRING8 Value:\"%s\"\n", lpProps[i].Value.lpszA);
  1113. } else {
  1114. DebugTrace("STRING8 Value is too long to display\n");
  1115. }
  1116. break;
  1117. case PT_LONG:
  1118. DebugTrace("LONG Value:%u\n", lpProps[i].Value.l);
  1119. break;
  1120. case PT_I2:
  1121. DebugTrace("I2 Value:%u\n", lpProps[i].Value.i);
  1122. break;
  1123. case PT_ERROR:
  1124. DebugTrace("ERROR Value: %s\n", SzDecodeScode(lpProps[i].Value.err));
  1125. break;
  1126. case PT_BOOLEAN:
  1127. DebugTrace("BOOLEAN Value:%s\n", lpProps[i].Value.b ?
  1128. "TRUE" : "FALSE");
  1129. break;
  1130. case PT_R4:
  1131. DebugTrace("R4 Value\n");
  1132. break;
  1133. case PT_DOUBLE:
  1134. DebugTrace("DOUBLE Value\n");
  1135. break;
  1136. case PT_CURRENCY:
  1137. DebugTrace("CURRENCY Value\n");
  1138. break;
  1139. case PT_APPTIME:
  1140. DebugTrace("APPTIME Value\n");
  1141. break;
  1142. case PT_SYSTIME:
  1143. // DebugTime(lpProps[i].Value.ft, "SYSTIME Value:%s\n");
  1144. break;
  1145. case PT_UNICODE:
  1146. DebugTrace("UNICODE Value\n");
  1147. break;
  1148. case PT_CLSID:
  1149. DebugTrace("CLSID Value\n");
  1150. break;
  1151. case PT_BINARY:
  1152. DebugTrace("BINARY Value %u bytes:\n", lpProps[i].Value.bin.cb);
  1153. DebugBinary(lpProps[i].Value.bin.cb, lpProps[i].Value.bin.lpb);
  1154. break;
  1155. case PT_I8:
  1156. DebugTrace("LARGE_INTEGER Value\n");
  1157. break;
  1158. case PT_MV_I2:
  1159. DebugTrace("MV_I2 Value\n");
  1160. break;
  1161. case PT_MV_LONG:
  1162. DebugTrace("MV_LONG Value\n");
  1163. break;
  1164. case PT_MV_R4:
  1165. DebugTrace("MV_R4 Value\n");
  1166. break;
  1167. case PT_MV_DOUBLE:
  1168. DebugTrace("MV_DOUBLE Value\n");
  1169. break;
  1170. case PT_MV_CURRENCY:
  1171. DebugTrace("MV_CURRENCY Value\n");
  1172. break;
  1173. case PT_MV_APPTIME:
  1174. DebugTrace("MV_APPTIME Value\n");
  1175. break;
  1176. case PT_MV_SYSTIME:
  1177. DebugTrace("MV_SYSTIME Value\n");
  1178. break;
  1179. case PT_MV_BINARY:
  1180. DebugTrace("MV_BINARY Value\n");
  1181. break;
  1182. case PT_MV_STRING8:
  1183. DebugTrace("MV_STRING8 Value\n");
  1184. break;
  1185. case PT_MV_UNICODE:
  1186. DebugTrace("MV_UNICODE Value\n");
  1187. break;
  1188. case PT_MV_CLSID:
  1189. DebugTrace("MV_CLSID Value\n");
  1190. break;
  1191. case PT_MV_I8:
  1192. DebugTrace("MV_I8 Value\n");
  1193. break;
  1194. case PT_NULL:
  1195. DebugTrace("NULL Value\n");
  1196. break;
  1197. case PT_OBJECT:
  1198. DebugTrace("OBJECT Value\n");
  1199. break;
  1200. default:
  1201. DebugTrace("Unknown Property Type\n");
  1202. break;
  1203. }
  1204. }
  1205. }
  1206. /***************************************************************************
  1207. Name : DebugObjectProps
  1208. Purpose : Displays MAPI properties of an object
  1209. Parameters: lpObject -> object to dump
  1210. Label = string to identify this prop dump
  1211. Returns : none
  1212. Comment :
  1213. ***************************************************************************/
  1214. void _DebugObjectProps(LPMAPIPROP lpObject, LPTSTR Label) {
  1215. DWORD cProps = 0;
  1216. LPSPropValue lpProps = NULL;
  1217. HRESULT hr = hrSuccess;
  1218. SCODE sc = SUCCESS_SUCCESS;
  1219. hr = lpObject->lpVtbl->GetProps(lpObject, NULL, 0, &cProps, &lpProps);
  1220. switch (sc = GetScode(hr)) {
  1221. case SUCCESS_SUCCESS:
  1222. break;
  1223. case MAPI_W_ERRORS_RETURNED:
  1224. DebugTrace("GetProps -> Errors Returned\n");
  1225. break;
  1226. default:
  1227. DebugTrace("GetProps -> Error 0x%x\n", sc);
  1228. return;
  1229. }
  1230. _DebugProperties(lpProps, cProps, Label);
  1231. FreeBufferAndNull(&lpProps);
  1232. }
  1233. /***************************************************************************
  1234. Name : DebugMapiTable
  1235. Purpose : Displays structure of a MAPITABLE including properties
  1236. Parameters: lpTable -> MAPITABLE to display
  1237. Returns : none
  1238. Comment : Don't sort the columns or rows here. This routine should
  1239. not produce side effects in the table.
  1240. ***************************************************************************/
  1241. void _DebugMapiTable(LPMAPITABLE lpTable) {
  1242. UCHAR szTemp[30]; // plenty for "ROW %u"
  1243. ULONG ulCount;
  1244. WORD wIndex;
  1245. LPSRowSet lpsRow = NULL;
  1246. ULONG ulCurrentRow = (ULONG)-1;
  1247. ULONG ulNum, ulDen, lRowsSeeked;
  1248. DebugTrace("=======================================\n");
  1249. DebugTrace("+ Dump of MAPITABLE at 0x%x:\n", lpTable);
  1250. DebugTrace("---------------------------------------\n");
  1251. // How big is the table?
  1252. lpTable->lpVtbl->GetRowCount(lpTable, 0, &ulCount);
  1253. DebugTrace("Table contains %u rows\n", ulCount);
  1254. // Save the current position in the table
  1255. lpTable->lpVtbl->QueryPosition(lpTable, &ulCurrentRow, &ulNum, &ulDen);
  1256. // Display the properties for each row in the table
  1257. for (wIndex = 0; wIndex < ulCount; wIndex++) {
  1258. // Get the next row
  1259. lpTable->lpVtbl->QueryRows(lpTable, 1, 0, &lpsRow);
  1260. if (lpsRow) {
  1261. Assert(lpsRow->cRows == 1); // should have exactly one row
  1262. wsprintf(szTemp, "ROW %u", wIndex);
  1263. DebugProperties(lpsRow->aRow[0].lpProps,
  1264. lpsRow->aRow[0].cValues, szTemp);
  1265. FreeProws(lpsRow);
  1266. }
  1267. }
  1268. // Restore the current position for the table
  1269. if (ulCurrentRow != (ULONG)-1) {
  1270. lpTable->lpVtbl->SeekRow(lpTable, BOOKMARK_BEGINNING, ulCurrentRow,
  1271. &lRowsSeeked);
  1272. }
  1273. }
  1274. #endif