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.

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