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.

1597 lines
46 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994
  5. //
  6. // File: ntpropb.cxx
  7. //
  8. // Contents: Property set implementation based on OLE Appendix B.
  9. //
  10. //---------------------------------------------------------------------------
  11. #include "pch.cxx"
  12. #include "h/propvar.hxx"
  13. #define Dbg DEBTRACE_NTPROP
  14. #define DbgS(s) (NT_SUCCESS(s)? Dbg : DEBTRACE_ERROR)
  15. #if DBG
  16. ULONG DebugLevel = DEBTRACE_ERROR;
  17. //ULONG DebugLevel = DEBTRACE_ERROR | DEBTRACE_CREATESTREAM;
  18. //ULONG DebugLevel = DEBTRACE_ERROR | MAXULONG;
  19. ULONG DebugIndent;
  20. ULONG cAlloc;
  21. ULONG cFree;
  22. #endif
  23. UNICODECALLOUTS UnicodeCallouts =
  24. {
  25. WIN32_UNICODECALLOUTS
  26. };
  27. //+---------------------------------------------------------------------------
  28. // Function: RtlSetUnicodeCallouts, public
  29. //
  30. // Synopsis: Set the Unicode conversion function pointers
  31. //
  32. // Arguments: [pUnicodeCallouts] -- Unicode callouts table
  33. //
  34. // Returns: Nothing
  35. //---------------------------------------------------------------------------
  36. VOID PROPSYSAPI PROPAPI
  37. RtlSetUnicodeCallouts(
  38. IN UNICODECALLOUTS *pUnicodeCallouts)
  39. {
  40. UnicodeCallouts = *pUnicodeCallouts;
  41. }
  42. //+---------------------------------------------------------------------------
  43. // Function: RtlCreatePropertySet, public
  44. //
  45. // Synopsis: Allocate and initialize a property set context
  46. //
  47. // Arguments: [ms] -- Nt Mapped Stream
  48. // [Flags] -- *one* of READ/WRITE/CREATE/CREATEIF/DELETE
  49. // [pguid] -- property set guid (create only)
  50. // [pclsid] -- CLASSID of propset code (create only)
  51. // [ma] -- caller's memory allocator
  52. // [LocaleId] -- Locale Id (create only)
  53. // [pOSVersion] -- pointer to the OS Version header field
  54. // [pCodePage] -- pointer to new/returned CodePage of propset
  55. // [pnp] -- pointer to returned property set context
  56. //
  57. // Returns: Status code
  58. //---------------------------------------------------------------------------
  59. NTSTATUS PROPSYSAPI PROPAPI
  60. RtlCreatePropertySet(
  61. IN NTMAPPEDSTREAM ms, // Nt Mapped Stream
  62. IN USHORT Flags, // *one* of READ/WRITE/CREATE/CREATEIF/DELETE
  63. OPTIONAL IN GUID const *pguid, // property set guid (create only)
  64. OPTIONAL IN GUID const *pclsid, // CLASSID of propset code (create only)
  65. IN NTMEMORYALLOCATOR ma, // caller's memory allocator
  66. IN ULONG LocaleId, // Locale Id (create only)
  67. OPTIONAL OUT ULONG *pOSVersion, // OS Version from the propset header
  68. IN OUT USHORT *pCodePage, // IN: CodePage of property set (create only)
  69. // OUT: CodePage of property set (always)
  70. OUT NTPROP *pnp) // pointer to return prop set context
  71. {
  72. NTSTATUS Status;
  73. CMappedStream *pmstm = (CMappedStream *) ms;
  74. CPropertySetStream *ppsstm = NULL;
  75. BOOLEAN fOpened = FALSE;
  76. DebugTrace(0, Dbg, ("RtlCreatePropertySet(ms=%x, f=%x, codepage=%x)\n",
  77. ms,
  78. Flags,
  79. *pCodePage));
  80. *pnp = NULL;
  81. Status = STATUS_INVALID_PARAMETER;
  82. if( pOSVersion != NULL )
  83. *pOSVersion = PROPSETHDR_OSVERSION_UNKNOWN;
  84. // Validate the input flags
  85. if (Flags & ~(CREATEPROP_MODEMASK | CREATEPROP_NONSIMPLE))
  86. {
  87. DebugTrace(0, DbgS(Status), (
  88. "RtlCreatePropertySet(ms=%x, Flags=%x) ==> bad flags!\n",
  89. ms,
  90. Flags));
  91. goto Exit;
  92. }
  93. switch (Flags & CREATEPROP_MODEMASK)
  94. {
  95. case CREATEPROP_DELETE:
  96. case CREATEPROP_CREATE:
  97. case CREATEPROP_CREATEIF:
  98. case CREATEPROP_WRITE:
  99. if (!pmstm->IsWriteable())
  100. {
  101. Status = STATUS_ACCESS_DENIED;
  102. goto Exit;
  103. }
  104. // FALLTHROUGH
  105. case CREATEPROP_READ:
  106. if (ma == NULL)
  107. {
  108. goto Exit;
  109. }
  110. break;
  111. default:
  112. DebugTrace(0, DbgS(Status), (
  113. "RtlCreatePropertySet(ms=%x, Flags=%x) ==> invalid mode!\n",
  114. ms,
  115. Flags));
  116. goto Exit;
  117. }
  118. ppsstm = new CPropertySetStream(
  119. Flags,
  120. pmstm,
  121. (PMemoryAllocator *) ma);
  122. if (ppsstm == NULL)
  123. {
  124. Status = STATUS_INSUFFICIENT_RESOURCES;
  125. goto Exit;
  126. }
  127. else
  128. {
  129. ppsstm->Open(pguid, pclsid, LocaleId,
  130. pOSVersion,
  131. *pCodePage,
  132. &Status);
  133. if( !NT_SUCCESS(Status) ) goto Exit;
  134. *pCodePage = ppsstm->GetCodePage();
  135. *pnp = (NTPROP) ppsstm;
  136. }
  137. // ----
  138. // Exit
  139. // ----
  140. Exit:
  141. // If we created a CPropertySetStream object, but
  142. // the overall operation failed, we must close/delete
  143. // the object. Note that we must do this after
  144. // the above unlock, since ppsstm will be gone after
  145. // this.
  146. if (!NT_SUCCESS(Status) && ppsstm != NULL)
  147. {
  148. RtlClosePropertySet((NTPROP) ppsstm);
  149. }
  150. DebugTrace(0, DbgS(Status), (
  151. "RtlCreatePropertySet() ==> ms=%x, s=%x\n--------\n",
  152. *pnp,
  153. Status));
  154. return(Status);
  155. }
  156. //+---------------------------------------------------------------------------
  157. // Function: RtlClosePropertySet, public
  158. //
  159. // Synopsis: Delete a property set context
  160. //
  161. // Arguments: [np] -- property set context
  162. //
  163. // Returns: Status code
  164. //---------------------------------------------------------------------------
  165. NTSTATUS PROPSYSAPI PROPAPI
  166. RtlClosePropertySet(
  167. IN NTPROP np) // property set context
  168. {
  169. NTSTATUS Status = STATUS_SUCCESS;
  170. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  171. DebugTrace(0, Dbg, ("RtlClosePropertySet(np=%x)\n", np));
  172. ppsstm->Close(&Status);
  173. if( !NT_SUCCESS(Status) ) goto Exit;
  174. // ----
  175. // Exit
  176. // ----
  177. Exit:
  178. delete ppsstm;
  179. DebugTrace(0, DbgS(Status), ("RtlClosePropertySet() ==> s=%x(%x)\n", STATUS_SUCCESS, Status));
  180. return(STATUS_SUCCESS);
  181. }
  182. //+---------------------------------------------------------------------------
  183. // Function: RtlOnMappedStreamEvent, public
  184. //
  185. // Synopsis: Handle a MappedStream event. Every such
  186. // event requires a byte-swap of the property set
  187. // headers.
  188. //
  189. // Arguments: [np] -- property set context
  190. // [pbuf] -- property set buffer
  191. // [cbstm] -- size of mapped stream (or CBSTM_UNKNOWN)
  192. //
  193. // NOTE: It is assumed that the caller has already taken
  194. // the CPropertySetStream::Lock.
  195. //
  196. // Returns: Status code
  197. //---------------------------------------------------------------------------
  198. NTSTATUS PROPSYSAPI PROPAPI
  199. RtlOnMappedStreamEvent(
  200. IN VOID * np, // property set context (an NTPROP)
  201. IN VOID *pbuf, // property set buffer
  202. IN ULONG cbstm )
  203. {
  204. NTSTATUS Status = STATUS_SUCCESS;
  205. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  206. DebugTrace(0, Dbg, ("RtlOnMappedStreamEvent(np=%x)\n", np));
  207. // Byte-swap the property set headers.
  208. ppsstm->ByteSwapHeaders((PROPERTYSETHEADER*) pbuf, cbstm, &Status );
  209. if( !NT_SUCCESS(Status) ) goto Exit;
  210. // ----
  211. // Exit
  212. // ----
  213. Exit:
  214. DebugTrace(0, DbgS(Status), ("RtlOnMappedStreamEvent() ==> s=%x\n", Status));
  215. return(Status);
  216. } // RtlOnMappedStreamEvent()
  217. //+---------------------------------------------------------------------------
  218. // Function: RtlFlushPropertySet, public
  219. //
  220. // Synopsis: Flush property set changes to disk
  221. //
  222. // Arguments: [np] -- property set context
  223. //
  224. // Returns: Status code
  225. //---------------------------------------------------------------------------
  226. NTSTATUS PROPSYSAPI PROPAPI
  227. RtlFlushPropertySet(
  228. IN NTPROP np) // property set context
  229. {
  230. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  231. NTSTATUS Status = STATUS_SUCCESS;
  232. DebugTrace(0, Dbg, ("RtlFlushPropertySet(np=%x)\n", np));
  233. if (ppsstm->IsModified())
  234. {
  235. ppsstm->ReOpen(&Status); // Reload header/size info
  236. if( !NT_SUCCESS(Status) ) goto Exit;
  237. ppsstm->Validate(&Status);
  238. if( !NT_SUCCESS(Status) ) goto Exit;
  239. ppsstm->Flush(&Status);
  240. if( !NT_SUCCESS(Status) ) goto Exit;
  241. ppsstm->Validate(&Status);
  242. if( !NT_SUCCESS(Status) ) goto Exit;
  243. }
  244. DebugTrace(0, DbgS(Status), ("RtlFlushPropertySet() ==> s=%x\n--------\n", Status));
  245. Exit:
  246. return(Status);
  247. }
  248. //+---------------------------------------------------------------------------
  249. // Function: MapNameToPropId, private
  250. //
  251. // Synopsis: Find an available propid and map it to the passed name
  252. //
  253. // Arguments: [ppsstm] -- property set stream
  254. // [CodePage] -- property set codepage
  255. // [aprs] -- array of property specifiers
  256. // [cprop] -- count of property specifiers
  257. // [iprop] -- index of propspec with name to map
  258. // [pidStart] -- first PROPID to start mapping attempts
  259. // [pstatus] -- NTSTATUS code
  260. //
  261. // Returns: PROPID mapped to passed name
  262. //
  263. // Note: Find the first unused propid starting at pidStart.
  264. //---------------------------------------------------------------------------
  265. PROPID
  266. MapNameToPropId(
  267. IN CPropertySetStream *ppsstm, // property set stream
  268. IN USHORT CodePage,
  269. IN PROPSPEC const aprs[], // array of property specifiers
  270. IN ULONG cprop,
  271. IN ULONG iprop,
  272. IN PROPID pidStart,
  273. OUT NTSTATUS *pstatus)
  274. {
  275. PROPID pid = PID_ILLEGAL;
  276. OLECHAR const *poszName;
  277. *pstatus = STATUS_SUCCESS;
  278. PROPASSERT(aprs[iprop].ulKind == PRSPEC_LPWSTR);
  279. poszName = aprs[iprop].lpwstr;
  280. #ifdef LITTLEENDIAN // this check will only work for litte Endian
  281. PROPASSERT(IsOLECHARString(poszName, MAXULONG));
  282. #endif
  283. for (pid = pidStart; ; pid++)
  284. {
  285. ULONG i;
  286. OLECHAR aocName[CCH_MAXPROPNAMESZ];
  287. ULONG cbName = sizeof(aocName);
  288. // The caller must specify a starting propid of 2 or larger, and we
  289. // must not increment into the reserved propids.
  290. if (pid == PID_DICTIONARY ||
  291. pid == PID_CODEPAGE ||
  292. pid < PID_FIRST_USABLE)
  293. {
  294. *pstatus = STATUS_INVALID_PARAMETER;
  295. goto Exit;
  296. }
  297. // Do not assign any propids that explitly appear in the array of
  298. // propspecs involved in this RtlSetProperties call, nor any propids
  299. // that are associated with any names in the propspec array.
  300. for (i = 0; i < cprop; i++)
  301. {
  302. if (i != iprop) // skip the entry we are mapping
  303. {
  304. // Is the current PID in Propspec[]?
  305. if (aprs[i].ulKind == PRSPEC_PROPID &&
  306. aprs[i].propid == pid)
  307. {
  308. goto nextpid; // skip colliding pid
  309. }
  310. // Is the current PID already used in the property set?
  311. if (aprs[i].ulKind == PRSPEC_LPWSTR &&
  312. ppsstm->QueryPropid(aprs[i].lpwstr, pstatus) == pid)
  313. {
  314. goto nextpid; // skip colliding pid
  315. }
  316. if (!NT_SUCCESS(*pstatus)) goto Exit;
  317. }
  318. } // for (i = 0; i < cprop; i++)
  319. // Do not assign any propids that currently map to any name.
  320. // Note that the property name we are mapping does not appear in the
  321. // dictionary -- the caller checked for this case already.
  322. if (!ppsstm->QueryPropertyNameBuf(pid, aocName, &cbName, pstatus))
  323. {
  324. // The property name could not be found in the dictionary
  325. ULONG cbT;
  326. SERIALIZEDPROPERTYVALUE const *pprop;
  327. // was the name not found due to an error in QueryProperyBuf?
  328. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  329. // Do not assign any propids that currently have a property value.
  330. pprop = ppsstm->GetValue(pid, &cbT, pstatus);
  331. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  332. if (pprop == NULL)
  333. {
  334. DebugTrace(0, Dbg, (
  335. "MapNameToPropId(Set Entry: pid=%x, name=L'%ws')\n",
  336. pid,
  337. poszName));
  338. // Add the caller-provided name to the dictionary, using
  339. // the PID that we now know is nowhere in use.
  340. ppsstm->SetPropertyNames(1, &pid, &poszName, pstatus);
  341. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  342. ppsstm->Validate(pstatus);
  343. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  344. break;
  345. } // if (pprop == NULL)
  346. } // if (!ppsstm->QueryPropertyNameBuf(pid, awcName,
  347. nextpid:
  348. ;
  349. } // for (pid = pidStart; ; pid++)
  350. Exit:
  351. return(pid);
  352. }
  353. //+---------------------------------------------------------------------------
  354. // Function: ConvertVariantToPropInfo, private
  355. //
  356. // Synopsis: Convert variant property values to PROPERTY_INFORMATION values
  357. //
  358. // Arguments: [ppsstm] -- property set stream
  359. // [cprop] -- property count
  360. // [pidNameFirst] -- first PROPID for new named properties
  361. // [aprs] -- array of property specifiers
  362. // [apid] -- buffer for array of propids
  363. // [avar] -- array of PROPVARIANTs
  364. // [apinfo] -- output array of property info
  365. //
  366. // Returns: none
  367. //
  368. //---------------------------------------------------------------------------
  369. VOID
  370. ConvertVariantToPropInfo(
  371. IN CPropertySetStream *ppsstm, // property set stream
  372. IN ULONG cprop, // property count
  373. IN PROPID pidNameFirst, // first PROPID for new named properties
  374. IN PROPSPEC const aprs[], // array of property specifiers
  375. OPTIONAL OUT PROPID apid[], // buffer for array of propids
  376. OPTIONAL IN PROPVARIANT const avar[],// array of properties+values
  377. OUT PROPERTY_INFORMATION *apinfo, // output array of property info
  378. OUT NTSTATUS *pstatus)
  379. {
  380. *pstatus = STATUS_SUCCESS;
  381. USHORT CodePage = ppsstm->GetCodePage();
  382. PROPID pidStart = pidNameFirst;
  383. ULONG iprop;
  384. for (iprop = 0; iprop < cprop; iprop++)
  385. {
  386. PROPID pid;
  387. ULONG cbprop;
  388. switch(aprs[iprop].ulKind)
  389. {
  390. case PRSPEC_LPWSTR:
  391. {
  392. PROPASSERT(IsOLECHARString(aprs[iprop].lpwstr, MAXULONG));
  393. pid = ppsstm->QueryPropid(aprs[iprop].lpwstr, pstatus);
  394. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  395. if (pid == PID_ILLEGAL && avar != NULL)
  396. {
  397. pid = MapNameToPropId(
  398. ppsstm,
  399. CodePage,
  400. aprs,
  401. cprop,
  402. iprop,
  403. pidStart,
  404. pstatus);
  405. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  406. pidStart = pid + 1;
  407. }
  408. break;
  409. }
  410. case PRSPEC_PROPID:
  411. pid = aprs[iprop].propid;
  412. break;
  413. default:
  414. PROPASSERT(!"Bad ulKind");
  415. *pstatus = STATUS_INVALID_PARAMETER;
  416. goto Exit;
  417. break;
  418. }
  419. if (apid != NULL)
  420. {
  421. apid[iprop] = pid;
  422. }
  423. // RtlConvertVariantToProperty returns NULL on overflow and
  424. // Raises on bad data.
  425. cbprop = 0; // Assume property deletion
  426. if (pid != PID_ILLEGAL && avar != NULL)
  427. {
  428. RtlConvertVariantToProperty(
  429. &avar[iprop],
  430. CodePage,
  431. NULL,
  432. &cbprop,
  433. pid,
  434. FALSE,
  435. pstatus);
  436. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  437. PROPASSERT(cbprop == DwordAlign(cbprop));
  438. }
  439. apinfo[iprop].cbprop = cbprop;
  440. apinfo[iprop].pid = pid;
  441. }
  442. // ----
  443. // Exit
  444. // ----
  445. Exit:
  446. return;
  447. }
  448. //+---------------------------------------------------------------------------
  449. // Function: RtlSetProperties, public
  450. //
  451. // Synopsis: Set property values for a property set
  452. //
  453. // Arguments: [np] -- property set context
  454. // [cprop] -- property count
  455. // [pidNameFirst] -- first PROPID for new named properties
  456. // [aprs] -- array of property specifiers
  457. // [apid] -- buffer for array of propids
  458. // [avar] -- array of PROPVARIANTs
  459. //
  460. // Returns: Status code
  461. //---------------------------------------------------------------------------
  462. NTSTATUS PROPSYSAPI PROPAPI
  463. RtlSetProperties(
  464. IN NTPROP np, // property set context
  465. IN ULONG cprop, // property count
  466. IN PROPID pidNameFirst, // first PROPID for new named properties
  467. IN PROPSPEC const aprs[], // array of property specifiers
  468. OPTIONAL OUT PROPID apid[], // buffer for array of propids
  469. OPTIONAL IN PROPVARIANT const avar[]) // array of properties+values
  470. {
  471. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  472. NTSTATUS Status = STATUS_SUCCESS;
  473. PROPERTY_INFORMATION apinfoStack[6];
  474. PROPERTY_INFORMATION *apinfo = apinfoStack;
  475. DebugTrace(0, Dbg, (
  476. "RtlSetProperties(np=%x,cprop=%x,pidNameFirst=%x,aprs=%x,apid=%x)\n",
  477. np,
  478. cprop,
  479. pidNameFirst,
  480. aprs,
  481. apid));
  482. if( !NT_SUCCESS(Status) ) goto Exit;
  483. // Is the stack-based apinfo big enough?
  484. if (cprop > sizeof(apinfoStack)/sizeof(apinfoStack[0]))
  485. {
  486. // No - we need to allocate an apinfo.
  487. apinfo = new PROPERTY_INFORMATION[cprop];
  488. if (NULL == apinfo)
  489. {
  490. Status = STATUS_INSUFFICIENT_RESOURCES;
  491. goto Exit;
  492. }
  493. }
  494. ppsstm->ReOpen(&Status); // Reload header/size info
  495. if( !NT_SUCCESS(Status) ) goto Exit;
  496. ppsstm->Validate(&Status);
  497. if( !NT_SUCCESS(Status) ) goto Exit;
  498. ConvertVariantToPropInfo(
  499. ppsstm,
  500. cprop,
  501. pidNameFirst,
  502. aprs,
  503. apid,
  504. avar,
  505. apinfo,
  506. &Status);
  507. if( !NT_SUCCESS(Status) ) goto Exit;
  508. ppsstm->SetValue(cprop, avar, apinfo, &Status);
  509. if( !NT_SUCCESS(Status) ) goto Exit;
  510. ppsstm->Validate(&Status);
  511. if( !NT_SUCCESS(Status) ) goto Exit;
  512. // ----
  513. // Exit
  514. // ----
  515. Exit:
  516. // If we allocated a temporary apinfo buffer, free it.
  517. if (cprop > sizeof(apinfoStack)/sizeof(apinfoStack[0]))
  518. {
  519. delete [] apinfo;
  520. }
  521. DebugTrace(0, DbgS(Status), (
  522. "RtlSetProperties() ==> status=%x\n--------\n",
  523. Status));
  524. return(Status);
  525. }
  526. //+---------------------------------------------------------------------------
  527. // Function: RtlQueryProperties, public
  528. //
  529. // Synopsis: Query property values from a property set
  530. //
  531. // Arguments: [np] -- property set context
  532. // [cprop] -- property count
  533. // [aprs] -- array of property specifiers
  534. // [apid] -- buffer for array of propids
  535. // [avar] -- array of PROPVARIANTs
  536. //
  537. // Returns: Status code
  538. //---------------------------------------------------------------------------
  539. NTSTATUS PROPSYSAPI PROPAPI
  540. RtlQueryProperties(
  541. IN NTPROP np, // property set context
  542. IN ULONG cprop, // property count
  543. IN PROPSPEC const aprs[], // array of property specifiers
  544. OPTIONAL OUT PROPID apid[], // buffer for array of propids
  545. IN OUT PROPVARIANT *avar, // IN: array of uninitialized PROPVARIANTs,
  546. // OUT: may contain pointers to alloc'd memory
  547. OUT ULONG *pcpropFound) // count of property values retrieved
  548. {
  549. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  550. SERIALIZEDPROPERTYVALUE const *pprop = NULL;
  551. NTSTATUS Status = STATUS_SUCCESS;
  552. ULONG iprop;
  553. DebugTrace(0, Dbg, (
  554. "RtlQueryProperties(np=%x, cprop=%x, aprs=%x, apid=%x)\n",
  555. np,
  556. cprop,
  557. aprs,
  558. apid));
  559. // Initialize the variant array enough to allow it to be cleaned up
  560. // by the caller (even on partial failure).
  561. *pcpropFound = 0;
  562. // Zero-ing out the caller-provided PropVariants, essentially
  563. // sets them all to VT_EMPTY. It also zeros out the data portion,
  564. // which prevents cleanup problems in error paths.
  565. RtlZeroMemory(avar, cprop * sizeof(avar[0]));
  566. ppsstm->ReOpen(&Status); // Reload header/size info
  567. if( !NT_SUCCESS(Status) ) goto Exit;
  568. ppsstm->Validate(&Status);
  569. if( !NT_SUCCESS(Status) ) goto Exit;
  570. for (iprop = 0; iprop < cprop; iprop++)
  571. {
  572. OLECHAR *poc;
  573. PROPID pid;
  574. ULONG cbprop;
  575. switch(aprs[iprop].ulKind)
  576. {
  577. case PRSPEC_LPWSTR:
  578. poc = aprs[iprop].lpwstr;
  579. pid = ppsstm->QueryPropid(poc, &Status);
  580. if( !NT_SUCCESS(Status) ) goto Exit;
  581. break;
  582. case PRSPEC_PROPID:
  583. pid = aprs[iprop].propid;
  584. break;
  585. default:
  586. PROPASSERT(!"Bad ulKind");
  587. Status = STATUS_INVALID_PARAMETER;
  588. goto Exit;
  589. }
  590. pprop = ppsstm->GetValue(pid, &cbprop, &Status);
  591. if( !NT_SUCCESS(Status) ) goto Exit;
  592. if (pprop != NULL)
  593. {
  594. (*pcpropFound)++;
  595. RtlConvertPropertyToVariant( pprop,
  596. ppsstm->GetCodePage(),
  597. &avar[iprop],
  598. ppsstm->GetAllocator(),
  599. &Status);
  600. if( !NT_SUCCESS(Status) ) goto Exit;
  601. }
  602. if (apid != NULL)
  603. {
  604. apid[iprop] = pid;
  605. }
  606. } // for (iprop = 0; iprop < cprop; iprop++)
  607. ppsstm->Validate(&Status);
  608. if( !NT_SUCCESS(Status) ) goto Exit;
  609. // ----
  610. // Exit
  611. // ----
  612. Exit:
  613. if( !NT_SUCCESS(Status) )
  614. {
  615. CleanupVariants(avar, cprop, ppsstm->GetAllocator());
  616. }
  617. DebugTrace(0, DbgS(Status), (
  618. "RtlQueryProperties() ==> s=%x\n--------\n",
  619. Status));
  620. return(Status);
  621. }
  622. //+---------------------------------------------------------------------------
  623. // Function: RtlEnumerateProperties, public
  624. //
  625. // Synopsis: Enumerate properties in a property set
  626. //
  627. // Arguments: [np] -- property set context
  628. // [cskip] -- count of properties to skip
  629. // [pcprop] -- pointer to property count
  630. // [Flags] -- flags: No Names (propids only), etc.
  631. // [asps] -- array of STATPROPSTGs
  632. //
  633. // Returns: Status code
  634. //---------------------------------------------------------------------------
  635. NTSTATUS PROPSYSAPI PROPAPI
  636. RtlEnumerateProperties(
  637. IN NTPROP np, // property set context
  638. IN ULONG Flags, // flags: No Names (propids only), etc.
  639. IN ULONG *pkey, // count of properties to skip
  640. IN OUT ULONG *pcprop, // pointer to property count
  641. OPTIONAL OUT PROPSPEC aprs[],// IN: array of uninitialized PROPSPECs
  642. // OUT: may contain pointers to alloc'd strings
  643. OPTIONAL OUT STATPROPSTG asps[]) // IN: array of uninitialized STATPROPSTGs
  644. // OUT: may contain pointers to alloc'd strings
  645. {
  646. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  647. NTSTATUS Status = STATUS_SUCCESS;
  648. SERIALIZEDPROPERTYVALUE const *pprop = NULL;
  649. PROPSPEC *pprs;
  650. STATPROPSTG *psps;
  651. PROPID *ppidBase = NULL;
  652. ULONG i;
  653. ULONG cpropin;
  654. PROPID apidStack[20];
  655. PROPID *ppid;
  656. ULONG cprop;
  657. PMemoryAllocator *pma = ppsstm->GetAllocator();
  658. DebugTrace(0, Dbg, (
  659. "RtlEnumerateProperties(np=%x, f=%x, key=%x, cprop=%x, aprs=%x, asps=%x)\n",
  660. np,
  661. Flags,
  662. *pkey,
  663. *pcprop,
  664. aprs,
  665. asps));
  666. cpropin = *pcprop;
  667. // Eliminate confusion for easy cleanup
  668. if (aprs != NULL)
  669. {
  670. // Set all the PropSpecs to PROPID (which require
  671. // no cleanup).
  672. for (i = 0; i < cpropin; i++)
  673. {
  674. aprs[i].ulKind = PRSPEC_PROPID;
  675. }
  676. }
  677. // Zero all pointers in the array for easy cleanup
  678. if (asps != NULL)
  679. {
  680. RtlZeroMemory(asps, cpropin * sizeof(asps[0]));
  681. }
  682. ppidBase = NULL;
  683. cprop = ppsstm->ReOpen(&Status); // Reload header/size info
  684. if( !NT_SUCCESS(Status) ) goto Exit;
  685. if (cprop > cpropin)
  686. {
  687. cprop = cpropin;
  688. }
  689. ppsstm->Validate(&Status);
  690. if( !NT_SUCCESS(Status) ) goto Exit;
  691. ppid = NULL;
  692. if (aprs != NULL || asps != NULL)
  693. {
  694. ppid = apidStack;
  695. if (cprop > sizeof(apidStack)/sizeof(apidStack[0]))
  696. {
  697. ppidBase = new PROPID[cprop];
  698. if (ppidBase == NULL)
  699. {
  700. Status = STATUS_INSUFFICIENT_RESOURCES;
  701. goto Exit;
  702. }
  703. ppid = ppidBase;
  704. }
  705. }
  706. ppsstm->EnumeratePropids(pkey, &cprop, ppid, &Status);
  707. if( !NT_SUCCESS(Status) ) goto Exit;
  708. *pcprop = cprop;
  709. if (ppid != NULL)
  710. {
  711. psps = asps;
  712. pprs = aprs;
  713. while (cprop-- > 0)
  714. {
  715. OLECHAR aocName[CCH_MAXPROPNAMESZ];
  716. ULONG cbName;
  717. ULONG cbprop;
  718. BOOLEAN fHasName;
  719. PROPASSERT(*ppid != PID_DICTIONARY && *ppid != PID_CODEPAGE);
  720. fHasName = FALSE;
  721. if ((Flags & ENUMPROP_NONAMES) == 0)
  722. {
  723. cbName = sizeof(aocName);
  724. fHasName = ppsstm->QueryPropertyNameBuf(
  725. *ppid,
  726. aocName,
  727. &cbName,
  728. &Status);
  729. if( !NT_SUCCESS(Status) ) goto Exit;
  730. }
  731. if (pprs != NULL)
  732. {
  733. PROPASSERT(pprs->ulKind == PRSPEC_PROPID);
  734. if (fHasName)
  735. {
  736. pprs->lpwstr = ppsstm->DuplicatePropertyName(
  737. aocName,
  738. cbName,
  739. &Status);
  740. if( !NT_SUCCESS(Status) ) goto Exit;
  741. PROPASSERT(pprs->lpwstr != NULL);
  742. // Make this assignment *after* memory allocation
  743. // succeeds so we free only valid pointers in below
  744. // cleanup code.
  745. pprs->ulKind = PRSPEC_LPWSTR;
  746. }
  747. else
  748. {
  749. pprs->propid = *ppid;
  750. }
  751. pprs++;
  752. } // if (pprs != NULL)
  753. if (psps != NULL)
  754. {
  755. pprop = ppsstm->GetValue(*ppid, &cbprop, &Status);
  756. if( !NT_SUCCESS(Status) ) goto Exit;
  757. PROPASSERT(psps->lpwstrName == NULL);
  758. if (fHasName)
  759. {
  760. psps->lpwstrName = ppsstm->DuplicatePropertyName(
  761. aocName,
  762. cbName,
  763. &Status);
  764. if( !NT_SUCCESS(Status) ) goto Exit;
  765. PROPASSERT(psps->lpwstrName != NULL);
  766. }
  767. psps->propid = *ppid;
  768. psps->vt = (VARTYPE) PropByteSwap(pprop->dwType);
  769. psps++;
  770. } // if (psps != NULL)
  771. ppid++;
  772. } // while (cprop-- > 0)
  773. } // if (ppid != NULL)
  774. ppsstm->Validate(&Status);
  775. if( !NT_SUCCESS(Status) ) goto Exit;
  776. // ----
  777. // Exit
  778. // ----
  779. Exit:
  780. delete [] ppidBase;
  781. if (!NT_SUCCESS(Status))
  782. {
  783. PMemoryAllocator *pma = ppsstm->GetAllocator();
  784. if (aprs != NULL)
  785. {
  786. for (i = 0; i < cpropin; i++)
  787. {
  788. if (aprs[i].ulKind == PRSPEC_LPWSTR)
  789. {
  790. pma->Free(aprs[i].lpwstr);
  791. aprs[i].ulKind = PRSPEC_PROPID;
  792. }
  793. }
  794. }
  795. if (asps != NULL)
  796. {
  797. for (i = 0; i < cpropin; i++)
  798. {
  799. if (asps[i].lpwstrName != NULL)
  800. {
  801. pma->Free(asps[i].lpwstrName);
  802. asps[i].lpwstrName = NULL;
  803. }
  804. }
  805. }
  806. } // if (!NT_SUCCESS(Status))
  807. #if DBG
  808. if (NT_SUCCESS(Status))
  809. {
  810. if (aprs != NULL)
  811. {
  812. for (i = 0; i < cpropin; i++)
  813. {
  814. if (aprs[i].ulKind == PRSPEC_LPWSTR)
  815. {
  816. PROPASSERT(aprs[i].lpwstr != NULL);
  817. PROPASSERT(ocslen(aprs[i].lpwstr) > 0);
  818. }
  819. }
  820. }
  821. if (asps != NULL)
  822. {
  823. for (i = 0; i < cpropin; i++)
  824. {
  825. if (asps[i].lpwstrName != NULL)
  826. {
  827. PROPASSERT(ocslen(asps[i].lpwstrName) > 0);
  828. }
  829. }
  830. }
  831. }
  832. #endif // DBG
  833. DebugTrace(0, DbgS(Status), (
  834. "RtlEnumerateProperties() ==> key=%x, cprop=%x, s=%x\n--------\n",
  835. *pkey,
  836. *pcprop,
  837. Status));
  838. return(Status);
  839. }
  840. //+---------------------------------------------------------------------------
  841. // Function: RtlQueryPropertyNames, public
  842. //
  843. // Synopsis: Read property names for PROPIDs in a property set
  844. //
  845. // Arguments: [np] -- property set context
  846. // [cprop] -- property count
  847. // [apid] -- array of PROPIDs
  848. // [aposz] -- array of pointers to OLECHAR strings
  849. //
  850. // Returns: Status code
  851. //---------------------------------------------------------------------------
  852. NTSTATUS PROPSYSAPI PROPAPI
  853. RtlQueryPropertyNames(
  854. IN NTPROP np, // property set context
  855. IN ULONG cprop, // property count
  856. IN PROPID const *apid, // PROPID array
  857. OUT OLECHAR *aposz[]) // OUT pointers to allocated strings
  858. {
  859. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  860. NTSTATUS Status = STATUS_SUCCESS;
  861. NTSTATUS StatusQuery = STATUS_SUCCESS;
  862. DebugTrace(0, Dbg, (
  863. "RtlQueryPropertyNames(np=%x, cprop=%x, apid=%x, aposz=%x)\n",
  864. np,
  865. cprop,
  866. apid,
  867. aposz));
  868. RtlZeroMemory(aposz, cprop * sizeof(aposz[0]));
  869. ppsstm->ReOpen(&Status); // Reload header/size info
  870. if( !NT_SUCCESS(Status) ) goto Exit;
  871. ppsstm->Validate(&Status);
  872. if( !NT_SUCCESS(Status) ) goto Exit;
  873. // we'will save the status from the following call. If there are no
  874. // other errors, we'll return it to the caller (it might contain a useful
  875. // success code
  876. ppsstm->QueryPropertyNames(cprop, apid, aposz, &StatusQuery);
  877. if( !NT_SUCCESS(StatusQuery) )
  878. {
  879. Status = StatusQuery;
  880. goto Exit;
  881. }
  882. ppsstm->Validate(&Status);
  883. if( !NT_SUCCESS(Status) ) goto Exit;
  884. // ----
  885. // Exit
  886. // ----
  887. Exit:
  888. DebugTrace(
  889. 0,
  890. Status == STATUS_BUFFER_ALL_ZEROS? Dbg : DbgS(Status),
  891. ("RtlQueryPropertyNames() ==> s=%x\n--------\n", Status));
  892. if( NT_SUCCESS(Status) )
  893. Status = StatusQuery;
  894. return(Status);
  895. } // RtlQueryPropertyNames()
  896. //+---------------------------------------------------------------------------
  897. // Function: RtlSetPropertyNames, public
  898. //
  899. // Synopsis: Write property names for PROPIDs in a property set
  900. //
  901. // Arguments: [np] -- property set context
  902. // [cprop] -- property count
  903. // [apid] -- array of PROPIDs
  904. // [aposz] -- array of pointers to OLECHAR strings
  905. //
  906. // Returns: Status code
  907. //---------------------------------------------------------------------------
  908. NTSTATUS PROPSYSAPI PROPAPI
  909. RtlSetPropertyNames(
  910. IN NTPROP np, // property set context
  911. IN ULONG cprop, // property count
  912. IN PROPID const *apid, // PROPID array
  913. IN OLECHAR const * const aposz[]) // pointers to property names
  914. {
  915. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  916. NTSTATUS Status = STATUS_SUCCESS;
  917. DebugTrace(0, Dbg, (
  918. "RtlSetPropertyNames(np=%x, cprop=%x, apid=%x, aposz=%x)\n",
  919. np,
  920. cprop,
  921. apid,
  922. aposz));
  923. ppsstm->ReOpen(&Status); // Reload header/size info
  924. if( !NT_SUCCESS(Status) ) goto Exit;
  925. ppsstm->Validate(&Status);
  926. if( !NT_SUCCESS(Status) ) goto Exit;
  927. ppsstm->SetPropertyNames(cprop, apid, aposz, &Status);
  928. if( !NT_SUCCESS(Status) ) goto Exit;
  929. ppsstm->Validate(&Status);
  930. if( !NT_SUCCESS(Status) ) goto Exit;
  931. // ----
  932. // Exit
  933. // ----
  934. Exit:
  935. DebugTrace(0, DbgS(Status), ("RtlSetPropertyNames() ==> s=%x\n--------\n", Status));
  936. return(Status);
  937. } // RtlSetPropertyNames()
  938. //+---------------------------------------------------------------------------
  939. // Function: RtlSetPropertySetClassId, public
  940. //
  941. // Synopsis: Set the property set's ClassId
  942. //
  943. // Arguments: [np] -- property set context
  944. // [pspss] -- pointer to STATPROPSETSTG
  945. //
  946. // Returns: Status code
  947. //---------------------------------------------------------------------------
  948. NTSTATUS PROPSYSAPI PROPAPI
  949. RtlSetPropertySetClassId(
  950. IN NTPROP np, // property set context
  951. IN GUID const *pclsid) // new CLASSID of propset code
  952. {
  953. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  954. NTSTATUS Status = STATUS_SUCCESS;
  955. DebugTrace(0, Dbg, ("RtlSetPropertySetClassId(np=%x)\n", np));
  956. ppsstm->ReOpen(&Status); // Reload header/size info
  957. if( !NT_SUCCESS(Status) ) goto Exit;
  958. ppsstm->Validate(&Status);
  959. if( !NT_SUCCESS(Status) ) goto Exit;
  960. ppsstm->SetClassId(pclsid, &Status);
  961. if( !NT_SUCCESS(Status) ) goto Exit;
  962. ppsstm->Validate(&Status);
  963. if( !NT_SUCCESS(Status) ) goto Exit;
  964. // ----
  965. // Exit
  966. // ----
  967. Exit:
  968. DebugTrace(0, DbgS(Status), ("RtlSetPropertySetClassId() ==> s=%x\n--------\n", Status));
  969. return(Status);
  970. } // RtlSetPropertySetClassId()
  971. //+---------------------------------------------------------------------------
  972. // Function: RtlQueryPropertySet, public
  973. //
  974. // Synopsis: Query the passed property set
  975. //
  976. // Arguments: [np] -- property set context
  977. // [pspss] -- pointer to STATPROPSETSTG
  978. //
  979. // Returns: Status code
  980. //---------------------------------------------------------------------------
  981. NTSTATUS PROPSYSAPI PROPAPI
  982. RtlQueryPropertySet(
  983. IN NTPROP np, // property set context
  984. OUT STATPROPSETSTG *pspss) // buffer for property set stat information
  985. {
  986. NTSTATUS Status = STATUS_SUCCESS;
  987. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  988. DebugTrace(0, Dbg, ("RtlQueryPropertySet(np=%x, pspss=%x)\n", np, pspss));
  989. RtlZeroMemory(pspss, sizeof(*pspss));
  990. ppsstm->ReOpen(&Status); // Reload header/size info
  991. if( !NT_SUCCESS(Status) ) goto Exit;
  992. ppsstm->Validate(&Status);
  993. if( !NT_SUCCESS(Status) ) goto Exit;
  994. ppsstm->QueryPropertySet(pspss, &Status);
  995. if( !NT_SUCCESS(Status) ) goto Exit;
  996. ppsstm->Validate(&Status);
  997. if( !NT_SUCCESS(Status) ) goto Exit;
  998. // ----
  999. // Exit
  1000. // ----
  1001. Exit:
  1002. DebugTrace(0, DbgS(Status), ("RtlQueryPropertySet() ==> s=%x\n--------\n", Status));
  1003. return(Status);
  1004. } // RtlQueryPropertySet()
  1005. inline BOOLEAN
  1006. _Compare_VT_BOOL(VARIANT_BOOL bool1, VARIANT_BOOL bool2)
  1007. {
  1008. // Allow any non-zero value to match any non-zero value
  1009. return((bool1 == FALSE) == (bool2 == FALSE));
  1010. }
  1011. BOOLEAN
  1012. _Compare_VT_CF(CLIPDATA *pclipdata1, CLIPDATA *pclipdata2)
  1013. {
  1014. BOOLEAN fSame;
  1015. if (pclipdata1 != NULL && pclipdata2 != NULL)
  1016. {
  1017. if (fSame =
  1018. pclipdata1->cbSize == pclipdata2->cbSize &&
  1019. pclipdata1->ulClipFmt == pclipdata2->ulClipFmt)
  1020. {
  1021. if (pclipdata1->pClipData != NULL && pclipdata2->pClipData != NULL)
  1022. {
  1023. fSame = memcmp(
  1024. pclipdata1->pClipData,
  1025. pclipdata2->pClipData,
  1026. CBPCLIPDATA(*pclipdata1)
  1027. ) == 0;
  1028. }
  1029. else
  1030. {
  1031. // They're the same if both are NULL, or if
  1032. // they have a zero length (if they have a zero
  1033. // length, either one may or may not be NULL, but they're
  1034. // still considered the same).
  1035. fSame = pclipdata1->pClipData == pclipdata2->pClipData
  1036. ||
  1037. CBPCLIPDATA(*pclipdata1) == 0;
  1038. }
  1039. }
  1040. }
  1041. else
  1042. {
  1043. fSame = pclipdata1 == pclipdata2;
  1044. }
  1045. return(fSame);
  1046. }
  1047. //+---------------------------------------------------------------------------
  1048. // Function: RtlCompareVariants, public
  1049. //
  1050. // Synopsis: Compare two passed PROPVARIANTs -- case sensitive for strings
  1051. //
  1052. // Arguments: [CodePage] -- CodePage
  1053. // [pvar1] -- pointer to PROPVARIANT
  1054. // [pvar2] -- pointer to PROPVARIANT
  1055. //
  1056. // Returns: TRUE if identical, else FALSE
  1057. //---------------------------------------------------------------------------
  1058. STDAPI_(BOOLEAN) PROPSYSAPI PROPAPI
  1059. RtlCompareVariants(
  1060. USHORT CodePage,
  1061. PROPVARIANT const *pvar1,
  1062. PROPVARIANT const *pvar2)
  1063. {
  1064. if (pvar1->vt != pvar2->vt)
  1065. {
  1066. return(FALSE);
  1067. }
  1068. BOOLEAN fSame;
  1069. ULONG i;
  1070. switch (pvar1->vt)
  1071. {
  1072. case VT_EMPTY:
  1073. case VT_NULL:
  1074. fSame = TRUE;
  1075. break;
  1076. #ifdef PROPVAR_VT_I1
  1077. case VT_I1:
  1078. #endif
  1079. case VT_UI1:
  1080. fSame = pvar1->bVal == pvar2->bVal;
  1081. break;
  1082. case VT_I2:
  1083. case VT_UI2:
  1084. fSame = pvar1->iVal == pvar2->iVal;
  1085. break;
  1086. case VT_BOOL:
  1087. fSame = _Compare_VT_BOOL(pvar1->boolVal, pvar2->boolVal);
  1088. break;
  1089. case VT_I4:
  1090. case VT_UI4:
  1091. case VT_R4:
  1092. case VT_ERROR:
  1093. fSame = pvar1->lVal == pvar2->lVal;
  1094. break;
  1095. case VT_I8:
  1096. case VT_UI8:
  1097. case VT_R8:
  1098. case VT_CY:
  1099. case VT_DATE:
  1100. case VT_FILETIME:
  1101. fSame = (pvar1->hVal.QuadPart == pvar2->hVal.QuadPart);
  1102. break;
  1103. case VT_CLSID:
  1104. fSame = memcmp(pvar1->puuid, pvar2->puuid, sizeof(CLSID)) == 0;
  1105. break;
  1106. case VT_BLOB:
  1107. case VT_BLOB_OBJECT:
  1108. if (fSame = pvar1->blob.cbSize == pvar2->blob.cbSize)
  1109. {
  1110. fSame = memcmp(
  1111. pvar1->blob.pBlobData,
  1112. pvar2->blob.pBlobData,
  1113. pvar1->blob.cbSize) == 0;
  1114. }
  1115. break;
  1116. case VT_CF:
  1117. fSame = _Compare_VT_CF(pvar1->pclipdata, pvar2->pclipdata);
  1118. break;
  1119. case VT_BSTR:
  1120. if (pvar1->bstrVal != NULL && pvar2->bstrVal != NULL)
  1121. {
  1122. if (fSame = BSTRLEN(pvar1->bstrVal) == BSTRLEN(pvar2->bstrVal))
  1123. {
  1124. fSame = memcmp(
  1125. pvar1->bstrVal,
  1126. pvar2->bstrVal,
  1127. BSTRLEN(pvar1->bstrVal)) == 0;
  1128. }
  1129. }
  1130. else
  1131. {
  1132. fSame = pvar1->bstrVal == pvar2->bstrVal;
  1133. }
  1134. break;
  1135. case VT_LPSTR:
  1136. if (pvar1->pszVal != NULL && pvar2->pszVal != NULL)
  1137. {
  1138. fSame = strcmp(pvar1->pszVal, pvar2->pszVal) == 0;
  1139. }
  1140. else
  1141. {
  1142. fSame = pvar1->pszVal == pvar2->pszVal;
  1143. }
  1144. break;
  1145. case VT_LPWSTR:
  1146. if (pvar1->pwszVal != NULL && pvar2->pwszVal != NULL)
  1147. {
  1148. fSame = Prop_wcscmp(pvar1->pwszVal, pvar2->pwszVal) == 0;
  1149. }
  1150. else
  1151. {
  1152. fSame = pvar1->pwszVal == pvar2->pwszVal;
  1153. }
  1154. break;
  1155. #ifdef PROPVAR_VT_I1
  1156. case VT_VECTOR | VT_I1:
  1157. #endif
  1158. case VT_VECTOR | VT_UI1:
  1159. if (fSame = pvar1->caub.cElems == pvar2->caub.cElems)
  1160. {
  1161. fSame = memcmp(
  1162. pvar1->caub.pElems,
  1163. pvar2->caub.pElems,
  1164. pvar1->caub.cElems * sizeof(pvar1->caub.pElems[0])) == 0;
  1165. }
  1166. break;
  1167. case VT_VECTOR | VT_I2:
  1168. case VT_VECTOR | VT_UI2:
  1169. if (fSame = pvar1->cai.cElems == pvar2->cai.cElems)
  1170. {
  1171. fSame = memcmp(
  1172. pvar1->cai.pElems,
  1173. pvar2->cai.pElems,
  1174. pvar1->cai.cElems * sizeof(pvar1->cai.pElems[0])) == 0;
  1175. }
  1176. break;
  1177. case VT_VECTOR | VT_BOOL:
  1178. if (fSame = pvar1->cabool.cElems == pvar2->cabool.cElems)
  1179. {
  1180. for (i = 0; i < pvar1->cabool.cElems; i++)
  1181. {
  1182. fSame = _Compare_VT_BOOL(
  1183. pvar1->cabool.pElems[i],
  1184. pvar2->cabool.pElems[i]);
  1185. if (!fSame)
  1186. {
  1187. break;
  1188. }
  1189. }
  1190. }
  1191. break;
  1192. case VT_VECTOR | VT_I4:
  1193. case VT_VECTOR | VT_UI4:
  1194. case VT_VECTOR | VT_R4:
  1195. case VT_VECTOR | VT_ERROR:
  1196. if (fSame = pvar1->cal.cElems == pvar2->cal.cElems)
  1197. {
  1198. fSame = memcmp(
  1199. pvar1->cal.pElems,
  1200. pvar2->cal.pElems,
  1201. pvar1->cal.cElems * sizeof(pvar1->cal.pElems[0])) == 0;
  1202. }
  1203. break;
  1204. case VT_VECTOR | VT_I8:
  1205. case VT_VECTOR | VT_UI8:
  1206. case VT_VECTOR | VT_R8:
  1207. case VT_VECTOR | VT_CY:
  1208. case VT_VECTOR | VT_DATE:
  1209. case VT_VECTOR | VT_FILETIME:
  1210. if (fSame = pvar1->cah.cElems == pvar2->cah.cElems)
  1211. {
  1212. fSame = memcmp(
  1213. pvar1->cah.pElems,
  1214. pvar2->cah.pElems,
  1215. pvar1->cah.cElems *
  1216. sizeof(pvar1->cah.pElems[0])) == 0;
  1217. }
  1218. break;
  1219. case VT_VECTOR | VT_CLSID:
  1220. if (fSame = (pvar1->cauuid.cElems == pvar2->cauuid.cElems))
  1221. {
  1222. fSame = memcmp(
  1223. pvar1->cauuid.pElems,
  1224. pvar2->cauuid.pElems,
  1225. pvar1->cauuid.cElems *
  1226. sizeof(pvar1->cauuid.pElems[0])) == 0;
  1227. }
  1228. break;
  1229. case VT_VECTOR | VT_CF:
  1230. if (fSame = pvar1->caclipdata.cElems == pvar2->caclipdata.cElems)
  1231. {
  1232. for (i = 0; i < pvar1->caclipdata.cElems; i++)
  1233. {
  1234. fSame = _Compare_VT_CF(
  1235. &pvar1->caclipdata.pElems[i],
  1236. &pvar2->caclipdata.pElems[i]);
  1237. if (!fSame)
  1238. {
  1239. break;
  1240. }
  1241. }
  1242. }
  1243. break;
  1244. case VT_VECTOR | VT_BSTR:
  1245. if (fSame = (pvar1->cabstr.cElems == pvar2->cabstr.cElems))
  1246. {
  1247. for (i = 0; i < pvar1->cabstr.cElems; i++)
  1248. {
  1249. if (pvar1->cabstr.pElems[i] != NULL &&
  1250. pvar2->cabstr.pElems[i] != NULL)
  1251. {
  1252. if (fSame =
  1253. BSTRLEN(pvar1->cabstr.pElems[i]) ==
  1254. BSTRLEN(pvar2->cabstr.pElems[i]))
  1255. {
  1256. fSame = memcmp(
  1257. pvar1->cabstr.pElems[i],
  1258. pvar2->cabstr.pElems[i],
  1259. BSTRLEN(pvar1->cabstr.pElems[i])) == 0;
  1260. }
  1261. }
  1262. else
  1263. {
  1264. fSame = pvar1->cabstr.pElems[i] == pvar2->cabstr.pElems[i];
  1265. }
  1266. if (!fSame)
  1267. {
  1268. break;
  1269. }
  1270. }
  1271. }
  1272. break;
  1273. case VT_VECTOR | VT_LPSTR:
  1274. if (fSame = (pvar1->calpstr.cElems == pvar2->calpstr.cElems))
  1275. {
  1276. for (i = 0; i < pvar1->calpstr.cElems; i++)
  1277. {
  1278. if (pvar1->calpstr.pElems[i] != NULL &&
  1279. pvar2->calpstr.pElems[i] != NULL)
  1280. {
  1281. fSame = strcmp(
  1282. pvar1->calpstr.pElems[i],
  1283. pvar2->calpstr.pElems[i]) == 0;
  1284. }
  1285. else
  1286. {
  1287. fSame = pvar1->calpstr.pElems[i] ==
  1288. pvar2->calpstr.pElems[i];
  1289. }
  1290. if (!fSame)
  1291. {
  1292. break;
  1293. }
  1294. }
  1295. }
  1296. break;
  1297. case VT_VECTOR | VT_LPWSTR:
  1298. if (fSame = pvar1->calpwstr.cElems == pvar2->calpwstr.cElems)
  1299. {
  1300. for (i = 0; i < pvar1->calpwstr.cElems; i++)
  1301. {
  1302. if (pvar1->calpwstr.pElems[i] != NULL &&
  1303. pvar2->calpwstr.pElems[i] != NULL)
  1304. {
  1305. fSame = Prop_wcscmp(
  1306. pvar1->calpwstr.pElems[i],
  1307. pvar2->calpwstr.pElems[i]) == 0;
  1308. }
  1309. else
  1310. {
  1311. fSame = pvar1->calpwstr.pElems[i] ==
  1312. pvar2->calpwstr.pElems[i];
  1313. }
  1314. if (!fSame)
  1315. {
  1316. break;
  1317. }
  1318. }
  1319. }
  1320. break;
  1321. case VT_VECTOR | VT_VARIANT:
  1322. if (fSame = pvar1->capropvar.cElems == pvar2->capropvar.cElems)
  1323. {
  1324. for (i = 0; i < pvar1->capropvar.cElems; i++)
  1325. {
  1326. fSame = RtlCompareVariants(
  1327. CodePage,
  1328. &pvar1->capropvar.pElems[i],
  1329. &pvar2->capropvar.pElems[i]);
  1330. if (!fSame)
  1331. {
  1332. break;
  1333. }
  1334. }
  1335. }
  1336. break;
  1337. default:
  1338. PROPASSERT(!"Invalid type for PROPVARIANT Comparison");
  1339. fSame = FALSE;
  1340. break;
  1341. }
  1342. return(fSame);
  1343. }