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.

1635 lines
44 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORP., 1999
  4. *
  5. * TITLE: wiapsc.cpp
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ByronC
  10. *
  11. * DATE: 2 June, 1999
  12. *
  13. * DESCRIPTION:
  14. * Implementation for the WIA Property Storage class.
  15. *
  16. *******************************************************************************/
  17. #include "precomp.h"
  18. #include "stiexe.h"
  19. #include <wiamindr.h>
  20. #include "helpers.h"
  21. #include "wiapsc.h"
  22. /**************************************************************************\
  23. * CurStg
  24. *
  25. * Returns the IPropertyStorage used to store the current property values.
  26. *
  27. * Arguments:
  28. *
  29. *
  30. * Return Value:
  31. *
  32. * IPropertyStorage for current values.
  33. *
  34. * History:
  35. *
  36. * 06/03/1999 Original Version
  37. *
  38. \**************************************************************************/
  39. IPropertyStorage* _stdcall CWiaPropStg::CurStg()
  40. {
  41. return m_pIPropStg[WIA_CUR_STG];
  42. }
  43. /**************************************************************************\
  44. * CurStm
  45. *
  46. * Returns the IStream used to store the current property values.
  47. *
  48. * Arguments:
  49. *
  50. *
  51. * Return Value:
  52. *
  53. * IStream for current values.
  54. *
  55. * History:
  56. *
  57. * 06/03/1999 Original Version
  58. *
  59. \**************************************************************************/
  60. IStream* _stdcall CWiaPropStg::CurStm()
  61. {
  62. return m_pIStream[WIA_CUR_STG];
  63. }
  64. /**************************************************************************\
  65. * OldStg
  66. *
  67. * Returns the IPropertyStorage used to store the old property values.
  68. *
  69. * Arguments:
  70. *
  71. *
  72. * Return Value:
  73. *
  74. * IPropertyStorage for old values.
  75. *
  76. * History:
  77. *
  78. * 06/03/1999 Original Version
  79. *
  80. \**************************************************************************/
  81. IPropertyStorage* _stdcall CWiaPropStg::OldStg()
  82. {
  83. return m_pIPropStg[WIA_OLD_STG];
  84. }
  85. /**************************************************************************\
  86. * OldStm
  87. *
  88. * Returns the IStream used to store the old property values.
  89. *
  90. * Arguments:
  91. *
  92. *
  93. * Return Value:
  94. *
  95. * IStream for old values.
  96. *
  97. * History:
  98. *
  99. * 06/03/1999 Original Version
  100. *
  101. \**************************************************************************/
  102. IStream* _stdcall CWiaPropStg::OldStm()
  103. {
  104. return m_pIStream[WIA_OLD_STG];
  105. }
  106. /**************************************************************************\
  107. * ValidStg
  108. *
  109. * Returns the IPropertyStorage used to store the valid values.
  110. *
  111. * Arguments:
  112. *
  113. *
  114. * Return Value:
  115. *
  116. * IPropertyStorage for valid values.
  117. *
  118. * History:
  119. *
  120. * 06/03/1999 Original Version
  121. *
  122. \**************************************************************************/
  123. IPropertyStorage* _stdcall CWiaPropStg::ValidStg()
  124. {
  125. return m_pIPropStg[WIA_VALID_STG];
  126. }
  127. /**************************************************************************\
  128. * ValidStm
  129. *
  130. * Returns the IStream used to store the current property values.
  131. *
  132. * Arguments:
  133. *
  134. *
  135. * Return Value:
  136. *
  137. * IStream for valid values.
  138. *
  139. * History:
  140. *
  141. * 06/03/1999 Original Version
  142. *
  143. \**************************************************************************/
  144. IStream* _stdcall CWiaPropStg::ValidStm()
  145. {
  146. return m_pIStream[WIA_VALID_STG];
  147. }
  148. /**************************************************************************\
  149. * AccessStg
  150. *
  151. * Returns the IPropertyStorage used to store the access flags.
  152. *
  153. * Arguments:
  154. *
  155. *
  156. * Return Value:
  157. *
  158. * IPropertyStorage for access values.
  159. *
  160. * History:
  161. *
  162. * 06/03/1999 Original Version
  163. *
  164. \**************************************************************************/
  165. IPropertyStorage* _stdcall CWiaPropStg::AccessStg()
  166. {
  167. return m_pIPropStg[WIA_ACCESS_STG];
  168. }
  169. /**************************************************************************\
  170. * AccessStm
  171. *
  172. * Returns the IStream used to store the access flag values.
  173. *
  174. * Arguments:
  175. *
  176. *
  177. * Return Value:
  178. *
  179. * IStream for access values.
  180. *
  181. * History:
  182. *
  183. * 06/03/1999 Original Version
  184. *
  185. \**************************************************************************/
  186. IStream* _stdcall CWiaPropStg::AccessStm()
  187. {
  188. return m_pIStream[WIA_ACCESS_STG];
  189. }
  190. /**************************************************************************\
  191. * Backup
  192. *
  193. * This sets the backup storages and sets the old value storage. The
  194. * backup storages are created here, but are released when either
  195. * Undo() or Save() are called (since they're no longer needed until the
  196. * next call to Backup()).
  197. *
  198. * Arguments:
  199. *
  200. *
  201. * Return Value:
  202. *
  203. * Status - S_OK if successful
  204. * - Error returns are those returned by CreateStorage
  205. * and CopyProps
  206. *
  207. * History:
  208. *
  209. * 06/03/1999 Original Version
  210. *
  211. \**************************************************************************/
  212. HRESULT _stdcall CWiaPropStg::Backup()
  213. {
  214. HRESULT hr = S_OK;
  215. ULONG ulIndexOfBackup;
  216. for (int lIndex = 0; lIndex < NUM_BACKUP_STG; lIndex++) {
  217. //
  218. // The normal storage indexes run from top to bottom, while their
  219. // corresponding backup storage indexes run from bottom to top -
  220. // this is to simplify the implementation of Backup()
  221. //
  222. ulIndexOfBackup = NUM_PROP_STG - (lIndex + 1);
  223. //
  224. // Create the corresponding backup storage.
  225. //
  226. hr = CreateStorage(ulIndexOfBackup);
  227. if (SUCCEEDED(hr)) {
  228. //
  229. // Make the backup copy.
  230. //
  231. hr = CopyProps(m_pIPropStg[lIndex],
  232. m_pIPropStg[ulIndexOfBackup]);
  233. if (FAILED(hr)) {
  234. DBG_ERR(("CWiaPropStg::Backup, CopyProps failed"));
  235. break;
  236. }
  237. } else {
  238. break;
  239. }
  240. }
  241. if (SUCCEEDED(hr)) {
  242. //
  243. // Backups worked, so set the old property values to the
  244. // current property values.
  245. //
  246. hr = CopyProps(CurStg(), OldStg());
  247. if (FAILED(hr)) {
  248. DBG_ERR(("CWiaPropStg::Backup, Could not set old values"));
  249. }
  250. }
  251. if (FAILED(hr)) {
  252. //
  253. // There was a failure, so clean up
  254. //
  255. ReleaseBackups();
  256. }
  257. return hr;
  258. }
  259. /**************************************************************************\
  260. * Undo
  261. *
  262. * This method is called if the properties fail validation and need to be
  263. * restored to their previous values. The backup storages are then
  264. * released.
  265. *
  266. * Arguments:
  267. *
  268. *
  269. * Return Value:
  270. *
  271. * Status -
  272. *
  273. * History:
  274. *
  275. * 06/03/1999 Original Version
  276. *
  277. \**************************************************************************/
  278. HRESULT _stdcall CWiaPropStg::Undo()
  279. {
  280. HRESULT hr = S_OK;
  281. ULONG ulIndexOfBackup;
  282. for (int lIndex = 0; lIndex < NUM_BACKUP_STG; lIndex++) {
  283. //
  284. // Restore the backup copy.
  285. //
  286. ulIndexOfBackup = NUM_PROP_STG - (lIndex + 1);
  287. hr = CopyProps(m_pIPropStg[ulIndexOfBackup],
  288. m_pIPropStg[lIndex]);
  289. if (FAILED(hr)) {
  290. DBG_ERR(("CWiaPropStg::Undo, CopyProps failed"));
  291. break;
  292. }
  293. }
  294. ReleaseBackups();
  295. return hr;
  296. }
  297. /**************************************************************************\
  298. * Initialize
  299. *
  300. * This method is called to set up the property streams and storages.
  301. * If the any of the creation fails, CleanUp() is called.
  302. *
  303. * Arguments:
  304. *
  305. *
  306. * Return Value:
  307. *
  308. * Status - S_OK if successful
  309. * - E_OUTOFMEMORY if not enough memory
  310. *
  311. * History:
  312. *
  313. * 06/03/1999 Original Version
  314. *
  315. \**************************************************************************/
  316. HRESULT _stdcall CWiaPropStg::Initialize()
  317. {
  318. HRESULT hr = S_OK;
  319. for (int lIndex = 0; lIndex < (NUM_PROP_STG - NUM_BACKUP_STG); lIndex++) {
  320. hr = CreateStorage(lIndex);
  321. if (FAILED(hr)) {
  322. break;
  323. }
  324. }
  325. return hr;
  326. }
  327. /**************************************************************************\
  328. * ReleaseBackups
  329. *
  330. * This frees all resources used by the backup storages.
  331. *
  332. * Arguments:
  333. *
  334. *
  335. * Return Value:
  336. *
  337. *
  338. * History:
  339. *
  340. * 06/03/1999 Original Version
  341. *
  342. \**************************************************************************/
  343. HRESULT _stdcall CWiaPropStg::ReleaseBackups()
  344. {
  345. LONG lIndex;
  346. //
  347. // Release the property storages and property streams. Start at the
  348. // last element in the array, and work up until the number of
  349. // backup storages has been reached.
  350. // The normal storage indexes run from top to bottom, while their
  351. // corresponding backup storage indexes run from bottom to top
  352. //
  353. for (int count = 1; count <= NUM_BACKUP_STG; count++) {
  354. lIndex = NUM_PROP_STG - count;
  355. if(m_pIPropStg[lIndex]) {
  356. m_pIPropStg[lIndex]->Release();
  357. m_pIPropStg[lIndex] = NULL;
  358. }
  359. if(m_pIStream[lIndex]) {
  360. m_pIStream[lIndex]->Release();
  361. m_pIStream[lIndex] = NULL;
  362. }
  363. }
  364. return S_OK;
  365. }
  366. /**************************************************************************\
  367. * CheckPropertyAccess
  368. *
  369. * This method checks the access flags for specified properties, and
  370. * fails if the access flags allow READ only access. Application
  371. * written properties will have no access flags and so are assumed
  372. * OK.
  373. *
  374. * Arguments:
  375. *
  376. * bShowErrors - specifies whether debug output should be shown when
  377. * an error occurs. This flag exists so that some methods
  378. * can skip over properties which don't have the correct
  379. * access flags set.
  380. * rgpspec - array of PROPSPECs specifying the properties.
  381. * cpspec - number of elements in rgpspec.
  382. *
  383. * Return Value:
  384. *
  385. * Status - S_OK if the access flags do not prohibit WRITEs.
  386. * E_POINTER if rgpspec is a bad read pointer.
  387. * E_ACCESSDENIED if any access does not allow WRITE
  388. * access.
  389. *
  390. * History:
  391. *
  392. * 28/04/1999 Original Version
  393. *
  394. \**************************************************************************/
  395. HRESULT _stdcall CWiaPropStg::CheckPropertyAccess(
  396. BOOL bShowErrors,
  397. LONG cpspec,
  398. PROPSPEC *rgpspec)
  399. {
  400. PROPVARIANT *ppvAccess;
  401. HRESULT hr;
  402. //
  403. // PROPSPEC pointer has not been checked yet, so check that it is valid.
  404. //
  405. if (IsBadWritePtr(rgpspec, sizeof(PROPSPEC) * cpspec)) {
  406. DBG_ERR(("CWiaPropStg::CheckPropertyAccess, PROPSPEC array is invalid"));
  407. return E_POINTER;
  408. }
  409. ppvAccess = (PROPVARIANT*) LocalAlloc(LPTR, sizeof(PROPVARIANT) * cpspec);
  410. if (ppvAccess) {
  411. hr = (AccessStg())->ReadMultiple(cpspec,
  412. rgpspec,
  413. ppvAccess);
  414. if (hr == S_OK) {
  415. for (LONG i = 0; i < cpspec; i++) {
  416. if (ppvAccess[i].vt == VT_EMPTY) {
  417. //
  418. // This is an application written property
  419. //
  420. hr = S_OK;
  421. } else if (!(ppvAccess[i].ulVal & WIA_PROP_WRITE)) {
  422. if (!bShowErrors) {
  423. hr = E_ACCESSDENIED;
  424. break;
  425. }
  426. #ifdef WIA_DEBUG
  427. if (rgpspec[i].ulKind == PRSPEC_PROPID) {
  428. DBG_ERR(("CWiaPropStg::CheckPropertyAccess, no write access on prop ID: %d (%ws)",
  429. rgpspec[i].propid,
  430. GetNameFromWiaPropId(rgpspec[i].propid)));
  431. }
  432. else if (rgpspec[i].ulKind == PRSPEC_LPWSTR) {
  433. DBG_ERR(("CWiaPropStg::CheckPropertyAccess, no write access prop ID: %ls", rgpspec[i].lpwstr));
  434. }
  435. else {
  436. DBG_ERR(("CWiaPropStg::CheckPropertyAccess, bad property specification"));
  437. hr = E_INVALIDARG;
  438. break;
  439. }
  440. #endif
  441. hr = E_ACCESSDENIED;
  442. }
  443. if (FAILED(hr)) {
  444. break;
  445. }
  446. }
  447. } else {
  448. //
  449. // ??? What about the application written property case?
  450. // If return is S_FALSE then all the specified properties are
  451. // application written properties so return OK.
  452. //
  453. if (hr == S_FALSE) {
  454. hr = S_OK;
  455. } else {
  456. ReportReadWriteMultipleError(hr, "CWiaPropStg:CheckPropertyAccess", "access flags", TRUE, cpspec, rgpspec);
  457. DBG_ERR(("CWiaPropStg:CheckPropertyAccess, unable to read access rights for some properties"));
  458. }
  459. }
  460. LocalFree(ppvAccess);
  461. }
  462. else {
  463. DBG_ERR(("CWiaPropStg:CheckPropertyAccess, unable to allocate access propvar, count: %d", cpspec));
  464. hr = E_OUTOFMEMORY;
  465. }
  466. return hr;
  467. }
  468. /**************************************************************************\
  469. * CheckPropertyType
  470. *
  471. * This method checks that the new property value type matches the current
  472. * property type for all properties being written.
  473. *
  474. * Arguments:
  475. *
  476. * pIPropStg - the property storage to check against
  477. * cpspec - number of elements in rgpspec.
  478. * rgpspec - array of PROPSPECs specifying the properties.
  479. * rgpvar - array of PROPVARIANTS holding
  480. *
  481. * Return Value:
  482. *
  483. * Status - S_OK if the access flags allow WRITEs.
  484. * E_INVALIDARG if property type is invalid
  485. * E_POINTER if rgpvar is a bad read pointer.
  486. * E_OUTOFMEMORY if temporary storage could not be
  487. * allocated.
  488. *
  489. * History:
  490. *
  491. * 13/05/1999 Original Version
  492. *
  493. \**************************************************************************/
  494. HRESULT _stdcall CWiaPropStg::CheckPropertyType(
  495. IPropertyStorage *pIPropStg,
  496. LONG cpspec,
  497. PROPSPEC *rgpspec,
  498. PROPVARIANT *rgpvar)
  499. {
  500. PROPVARIANT *ppvCurrent;
  501. HRESULT hr;
  502. //
  503. // PROPVARIANT pointer has not been checked yet, so check it now.
  504. //
  505. if (IsBadWritePtr(rgpvar, sizeof(PROPSPEC) * cpspec)) {
  506. DBG_ERR(("CWiaPropStg::CheckPropertyType, PROPVARIANT array is invalid"));
  507. return E_POINTER;
  508. }
  509. ppvCurrent = (PROPVARIANT*) LocalAlloc(LPTR, sizeof(PROPVARIANT) * cpspec);
  510. if (ppvCurrent) {
  511. //
  512. // Get the current values
  513. //
  514. hr = pIPropStg->ReadMultiple(cpspec,
  515. rgpspec,
  516. ppvCurrent);
  517. if (SUCCEEDED(hr)) {
  518. //
  519. // Check that the PROPVARIANT types match. If VT is VT_EMPTY,
  520. // then it's an application written property so skip check.
  521. //
  522. for (LONG i = 0; i < cpspec; i++) {
  523. if ((rgpvar[i].vt != ppvCurrent[i].vt) && (ppvCurrent[i].vt != VT_EMPTY)) {
  524. hr = E_INVALIDARG;
  525. break;
  526. }
  527. }
  528. FreePropVariantArray(cpspec, ppvCurrent);
  529. } else {
  530. ReportReadWriteMultipleError(hr,
  531. "CWiaPropStg::CheckPropertyType",
  532. "Reading current values",
  533. TRUE,
  534. 1,
  535. rgpspec);
  536. }
  537. LocalFree(ppvCurrent);
  538. }
  539. else {
  540. DBG_ERR(("CWiaPropStg::CheckPropertyType, unable to allocate PropVar, count: %d", cpspec));
  541. hr = E_OUTOFMEMORY;
  542. }
  543. return hr;
  544. }
  545. /**************************************************************************\
  546. * GetPropIDFromName
  547. *
  548. * This method takes in a PROPSPEC that identifies a property by its name
  549. * and returns a PROPSPEC with the corresponding PropID. It checks against
  550. * the current value storage.
  551. *
  552. * Arguments:
  553. *
  554. * pPropSpecIn - A pointer to the input PROPSPEC containing the
  555. * property name.
  556. * pPropSpecOut - A pointer to a PROPSPEC where the corresponding
  557. * PropID will be put.
  558. *
  559. * Return Value:
  560. *
  561. * Status - An E_INVALIDARG will be returned if the property
  562. * is not found. If it is, then S_OK will be returned.
  563. * If an error occurs getting the enumerator from the
  564. * property storage, then that error is returned.
  565. *
  566. * History:
  567. *
  568. * 27/4/1998 Original Version
  569. *
  570. \**************************************************************************/
  571. HRESULT _stdcall CWiaPropStg::GetPropIDFromName(
  572. PROPSPEC *pPropSpecIn,
  573. PROPSPEC *pPropSpecOut)
  574. {
  575. HRESULT hr;
  576. IEnumSTATPROPSTG *pIEnum;
  577. hr = (CurStg())->Enum(&pIEnum);
  578. if (FAILED(hr)) {
  579. DBG_ERR(("GetPropIDFromName, error getting IEnumSTATPROPSTG"));
  580. return hr;
  581. }
  582. //
  583. // Go through properties
  584. //
  585. STATPROPSTG statProp;
  586. ULONG celtFetched;
  587. statProp.lpwstrName = NULL;
  588. for (celtFetched = 1; celtFetched > 0; pIEnum->Next(1, &statProp, &celtFetched)) {
  589. if (statProp.lpwstrName) {
  590. if ((wcscmp(statProp.lpwstrName, pPropSpecIn->lpwstr)) == 0) {
  591. //
  592. // Found the right one, so get it's PropID
  593. //
  594. pPropSpecOut->ulKind = PRSPEC_PROPID;
  595. pPropSpecOut->propid = statProp.propid;
  596. CoTaskMemFree(statProp.lpwstrName);
  597. pIEnum->Release();
  598. return S_OK;
  599. }
  600. //
  601. // Free the property name
  602. //
  603. CoTaskMemFree(statProp.lpwstrName);
  604. statProp.lpwstrName = NULL;
  605. }
  606. }
  607. pIEnum->Release();
  608. //
  609. // Property not found
  610. //
  611. return E_INVALIDARG;
  612. }
  613. /**************************************************************************\
  614. * NamesToPropIDs
  615. *
  616. * This method takes in an array of PROPSPECs, and outputs an array
  617. * of PROPSPECs which contain only PropIDs. This function should
  618. * be called by methods which only want to deal with PropIDs, and not
  619. * property names.
  620. *
  621. * If none of the PropSpecs have to be converted, then the returned
  622. * PROPSPEC is NULL, else a new PropSpec array is allocated and
  623. * returned. Users of this method must use LocalFree to free
  624. * up the returned array.
  625. *
  626. * Arguments:
  627. *
  628. * pPropSpecIn - A pointer to the input PROPSPEC containing the
  629. * property name.
  630. * ppPropSpecOut - A pointer to a PROPSPEC where the corresponding
  631. * PropID will be put.
  632. * celt - Number of PROPSPECS
  633. *
  634. * Return Value:
  635. *
  636. * Status - An E_INVALIDARG will be returned if the property
  637. * is not found. If it is, then S_OK will be returned
  638. * E_OUTOFMEMORY will be returned if the new PROPSPEC
  639. * array could not be allocated.
  640. *
  641. * History:
  642. *
  643. * 27/4/1998 Original Version
  644. *
  645. \**************************************************************************/
  646. HRESULT _stdcall CWiaPropStg::NamesToPropIDs(
  647. LONG celt,
  648. PROPSPEC *pPropSpecIn,
  649. PROPSPEC **ppPropSpecOut)
  650. {
  651. HRESULT hr;
  652. *ppPropSpecOut = NULL;
  653. if (celt < 1) {
  654. return S_OK;
  655. }
  656. //
  657. // Check whether conversion needs to be done.
  658. //
  659. for (int i = 0; i < celt; i++) {
  660. if (pPropSpecIn[i].ulKind == PRSPEC_LPWSTR) {
  661. //
  662. // Found a Name, so we need to convert the whole thing
  663. //
  664. PROPSPEC *pOut;
  665. pOut = (PROPSPEC*) LocalAlloc(LPTR, sizeof(PROPSPEC) * celt);
  666. if (!pOut) {
  667. DBG_ERR(("NamesToPropIDs, out of memory"));
  668. return E_OUTOFMEMORY;
  669. }
  670. for (int j = 0; j < celt; j++) {
  671. if (pPropSpecIn[j].ulKind == PRSPEC_LPWSTR) {
  672. hr = GetPropIDFromName(&pPropSpecIn[j], &pOut[j]);
  673. if (FAILED(hr)) {
  674. LocalFree(pOut);
  675. return hr;
  676. }
  677. }
  678. else {
  679. pOut[j].ulKind = PRSPEC_PROPID;
  680. pOut[j].propid = pPropSpecIn[j].propid;
  681. }
  682. }
  683. //
  684. // Everything converted, so return
  685. //
  686. *ppPropSpecOut = pOut;
  687. return S_OK;
  688. }
  689. }
  690. //
  691. // Nothing to convert
  692. //
  693. return S_OK;
  694. }
  695. /**************************************************************************\
  696. * CopyItemProp
  697. *
  698. * This method copies a single property from source to destination.
  699. *
  700. * Arguments:
  701. *
  702. * pIPropStgSrc - The IPropertyStorage that contains the property to
  703. * copy.
  704. * pIPropStgDst - The IPropertyStorage where the value is copied to.
  705. * pps - The PROPSPEC which specifies the source property.
  706. * pszErr - A string that will be printed out when an error
  707. * occurs.
  708. * Return Value:
  709. *
  710. * Status - Returns HRESULT from ReadMultiple and WriteMultiple.
  711. *
  712. * History:
  713. *
  714. * 28/04/1999 Original Version
  715. *
  716. \**************************************************************************/
  717. HRESULT CWiaPropStg::CopyItemProp(
  718. IPropertyStorage *pIPropStgSrc,
  719. IPropertyStorage *pIPropStgDst,
  720. PROPSPEC *pps,
  721. LPSTR pszErr)
  722. {
  723. PROPVARIANT pv[1];
  724. HRESULT hr = pIPropStgSrc->ReadMultiple(1, pps, pv);
  725. if (SUCCEEDED(hr)) {
  726. hr = pIPropStgDst->WriteMultiple(1, pps, pv, WIA_DIP_FIRST);
  727. if (FAILED(hr)) {
  728. ReportReadWriteMultipleError(hr,
  729. "CopyItemProp",
  730. pszErr,
  731. FALSE,
  732. 1,
  733. pps);
  734. }
  735. PropVariantClear(pv);
  736. }
  737. else {
  738. ReportReadWriteMultipleError(hr,
  739. "CopyItemProp",
  740. pszErr,
  741. TRUE,
  742. 1,
  743. pps);
  744. }
  745. return hr;
  746. }
  747. /*******************************************************************************
  748. *
  749. * CopyProps
  750. *
  751. * This is a helper function used to copy the property values from one
  752. * property storage into another.
  753. *
  754. * Parameters:
  755. *
  756. * pSrc - the source property storage
  757. * pDest - the destination property storage
  758. *
  759. * Return:
  760. *
  761. * Status - S_OK if successful.
  762. * Error returns are those returned by WriteMultiple
  763. *
  764. * History
  765. *
  766. * 06/05/1999 Original Version
  767. *
  768. *******************************************************************************/
  769. HRESULT CWiaPropStg::CopyProps(
  770. IPropertyStorage *pSrc,
  771. IPropertyStorage *pDest)
  772. {
  773. IEnumSTATPROPSTG *pIEnum;
  774. STATPROPSTG StatPropStg;
  775. PROPSPEC ps[1];
  776. HRESULT hr;
  777. hr = pSrc->Enum(&pIEnum);
  778. if (SUCCEEDED(hr)) {
  779. ULONG ulFetched;
  780. ps[0].ulKind = PRSPEC_PROPID;
  781. while (pIEnum->Next(1, &StatPropStg, &ulFetched) == S_OK) {
  782. PROPID pi[1];
  783. LPWSTR psz[1];
  784. pi[0] = StatPropStg.propid;
  785. psz[0] = StatPropStg.lpwstrName;
  786. if (StatPropStg.lpwstrName) {
  787. //
  788. // Copy the property name
  789. //
  790. hr = pDest->WritePropertyNames(1, pi, psz);
  791. if (FAILED(hr)) {
  792. CoTaskMemFree(StatPropStg.lpwstrName);
  793. break;
  794. }
  795. }
  796. ps[0].propid = StatPropStg.propid;
  797. //
  798. // Copy the property value
  799. //
  800. hr = CopyItemProp(pSrc,
  801. pDest,
  802. ps,
  803. "CopyProps");
  804. CoTaskMemFree(StatPropStg.lpwstrName);
  805. if (FAILED(hr)) {
  806. break; hr;
  807. }
  808. }
  809. pIEnum->Release();
  810. } else {
  811. return hr;
  812. }
  813. return hr;
  814. }
  815. /**************************************************************************\
  816. * WriteItemPropNames
  817. *
  818. * Write property names to all internal property storages (except the
  819. * storages used for backups).
  820. *
  821. * Arguments:
  822. *
  823. *
  824. *
  825. * Return Value:
  826. *
  827. * Status
  828. *
  829. * History:
  830. *
  831. * 06/03/1999 Original Version
  832. *
  833. \**************************************************************************/
  834. HRESULT _stdcall CWiaPropStg::WriteItemPropNames(
  835. LONG cItemProps,
  836. PROPID *ppId,
  837. LPOLESTR *ppszNames)
  838. {
  839. HRESULT hr = S_OK;
  840. for(LONG lIndex = 0; lIndex < (NUM_PROP_STG - NUM_BACKUP_STG); lIndex++) {
  841. if (m_pIPropStg[lIndex]) {
  842. hr = m_pIPropStg[lIndex]->WritePropertyNames(cItemProps,
  843. ppId,
  844. ppszNames);
  845. if (FAILED(hr)) {
  846. DBG_ERR(("CWiaPropStg::WriteItemPropNames, WritePropertyNames failed 0x%X", hr));
  847. return hr;
  848. }
  849. }
  850. }
  851. return hr;
  852. }
  853. /*******************************************************************************
  854. *
  855. * CreateStorage
  856. *
  857. * This is a helper function used to create streams and property storage.
  858. * The ulIndex argument indicates where the pointers are stored in the
  859. * streams and propertystorage arrays.
  860. *
  861. * Parameters:
  862. *
  863. * ulIndex - the index of the IPropertyStorage
  864. *
  865. * Return:
  866. *
  867. * Status - S_OK if successful.
  868. * - Error returns are those returned by CreateStreamOnHGlobal
  869. * and StgCreatePropStg
  870. *
  871. * History
  872. *
  873. * 06/05/1999 Original Version
  874. *
  875. *******************************************************************************/
  876. HRESULT CWiaPropStg::CreateStorage(
  877. ULONG ulIndex)
  878. {
  879. HRESULT hr;
  880. //
  881. // Create stream and property storage.
  882. //
  883. hr = CreateStreamOnHGlobal(NULL, TRUE, &m_pIStream[ulIndex]);
  884. if (SUCCEEDED(hr)) {
  885. hr = StgCreatePropStg(m_pIStream[ulIndex],
  886. FMTID_NULL,
  887. &CLSID_NULL,
  888. PROPSETFLAG_DEFAULT,
  889. 0,
  890. &m_pIPropStg[ulIndex]);
  891. if (FAILED(hr)) {
  892. DBG_ERR(("CWiaPropStg::CreateStorage, StgCreatePropStg failed 0x%X", hr));
  893. }
  894. } else {
  895. DBG_ERR(("CWiaPropStg::CreateStorage, CreateStreamOnHGlobal failed 0x%X", hr));
  896. }
  897. return hr;
  898. }
  899. /**************************************************************************\
  900. * CopyRWStreamProps
  901. *
  902. * Copies properties from source stream to destination stream. Only copies
  903. * properties that the app. has read/write access to.
  904. *
  905. * Arguments:
  906. *
  907. * pstmPropSrc - Pointer to source property stream.
  908. * pstmPropDst - Pointer to returned destination property stream.
  909. * pCompatibilityId - Address of GUID to receive the property
  910. * stream CompatibilityId.
  911. *
  912. * Return Value:
  913. *
  914. * Status
  915. *
  916. * History:
  917. *
  918. * 9/3/1998 Original Version
  919. * 06/04/1999 Moved from CWiaItem to CWiaPropStg
  920. *
  921. \**************************************************************************/
  922. HRESULT CWiaPropStg::CopyRWStreamProps(
  923. LPSTREAM pstmPropSrc,
  924. LPSTREAM pstmPropDst,
  925. GUID *pCompatibilityId)
  926. {
  927. IPropertyStorage *pSrc;
  928. IPropertyStorage *pDst;
  929. IEnumSTATPROPSTG *pIEnum;
  930. STATPROPSTG StatPropStg;
  931. LONG lNumProps = 0;
  932. HRESULT hr;
  933. PROPSPEC ps[1] = {{PRSPEC_PROPID, WIA_IPA_PROP_STREAM_COMPAT_ID}};
  934. PROPVARIANT pv[1];
  935. //
  936. // Open a storage on the source stream.
  937. //
  938. hr = StgOpenPropStg(pstmPropSrc,
  939. FMTID_NULL,
  940. PROPSETFLAG_DEFAULT,
  941. 0,
  942. &pSrc);
  943. if (SUCCEEDED(hr)) {
  944. //
  945. // Get the compatibility ID. If stream doesn't contain a
  946. // compatibility ID then assume GUID_NULL.
  947. //
  948. PropVariantInit(pv);
  949. hr = pSrc->ReadMultiple(1, ps, pv);
  950. if (hr == S_OK) {
  951. *pCompatibilityId = *(pv[0].puuid);
  952. } else {
  953. *pCompatibilityId = GUID_NULL;
  954. }
  955. PropVariantClear(pv);
  956. //
  957. // Create a storage on the destination stream.
  958. //
  959. hr = StgCreatePropStg(pstmPropDst,
  960. FMTID_NULL,
  961. &CLSID_NULL,
  962. PROPSETFLAG_DEFAULT,
  963. 0,
  964. &pDst);
  965. if (SUCCEEDED(hr)) {
  966. hr = pSrc->Enum(&pIEnum);
  967. if (SUCCEEDED(hr)) {
  968. ULONG ulFetched;
  969. ps[0].ulKind = PRSPEC_PROPID;
  970. //
  971. // Enumerate through the properties in the stream
  972. //
  973. while (pIEnum->Next(1, &StatPropStg, &ulFetched) == S_OK) {
  974. PROPID pi[1];
  975. LPWSTR psz[1];
  976. pi[0] = StatPropStg.propid;
  977. psz[0] = StatPropStg.lpwstrName;
  978. ps[0].propid = StatPropStg.propid;
  979. //
  980. // Check whether property has read/write access. Skip
  981. // property write if this check fails
  982. //
  983. hr = CheckPropertyAccess(FALSE, 1, ps);
  984. if (hr != S_OK) {
  985. hr = S_OK;
  986. if (StatPropStg.lpwstrName) {
  987. CoTaskMemFree(StatPropStg.lpwstrName);
  988. }
  989. continue;
  990. }
  991. //
  992. // Copy the property name (if it has one), and value
  993. //
  994. if (StatPropStg.lpwstrName) {
  995. hr = pDst->WritePropertyNames(1, pi, psz);
  996. if (FAILED(hr)) {
  997. DBG_ERR(("CWiaPropStg::CopyRWStreamProps WritePropertyNames failed"));
  998. break;
  999. }
  1000. CoTaskMemFree(StatPropStg.lpwstrName);
  1001. }
  1002. hr = CopyItemProp(pSrc,
  1003. pDst,
  1004. ps,
  1005. "CWiaPropStg::CopyRWStreamProps");
  1006. if (FAILED(hr)) {
  1007. break;
  1008. }
  1009. //
  1010. // Increase the property count
  1011. //
  1012. lNumProps++;
  1013. }
  1014. pIEnum->Release();
  1015. } else {
  1016. DBG_ERR(("CWiaPropStg::CopyRWStreamProps, Enum failed 0x%X", hr));
  1017. }
  1018. if (SUCCEEDED(hr)) {
  1019. //
  1020. // Write the number of properties to stream
  1021. //
  1022. ps[0].propid = WIA_NUM_PROPS_ID;
  1023. pv[0].vt = VT_I4;
  1024. pv[0].lVal = lNumProps;
  1025. hr = pDst->WriteMultiple(1, ps, pv, WIA_IPA_FIRST);
  1026. if (FAILED(hr)) {
  1027. DBG_ERR(("CWiaPropStg::CopyRWStreamProps, Error writing number of properties"));
  1028. }
  1029. }
  1030. pDst->Release();
  1031. } else {
  1032. DBG_ERR(("CWiaPropStg::CopyRWStreamProps, creating Dst storage failed 0x%X", hr));
  1033. }
  1034. pSrc->Release();
  1035. } else {
  1036. DBG_ERR(("CWiaPropStg::CopyRWStreamProps, StgCreatePropStg for pSrc failed 0x%X", hr));
  1037. }
  1038. return hr;
  1039. }
  1040. /**************************************************************************\
  1041. * GetPropertyStream
  1042. *
  1043. * Get a copy of an items property stream. Caller must free returned
  1044. * property stream.
  1045. *
  1046. * Arguments:
  1047. *
  1048. * pCompatibilityId - Address of GUID to receive the property
  1049. * stream CompatibilityId.
  1050. * ppstmProp - Pointer to returned property stream.
  1051. *
  1052. * Return Value:
  1053. *
  1054. * Status
  1055. *
  1056. * History:
  1057. *
  1058. * 9/3/1998 Original Version
  1059. * 06/04/1999 Updated and moved from CWiaItem to CWiaPropStg
  1060. * 12/12/1999 Modified to use CompatibilityId
  1061. *
  1062. \**************************************************************************/
  1063. HRESULT _stdcall CWiaPropStg::GetPropertyStream(
  1064. GUID *pCompatibilityId,
  1065. LPSTREAM *ppstmProp)
  1066. {
  1067. IStream *pStm;
  1068. *ppstmProp = NULL;
  1069. //
  1070. // Commit any pending transactions.
  1071. //
  1072. HRESULT hr = m_pIPropStg[WIA_CUR_STG]->Commit(STGC_DEFAULT);
  1073. if (FAILED(hr)) {
  1074. DBG_ERR(("CWiaPropStg::GetPropertyStream, Commit failed"));
  1075. return hr;
  1076. }
  1077. //
  1078. // Create a stream
  1079. //
  1080. hr = CreateStreamOnHGlobal(NULL, TRUE, ppstmProp);
  1081. if (SUCCEEDED(hr)) {
  1082. //
  1083. // Copy the RW properties from one stream to another.
  1084. //
  1085. hr = CopyRWStreamProps(m_pIStream[WIA_CUR_STG], *ppstmProp, pCompatibilityId);
  1086. if (FAILED(hr)) {
  1087. (*ppstmProp)->Release();
  1088. *ppstmProp = NULL;
  1089. }
  1090. } else {
  1091. DBG_ERR(("CWiaPropStg::GetPropertyStream, CreateStreamOnHGlobal failed"));
  1092. }
  1093. return hr;
  1094. }
  1095. /**************************************************************************\
  1096. * GetPropsFromStorage
  1097. *
  1098. * Gets the properties contained in a storage which was opened on a stream
  1099. * returned by GetPropertyStream. The property values are returned in
  1100. * ppVar, and the propID's are returned in ppPSpec.
  1101. *
  1102. * Arguments:
  1103. *
  1104. * pSrc - pointer to the IProperty storage
  1105. * pPSpec - address where the number of properties is returned
  1106. * ppPSpec - address of a pointer to hold PROPSPECs
  1107. * ppVar - address of pointer to hold PROPVARIANTs
  1108. *
  1109. * Return Value:
  1110. *
  1111. * Status
  1112. *
  1113. * History:
  1114. *
  1115. * 07/04/1999 Original Version
  1116. *
  1117. \**************************************************************************/
  1118. HRESULT CWiaPropStg::GetPropsFromStorage(
  1119. IPropertyStorage *pSrc,
  1120. ULONG *cPSpec,
  1121. PROPSPEC **ppPSpec,
  1122. PROPVARIANT **ppVar)
  1123. {
  1124. IEnumSTATPROPSTG *pIEnum = NULL;
  1125. STATPROPSTG StatPropStg;
  1126. PROPSPEC *ps = NULL;
  1127. PROPVARIANT *pv = NULL;
  1128. LONG lIndex = 0;
  1129. //
  1130. // Read the number of properties
  1131. //
  1132. PROPSPEC psNumProps[1];
  1133. PROPVARIANT pvNumProps[1];
  1134. psNumProps[0].ulKind = PRSPEC_PROPID;
  1135. psNumProps[0].propid = WIA_NUM_PROPS_ID;
  1136. PropVariantInit(pvNumProps);
  1137. HRESULT hr = pSrc->ReadMultiple(1, psNumProps, pvNumProps);
  1138. if (hr == S_OK) {
  1139. //
  1140. // Get the memory for the values
  1141. //
  1142. ps = (PROPSPEC*) LocalAlloc(LPTR, sizeof(PROPSPEC) * pvNumProps[0].lVal);
  1143. pv = (PROPVARIANT*) LocalAlloc(LPTR, sizeof(PROPVARIANT) * pvNumProps[0].lVal);
  1144. if (!pv || !ps) {
  1145. DBG_ERR(("CWiaPropStg::GetPropsFromStream, out of memory"));
  1146. hr = E_OUTOFMEMORY;
  1147. }
  1148. } else {
  1149. DBG_ERR(("CWiaPropStg::GetPropsFromStream, reading WIA_NUM_PROPS_ID failed"));
  1150. hr = E_INVALIDARG;
  1151. }
  1152. if (SUCCEEDED(hr)) {
  1153. hr = pSrc->Enum(&pIEnum);
  1154. if (SUCCEEDED(hr)) {
  1155. //
  1156. // Enumerate through the properties in the stream
  1157. //
  1158. for (lIndex = 0; lIndex < pvNumProps[0].lVal; lIndex++) {
  1159. hr = pIEnum->Next(1, &StatPropStg, NULL);
  1160. //
  1161. // Ignore the WIA_NUM_PROPS_ID property
  1162. //
  1163. if (StatPropStg.propid == WIA_NUM_PROPS_ID) {
  1164. hr = pIEnum->Next(1, &StatPropStg, NULL);
  1165. }
  1166. if (hr != S_OK) {
  1167. DBG_ERR(("CWiaPropStg::GetPropsFromStream, error enumerating properties"));
  1168. hr = E_INVALIDARG;
  1169. if(StatPropStg.lpwstrName) {
  1170. CoTaskMemFree(StatPropStg.lpwstrName);
  1171. }
  1172. break;
  1173. }
  1174. ps[lIndex].ulKind = PRSPEC_PROPID;
  1175. ps[lIndex].propid = StatPropStg.propid;
  1176. if(StatPropStg.lpwstrName) {
  1177. CoTaskMemFree(StatPropStg.lpwstrName);
  1178. }
  1179. }
  1180. if (SUCCEEDED(hr)) {
  1181. hr = pSrc->ReadMultiple(pvNumProps[0].lVal, ps, pv);
  1182. if (hr != S_OK) {
  1183. DBG_ERR(("CWiaPropStg::GetPropsFromStream, read multiple failed"));
  1184. if (hr == S_FALSE) {
  1185. hr = E_INVALIDARG;
  1186. }
  1187. }
  1188. }
  1189. pIEnum->Release();
  1190. } else {
  1191. DBG_ERR(("CWiaPropStg::GetPropsFromStream, Enum failed"));
  1192. }
  1193. }
  1194. if (FAILED(hr)) {
  1195. if (ps) {
  1196. LocalFree(ps);
  1197. ps = NULL;
  1198. }
  1199. if (pv) {
  1200. LocalFree(pv);
  1201. pv = NULL;
  1202. }
  1203. }
  1204. //
  1205. // Set return values
  1206. //
  1207. *cPSpec = pvNumProps[0].lVal;
  1208. PropVariantClear(pvNumProps);
  1209. *ppPSpec = ps;
  1210. *ppVar = pv;
  1211. return hr;
  1212. }
  1213. /**************************************************************************\
  1214. * SetPropertyStream
  1215. *
  1216. * Sets the current value properties to the values contained in the argument
  1217. * stream. The properties are written to the corresponding WiaItem.
  1218. *
  1219. * Arguments:
  1220. *
  1221. * pCompatibilityId - Pointer to a GUID representing the property
  1222. * stream CompatibilityId.
  1223. * pItem - Pointer to the WiaItem.
  1224. * pstmProp - Pointer to property stream.
  1225. *
  1226. * Return Value:
  1227. *
  1228. * Status
  1229. *
  1230. * History:
  1231. *
  1232. * 07/06/1999 Original Version
  1233. * 12/12/1999 Modified to use CompatibilityId
  1234. *
  1235. \**************************************************************************/
  1236. HRESULT _stdcall CWiaPropStg::SetPropertyStream(
  1237. GUID *pCompatibilityId,
  1238. IWiaItem *pItem,
  1239. LPSTREAM pstmProp)
  1240. {
  1241. IPropertyStorage *pSrc = NULL;
  1242. PROPSPEC *ps = NULL;
  1243. PROPVARIANT *pv = NULL;
  1244. PROPSPEC psCompatId[1] = {{PRSPEC_PROPID, WIA_IPA_PROP_STREAM_COMPAT_ID}};
  1245. PROPVARIANT pvCompatId[1];
  1246. ULONG celt = 0;
  1247. HRESULT hr = S_OK;
  1248. //
  1249. // Write the compatibility ID. This way the driver will validate the
  1250. // ID before we attempt to write all the properties in this stream.
  1251. // Skip this step if pCompatibilityId is GUID_NULL.
  1252. //
  1253. if (*pCompatibilityId != GUID_NULL) {
  1254. pvCompatId[0].vt = VT_CLSID;
  1255. pvCompatId[0].puuid = pCompatibilityId;
  1256. hr = ((CWiaItem*) pItem)->WriteMultiple(1,
  1257. psCompatId,
  1258. pvCompatId,
  1259. WIA_IPA_FIRST);
  1260. if (FAILED(hr)) {
  1261. DBG_ERR(("CWiaPropStg::SetPropertyStream, Writing Compatibility ID failed!"));
  1262. return hr;
  1263. }
  1264. }
  1265. //
  1266. // If the stream is NULL, return here. The stream will be NULL if the
  1267. // application simply wants to check whether the CompatibilityId is
  1268. // valid.
  1269. //
  1270. if (pstmProp == NULL) {
  1271. return S_OK;
  1272. }
  1273. //
  1274. // We need to impersonate the client to be able to access the
  1275. // properties in the stream
  1276. //
  1277. BOOL bImpersonating = FALSE;
  1278. _try
  1279. {
  1280. hr = CoImpersonateClient();
  1281. if (SUCCEEDED(hr))
  1282. {
  1283. bImpersonating = TRUE;
  1284. //
  1285. // Create a storage on the incoming stream
  1286. //
  1287. hr = StgOpenPropStg(pstmProp,
  1288. FMTID_NULL,
  1289. PROPSETFLAG_DEFAULT,
  1290. 0,
  1291. &pSrc);
  1292. if (SUCCEEDED(hr)) {
  1293. //
  1294. // Get the properties from the stream
  1295. //
  1296. hr = GetPropsFromStorage(pSrc, &celt, &ps, &pv);
  1297. //
  1298. // Release the property stream - we no longer need it
  1299. //
  1300. if (pSrc)
  1301. {
  1302. pSrc->Release();
  1303. pSrc = NULL;
  1304. }
  1305. } else {
  1306. DBG_ERR(("CWiaPropStg::SetPropertyStream, open storage failed 0x%X", hr));
  1307. pSrc = NULL;
  1308. }
  1309. }
  1310. }
  1311. _finally
  1312. {
  1313. if (bImpersonating)
  1314. {
  1315. HRESULT hres = CoRevertToSelf();
  1316. }
  1317. }
  1318. //
  1319. // If everything is still successful, we now have ps and pv arrays
  1320. // allocated and filled with properties
  1321. //
  1322. if (SUCCEEDED(hr)) {
  1323. //
  1324. // Write the properties to the item
  1325. //
  1326. hr = ((CWiaItem*) pItem)->WriteMultiple(celt, ps, pv, WIA_IPA_FIRST);
  1327. if (FAILED(hr)) {
  1328. DBG_ERR(("CWiaPropStg::SetPropertyStream, WriteMultiple failed"));
  1329. }
  1330. }
  1331. //
  1332. // Cleanup
  1333. //
  1334. if (ps)
  1335. {
  1336. LocalFree(ps);
  1337. ps = NULL;
  1338. }
  1339. if (pv)
  1340. {
  1341. for (ULONG i = 0; i < celt; i++)
  1342. {
  1343. PropVariantClear(&pv[i]);
  1344. }
  1345. LocalFree(pv);
  1346. pv = NULL;
  1347. }
  1348. return hr;
  1349. }
  1350. /**************************************************************************\
  1351. * CWiaPropStg
  1352. *
  1353. * Constructor for CWiaPropStg.
  1354. *
  1355. * Arguments:
  1356. *
  1357. *
  1358. * Return Value:
  1359. *
  1360. *
  1361. * History:
  1362. *
  1363. * 06/03/1999 Original Version
  1364. *
  1365. \**************************************************************************/
  1366. CWiaPropStg::CWiaPropStg()
  1367. {
  1368. //
  1369. // Set the property storage and property stream pointers to NULL
  1370. //
  1371. for (int lIndex = 0; lIndex < NUM_PROP_STG; lIndex++) {
  1372. m_pIPropStg[lIndex] = NULL;
  1373. m_pIStream[lIndex] = NULL;
  1374. }
  1375. }
  1376. /**************************************************************************\
  1377. * ~CWiaPropStg
  1378. *
  1379. * Destructor for CWiaPropStg. Calls CleanUp to free resources.
  1380. *
  1381. * Arguments:
  1382. *
  1383. *
  1384. * Return Value:
  1385. *
  1386. *
  1387. * History:
  1388. *
  1389. * 06/03/1999 Original Version
  1390. *
  1391. \**************************************************************************/
  1392. CWiaPropStg::~CWiaPropStg()
  1393. {
  1394. //
  1395. // Release the property storages and property streams
  1396. //
  1397. for (int lIndex = 0; lIndex < NUM_PROP_STG; lIndex++) {
  1398. if(m_pIPropStg[lIndex]) {
  1399. m_pIPropStg[lIndex]->Release();
  1400. m_pIPropStg[lIndex] = NULL;
  1401. }
  1402. if(m_pIStream[lIndex]) {
  1403. m_pIStream[lIndex]->Release();
  1404. m_pIStream[lIndex] = NULL;
  1405. }
  1406. }
  1407. }