Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

707 lines
18 KiB

  1. #include <pch.hxx>
  2. #include <shlwapi.h>
  3. #include <shlwapip.h>
  4. #include "propbckt.h"
  5. #include "optbckt.h"
  6. #include "demand.h"
  7. MSOEACCTAPI CreateOptionBucketEx(IOptionBucketEx **ppOptBckt)
  8. {
  9. COptionBucket *pBckt;
  10. Assert(ppOptBckt != NULL);
  11. pBckt = new COptionBucket;
  12. *ppOptBckt = (IOptionBucketEx *)pBckt;
  13. return(pBckt == NULL ? E_OUTOFMEMORY : S_OK);
  14. }
  15. COptionBucket::COptionBucket(void)
  16. {
  17. m_cRef = 1;
  18. m_pProp = NULL;
  19. m_pNotify = NULL;
  20. m_fNotify = TRUE;
  21. m_idNotify = 0;
  22. m_rgInfo = NULL;
  23. m_cInfo = 0;
  24. m_cpszRegKey = 0;
  25. m_pszRegKeyBase = NULL;
  26. }
  27. COptionBucket::~COptionBucket(void)
  28. {
  29. int i;
  30. if (m_pProp != NULL)
  31. m_pProp->Release();
  32. if (m_pNotify != NULL)
  33. m_pNotify->Release();
  34. Assert(m_cpszRegKey <= CKEYMAX);
  35. for (i = 0; i < m_cpszRegKey; i++)
  36. MemFree(m_rgpszRegKey[i]);
  37. if (m_pszRegKeyBase != NULL)
  38. MemFree(m_pszRegKeyBase);
  39. }
  40. STDMETHODIMP COptionBucket::QueryInterface(REFIID riid, LPVOID *ppv)
  41. {
  42. if (ppv == NULL)
  43. return(E_INVALIDARG);
  44. if (IID_IUnknown == riid)
  45. {
  46. *ppv = (IUnknown *)this;
  47. }
  48. else if (IID_IOptionBucketEx == riid)
  49. {
  50. *ppv = (IOptionBucketEx *)this;
  51. }
  52. else if (IID_IOptionBucket == riid)
  53. {
  54. *ppv = (IOptionBucket *)this;
  55. }
  56. else if (IID_IPropertyBucket == riid)
  57. {
  58. *ppv = (IPropertyBucket *)this;
  59. }
  60. else
  61. {
  62. *ppv = NULL;
  63. return(E_NOINTERFACE);
  64. }
  65. ((IUnknown *)*ppv)->AddRef();
  66. return(S_OK);
  67. }
  68. STDMETHODIMP_(ULONG) COptionBucket::AddRef(void)
  69. {
  70. return((ULONG)InterlockedIncrement(&m_cRef));
  71. }
  72. STDMETHODIMP_(ULONG) COptionBucket::Release(void)
  73. {
  74. LONG cRef = InterlockedDecrement(&m_cRef);
  75. if (0 == cRef)
  76. delete this;
  77. return((ULONG)cRef);
  78. }
  79. #define REG_INVALID 0xffffffff
  80. DWORD RegTypeFromVarType(VARTYPE vt)
  81. {
  82. DWORD type;
  83. switch (vt)
  84. {
  85. case VT_UI4:
  86. type = REG_DWORD;
  87. break;
  88. case VT_LPSTR:
  89. case VT_LPWSTR:
  90. type = REG_SZ;
  91. break;
  92. case VT_BLOB:
  93. type = REG_BINARY;
  94. break;
  95. default:
  96. Assert(FALSE);
  97. type = REG_INVALID;
  98. break;
  99. }
  100. return(type);
  101. }
  102. STDMETHODIMP COptionBucket::GetProperty(LPCSTR pszProp, LPPROPVARIANT pVar, DWORD dwReserved)
  103. {
  104. HRESULT hr;
  105. LPCOPTIONINFO pInfo;
  106. DWORD cb,
  107. type = REG_INVALID,
  108. dw;
  109. LPBYTE pbT = NULL;
  110. LPCSTR pszKey,
  111. pszValue;
  112. LPWSTR pwszValue = NULL;
  113. HKEY hkey = 0;
  114. BOOL fSucceeded = FALSE;
  115. if (pszProp == NULL || pVar == NULL || dwReserved != 0)
  116. IF_FAILEXIT(hr = E_INVALIDARG);
  117. Assert(m_pProp != NULL);
  118. hr = m_pProp->GetProperty(pszProp, pVar, dwReserved);
  119. if (hr == E_PROP_NOT_FOUND) // the property hasn't been set yet
  120. {
  121. hr = S_OK;
  122. pbT = NULL;
  123. pInfo = NULL;
  124. pInfo = GetOptionInfo(pszProp);
  125. if (pInfo == NULL)
  126. IF_FAILEXIT(hr = E_PROP_NOT_FOUND);
  127. Assert(pInfo->iszRegKey < m_cpszRegKey);
  128. #pragma prefast(disable:11, "noise")
  129. pszKey = m_rgpszRegKey[pInfo->iszRegKey];
  130. pszValue = pInfo->pszRegValue;
  131. if (pszValue && (ERROR_SUCCESS == RegOpenKeyEx(m_hkey, pszKey, 0, KEY_READ, &hkey)))
  132. {
  133. if (VT_LPWSTR == pInfo->vt)
  134. {
  135. #pragma prefast(enable:11, "noise")
  136. IF_NULLEXIT(pwszValue = PszToUnicode(CP_ACP, pszValue));
  137. if (ERROR_SUCCESS == RegQueryValueExWrapW(hkey, pwszValue, NULL, &type, NULL, &cb))
  138. {
  139. Assert(cb > 0);
  140. IF_NULLEXIT(MemAlloc((void **)&pbT, cb));
  141. fSucceeded = (ERROR_SUCCESS == RegQueryValueExWrapW(hkey, pwszValue, NULL, &type, pbT, &cb));
  142. }
  143. }
  144. else
  145. {
  146. if (ERROR_SUCCESS == RegQueryValueEx(hkey, pszValue, NULL, &type, NULL, &cb))
  147. {
  148. Assert(cb > 0);
  149. IF_NULLEXIT(MemAlloc((void **)&pbT, cb));
  150. fSucceeded = (ERROR_SUCCESS == RegQueryValueEx(hkey, pszValue, NULL, &type, pbT, &cb));
  151. }
  152. }
  153. if (fSucceeded)
  154. {
  155. if (pInfo != NULL && pInfo->vt == VT_UI4 && type == REG_BINARY)
  156. {
  157. // values set via the INF file may have type REG_BINARY instead of REG_DWORD
  158. // but we need them to be REG_DWORD. the next time the value is set in the registry
  159. // it will be set as REG_DWORD and everything will be cool from that point on...
  160. Assert(cb >= 4);
  161. pVar->vt = VT_UI4;
  162. }
  163. else
  164. {
  165. // Either we didn't find the entry, or the regtypes match.
  166. Assert(type == RegTypeFromVarType(pInfo->vt));
  167. pVar->vt = pInfo->vt;
  168. }
  169. if (pVar->vt == VT_ILLEGAL)
  170. IF_FAILEXIT(hr = E_INVALID_PROP_TYPE);
  171. }
  172. else if (pInfo) // the property isn't set in the registry yet so grab default
  173. {
  174. IF_FAILEXIT(hr = GetPropertyDefault(SzToPropId(pszProp), pVar, dwReserved));
  175. goto exit;
  176. }
  177. }
  178. if (!fSucceeded)
  179. {
  180. hr = E_PROP_NOT_FOUND;
  181. goto exit;
  182. }
  183. switch (pVar->vt)
  184. {
  185. case VT_UI4:
  186. pVar->ulVal = *((DWORD *)pbT);
  187. break;
  188. case VT_LPSTR:
  189. pVar->pszVal = (LPSTR)pbT;
  190. break;
  191. case VT_LPWSTR:
  192. pVar->pwszVal = (LPWSTR)pbT;
  193. break;
  194. case VT_BLOB:
  195. pVar->blob.cbSize = cb;
  196. pVar->blob.pBlobData = pbT;
  197. break;
  198. default:
  199. Assert(FALSE);
  200. IF_FAILEXIT(hr = E_INVALID_PROP_TYPE);
  201. break;
  202. }
  203. IF_FAILEXIT(hr = m_pProp->SetProperty(pszProp, pVar, 0));
  204. if (pVar->vt != VT_UI4)
  205. {
  206. // we're handing this memory off to the caller, so don't free it
  207. pbT = NULL;
  208. }
  209. }
  210. else
  211. IF_FAILEXIT(hr);
  212. exit:
  213. MemFree(pbT);
  214. MemFree(pwszValue);
  215. if (hkey)
  216. RegCloseKey(hkey);
  217. return(hr);
  218. }
  219. STDMETHODIMP COptionBucket::SetProperty(LPCSTR pszProp, LPCPROPVARIANT pVar, DWORD dwReserved)
  220. {
  221. if (pszProp == NULL || pVar == NULL || dwReserved != 0)
  222. return(E_INVALIDARG);
  223. return(ISetProperty(NULL, pszProp, pVar, 0));
  224. }
  225. STDMETHODIMP COptionBucket::ISetProperty(HWND hwnd, LPCSTR pszProp, LPCPROPVARIANT pVar, DWORD dwFlags)
  226. {
  227. HRESULT hr;
  228. DWORD type,
  229. cb;
  230. LPBYTE pb;
  231. LPCSTR pszKey,
  232. pszValue;
  233. LPWSTR pwszValue = NULL;
  234. LPCOPTIONINFO pInfo;
  235. LONG lRet;
  236. HKEY hkey = 0;
  237. if (pszProp == NULL || pVar == NULL)
  238. IF_FAILEXIT(hr = E_INVALIDARG);
  239. type = RegTypeFromVarType(pVar->vt);
  240. if (type == REG_INVALID)
  241. IF_FAILEXIT(hr = E_INVALID_PROP_TYPE);
  242. Assert(m_pProp != NULL);
  243. IF_FAILEXIT(hr = m_pProp->SetProperty(pszProp, pVar, 0));
  244. if (hr != S_NO_CHANGE)
  245. {
  246. pInfo = GetOptionInfo(pszProp);
  247. Assert(pInfo != NULL);
  248. Assert(pInfo->iszRegKey < m_cpszRegKey);
  249. pszKey = m_rgpszRegKey[pInfo->iszRegKey];
  250. pszValue = pInfo->pszRegValue;
  251. switch (pVar->vt)
  252. {
  253. case VT_UI4:
  254. pb = (BYTE *)&pVar->ulVal;
  255. cb = sizeof(DWORD);
  256. break;
  257. case VT_LPSTR:
  258. pb = (BYTE *)pVar->pszVal;
  259. cb = lstrlen(pVar->pszVal) + 1;
  260. break;
  261. case VT_LPWSTR:
  262. pb = (BYTE *)pVar->pwszVal;
  263. cb = (lstrlenW(pVar->pwszVal) + 1) * sizeof(WCHAR);
  264. break;
  265. case VT_BLOB:
  266. pb = pVar->blob.pBlobData;
  267. cb = pVar->blob.cbSize;
  268. break;
  269. default:
  270. Assert(FALSE);
  271. break;
  272. }
  273. if (pszValue != NULL)
  274. {
  275. if ((REG_BINARY == type) && (0 == cb))
  276. {
  277. SHDeleteValue(m_hkey, pszKey, pszValue);
  278. lRet = ERROR_SUCCESS; // failure on delete is probably just NOT_FOUND
  279. }
  280. else
  281. {
  282. lRet= RegOpenKeyEx(m_hkey, pszKey, 0, KEY_WRITE, &hkey);
  283. if (ERROR_SUCCESS == lRet)
  284. {
  285. if (VT_LPWSTR == pVar->vt)
  286. {
  287. IF_NULLEXIT(pwszValue = PszToUnicode(CP_ACP, pszValue));
  288. lRet = RegSetValueExWrapW(hkey, pwszValue, NULL, type, pb, cb);
  289. }
  290. else
  291. {
  292. lRet = RegSetValueEx(hkey, pszValue, NULL, type, pb, cb);
  293. }
  294. }
  295. }
  296. if (ERROR_SUCCESS == lRet)
  297. {
  298. Assert(IsPropId(pszProp));
  299. if (m_pNotify != NULL)
  300. {
  301. if (m_fNotify)
  302. {
  303. m_pNotify->DoNotification((IOptionBucketEx *)this, hwnd, SzToPropId(pszProp));
  304. }
  305. else
  306. {
  307. if (m_idNotify == 0)
  308. m_idNotify = SzToPropId(pszProp);
  309. else
  310. m_idNotify = 0xffffffff;
  311. }
  312. }
  313. }
  314. else
  315. IF_FAILEXIT(hr = E_FAIL);
  316. }
  317. }
  318. exit:
  319. if (hkey)
  320. RegCloseKey(hkey);
  321. MemFree(pwszValue);
  322. return(hr);
  323. }
  324. STDMETHODIMP COptionBucket::ValidateProperty(PROPID id, LPCPROPVARIANT pVar, DWORD dwReserved)
  325. {
  326. HRESULT hr;
  327. LPCOPTIONINFO pInfo;
  328. if (pVar == NULL || dwReserved != 0)
  329. return(E_INVALIDARG);
  330. pInfo = GetOptionInfo(MAKEPROPSTRING(id));
  331. if (pInfo == NULL)
  332. hr = E_PROP_NOT_FOUND;
  333. else if (pInfo->vt != pVar->vt)
  334. hr = E_INVALID_PROP_TYPE;
  335. else if (pInfo->pfnValid != NULL)
  336. hr = pInfo->pfnValid(id, pVar);
  337. else if (pVar->vt == VT_UI4 &&
  338. (pInfo->dwMin != 0 || pInfo->dwMax != 0))
  339. hr = (pVar->ulVal >= pInfo->dwMin && pVar->ulVal <= pInfo->dwMax) ? S_OK : E_INVALID_PROP_VALUE;
  340. else
  341. hr = S_OK;
  342. return(hr);
  343. }
  344. STDMETHODIMP COptionBucket::GetPropertyDefault(PROPID id, LPPROPVARIANT pVar, DWORD dwReserved)
  345. {
  346. LPCOPTIONINFO pInfo;
  347. HRESULT hr = S_OK;
  348. LPBYTE pb = NULL;
  349. DWORD cb = 0;
  350. if (NULL == pVar || 0 != dwReserved)
  351. IF_FAILEXIT(hr = E_INVALIDARG);
  352. pInfo = GetOptionInfo(MAKEPROPSTRING(id));
  353. if (NULL == pInfo)
  354. IF_FAILEXIT(hr = E_PROP_NOT_FOUND);
  355. pVar->vt = pInfo->vt;
  356. if (pVar->vt == VT_UI4)
  357. {
  358. pVar->ulVal = (DWORD)PtrToUlong(pInfo->pszDef);
  359. }
  360. else
  361. {
  362. if (pInfo->pszDef)
  363. {
  364. switch (pVar->vt)
  365. {
  366. case VT_LPSTR:
  367. cb = lstrlen(pInfo->pszDef) + 1;
  368. break;
  369. case VT_LPWSTR:
  370. cb = (lstrlenW((LPWSTR)pInfo->pszDef) + 1) * sizeof(WCHAR);
  371. break;
  372. case VT_BLOB:
  373. cb = pInfo->cbDefBinary;
  374. break;
  375. default:
  376. Assert(FALSE);
  377. break;
  378. }
  379. IF_NULLEXIT(MemAlloc((void **)&pb, cb));
  380. CopyMemory(pb, pInfo->pszDef, cb);
  381. switch (pVar->vt)
  382. {
  383. case VT_LPSTR:
  384. pVar->pszVal = (LPSTR)pb;
  385. break;
  386. case VT_LPWSTR:
  387. pVar->pwszVal = (LPWSTR)pb;
  388. break;
  389. case VT_BLOB:
  390. pVar->blob.cbSize = cb;
  391. pVar->blob.pBlobData = pb;
  392. break;
  393. }
  394. }
  395. else
  396. // Since this happens quite often, don't trace it.
  397. hr = E_NO_DEFAULT_VALUE;
  398. }
  399. pb = NULL;
  400. exit:
  401. MemFree(pb);
  402. return(hr);
  403. }
  404. STDMETHODIMP COptionBucket::GetPropertyInfo(PROPID id, PROPINFO *pPropInfo, DWORD dwReserved)
  405. {
  406. LPCOPTIONINFO pInfo;
  407. HRESULT hr = S_OK;
  408. LPBYTE pb;
  409. DWORD cb;
  410. if (pPropInfo == NULL || pPropInfo->cbSize < sizeof(PROPINFO))
  411. IF_FAILEXIT(hr = E_INVALIDARG);
  412. #pragma prefast(disable:11, "noise")
  413. pPropInfo->uMin = 0;
  414. pPropInfo->uMax = 0;
  415. #pragma prefast(enable:11, "noise")
  416. pInfo = GetOptionInfo(MAKEPROPSTRING(id));
  417. if (NULL == pInfo)
  418. IF_FAILEXIT(hr = E_PROP_NOT_FOUND);
  419. #pragma prefast(disable:11, "noise")
  420. pPropInfo->vt = pInfo->vt;
  421. switch (pPropInfo->vt)
  422. {
  423. case VT_LPSTR:
  424. case VT_LPWSTR:
  425. pPropInfo->cchMax = pInfo->dwMax;
  426. break;
  427. case VT_UI4:
  428. pPropInfo->uMin = pInfo->dwMin;
  429. pPropInfo->uMax = pInfo->dwMax;
  430. break;
  431. }
  432. #pragma prefast(enable:11, "noise")
  433. exit:
  434. return(hr);
  435. }
  436. LPSTR DupPath(LPCSTR sz, LPCSTR szSubDir)
  437. {
  438. LPSTR szT = NULL;
  439. if (MemAlloc((void **)&szT, MAX_PATH))
  440. {
  441. StrCpyN(szT, sz, MAX_PATH);
  442. if (szSubDir != NULL)
  443. PathAppend(szT, szSubDir);
  444. }
  445. else
  446. TraceResult(E_OUTOFMEMORY);
  447. return(szT);
  448. }
  449. STDMETHODIMP COptionBucket::Initialize(LPCOPTBCKTINIT pInit)
  450. {
  451. int i;
  452. HRESULT hr = S_OK;
  453. Assert(pInit != NULL);
  454. Assert(pInit->rgInfo != NULL);
  455. Assert(pInit->cInfo > 0);
  456. Assert(pInit->pszRegKeyBase != NULL);
  457. Assert(pInit->cszRegKey <= CKEYMAX);
  458. Assert(pInit->hkey != NULL);
  459. Assert(m_pProp == NULL);
  460. m_rgInfo = pInit->rgInfo;
  461. m_cInfo = pInit->cInfo;
  462. #ifdef DEBUG
  463. for (i = 0; i < m_cInfo - 1; i++)
  464. {
  465. Assert(m_rgInfo[i].id < m_rgInfo[i + 1].id);
  466. }
  467. #endif // DEBUG
  468. m_hkey = pInit->hkey;
  469. IF_NULLEXIT(m_pszRegKeyBase = PszDup(pInit->pszRegKeyBase));
  470. Assert(m_cpszRegKey == 0);
  471. if (pInit->cszRegKey == 0)
  472. {
  473. IF_NULLEXIT(m_rgpszRegKey[0] = PszDup(m_pszRegKeyBase));
  474. m_cpszRegKey = 1;
  475. }
  476. else
  477. {
  478. for (i = 0; i < pInit->cszRegKey; i++)
  479. {
  480. IF_NULLEXIT(m_rgpszRegKey[i] = DupPath(m_pszRegKeyBase, pInit->rgpszRegSubKey[i]));
  481. m_cpszRegKey++;
  482. }
  483. }
  484. IF_NULLEXIT(m_pProp = new CPropertyBucket);
  485. exit:
  486. return hr;
  487. }
  488. LPCOPTIONINFO COptionBucket::GetOptionInfo(LPCSTR pszProp)
  489. {
  490. int left, right, x;
  491. LPCOPTIONINFO pInfo;
  492. PROPID id;
  493. Assert(pszProp != NULL);
  494. Assert(IsPropId(pszProp));
  495. id = SzToPropId(pszProp);
  496. left = 0;
  497. right = m_cInfo - 1;
  498. do
  499. {
  500. x = (left + right) / 2;
  501. pInfo = &m_rgInfo[x];
  502. if (id == pInfo->id)
  503. return(pInfo);
  504. else if (id < pInfo->id)
  505. right = x - 1;
  506. else
  507. left = x + 1;
  508. }
  509. while (right >= left);
  510. return(NULL);
  511. }
  512. STDMETHODIMP COptionBucket::SetNotification(IOptionBucketNotify *pNotify)
  513. {
  514. if (m_pNotify != NULL)
  515. {
  516. m_pNotify->Release();
  517. m_pNotify = NULL;
  518. }
  519. if (pNotify != NULL)
  520. {
  521. m_pNotify = pNotify;
  522. pNotify->AddRef();
  523. }
  524. return(S_OK);
  525. }
  526. STDMETHODIMP COptionBucket::EnableNotification(BOOL fEnable)
  527. {
  528. Assert(m_fNotify != fEnable);
  529. m_fNotify = fEnable;
  530. if (m_fNotify && m_pNotify && m_idNotify != 0)
  531. {
  532. m_pNotify->DoNotification((IOptionBucketEx *)this, 0, m_idNotify);
  533. m_idNotify = 0;
  534. }
  535. return(S_OK);
  536. }
  537. // WARNING!!! This function doesn't handle getting values that are unicode.
  538. STDMETHODIMP_(LONG) COptionBucket::GetValue(LPCSTR szSubKey, LPCSTR szValue, DWORD *ptype, LPBYTE pb, DWORD *pcb)
  539. {
  540. char szKey[MAX_PATH];
  541. LONG lRet;
  542. Assert(ptype != NULL);
  543. Assert(szValue != NULL);
  544. Assert(pcb != NULL);
  545. if (szSubKey != NULL)
  546. {
  547. StrCpyN(szKey, m_pszRegKeyBase, ARRAYSIZE(szKey));
  548. PathAppend(szKey, szSubKey);
  549. szSubKey = szKey;
  550. }
  551. else
  552. {
  553. szSubKey = m_pszRegKeyBase;
  554. }
  555. lRet = SHGetValue(m_hkey, szSubKey, szValue, ptype, pb, pcb);
  556. return(lRet);
  557. }
  558. // WARNING!!! This function doesn't handle setting values that are unicode.
  559. STDMETHODIMP_(LONG) COptionBucket::SetValue(LPCSTR szSubKey, LPCSTR szValue, DWORD type, LPBYTE pb, DWORD cb)
  560. {
  561. char szKey[MAX_PATH];
  562. LONG lRet;
  563. Assert(szValue != NULL);
  564. if (szSubKey != NULL)
  565. {
  566. StrCpyN(szKey, m_pszRegKeyBase, ARRAYSIZE(szKey));
  567. PathAppend(szKey, szSubKey);
  568. szSubKey = szKey;
  569. }
  570. else
  571. {
  572. szSubKey = m_pszRegKeyBase;
  573. }
  574. if (pb == NULL)
  575. {
  576. Assert(cb == 0);
  577. lRet = SHDeleteValue(m_hkey, szSubKey, szValue);
  578. }
  579. else
  580. {
  581. Assert(cb > 0);
  582. lRet = SHSetValue(m_hkey, szSubKey, szValue, type, pb, cb);
  583. }
  584. return(lRet);
  585. }