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.

678 lines
21 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // CreateRegBag.cpp : Implementation of CCreateRegBag
  4. // Copyright (c) Microsoft Corporation 1999.
  5. //
  6. // some code copied from DShow device moniker devmon.cpp
  7. //
  8. #include "stdafx.h"
  9. #include "Regbag.h"
  10. #include "CreateRegBag.h"
  11. DEFINE_EXTERN_OBJECT_ENTRY(CLSID_CreatePropBagOnRegKey, CCreateRegBag)
  12. // REV2: support for more data types
  13. // REG_MULTI_SZ could be supported via VT_BSTR | VT_ARRAY
  14. // REG_BINARY blobs could be vt_unknown that's an istream
  15. // subkeys could be vt_unknown that's an IPropertyBag2 if default val isn't clsid
  16. //
  17. /////////////////////////////////////////////////////////////////////////////
  18. // CCreateRegBag
  19. HRESULT CRegBagBase::DeleteSubKey(CRegKey& hk, LPCOLESTR pszPropName) {
  20. // the registry will allow a peer subkey and value to have the same name
  21. // this doesn't match property bag semantics. so we force this to never occur.
  22. // after we write a primitive value then we check for a subkey of the
  23. // same name and recursively delete it if it exists. from the property bag
  24. // perspective this amounts to changing the type of the property by writing
  25. // a new type to the same name.
  26. // however, if pszpropname is empty(the default value) the current key will
  27. // get deleted which we don't want
  28. ASSERT(hk.m_hKey != NULL && pszPropName);
  29. if (!wcslen(pszPropName)) {
  30. return NOERROR;
  31. }
  32. USES_CONVERSION;
  33. DWORD hr = hk.RecurseDeleteKey(OLE2CT(pszPropName));
  34. switch (hr) {
  35. case ERROR_BADKEY:
  36. case ERROR_CANTOPEN:
  37. case ERROR_KEY_DELETED:
  38. case ERROR_FILE_NOT_FOUND:
  39. return S_FALSE;
  40. default:
  41. return HRESULT_FROM_WIN32(hr);
  42. }
  43. }
  44. HRESULT CRegBagBase::DeleteValue(CRegKey& hk, LPCOLESTR pszPropName) {
  45. ASSERT(hk.m_hKey && pszPropName);
  46. // this is the inverse of delete duplicate key name
  47. USES_CONVERSION;
  48. DWORD hr = hk.DeleteValue(OLE2CT(pszPropName));
  49. switch (hr) {
  50. case ERROR_FILE_NOT_FOUND:
  51. #if 0
  52. ??? what else does reg return for missing value
  53. case ??? missing value
  54. #endif
  55. return S_FALSE;
  56. default:
  57. return HRESULT_FROM_WIN32(hr);
  58. }
  59. }
  60. HRESULT CRegBagBase::RegConvertToVARIANT(VARIANT *pVar, DWORD dwType, LPBYTE pbData, DWORD cbSize) {
  61. ASSERT(pVar && pbData);
  62. USES_CONVERSION;
  63. switch (dwType) {
  64. case REG_DWORD:
  65. if (pVar->vt != VT_UI4) {
  66. HRESULT hr = VariantChangeType(pVar, pVar, 0, VT_UI4);
  67. if (FAILED(hr)) {
  68. return E_INVALIDARG;
  69. }
  70. }
  71. ASSERT(pVar->vt == VT_UI4);
  72. ASSERT(pbData);
  73. pVar->ulVal = *(reinterpret_cast<ULONG *>(pbData));
  74. break;
  75. case REG_QWORD:
  76. if (pVar->vt != VT_UI8) {
  77. HRESULT hr = VariantChangeType(pVar, pVar, 0, VT_UI8);
  78. if (FAILED(hr)) {
  79. return E_INVALIDARG;
  80. }
  81. }
  82. ASSERT(pVar->vt == VT_UI8);
  83. ASSERT(pbData);
  84. pVar->ullVal = *(reinterpret_cast<ULONGLONG *>(pbData));
  85. break;
  86. case REG_SZ:
  87. switch(pVar->vt) {
  88. case VT_EMPTY:
  89. case VT_NULL:
  90. pVar->vt = VT_BSTR;
  91. pVar->bstrVal = NULL;
  92. break;
  93. case VT_BSTR:
  94. break;
  95. default:
  96. HRESULT hr = VariantChangeType(pVar, pVar, 0, VT_BSTR);
  97. if (FAILED(hr)) {
  98. return E_INVALIDARG;
  99. }
  100. }
  101. ASSERT(pVar->vt == VT_BSTR);
  102. if (pVar->bstrVal) {
  103. ::SysFreeString(pVar->bstrVal);
  104. }
  105. if (cbSize) {
  106. ASSERT(pbData);
  107. pVar->bstrVal = ::SysAllocString(T2OLE(LPTSTR(pbData)));
  108. } else {
  109. pVar->bstrVal = NULL; // empty string
  110. }
  111. break;
  112. case REG_MULTI_SZ:
  113. switch(pVar->vt) {
  114. case VT_EMPTY:
  115. case VT_NULL:
  116. pVar->vt = VT_BSTR_BLOB;
  117. break;
  118. case VT_VECTOR | VT_BSTR:
  119. case VT_BSTR:
  120. if (pVar->bstrVal) {
  121. ::SysFreeString(pVar->bstrVal);
  122. }
  123. pVar->vt = VT_BSTR_BLOB;
  124. break;
  125. default:
  126. pVar->vt = VT_BSTR_BLOB;
  127. }
  128. if (cbSize) {
  129. pVar->bstrVal = ::SysAllocStringByteLen(NULL, cbSize);
  130. if (!pVar->bstrVal) {
  131. return E_OUTOFMEMORY;
  132. }
  133. if (pbData) {
  134. memcpy(pVar->bstrVal, pbData, cbSize);
  135. }
  136. }
  137. break;
  138. default: // binary
  139. switch (pVar->vt) {
  140. case VT_BSTR_BLOB:
  141. case VT_BSTR:
  142. if (pVar->bstrVal) {
  143. ::SysFreeString(pVar->bstrVal);
  144. }
  145. pVar->bstrVal = ::SysAllocStringByteLen(NULL, cbSize);
  146. if (!pVar->bstrVal) {
  147. return E_OUTOFMEMORY;
  148. }
  149. if (pbData) {
  150. memcpy(pVar->bstrVal, pbData, cbSize);
  151. }
  152. break;
  153. default:
  154. if (pVar->vt != (VT_UI1 | VT_ARRAY)) {
  155. HRESULT hr = VariantChangeType(pVar, pVar, 0, VT_UI1 | VT_ARRAY);
  156. if (FAILED(hr)) {
  157. return E_INVALIDARG;
  158. }
  159. }
  160. ASSERT(pVar->vt == (VT_UI1 | VT_ARRAY));
  161. SAFEARRAY * psa = NULL;
  162. if (cbSize) {
  163. ASSERT(pbData);
  164. SAFEARRAYBOUND rgsabound[1];
  165. rgsabound[0].lLbound = 0;
  166. rgsabound[0].cElements = cbSize;
  167. psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
  168. if(!psa) {
  169. return E_OUTOFMEMORY;
  170. }
  171. BYTE *pbArray;
  172. HRESULT hr = SafeArrayAccessData(psa, reinterpret_cast<LPVOID *>(&pbArray));
  173. if (hr != S_OK) {
  174. return E_FAIL;
  175. }
  176. memcpy(pbArray, pbData, cbSize);
  177. hr = SafeArrayUnaccessData(psa);
  178. if (hr != S_OK) {
  179. return E_FAIL;
  180. }
  181. }
  182. pVar->parray = psa;
  183. }
  184. }
  185. return NOERROR;
  186. }
  187. HRESULT CRegBagBase::SaveObject(CRegKey& hk, LPCOLESTR pszPropName, VARIANT* pV) {
  188. ASSERT(hk.m_hKey && pszPropName && pV);
  189. if (pV->vt != VT_UNKNOWN) {
  190. return E_UNEXPECTED;
  191. }
  192. HRESULT hr = NOERROR;
  193. USES_CONVERSION;
  194. if (!pV->punkVal) {
  195. hk.DeleteValue(OLE2CT(pszPropName));
  196. hk.RecurseDeleteKey(OLE2CT(pszPropName));
  197. } else {
  198. PQPersistPropertyBag2 p2(pV->punkVal);
  199. if (p2) {
  200. CRegKey sk;
  201. DWORD rc = sk.Create(m_hk, OLE2CT(pszPropName), NULL, 0, KEY_READ | KEY_WRITE, NULL, NULL);
  202. if (rc != ERROR_SUCCESS) {
  203. return HRESULT_FROM_WIN32(rc);
  204. }
  205. CLSID cl;
  206. hr = p2->GetClassID(&cl);
  207. if (FAILED(hr)) {
  208. return E_UNEXPECTED;
  209. }
  210. OLECHAR szClsid[64];
  211. rc = StringFromGUID2(cl, szClsid, sizeof(szClsid)/sizeof(OLECHAR));
  212. if (!rc) {
  213. return E_UNEXPECTED;
  214. }
  215. rc = RegSetValue(sk, NULL, REG_SZ, OLE2T(szClsid), _tcslen(OLE2T(szClsid)) * sizeof(TCHAR));
  216. if (rc != ERROR_SUCCESS) {
  217. return HRESULT_FROM_WIN32(rc);
  218. }
  219. try {
  220. PQPropertyBag2 pBag2(new CRegBag(sk, NULL, 0, KEY_READ | KEY_WRITE));
  221. if (pBag2) {
  222. hr = p2->Save(pBag2, false, true);
  223. } else {
  224. hr = E_OUTOFMEMORY;
  225. }
  226. } CATCHCOM();
  227. } else {
  228. PQPersistPropertyBag p(pV->punkVal);
  229. if (p) {
  230. CRegKey sk;
  231. DWORD rc = sk.Create(m_hk, OLE2CT(pszPropName), NULL, 0, KEY_READ | KEY_WRITE, NULL, NULL);
  232. if (rc != ERROR_SUCCESS) {
  233. return HRESULT_FROM_WIN32(rc);
  234. }
  235. CLSID cl;
  236. hr = p->GetClassID(&cl);
  237. if (FAILED(hr)) {
  238. return E_UNEXPECTED;
  239. }
  240. OLECHAR szClsid[64];
  241. rc = StringFromGUID2(cl, szClsid, sizeof(szClsid)/sizeof(OLECHAR));
  242. if (!rc) {
  243. return E_UNEXPECTED;
  244. }
  245. rc = RegSetValue(sk, NULL, REG_SZ, OLE2T(szClsid), _tcslen(OLE2T(szClsid)) * sizeof(TCHAR));
  246. if (rc != ERROR_SUCCESS) {
  247. return HRESULT_FROM_WIN32(rc);
  248. }
  249. try {
  250. PQPropertyBag pBag(new CRegBag(sk, NULL, 0, KEY_READ | KEY_WRITE));
  251. if (pBag) {
  252. hr = p->Save(pBag, false, true);
  253. } else {
  254. hr = E_OUTOFMEMORY;
  255. }
  256. } CATCHCOM();
  257. }
  258. }
  259. // rev2: support other persistence interfaces, esp stream via shopenregstream()
  260. }
  261. return hr;
  262. }
  263. // IPropertyBag
  264. STDMETHODIMP CRegBagBase::Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog) {
  265. if (!pszPropName || !pVar) {
  266. return E_POINTER;
  267. }
  268. ATL_LOCK();
  269. DWORD dwType, cbSize = 64;
  270. BYTE data[64];
  271. LPBYTE pbData = data;
  272. USES_CONVERSION;
  273. HRESULT hr = RegQueryValueEx(m_hk, OLE2CT(pszPropName), NULL, &dwType, pbData, &cbSize);
  274. if (hr == ERROR_SUCCESS) {
  275. return RegConvertToVARIANT(pVar, dwType, pbData, cbSize);
  276. } else if (hr == ERROR_MORE_DATA) {
  277. cbSize += sizeof(TCHAR);
  278. pbData = new BYTE[cbSize];
  279. hr = RegQueryValueEx(m_hk, OLE2CT(pszPropName), NULL, &dwType, pbData, &cbSize);
  280. if (hr == ERROR_SUCCESS) {
  281. hr = RegConvertToVARIANT(pVar, dwType, pbData, cbSize);
  282. delete[] pbData;
  283. return hr;
  284. }
  285. delete[] pbData;
  286. }
  287. // must be a key, so try the object
  288. CRegKey sk;
  289. hr = sk.Open(m_hk, OLE2CT(pszPropName), KEY_READ);
  290. if (hr != ERROR_SUCCESS) {
  291. return HRESULT_FROM_WIN32(hr);
  292. }
  293. TCHAR pszclsid[80 * sizeof(TCHAR)];
  294. LONG dwSize = sizeof(pszclsid);
  295. hr = RegQueryValue(sk, NULL, pszclsid, &dwSize);
  296. if (hr != ERROR_SUCCESS) {
  297. return HRESULT_FROM_WIN32(hr);
  298. }
  299. GUID clsid;
  300. hr = CLSIDFromString(T2OLE(pszclsid), &clsid);
  301. if (FAILED(hr)) {
  302. return E_FAIL;
  303. }
  304. switch (pVar->vt) {
  305. case VT_EMPTY:
  306. case VT_NULL:
  307. //DISPATCH is preferred if object supports it. if not we'll convert back
  308. // to unknown down below.
  309. pVar->vt = VT_DISPATCH;
  310. pVar->pdispVal = NULL;
  311. break;
  312. case VT_DISPATCH:
  313. case VT_UNKNOWN:
  314. break;
  315. default:
  316. hr = VariantChangeType(pVar, pVar, 0, VT_DISPATCH);
  317. if (FAILED(hr)) {
  318. hr = VariantChangeType(pVar, pVar, 0, VT_UNKNOWN);
  319. if (FAILED(hr)) {
  320. return E_INVALIDARG;
  321. }
  322. }
  323. }
  324. PQPersistPropertyBag pPersistObj(((pVar->vt == VT_UNKNOWN) ? pVar->punkVal : pVar->pdispVal));
  325. hr = LoadPersistedObject<PQPropertyBag, PQPersistPropertyBag> (pPersistObj, clsid, pVar, m_hk, pszPropName, pErrorLog);
  326. if (FAILED(hr)) {
  327. PQPersistPropertyBag2 pPersistObj2(((pVar->vt == VT_UNKNOWN) ? pVar->punkVal : pVar->pdispVal));
  328. hr = LoadPersistedObject<PQPropertyBag2, PQPersistPropertyBag2> (pPersistObj2, clsid, pVar, m_hk, pszPropName, pErrorLog);
  329. }
  330. return hr;
  331. }
  332. STDMETHODIMP CRegBagBase::Write(LPCOLESTR pszPropName, VARIANT *pVar) {
  333. if (!pszPropName || !pVar) {
  334. return E_POINTER;
  335. }
  336. ATL_LOCK();
  337. HRESULT hrc;
  338. if (pVar->vt & VT_BYREF) {
  339. hrc = VariantChangeType(pVar, pVar, 0, pVar->vt & ~VT_BYREF);
  340. if (FAILED(hrc)) {
  341. return E_INVALIDARG;
  342. }
  343. }
  344. USES_CONVERSION;
  345. hrc = NOERROR;
  346. switch(pVar->vt) {
  347. case VT_I1: //fall thru
  348. case VT_I2: //fall thru
  349. case VT_I4: //fall thru
  350. case VT_UI1: //fall thru
  351. case VT_UI2: //change type and fall thru
  352. case VT_INT: //change type and fall thru
  353. case VT_UINT: //change type and fall thru
  354. case VT_BOOL: //change type and fall thru
  355. hrc = VariantChangeType(pVar, pVar, 0, VT_UI4);
  356. if (FAILED(hrc)) {
  357. return E_INVALIDARG;
  358. }
  359. case VT_UI4: //REG_DWORD
  360. hrc = RegSetValueEx(
  361. m_hk,
  362. OLE2CT(pszPropName),
  363. 0, // dwReserved
  364. REG_DWORD,
  365. reinterpret_cast<LPBYTE>(&pVar->ulVal),
  366. sizeof(pVar->ulVal));
  367. if (hrc != ERROR_SUCCESS) {
  368. return HRESULT_FROM_WIN32(hrc);
  369. }
  370. // make sure no old object exists
  371. DeleteSubKey(m_hk, pszPropName);
  372. break;
  373. case VT_BSTR: { //REG_SZ
  374. hrc = ERROR_SUCCESS;
  375. LPTSTR val = OLE2T(pVar->bstrVal);
  376. if (val) {
  377. UINT len = ::SysStringByteLen(pVar->bstrVal);
  378. hrc = RegSetValueEx(
  379. m_hk,
  380. OLE2CT(pszPropName),
  381. 0, // dwReserved
  382. REG_SZ,
  383. reinterpret_cast<LPBYTE>(val),
  384. len);
  385. }
  386. if (hrc == ERROR_SUCCESS) {
  387. // make sure no old object exists
  388. DeleteSubKey(m_hk, pszPropName);
  389. }
  390. } break;
  391. #if 0
  392. // we're not actually going to enable this since REG_MULTI_SZ only exists on NT
  393. // if we had REG_MULTI_SZ on 9x then we'd have to loop over the hole block skipping embedded nulls and unicode/ansi convert the
  394. // entire vector of strings
  395. // instead we're just going to treat vectors of bstrs as binary blobs
  396. case VT_VECTOR | VT_BSTR: { //REG_MULTI_SZ
  397. hrc = ERROR_SUCCESS;
  398. LPTSTR val = OLE2T(pVar->bstrVal);
  399. if (val) {
  400. UINT len = ::SysStringByteLen(pVar->bstrVal);
  401. hrc = RegSetValueEx(
  402. m_hk,
  403. OLE2CT(pszPropName),
  404. 0, // dwReserved
  405. REG_MULTI_SZ,
  406. reinterpret_cast<LPBYTE>(val),
  407. len);
  408. }
  409. if (hrc == ERROR_SUCCESS) {
  410. // make sure no old object exists
  411. DeleteSubKey(m_hk, pszPropName);
  412. }
  413. } break;
  414. #else
  415. case VT_VECTOR | VT_BSTR: // fall-thru to array(REG_BINARY)
  416. #endif
  417. case VT_BSTR_BLOB: { //REG_BINARY
  418. SIZE_T len = 0;
  419. LPBYTE pData = reinterpret_cast<LPBYTE>(pVar->bstrVal);
  420. if (pData) {
  421. len = ::SysStringByteLen(pVar->bstrVal);
  422. hrc = RegSetValueEx(
  423. m_hk,
  424. OLE2CT(pszPropName),
  425. 0, // dwReserved
  426. REG_BINARY,
  427. pData,
  428. len);
  429. if (hrc == ERROR_SUCCESS) {
  430. // make sure no old object exists
  431. DeleteSubKey(m_hk, pszPropName);
  432. }
  433. }
  434. } break;
  435. case VT_ARRAY | VT_UI1: { //REG_BINARY
  436. LPBYTE pData = NULL;
  437. SIZE_T len = 0;
  438. if (pVar->parray) {
  439. HRESULT hr = SafeArrayAccessData(pVar->parray, reinterpret_cast<LPVOID *>(&pData));
  440. if (FAILED(hr)) {
  441. return hr;
  442. }
  443. for (int i = pVar->parray->cDims; i--;) {
  444. len += pVar->parray->rgsabound[i].cElements;
  445. }
  446. len *= pVar->parray->cbElements;
  447. hrc = RegSetValueEx(
  448. m_hk,
  449. OLE2CT(pszPropName),
  450. 0, // dwReserved
  451. REG_BINARY,
  452. pData,
  453. len);
  454. if (hrc == ERROR_SUCCESS) {
  455. // make sure no old object exists
  456. DeleteSubKey(m_hk, pszPropName);
  457. }
  458. SafeArrayUnaccessData(pVar->parray);
  459. }
  460. } break;
  461. case VT_I8://change type and fall thru
  462. hrc = VariantChangeType(pVar, pVar, 0, VT_UI8);
  463. if (FAILED(hrc)) {
  464. return E_INVALIDARG;
  465. }
  466. case VT_UI8: //REG_QWORD
  467. hrc = RegSetValueEx(
  468. m_hk,
  469. OLE2CT(pszPropName),
  470. 0, // dwReserved
  471. REG_QWORD,
  472. reinterpret_cast<LPBYTE>(&pVar->ullVal),
  473. sizeof(pVar->ullVal));
  474. if (hrc == ERROR_SUCCESS) {
  475. // make sure no old object exists
  476. DeleteSubKey(m_hk, pszPropName);
  477. }
  478. break;
  479. case VT_DISPATCH:
  480. hrc = VariantChangeType(pVar, pVar, 0, VT_UNKNOWN);
  481. if (FAILED(hrc)) {
  482. return E_UNEXPECTED;
  483. }
  484. case VT_UNKNOWN:
  485. DeleteValue(m_hk, pszPropName);
  486. hrc = SaveObject(m_hk, pszPropName, pVar);
  487. break;
  488. case VT_EMPTY:
  489. case VT_NULL:
  490. // remove from registry
  491. DeleteValue(m_hk, pszPropName);
  492. DeleteSubKey(m_hk, pszPropName);
  493. hrc = NOERROR;
  494. break;
  495. default:
  496. hrc = E_INVALIDARG;
  497. }
  498. return hrc;
  499. }
  500. STDMETHODIMP CRegBag::CountProperties(ULONG * pcProperties) {
  501. if (!pcProperties) {
  502. return E_POINTER;
  503. }
  504. ATL_LOCK();
  505. if (!pcProperties) {
  506. return E_POINTER;
  507. }
  508. DWORD cKeys, cValues;
  509. DWORD rc = RegQueryInfoKey(m_hk,
  510. NULL, NULL, NULL,
  511. &cKeys, NULL, NULL,
  512. &cValues, NULL, NULL,
  513. NULL, NULL);
  514. if (rc != ERROR_SUCCESS) {
  515. return HRESULT_FROM_WIN32(rc);
  516. }
  517. *pcProperties = cKeys + cValues;
  518. return NOERROR;
  519. }
  520. STDMETHODIMP CRegBag::GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG * pcProperties) {
  521. if (!pPropBag || !pcProperties) {
  522. return E_POINTER;
  523. }
  524. ATL_LOCK();
  525. memset(pPropBag, 0, sizeof(*pPropBag) * cProperties);
  526. // NOTE: since the registry functions don't provide a unified enumeration
  527. // of subkeys and values, we're just going to establish values as coming
  528. // before subkeys by definition.
  529. DWORD cKeys, cValues, cbMaxKeyName, cbMaxValueName, cbMaxValue;
  530. DWORD rc = RegQueryInfoKey(m_hk,
  531. NULL, NULL, NULL,
  532. &cKeys, &cbMaxKeyName, NULL,
  533. &cValues, &cbMaxValueName, &cbMaxValue,
  534. NULL, NULL);
  535. if (rc != ERROR_SUCCESS) {
  536. return HRESULT_FROM_WIN32(rc);
  537. }
  538. // nt doesn't return enough room for the terminating character
  539. // but these are still char counts not byte counts yet.
  540. ++cbMaxKeyName;
  541. ++cbMaxValueName;
  542. cbMaxKeyName *= sizeof(TCHAR);
  543. cbMaxValueName *= sizeof(TCHAR);
  544. // now they're real byte counts
  545. DWORD dwValIndex = 0, dwBagIndex = 0;
  546. USES_CONVERSION;
  547. if (iProperty < cValues) {
  548. LPTSTR pszName = new TCHAR[cbMaxValueName + 1];
  549. // we're starting with values
  550. for (;dwValIndex < cProperties; ++dwValIndex) {
  551. DWORD Type;
  552. DWORD cbName = cbMaxValueName + 1;
  553. rc = RegEnumValue(m_hk, dwValIndex, pszName, &cbName, NULL, &Type, NULL, NULL);
  554. if (rc != ERROR_SUCCESS) {
  555. break;
  556. }
  557. if (dwValIndex < iProperty) {
  558. continue; // skip until we get to first requested
  559. }
  560. switch (Type) {
  561. case REG_DWORD:
  562. pPropBag[dwBagIndex].dwType = PROPBAG2_TYPE_DATA;
  563. pPropBag[dwBagIndex].vt = VT_UI4;
  564. break;
  565. case REG_QWORD:
  566. pPropBag[dwBagIndex].dwType = PROPBAG2_TYPE_DATA;
  567. pPropBag[dwBagIndex].vt = VT_UI8;
  568. break;
  569. case REG_SZ:
  570. pPropBag[dwBagIndex].dwType = PROPBAG2_TYPE_DATA;
  571. pPropBag[dwBagIndex].vt = VT_BSTR;
  572. pPropBag[dwBagIndex].cfType = CF_TEXT;
  573. break;
  574. default: // binary
  575. pPropBag[dwBagIndex].dwType = PROPBAG2_TYPE_DATA;
  576. pPropBag[dwBagIndex].vt = VT_UI1 | VT_ARRAY;
  577. break;
  578. }
  579. int len = sizeof(OLECHAR) * (_tcsclen(pszName) + 1);
  580. pPropBag[dwBagIndex].pstrName = reinterpret_cast<LPOLESTR>(CoTaskMemAlloc(len + 1));
  581. if (!pPropBag[dwBagIndex].pstrName) {
  582. delete[] pszName;
  583. return E_OUTOFMEMORY;
  584. }
  585. (void)StringCchCopy(pPropBag[dwBagIndex].pstrName, len + 1, T2OLE(pszName));
  586. ++dwBagIndex;
  587. }
  588. delete[] pszName;
  589. }
  590. DWORD dwKeyIndex = 0;
  591. if (iProperty < cKeys + cValues) {
  592. LPTSTR pszName = new TCHAR[cbMaxKeyName + 1];
  593. for (; (dwKeyIndex + dwValIndex) < cProperties; ++dwKeyIndex) {
  594. DWORD cbName = cbMaxKeyName + 1;
  595. rc = RegEnumKeyEx(m_hk, dwKeyIndex, pszName, &cbName, NULL, NULL, NULL, NULL);
  596. if (rc != ERROR_SUCCESS) {
  597. break;
  598. }
  599. if ((dwValIndex + dwKeyIndex) < iProperty) {
  600. continue;
  601. }
  602. pPropBag[dwBagIndex].dwType = PROPBAG2_TYPE_OBJECT;
  603. pPropBag[dwBagIndex].vt = VT_UNKNOWN;
  604. int len = sizeof(OLECHAR) * (_tcsclen(pszName) + 1);
  605. pPropBag[dwBagIndex].pstrName = reinterpret_cast<LPOLESTR>(CoTaskMemAlloc(len + 1));
  606. if (!pPropBag[dwBagIndex].pstrName) {
  607. delete[] pszName;
  608. return E_OUTOFMEMORY;
  609. }
  610. (void)StringCchCopy(pPropBag[dwBagIndex].pstrName, len + 1, T2OLE(pszName));
  611. ++dwBagIndex;
  612. }
  613. delete[] pszName;
  614. }
  615. *pcProperties = dwBagIndex;
  616. return NOERROR;
  617. }
  618. STDMETHODIMP CRegBag::LoadObject(LPCOLESTR pstrName, ULONG dwHint, IUnknown * pUnkObject, IErrorLog * pErrLog) {
  619. if (!pstrName || !pUnkObject) {
  620. return E_POINTER;
  621. }
  622. VARIANT v; // don't clear the variant, we're guaranteed nested lifetimes and
  623. // we're not addref'ing
  624. v.vt = VT_UNKNOWN;
  625. v.punkVal = pUnkObject;
  626. return Read(pstrName, &v, pErrLog);
  627. }
  628. STDMETHODIMP CCreateRegBag::Create(HKEY hkey, LPCOLESTR subkey, DWORD options, DWORD sam, REFIID iid, LPVOID* ppBag) {
  629. if (!ppBag) {
  630. return E_POINTER;
  631. }
  632. ATL_LOCK();
  633. if (ppBag == NULL)
  634. return E_POINTER;
  635. try {
  636. USES_CONVERSION;
  637. if (iid == __uuidof(IPropertyBag)) {
  638. PQPropertyBag temp = new CRegBag(hkey, OLE2CT(subkey), options, sam);
  639. *ppBag = temp.Detach();
  640. } else if (iid == __uuidof(IPropertyBag2)) {
  641. PQPropertyBag2 temp = new CRegBag(hkey, OLE2CT(subkey), options, sam);
  642. *ppBag = temp.Detach();
  643. } else {
  644. return E_NOTIMPL;
  645. }
  646. if (!*ppBag) return E_OUTOFMEMORY;
  647. return NOERROR;
  648. } CATCHCOM();
  649. }