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.

2074 lines
62 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994
  5. //
  6. // File: ntpropb.cxx
  7. //
  8. // Contents: Nt property set implementation based on OLE Appendix B.
  9. //
  10. // History:
  11. // 5-Dec-94 vich created
  12. // 09-May-96 MikeHill Use the 'boolVal' member of PropVariant,
  13. // rather than the member named 'bool'
  14. // (which is a reserved keyword).
  15. // 22-May-96 MikeHill - Get the OSVersion during a CreatePropSet.
  16. // - Let CPropSetStm allocate prop name buffers.
  17. // 07-Jun-96 MikeHill - Correct ClipData.cbSize to include
  18. // sizeof(ulClipFmt).
  19. // - Removed unnecessary Flushes.
  20. // - Take the psstm lock on RtlClosePropSet.
  21. // 12-Jun-96 MikeHill - Fix locking in RtlClosePropertySet.
  22. // - VT_I1 support (under ifdefs)
  23. // 25-Jul-96 MikeHill - Removed Win32 SEH.
  24. // - BSTRs & prop names: WCHAR => OLECHAR.
  25. // - Added RtlOnMappedStreamEvent
  26. // - Enabled for use in "iprop.dll".
  27. // 03-Mar-98 MikeHill - Chagned "Pr" routines to "Stg".
  28. // 06-May-98 MikeHill - Removed UnicodeCallouts.
  29. // - Use CoTaskMem rather than new/delete.
  30. // - Added support for VT_VECTOR|VT_I1
  31. // 18-May-98 MikeHill - Fixed typos.
  32. // 11-June-98 MikeHIll - Removed some old Cairo code.
  33. // - Dbg output.
  34. // - Add a pCodePage to PrSetProperties.
  35. //
  36. //---------------------------------------------------------------------------
  37. #include <pch.cxx>
  38. #include "propvar.h"
  39. #include <olechar.h>
  40. #include <stgprop.h>
  41. #define Dbg DEBTRACE_NTPROP
  42. #define DbgS(s) (NT_SUCCESS(s)? Dbg : DEBTRACE_ERROR)
  43. #if DBG
  44. ULONG DebugLevel = DEBTRACE_ERROR;
  45. //ULONG DebugLevel = DEBTRACE_ERROR | DEBTRACE_CREATESTREAM;
  46. //ULONG DebugLevel = DEBTRACE_ERROR | MAXULONG;
  47. ULONG DebugIndent;
  48. ULONG cAlloc;
  49. ULONG cFree;
  50. #endif
  51. #if defined(WINNT) && !defined(IPROPERTY_DLL)
  52. GUID guidStorage = PSGUID_STORAGE;
  53. #endif // #if defined(WINNT) && !defined(IPROPERTY_DLL)
  54. //+---------------------------------------------------------------------------
  55. // Function: UnLock, private
  56. //
  57. // Synopsis: Unlock a PropertySetStream, and return the
  58. // more severe of two NTSTATUSs; the result of
  59. // the Unlock, or the one passed in by the caller.
  60. //
  61. // Arguments: [ppsstm] -- The CPropertySetStream to unlock
  62. // [Status] -- NTSTATUS
  63. //
  64. // Returns: NTSTATUS
  65. //---------------------------------------------------------------------------
  66. inline NTSTATUS
  67. Unlock( CPropertySetStream *ppsstm, NTSTATUS Status )
  68. {
  69. NTSTATUS StatusT = ppsstm->Unlock();
  70. // Note that the statement below preserves
  71. // success codes in the original Status unless
  72. // there was an error in the Unlock.
  73. if( NT_SUCCESS(Status) && !NT_SUCCESS(StatusT) )
  74. Status = StatusT;
  75. return( Status );
  76. }
  77. //+---------------------------------------------------------------------------
  78. // Function: PrCreatePropertySet, public
  79. //
  80. // Synopsis: Allocate and initialize a property set context
  81. //
  82. // Arguments: [ms] -- Nt Mapped Stream
  83. // [Flags] -- *one* of READ/WRITE/CREATE/CREATEIF/DELETE
  84. // [pguid] -- property set guid (create only)
  85. // [pclsid] -- CLASSID of propset code (create only)
  86. // [ma] -- caller's memory allocator
  87. // [LocaleId] -- Locale Id (create only)
  88. // [pOSVersion] -- pointer to the OS Version header field
  89. // [pCodePage] -- pointer to new/returned CodePage of propset
  90. // [pgrfBehavior] -- pointer to PROPSET_BEHAVIOR_* flags
  91. // [pnp] -- pointer to returned property set context
  92. //
  93. // Returns: Status code
  94. //---------------------------------------------------------------------------
  95. NTSTATUS
  96. PrCreatePropertySet(
  97. IN NTMAPPEDSTREAM ms, // Nt Mapped Stream
  98. IN USHORT Flags, // *one* of READ/WRITE/CREATE/CREATEIF/DELETE
  99. OPTIONAL IN GUID const *pguid, // property set guid (create only)
  100. OPTIONAL IN GUID const *pclsid, // CLASSID of propset code (create only)
  101. IN NTMEMORYALLOCATOR ma, // caller's memory allocator
  102. IN ULONG LocaleId, // Locale Id (create only)
  103. OPTIONAL OUT ULONG *pOSVersion, // OS Version from the propset header
  104. IN OUT USHORT *pCodePage, // IN: CodePage of property set (create only)
  105. // OUT: CodePage of property set (always)
  106. IN OUT DWORD *pgrfBehavior, // IN: Behavior of property set (create only)
  107. // OUT: Behavior of property set (always)
  108. OUT NTPROP *pnp) // pointer to return prop set context
  109. {
  110. NTSTATUS Status;
  111. IMappedStream *pmstm = (IMappedStream *) ms;
  112. CPropertySetStream *ppsstm = NULL;
  113. BOOLEAN fLocked = FALSE;
  114. BOOLEAN fOpened = FALSE;
  115. IFDBG( HRESULT &hr = Status );
  116. propITraceStatic( "PrCreatePropertySet" );
  117. propTraceParameters(( "ms=%p, f=0x%x, codepage=0x%x)", ms, Flags, *pCodePage ));
  118. *pnp = NULL;
  119. Status = STATUS_INVALID_PARAMETER;
  120. if( pOSVersion != NULL )
  121. *pOSVersion = PROPSETHDR_OSVERSION_UNKNOWN;
  122. // Validate the input flags
  123. if (Flags & ~(CREATEPROP_MODEMASK | CREATEPROP_NONSIMPLE))
  124. {
  125. propDbg(( DEB_ERROR, "PrCreatePropertySet(ms=%x, Flags=%x) ==> bad flags!\n",
  126. ms, Flags));
  127. goto Exit;
  128. }
  129. PROPASSERT( (0 == *pgrfBehavior) || (CREATEPROP_CREATE & Flags) );
  130. PROPASSERT( !(*pgrfBehavior & ~PROPSET_BEHAVIOR_CASE_SENSITIVE) );
  131. switch (Flags & CREATEPROP_MODEMASK)
  132. {
  133. case CREATEPROP_DELETE:
  134. case CREATEPROP_CREATE:
  135. case CREATEPROP_CREATEIF:
  136. case CREATEPROP_WRITE:
  137. if (!pmstm->IsWriteable())
  138. {
  139. Status = STATUS_ACCESS_DENIED;
  140. goto Exit;
  141. }
  142. // FALLTHROUGH
  143. case CREATEPROP_READ:
  144. case CREATEPROP_UNKNOWN:
  145. if (ma == NULL)
  146. {
  147. goto Exit;
  148. }
  149. break;
  150. default:
  151. propDbg(( DEB_ERROR, "PrCreatePropertySet(ms=%x, Flags=%x) ==> invalid mode!\n",
  152. ms, Flags));
  153. goto Exit;
  154. }
  155. Status = pmstm->Lock((Flags & CREATEPROP_MODEMASK) != CREATEPROP_READ);
  156. if( !NT_SUCCESS(Status) ) goto Exit;
  157. fLocked = TRUE;
  158. ppsstm = new CPropertySetStream( Flags, pmstm, (PMemoryAllocator *) ma);
  159. if (ppsstm == NULL)
  160. {
  161. Status = STATUS_INSUFFICIENT_RESOURCES;
  162. goto Exit;
  163. }
  164. else
  165. {
  166. ppsstm->Open(pguid, pclsid, LocaleId,
  167. pOSVersion, *pCodePage, *pgrfBehavior, &Status);
  168. if( !NT_SUCCESS(Status) ) goto Exit;
  169. }
  170. // ----
  171. // Exit
  172. // ----
  173. Exit:
  174. if (fLocked)
  175. Status = Unlock( ppsstm, Status );
  176. // If we were successfull with everything, set the
  177. // out-parameters.
  178. if( NT_SUCCESS(Status) )
  179. {
  180. // pOSVersion has already been set.
  181. *pCodePage = ppsstm->GetCodePage();
  182. *pgrfBehavior = ppsstm->GetBehavior();
  183. *pnp = (NTPROP) ppsstm;
  184. }
  185. // Otherwise, if we created a CPropertySetStream object, but
  186. // the overall operation failed, we must close/delete
  187. // the object. Note that we must do this after
  188. // the above unlock, since ppsstm will be gone after
  189. // this call.
  190. else if( NULL != ppsstm )
  191. {
  192. PrClosePropertySet((NTPROP) ppsstm);
  193. }
  194. if( STATUS_PROPSET_NOT_FOUND == Status )
  195. propSuppressExitErrors();
  196. return(Status);
  197. }
  198. //+---------------------------------------------------------------------------
  199. // Function: PrClosePropertySet, public
  200. //
  201. // Synopsis: Delete a property set context
  202. //
  203. // Arguments: [np] -- property set context
  204. //
  205. // Returns: Status code
  206. //---------------------------------------------------------------------------
  207. NTSTATUS
  208. PrClosePropertySet(
  209. IN NTPROP np) // property set context
  210. {
  211. NTSTATUS Status = STATUS_SUCCESS;
  212. BOOL fLocked = FALSE;
  213. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  214. IFDBG( HRESULT &hr = Status );
  215. propITraceStatic( "PrClosePropertySet" );
  216. propTraceParameters(( "np=%p", np ));
  217. // Lock the mapped stream, because this close
  218. // may trigger a Write.
  219. Status = ppsstm->Lock(TRUE);
  220. if( !NT_SUCCESS(Status) ) goto Exit;
  221. fLocked = TRUE;
  222. // Note that we haven't ReOpen-ed the mapped stream. This
  223. // isn't required for the CPropertySetStream::Close method.
  224. ppsstm->Close(&Status);
  225. if( !NT_SUCCESS(Status) ) goto Exit;
  226. // ----
  227. // Exit
  228. // ----
  229. Exit:
  230. if (fLocked)
  231. Status = Unlock( ppsstm, Status );
  232. if( STG_E_REVERTED == Status )
  233. propSuppressExitErrors();
  234. delete ppsstm;
  235. return(Status);
  236. }
  237. //+---------------------------------------------------------------------------
  238. // Function: PrOnMappedStreamEvent, public
  239. //
  240. // Synopsis: Handle a MappedStream event. Every such
  241. // event requires a byte-swap of the property set
  242. // headers.
  243. //
  244. // Arguments: [np] -- property set context
  245. // [pbuf] -- property set buffer
  246. // [cbstm] -- size of mapped stream (or CBSTM_UNKNOWN)
  247. //
  248. // NOTE: It is assumed that the caller has already taken
  249. // the CPropertySetStream::Lock.
  250. //
  251. // Returns: Status code
  252. //---------------------------------------------------------------------------
  253. #ifdef BIGENDIAN
  254. NTSTATUS
  255. PrOnMappedStreamEvent(
  256. IN VOID * np, // property set context (an NTPROP)
  257. IN VOID *pbuf, // property set buffer
  258. IN ULONG cbstm )
  259. {
  260. NTSTATUS Status = STATUS_SUCCESS;
  261. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  262. IFDBG( HRESULT &hr = Status );
  263. propITraceStatic( "PrOnMappedStreamEvent" );
  264. propTraceParameters(( "np=%p, pbuf=%p, cbstm=%lu", np, pbuf, cbstm ));
  265. // Byte-swap the property set headers.
  266. ppsstm->ByteSwapHeaders((PROPERTYSETHEADER*) pbuf, cbstm, &Status );
  267. if( !NT_SUCCESS(Status) ) goto Exit;
  268. // ----
  269. // Exit
  270. // ----
  271. Exit:
  272. return(Status);
  273. } // PrOnMappedStreamEvent()
  274. #endif
  275. //+---------------------------------------------------------------------------
  276. // Function: PrFlushPropertySet, public
  277. //
  278. // Synopsis: Flush property set changes to disk
  279. //
  280. // Arguments: [np] -- property set context
  281. //
  282. // Returns: Status code
  283. //---------------------------------------------------------------------------
  284. NTSTATUS
  285. PrFlushPropertySet(
  286. IN NTPROP np) // property set context
  287. {
  288. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  289. NTSTATUS Status = STATUS_SUCCESS;
  290. BOOL fLocked = FALSE;
  291. IFDBG( HRESULT &hr = Status );
  292. propITraceStatic( "PrFlushPropertySet" );
  293. propTraceParameters(( "np=%p", np ));
  294. Status = ppsstm->Lock(TRUE);
  295. if( !NT_SUCCESS(Status) ) goto Exit;
  296. fLocked = TRUE;
  297. if (ppsstm->IsModified())
  298. {
  299. ppsstm->ReOpen(&Status); // Reload header/size info
  300. if( !NT_SUCCESS(Status) ) goto Exit;
  301. ppsstm->Validate(&Status); // (Debug only)
  302. if( !NT_SUCCESS(Status) ) goto Exit;
  303. ppsstm->Flush(&Status);
  304. if( !NT_SUCCESS(Status) ) goto Exit;
  305. ppsstm->Validate(&Status);
  306. if( !NT_SUCCESS(Status) ) goto Exit;
  307. }
  308. Exit:
  309. if( fLocked )
  310. Status = Unlock( ppsstm, Status );
  311. return(Status);
  312. }
  313. //+---------------------------------------------------------------------------
  314. // Function: MapNameToPropId, private
  315. //
  316. // Synopsis: Find an available propid and map it to the passed name
  317. //
  318. // Arguments: [ppsstm] -- property set stream
  319. // [CodePage] -- property set codepage
  320. // [aprs] -- array of property specifiers
  321. // [cprop] -- count of property specifiers
  322. // [iprop] -- index of propspec with name to map
  323. // [pidStart] -- first PROPID to start mapping attempts
  324. // [pstatus] -- NTSTATUS code
  325. //
  326. // Returns: PROPID mapped to passed name
  327. //
  328. // Note: Find the first unused propid starting at pidStart.
  329. //---------------------------------------------------------------------------
  330. PROPID
  331. MapNameToPropId(
  332. IN CPropertySetStream *ppsstm, // property set stream
  333. IN USHORT CodePage,
  334. IN PROPSPEC const aprs[], // array of property specifiers
  335. IN ULONG cprop,
  336. IN ULONG iprop,
  337. IN PROPID pidStart,
  338. OUT NTSTATUS *pstatus)
  339. {
  340. PROPID pid = PID_ILLEGAL;
  341. const OLECHAR *poszName = NULL;
  342. OLECHAR *poszNameFromDictionary = NULL;
  343. ULONG cbName;
  344. *pstatus = STATUS_SUCCESS;
  345. PROPASSERT(aprs[iprop].ulKind == PRSPEC_LPWSTR);
  346. poszName = aprs[iprop].lpwstr;
  347. PROPASSERT(IsOLECHARString( poszName, MAXULONG ));
  348. IFDBG( HRESULT &hr = *pstatus );
  349. propITraceStatic( "MapNameToPropId" );
  350. propTraceParameters(( "ppsstm=%p, CodePage=%d, aprs=%p, cprop=%d, iprop=%d, pidStart=%d",
  351. ppsstm, CodePage, aprs, cprop, iprop, pidStart ));
  352. // Starting with the caller-provided PID, search sequentially
  353. // until we find a PID we can use.
  354. for (pid = pidStart; ; pid++)
  355. {
  356. ULONG i;
  357. // The caller must specify a starting propid of 2 or larger, and we
  358. // must not increment into the reserved propids.
  359. if (pid == PID_DICTIONARY ||
  360. pid == PID_CODEPAGE ||
  361. pid < PID_FIRST_USABLE)
  362. {
  363. *pstatus = STATUS_INVALID_PARAMETER;
  364. goto Exit;
  365. }
  366. // Do not assign any propids that explitly appear in the array of
  367. // propspecs involved in this PrSetProperties call, nor any propids
  368. // that are associated with any names in the propspec array.
  369. for (i = 0; i < cprop; i++)
  370. {
  371. if (i != iprop) // skip the entry we are mapping
  372. {
  373. // Is the current PID in the PropSpec[]?
  374. if (aprs[i].ulKind == PRSPEC_PROPID &&
  375. aprs[i].propid == pid)
  376. {
  377. goto nextpid; // skip colliding pid
  378. }
  379. // Is the current PID already used in the property set?
  380. if (aprs[i].ulKind == PRSPEC_LPWSTR &&
  381. ppsstm->QueryPropid(aprs[i].lpwstr, pstatus) == pid)
  382. {
  383. goto nextpid; // skip colliding pid
  384. }
  385. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  386. }
  387. } // for (i = 0; i < cprop; i++)
  388. // Do not assign any propids that currently map to any name.
  389. // Note that the property name we are mapping does not appear in the
  390. // dictionary -- the caller checked for this case already.
  391. if( ppsstm->QueryPropertyNames( 1, &pid, &poszNameFromDictionary, pstatus ))
  392. {
  393. CoTaskMemFree( poszNameFromDictionary );
  394. poszNameFromDictionary = NULL;
  395. }
  396. else
  397. {
  398. // The property name could not be found in the dictionary.
  399. ULONG cbT;
  400. SERIALIZEDPROPERTYVALUE const *pprop;
  401. PROPASSERT( NULL == poszNameFromDictionary );
  402. // Was the name not found due to an error in QueryPropertyNames?
  403. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  404. // Do not assign any propids that currently have a property value.
  405. pprop = ppsstm->GetValue(pid, &cbT, pstatus);
  406. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  407. if (pprop == NULL)
  408. {
  409. // There was no property value corresponding to this PID.
  410. DebugTrace(0, Dbg, (
  411. "MapNameToPropId(Set Entry: pid=%x, name=L'%ws')\n",
  412. pid,
  413. poszName));
  414. // Add the caller-provided name to the dictionary, using
  415. // the PID that we now know is nowhere in use.
  416. ppsstm->SetPropertyNames(1, &pid, &poszName, pstatus);
  417. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  418. ppsstm->Validate(pstatus);
  419. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  420. break;
  421. } // if (pprop == NULL)
  422. } // if( ppsstm->QueryPropertyNames( 1, &pid, &poszNameFromDictionary, pstatus ))
  423. nextpid:
  424. ;
  425. } // for (pid = pidStart; ; pid++)
  426. Exit:
  427. if( NULL != poszNameFromDictionary )
  428. CoTaskMemFree( poszNameFromDictionary );
  429. return(pid);
  430. }
  431. //+---------------------------------------------------------------------------
  432. // Function: ConvertVariantToPropInfo, private
  433. //
  434. // Synopsis: Convert variant property values to PROPERTY_INFORMATION values
  435. //
  436. // Arguments: [ppsstm] -- property set stream
  437. // [cprop] -- property count
  438. // [pidNameFirst] -- first PROPID for new named properties
  439. // [aprs] -- array of property specifiers
  440. // [apid] -- buffer for array of propids
  441. // [avar] -- array of PROPVARIANTs
  442. // [apinfo] -- output array of property info
  443. // [pcIndirect] -- output count of indirect properties
  444. //
  445. // Returns: None
  446. //
  447. // Note: If pcIndirect is NULL,
  448. //---------------------------------------------------------------------------
  449. VOID
  450. ConvertVariantToPropInfo(
  451. IN CPropertySetStream *ppsstm, // property set stream
  452. IN ULONG cprop, // property count
  453. IN PROPID pidNameFirst, // first PROPID for new named properties
  454. IN PROPSPEC const aprs[], // array of property specifiers
  455. OPTIONAL OUT PROPID apid[], // buffer for array of propids
  456. OPTIONAL IN PROPVARIANT const avar[],// array of properties+values
  457. OUT PROPERTY_INFORMATION *apinfo, // output array of property info
  458. OUT ULONG *pcIndirect, // output count of indirect properties
  459. OUT NTSTATUS *pstatus )
  460. {
  461. *pstatus = STATUS_SUCCESS;
  462. USHORT CodePage = ppsstm->GetCodePage();
  463. PROPID pidStart = pidNameFirst;
  464. ULONG iprop;
  465. IFDBG( HRESULT &hr = *pstatus );
  466. propITraceStatic( "ConvertVariantToPropInfo" );
  467. propTraceParameters(( "ppsstm=%p, cprop=%d, pidNameFirst=%d, aprs=%p, apid=%p, avar=%p, apinfo=%p, pcIndirect=%p",
  468. ppsstm, cprop, pidNameFirst, aprs, apid, avar, apinfo, pcIndirect ));
  469. if (pcIndirect != NULL)
  470. {
  471. *pcIndirect = 0;
  472. }
  473. // Loop through each of the input propvariants and put it's info
  474. // in the apinfo array.
  475. for (iprop = 0; iprop < cprop; iprop++)
  476. {
  477. PROPID pid;
  478. ULONG cbprop;
  479. // Get the PROPID into 'pid' (harder if this is a name)
  480. // If a property is being written with a new name, we'll
  481. // add it to the dictionary here.
  482. switch(aprs[iprop].ulKind)
  483. {
  484. // For names, we have to work with the dictionary.
  485. case PRSPEC_LPWSTR:
  486. {
  487. PROPASSERT(IsOLECHARString(aprs[iprop].lpwstr, MAXULONG));
  488. // Is this property already in the dictionary?
  489. pid = ppsstm->QueryPropid(aprs[iprop].lpwstr, pstatus);
  490. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  491. // If it's not in the dictionary, add it.
  492. if (pid == PID_ILLEGAL && avar != NULL)
  493. {
  494. pid = MapNameToPropId(
  495. ppsstm,
  496. CodePage,
  497. aprs,
  498. cprop,
  499. iprop,
  500. pidStart,
  501. pstatus);
  502. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  503. pidStart = pid + 1;
  504. }
  505. break;
  506. }
  507. // Otherwise, the caller has already explicitely given us the PID.
  508. case PRSPEC_PROPID:
  509. pid = aprs[iprop].propid;
  510. break;
  511. default:
  512. PROPASSERT(!"Bad ulKind");
  513. *pstatus = STATUS_INVALID_PARAMETER;
  514. goto Exit;
  515. break;
  516. } // switch(aprs[iprop].ulKind)
  517. // Store the PROPID in the apid array.
  518. if (apid != NULL)
  519. {
  520. apid[iprop] = pid;
  521. }
  522. // Calculate the size of the serialized property (cbprop).
  523. // StgConvertVariantToProperty returns NULL on overflow and
  524. // Raises on bad data.
  525. cbprop = 0; // Assume property deletion
  526. if (pid != PID_ILLEGAL && avar != NULL)
  527. {
  528. StgConvertVariantToPropertyNoEH(
  529. &avar[iprop],
  530. CodePage,
  531. NULL, // Don't actualy convert. We just want to calc cbprop.
  532. &cbprop,
  533. pid,
  534. FALSE, FALSE, // Not a vector or array recursive call
  535. pcIndirect,
  536. NULL, // Don't check for min format version required yet
  537. pstatus);
  538. if( !NT_SUCCESS(*pstatus) ) goto Exit;
  539. PROPASSERT(cbprop == DwordAlign(cbprop));
  540. }
  541. // Store the size & PROPID into the PROPINFO array.
  542. apinfo[iprop].cbprop = cbprop;
  543. apinfo[iprop].pid = pid;
  544. } // for (iprop = 0; iprop < cprop; iprop++)
  545. // ----
  546. // Exit
  547. // ----
  548. Exit:
  549. if( STATUS_NOT_SUPPORTED == *pstatus )
  550. propSuppressExitErrors();
  551. return;
  552. }
  553. //+---------------------------------------------------------------------------
  554. // Function: BuildIndirectIndexArray, private
  555. //
  556. // Synopsis: Set property values for a property set
  557. //
  558. // Arguments: [cprop] -- count of properties in avar
  559. // [cAlloc] -- max count of indirect properties
  560. // [cIndirect] -- count of indirect properties in avar
  561. // [avar] -- array of PROPVARIANTs
  562. // [ppip] -- ptr to ptr to Indirect property structures
  563. //
  564. // Returns: None
  565. //---------------------------------------------------------------------------
  566. VOID
  567. BuildIndirectIndexArray(
  568. IN ULONG cprop, // count of properties in avar
  569. IN ULONG cAlloc, // max count of indirect properties
  570. IN ULONG cIndirect, // count of indirect properties in avar
  571. IN PROPVARIANT const avar[],// array of properties+values
  572. OPTIONAL OUT INDIRECTPROPERTY **ppip, // pointer to returned pointer to
  573. // MAXULONG terminated array of Indirect
  574. // properties w/indexes into aprs & avar
  575. OUT NTSTATUS *pstatus)
  576. {
  577. *pstatus = STATUS_SUCCESS;
  578. IFDBG( HRESULT &hr = *pstatus );
  579. propITraceStatic( "BuildIndirectIndexArray" );
  580. propTraceParameters(( "cprop=%d, cAlloc=%d, cIndirect=%d, avar=%p",
  581. cprop, cAlloc, cIndirect, avar ));
  582. PROPASSERT(cIndirect > 0);
  583. PROPASSERT(cAlloc >= cIndirect);
  584. PROPASSERT(cprop >= cAlloc);
  585. if (ppip != NULL)
  586. {
  587. INDIRECTPROPERTY *pip;
  588. ULONG iprop;
  589. // Get a pointer to an INDIRECTPROPERTY array. If there
  590. // is only one entry, then the caller has provided us the buffer.
  591. // Otherwise, we need to allocate it.
  592. if (cprop == 1)
  593. {
  594. pip = (INDIRECTPROPERTY *) ppip;
  595. }
  596. else
  597. {
  598. // Allocate the indrect property array
  599. pip = (INDIRECTPROPERTY *) CoTaskMemAlloc( (cAlloc+1) * sizeof(INDIRECTPROPERTY) );
  600. if (pip == NULL)
  601. {
  602. *pstatus = STATUS_INSUFFICIENT_RESOURCES;
  603. goto Exit;
  604. }
  605. *ppip = pip;
  606. }
  607. // Loop through the properties, and for each that is indirect,
  608. // put it's index into the INDIRECTPROPERTY array.
  609. for (iprop = 0; iprop < cprop; iprop++)
  610. {
  611. if (IsIndirectVarType(avar[iprop].vt))
  612. {
  613. PROPASSERT(cprop == 1 || (ULONG) (pip - *ppip) < cIndirect);
  614. pip->Index = iprop;
  615. pip->poszName = NULL;
  616. pip++;
  617. }
  618. }
  619. // For the case where we allocated an array, we allocated an extra entry
  620. // so that we could put a terminator at the end of the array.
  621. if (cprop > 1)
  622. {
  623. pip->Index = MAXULONG;
  624. PROPASSERT((ULONG) (pip - *ppip) == cIndirect);
  625. }
  626. } // if (ppip != NULL)
  627. // ----
  628. // Exit
  629. // ----
  630. Exit:
  631. return;
  632. }
  633. //+---------------------------------------------------------------------------
  634. // Function: PrSetProperties, public
  635. //
  636. // Synopsis: Set property values for a property set
  637. //
  638. // Arguments: [np] -- property set context
  639. // [cprop] -- property count
  640. // [pidNameFirst] -- first PROPID for new named properties
  641. // [aprs] -- array of property specifiers
  642. // [apid] -- buffer for array of propids
  643. // -- values to write in place of indirect properties
  644. // [ppip] -- ptr to ptr to Indirect property structures
  645. // [avar] -- array of PROPVARIANTs
  646. //
  647. // Returns: Status code
  648. //---------------------------------------------------------------------------
  649. NTSTATUS
  650. PrSetProperties(
  651. IN NTPROP np, // property set context
  652. IN ULONG cprop, // property count
  653. IN PROPID pidNameFirst, // first PROPID for new named properties
  654. IN PROPSPEC const aprs[], // array of property specifiers
  655. OUT USHORT *pCodePage,
  656. OPTIONAL OUT PROPID apid[], // buffer for array of propids
  657. OPTIONAL OUT INDIRECTPROPERTY **ppip, // pointer to returned pointer to
  658. // MAXULONG terminated array of Indirect
  659. // properties w/indexes into aprs & avar
  660. IN PROPVARIANT const avar[]) // array of properties+values
  661. {
  662. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  663. NTSTATUS Status = STATUS_SUCCESS;
  664. BOOL fLocked = FALSE;
  665. PROPERTY_INFORMATION apinfoStack[6];
  666. PROPERTY_INFORMATION *apinfo = apinfoStack;
  667. ULONG cIndirect = 0;
  668. IFDBG( HRESULT &hr = Status );
  669. propITraceStatic( "PrSetProperties" );
  670. propTraceParameters(( "np=%p, cprop=%d, pidNameFirst=%d, aprs=%p, CodePage=%d, apid=%p, ppip=%p, avar=%p",
  671. np, cprop, pidNameFirst, aprs, *pCodePage, apid, ppip, avar ));
  672. // Initialize the INDIRECTPROPERTY structure.
  673. if (ppip != NULL)
  674. {
  675. *ppip = NULL;
  676. // If cprop is 1, ppip is actually pip (one level
  677. // of indirection).
  678. if (cprop == 1)
  679. {
  680. // Default the index.
  681. ((INDIRECTPROPERTY *) ppip)->Index = MAXULONG;
  682. }
  683. }
  684. // Lock the property set.
  685. Status = ppsstm->Lock(TRUE);
  686. if( !NT_SUCCESS(Status) ) goto Exit;
  687. fLocked = TRUE;
  688. // Is the stack-based apinfo big enough?
  689. if (cprop > sizeof(apinfoStack)/sizeof(apinfoStack[0]))
  690. {
  691. // No - we need to allocate an apinfo.
  692. apinfo = reinterpret_cast<PROPERTY_INFORMATION*>
  693. ( CoTaskMemAlloc( sizeof(PROPERTY_INFORMATION) * cprop ));
  694. if( NULL == apinfo )
  695. {
  696. Status = STATUS_INSUFFICIENT_RESOURCES;
  697. goto Exit;
  698. }
  699. }
  700. ppsstm->ReOpen(&Status); // Reload header/size info
  701. if( !NT_SUCCESS(Status) ) goto Exit;
  702. ppsstm->Validate(&Status);
  703. if( !NT_SUCCESS(Status) ) goto Exit;
  704. // Describe the request into the apinfo array. This also writes the names
  705. // to the dictionary.
  706. ConvertVariantToPropInfo(
  707. ppsstm,
  708. cprop,
  709. pidNameFirst,
  710. aprs,
  711. apid,
  712. avar,
  713. apinfo,
  714. ppip == NULL? NULL : &cIndirect,
  715. &Status);
  716. if( !NT_SUCCESS(Status) ) goto Exit;
  717. // Write the value. If there are indirect properties, ppip will hold
  718. // the stream/storage names.
  719. ppsstm->SetValue(cprop, ppip, avar, apinfo, pCodePage, &Status);
  720. if( !NT_SUCCESS(Status) ) goto Exit;
  721. ppsstm->Validate(&Status);
  722. if( !NT_SUCCESS(Status) ) goto Exit;
  723. // ----
  724. // Exit
  725. // ----
  726. Exit:
  727. // If we allocated a temporary apinfo buffer, free it.
  728. if (apinfo != apinfoStack)
  729. {
  730. CoTaskMemFree( apinfo );
  731. }
  732. // Clean up the PIP array on error.
  733. if (!NT_SUCCESS(Status))
  734. {
  735. if (ppip != NULL)
  736. {
  737. if (cprop == 1)
  738. {
  739. ((INDIRECTPROPERTY *) ppip)->Index = MAXULONG;
  740. }
  741. else if (*ppip != NULL)
  742. {
  743. CoTaskMemFree( *ppip );
  744. *ppip = NULL;
  745. }
  746. }
  747. }
  748. if (fLocked)
  749. Status = Unlock( ppsstm, Status );
  750. if( STATUS_NOT_SUPPORTED == Status )
  751. propSuppressExitErrors();
  752. return(Status);
  753. }
  754. //+---------------------------------------------------------------------------
  755. // Function: PrQueryProperties, public
  756. //
  757. // Synopsis: Query property values from a property set
  758. //
  759. // Arguments: [np] -- property set context
  760. // [cprop] -- property count
  761. // [aprs] -- array of property specifiers
  762. // [apid] -- buffer for array of propids
  763. // [ppip] -- ptr to ptr to Indirect property structures
  764. // [avar] -- array of PROPVARIANTs
  765. //
  766. // Returns: Status code
  767. //---------------------------------------------------------------------------
  768. NTSTATUS
  769. PrQueryProperties(
  770. IN NTPROP np, // property set context
  771. IN ULONG cprop, // property count
  772. IN PROPSPEC const aprs[], // array of property specifiers
  773. OPTIONAL OUT PROPID apid[], // buffer for array of propids
  774. OPTIONAL OUT INDIRECTPROPERTY **ppip, // pointer to returned pointer to
  775. // MAXULONG terminated array of Indirect
  776. // properties w/indexes into aprs & avar
  777. IN OUT PROPVARIANT *avar, // IN: array of uninitialized PROPVARIANTs,
  778. // OUT: may contain pointers to alloc'd memory
  779. OUT ULONG *pcpropFound) // count of property values retrieved
  780. {
  781. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  782. SERIALIZEDPROPERTYVALUE const *pprop = NULL;
  783. NTSTATUS Status = STATUS_SUCCESS;
  784. ULONG cIndirect = 0;
  785. ULONG iprop;
  786. BOOL fLocked = FALSE;
  787. IFDBG( HRESULT &hr = Status );
  788. propITraceStatic( "PrQueryProperties" );
  789. propTraceParameters(( "np=%p, cprop=%d, aprs=%p, apid=%p, ppip=%p)",
  790. np, cprop, aprs, apid, ppip ));
  791. // Initialize the variant array enough to allow it to be cleaned up
  792. // by the caller (even on partial failure).
  793. *pcpropFound = 0;
  794. if (ppip != NULL)
  795. {
  796. *ppip = NULL;
  797. if (cprop == 1)
  798. {
  799. ((INDIRECTPROPERTY *) ppip)->Index = MAXULONG;
  800. }
  801. }
  802. // Zero-ing out the caller-provided PropVariants, essentially
  803. // sets them all to VT_EMPTY. It also zeros out the data portion,
  804. // which prevents cleanup problems in error paths.
  805. RtlZeroMemory(avar, cprop * sizeof(avar[0]));
  806. Status = ppsstm->Lock(FALSE);
  807. if( !NT_SUCCESS(Status) ) goto Exit;
  808. fLocked = TRUE;
  809. ppsstm->ReOpen(&Status); // Reload header/size info
  810. if( !NT_SUCCESS(Status) ) goto Exit;
  811. ppsstm->Validate(&Status);
  812. if( !NT_SUCCESS(Status) ) goto Exit;
  813. // Loop through and get all the property values.
  814. for (iprop = 0; iprop < cprop; iprop++)
  815. {
  816. PROPID pid;
  817. ULONG cbprop;
  818. // Get the PROPID to query
  819. switch(aprs[iprop].ulKind)
  820. {
  821. // Query the PROPID from the caller-provided name.
  822. case PRSPEC_LPWSTR:
  823. pid = ppsstm->QueryPropid(aprs[iprop].lpwstr, &Status);
  824. if( !NT_SUCCESS(Status) ) goto Exit;
  825. break;
  826. // The caller already gave us the PROPID
  827. case PRSPEC_PROPID:
  828. pid = aprs[iprop].propid;
  829. break;
  830. default:
  831. PROPASSERT(!"Bad ulKind");
  832. Status = STATUS_INVALID_PARAMETER;
  833. goto Exit;
  834. }
  835. // Get a pointer to the value in the serialized stream
  836. // (into pprop). If this succeeds, pprop will point
  837. // to the value, and we will know that the value fits within
  838. // the section (so e.g. there's no corrupt length fields).
  839. pprop = ppsstm->GetValue(pid, &cbprop, &Status);
  840. if( !NT_SUCCESS(Status) ) goto Exit;
  841. if (pprop != NULL)
  842. {
  843. // We got the property value.
  844. BOOL fIndirect;
  845. // De-serialize the property value from pprop to
  846. // a PROPVARIANT (into an entry in the avar array).
  847. (*pcpropFound)++;
  848. fIndirect = StgConvertPropertyToVariantNoEH(
  849. pprop,
  850. cbprop,
  851. ppsstm->GetCodePage(),
  852. &avar[iprop],
  853. ppsstm->GetAllocator(),
  854. &Status);
  855. if( !NT_SUCCESS(Status) ) goto Exit;
  856. PROPASSERT( ( !(VT_ARRAY & avar[iprop].vt)
  857. &&
  858. !(VT_BYREF & avar[iprop].vt)
  859. &&
  860. VT_DECIMAL != avar[iprop].vt
  861. &&
  862. VT_I1 != avar[iprop].vt
  863. &&
  864. VT_INT != avar[iprop].vt
  865. &&
  866. VT_UINT != avar[iprop].vt
  867. )
  868. ||
  869. PROPSET_WFORMAT_EXPANDED_VTS <= ppsstm->GetFormatVersion()
  870. );
  871. // Keep a count of the number of indirect (aka non-simple) properties.
  872. if( fIndirect )
  873. {
  874. cIndirect++;
  875. }
  876. } // if (pprop != NULL)
  877. // Pass the actual PROPID back to the caller.
  878. if (apid != NULL)
  879. {
  880. apid[iprop] = pid;
  881. }
  882. } // for (iprop = 0; iprop < cprop; iprop++)
  883. // If the caller wants to know about indirect streams and
  884. // storages (and if there were any), allocate memory for a
  885. // MAXULONG terminated array of indexes to the indirect
  886. // variant structures, and fill it in.
  887. if (cIndirect != 0)
  888. {
  889. BuildIndirectIndexArray(
  890. cprop,
  891. cIndirect,
  892. cIndirect,
  893. avar,
  894. ppip,
  895. &Status);
  896. if( !NT_SUCCESS(Status) ) goto Exit;
  897. }
  898. ppsstm->Validate(&Status);
  899. if( !NT_SUCCESS(Status) ) goto Exit;
  900. // ----
  901. // Exit
  902. // ----
  903. Exit:
  904. if( !NT_SUCCESS(Status) )
  905. {
  906. if (ppip != NULL)
  907. {
  908. if (cprop == 1)
  909. {
  910. ((INDIRECTPROPERTY *) ppip)->Index = MAXULONG;
  911. }
  912. else if (*ppip != NULL)
  913. {
  914. CoTaskMemFree( *ppip );
  915. *ppip = NULL;
  916. }
  917. }
  918. CleanupVariants(avar, cprop, ppsstm->GetAllocator());
  919. }
  920. if (fLocked)
  921. Status = Unlock( ppsstm, Status );
  922. if( STATUS_NOT_SUPPORTED == Status )
  923. propSuppressExitErrors();
  924. return(Status);
  925. }
  926. //+---------------------------------------------------------------------------
  927. // Function: PrEnumerateProperties, public
  928. //
  929. // Synopsis: Enumerate properties in a property set
  930. //
  931. // Arguments: [np] -- property set context
  932. // [cskip] -- count of properties to skip
  933. // [pcprop] -- pointer to property count
  934. // [Flags] -- flags: No Names (propids only), etc.
  935. // [asps] -- array of STATPROPSTGs
  936. //
  937. // Returns: Status code
  938. //---------------------------------------------------------------------------
  939. NTSTATUS
  940. PrEnumerateProperties(
  941. IN NTPROP np, // property set context
  942. IN ULONG Flags, // flags: No Names (propids only), etc.
  943. IN ULONG *pkey, // count of properties to skip
  944. IN OUT ULONG *pcprop, // pointer to property count
  945. OPTIONAL OUT PROPSPEC aprs[],// IN: array of uninitialized PROPSPECs
  946. // OUT: may contain pointers to alloc'd strings
  947. OPTIONAL OUT STATPROPSTG asps[]) // IN: array of uninitialized STATPROPSTGs
  948. // OUT: may contain pointers to alloc'd strings
  949. {
  950. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  951. NTSTATUS Status = STATUS_SUCCESS;
  952. SERIALIZEDPROPERTYVALUE const *pprop = NULL;
  953. PROPSPEC *pprs;
  954. STATPROPSTG *psps;
  955. PROPID *ppidBase = NULL;
  956. ULONG i;
  957. ULONG cpropin;
  958. BOOL fLocked = FALSE;
  959. PROPID apidStack[20];
  960. PROPID *ppid;
  961. ULONG cprop;
  962. PMemoryAllocator *pma = ppsstm->GetAllocator();
  963. // PERF: It'd be good to rewrite this name code so that it uses
  964. // a default-sized stack buffer where possible, which will be most of
  965. // the time.
  966. OLECHAR *poszName = NULL;
  967. IFDBG( HRESULT &hr = Status );
  968. propITraceStatic( "PrEnumerateProperties" );
  969. propTraceParameters(( "np=%p, Flags=0x%x, key=0x%x, cprop=%d, aprs=%p, asps=%p)\n",
  970. np, Flags, *pkey, *pcprop, aprs, asps));
  971. cpropin = *pcprop;
  972. // Eliminate confusion for easy cleanup
  973. if (aprs != NULL)
  974. {
  975. // Set all the PropSpecs to PROPID (which require
  976. // no cleanup).
  977. for (i = 0; i < cpropin; i++)
  978. {
  979. aprs[i].ulKind = PRSPEC_PROPID;
  980. }
  981. }
  982. // Zero all pointers in the array for easy cleanup
  983. if (asps != NULL)
  984. {
  985. RtlZeroMemory(asps, cpropin * sizeof(asps[0]));
  986. }
  987. Status = ppsstm->Lock(FALSE);
  988. if( !NT_SUCCESS(Status) ) goto Exit;
  989. fLocked = TRUE;
  990. ppidBase = NULL;
  991. cprop = ppsstm->ReOpen(&Status); // Reload header/size info
  992. if( !NT_SUCCESS(Status) ) goto Exit;
  993. if (cprop > cpropin)
  994. {
  995. cprop = cpropin;
  996. }
  997. ppsstm->Validate(&Status);
  998. if( !NT_SUCCESS(Status) ) goto Exit;
  999. // Point ppid to an array of PROPIDs (either on stack for perf, or in heap
  1000. // if too big).
  1001. ppid = NULL;
  1002. if (aprs != NULL || asps != NULL)
  1003. {
  1004. ppid = apidStack;
  1005. if (cprop > sizeof(apidStack)/sizeof(apidStack[0]))
  1006. {
  1007. // Too big for the stack, alloc it out of heap.
  1008. ppidBase = reinterpret_cast<PROPID*>( CoTaskMemAlloc( cprop * sizeof(PROPID) ));
  1009. if (ppidBase == NULL)
  1010. {
  1011. Status = STATUS_INSUFFICIENT_RESOURCES;
  1012. goto Exit;
  1013. }
  1014. ppid = ppidBase;
  1015. }
  1016. }
  1017. // Enumerate the PROPIDs and put them into the PROPID array we
  1018. // just set up (ppid)
  1019. ppsstm->EnumeratePropids(pkey, &cprop, ppid, &Status);
  1020. if( !NT_SUCCESS(Status) ) goto Exit;
  1021. *pcprop = cprop;
  1022. // Load the STATPROPSTG array (asps) and PROPSPEC array (aprs)
  1023. if (ppid != NULL)
  1024. {
  1025. psps = asps;
  1026. pprs = aprs;
  1027. while (cprop-- > 0)
  1028. {
  1029. ULONG cbprop;
  1030. BOOLEAN fHasName;
  1031. PROPASSERT(*ppid != PID_DICTIONARY && *ppid != PID_CODEPAGE);
  1032. fHasName = FALSE;
  1033. // Unless the caller doesn't want names, get this property's name.
  1034. if ((Flags & ENUMPROP_NONAMES) == 0)
  1035. {
  1036. fHasName = ppsstm->QueryPropertyNames( 1, ppid, &poszName, &Status );
  1037. if( !NT_SUCCESS(Status) ) goto Exit;
  1038. }
  1039. // If we're filling in the PROPSPEC array, load the
  1040. // name or PROPID now.
  1041. if (pprs != NULL)
  1042. {
  1043. PROPASSERT(pprs->ulKind == PRSPEC_PROPID);
  1044. if (fHasName)
  1045. {
  1046. pprs->lpwstr = ppsstm->DuplicatePropertyName( poszName, &Status );
  1047. if( !NT_SUCCESS(Status) ) goto Exit;
  1048. PROPASSERT(pprs->lpwstr != NULL);
  1049. // Make this assignment *after* memory allocation
  1050. // succeeds so we free only valid pointers in below
  1051. // cleanup code.
  1052. pprs->ulKind = PRSPEC_LPWSTR;
  1053. }
  1054. else
  1055. {
  1056. pprs->propid = *ppid;
  1057. }
  1058. pprs++;
  1059. } // if (pprs != NULL)
  1060. // If we're passing back the STATPROPSTGs, fill it in for
  1061. // this property.
  1062. if (psps != NULL)
  1063. {
  1064. pprop = ppsstm->GetValue(*ppid, &cbprop, &Status);
  1065. if( !NT_SUCCESS(Status) ) goto Exit;
  1066. PROPASSERT(psps->lpwstrName == NULL);
  1067. if (fHasName)
  1068. {
  1069. psps->lpwstrName = ppsstm->DuplicatePropertyName( poszName, &Status);
  1070. if( !NT_SUCCESS(Status) ) goto Exit;
  1071. PROPASSERT(psps->lpwstrName != NULL);
  1072. }
  1073. psps->propid = *ppid;
  1074. psps->vt = (VARTYPE) PropByteSwap( pprop->dwType );
  1075. psps++;
  1076. } // if (psps != NULL)
  1077. ppid++;
  1078. CoTaskMemFree( poszName ); poszName = NULL;
  1079. } // while (cprop-- > 0)
  1080. } // if (ppid != NULL)
  1081. ppsstm->Validate(&Status);
  1082. if( !NT_SUCCESS(Status) ) goto Exit;
  1083. // ----
  1084. // Exit
  1085. // ----
  1086. Exit:
  1087. if (fLocked)
  1088. Status = Unlock( ppsstm, Status );
  1089. if( NULL != poszName )
  1090. CoTaskMemFree( poszName );
  1091. CoTaskMemFree( ppidBase );
  1092. if (!NT_SUCCESS(Status))
  1093. {
  1094. PMemoryAllocator *pma2 = ppsstm->GetAllocator();
  1095. if (aprs != NULL)
  1096. {
  1097. for (i = 0; i < cpropin; i++)
  1098. {
  1099. if (aprs[i].ulKind == PRSPEC_LPWSTR)
  1100. {
  1101. pma2->Free(aprs[i].lpwstr);
  1102. aprs[i].ulKind = PRSPEC_PROPID;
  1103. }
  1104. }
  1105. }
  1106. if (asps != NULL)
  1107. {
  1108. for (i = 0; i < cpropin; i++)
  1109. {
  1110. if (asps[i].lpwstrName != NULL)
  1111. {
  1112. pma2->Free(asps[i].lpwstrName);
  1113. asps[i].lpwstrName = NULL;
  1114. }
  1115. }
  1116. }
  1117. } // if (!NT_SUCCESS(Status))
  1118. #if DBG
  1119. if (NT_SUCCESS(Status))
  1120. {
  1121. if (aprs != NULL)
  1122. {
  1123. for (i = 0; i < cpropin; i++)
  1124. {
  1125. if (aprs[i].ulKind == PRSPEC_LPWSTR)
  1126. {
  1127. PROPASSERT(aprs[i].lpwstr != NULL);
  1128. PROPASSERT(ocslen(aprs[i].lpwstr) > 0);
  1129. }
  1130. }
  1131. }
  1132. if (asps != NULL)
  1133. {
  1134. for (i = 0; i < cpropin; i++)
  1135. {
  1136. if (asps[i].lpwstrName != NULL)
  1137. {
  1138. PROPASSERT(ocslen(asps[i].lpwstrName) > 0);
  1139. }
  1140. }
  1141. }
  1142. }
  1143. #endif // DBG
  1144. return(Status);
  1145. }
  1146. //+---------------------------------------------------------------------------
  1147. // Function: PrQueryPropertyNames, public
  1148. //
  1149. // Synopsis: Read property names for PROPIDs in a property set
  1150. //
  1151. // Arguments: [np] -- property set context
  1152. // [cprop] -- property count
  1153. // [apid] -- array of PROPIDs
  1154. // [aposz] -- array of pointers to WCHAR strings
  1155. //
  1156. // Returns: Status code
  1157. //---------------------------------------------------------------------------
  1158. NTSTATUS
  1159. PrQueryPropertyNames(
  1160. IN NTPROP np, // property set context
  1161. IN ULONG cprop, // property count
  1162. IN PROPID const *apid, // PROPID array
  1163. OUT OLECHAR *aposz[]) // OUT pointers to allocated strings
  1164. {
  1165. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  1166. NTSTATUS Status = STATUS_SUCCESS;
  1167. NTSTATUS StatusQuery = STATUS_SUCCESS;
  1168. BOOL fLocked = FALSE;
  1169. IFDBG( HRESULT &hr = Status );
  1170. propITraceStatic( "PrQueryPropertyNames" );
  1171. propTraceParameters(( "np=%p, cprop=%d, apid=%p, aposz=%p)",
  1172. np, cprop, apid, aposz ));
  1173. RtlZeroMemory(aposz, cprop * sizeof(aposz[0]));
  1174. Status = ppsstm->Lock(FALSE);
  1175. if( !NT_SUCCESS(Status) ) goto Exit;
  1176. fLocked = TRUE;
  1177. ppsstm->ReOpen(&Status); // Reload header/size info
  1178. if( !NT_SUCCESS(Status) ) goto Exit;
  1179. ppsstm->Validate(&Status);
  1180. if( !NT_SUCCESS(Status) ) goto Exit;
  1181. // We'll save the Status from the following call. If there
  1182. // are no other errors, we'll return it to the caller (it
  1183. // might contain a useful success code).
  1184. ppsstm->QueryPropertyNames(cprop, apid, aposz, &StatusQuery);
  1185. if( !NT_SUCCESS(StatusQuery) )
  1186. {
  1187. Status = StatusQuery;
  1188. goto Exit;
  1189. }
  1190. ppsstm->Validate(&Status);
  1191. if( !NT_SUCCESS(Status) ) goto Exit;
  1192. // ----
  1193. // Exit
  1194. // ----
  1195. Exit:
  1196. if (fLocked)
  1197. Status = Unlock( ppsstm, Status );
  1198. if( NT_SUCCESS(Status) )
  1199. Status = StatusQuery;
  1200. return(Status);
  1201. } // PrQueryPropertyNames()
  1202. //+---------------------------------------------------------------------------
  1203. // Function: PrSetPropertyNames, public
  1204. //
  1205. // Synopsis: Write property names for PROPIDs in a property set
  1206. //
  1207. // Arguments: [np] -- property set context
  1208. // [cprop] -- property count
  1209. // [apid] -- array of PROPIDs
  1210. // [aposz] -- array of pointers to OLECHAR strings
  1211. //
  1212. // Returns: Status code
  1213. //---------------------------------------------------------------------------
  1214. NTSTATUS
  1215. PrSetPropertyNames(
  1216. IN NTPROP np, // property set context
  1217. IN ULONG cprop, // property count
  1218. IN PROPID const *apid, // PROPID array
  1219. IN OLECHAR const * const aposz[]) // pointers to property names
  1220. {
  1221. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  1222. NTSTATUS Status = STATUS_SUCCESS;
  1223. BOOL fLocked = FALSE;
  1224. IFDBG( HRESULT &hr = Status );
  1225. propITraceStatic( "PrSetPropertyNames" );
  1226. propTraceParameters(( "np=%p, cprop=%d, apid=%p, aposz=%p",
  1227. np, cprop, apid, aposz ));
  1228. Status = ppsstm->Lock(TRUE);
  1229. if( !NT_SUCCESS(Status) ) goto Exit;
  1230. fLocked = TRUE;
  1231. ppsstm->ReOpen(&Status); // Reload header/size info
  1232. if( !NT_SUCCESS(Status) ) goto Exit;
  1233. ppsstm->Validate(&Status);
  1234. if( !NT_SUCCESS(Status) ) goto Exit;
  1235. ppsstm->SetPropertyNames(cprop, apid, aposz, &Status);
  1236. if( !NT_SUCCESS(Status) ) goto Exit;
  1237. ppsstm->Validate(&Status);
  1238. if( !NT_SUCCESS(Status) ) goto Exit;
  1239. // ----
  1240. // Exit
  1241. // ----
  1242. Exit:
  1243. if (fLocked)
  1244. Status = Unlock( ppsstm, Status );
  1245. return(Status);
  1246. } // PrSetPropertyNames()
  1247. //+---------------------------------------------------------------------------
  1248. // Function: PrSetPropertySetClassId, public
  1249. //
  1250. // Synopsis: Set the property set's ClassId
  1251. //
  1252. // Arguments: [np] -- property set context
  1253. // [pspss] -- pointer to STATPROPSETSTG
  1254. //
  1255. // Returns: Status code
  1256. //---------------------------------------------------------------------------
  1257. NTSTATUS
  1258. PrSetPropertySetClassId(
  1259. IN NTPROP np, // property set context
  1260. IN GUID const *pclsid) // new CLASSID of propset code
  1261. {
  1262. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  1263. NTSTATUS Status = STATUS_SUCCESS;
  1264. BOOL fLocked = FALSE;
  1265. IFDBG( HRESULT &hr = Status );
  1266. propITraceStatic( "PrSetPropertySetClassId" );
  1267. propTraceParameters(( "np=%p, pclsid=%p", np, pclsid ));
  1268. Status = ppsstm->Lock(TRUE);
  1269. if( !NT_SUCCESS(Status) ) goto Exit;
  1270. fLocked = TRUE;
  1271. ppsstm->ReOpen(&Status); // Reload header/size info
  1272. if( !NT_SUCCESS(Status) ) goto Exit;
  1273. ppsstm->Validate(&Status);
  1274. if( !NT_SUCCESS(Status) ) goto Exit;
  1275. ppsstm->SetClassId(pclsid, &Status);
  1276. if( !NT_SUCCESS(Status) ) goto Exit;
  1277. ppsstm->Validate(&Status);
  1278. if( !NT_SUCCESS(Status) ) goto Exit;
  1279. // ----
  1280. // Exit
  1281. // ----
  1282. Exit:
  1283. if (fLocked)
  1284. Status = Unlock( ppsstm, Status );
  1285. return(Status);
  1286. } // PrSetPropertySetClassId()
  1287. //+---------------------------------------------------------------------------
  1288. // Function: PrQueryPropertySet, public
  1289. //
  1290. // Synopsis: Query the passed property set
  1291. //
  1292. // Arguments: [np] -- property set context
  1293. // [pspss] -- pointer to STATPROPSETSTG
  1294. //
  1295. // Returns: Status code
  1296. //---------------------------------------------------------------------------
  1297. NTSTATUS
  1298. PrQueryPropertySet(
  1299. IN NTPROP np, // property set context
  1300. OUT STATPROPSETSTG *pspss) // buffer for property set stat information
  1301. {
  1302. NTSTATUS Status = STATUS_SUCCESS;
  1303. BOOL fLocked = FALSE;
  1304. CPropertySetStream *ppsstm = (CPropertySetStream *) np;
  1305. IFDBG( HRESULT &hr = Status );
  1306. propITraceStatic( "PrQueryPropertySet" );
  1307. propTraceParameters(( "np=%p, pspss=%p", np, pspss ));
  1308. RtlZeroMemory(pspss, sizeof(*pspss));
  1309. Status = ppsstm->Lock(FALSE);
  1310. if( !NT_SUCCESS(Status) ) goto Exit;
  1311. fLocked = TRUE;
  1312. ppsstm->ReOpen(&Status); // Reload header/size info
  1313. if( !NT_SUCCESS(Status) ) goto Exit;
  1314. ppsstm->Validate(&Status);
  1315. if( !NT_SUCCESS(Status) ) goto Exit;
  1316. ppsstm->QueryPropertySet(pspss, &Status);
  1317. if( !NT_SUCCESS(Status) ) goto Exit;
  1318. ppsstm->Validate(&Status);
  1319. if( !NT_SUCCESS(Status) ) goto Exit;
  1320. // ----
  1321. // Exit
  1322. // ----
  1323. Exit:
  1324. if (fLocked)
  1325. Status = Unlock( ppsstm, Status );
  1326. return(Status);
  1327. } // PrQueryPropertySet()
  1328. inline BOOLEAN
  1329. _Compare_VT_BOOL(VARIANT_BOOL bool1, VARIANT_BOOL bool2)
  1330. {
  1331. // Allow any non-zero value to match any non-zero value
  1332. return((bool1 == FALSE) == (bool2 == FALSE));
  1333. }
  1334. BOOLEAN
  1335. _Compare_VT_CF(CLIPDATA *pclipdata1, CLIPDATA *pclipdata2)
  1336. {
  1337. BOOLEAN fSame;
  1338. if (pclipdata1 != NULL && pclipdata2 != NULL)
  1339. {
  1340. fSame = ( pclipdata1->cbSize == pclipdata2->cbSize
  1341. &&
  1342. pclipdata1->ulClipFmt == pclipdata2->ulClipFmt );
  1343. if (fSame)
  1344. {
  1345. if (pclipdata1->pClipData != NULL && pclipdata2->pClipData != NULL)
  1346. {
  1347. fSame = memcmp(
  1348. pclipdata1->pClipData,
  1349. pclipdata2->pClipData,
  1350. CBPCLIPDATA(*pclipdata1)
  1351. ) == 0;
  1352. }
  1353. else
  1354. {
  1355. // They're the same if both are NULL, or if
  1356. // they have a zero length (if they have a zero
  1357. // length, either one may or may not be NULL, but they're
  1358. // still considered the same).
  1359. // Note that CBPCLIPDATA(*pclipdata1)==CBPCLIPDATA(*pclipdata2).
  1360. fSame = pclipdata1->pClipData == pclipdata2->pClipData
  1361. ||
  1362. CBPCLIPDATA(*pclipdata1) == 0;
  1363. }
  1364. }
  1365. }
  1366. else
  1367. {
  1368. fSame = pclipdata1 == pclipdata2;
  1369. }
  1370. return(fSame);
  1371. }
  1372. //+---------------------------------------------------------------------------
  1373. // Function: PrCompareVariants, public
  1374. //
  1375. // Synopsis: Compare two passed PROPVARIANTs -- case sensitive for strings
  1376. //
  1377. // Arguments: [CodePage] -- CodePage
  1378. // [pvar1] -- pointer to PROPVARIANT
  1379. // [pvar2] -- pointer to PROPVARIANT
  1380. //
  1381. // Returns: TRUE if identical, else FALSE
  1382. //---------------------------------------------------------------------------
  1383. #ifdef _MAC
  1384. EXTERN_C // The Mac linker doesn't seem to be able to export with C++ decorations
  1385. #endif
  1386. BOOLEAN
  1387. PrCompareVariants(
  1388. USHORT CodePage,
  1389. PROPVARIANT const *pvar1,
  1390. PROPVARIANT const *pvar2)
  1391. {
  1392. if (pvar1->vt != pvar2->vt)
  1393. {
  1394. return(FALSE);
  1395. }
  1396. BOOLEAN fSame;
  1397. ULONG i;
  1398. switch (pvar1->vt)
  1399. {
  1400. case VT_EMPTY:
  1401. case VT_NULL:
  1402. fSame = TRUE;
  1403. break;
  1404. case VT_I1:
  1405. case VT_UI1:
  1406. fSame = pvar1->bVal == pvar2->bVal;
  1407. break;
  1408. case VT_I2:
  1409. case VT_UI2:
  1410. fSame = pvar1->iVal == pvar2->iVal;
  1411. break;
  1412. case VT_BOOL:
  1413. fSame = _Compare_VT_BOOL(pvar1->boolVal, pvar2->boolVal);
  1414. break;
  1415. case VT_I4:
  1416. case VT_UI4:
  1417. case VT_R4:
  1418. case VT_ERROR:
  1419. fSame = pvar1->lVal == pvar2->lVal;
  1420. break;
  1421. case VT_I8:
  1422. case VT_UI8:
  1423. case VT_R8:
  1424. case VT_CY:
  1425. case VT_DATE:
  1426. case VT_FILETIME:
  1427. fSame = pvar1->hVal.HighPart == pvar2->hVal.HighPart
  1428. &&
  1429. pvar1->hVal.LowPart == pvar2->hVal.LowPart;
  1430. break;
  1431. case VT_CLSID:
  1432. fSame = memcmp(pvar1->puuid, pvar2->puuid, sizeof(CLSID)) == 0;
  1433. break;
  1434. case VT_BLOB:
  1435. case VT_BLOB_OBJECT:
  1436. fSame = ( pvar1->blob.cbSize == pvar2->blob.cbSize );
  1437. if (fSame)
  1438. {
  1439. fSame = memcmp(
  1440. pvar1->blob.pBlobData,
  1441. pvar2->blob.pBlobData,
  1442. pvar1->blob.cbSize) == 0;
  1443. }
  1444. break;
  1445. case VT_CF:
  1446. fSame = _Compare_VT_CF(pvar1->pclipdata, pvar2->pclipdata);
  1447. break;
  1448. case VT_BSTR:
  1449. if (pvar1->bstrVal != NULL && pvar2->bstrVal != NULL)
  1450. {
  1451. fSame = ( BSTRLEN(pvar1->bstrVal) == BSTRLEN(pvar2->bstrVal) );
  1452. if (fSame)
  1453. {
  1454. fSame = memcmp(
  1455. pvar1->bstrVal,
  1456. pvar2->bstrVal,
  1457. BSTRLEN(pvar1->bstrVal)) == 0;
  1458. }
  1459. }
  1460. else
  1461. {
  1462. fSame = pvar1->bstrVal == pvar2->bstrVal;
  1463. }
  1464. break;
  1465. case VT_LPSTR:
  1466. if (pvar1->pszVal != NULL && pvar2->pszVal != NULL)
  1467. {
  1468. fSame = strcmp(pvar1->pszVal, pvar2->pszVal) == 0;
  1469. }
  1470. else
  1471. {
  1472. fSame = pvar1->pszVal == pvar2->pszVal;
  1473. }
  1474. break;
  1475. case VT_STREAM:
  1476. case VT_STREAMED_OBJECT:
  1477. case VT_STORAGE:
  1478. case VT_STORED_OBJECT:
  1479. case VT_LPWSTR:
  1480. if (pvar1->pwszVal != NULL && pvar2->pwszVal != NULL)
  1481. {
  1482. fSame = Prop_wcscmp(pvar1->pwszVal, pvar2->pwszVal) == 0;
  1483. }
  1484. else
  1485. {
  1486. fSame = pvar1->pwszVal == pvar2->pwszVal;
  1487. }
  1488. break;
  1489. case VT_VECTOR | VT_I1:
  1490. case VT_VECTOR | VT_UI1:
  1491. fSame = ( pvar1->caub.cElems == pvar2->caub.cElems );
  1492. if (fSame)
  1493. {
  1494. fSame = memcmp(
  1495. pvar1->caub.pElems,
  1496. pvar2->caub.pElems,
  1497. pvar1->caub.cElems * sizeof(pvar1->caub.pElems[0])) == 0;
  1498. }
  1499. break;
  1500. case VT_VECTOR | VT_I2:
  1501. case VT_VECTOR | VT_UI2:
  1502. fSame = ( pvar1->cai.cElems == pvar2->cai.cElems );
  1503. if (fSame)
  1504. {
  1505. fSame = memcmp(
  1506. pvar1->cai.pElems,
  1507. pvar2->cai.pElems,
  1508. pvar1->cai.cElems * sizeof(pvar1->cai.pElems[0])) == 0;
  1509. }
  1510. break;
  1511. case VT_VECTOR | VT_BOOL:
  1512. fSame = ( pvar1->cabool.cElems == pvar2->cabool.cElems );
  1513. if (fSame)
  1514. {
  1515. for (i = 0; i < pvar1->cabool.cElems; i++)
  1516. {
  1517. fSame = _Compare_VT_BOOL(
  1518. pvar1->cabool.pElems[i],
  1519. pvar2->cabool.pElems[i]);
  1520. if (!fSame)
  1521. {
  1522. break;
  1523. }
  1524. }
  1525. }
  1526. break;
  1527. case VT_VECTOR | VT_I4:
  1528. case VT_VECTOR | VT_UI4:
  1529. case VT_VECTOR | VT_R4:
  1530. case VT_VECTOR | VT_ERROR:
  1531. fSame = ( pvar1->cal.cElems == pvar2->cal.cElems );
  1532. if (fSame)
  1533. {
  1534. fSame = memcmp(
  1535. pvar1->cal.pElems,
  1536. pvar2->cal.pElems,
  1537. pvar1->cal.cElems * sizeof(pvar1->cal.pElems[0])) == 0;
  1538. }
  1539. break;
  1540. case VT_VECTOR | VT_I8:
  1541. case VT_VECTOR | VT_UI8:
  1542. case VT_VECTOR | VT_R8:
  1543. case VT_VECTOR | VT_CY:
  1544. case VT_VECTOR | VT_DATE:
  1545. case VT_VECTOR | VT_FILETIME:
  1546. fSame = ( pvar1->cah.cElems == pvar2->cah.cElems );
  1547. if (fSame)
  1548. {
  1549. fSame = memcmp(
  1550. pvar1->cah.pElems,
  1551. pvar2->cah.pElems,
  1552. pvar1->cah.cElems *
  1553. sizeof(pvar1->cah.pElems[0])) == 0;
  1554. }
  1555. break;
  1556. case VT_VECTOR | VT_CLSID:
  1557. fSame = ( pvar1->cauuid.cElems == pvar2->cauuid.cElems );
  1558. if (fSame)
  1559. {
  1560. fSame = memcmp(
  1561. pvar1->cauuid.pElems,
  1562. pvar2->cauuid.pElems,
  1563. pvar1->cauuid.cElems *
  1564. sizeof(pvar1->cauuid.pElems[0])) == 0;
  1565. }
  1566. break;
  1567. case VT_VECTOR | VT_CF:
  1568. fSame = ( pvar1->caclipdata.cElems == pvar2->caclipdata.cElems );
  1569. if (fSame)
  1570. {
  1571. for (i = 0; i < pvar1->caclipdata.cElems; i++)
  1572. {
  1573. fSame = _Compare_VT_CF(
  1574. &pvar1->caclipdata.pElems[i],
  1575. &pvar2->caclipdata.pElems[i]);
  1576. if (!fSame)
  1577. {
  1578. break;
  1579. }
  1580. }
  1581. }
  1582. break;
  1583. case VT_VECTOR | VT_BSTR:
  1584. fSame = ( pvar1->cabstr.cElems == pvar2->cabstr.cElems );
  1585. if (fSame)
  1586. {
  1587. for (i = 0; i < pvar1->cabstr.cElems; i++)
  1588. {
  1589. if (pvar1->cabstr.pElems[i] != NULL &&
  1590. pvar2->cabstr.pElems[i] != NULL)
  1591. {
  1592. fSame = ( BSTRLEN(pvar1->cabstr.pElems[i])
  1593. ==
  1594. BSTRLEN(pvar2->cabstr.pElems[i]) );
  1595. if (fSame)
  1596. {
  1597. fSame = memcmp(
  1598. pvar1->cabstr.pElems[i],
  1599. pvar2->cabstr.pElems[i],
  1600. BSTRLEN(pvar1->cabstr.pElems[i])) == 0;
  1601. }
  1602. }
  1603. else
  1604. {
  1605. fSame = pvar1->cabstr.pElems[i] == pvar2->cabstr.pElems[i];
  1606. }
  1607. if (!fSame)
  1608. {
  1609. break;
  1610. }
  1611. }
  1612. }
  1613. break;
  1614. case VT_VECTOR | VT_LPSTR:
  1615. fSame = ( pvar1->calpstr.cElems == pvar2->calpstr.cElems );
  1616. if (fSame)
  1617. {
  1618. for (i = 0; i < pvar1->calpstr.cElems; i++)
  1619. {
  1620. if (pvar1->calpstr.pElems[i] != NULL &&
  1621. pvar2->calpstr.pElems[i] != NULL)
  1622. {
  1623. fSame = strcmp(
  1624. pvar1->calpstr.pElems[i],
  1625. pvar2->calpstr.pElems[i]) == 0;
  1626. }
  1627. else
  1628. {
  1629. fSame = pvar1->calpstr.pElems[i] ==
  1630. pvar2->calpstr.pElems[i];
  1631. }
  1632. if (!fSame)
  1633. {
  1634. break;
  1635. }
  1636. }
  1637. }
  1638. break;
  1639. case VT_VECTOR | VT_LPWSTR:
  1640. fSame = ( pvar1->calpwstr.cElems == pvar2->calpwstr.cElems );
  1641. if (fSame)
  1642. {
  1643. for (i = 0; i < pvar1->calpwstr.cElems; i++)
  1644. {
  1645. if (pvar1->calpwstr.pElems[i] != NULL &&
  1646. pvar2->calpwstr.pElems[i] != NULL)
  1647. {
  1648. fSame = Prop_wcscmp(
  1649. pvar1->calpwstr.pElems[i],
  1650. pvar2->calpwstr.pElems[i]) == 0;
  1651. }
  1652. else
  1653. {
  1654. fSame = pvar1->calpwstr.pElems[i] ==
  1655. pvar2->calpwstr.pElems[i];
  1656. }
  1657. if (!fSame)
  1658. {
  1659. break;
  1660. }
  1661. }
  1662. }
  1663. break;
  1664. case VT_VECTOR | VT_VARIANT:
  1665. fSame = ( pvar1->capropvar.cElems == pvar2->capropvar.cElems );
  1666. if (fSame)
  1667. {
  1668. for (i = 0; i < pvar1->capropvar.cElems; i++)
  1669. {
  1670. fSame = PrCompareVariants(
  1671. CodePage,
  1672. &pvar1->capropvar.pElems[i],
  1673. &pvar2->capropvar.pElems[i]);
  1674. if (!fSame)
  1675. {
  1676. break;
  1677. }
  1678. }
  1679. }
  1680. break;
  1681. default:
  1682. PROPASSERT(!"Invalid type for PROPVARIANT Comparison");
  1683. fSame = FALSE;
  1684. break;
  1685. }
  1686. return(fSame);
  1687. }