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.

2682 lines
71 KiB

  1. #include "priv.h"
  2. #include "varutil.h"
  3. #define COMPILE_MULTIMON_STUBS
  4. #include "multimon.h"
  5. #define MAX_PROPERTY_SIZE 2048
  6. // simple inline base class.
  7. class CBasePropertyBag : public IPropertyBag, IPropertyBag2
  8. {
  9. public:
  10. // IUnknown
  11. STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
  12. {
  13. static const QITAB qit[] = {
  14. QITABENT(CBasePropertyBag, IPropertyBag),
  15. QITABENT(CBasePropertyBag, IPropertyBag2),
  16. { 0 },
  17. };
  18. return QISearch(this, qit, riid, ppv);
  19. }
  20. STDMETHODIMP_(ULONG) AddRef()
  21. {
  22. return InterlockedIncrement(&_cRef);
  23. }
  24. STDMETHODIMP_(ULONG) Release()
  25. {
  26. ASSERT( 0 != _cRef );
  27. ULONG cRef = InterlockedDecrement(&_cRef);
  28. if ( 0 == cRef )
  29. {
  30. delete this;
  31. }
  32. return cRef;
  33. }
  34. // IPropertyBag
  35. STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog) PURE;
  36. STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT *pVar) PURE;
  37. // IPropertyBag2 (note, does not derive from IPropertyBag)
  38. STDMETHODIMP Read(ULONG cProperties, PROPBAG2 *pPropBag, IErrorLog *pErrLog, VARIANT *pvarValue, HRESULT *phrError);
  39. STDMETHODIMP Write(ULONG cProperties, PROPBAG2 *pPropBag, VARIANT *pvarValue);
  40. STDMETHODIMP CountProperties(ULONG *pcProperties);
  41. STDMETHODIMP GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2 *pPropBag, ULONG *pcProperties);
  42. STDMETHODIMP LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown *pUnkObject, IErrorLog *pErrLog);
  43. protected: // methods
  44. CBasePropertyBag() {} // DONT DELETE ME
  45. CBasePropertyBag(DWORD grfMode) :
  46. _cRef(1), _grfMode(grfMode) {}
  47. virtual ~CBasePropertyBag() {} // DONT DELETE ME
  48. HRESULT _CanRead(void)
  49. { return STGM_WRITE != (_grfMode & (STGM_WRITE | STGM_READWRITE)) ? S_OK : E_ACCESSDENIED;}
  50. HRESULT _CanWrite(void)
  51. { return (_grfMode & (STGM_WRITE | STGM_READWRITE)) ? S_OK : E_ACCESSDENIED;}
  52. protected: // members
  53. LONG _cRef;
  54. DWORD _grfMode;
  55. };
  56. STDMETHODIMP CBasePropertyBag::Read(ULONG cProperties, PROPBAG2 *pPropBag, IErrorLog *pErrLog, VARIANT *pvarValue, HRESULT *phrError)
  57. {
  58. return E_NOTIMPL;
  59. }
  60. STDMETHODIMP CBasePropertyBag::Write(ULONG cProperties, PROPBAG2 *pPropBag, VARIANT *pvarValue)
  61. {
  62. return E_NOTIMPL;
  63. }
  64. STDMETHODIMP CBasePropertyBag::CountProperties(ULONG *pcProperties)
  65. {
  66. return E_NOTIMPL;
  67. }
  68. STDMETHODIMP CBasePropertyBag::GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2 *pPropBag, ULONG *pcProperties)
  69. {
  70. return E_NOTIMPL;
  71. }
  72. STDMETHODIMP CBasePropertyBag::LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown *pUnkObject, IErrorLog *pErrLog)
  73. {
  74. return E_NOTIMPL;
  75. }
  76. //
  77. // Ini file property bag implementation
  78. //
  79. class CIniPropertyBag : public CBasePropertyBag
  80. {
  81. public:
  82. // IPropertyBag
  83. STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
  84. STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT *pVar);
  85. protected: // methods
  86. CIniPropertyBag(DWORD grfMode) : CBasePropertyBag(grfMode) {}
  87. virtual ~CIniPropertyBag();
  88. HRESULT _Init(LPCWSTR pszFile, LPCWSTR pszSection);
  89. HRESULT _GetSectionAndName(LPCWSTR pszProp, LPWSTR pszSection, UINT cchSec, LPWSTR pszName, UINT cchName);
  90. protected: // members
  91. LPWSTR _pszFile;
  92. LPWSTR _pszSection;
  93. friend HRESULT SHCreatePropertyBagOnProfileSection(LPCWSTR pszFile, LPCWSTR pszSection, DWORD grfMode, REFIID riid, void **ppv);
  94. };
  95. CIniPropertyBag::~CIniPropertyBag()
  96. {
  97. LocalFree(_pszFile); // accepts NULL
  98. LocalFree(_pszSection); // accepts NULL
  99. }
  100. HRESULT CIniPropertyBag::_Init(LPCWSTR pszFile, LPCWSTR pszSection)
  101. {
  102. HRESULT hr = E_OUTOFMEMORY;
  103. _pszFile = StrDupW(pszFile);
  104. if (_pszFile)
  105. {
  106. if (pszSection)
  107. {
  108. _pszSection = StrDupW(pszSection);
  109. if (_pszSection)
  110. hr = S_OK;
  111. }
  112. else
  113. {
  114. hr = S_OK;
  115. }
  116. }
  117. return hr;
  118. }
  119. // support the <section name>.<prop name> scheme
  120. HRESULT CIniPropertyBag::_GetSectionAndName(LPCWSTR pszProp,
  121. LPWSTR pszSection, UINT cchSec,
  122. LPWSTR pszName, UINT cchName)
  123. {
  124. HRESULT hr;
  125. LPCWSTR pszSlash = StrChrW(pszProp, L'\\');
  126. if (pszSlash)
  127. {
  128. StrCpyNW(pszSection, pszProp, min((UINT)(pszSlash - pszProp) + 1, cchSec));
  129. StrCpyNW(pszName, pszSlash + 1, cchName);
  130. hr = S_OK;
  131. }
  132. else if (_pszSection)
  133. {
  134. StrCpyNW(pszSection, _pszSection, cchSec);
  135. StrCpyNW(pszName, pszProp, cchName);
  136. hr = S_OK;
  137. }
  138. else
  139. {
  140. hr = E_INVALIDARG;
  141. }
  142. return hr;
  143. }
  144. // only supports strings. use VariantChangeType() to suppor others
  145. HRESULT CIniPropertyBag::Read(LPCOLESTR pszPropName, VARIANT *pvar, IErrorLog *pErrorLog)
  146. {
  147. VARTYPE vtDesired = pvar->vt;
  148. VariantInit(pvar);
  149. HRESULT hr = _CanRead();
  150. if (SUCCEEDED(hr))
  151. {
  152. WCHAR szSec[64], szName[64];
  153. hr = _GetSectionAndName(pszPropName, szSec, ARRAYSIZE(szSec), szName, ARRAYSIZE(szName));
  154. if (SUCCEEDED(hr))
  155. {
  156. WCHAR sz[MAX_PROPERTY_SIZE];
  157. if (SHGetIniStringUTF7W(szSec, szName, sz, ARRAYSIZE(sz), _pszFile))
  158. {
  159. pvar->bstrVal = SysAllocString(sz);
  160. if (pvar->bstrVal)
  161. {
  162. pvar->vt = VT_BSTR;
  163. hr = VariantChangeTypeForRead(pvar, vtDesired);
  164. }
  165. else
  166. {
  167. hr = E_OUTOFMEMORY;
  168. }
  169. }
  170. else
  171. {
  172. hr = E_FAIL;
  173. }
  174. }
  175. }
  176. return hr;
  177. }
  178. // only writes as strings to the INI file, we use VariantChangeType() to morp the types.
  179. HRESULT CIniPropertyBag::Write(LPCOLESTR pszPropName, VARIANT *pvar)
  180. {
  181. HRESULT hr = _CanWrite();
  182. if (SUCCEEDED(hr))
  183. {
  184. LPCWSTR psz = pvar->vt == VT_EMPTY ? NULL : pvar->bstrVal;
  185. VARIANT var = { 0 };
  186. if ((pvar->vt != VT_EMPTY) && (pvar->vt != VT_BSTR))
  187. {
  188. hr = VariantChangeType(&var, pvar, 0, VT_BSTR);
  189. if (SUCCEEDED(hr))
  190. psz = var.bstrVal;
  191. }
  192. if (SUCCEEDED(hr))
  193. {
  194. WCHAR szSec[64], szName[64];
  195. hr = _GetSectionAndName(pszPropName, szSec, ARRAYSIZE(szSec), szName, ARRAYSIZE(szName));
  196. if (SUCCEEDED(hr))
  197. {
  198. if (!SHSetIniStringUTF7W(szSec, szName, psz, _pszFile))
  199. {
  200. hr = E_FAIL;
  201. }
  202. else
  203. {
  204. SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW, _pszFile, NULL);
  205. }
  206. }
  207. }
  208. VariantClear(&var);
  209. }
  210. return hr;
  211. }
  212. HRESULT SHCreatePropertyBagOnProfileSection(LPCWSTR pszFile, LPCWSTR pszSection, DWORD grfMode, REFIID riid, void **ppv)
  213. {
  214. if (grfMode & STGM_CREATE)
  215. {
  216. // we need to touch this file first
  217. HANDLE h = CreateFileW(pszFile, 0, FILE_SHARE_DELETE, NULL, CREATE_NEW, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, NULL);
  218. if (INVALID_HANDLE_VALUE != h)
  219. {
  220. WCHAR szFolder[MAX_PATH];
  221. StrCpyNW(szFolder, pszFile, ARRAYSIZE(szFolder));
  222. if (PathRemoveFileSpecW(szFolder))
  223. {
  224. PathMakeSystemFolderW(szFolder);
  225. }
  226. CloseHandle(h);
  227. }
  228. }
  229. if (PathFileExistsAndAttributesW(pszFile, NULL))
  230. {
  231. CIniPropertyBag *pbag = new CIniPropertyBag(grfMode);
  232. if (pbag)
  233. {
  234. HRESULT hr = pbag->_Init(pszFile, pszSection);
  235. if (SUCCEEDED(hr))
  236. hr = pbag->QueryInterface(riid, ppv);
  237. pbag->Release();
  238. return hr;
  239. }
  240. }
  241. *ppv = NULL;
  242. return E_OUTOFMEMORY;
  243. }
  244. //
  245. // Registry property bag implementation
  246. //
  247. class CRegPropertyBag : public CBasePropertyBag
  248. {
  249. public:
  250. // IPropertyBag
  251. STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
  252. STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT *pVar);
  253. protected: // methods
  254. CRegPropertyBag(DWORD grfMode);
  255. virtual ~CRegPropertyBag();
  256. HRESULT _Init(HKEY hk, LPCWSTR pszSubKey);
  257. friend HRESULT SHCreatePropertyBagOnRegKey(HKEY hk, LPCWSTR pszSubKey, DWORD grfMode, REFIID riid, void **ppv);
  258. private:
  259. HRESULT _ReadDword(LPCOLESTR pszPropName, VARIANT *pvar);
  260. HRESULT _ReadString(LPCOLESTR pszPropName, VARIANT *pvar, DWORD cb);
  261. HRESULT _ReadStream(VARIANT* pvar, BYTE* pBuff, DWORD cb);
  262. HRESULT _ReadBinary(LPCOLESTR pszPropName, VARIANT* pvar, VARTYPE vt, DWORD cb);
  263. HRESULT _GetStreamSize(IStream* pstm, DWORD* pcb);
  264. HRESULT _CopyStreamIntoBuff(IStream* pstm, BYTE* pBuff, DWORD cb);
  265. HRESULT _WriteStream(LPCOLESTR pszPropName, IStream* pstm);
  266. protected: // members
  267. HKEY _hk;
  268. friend HRESULT SHCreatePropertyBagOnRegKey(HKEY hk, LPCWSTR pszSubKey, DWORD grfMode, REFIID riid, void **ppv);
  269. };
  270. CRegPropertyBag::CRegPropertyBag(DWORD grfMode) : CBasePropertyBag(grfMode)
  271. {
  272. ASSERT(NULL == _hk);
  273. }
  274. CRegPropertyBag::~CRegPropertyBag()
  275. {
  276. if (_hk)
  277. RegCloseKey(_hk);
  278. }
  279. HRESULT CRegPropertyBag::_Init(HKEY hk, LPCWSTR pszSubKey)
  280. {
  281. DWORD err;
  282. REGSAM sam = 0;
  283. if (SUCCEEDED(_CanRead()))
  284. sam |= KEY_READ;
  285. if (SUCCEEDED(_CanWrite()))
  286. sam |= KEY_WRITE;
  287. if (_grfMode & STGM_CREATE)
  288. err = RegCreateKeyExW(hk, pszSubKey, 0, NULL, 0, sam, NULL, &_hk, NULL);
  289. else
  290. err = RegOpenKeyExW(hk, pszSubKey, 0, sam, &_hk);
  291. return HRESULT_FROM_WIN32(err);
  292. }
  293. HRESULT CRegPropertyBag::_ReadDword(LPCOLESTR pszPropName, VARIANT *pvar)
  294. {
  295. HRESULT hr;
  296. DWORD dwType;
  297. DWORD cb = sizeof(pvar->lVal);
  298. if (NOERROR == SHGetValueW(_hk, NULL, pszPropName, &dwType, &pvar->lVal, &cb))
  299. {
  300. ASSERT(REG_DWORD == dwType);
  301. pvar->vt = VT_UI4;
  302. hr = S_OK;
  303. }
  304. else
  305. {
  306. hr = E_FAIL;
  307. }
  308. return hr;
  309. }
  310. HRESULT CRegPropertyBag::_ReadString(LPCOLESTR pszPropName, VARIANT *pvar, DWORD cb)
  311. {
  312. HRESULT hr;
  313. DWORD dwType;
  314. pvar->bstrVal = SysAllocStringByteLen(NULL, cb);
  315. if (pvar->bstrVal)
  316. {
  317. pvar->vt = VT_BSTR;
  318. if (NOERROR == SHGetValueW(_hk, NULL, pszPropName, &dwType, pvar->bstrVal, &cb))
  319. {
  320. hr = S_OK;
  321. }
  322. else
  323. {
  324. VariantClear(pvar);
  325. hr = E_FAIL;
  326. }
  327. }
  328. else
  329. {
  330. hr = E_OUTOFMEMORY;
  331. }
  332. return hr;
  333. }
  334. HRESULT CRegPropertyBag::_ReadStream(VARIANT* pvar, BYTE* pBuff, DWORD cb)
  335. {
  336. HRESULT hr;
  337. pvar->punkVal = SHCreateMemStream(pBuff, cb);
  338. if (pvar->punkVal)
  339. {
  340. pvar->vt = VT_UNKNOWN;
  341. hr = S_OK;
  342. }
  343. else
  344. {
  345. hr = E_OUTOFMEMORY;
  346. }
  347. return hr;
  348. }
  349. HRESULT CRegPropertyBag::_ReadBinary(LPCOLESTR pszPropName, VARIANT* pvar, VARTYPE vt, DWORD cb)
  350. {
  351. HRESULT hr;
  352. switch(vt)
  353. {
  354. case VT_UNKNOWN:
  355. hr = E_FAIL;
  356. if (EVAL(cb >= sizeof(GUID)))
  357. {
  358. BYTE* pBuff = static_cast<BYTE*>(LocalAlloc(LPTR, cb));
  359. if (pBuff)
  360. {
  361. DWORD dwType;
  362. if (NOERROR == SHGetValueW(_hk, NULL, pszPropName, &dwType, pBuff, &cb))
  363. {
  364. GUID* pguid = (GUID*)pBuff;
  365. if (IsEqualGUID(GUID_NULL, *pguid))
  366. {
  367. // it's our non-cocreatable IStream implementation
  368. hr = _ReadStream(pvar, pBuff + sizeof(GUID), cb - sizeof(GUID));
  369. }
  370. else
  371. {
  372. ASSERTMSG(FALSE, "We don't support writing other types of objects yet.");
  373. }
  374. }
  375. LocalFree(pBuff);
  376. }
  377. }
  378. break;
  379. default:
  380. hr = E_FAIL;
  381. break;
  382. }
  383. return hr;
  384. }
  385. HRESULT CRegPropertyBag::Read(LPCOLESTR pszPropName, VARIANT *pvar, IErrorLog *pErrorLog)
  386. {
  387. HRESULT hr = _CanRead();
  388. if (SUCCEEDED(hr))
  389. {
  390. VARTYPE vtDesired = pvar->vt;
  391. VariantInit(pvar);
  392. DWORD dwType;
  393. DWORD cb;
  394. if (NOERROR == SHGetValueW(_hk, NULL, pszPropName, &dwType, NULL, &cb))
  395. {
  396. switch(dwType)
  397. {
  398. case REG_DWORD:
  399. hr = _ReadDword(pszPropName, pvar);
  400. break;
  401. case REG_SZ:
  402. hr = _ReadString(pszPropName, pvar, cb);
  403. break;
  404. case REG_BINARY:
  405. hr = _ReadBinary(pszPropName, pvar, vtDesired, cb);
  406. break;
  407. default:
  408. hr = E_FAIL;
  409. break;
  410. }
  411. if (SUCCEEDED(hr))
  412. {
  413. hr = VariantChangeTypeForRead(pvar, vtDesired);
  414. }
  415. }
  416. else
  417. {
  418. hr = E_FAIL;
  419. }
  420. }
  421. if (FAILED(hr))
  422. VariantInit(pvar);
  423. return hr;
  424. }
  425. HRESULT CRegPropertyBag::_GetStreamSize(IStream* pstm, DWORD* pcb)
  426. {
  427. HRESULT hr;
  428. *pcb = 0;
  429. ULARGE_INTEGER uli;
  430. hr = IStream_Size(pstm, &uli);
  431. if (SUCCEEDED(hr))
  432. {
  433. if (0 == uli.HighPart)
  434. {
  435. *pcb = uli.LowPart;
  436. }
  437. else
  438. {
  439. hr = E_FAIL;
  440. }
  441. }
  442. return hr;
  443. }
  444. HRESULT CRegPropertyBag::_CopyStreamIntoBuff(IStream* pstm, BYTE* pBuff, DWORD cb)
  445. {
  446. HRESULT hr;
  447. hr = IStream_Reset(pstm);
  448. if (SUCCEEDED(hr))
  449. {
  450. hr = IStream_Read(pstm, pBuff, cb);
  451. }
  452. return hr;
  453. }
  454. HRESULT CRegPropertyBag::_WriteStream(LPCOLESTR pszPropName, IStream* pstm)
  455. {
  456. HRESULT hr;
  457. DWORD cb;
  458. hr = _GetStreamSize(pstm, &cb);
  459. if (SUCCEEDED(hr) && cb)
  460. {
  461. BYTE* pBuff = static_cast<BYTE*>(LocalAlloc(LPTR, cb + sizeof(GUID)));
  462. if (pBuff)
  463. {
  464. // we're using a NULL GUID to mean our own IStream implementation
  465. hr = _CopyStreamIntoBuff(pstm, pBuff + sizeof(GUID), cb);
  466. if (SUCCEEDED(hr))
  467. {
  468. if (NOERROR != SHSetValueW(_hk, NULL, pszPropName, REG_BINARY, pBuff, cb + sizeof(GUID)))
  469. {
  470. hr = E_FAIL;
  471. }
  472. }
  473. LocalFree(pBuff);
  474. }
  475. else
  476. {
  477. hr = E_OUTOFMEMORY;
  478. }
  479. }
  480. return hr;
  481. }
  482. HRESULT CRegPropertyBag::Write(LPCOLESTR pszPropName, VARIANT *pvar)
  483. {
  484. HRESULT hr = _CanWrite();
  485. if (SUCCEEDED(hr))
  486. {
  487. VARIANT var = { 0 };
  488. switch(pvar->vt)
  489. {
  490. case VT_EMPTY:
  491. SHDeleteValueW(_hk, NULL, pszPropName);
  492. break;
  493. case VT_I1:
  494. case VT_I2:
  495. case VT_I4:
  496. case VT_INT:
  497. case VT_UI1:
  498. case VT_UI2:
  499. case VT_UI4:
  500. case VT_UINT:
  501. case VT_BOOL:
  502. hr = VariantChangeType(&var, pvar, 0, VT_UI4);
  503. if (SUCCEEDED(hr))
  504. {
  505. if (NOERROR != SHSetValueW(_hk, NULL, pszPropName, REG_DWORD, &var.lVal, sizeof(var.lVal)))
  506. {
  507. hr = E_FAIL;
  508. }
  509. }
  510. break;
  511. case VT_UNKNOWN:
  512. IStream* pstm;
  513. hr = pvar->punkVal->QueryInterface(IID_PPV_ARG(IStream, &pstm));
  514. if (SUCCEEDED(hr))
  515. {
  516. hr = _WriteStream(pszPropName, pstm);
  517. pstm->Release();
  518. }
  519. else
  520. {
  521. TraceMsg(TF_WARNING, "CRegPropertyBag::Write: Someone is trying to write an object we don't know how to save");
  522. }
  523. break;
  524. default:
  525. hr = VariantChangeType(&var, pvar, 0, VT_BSTR);
  526. if (SUCCEEDED(hr))
  527. {
  528. if (NOERROR != SHSetValueW(_hk, NULL, pszPropName, REG_SZ, var.bstrVal, CbFromCchW(lstrlenW(var.bstrVal) + 1)))
  529. {
  530. hr = E_FAIL;
  531. }
  532. VariantClear(&var);
  533. }
  534. break;
  535. }
  536. }
  537. return hr;
  538. }
  539. HRESULT SHCreatePropertyBagOnRegKey(HKEY hk, LPCWSTR pszSubKey, DWORD grfMode, REFIID riid, void **ppv)
  540. {
  541. HRESULT hr;
  542. CRegPropertyBag *pbag = new CRegPropertyBag(grfMode);
  543. if (pbag)
  544. {
  545. hr = pbag->_Init(hk, pszSubKey);
  546. if (SUCCEEDED(hr))
  547. hr = pbag->QueryInterface(riid, ppv);
  548. pbag->Release();
  549. }
  550. else
  551. {
  552. *ppv = NULL;
  553. hr = E_OUTOFMEMORY;
  554. }
  555. return hr;
  556. }
  557. //
  558. // Memory property bag implementation
  559. //
  560. typedef struct
  561. {
  562. LPWSTR pszPropName;
  563. VARIANT variant;
  564. } PBAGENTRY, * LPPBAGENTRY;
  565. class CMemPropertyBag : public CBasePropertyBag
  566. {
  567. public:
  568. // IPropertyBag
  569. STDMETHOD(Read)(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
  570. STDMETHOD(Write)(LPCOLESTR pszPropName, VARIANT *pVar);
  571. protected: // methods
  572. CMemPropertyBag(DWORD grfMode) : CBasePropertyBag(grfMode) {}
  573. ~CMemPropertyBag();
  574. HRESULT _Find(LPCOLESTR pszPropName, PBAGENTRY **pppbe, BOOL fCreate);
  575. friend HRESULT SHCreatePropertyBagOnMemory(DWORD grfMode, REFIID riid, void **ppv);
  576. protected: // members
  577. HDSA _hdsaProperties;
  578. };
  579. INT _FreePropBagCB(LPVOID pData, LPVOID lParam)
  580. {
  581. LPPBAGENTRY ppbe = (LPPBAGENTRY)pData;
  582. Str_SetPtrW(&ppbe->pszPropName, NULL);
  583. VariantClear(&ppbe->variant);
  584. return 1;
  585. }
  586. CMemPropertyBag::~CMemPropertyBag()
  587. {
  588. if (_hdsaProperties)
  589. DSA_DestroyCallback(_hdsaProperties, _FreePropBagCB, NULL);
  590. }
  591. //
  592. // manange the list of propeties in the property bag
  593. //
  594. HRESULT CMemPropertyBag::_Find(LPCOLESTR pszPropName, PBAGENTRY **pppbe, BOOL fCreate)
  595. {
  596. int i;
  597. PBAGENTRY pbe = { 0 };
  598. *pppbe = NULL;
  599. // look up the property in the DSA
  600. // PERF: change to a DPA and sort accordingly for better perf (daviddv 110798)
  601. for ( i = 0 ; _hdsaProperties && (i < DSA_GetItemCount(_hdsaProperties)) ; i++ )
  602. {
  603. LPPBAGENTRY ppbe = (LPPBAGENTRY)DSA_GetItemPtr(_hdsaProperties, i);
  604. if ( !StrCmpIW(pszPropName, ppbe->pszPropName) )
  605. {
  606. *pppbe = ppbe;
  607. return S_OK;
  608. }
  609. }
  610. // no entry found, should we create one?
  611. if ( !fCreate )
  612. return E_FAIL;
  613. // yes, so lets check to see if we have a DSA yet.
  614. if ( !_hdsaProperties )
  615. _hdsaProperties = DSA_Create(SIZEOF(PBAGENTRY), 4);
  616. if ( !_hdsaProperties )
  617. return E_OUTOFMEMORY;
  618. // we have the DSA so lets fill the record we want to put into it
  619. if ( !Str_SetPtrW(&pbe.pszPropName, pszPropName) )
  620. return E_OUTOFMEMORY;
  621. VariantInit(&pbe.variant);
  622. // append it to the DSA we are using
  623. i = DSA_AppendItem(_hdsaProperties, &pbe);
  624. if ( -1 == i )
  625. {
  626. Str_SetPtrW(&pbe.pszPropName, NULL);
  627. return E_OUTOFMEMORY;
  628. }
  629. *pppbe = (LPPBAGENTRY)DSA_GetItemPtr(_hdsaProperties, i);
  630. return S_OK;
  631. }
  632. //
  633. // IPropertyBag methods
  634. //
  635. STDMETHODIMP CMemPropertyBag::Read(LPCOLESTR pszPropName, VARIANT *pv, IErrorLog *pErrorLog)
  636. {
  637. VARTYPE vtDesired = pv->vt;
  638. VariantInit(pv);
  639. HRESULT hr = _CanRead();
  640. if (SUCCEEDED(hr))
  641. {
  642. hr = (pszPropName && pv) ? S_OK : E_INVALIDARG;
  643. if (SUCCEEDED(hr))
  644. {
  645. LPPBAGENTRY ppbe;
  646. hr = _Find(pszPropName, &ppbe, FALSE);
  647. if (SUCCEEDED(hr))
  648. {
  649. hr = VariantCopy(pv, &ppbe->variant);
  650. if (SUCCEEDED(hr))
  651. hr = VariantChangeTypeForRead(pv, vtDesired);
  652. }
  653. }
  654. }
  655. return hr;
  656. }
  657. STDMETHODIMP CMemPropertyBag::Write(LPCOLESTR pszPropName, VARIANT *pv)
  658. {
  659. HRESULT hr = _CanWrite();
  660. if (SUCCEEDED(hr))
  661. {
  662. hr = (pszPropName && pv) ? S_OK : E_INVALIDARG;
  663. if (SUCCEEDED(hr))
  664. {
  665. LPPBAGENTRY ppbe;
  666. hr = _Find(pszPropName, &ppbe, TRUE);
  667. if (SUCCEEDED(hr))
  668. {
  669. hr = VariantCopy(&ppbe->variant, pv);
  670. }
  671. }
  672. }
  673. return hr;
  674. }
  675. //
  676. // Exported function for creating a IPropertyBag (or variant of) object.
  677. //
  678. STDAPI SHCreatePropertyBagOnMemory(DWORD grfMode, REFIID riid, void **ppv)
  679. {
  680. CMemPropertyBag *ppb = new CMemPropertyBag(grfMode);
  681. if (ppb)
  682. {
  683. HRESULT hres = ppb->QueryInterface(riid, ppv);
  684. ppb->Release();
  685. return hres;
  686. }
  687. *ppv = NULL;
  688. return E_OUTOFMEMORY;
  689. }
  690. //
  691. // Property bag helper functions
  692. //
  693. STDAPI SHPropertyBag_ReadType(IPropertyBag *ppb, LPCWSTR pszPropName, VARIANT *pv, VARTYPE vt)
  694. {
  695. VariantInit(pv);
  696. pv->vt = vt;
  697. HRESULT hr = ppb->Read(pszPropName, pv, NULL);
  698. if (SUCCEEDED(hr))
  699. {
  700. if (vt != pv->vt && vt != VT_EMPTY)
  701. {
  702. TraceMsg(TF_WARNING, "SHPropertyBag_ReadType found an IPropertyBag that did not return the correct data!");
  703. }
  704. // Our IPropertyBag implementations have been buggy in the past, cover up for them
  705. hr = VariantChangeTypeForRead(pv, vt);
  706. }
  707. else
  708. {
  709. // don't break the caller by returning a bogus VARIANT struct
  710. VariantInit(pv);
  711. }
  712. return hr;
  713. }
  714. STDAPI SHPropertyBag_ReadBSTR(IPropertyBag *ppb, LPCWSTR pszPropName, BSTR* pbstr)
  715. {
  716. RIPMSG(NULL != ppb, "SHPropertyBag_ReadBSTR caller passed bad ppb");
  717. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_ReadBSTR caller passed bad pszPropName");
  718. RIPMSG(IS_VALID_WRITE_PTR(pbstr, *pbstr), "SHPropertyBag_ReadBSTR caller passed bad pbstr");
  719. HRESULT hr;
  720. if (ppb && pszPropName && pbstr)
  721. {
  722. VARIANT va;
  723. hr = SHPropertyBag_ReadType(ppb, pszPropName, &va, VT_BSTR);
  724. if (SUCCEEDED(hr))
  725. *pbstr = va.bstrVal;
  726. else
  727. *pbstr = NULL;
  728. }
  729. else
  730. {
  731. hr = E_INVALIDARG;
  732. }
  733. return hr;
  734. }
  735. STDAPI SHPropertyBag_ReadStr(IPropertyBag* ppb, LPCWSTR pszPropName, LPWSTR psz, int cch)
  736. {
  737. RIPMSG(NULL != ppb, "SHPropertyBag_ReadStr caller passed bad ppb");
  738. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_ReadStr caller passed bad pszPropName");
  739. RIPMSG(IS_VALID_WRITE_BUFFER(psz, *psz, cch), "SHPropertyBag_ReadStr caller passed bad psz and cch");
  740. HRESULT hr;
  741. if (ppb && pszPropName && psz)
  742. {
  743. VARIANT va;
  744. hr = SHPropertyBag_ReadType(ppb, pszPropName, &va, VT_BSTR);
  745. if (SUCCEEDED(hr))
  746. {
  747. StrCpyNW(psz, va.bstrVal, cch);
  748. VariantClear(&va);
  749. hr = S_OK;
  750. }
  751. else
  752. {
  753. hr = E_FAIL;
  754. }
  755. }
  756. else
  757. {
  758. hr = E_INVALIDARG;
  759. }
  760. return hr;
  761. }
  762. STDAPI SHPropertyBag_WriteStr(IPropertyBag* ppb, LPCWSTR pszPropName, LPCWSTR psz)
  763. {
  764. RIPMSG(NULL != ppb, "SHPropertyBag_WriteStr caller passed bad ppb");
  765. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_WriteStr caller passed bad pszPropName");
  766. RIPMSG(NULL == psz || IS_VALID_STRING_PTRW(psz, -1), "SHPropertyBag_WriteStr caller passed bad psz");
  767. HRESULT hr;
  768. if (ppb && pszPropName)
  769. {
  770. VARIANT va;
  771. va.bstrVal = SysAllocString(psz);
  772. if (va.bstrVal)
  773. {
  774. va.vt = VT_BSTR;
  775. hr = ppb->Write(pszPropName, &va);
  776. SysFreeString(va.bstrVal);
  777. }
  778. else
  779. {
  780. hr = E_OUTOFMEMORY;
  781. }
  782. }
  783. else
  784. {
  785. hr = E_INVALIDARG;
  786. }
  787. return hr;
  788. }
  789. STDAPI SHPropertyBag_ReadInt(IPropertyBag* ppb, LPCWSTR pszPropName, int* piResult)
  790. {
  791. RIPMSG(NULL != ppb, "SHPropertyBag_ReadInt caller passed bad ppb");
  792. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_ReadInt caller passed bad pszPropName");
  793. RIPMSG(IS_VALID_WRITE_PTR(piResult, *piResult), "SHPropertyBag_ReadInt caller passed bad piResult");
  794. HRESULT hr;
  795. if (ppb && pszPropName && piResult)
  796. {
  797. VARIANT va;
  798. hr = SHPropertyBag_ReadType(ppb, pszPropName, &va, VT_I4);
  799. if (SUCCEEDED(hr))
  800. {
  801. *piResult = va.ulVal;
  802. // VT_I4 has nothing to VariantClear
  803. }
  804. }
  805. else
  806. {
  807. hr = E_INVALIDARG;
  808. }
  809. return hr;
  810. }
  811. STDAPI SHPropertyBag_WriteInt(IPropertyBag* ppb, LPCWSTR pszPropName, int i)
  812. {
  813. RIPMSG(NULL != ppb, "SHPropertyBag_WriteInt caller passed bad ppb");
  814. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_WriteInt caller passed bad pszPropName");
  815. HRESULT hr;
  816. if (ppb && pszPropName)
  817. {
  818. VARIANT va;
  819. va.vt = VT_I4;
  820. va.lVal = i;
  821. hr = ppb->Write(pszPropName, &va);
  822. }
  823. else
  824. {
  825. hr = E_INVALIDARG;
  826. }
  827. return hr;
  828. }
  829. STDAPI SHPropertyBag_ReadSHORT(IPropertyBag* ppb, LPCWSTR pszPropName, SHORT* psh)
  830. {
  831. RIPMSG(NULL != ppb, "SHPropertyBag_ReadSHORT caller passed bad ppb");
  832. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_ReadSHORT caller passed bad pszPropName");
  833. RIPMSG(IS_VALID_WRITE_PTR(psh, *psh), "SHPropertyBag_ReadSHORT caller passed bad psh");
  834. HRESULT hr;
  835. if (ppb && pszPropName && psh)
  836. {
  837. VARIANT va;
  838. hr = SHPropertyBag_ReadType(ppb, pszPropName, &va, VT_UI2);
  839. if (SUCCEEDED(hr))
  840. {
  841. *psh = va.iVal;
  842. }
  843. }
  844. else
  845. {
  846. hr = E_INVALIDARG;
  847. }
  848. return hr;
  849. }
  850. STDAPI SHPropertyBag_WriteSHORT(IPropertyBag* ppb, LPCWSTR pszPropName, SHORT sh)
  851. {
  852. RIPMSG(NULL != ppb, "SHPropertyBag_WriteSHORT caller passed bad ppb");
  853. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_WriteSHORT caller passed bad pszPropName");
  854. HRESULT hr;
  855. if (ppb && pszPropName)
  856. {
  857. VARIANT va;
  858. va.vt = VT_UI2;
  859. va.iVal = sh;
  860. hr = ppb->Write(pszPropName, &va);
  861. }
  862. else
  863. {
  864. hr = E_INVALIDARG;
  865. }
  866. return hr;
  867. }
  868. STDAPI SHPropertyBag_ReadLONG(IPropertyBag* ppb, LPCWSTR pszPropName, LONG* pl)
  869. {
  870. RIPMSG(NULL != ppb, "SHPropertyBag_ReadLONG caller passed bad ppb");
  871. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_ReadLONG caller passed bad pszPropName");
  872. RIPMSG(IS_VALID_WRITE_PTR(pl, *pl), "SHPropertyBag_ReadLONG caller passed bad pl");
  873. HRESULT hr;
  874. if (ppb && pszPropName && pl)
  875. {
  876. VARIANT va;
  877. hr = SHPropertyBag_ReadType(ppb, pszPropName, &va, VT_I4);
  878. if (SUCCEEDED(hr))
  879. {
  880. *pl = va.ulVal;
  881. }
  882. }
  883. else
  884. {
  885. hr = E_INVALIDARG;
  886. }
  887. return hr;
  888. }
  889. STDAPI SHPropertyBag_WriteLONG(IPropertyBag* ppb, LPCWSTR pszPropName, LONG l)
  890. {
  891. RIPMSG(NULL != ppb, "SHPropertyBag_WriteLONG caller passed bad ppb");
  892. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_WriteLONG caller passed bad pszPropName");
  893. HRESULT hr;
  894. if (ppb && pszPropName)
  895. {
  896. VARIANT va;
  897. va.vt = VT_I4;
  898. va.lVal = l;
  899. hr = ppb->Write(pszPropName, &va);
  900. }
  901. else
  902. {
  903. hr = E_INVALIDARG;
  904. }
  905. return hr;
  906. }
  907. STDAPI SHPropertyBag_ReadDWORD(IPropertyBag* ppb, LPCWSTR pszPropName, DWORD* pdw)
  908. {
  909. RIPMSG(NULL != ppb, "SHPropertyBag_ReadDWORD caller passed bad ppb");
  910. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_ReadDWORD caller passed bad pszPropName");
  911. RIPMSG(IS_VALID_WRITE_PTR(pdw, *pdw), "SHPropertyBag_ReadInt caller passed bad pdw");
  912. HRESULT hr;
  913. if (ppb && pszPropName && pdw)
  914. {
  915. VARIANT va;
  916. hr = SHPropertyBag_ReadType(ppb, pszPropName, &va, VT_UI4);
  917. if (SUCCEEDED(hr))
  918. {
  919. *pdw = va.ulVal;
  920. // VT_UI4 has nothing to VariantClear
  921. }
  922. }
  923. else
  924. {
  925. hr = E_INVALIDARG;
  926. }
  927. return hr;
  928. }
  929. STDAPI SHPropertyBag_WriteDWORD(IPropertyBag* ppb, LPCWSTR pszPropName, DWORD dw)
  930. {
  931. RIPMSG(NULL != ppb, "SHPropertyBag_WriteDWORD caller passed bad ppb");
  932. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_WriteDWORD caller passed bad pszPropName");
  933. HRESULT hr;
  934. if (ppb && pszPropName)
  935. {
  936. VARIANT va;
  937. va.vt = VT_UI4;
  938. va.ulVal = dw;
  939. hr = ppb->Write(pszPropName, &va);
  940. }
  941. else
  942. {
  943. hr = E_INVALIDARG;
  944. }
  945. return hr;
  946. }
  947. // This shipped on Whistler Beta 1. It's exported by ordinal.
  948. STDAPI_(BOOL) SHPropertyBag_ReadBOOLOld(IPropertyBag *ppb, LPCWSTR pwzPropName, BOOL fResult)
  949. {
  950. VARIANT va;
  951. HRESULT hr = SHPropertyBag_ReadType(ppb, pwzPropName, &va, VT_BOOL);
  952. if (SUCCEEDED(hr))
  953. {
  954. fResult = (va.boolVal == VARIANT_TRUE);
  955. // VT_BOOL has nothing to VariantClear
  956. }
  957. return fResult;
  958. }
  959. STDAPI SHPropertyBag_ReadBOOL(IPropertyBag* ppb, LPCWSTR pszPropName, BOOL* pfResult)
  960. {
  961. RIPMSG(NULL != ppb, "SHPropertyBag_ReadBOOL caller passed bad ppb");
  962. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_ReadBOOL caller passed bad pszPropName");
  963. RIPMSG(IS_VALID_WRITE_PTR(pfResult, *pfResult), "SHPropertyBag_ReadBOOL caller passed bad pfResult");
  964. HRESULT hr;
  965. if (ppb && pszPropName && pfResult)
  966. {
  967. VARIANT va;
  968. hr = SHPropertyBag_ReadType(ppb, pszPropName, &va, VT_BOOL);
  969. if (SUCCEEDED(hr))
  970. {
  971. *pfResult = (va.boolVal == VARIANT_TRUE);
  972. }
  973. }
  974. else
  975. {
  976. hr = E_INVALIDARG;
  977. }
  978. return hr;
  979. }
  980. STDAPI SHPropertyBag_WriteBOOL(IPropertyBag* ppb, LPCWSTR pszPropName, BOOL fValue)
  981. {
  982. RIPMSG(NULL != ppb, "SHPropertyBag_WriteBOOL caller passed bad ppb");
  983. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_WriteBOOL caller passed bad pszPropName");
  984. HRESULT hr;
  985. if (ppb && pszPropName)
  986. {
  987. VARIANT va;
  988. va.vt = VT_BOOL;
  989. va.boolVal = fValue ? VARIANT_TRUE : VARIANT_FALSE;
  990. hr = ppb->Write(pszPropName, &va);
  991. }
  992. else
  993. {
  994. hr = E_INVALIDARG;
  995. }
  996. return hr;
  997. }
  998. STDAPI SHPropertyBag_ReadGUID(IPropertyBag* ppb, LPCWSTR pszPropName, GUID* pguid)
  999. {
  1000. RIPMSG(NULL != ppb, "SHPropertyBag_ReadGUID caller passed bad ppb");
  1001. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_ReadGUID caller passed bad pszPropName");
  1002. RIPMSG(IS_VALID_WRITE_PTR(pguid, *pguid), "SHPropertyBag_ReadGUID caller passed bad pguid");
  1003. HRESULT hr;
  1004. if (ppb && pszPropName && pguid)
  1005. {
  1006. VARIANT var;
  1007. hr = SHPropertyBag_ReadType(ppb, pszPropName, &var, VT_EMPTY);
  1008. if (SUCCEEDED(hr))
  1009. {
  1010. if (var.vt == (VT_ARRAY | VT_UI1)) // some code has been writing GUIDs as array's of bytes
  1011. {
  1012. hr = VariantToGUID(&var, pguid) ? S_OK : E_FAIL;
  1013. }
  1014. else if (var.vt == VT_BSTR)
  1015. {
  1016. hr = GUIDFromStringW(var.bstrVal, pguid) ? S_OK : E_FAIL;
  1017. }
  1018. VariantClear(&var);
  1019. }
  1020. }
  1021. else
  1022. {
  1023. hr = E_INVALIDARG;
  1024. }
  1025. return hr;
  1026. }
  1027. STDAPI SHPropertyBag_WriteGUID(IPropertyBag *ppb, LPCWSTR pszPropName, const GUID *pguid)
  1028. {
  1029. RIPMSG(NULL != ppb, "SHPropertyBag_WriteGUID caller passed bad ppb");
  1030. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_WriteGUID caller passed bad pszPropName");
  1031. RIPMSG(IS_VALID_READ_PTR(pguid, *pguid), "SHPropertyBag_WriteGUID caller passed bad pguid");
  1032. HRESULT hr;
  1033. if (ppb && pszPropName && pguid)
  1034. {
  1035. WCHAR sz[64];
  1036. SHStringFromGUIDW(*pguid, sz, ARRAYSIZE(sz));
  1037. hr = SHPropertyBag_WriteStr(ppb, pszPropName, sz); // assumes null terminator
  1038. }
  1039. else
  1040. {
  1041. hr = E_INVALIDARG;
  1042. }
  1043. return hr;
  1044. }
  1045. STDAPI SHPropertyBag_ReadPOINTL(IPropertyBag* ppb, LPCWSTR pszPropName, POINTL* ppt)
  1046. {
  1047. RIPMSG(NULL != ppb, "SHPropertyBag_ReadPOINTL caller passed bad ppb");
  1048. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_ReadPOINTL caller passed bad pszPropName");
  1049. RIPMSG(IS_VALID_WRITE_PTR(ppt, *ppt), "SHPropertyBag_ReadPOINTL caller passed bad ppt");
  1050. HRESULT hr;
  1051. if (ppb && pszPropName && ppt)
  1052. {
  1053. WCHAR szProp[MAX_PATH];
  1054. RIP(lstrlenW(pszPropName) < ARRAYSIZE(szProp) - 2);
  1055. StrCpyNW(szProp, pszPropName, ARRAYSIZE(szProp));
  1056. UINT cch = lstrlenW(szProp);
  1057. if (ARRAYSIZE(szProp) - cch >= 3)
  1058. {
  1059. StrCpyNW(szProp + cch, L".x", ARRAYSIZE(szProp) - cch);
  1060. hr = SHPropertyBag_ReadLONG(ppb, szProp, &ppt->x);
  1061. if (SUCCEEDED(hr))
  1062. {
  1063. StrCpyNW(szProp + cch, L".y", ARRAYSIZE(szProp) - cch);
  1064. hr = SHPropertyBag_ReadLONG(ppb, szProp, &ppt->y);
  1065. }
  1066. }
  1067. else
  1068. {
  1069. hr = E_FAIL;
  1070. }
  1071. }
  1072. else
  1073. {
  1074. hr = E_INVALIDARG;
  1075. }
  1076. return hr;
  1077. }
  1078. STDAPI SHPropertyBag_WritePOINTL(IPropertyBag* ppb, LPCWSTR pszPropName, const POINTL* ppt)
  1079. {
  1080. RIPMSG(NULL != ppb, "SHPropertyBag_WritePOINTL caller passed bad ppb");
  1081. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_WritePOINTL caller passed bad pszPropName");
  1082. RIPMSG(IS_VALID_READ_PTR(ppt, *ppt), "SHPropertyBag_WritePOINTL caller passed bad ppt");
  1083. HRESULT hr;
  1084. if (ppb && pszPropName && ppt)
  1085. {
  1086. WCHAR szProp[MAX_PATH];
  1087. RIP(lstrlenW(pszPropName) < ARRAYSIZE(szProp) - 2);
  1088. StrCpyNW(szProp, pszPropName, ARRAYSIZE(szProp));
  1089. UINT cch = lstrlenW(szProp);
  1090. if (ARRAYSIZE(szProp) - cch >= 3)
  1091. {
  1092. StrCpyNW(szProp + cch, L".x", ARRAYSIZE(szProp) - cch);
  1093. hr = SHPropertyBag_WriteLONG(ppb, szProp, ppt->x);
  1094. if (SUCCEEDED(hr))
  1095. {
  1096. StrCpyNW(szProp + cch, L".y", ARRAYSIZE(szProp) - cch);
  1097. hr = SHPropertyBag_WriteLONG(ppb, szProp, ppt->y);
  1098. if (FAILED(hr))
  1099. {
  1100. StrCpyNW(szProp + cch, L".x", ARRAYSIZE(szProp) - cch);
  1101. hr = SHPropertyBag_Delete(ppb, szProp);
  1102. }
  1103. }
  1104. }
  1105. else
  1106. {
  1107. hr = E_FAIL;
  1108. }
  1109. }
  1110. else
  1111. {
  1112. hr = E_INVALIDARG;
  1113. }
  1114. return hr;
  1115. }
  1116. STDAPI SHPropertyBag_ReadPOINTS(IPropertyBag* ppb, LPCWSTR pszPropName, POINTS* ppt)
  1117. {
  1118. RIPMSG(NULL != ppb, "SHPropertyBag_ReadPOINTS caller passed bad ppb");
  1119. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_ReadPOINTS caller passed bad pszPropName");
  1120. RIPMSG(IS_VALID_WRITE_PTR(ppt, *ppt), "SHPropertyBag_ReadPOINTS caller passed bad ppt");
  1121. HRESULT hr;
  1122. if (ppb && pszPropName && ppt)
  1123. {
  1124. POINTL ptL;
  1125. hr = SHPropertyBag_ReadPOINTL(ppb, pszPropName, &ptL);
  1126. if (SUCCEEDED(hr))
  1127. {
  1128. ppt->x = static_cast<SHORT>(ptL.x);
  1129. ppt->y = static_cast<SHORT>(ptL.y);
  1130. }
  1131. }
  1132. else
  1133. {
  1134. hr = E_INVALIDARG;
  1135. }
  1136. return hr;
  1137. }
  1138. STDAPI SHPropertyBag_WritePOINTS(IPropertyBag* ppb, LPCWSTR pszPropName, const POINTS* ppt)
  1139. {
  1140. RIPMSG(NULL != ppb, "SHPropertyBag_WritePOINTS caller passed bad ppb");
  1141. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_WritePOINTS caller passed bad pszPropName");
  1142. RIPMSG(IS_VALID_READ_PTR(ppt, *ppt), "SHPropertyBag_WritePOINTS caller passed bad ppt");
  1143. HRESULT hr;
  1144. if (ppb && pszPropName && ppt)
  1145. {
  1146. POINTL ptL;
  1147. ptL.x = ppt->x;
  1148. ptL.y = ppt->y;
  1149. hr = SHPropertyBag_WritePOINTL(ppb, pszPropName, &ptL);
  1150. }
  1151. else
  1152. {
  1153. hr = E_INVALIDARG;
  1154. }
  1155. return hr;
  1156. }
  1157. STDAPI SHPropertyBag_ReadRECTL(IPropertyBag* ppb, LPCWSTR pszPropName, RECTL* prc)
  1158. {
  1159. RIPMSG(NULL != ppb, "SHPropertyBag_ReadRECTL caller passed bad ppb");
  1160. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_ReadRECTL caller passed bad pszPropName");
  1161. RIPMSG(IS_VALID_WRITE_PTR(prc, *prc), "SHPropertyBag_ReadRECTL caller passed bad prc");
  1162. HRESULT hr;
  1163. if (ppb && pszPropName && prc)
  1164. {
  1165. WCHAR szProp[MAX_PATH];
  1166. RIP(lstrlenW(pszPropName) < ARRAYSIZE(szProp) - 7);
  1167. StrCpyNW(szProp, pszPropName, ARRAYSIZE(szProp));
  1168. UINT cch = lstrlenW(szProp);
  1169. if (ARRAYSIZE(szProp) - cch >= 8)
  1170. {
  1171. StrCpyNW(szProp + cch, L".left", ARRAYSIZE(szProp) - cch);
  1172. hr = SHPropertyBag_ReadLONG(ppb, szProp, &prc->left);
  1173. if (SUCCEEDED(hr))
  1174. {
  1175. StrCpyNW(szProp + cch, L".top", ARRAYSIZE(szProp) - cch);
  1176. hr = SHPropertyBag_ReadLONG(ppb, szProp, &prc->top);
  1177. if (SUCCEEDED(hr))
  1178. {
  1179. StrCpyNW(szProp + cch, L".right", ARRAYSIZE(szProp) - cch);
  1180. hr = SHPropertyBag_ReadLONG(ppb, szProp, &prc->right);
  1181. if (SUCCEEDED(hr))
  1182. {
  1183. StrCpyNW(szProp + cch, L".bottom", ARRAYSIZE(szProp) - cch);
  1184. hr = SHPropertyBag_ReadLONG(ppb, szProp, &prc->bottom);
  1185. }
  1186. }
  1187. }
  1188. }
  1189. else
  1190. {
  1191. hr = E_FAIL;
  1192. }
  1193. }
  1194. else
  1195. {
  1196. hr = E_INVALIDARG;
  1197. }
  1198. return hr;
  1199. }
  1200. STDAPI SHPropertyBag_WriteRECTL(IPropertyBag* ppb, LPCWSTR pszPropName, const RECTL* prc)
  1201. {
  1202. RIPMSG(NULL != ppb, "SHPropertyBag_WriteRECTL caller passed bad ppb");
  1203. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_WriteRECTL caller passed bad pszPropName");
  1204. RIPMSG(IS_VALID_READ_PTR(prc, *prc), "SHPropertyBag_WriteRECTL caller passed bad prc");
  1205. HRESULT hr;
  1206. if (ppb && pszPropName && prc)
  1207. {
  1208. WCHAR szProp[MAX_PATH];
  1209. RIP(lstrlenW(pszPropName) < ARRAYSIZE(szProp) - 7);
  1210. StrCpyNW(szProp, pszPropName, ARRAYSIZE(szProp));
  1211. UINT cch = lstrlenW(szProp);
  1212. if (ARRAYSIZE(szProp) - cch >= 8)
  1213. {
  1214. StrCpyNW(szProp + cch, L".left", ARRAYSIZE(szProp) - cch);
  1215. hr = SHPropertyBag_WriteLONG(ppb, szProp, prc->left);
  1216. if (SUCCEEDED(hr))
  1217. {
  1218. StrCpyNW(szProp + cch, L".top", ARRAYSIZE(szProp) - cch);
  1219. hr = SHPropertyBag_WriteLONG(ppb, szProp, prc->top);
  1220. if (SUCCEEDED(hr))
  1221. {
  1222. StrCpyNW(szProp + cch, L".right", ARRAYSIZE(szProp) - cch);
  1223. hr = SHPropertyBag_WriteLONG(ppb, szProp, prc->right);
  1224. if (SUCCEEDED(hr))
  1225. {
  1226. StrCpyNW(szProp + cch, L".bottom", ARRAYSIZE(szProp) - cch);
  1227. hr = SHPropertyBag_WriteLONG(ppb, szProp, prc->bottom);
  1228. if (FAILED(hr))
  1229. {
  1230. StrCpyNW(szProp + cch, L".right", ARRAYSIZE(szProp) - cch);
  1231. hr = SHPropertyBag_Delete(ppb, szProp);
  1232. }
  1233. }
  1234. if (FAILED(hr))
  1235. {
  1236. StrCpyNW(szProp + cch, L".top", ARRAYSIZE(szProp) - cch);
  1237. hr = SHPropertyBag_Delete(ppb, szProp);
  1238. }
  1239. }
  1240. if (FAILED(hr))
  1241. {
  1242. StrCpyNW(szProp + cch, L".left", ARRAYSIZE(szProp) - cch);
  1243. hr = SHPropertyBag_Delete(ppb, szProp);
  1244. }
  1245. }
  1246. }
  1247. else
  1248. {
  1249. hr = E_FAIL;
  1250. }
  1251. }
  1252. else
  1253. {
  1254. hr = E_INVALIDARG;
  1255. }
  1256. return hr;
  1257. }
  1258. STDAPI SHPropertyBag_ReadStream(IPropertyBag* ppb, LPCWSTR pszPropName, IStream** ppstm)
  1259. {
  1260. RIPMSG(NULL != ppb, "SHPropertyBag_GetSTREAM caller passed bad ppb");
  1261. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_GetSTREAM caller passed bad pszPropName");
  1262. RIPMSG(IS_VALID_WRITE_PTR(ppstm, *ppstm), "SHPropertyBag_GetSTREAM caller passed bad ppstm");
  1263. HRESULT hr;
  1264. if (ppb && pszPropName && ppstm)
  1265. {
  1266. VARIANT va;
  1267. hr = SHPropertyBag_ReadType(ppb, pszPropName, &va, VT_UNKNOWN);
  1268. if (SUCCEEDED(hr))
  1269. {
  1270. hr = va.punkVal->QueryInterface(IID_PPV_ARG(IStream, ppstm));
  1271. va.punkVal->Release();
  1272. }
  1273. }
  1274. else
  1275. {
  1276. hr = E_INVALIDARG;
  1277. }
  1278. return hr;
  1279. }
  1280. STDAPI SHPropertyBag_WriteStream(IPropertyBag* ppb, LPCWSTR pszPropName, IStream* pstm)
  1281. {
  1282. RIPMSG(NULL != ppb, "SHPropertyBag_GetSTREAM caller passed bad ppb");
  1283. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_GetSTREAM caller passed bad pszPropName");
  1284. RIPMSG(NULL != pstm, "SHPropertyBag_GetSTREAM caller passed bad pstm");
  1285. HRESULT hr;
  1286. if (ppb && pszPropName && pstm)
  1287. {
  1288. VARIANT va;
  1289. va.vt = VT_UNKNOWN;
  1290. va.punkVal = pstm;
  1291. hr = ppb->Write(pszPropName, &va);
  1292. }
  1293. else
  1294. {
  1295. hr = E_INVALIDARG;
  1296. }
  1297. return hr;
  1298. }
  1299. STDAPI SHPropertyBag_Delete(IPropertyBag* ppb, LPCWSTR pszPropName)
  1300. {
  1301. RIPMSG(NULL != ppb, "SHPropertyBag_GetSTREAM caller passed bad ppb");
  1302. RIPMSG(IS_VALID_STRING_PTRW(pszPropName, -1), "SHPropertyBag_GetSTREAM caller passed bad pszPropName");
  1303. HRESULT hr;
  1304. if (ppb && pszPropName)
  1305. {
  1306. VARIANT va;
  1307. va.vt = VT_EMPTY;
  1308. hr = ppb->Write(pszPropName, &va);
  1309. }
  1310. else
  1311. {
  1312. hr = E_INVALIDARG;
  1313. }
  1314. return hr;
  1315. }
  1316. class CDesktopUpgradePropertyBag : public CBasePropertyBag
  1317. {
  1318. public:
  1319. // IPropertyBag
  1320. STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
  1321. STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT *pVar);
  1322. protected:
  1323. CDesktopUpgradePropertyBag() : CBasePropertyBag(STGM_READ) {}
  1324. ~CDesktopUpgradePropertyBag() {}
  1325. friend HRESULT SHGetDesktopUpgradePropertyBag(REFIID riid, void** ppv);
  1326. private:
  1327. HRESULT _ReadFlags(VARIANT* pVar);
  1328. HRESULT _ReadItemPositions(VARIANT* pVar);
  1329. IStream* _GetOldDesktopViewStream(void);
  1330. IStream* _NewStreamFromOld(IStream* pstmOld);
  1331. BOOL _AlreadyUpgraded(HKEY hk);
  1332. void _MarkAsUpgraded(HKEY hk);
  1333. };
  1334. HRESULT CDesktopUpgradePropertyBag::_ReadFlags(VARIANT* pVar)
  1335. {
  1336. HRESULT hr;
  1337. FOLDERSETTINGS fs;
  1338. DWORD cb = sizeof(fs);
  1339. if (NOERROR == SHGetValue(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER TEXT("\\DeskView"),
  1340. TEXT("Settings"), NULL, (BYTE *)&fs, &cb) &&
  1341. cb >= sizeof(fs))
  1342. {
  1343. pVar->uintVal = fs.fFlags | FWF_DESKTOP | FWF_NOCLIENTEDGE;
  1344. pVar->vt = VT_UINT;
  1345. hr = S_OK;
  1346. }
  1347. else
  1348. {
  1349. hr = E_FAIL;
  1350. }
  1351. return hr;
  1352. }
  1353. typedef struct
  1354. {
  1355. WORD wSig;
  1356. BYTE bDontCare[12];
  1357. WORD cbPosOffset;
  1358. }OLDVS_STREAMHEADER;
  1359. #define OLDVS_STREAMHEADERSIG 28 // sizeof(WIN95HEADER)
  1360. IStream* CDesktopUpgradePropertyBag::_NewStreamFromOld(IStream* pstmOld)
  1361. {
  1362. IStream* pstmNew = NULL;
  1363. OLDVS_STREAMHEADER ovssh;
  1364. if (SUCCEEDED(IStream_Read(pstmOld, &ovssh, sizeof(ovssh))) && OLDVS_STREAMHEADERSIG == ovssh.wSig)
  1365. {
  1366. LARGE_INTEGER liPos;
  1367. liPos.QuadPart = ovssh.cbPosOffset - sizeof(ovssh);
  1368. if (SUCCEEDED(pstmOld->Seek(liPos, STREAM_SEEK_CUR, NULL)))
  1369. {
  1370. ULARGE_INTEGER uliSize;
  1371. if (SUCCEEDED(IStream_Size(pstmOld, &uliSize)))
  1372. {
  1373. pstmNew = SHCreateMemStream(NULL, 0);
  1374. if (pstmNew)
  1375. {
  1376. uliSize.QuadPart -= ovssh.cbPosOffset;
  1377. if (SUCCEEDED(pstmOld->CopyTo(pstmNew, uliSize, NULL, NULL)))
  1378. {
  1379. IStream_Reset(pstmNew);
  1380. }
  1381. else
  1382. {
  1383. pstmNew->Release();
  1384. pstmNew = NULL;
  1385. }
  1386. }
  1387. }
  1388. }
  1389. }
  1390. return pstmNew;
  1391. }
  1392. BOOL CDesktopUpgradePropertyBag::_AlreadyUpgraded(HKEY hk)
  1393. {
  1394. DWORD dwUpgrade;
  1395. DWORD cbUpgrade = sizeof(dwUpgrade);
  1396. DWORD dwType;
  1397. return (ERROR_SUCCESS == SHGetValueW(hk, NULL, L"Upgrade", &dwType, &dwUpgrade, &cbUpgrade));
  1398. }
  1399. void CDesktopUpgradePropertyBag::_MarkAsUpgraded(HKEY hk)
  1400. {
  1401. DWORD dwVal = 1;
  1402. SHSetValueW(hk, NULL, L"Upgrade", REG_DWORD, &dwVal, sizeof(dwVal));
  1403. }
  1404. IStream* CDesktopUpgradePropertyBag::_GetOldDesktopViewStream()
  1405. {
  1406. IStream* pstmRet = NULL;
  1407. HKEY hk = SHGetShellKey(SHELLKEY_HKCU_EXPLORER, L"Streams\\Desktop", FALSE);
  1408. if (hk)
  1409. {
  1410. if (!_AlreadyUpgraded(hk))
  1411. {
  1412. pstmRet = SHOpenRegStream2W(hk, NULL, L"ViewView2", STGM_READ);
  1413. if (NULL != pstmRet)
  1414. {
  1415. ULARGE_INTEGER uliSize;
  1416. if (SUCCEEDED(IStream_Size(pstmRet, &uliSize)) && 0 == uliSize.QuadPart)
  1417. {
  1418. pstmRet->Release();
  1419. pstmRet = NULL;
  1420. }
  1421. }
  1422. if (NULL == pstmRet)
  1423. pstmRet = SHOpenRegStream2W(hk, NULL, L"ViewView", STGM_READ);
  1424. _MarkAsUpgraded(hk);
  1425. }
  1426. RegCloseKey(hk);
  1427. }
  1428. return pstmRet;
  1429. }
  1430. HRESULT CDesktopUpgradePropertyBag::_ReadItemPositions(VARIANT* pVar)
  1431. {
  1432. HRESULT hr = E_FAIL;
  1433. IStream* pstmOld = _GetOldDesktopViewStream();
  1434. if (pstmOld)
  1435. {
  1436. IStream* pstmNew = _NewStreamFromOld(pstmOld);
  1437. if (pstmNew)
  1438. {
  1439. pVar->punkVal = pstmNew;
  1440. pVar->vt = VT_UNKNOWN;
  1441. hr = S_OK;
  1442. }
  1443. pstmOld->Release();
  1444. }
  1445. return hr;
  1446. }
  1447. HRESULT CDesktopUpgradePropertyBag::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog *pErrorLog)
  1448. {
  1449. HRESULT hr;
  1450. VARTYPE vtDesired = pVar->vt;
  1451. if (0 == StrCmpW(VS_PROPSTR_FFLAGS, pszPropName))
  1452. {
  1453. hr = _ReadFlags(pVar);
  1454. }
  1455. else if (0 == StrCmpNW(VS_PROPSTR_ITEMPOS, pszPropName, ARRAYSIZE(VS_PROPSTR_ITEMPOS) - 1))
  1456. {
  1457. hr = _ReadItemPositions(pVar);
  1458. }
  1459. else
  1460. {
  1461. hr = E_FAIL;
  1462. }
  1463. if (SUCCEEDED(hr))
  1464. {
  1465. hr = VariantChangeTypeForRead(pVar, vtDesired);
  1466. }
  1467. else
  1468. {
  1469. VariantInit(pVar);
  1470. }
  1471. return hr;
  1472. }
  1473. HRESULT CDesktopUpgradePropertyBag::Write(LPCOLESTR pszPropName, VARIANT *pVar)
  1474. {
  1475. return E_NOTIMPL;
  1476. }
  1477. HRESULT SHGetDesktopUpgradePropertyBag(REFIID riid, void** ppv)
  1478. {
  1479. HRESULT hr;
  1480. *ppv = NULL;
  1481. CDesktopUpgradePropertyBag* pbag = new CDesktopUpgradePropertyBag();
  1482. if (pbag)
  1483. {
  1484. hr = pbag->QueryInterface(riid, ppv);
  1485. pbag->Release();
  1486. }
  1487. else
  1488. {
  1489. hr = E_OUTOFMEMORY;
  1490. }
  1491. return hr;
  1492. }
  1493. class CViewStatePropertyBag : public CBasePropertyBag
  1494. {
  1495. public:
  1496. // IPropertyBag
  1497. STDMETHODIMP Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
  1498. STDMETHODIMP Write(LPCOLESTR pszPropName, VARIANT *pVar);
  1499. protected:
  1500. CViewStatePropertyBag(void);
  1501. virtual ~CViewStatePropertyBag();
  1502. HRESULT _Init(LPCITEMIDLIST pidl, LPCWSTR pszBagName, DWORD dwFlags);
  1503. BOOL _IsSameBag(LPCITEMIDLIST pidl, LPCWSTR pszBagName, DWORD dwFlags);
  1504. friend HRESULT SHGetViewStatePropertyBag(LPCITEMIDLIST pidl, LPCWSTR pszBagName, DWORD dwFlags, REFIID riid, void** ppv);
  1505. friend HRESULT GetCachedViewStatePropertyBag(LPCITEMIDLIST pidl, LPCWSTR pszBagName, DWORD dwFlags, REFIID riid, void** ppv);
  1506. private:
  1507. HRESULT _CreateBag(LPCITEMIDLIST pidl, LPCWSTR pszBagName, DWORD dwFlags, DWORD grfMode, REFIID riid, void** ppv);
  1508. HRESULT _CreateUpgradeBag(REFIID riid, void** ppv);
  1509. BOOL _CanAccessPidlBag(void);
  1510. BOOL _EnsurePidlBag(DWORD grfMode, REFIID riid);
  1511. HRESULT _ReadPidlBag(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
  1512. BOOL _CanAccessUpgradeBag(void);
  1513. BOOL _EnsureUpgradeBag(DWORD grfMode, REFIID riid);
  1514. HRESULT _ReadUpgradeBag(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
  1515. BOOL _CanAccessInheritBag(void);
  1516. BOOL _EnsureInheritBag(DWORD grfMode, REFIID riid);
  1517. HRESULT _ReadInheritBag(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
  1518. BOOL _CanAccessUserDefaultsBag(void);
  1519. BOOL _EnsureUserDefaultsBag(DWORD grfMode, REFIID riid);
  1520. HRESULT _ReadUserDefaultsBag(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
  1521. BOOL _CanAccessFolderDefaultsBag(void);
  1522. BOOL _EnsureFolderDefaultsBag(DWORD grfMode, REFIID riid);
  1523. HRESULT _ReadFolderDefaultsBag(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
  1524. BOOL _CanAccessGlobalDefaultsBag(void);
  1525. BOOL _EnsureGlobalDefaultsBag(DWORD grfMode, REFIID riid);
  1526. HRESULT _ReadGlobalDefaultsBag(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog);
  1527. BOOL _EnsureReadBag(DWORD grfMode, REFIID riid);
  1528. BOOL _EnsureWriteBag(DWORD grfMode, REFIID riid);
  1529. HRESULT _GetRegKey(LPCITEMIDLIST pidl, LPCWSTR pszBagName, DWORD dwFlags, DWORD grfMode, HKEY hk, LPWSTR pszKey, UINT cch);
  1530. DWORD _GetMRUSize(HKEY hk);
  1531. HRESULT _GetMRUSlots(LPCITEMIDLIST pidl, DWORD grfMode, HKEY hk, DWORD adwSlot[], DWORD dwcSlots, DWORD* pdwFetched);
  1532. HRESULT _GetMRUSlot(LPCITEMIDLIST pidl, DWORD grfMode, HKEY hk, DWORD* pdwSlot);
  1533. HKEY _GetHKey(DWORD dwFlags);
  1534. void _ResetTryAgainFlag();
  1535. HRESULT _FindNearestInheritBag(REFIID riid, void** ppv);
  1536. void _PruneMRUTree(void);
  1537. BOOL _IsSamePidl(LPCITEMIDLIST pidl);
  1538. BOOL _IsSystemFolder(void);
  1539. private:
  1540. LPITEMIDLIST _pidl;
  1541. LPWSTR _pszBagName;
  1542. DWORD _dwFlags;
  1543. IPropertyBag* _ppbPidl;
  1544. IPropertyBag* _ppbUpgrade;
  1545. IPropertyBag* _ppbInherit;
  1546. IPropertyBag* _ppbUserDefaults;
  1547. IPropertyBag* _ppbFolderDefaults;
  1548. IPropertyBag* _ppbGlobalDefaults;
  1549. IPropertyBag* _ppbRead;
  1550. IPropertyBag* _ppbWrite;
  1551. BOOL _fTriedPidlBag;
  1552. BOOL _fTriedUpgradeBag;
  1553. BOOL _fTriedInheritBag;
  1554. BOOL _fTriedUserDefaultsBag;
  1555. BOOL _fTriedFolderDefaultsBag;
  1556. BOOL _fTriedGlobalDefaultsBag;
  1557. BOOL _fTriedReadBag;
  1558. BOOL _fTriedWriteBag;
  1559. };
  1560. CViewStatePropertyBag::CViewStatePropertyBag() : CBasePropertyBag(STGM_READ)
  1561. {
  1562. ASSERT(NULL == _pidl);
  1563. ASSERT(NULL == _pszBagName);
  1564. ASSERT( 0 == _dwFlags);
  1565. ASSERT(NULL == _ppbPidl);
  1566. ASSERT(NULL == _ppbUpgrade);
  1567. ASSERT(NULL == _ppbInherit);
  1568. ASSERT(NULL == _ppbUserDefaults);
  1569. ASSERT(NULL == _ppbFolderDefaults);
  1570. ASSERT(NULL == _ppbGlobalDefaults);
  1571. ASSERT(NULL == _ppbRead);
  1572. ASSERT(NULL == _ppbWrite);
  1573. }
  1574. CViewStatePropertyBag::~CViewStatePropertyBag()
  1575. {
  1576. if (_pidl)
  1577. ILFree(_pidl);
  1578. if (_pszBagName)
  1579. LocalFree(_pszBagName);
  1580. if (_ppbPidl)
  1581. _ppbPidl->Release();
  1582. if (_ppbUpgrade)
  1583. _ppbUpgrade->Release();
  1584. if (_ppbInherit)
  1585. _ppbInherit->Release();
  1586. if (_ppbUserDefaults)
  1587. _ppbUserDefaults->Release();
  1588. if (_ppbFolderDefaults)
  1589. _ppbFolderDefaults->Release();
  1590. if (_ppbGlobalDefaults)
  1591. _ppbGlobalDefaults->Release();
  1592. if (_ppbRead)
  1593. _ppbRead->Release();
  1594. if (_ppbWrite)
  1595. _ppbWrite->Release();
  1596. }
  1597. HKEY CViewStatePropertyBag::_GetHKey(DWORD dwFlags)
  1598. {
  1599. HKEY hkRet;
  1600. if ((dwFlags & SHGVSPB_PERUSER) || (dwFlags & SHGVSPB_INHERIT))
  1601. {
  1602. if (!(_dwFlags & SHGVSPB_ROAM) || !(dwFlags & SHGVSPB_PERFOLDER))
  1603. {
  1604. hkRet = SHGetShellKey(SHELLKEY_HKCU_SHELLNOROAM, NULL, TRUE);
  1605. }
  1606. else
  1607. {
  1608. hkRet = SHGetShellKey(SHELLKEY_HKCU_SHELL, NULL, TRUE);
  1609. }
  1610. }
  1611. else
  1612. {
  1613. hkRet = SHGetShellKey(SHELLKEY_HKLM_SHELL, NULL, TRUE);
  1614. }
  1615. return hkRet;
  1616. }
  1617. DWORD CViewStatePropertyBag::_GetMRUSize(HKEY hk)
  1618. {
  1619. DWORD dwMRUSize;
  1620. DWORD dwSize = sizeof(dwMRUSize);
  1621. if (NOERROR != SHGetValueW(hk, NULL, L"BagMRU Size", NULL, &dwMRUSize, &dwSize))
  1622. {
  1623. dwMRUSize = 400; // default size.
  1624. }
  1625. return dwMRUSize;
  1626. }
  1627. HRESULT CViewStatePropertyBag::_GetMRUSlots(LPCITEMIDLIST pidl, DWORD grfMode, HKEY hk, DWORD adwSlots[], DWORD cSlots, DWORD* pdwFetched)
  1628. {
  1629. HRESULT hr;
  1630. IMruPidlList *pmru;
  1631. hr = CoCreateInstance(CLSID_MruPidlList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IMruPidlList, &pmru));
  1632. if (SUCCEEDED(hr))
  1633. {
  1634. hr = pmru->InitList(_GetMRUSize(hk), hk, L"BagMRU");
  1635. if (SUCCEEDED(hr))
  1636. {
  1637. hr = pmru->QueryPidl(pidl, cSlots, adwSlots, pdwFetched);
  1638. if (S_OK == hr || (grfMode & (STGM_WRITE | STGM_READWRITE)))
  1639. {
  1640. hr = pmru->UsePidl(pidl, &adwSlots[0]);
  1641. }
  1642. else if (1 == cSlots) // return S_FALSE for cSlots > 1 if parent slots exist.
  1643. {
  1644. hr = E_FAIL;
  1645. }
  1646. }
  1647. pmru->Release();
  1648. }
  1649. return hr;
  1650. }
  1651. HRESULT CViewStatePropertyBag::_GetMRUSlot(LPCITEMIDLIST pidl, DWORD grfMode, HKEY hk, DWORD* pdwSlot)
  1652. {
  1653. DWORD dwFetched;
  1654. return _GetMRUSlots(pidl, grfMode, hk, pdwSlot, 1, &dwFetched);
  1655. }
  1656. HRESULT CViewStatePropertyBag::_GetRegKey(LPCITEMIDLIST pidl, LPCWSTR pszBagName, DWORD dwFlags, DWORD grfMode, HKEY hk, LPWSTR pszKey, UINT cch)
  1657. {
  1658. HRESULT hr = S_OK;
  1659. if ((dwFlags & SHGVSPB_PERFOLDER) || (dwFlags & SHGVSPB_INHERIT))
  1660. {
  1661. DWORD dwSlot;
  1662. hr = _GetMRUSlot(pidl, grfMode, hk, &dwSlot);
  1663. if (SUCCEEDED(hr))
  1664. {
  1665. if (!(dwFlags & SHGVSPB_INHERIT))
  1666. {
  1667. wnsprintfW(pszKey, cch, L"Bags\\%d\\%s", dwSlot, pszBagName);
  1668. }
  1669. else
  1670. {
  1671. wnsprintfW(pszKey, cch, L"Bags\\%d\\%s\\Inherit", dwSlot, pszBagName);
  1672. }
  1673. }
  1674. }
  1675. else
  1676. {
  1677. wnsprintfW(pszKey, cch, L"Bags\\AllFolders\\%s", pszBagName);
  1678. }
  1679. return hr;
  1680. }
  1681. HRESULT CViewStatePropertyBag::_Init(LPCITEMIDLIST pidl, LPCWSTR pszBagName, DWORD dwFlags)
  1682. {
  1683. HRESULT hr = E_OUTOFMEMORY;
  1684. if (pidl)
  1685. {
  1686. _pidl = ILClone(pidl);
  1687. }
  1688. _pszBagName = StrDupW(pszBagName);
  1689. if (_pszBagName)
  1690. {
  1691. _dwFlags = dwFlags;
  1692. hr = S_OK;
  1693. }
  1694. return hr;
  1695. }
  1696. BOOL CViewStatePropertyBag::_IsSamePidl(LPCITEMIDLIST pidl)
  1697. {
  1698. return (((pidl == NULL) && (_pidl == NULL)) ||
  1699. ((pidl != NULL) && (_pidl != NULL) && ILIsEqual(pidl, _pidl)));
  1700. }
  1701. BOOL CViewStatePropertyBag::_IsSameBag(LPCITEMIDLIST pidl, LPCWSTR pszBagName, DWORD dwFlags)
  1702. {
  1703. return dwFlags == _dwFlags && 0 == StrCmpW(pszBagName, _pszBagName) && _IsSamePidl(pidl);
  1704. }
  1705. HRESULT CViewStatePropertyBag::_CreateBag(LPCITEMIDLIST pidl, LPCWSTR pszBagName, DWORD dwFlags, DWORD grfMode, REFIID riid, void** ppv)
  1706. {
  1707. HRESULT hr;
  1708. DWORD grfMode2 = grfMode | ((grfMode & (STGM_WRITE | STGM_READWRITE)) ? STGM_CREATE : 0);
  1709. if (!(dwFlags & SHGVSPB_ALLUSERS) || !(dwFlags & SHGVSPB_PERFOLDER))
  1710. {
  1711. HKEY hk = _GetHKey(dwFlags);
  1712. if (hk)
  1713. {
  1714. WCHAR szRegSubKey[64];
  1715. hr = _GetRegKey(pidl, pszBagName, dwFlags, grfMode2, hk, szRegSubKey, ARRAYSIZE(szRegSubKey));
  1716. if (SUCCEEDED(hr))
  1717. {
  1718. hr = SHCreatePropertyBagOnRegKey(hk, szRegSubKey, grfMode2, riid, ppv);
  1719. }
  1720. RegCloseKey(hk);
  1721. }
  1722. else
  1723. {
  1724. hr = E_FAIL;
  1725. }
  1726. }
  1727. else
  1728. {
  1729. IBindCtx* pbctx;
  1730. hr = BindCtx_CreateWithMode(grfMode2, &pbctx);
  1731. if (SUCCEEDED(hr))
  1732. {
  1733. // can't use - causes link problems.
  1734. // hr = SHBindToObjectEx(NULL, _pidl, pbctx, riid, ppv);
  1735. IShellFolder* psf;
  1736. hr = SHGetDesktopFolder(&psf);
  1737. if (SUCCEEDED(hr))
  1738. {
  1739. hr = psf->BindToObject(_pidl, pbctx, riid, ppv);
  1740. if (SUCCEEDED(hr) && NULL == *ppv)
  1741. hr = E_FAIL;
  1742. psf->Release();
  1743. }
  1744. pbctx->Release();
  1745. }
  1746. }
  1747. return hr;
  1748. }
  1749. HRESULT CViewStatePropertyBag::_CreateUpgradeBag(REFIID riid, void** ppv)
  1750. {
  1751. return SHGetDesktopUpgradePropertyBag(riid, ppv);
  1752. }
  1753. BOOL CViewStatePropertyBag::_CanAccessPidlBag()
  1754. {
  1755. return (_dwFlags & SHGVSPB_PERUSER) && (_dwFlags & SHGVSPB_PERFOLDER);
  1756. }
  1757. BOOL CViewStatePropertyBag::_EnsurePidlBag(DWORD grfMode, REFIID riid)
  1758. {
  1759. if (!_ppbPidl && !_fTriedPidlBag && _CanAccessPidlBag())
  1760. {
  1761. _fTriedPidlBag = TRUE;
  1762. _CreateBag(_pidl, _pszBagName, (SHGVSPB_PERUSER | SHGVSPB_PERFOLDER), grfMode, riid, (void**)&_ppbPidl);
  1763. }
  1764. return NULL != _ppbPidl;
  1765. }
  1766. HRESULT CViewStatePropertyBag::_ReadPidlBag(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
  1767. {
  1768. HRESULT hr;
  1769. if (_EnsurePidlBag(STGM_READ, IID_IPropertyBag))
  1770. {
  1771. hr = _ppbPidl->Read(pszPropName, pVar, pErrorLog);
  1772. }
  1773. else
  1774. {
  1775. hr = E_FAIL;
  1776. }
  1777. return hr;
  1778. }
  1779. BOOL CViewStatePropertyBag::_CanAccessUpgradeBag()
  1780. {
  1781. // only upgrade desktop for now.
  1782. return 0 == StrCmpW(_pszBagName, VS_BAGSTR_DESKTOP);
  1783. }
  1784. BOOL CViewStatePropertyBag::_EnsureUpgradeBag(DWORD grfMode, REFIID riid)
  1785. {
  1786. if (!_ppbUpgrade && !_fTriedUpgradeBag && _CanAccessUpgradeBag())
  1787. {
  1788. _fTriedUpgradeBag = TRUE;
  1789. _CreateUpgradeBag(riid, (void**)&_ppbUpgrade);
  1790. }
  1791. return NULL != _ppbUpgrade;
  1792. }
  1793. HRESULT CViewStatePropertyBag::_ReadUpgradeBag(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
  1794. {
  1795. HRESULT hr;
  1796. if (_EnsureUpgradeBag(STGM_READ, IID_IPropertyBag))
  1797. {
  1798. hr = _ppbUpgrade->Read(pszPropName, pVar, pErrorLog);
  1799. }
  1800. else
  1801. {
  1802. hr = E_FAIL;
  1803. }
  1804. return hr;
  1805. }
  1806. HRESULT CViewStatePropertyBag::_FindNearestInheritBag(REFIID riid, void** ppv)
  1807. {
  1808. HRESULT hr = E_FAIL;
  1809. *ppv = NULL;
  1810. HKEY hk = _GetHKey(SHGVSPB_INHERIT);
  1811. if (hk)
  1812. {
  1813. DWORD aParentSlots[64];
  1814. DWORD dwFetched;
  1815. if (SUCCEEDED(_GetMRUSlots(_pidl, STGM_READ, hk, aParentSlots, ARRAYSIZE(aParentSlots), &dwFetched)))
  1816. {
  1817. for (DWORD i = 0; i < dwFetched && FAILED(hr); i++)
  1818. {
  1819. WCHAR szRegSubKey[64];
  1820. wnsprintfW(szRegSubKey, ARRAYSIZE(szRegSubKey), L"Bags\\%d\\%s\\Inherit", aParentSlots[i], _pszBagName);
  1821. hr = SHCreatePropertyBagOnRegKey(hk, szRegSubKey, STGM_READ, riid, ppv);
  1822. }
  1823. }
  1824. RegCloseKey(hk);
  1825. }
  1826. return hr;
  1827. }
  1828. BOOL CViewStatePropertyBag::_CanAccessInheritBag()
  1829. {
  1830. return _CanAccessPidlBag() || (_dwFlags & SHGVSPB_INHERIT);
  1831. }
  1832. BOOL CViewStatePropertyBag::_EnsureInheritBag(DWORD grfMode, REFIID riid)
  1833. {
  1834. if (!_ppbInherit && !_fTriedInheritBag && _CanAccessInheritBag())
  1835. {
  1836. _fTriedInheritBag = TRUE;
  1837. _FindNearestInheritBag(riid, (void**)&_ppbInherit);
  1838. }
  1839. return NULL != _ppbInherit;
  1840. }
  1841. HRESULT CViewStatePropertyBag::_ReadInheritBag(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
  1842. {
  1843. HRESULT hr;
  1844. if (_EnsureInheritBag(STGM_READ, IID_IPropertyBag))
  1845. {
  1846. hr = _ppbInherit->Read(pszPropName, pVar, pErrorLog);
  1847. }
  1848. else
  1849. {
  1850. hr = E_FAIL;
  1851. }
  1852. return hr;
  1853. }
  1854. BOOL CViewStatePropertyBag::_CanAccessUserDefaultsBag()
  1855. {
  1856. return _CanAccessPidlBag() || ((_dwFlags & SHGVSPB_PERUSER) && (_dwFlags & SHGVSPB_ALLFOLDERS));
  1857. }
  1858. BOOL CViewStatePropertyBag::_EnsureUserDefaultsBag(DWORD grfMode, REFIID riid)
  1859. {
  1860. if (!_ppbUserDefaults && !_fTriedUserDefaultsBag && _CanAccessUserDefaultsBag())
  1861. {
  1862. _fTriedUserDefaultsBag = TRUE;
  1863. _CreateBag(NULL, _pszBagName, SHGVSPB_PERUSER | SHGVSPB_ALLFOLDERS, grfMode, riid, (void**)&_ppbUserDefaults);
  1864. }
  1865. return NULL != _ppbUserDefaults;
  1866. }
  1867. HRESULT CViewStatePropertyBag::_ReadUserDefaultsBag(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
  1868. {
  1869. HRESULT hr;
  1870. if (_EnsureUserDefaultsBag(STGM_READ, IID_IPropertyBag))
  1871. {
  1872. hr = _ppbUserDefaults->Read(pszPropName, pVar, pErrorLog);
  1873. }
  1874. else
  1875. {
  1876. hr = E_FAIL;
  1877. }
  1878. return hr;
  1879. }
  1880. BOOL CViewStatePropertyBag::_CanAccessFolderDefaultsBag()
  1881. {
  1882. return _CanAccessUserDefaultsBag() || ((_dwFlags & SHGVSPB_ALLUSERS) && (_dwFlags & SHGVSPB_PERFOLDER));
  1883. }
  1884. BOOL CViewStatePropertyBag::_IsSystemFolder()
  1885. {
  1886. BOOL fRet = FALSE;
  1887. LPCITEMIDLIST pidlLast;
  1888. IShellFolder* psf;
  1889. if (SUCCEEDED(SHBindToParent(_pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast)))
  1890. {
  1891. WIN32_FIND_DATAW fd;
  1892. if (SUCCEEDED(SHGetDataFromIDListW(psf, pidlLast, SHGDFIL_FINDDATA, &fd, sizeof(fd))))
  1893. {
  1894. fRet = PathIsSystemFolder(NULL, fd.dwFileAttributes);
  1895. }
  1896. psf->Release();
  1897. }
  1898. return fRet;
  1899. }
  1900. BOOL CViewStatePropertyBag::_EnsureFolderDefaultsBag(DWORD grfMode, REFIID riid)
  1901. {
  1902. if (!_ppbFolderDefaults && !_fTriedFolderDefaultsBag && _CanAccessFolderDefaultsBag())
  1903. {
  1904. _fTriedFolderDefaultsBag = TRUE;
  1905. // PERF: Use the desktop.ini only if the folder is a system folder.
  1906. if (_IsSystemFolder())
  1907. {
  1908. _CreateBag(_pidl, _pszBagName, SHGVSPB_ALLUSERS | SHGVSPB_PERFOLDER, grfMode, riid, (void**)&_ppbFolderDefaults);
  1909. }
  1910. }
  1911. return NULL != _ppbFolderDefaults;
  1912. }
  1913. HRESULT CViewStatePropertyBag::_ReadFolderDefaultsBag(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
  1914. {
  1915. HRESULT hr;
  1916. if (_EnsureFolderDefaultsBag(STGM_READ, IID_IPropertyBag))
  1917. {
  1918. hr = _ppbFolderDefaults->Read(pszPropName, pVar, pErrorLog);
  1919. }
  1920. else
  1921. {
  1922. hr = E_FAIL;
  1923. }
  1924. return hr;
  1925. }
  1926. BOOL CViewStatePropertyBag::_CanAccessGlobalDefaultsBag()
  1927. {
  1928. return _CanAccessFolderDefaultsBag() || ((_dwFlags & SHGVSPB_ALLUSERS) && (_dwFlags & SHGVSPB_ALLFOLDERS));
  1929. }
  1930. BOOL CViewStatePropertyBag::_EnsureGlobalDefaultsBag(DWORD grfMode, REFIID riid)
  1931. {
  1932. if (!_ppbGlobalDefaults && !_fTriedGlobalDefaultsBag && _CanAccessGlobalDefaultsBag())
  1933. {
  1934. _fTriedGlobalDefaultsBag = TRUE;
  1935. _CreateBag(NULL, _pszBagName, SHGVSPB_ALLUSERS | SHGVSPB_ALLFOLDERS, grfMode, riid, (void**)&_ppbGlobalDefaults);
  1936. }
  1937. return NULL != _ppbGlobalDefaults;
  1938. }
  1939. HRESULT CViewStatePropertyBag::_ReadGlobalDefaultsBag(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
  1940. {
  1941. HRESULT hr;
  1942. if (_EnsureGlobalDefaultsBag(STGM_READ, IID_IPropertyBag))
  1943. {
  1944. hr = _ppbGlobalDefaults->Read(pszPropName, pVar, pErrorLog);
  1945. }
  1946. else
  1947. {
  1948. hr = E_FAIL;
  1949. }
  1950. return hr;
  1951. }
  1952. BOOL CViewStatePropertyBag::_EnsureReadBag(DWORD grfMode, REFIID riid)
  1953. {
  1954. if (!_ppbRead && !_fTriedReadBag)
  1955. {
  1956. _fTriedReadBag = TRUE;
  1957. _CreateBag(_pidl, _pszBagName, _dwFlags, grfMode, riid, (void**)&_ppbRead);
  1958. }
  1959. return NULL != _ppbRead;
  1960. }
  1961. HRESULT CViewStatePropertyBag::Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
  1962. {
  1963. HRESULT hr;
  1964. if ((_dwFlags & SHGVSPB_NOAUTODEFAULTS) || (_dwFlags & SHGVSPB_INHERIT))
  1965. {
  1966. if (_EnsureReadBag(STGM_READ, IID_IPropertyBag))
  1967. {
  1968. hr = _ppbRead->Read(pszPropName, pVar, pErrorLog);
  1969. }
  1970. else
  1971. {
  1972. hr = E_FAIL;
  1973. }
  1974. }
  1975. else
  1976. {
  1977. hr = _ReadPidlBag(pszPropName, pVar, pErrorLog); // per user per folder
  1978. if (FAILED(hr))
  1979. {
  1980. hr = _ReadInheritBag(pszPropName, pVar, pErrorLog);
  1981. if (FAILED(hr))
  1982. {
  1983. hr = _ReadUpgradeBag(pszPropName, pVar, pErrorLog); // (legacy per user per folder)
  1984. if (FAILED(hr))
  1985. {
  1986. hr = _ReadUserDefaultsBag(pszPropName, pVar, pErrorLog); // per user all folders
  1987. if (FAILED(hr))
  1988. {
  1989. hr = _ReadFolderDefaultsBag(pszPropName, pVar, pErrorLog); // per folder all users
  1990. if (FAILED(hr))
  1991. {
  1992. hr = _ReadGlobalDefaultsBag(pszPropName, pVar, pErrorLog); // all folders all users
  1993. }
  1994. }
  1995. }
  1996. }
  1997. }
  1998. }
  1999. return hr;
  2000. }
  2001. void CViewStatePropertyBag::_PruneMRUTree()
  2002. {
  2003. HKEY hk = _GetHKey(SHGVSPB_INHERIT);
  2004. if (hk)
  2005. {
  2006. IMruPidlList *pmru;
  2007. HRESULT hr = CoCreateInstance(CLSID_MruPidlList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IMruPidlList, &pmru));
  2008. if (SUCCEEDED(hr))
  2009. {
  2010. hr = pmru->InitList(200, hk, L"BagMRU");
  2011. if (SUCCEEDED(hr))
  2012. {
  2013. pmru->PruneKids(_pidl);
  2014. }
  2015. pmru->Release();
  2016. }
  2017. RegCloseKey(hk);
  2018. }
  2019. }
  2020. void CViewStatePropertyBag::_ResetTryAgainFlag()
  2021. {
  2022. if (_dwFlags & SHGVSPB_NOAUTODEFAULTS)
  2023. {
  2024. _fTriedReadBag = FALSE;
  2025. }
  2026. else
  2027. {
  2028. if ((_dwFlags & SHGVSPB_PERUSER) && (_dwFlags & SHGVSPB_PERFOLDER))
  2029. {
  2030. _fTriedPidlBag = FALSE;
  2031. }
  2032. else if (_dwFlags & SHGVSPB_INHERIT)
  2033. {
  2034. _fTriedInheritBag = FALSE;
  2035. }
  2036. else if ((_dwFlags & SHGVSPB_PERUSER) && (_dwFlags & SHGVSPB_ALLFOLDERS))
  2037. {
  2038. _fTriedUserDefaultsBag = FALSE;
  2039. }
  2040. else if ((_dwFlags & SHGVSPB_ALLUSERS) && (_dwFlags & SHGVSPB_PERFOLDER))
  2041. {
  2042. _fTriedFolderDefaultsBag = FALSE;
  2043. }
  2044. else if ((_dwFlags & SHGVSPB_ALLUSERS) && (_dwFlags & SHGVSPB_ALLFOLDERS))
  2045. {
  2046. _fTriedGlobalDefaultsBag = FALSE;
  2047. }
  2048. }
  2049. }
  2050. BOOL CViewStatePropertyBag::_EnsureWriteBag(DWORD grfMode, REFIID riid)
  2051. {
  2052. if (!_ppbWrite && !_fTriedWriteBag)
  2053. {
  2054. _fTriedWriteBag = TRUE;
  2055. _CreateBag(_pidl, _pszBagName, _dwFlags, grfMode, riid, (void**)&_ppbWrite);
  2056. if (_ppbWrite)
  2057. {
  2058. _ResetTryAgainFlag();
  2059. if (SHGVSPB_INHERIT & _dwFlags)
  2060. {
  2061. _PruneMRUTree();
  2062. }
  2063. }
  2064. }
  2065. return NULL != _ppbWrite;
  2066. }
  2067. HRESULT CViewStatePropertyBag::Write(LPCOLESTR pszPropName, VARIANT *pVar)
  2068. {
  2069. HRESULT hr;
  2070. if (_EnsureWriteBag(STGM_WRITE, IID_IPropertyBag))
  2071. {
  2072. hr = _ppbWrite->Write(pszPropName, pVar);
  2073. }
  2074. else
  2075. {
  2076. hr = E_FAIL;
  2077. }
  2078. return hr;
  2079. }
  2080. #ifdef DEBUG
  2081. void IS_VALID_SHGVSPB_PARAMS(LPCITEMIDLIST pidl, LPCWSTR pszBagName, DWORD dwFlags, REFIID riid, void** ppv)
  2082. {
  2083. RIP((NULL == pidl && (dwFlags & SHGVSPB_ALLFOLDERS)) || (IsValidPIDL(pidl) && ((SHGVSPB_PERFOLDER & dwFlags) || (SHGVSPB_INHERIT & dwFlags))));
  2084. RIP(pszBagName);
  2085. RIP(SHGVSPB_PERUSER == (dwFlags & (SHGVSPB_PERUSER | SHGVSPB_ALLUSERS | SHGVSPB_INHERIT)) || SHGVSPB_ALLUSERS == (dwFlags & (SHGVSPB_PERUSER | SHGVSPB_ALLUSERS | SHGVSPB_INHERIT)) || SHGVSPB_INHERIT == (dwFlags & (SHGVSPB_PERUSER | SHGVSPB_ALLUSERS | SHGVSPB_INHERIT)));
  2086. RIP(SHGVSPB_PERFOLDER == (dwFlags & (SHGVSPB_PERFOLDER | SHGVSPB_ALLFOLDERS | SHGVSPB_INHERIT)) || SHGVSPB_ALLFOLDERS == (dwFlags & (SHGVSPB_PERFOLDER | SHGVSPB_ALLFOLDERS | SHGVSPB_INHERIT)) || SHGVSPB_INHERIT == (dwFlags & (SHGVSPB_PERFOLDER | SHGVSPB_ALLFOLDERS | SHGVSPB_INHERIT)));
  2087. RIP(riid == IID_IPropertyBag || riid == IID_IUnknown);
  2088. RIP(NULL != ppv);
  2089. }
  2090. #else
  2091. #define IS_VALID_SHGVSPB_PARAMS(a, b, c, d, e)
  2092. #endif
  2093. // Cache the last bag accessed.
  2094. CViewStatePropertyBag* g_pCachedBag = NULL;
  2095. EXTERN_C void FreeViewStatePropertyBagCache()
  2096. {
  2097. ENTERCRITICAL;
  2098. {
  2099. if (g_pCachedBag)
  2100. {
  2101. g_pCachedBag->Release();
  2102. g_pCachedBag = NULL;
  2103. }
  2104. }
  2105. LEAVECRITICAL;
  2106. }
  2107. BOOL SHIsRemovableDrive(LPCITEMIDLIST pidl)
  2108. {
  2109. BOOL fRet = FALSE;
  2110. LPCITEMIDLIST pidlLast;
  2111. IShellFolder* psf;
  2112. if (SUCCEEDED(SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast)))
  2113. {
  2114. STRRET str;
  2115. if (SUCCEEDED(psf->GetDisplayNameOf(pidlLast, SHGDN_FORPARSING, &str)))
  2116. {
  2117. WCHAR szPath[MAX_PATH];
  2118. if (SUCCEEDED(StrRetToBufW(&str, pidlLast, szPath, ARRAYSIZE(szPath))))
  2119. {
  2120. int iDrive = PathGetDriveNumberW(szPath);
  2121. if (iDrive != -1)
  2122. {
  2123. int iDriveType = RealDriveType(iDrive, FALSE);
  2124. fRet = (DRIVE_REMOVABLE == iDriveType || DRIVE_CDROM == iDriveType);
  2125. }
  2126. }
  2127. }
  2128. psf->Release();
  2129. }
  2130. return fRet;
  2131. }
  2132. STDAPI SHGetViewStatePropertyBag(LPCITEMIDLIST pidl, LPCWSTR pszBagName, DWORD dwFlags, REFIID riid, void** ppv)
  2133. {
  2134. IS_VALID_SHGVSPB_PARAMS(pidl, pszBagName, dwFlags, riid, ppv);
  2135. HRESULT hr;
  2136. *ppv = NULL;
  2137. ENTERCRITICAL;
  2138. {
  2139. if (g_pCachedBag && g_pCachedBag->_IsSameBag(pidl, pszBagName, dwFlags))
  2140. {
  2141. hr = S_OK;
  2142. }
  2143. else
  2144. {
  2145. if (!SHIsRemovableDrive(pidl))
  2146. {
  2147. CViewStatePropertyBag* pBag = new CViewStatePropertyBag();
  2148. if (pBag)
  2149. {
  2150. hr = pBag->_Init(pidl, pszBagName, dwFlags);
  2151. if (SUCCEEDED(hr))
  2152. {
  2153. if (g_pCachedBag)
  2154. g_pCachedBag->Release();
  2155. g_pCachedBag = pBag;
  2156. }
  2157. else
  2158. {
  2159. pBag->Release();
  2160. }
  2161. }
  2162. else
  2163. {
  2164. hr = E_OUTOFMEMORY;
  2165. }
  2166. }
  2167. else
  2168. {
  2169. hr = E_FAIL; // don't save property bags for removable drives.
  2170. }
  2171. }
  2172. if (SUCCEEDED(hr))
  2173. {
  2174. hr = g_pCachedBag->QueryInterface(riid, ppv);
  2175. }
  2176. }
  2177. LEAVECRITICAL;
  2178. return hr;
  2179. }
  2180. ULONG SHGetPerScreenResName(WCHAR* pszRes, ULONG cch, DWORD dwVersion)
  2181. {
  2182. RIPMSG(IS_VALID_WRITE_BUFFER(pszRes, *pszRes, cch), "SHGetPerScreenResName caller passed bad pszRes or cch");
  2183. ULONG uRet;
  2184. if (0 == dwVersion)
  2185. {
  2186. HDC hdc = GetDC(NULL);
  2187. int x = GetDeviceCaps(hdc, HORZRES);
  2188. int y = GetDeviceCaps(hdc, VERTRES);
  2189. ReleaseDC(NULL, hdc);
  2190. int n = GetSystemMetrics(SM_CMONITORS);
  2191. int cchLen = wnsprintfW(pszRes, cch, L"%dx%d(%d)", x, y, n);
  2192. uRet = (cchLen > 0) ? cchLen : 0;
  2193. }
  2194. else
  2195. {
  2196. uRet = 0;
  2197. }
  2198. return uRet;
  2199. }