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

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