Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

777 lines
22 KiB

  1. //+============================================================================
  2. //
  3. // File: RtlStub.cxx
  4. //
  5. // Purpose:
  6. // This file provides some RTL routines which are also implemented
  7. // in NTDLL. They are duplicated here so that we can build
  8. // PropTest without linking to NTDLL, which doesn't exist
  9. // on Win95.
  10. //
  11. //+============================================================================
  12. #include "pch.cxx" // Brings in most other includes/defines/etc.
  13. #define BSTRLEN(bstrVal) *((ULONG *) bstrVal - 1)
  14. // we use static array instead of string literals because some systems
  15. // have 4 bytes string literals, and would not produce the correct result
  16. // for REF's 2 byte Unicode convention
  17. //
  18. OLECHAR aocMap[CCH_MAP + 1] = {'a','b','c','d','e','f','g',
  19. 'h','i','j','k','l','m','n',
  20. 'o','p','q','r','s','t','u',
  21. 'v','w','x','y','z',
  22. '0','1','2','3','4','5','\0'};
  23. GUID guidSummary =
  24. { 0xf29f85e0,
  25. 0x4ff9, 0x1068,
  26. { 0xab, 0x91, 0x08, 0x00, 0x2b, 0x27, 0xb3, 0xd9 } };
  27. OLECHAR oszSummary[] = {'S','u','m','m','a','r','y',
  28. 'I','n','f','o','r','m','a','t','i','o','n','\0'};
  29. GUID guidDocumentSummary =
  30. { 0xd5cdd502,
  31. 0x2e9c, 0x101b,
  32. { 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae } };
  33. OLECHAR oszDocumentSummary[] = {'D','o','c','u','m','e','n','t',
  34. 'S','u','m','m','a','r','y',
  35. 'I','n','f','o','r','m','a','t','i','o','n',
  36. '\0'};
  37. // Note that user defined properties are placed in section 2 with the below
  38. // GUID as the FMTID -- alas, we did not expect Office95 to actually use it.
  39. GUID guidDocumentSummarySection2 =
  40. { 0xd5cdd505,
  41. 0x2e9c, 0x101b,
  42. { 0x93, 0x97, 0x08, 0x00, 0x2b, 0x2c, 0xf9, 0xae } };
  43. // *Global Info*
  44. GUID guidGlobalInfo =
  45. { 0x56616F00,
  46. 0xC154, 0x11ce,
  47. { 0x85, 0x53, 0x00, 0xAA, 0x00, 0xA1, 0xF9, 0x5B } };
  48. // *Image Contents*
  49. GUID guidImageContents =
  50. { 0x56616500,
  51. 0xC154, 0x11ce,
  52. { 0x85, 0x53, 0x00, 0xAA, 0x00, 0xA1, 0xF9, 0x5B } };
  53. // *Image Info*
  54. GUID guidImageInfo =
  55. { 0x56616500,
  56. 0xC154, 0x11ce,
  57. { 0x85, 0x53, 0x00, 0xAA, 0x00, 0xA1, 0xF9, 0x5B } };
  58. //+--------------------------------------------------------------------------
  59. // Function: RtlGuidToPropertySetName
  60. //
  61. // Synopsis: Map property set GUID to null-terminated UNICODE name string.
  62. //
  63. // The awcname parameter is assumed to be a buffer with room for
  64. // CWC_PROPSETSZ (28) UNICODE characters. The first character
  65. // is always WC_PROPSET0 (0x05), as specified by the OLE Appendix
  66. // B documentation. The colon character normally used as an NT
  67. // stream name separator is not written to the caller's buffer.
  68. //
  69. // No error is possible.
  70. //
  71. // Arguments: IN GUID *pguid -- pointer to GUID to convert
  72. // OUT OLECHAR aocname[] -- output string buffer
  73. //
  74. // Returns: count of non-NULL characters in the output string buffer
  75. //---------------------------------------------------------------------------
  76. ULONG PROPSYSAPI PROPAPI
  77. RtlGuidToPropertySetName(
  78. IN GUID const *pguid,
  79. OUT OLECHAR aocname[])
  80. {
  81. ULONG cbitRemain = CBIT_BYTE;
  82. OLECHAR *poc = aocname;
  83. BYTE *pb;
  84. BYTE *pbEnd;
  85. *poc++ = OC_PROPSET0;
  86. // -----------------------
  87. // Check for special-cases
  88. // -----------------------
  89. // Note: CCH_PROPSET includes the OC_PROPSET0, and sizeof(osz...)
  90. // includes the trailing '\0', so sizeof(osz...) is ok because the
  91. // OC_PROPSET0 character compensates for the trailing NULL character.
  92. // Is this the SummaryInformation propset?
  93. PROPASSERT(CCH_PROPSET >= sizeof(oszSummary)/sizeof(OLECHAR));
  94. if (*pguid == guidSummary)
  95. {
  96. RtlCopyMemory(poc, oszSummary, sizeof(oszSummary));
  97. return(sizeof(oszSummary)/sizeof(OLECHAR));
  98. }
  99. // Is this The DocumentSummaryInformation or User-Defined propset?
  100. PROPASSERT(CCH_PROPSET >= sizeof(oszDocumentSummary)/sizeof(OLECHAR));
  101. if (*pguid == guidDocumentSummary || *pguid == guidDocumentSummarySection2)
  102. {
  103. RtlCopyMemory(poc, oszDocumentSummary, sizeof(oszDocumentSummary));
  104. return(sizeof(oszDocumentSummary)/sizeof(OLECHAR));
  105. }
  106. // Is this the Global Info propset?
  107. PROPASSERT(CCH_PROPSET >= sizeof(oszGlobalInfo)/sizeof(OLECHAR));
  108. if (*pguid == guidGlobalInfo)
  109. {
  110. RtlCopyMemory(poc, oszGlobalInfo, cboszGlobalInfo);
  111. return(cboszGlobalInfo/sizeof(OLECHAR));
  112. }
  113. // Is this the Image Contents propset?
  114. PROPASSERT(CCH_PROPSET >= sizeof(oszImageContents)/sizeof(OLECHAR));
  115. if (*pguid == guidImageContents)
  116. {
  117. RtlCopyMemory(poc, oszImageContents, cboszImageContents);
  118. return(cboszImageContents/sizeof(OLECHAR));
  119. }
  120. // Is this the Image Info propset?
  121. PROPASSERT(CCH_PROPSET >= sizeof(oszImageInfo)/sizeof(OLECHAR));
  122. if (*pguid == guidImageInfo)
  123. {
  124. RtlCopyMemory(poc, oszImageInfo, cboszImageInfo);
  125. return(cboszImageInfo/sizeof(OLECHAR));
  126. }
  127. // ------------------------------
  128. // Calculate the string-ized GUID
  129. // ------------------------------
  130. // If this is a big-endian system, we need to convert
  131. // the GUID to little-endian for the conversion.
  132. #if BIGENDIAN
  133. GUID guidByteSwapped = *pguid;
  134. PropByteSwap( &guidByteSwapped );
  135. pguid = &guidByteSwapped;
  136. #endif
  137. // Point to the beginning and ending of the GUID
  138. pb = (BYTE*) pguid;
  139. pbEnd = pb + sizeof(*pguid);
  140. // Walk 'pb' through each byte of the GUID.
  141. while (pb < pbEnd)
  142. {
  143. ULONG i = *pb >> (CBIT_BYTE - cbitRemain);
  144. if (cbitRemain >= CBIT_CHARMASK)
  145. {
  146. *poc = MapChar(i);
  147. if (cbitRemain == CBIT_BYTE && *poc >= (OLECHAR)'a'
  148. && *poc <= ((OLECHAR)'z'))
  149. {
  150. *poc += (OLECHAR) ( ((OLECHAR)'A') - ((OLECHAR)'a') );
  151. }
  152. poc++;
  153. cbitRemain -= CBIT_CHARMASK;
  154. if (cbitRemain == 0)
  155. {
  156. pb++;
  157. cbitRemain = CBIT_BYTE;
  158. }
  159. }
  160. else
  161. {
  162. if (++pb < pbEnd)
  163. {
  164. i |= *pb << cbitRemain;
  165. }
  166. *poc++ = MapChar(i);
  167. cbitRemain += CBIT_BYTE - CBIT_CHARMASK;
  168. }
  169. } // while (pb < pbEnd)
  170. *poc = OLESTR( '\0' );
  171. return(CCH_PROPSET);
  172. }
  173. //+--------------------------------------------------------------------------
  174. // Function: RtlPropertySetNameToGuid
  175. //
  176. // Synopsis: Map non null-terminated UNICODE string to a property set GUID.
  177. //
  178. // If the name is not properly formed as per
  179. // RtlGuidToPropertySetName(), STATUS_INVALID_PARAMETER is
  180. // returned. The pguid parameter is assumed to point to a buffer
  181. // with room for a GUID structure.
  182. //
  183. // Arguments: IN ULONG cocname -- count of OLECHARs in string to convert
  184. // IN OLECHAR aocname[] -- input string to convert
  185. // OUT GUID *pguid -- pointer to buffer for converted GUID
  186. //
  187. // Returns: NTSTATUS
  188. //---------------------------------------------------------------------------
  189. NTSTATUS PROPSYSAPI PROPAPI
  190. RtlPropertySetNameToGuid(
  191. IN ULONG cocname,
  192. IN OLECHAR const aocname[],
  193. OUT GUID *pguid)
  194. {
  195. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  196. OLECHAR const *poc = aocname;
  197. if (poc[0] == OC_PROPSET0)
  198. {
  199. // -----------------------
  200. // Check for Special-Cases
  201. // -----------------------
  202. // Note: cocname includes the OC_PROPSET0, and sizeof(osz...)
  203. // includes the trailing OLESTR('\0'), but the comparison excludes both
  204. // the leading OC_PROPSET0 and the trailing '\0'.
  205. // Is this SummaryInformation?
  206. if (cocname == sizeof(oszSummary)/sizeof(OLECHAR) &&
  207. ocsnicmp(&poc[1], oszSummary, cocname - 1) == 0)
  208. {
  209. *pguid = guidSummary;
  210. return(STATUS_SUCCESS);
  211. }
  212. // Is this DocumentSummaryInformation?
  213. if (cocname == sizeof(oszDocumentSummary)/sizeof(OLECHAR) &&
  214. ocsnicmp(&poc[1], oszDocumentSummary, cocname - 1) == 0)
  215. {
  216. *pguid = guidDocumentSummary;
  217. return(STATUS_SUCCESS);
  218. }
  219. // Is this Global Info?
  220. if (cocname == cboszGlobalInfo/sizeof(OLECHAR) &&
  221. ocsnicmp(&poc[1], oszGlobalInfo, cocname - 1) == 0)
  222. {
  223. *pguid = guidGlobalInfo;
  224. return(STATUS_SUCCESS);
  225. }
  226. // Is this Image Info?
  227. if (cocname == cboszImageInfo/sizeof(OLECHAR) &&
  228. ocsnicmp(&poc[1], oszImageInfo, cocname - 1) == 0)
  229. {
  230. *pguid = guidImageInfo;
  231. return(STATUS_SUCCESS);
  232. }
  233. // Is this Image Contents?
  234. if (cocname == cboszImageContents/sizeof(OLECHAR) &&
  235. ocsnicmp(&poc[1], oszImageContents, cocname - 1) == 0)
  236. {
  237. *pguid = guidImageContents;
  238. return(STATUS_SUCCESS);
  239. }
  240. // ------------------
  241. // Calculate the GUID
  242. // ------------------
  243. // None of the special-cases hit, so we must calculate
  244. // the GUID from the name.
  245. if (cocname == CCH_PROPSET)
  246. {
  247. ULONG cbit;
  248. BYTE *pb = (BYTE *) pguid - 1;
  249. RtlZeroMemory(pguid, sizeof(*pguid));
  250. for (cbit = 0; cbit < CBIT_GUID; cbit += CBIT_CHARMASK)
  251. {
  252. ULONG cbitUsed = cbit % CBIT_BYTE;
  253. ULONG cbitStored;
  254. OLECHAR oc;
  255. if (cbitUsed == 0)
  256. {
  257. pb++;
  258. }
  259. oc = *++poc - (OLECHAR)'A'; // assume upper case
  260. // for wchar (unsigned) -ve values becomes a large number
  261. // but for char, which is signed, -ve is -ve
  262. if (oc > CALPHACHARS || oc < 0)
  263. {
  264. // oops, try lower case
  265. oc += (OLECHAR) ( ((OLECHAR)'A') - ((OLECHAR)'a'));
  266. if (oc > CALPHACHARS || oc < 0)
  267. {
  268. // must be a digit
  269. oc += ((OLECHAR)'a') - ((OLECHAR)'0') + CALPHACHARS;
  270. if (oc > CHARMASK)
  271. {
  272. goto Exit; // invalid character
  273. }
  274. }
  275. }
  276. *pb |= (BYTE) (oc << cbitUsed);
  277. cbitStored = min(CBIT_BYTE - cbitUsed, CBIT_CHARMASK);
  278. // If the translated bits wouldn't all fit in the current byte
  279. if (cbitStored < CBIT_CHARMASK)
  280. {
  281. oc >>= CBIT_BYTE - cbitUsed;
  282. if (cbit + cbitStored == CBIT_GUID)
  283. {
  284. if (oc != 0)
  285. {
  286. goto Exit; // extra bits
  287. }
  288. break;
  289. }
  290. pb++;
  291. *pb |= (BYTE) oc;
  292. }
  293. } // for (cbit = 0; cbit < CBIT_GUID; cbit += CBIT_CHARMASK)
  294. Status = STATUS_SUCCESS;
  295. // If byte-swapping is necessary, do so now on the calculated
  296. // GUID.
  297. PropByteSwap( pguid );
  298. } // if (cocname == CCH_PROPSET)
  299. } // if (poc[0] == OC_PROPSET0)
  300. // ----
  301. // Exit
  302. // ----
  303. Exit:
  304. return(Status);
  305. }
  306. inline BOOLEAN
  307. _Compare_VT_BOOL(VARIANT_BOOL bool1, VARIANT_BOOL bool2)
  308. {
  309. // Allow any non-zero value to match any non-zero value
  310. return((bool1 == FALSE) == (bool2 == FALSE));
  311. }
  312. BOOLEAN
  313. _Compare_VT_CF(CLIPDATA *pclipdata1, CLIPDATA *pclipdata2)
  314. {
  315. BOOLEAN fSame;
  316. if (pclipdata1 != NULL && pclipdata2 != NULL)
  317. {
  318. fSame = ( pclipdata1->cbSize == pclipdata2->cbSize
  319. &&
  320. pclipdata1->ulClipFmt == pclipdata2->ulClipFmt );
  321. if (fSame)
  322. {
  323. if (pclipdata1->pClipData != NULL && pclipdata2->pClipData != NULL)
  324. {
  325. fSame = memcmp(
  326. pclipdata1->pClipData,
  327. pclipdata2->pClipData,
  328. CBPCLIPDATA(*pclipdata1)
  329. ) == 0;
  330. }
  331. else
  332. {
  333. // They're the same if both are NULL, or if
  334. // they have a zero length (if they have a zero
  335. // length, either one may or may not be NULL, but they're
  336. // still considered the same).
  337. fSame = pclipdata1->pClipData == pclipdata2->pClipData
  338. ||
  339. CBPCLIPDATA(*pclipdata1) == 0;
  340. }
  341. }
  342. }
  343. else
  344. {
  345. fSame = pclipdata1 == pclipdata2;
  346. }
  347. return(fSame);
  348. }
  349. //+---------------------------------------------------------------------------
  350. // Function: RtlCompareVariants, public
  351. //
  352. // Synopsis: Compare two passed PROPVARIANTs -- case sensitive for strings
  353. //
  354. // Arguments: [CodePage] -- CodePage
  355. // [pvar1] -- pointer to PROPVARIANT
  356. // [pvar2] -- pointer to PROPVARIANT
  357. //
  358. // Returns: TRUE if identical, else FALSE
  359. //---------------------------------------------------------------------------
  360. #ifdef _MAC
  361. EXTERN_C // The Mac linker doesn't seem to be able to export with C++ decorations
  362. #endif
  363. BOOLEAN PROPSYSAPI PROPAPI
  364. PropTestCompareVariants(
  365. USHORT CodePage,
  366. PROPVARIANT const *pvar1,
  367. PROPVARIANT const *pvar2)
  368. {
  369. if (pvar1->vt != pvar2->vt)
  370. {
  371. return(FALSE);
  372. }
  373. BOOLEAN fSame;
  374. ULONG i;
  375. switch (pvar1->vt)
  376. {
  377. case VT_EMPTY:
  378. case VT_NULL:
  379. fSame = TRUE;
  380. break;
  381. case VT_I1:
  382. case VT_UI1:
  383. fSame = pvar1->bVal == pvar2->bVal;
  384. break;
  385. case VT_I2:
  386. case VT_UI2:
  387. fSame = pvar1->iVal == pvar2->iVal;
  388. break;
  389. case VT_BOOL:
  390. fSame = _Compare_VT_BOOL(pvar1->boolVal, pvar2->boolVal);
  391. break;
  392. case VT_I4:
  393. case VT_UI4:
  394. case VT_R4:
  395. case VT_ERROR:
  396. fSame = pvar1->lVal == pvar2->lVal;
  397. break;
  398. case VT_I8:
  399. case VT_UI8:
  400. case VT_R8:
  401. case VT_CY:
  402. case VT_DATE:
  403. case VT_FILETIME:
  404. fSame = pvar1->hVal.HighPart == pvar2->hVal.HighPart
  405. &&
  406. pvar1->hVal.LowPart == pvar2->hVal.LowPart;
  407. break;
  408. case VT_CLSID:
  409. fSame = memcmp(pvar1->puuid, pvar2->puuid, sizeof(CLSID)) == 0;
  410. break;
  411. case VT_BLOB:
  412. case VT_BLOB_OBJECT:
  413. fSame = ( pvar1->blob.cbSize == pvar2->blob.cbSize );
  414. if (fSame)
  415. {
  416. fSame = memcmp(
  417. pvar1->blob.pBlobData,
  418. pvar2->blob.pBlobData,
  419. pvar1->blob.cbSize) == 0;
  420. }
  421. break;
  422. case VT_CF:
  423. fSame = _Compare_VT_CF(pvar1->pclipdata, pvar2->pclipdata);
  424. break;
  425. case VT_BSTR:
  426. if (pvar1->bstrVal != NULL && pvar2->bstrVal != NULL)
  427. {
  428. fSame = ( BSTRLEN(pvar1->bstrVal) == BSTRLEN(pvar2->bstrVal) );
  429. if (fSame)
  430. {
  431. fSame = memcmp(
  432. pvar1->bstrVal,
  433. pvar2->bstrVal,
  434. BSTRLEN(pvar1->bstrVal)) == 0;
  435. }
  436. }
  437. else
  438. {
  439. fSame = pvar1->bstrVal == pvar2->bstrVal;
  440. }
  441. break;
  442. case VT_LPSTR:
  443. if (pvar1->pszVal != NULL && pvar2->pszVal != NULL)
  444. {
  445. fSame = strcmp(pvar1->pszVal, pvar2->pszVal) == 0;
  446. }
  447. else
  448. {
  449. fSame = pvar1->pszVal == pvar2->pszVal;
  450. }
  451. break;
  452. case VT_STREAM:
  453. case VT_STREAMED_OBJECT:
  454. case VT_STORAGE:
  455. case VT_STORED_OBJECT:
  456. case VT_LPWSTR:
  457. if (pvar1->pwszVal != NULL && pvar2->pwszVal != NULL)
  458. {
  459. fSame = Prop_wcscmp(pvar1->pwszVal, pvar2->pwszVal) == 0;
  460. }
  461. else
  462. {
  463. fSame = pvar1->pwszVal == pvar2->pwszVal;
  464. }
  465. break;
  466. case VT_VECTOR | VT_I1:
  467. case VT_VECTOR | VT_UI1:
  468. fSame = ( pvar1->caub.cElems == pvar2->caub.cElems );
  469. if (fSame)
  470. {
  471. fSame = memcmp(
  472. pvar1->caub.pElems,
  473. pvar2->caub.pElems,
  474. pvar1->caub.cElems * sizeof(pvar1->caub.pElems[0])) == 0;
  475. }
  476. break;
  477. case VT_VECTOR | VT_I2:
  478. case VT_VECTOR | VT_UI2:
  479. fSame = ( pvar1->cai.cElems == pvar2->cai.cElems );
  480. if (fSame)
  481. {
  482. fSame = memcmp(
  483. pvar1->cai.pElems,
  484. pvar2->cai.pElems,
  485. pvar1->cai.cElems * sizeof(pvar1->cai.pElems[0])) == 0;
  486. }
  487. break;
  488. case VT_VECTOR | VT_BOOL:
  489. fSame = ( pvar1->cabool.cElems == pvar2->cabool.cElems );
  490. if (fSame)
  491. {
  492. for (i = 0; i < pvar1->cabool.cElems; i++)
  493. {
  494. fSame = _Compare_VT_BOOL(
  495. pvar1->cabool.pElems[i],
  496. pvar2->cabool.pElems[i]);
  497. if (!fSame)
  498. {
  499. break;
  500. }
  501. }
  502. }
  503. break;
  504. case VT_VECTOR | VT_I4:
  505. case VT_VECTOR | VT_UI4:
  506. case VT_VECTOR | VT_R4:
  507. case VT_VECTOR | VT_ERROR:
  508. fSame = ( pvar1->cal.cElems == pvar2->cal.cElems );
  509. if (fSame)
  510. {
  511. fSame = memcmp(
  512. pvar1->cal.pElems,
  513. pvar2->cal.pElems,
  514. pvar1->cal.cElems * sizeof(pvar1->cal.pElems[0])) == 0;
  515. }
  516. break;
  517. case VT_VECTOR | VT_I8:
  518. case VT_VECTOR | VT_UI8:
  519. case VT_VECTOR | VT_R8:
  520. case VT_VECTOR | VT_CY:
  521. case VT_VECTOR | VT_DATE:
  522. case VT_VECTOR | VT_FILETIME:
  523. fSame = ( pvar1->cah.cElems == pvar2->cah.cElems );
  524. if (fSame)
  525. {
  526. fSame = memcmp(
  527. pvar1->cah.pElems,
  528. pvar2->cah.pElems,
  529. pvar1->cah.cElems *
  530. sizeof(pvar1->cah.pElems[0])) == 0;
  531. }
  532. break;
  533. case VT_VECTOR | VT_CLSID:
  534. fSame = ( pvar1->cauuid.cElems == pvar2->cauuid.cElems );
  535. if (fSame)
  536. {
  537. fSame = memcmp(
  538. pvar1->cauuid.pElems,
  539. pvar2->cauuid.pElems,
  540. pvar1->cauuid.cElems *
  541. sizeof(pvar1->cauuid.pElems[0])) == 0;
  542. }
  543. break;
  544. case VT_VECTOR | VT_CF:
  545. fSame = ( pvar1->caclipdata.cElems == pvar2->caclipdata.cElems );
  546. if (fSame)
  547. {
  548. for (i = 0; i < pvar1->caclipdata.cElems; i++)
  549. {
  550. fSame = _Compare_VT_CF(
  551. &pvar1->caclipdata.pElems[i],
  552. &pvar2->caclipdata.pElems[i]);
  553. if (!fSame)
  554. {
  555. break;
  556. }
  557. }
  558. }
  559. break;
  560. case VT_VECTOR | VT_BSTR:
  561. fSame = ( pvar1->cabstr.cElems == pvar2->cabstr.cElems );
  562. if (fSame)
  563. {
  564. for (i = 0; i < pvar1->cabstr.cElems; i++)
  565. {
  566. if (pvar1->cabstr.pElems[i] != NULL &&
  567. pvar2->cabstr.pElems[i] != NULL)
  568. {
  569. fSame = ( BSTRLEN(pvar1->cabstr.pElems[i])
  570. ==
  571. BSTRLEN(pvar2->cabstr.pElems[i]) );
  572. if (fSame)
  573. {
  574. fSame = memcmp(
  575. pvar1->cabstr.pElems[i],
  576. pvar2->cabstr.pElems[i],
  577. BSTRLEN(pvar1->cabstr.pElems[i])) == 0;
  578. }
  579. }
  580. else
  581. {
  582. fSame = pvar1->cabstr.pElems[i] == pvar2->cabstr.pElems[i];
  583. }
  584. if (!fSame)
  585. {
  586. break;
  587. }
  588. }
  589. }
  590. break;
  591. case VT_VECTOR | VT_LPSTR:
  592. fSame = ( pvar1->calpstr.cElems == pvar2->calpstr.cElems );
  593. if (fSame)
  594. {
  595. for (i = 0; i < pvar1->calpstr.cElems; i++)
  596. {
  597. if (pvar1->calpstr.pElems[i] != NULL &&
  598. pvar2->calpstr.pElems[i] != NULL)
  599. {
  600. fSame = strcmp(
  601. pvar1->calpstr.pElems[i],
  602. pvar2->calpstr.pElems[i]) == 0;
  603. }
  604. else
  605. {
  606. fSame = pvar1->calpstr.pElems[i] ==
  607. pvar2->calpstr.pElems[i];
  608. }
  609. if (!fSame)
  610. {
  611. break;
  612. }
  613. }
  614. }
  615. break;
  616. case VT_VECTOR | VT_LPWSTR:
  617. fSame = ( pvar1->calpwstr.cElems == pvar2->calpwstr.cElems );
  618. if (fSame)
  619. {
  620. for (i = 0; i < pvar1->calpwstr.cElems; i++)
  621. {
  622. if (pvar1->calpwstr.pElems[i] != NULL &&
  623. pvar2->calpwstr.pElems[i] != NULL)
  624. {
  625. fSame = Prop_wcscmp(
  626. pvar1->calpwstr.pElems[i],
  627. pvar2->calpwstr.pElems[i]) == 0;
  628. }
  629. else
  630. {
  631. fSame = pvar1->calpwstr.pElems[i] ==
  632. pvar2->calpwstr.pElems[i];
  633. }
  634. if (!fSame)
  635. {
  636. break;
  637. }
  638. }
  639. }
  640. break;
  641. case VT_VECTOR | VT_VARIANT:
  642. fSame = ( pvar1->capropvar.cElems == pvar2->capropvar.cElems );
  643. if (fSame)
  644. {
  645. for (i = 0; i < pvar1->capropvar.cElems; i++)
  646. {
  647. fSame = PropTestCompareVariants(
  648. CodePage,
  649. &pvar1->capropvar.pElems[i],
  650. &pvar2->capropvar.pElems[i]);
  651. if (!fSame)
  652. {
  653. break;
  654. }
  655. }
  656. }
  657. break;
  658. default:
  659. PROPASSERT(!"Invalid type for PROPVARIANT Comparison");
  660. fSame = FALSE;
  661. break;
  662. }
  663. return(fSame);
  664. }