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.

1297 lines
44 KiB

  1. #include "priv.h"
  2. #include "resource.h"
  3. #include "tmschema.h"
  4. #include "uxtheme.h"
  5. #include "uxthemep.h"
  6. #include "mluisupp.h"
  7. #include <oleacc.h>
  8. #include <cowsite.h>
  9. #include <apithk.h>
  10. const struct
  11. {
  12. TREE_TYPE type;
  13. LPCTSTR name;
  14. } c_aTreeTypes[] =
  15. {
  16. {TREE_CHECKBOX, TEXT("checkbox")},
  17. {TREE_RADIO, TEXT("radio")},
  18. {TREE_GROUP, TEXT("group")}
  19. };
  20. const TCHAR c_szType[] = TEXT("Type");
  21. const TCHAR c_szText[] = TEXT("Text");
  22. const TCHAR c_szPlugUIText[] = TEXT("PlugUIText");
  23. const TCHAR c_szDefaultBitmap[] = TEXT("Bitmap");
  24. const TCHAR c_szHKeyRoot[] = TEXT("HKeyRoot");
  25. const TCHAR c_szValueName[] = TEXT("ValueName");
  26. const TCHAR c_szCheckedValue[] = TEXT("CheckedValue");
  27. const TCHAR c_szUncheckedValue[] = TEXT("UncheckedValue");
  28. const TCHAR c_szDefaultValue[] = TEXT("DefaultValue");
  29. const TCHAR c_szSPIActionGet[] = TEXT("SPIActionGet");
  30. const TCHAR c_szSPIActionSet[] = TEXT("SPIActionSet");
  31. const TCHAR c_szCLSID[] = TEXT("CLSID");
  32. const TCHAR c_szCheckedValueNT[] = TEXT("CheckedValueNT");
  33. const TCHAR c_szCheckedValueW95[] = TEXT("CheckedValueW95");
  34. const TCHAR c_szMask[] = TEXT("Mask");
  35. const TCHAR c_szOffset[] = TEXT("Offset");
  36. const TCHAR c_szHelpID[] = TEXT("HelpID");
  37. const TCHAR c_szWarning[] = TEXT("WarningIfNotDefault");
  38. #define BITMAP_WIDTH 16
  39. #define BITMAP_HEIGHT 16
  40. #define NUM_BITMAPS 5
  41. #define MAX_KEY_NAME 64
  42. DWORD RegTreeType(LPCTSTR pszType);
  43. BOOL AppendStatus(LPTSTR pszText, UINT cchText, BOOL fOn);
  44. BOOL IsScreenReaderEnabled();
  45. class CRegTreeOptions : public IRegTreeOptions, public CObjectWithSite
  46. {
  47. public:
  48. CRegTreeOptions();
  49. IUnknown *GetUnknown() { return SAFECAST(this, IRegTreeOptions*); }
  50. // IUnknown Methods
  51. STDMETHODIMP QueryInterface(REFIID,void **);
  52. STDMETHODIMP_(ULONG) AddRef(void);
  53. STDMETHODIMP_(ULONG) Release(void);
  54. // IRegTreeOptions Methods
  55. STDMETHODIMP InitTree(HWND hwndTree, HKEY hkeyRoot, LPCSTR pszRegKey, LPCSTR pszParam);
  56. STDMETHODIMP WalkTree(WALK_TREE_CMD cmd);
  57. STDMETHODIMP ShowHelp(HTREEITEM hti, DWORD dwFlags);
  58. STDMETHODIMP ToggleItem(HTREEITEM hti);
  59. protected:
  60. ~CRegTreeOptions();
  61. void _RegEnumTree(HUSKEY huskey, HTREEITEM htviparent, HTREEITEM htvins);
  62. int _DefaultIconImage(HUSKEY huskey, int iImage);
  63. DWORD _GetCheckStatus(HUSKEY huskey, BOOL *pbChecked, BOOL bUseDefault);
  64. DWORD _GetSetByCLSID(REFCLSID clsid, BOOL *pbData, BOOL fGet);
  65. DWORD _GetSetByRegKey(HUSKEY husKey, DWORD *pType, LPBYTE pData, DWORD *pcbData, REG_CMD cmd);
  66. DWORD _RegGetSetSetting(HUSKEY husKey, DWORD *pType, LPBYTE pData, DWORD *pcbData, REG_CMD cmd);
  67. BOOL _WalkTreeRecursive(HTREEITEM htvi,WALK_TREE_CMD cmd);
  68. DWORD _SaveCheckStatus(HUSKEY huskey, BOOL bChecked);
  69. BOOL _RegIsRestricted(HUSKEY hussubkey);
  70. UINT _cRef;
  71. HWND _hwndTree;
  72. LPTSTR _pszParam;
  73. HIMAGELIST _hIml;
  74. };
  75. //////////////////////////////////////////////////////////////////////////////
  76. //
  77. // CRegTreeOptions Object
  78. //
  79. //////////////////////////////////////////////////////////////////////////////
  80. STDAPI CRegTreeOptions_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  81. {
  82. // aggregation checking is handled in class factory
  83. TraceMsg(DM_TRACE, "rto - CreateInstance(...) called");
  84. CRegTreeOptions *pTO = new CRegTreeOptions();
  85. if (pTO)
  86. {
  87. *ppunk = pTO->GetUnknown();
  88. return S_OK;
  89. }
  90. return E_OUTOFMEMORY;
  91. }
  92. CRegTreeOptions::CRegTreeOptions()
  93. {
  94. TraceMsg(DM_TRACE, "rto - CRegTreeOptions() called.");
  95. _cRef = 1;
  96. DllAddRef();
  97. }
  98. CRegTreeOptions::~CRegTreeOptions()
  99. {
  100. ASSERT(_cRef == 0); // should always have zero
  101. TraceMsg(DM_TRACE, "rto - ~CRegTreeOptions() called.");
  102. Str_SetPtr(&_pszParam, NULL);
  103. DllRelease();
  104. }
  105. //////////////////////////////////
  106. //
  107. // IUnknown Methods...
  108. //
  109. HRESULT CRegTreeOptions::QueryInterface(REFIID riid, void **ppv)
  110. {
  111. static const QITAB qit[] = {
  112. QITABENT(CRegTreeOptions, IRegTreeOptions), // IID_IRegTreeOptions
  113. QITABENT(CRegTreeOptions, IObjectWithSite), // IID_IObjectWithSite
  114. { 0 },
  115. };
  116. return QISearch(this, qit, riid, ppv);
  117. }
  118. ULONG CRegTreeOptions::AddRef()
  119. {
  120. TraceMsg(DM_TRACE, "rto - AddRef() called.");
  121. return ++_cRef;
  122. }
  123. ULONG CRegTreeOptions::Release()
  124. {
  125. TraceMsg(DM_TRACE, "rto - Release() called.");
  126. if (--_cRef)
  127. return _cRef;
  128. // destroy the imagelist
  129. if (_hwndTree)
  130. {
  131. ImageList_Destroy(TreeView_SetImageList(_hwndTree, NULL, TVSIL_NORMAL));
  132. // Clean up the accessibility stuff
  133. RemoveProp(_hwndTree, TEXT("MSAAStateImageMapCount"));
  134. RemoveProp(_hwndTree, TEXT("MSAAStateImageMapAddr"));
  135. }
  136. delete this;
  137. return 0;
  138. }
  139. //////////////////////////////////
  140. //
  141. // IRegTreeOptions Methods...
  142. //
  143. //
  144. // Accessibility structure so it knows how to convert treeview state images
  145. // into accessibility roles and states.
  146. //
  147. struct MSAASTATEIMAGEMAPENT
  148. {
  149. DWORD dwRole;
  150. DWORD dwState;
  151. };
  152. const struct MSAASTATEIMAGEMAPENT c_rgimeTree[] =
  153. {
  154. { ROLE_SYSTEM_CHECKBUTTON, STATE_SYSTEM_CHECKED }, // IDCHECKED
  155. { ROLE_SYSTEM_CHECKBUTTON, 0 }, // IDUNCHECKED
  156. { ROLE_SYSTEM_RADIOBUTTON, STATE_SYSTEM_CHECKED }, // IDRADIOON
  157. { ROLE_SYSTEM_RADIOBUTTON, 0 }, // IDRADIOOFF
  158. { ROLE_SYSTEM_OUTLINE, 0 }, // IDUNKNOWN
  159. };
  160. HBITMAP CreateDIB(HDC h, int cx, int cy, RGBQUAD** pprgb)
  161. {
  162. BITMAPINFO bi = {0};
  163. bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
  164. bi.bmiHeader.biWidth = cx;
  165. bi.bmiHeader.biHeight = cy;
  166. bi.bmiHeader.biPlanes = 1;
  167. bi.bmiHeader.biBitCount = 32;
  168. bi.bmiHeader.biCompression = BI_RGB;
  169. return CreateDIBSection(h, &bi, DIB_RGB_COLORS, (void**)pprgb, NULL, 0);
  170. }
  171. HRESULT CRegTreeOptions::InitTree(HWND hwndTree, HKEY hkeyRoot, LPCSTR pszRegKey, LPCSTR pszParam)
  172. {
  173. // all callers pass HKEY_LOCAL_MACHINE, yay what a cool interface
  174. // assert that this is so, since the HUSKEY code now relies on being able to switch between
  175. // HKCU and HKLM.
  176. ASSERT(hkeyRoot == HKEY_LOCAL_MACHINE);
  177. TCHAR szParam[MAX_URL_STRING];
  178. TraceMsg(DM_TRACE, "rto - InitTree called().");
  179. UINT flags = ILC_MASK | (IsOS(OS_WHISTLERORGREATER)?ILC_COLOR32:ILC_COLOR);
  180. if (!hkeyRoot || !pszRegKey)
  181. return E_INVALIDARG;
  182. if (pszParam)
  183. {
  184. SHAnsiToTChar(pszParam, szParam, ARRAYSIZE(szParam));
  185. Str_SetPtr(&_pszParam, szParam); // be sure to free in destructor
  186. }
  187. _hwndTree = hwndTree;
  188. if(IS_WINDOW_RTL_MIRRORED(_hwndTree))
  189. {
  190. flags |= ILC_MIRROR;
  191. }
  192. _hIml = ImageList_Create(BITMAP_WIDTH, BITMAP_HEIGHT, flags, NUM_BITMAPS, 4);
  193. // Initialize the tree view window.
  194. SHSetWindowBits(_hwndTree, GWL_STYLE, TVS_CHECKBOXES, 0);
  195. HBITMAP hBitmap = 0;
  196. #ifdef UNIX
  197. // IEUNIX (Varma): an ugly hack to workaround _AddMasked api problems while
  198. // creating masked bitmaps. Need to create DIBSection from
  199. // CreateMappedBitmap. This is to fix buttons visibility on mono when black
  200. if (SHGetCurColorRes() < 2)
  201. {
  202. hBitmap = CreateMappedBitmap(g_hinst, IDB_BUTTONS, CMB_MASKED, NULL, 0);
  203. if (hBitmap)
  204. {
  205. ImageList_Add(_hIml, hBitmap, NULL);
  206. // Delete hBitmap in common further down this codepath
  207. }
  208. }
  209. else
  210. #endif
  211. {
  212. HTHEME hTheme = OpenThemeData(NULL, L"Button");
  213. if (hTheme)
  214. {
  215. HDC hdc = CreateCompatibleDC(NULL);
  216. if (hdc)
  217. {
  218. HBITMAP hbmp = CreateDIB(hdc, BITMAP_WIDTH, BITMAP_HEIGHT, NULL);
  219. if (hbmp)
  220. {
  221. RECT rc = {0, 0, BITMAP_WIDTH, BITMAP_HEIGHT};
  222. static const s_rgParts[] = {BP_CHECKBOX,BP_CHECKBOX,BP_RADIOBUTTON,BP_RADIOBUTTON};
  223. static const s_rgStates[] = {CBS_CHECKEDNORMAL, CBS_UNCHECKEDNORMAL, RBS_CHECKEDNORMAL, RBS_UNCHECKEDNORMAL};
  224. for (int i = 0; i < ARRAYSIZE(s_rgParts); i++)
  225. {
  226. HBITMAP hOld = (HBITMAP)SelectObject(hdc, hbmp);
  227. SHFillRectClr(hdc, &rc, RGB(0,0,0));
  228. DTBGOPTS dtbg = {sizeof(DTBGOPTS), DTBG_DRAWSOLID, 0,}; // tell drawthemebackground to preserve the alpha channel
  229. DrawThemeBackgroundEx(hTheme, hdc, s_rgParts[i], s_rgStates[i], &rc, &dtbg);
  230. SelectObject(hdc, hOld);
  231. ImageList_Add(_hIml, hbmp, NULL);
  232. }
  233. DeleteObject(hbmp);
  234. // Hate this. Maybe get an authored icon?
  235. hBitmap = CreateMappedBitmap(g_hinst, IDB_GROUPBUTTON, 0, NULL, 0);
  236. if (hBitmap)
  237. {
  238. ImageList_AddMasked(_hIml, hBitmap, CLR_DEFAULT);
  239. // Delete hBitmap in common further down the codepath
  240. }
  241. }
  242. DeleteDC(hdc);
  243. }
  244. CloseThemeData(hTheme);
  245. }
  246. else
  247. {
  248. hBitmap = CreateMappedBitmap(g_hinst, IDB_BUTTONS, 0, NULL, 0);
  249. if (hBitmap)
  250. {
  251. ImageList_AddMasked(_hIml, hBitmap, CLR_DEFAULT);
  252. // Delete hBitmap in common further down the codepath
  253. }
  254. }
  255. }
  256. if (hBitmap)
  257. DeleteObject(hBitmap);
  258. // Associate the image list with the tree.
  259. HIMAGELIST himl = TreeView_SetImageList(_hwndTree, _hIml, TVSIL_NORMAL);
  260. if (himl)
  261. ImageList_Destroy(himl);
  262. // Let accessibility know about our state images
  263. SetProp(_hwndTree, TEXT("MSAAStateImageMapCount"), LongToPtr(ARRAYSIZE(c_rgimeTree)));
  264. SetProp(_hwndTree, TEXT("MSAAStateImageMapAddr"), (HANDLE)c_rgimeTree);
  265. HUSKEY huskey;
  266. if (ERROR_SUCCESS == SHRegOpenUSKeyA(pszRegKey, KEY_ENUMERATE_SUB_KEYS, NULL, &huskey, FALSE))
  267. {
  268. _RegEnumTree(huskey, NULL, TVI_ROOT);
  269. SHRegCloseUSKey(huskey);
  270. }
  271. return S_OK;
  272. }
  273. HRESULT CRegTreeOptions::WalkTree(WALK_TREE_CMD cmd)
  274. {
  275. HTREEITEM htvi = TreeView_GetRoot(_hwndTree);
  276. // and walk the list of other roots
  277. while (htvi)
  278. {
  279. // recurse through its children
  280. _WalkTreeRecursive(htvi, cmd);
  281. // get the next root
  282. htvi = TreeView_GetNextSibling(_hwndTree, htvi);
  283. }
  284. return S_OK; // success?
  285. }
  286. HRESULT _LoadUSRegUIString(HUSKEY huskey, PCTSTR pszValue, PTSTR psz, UINT cch)
  287. {
  288. psz[0] = 0;
  289. HRESULT hr = E_FAIL;
  290. TCHAR szIndirect[MAX_PATH];
  291. DWORD cb = sizeof(szIndirect);
  292. if (ERROR_SUCCESS == SHRegQueryUSValue(huskey, pszValue, NULL, szIndirect, &cb, FALSE, NULL, 0))
  293. {
  294. hr = SHLoadIndirectString(szIndirect, psz, cch, NULL);
  295. }
  296. return hr;
  297. }
  298. HRESULT CRegTreeOptions::ToggleItem(HTREEITEM hti)
  299. {
  300. TV_ITEM tvi;
  301. TCHAR szText[MAX_PATH];
  302. tvi.hItem = hti;
  303. tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT | TVIF_PARAM;
  304. tvi.pszText = szText;
  305. tvi.cchTextMax = ARRAYSIZE(szText);
  306. if (hti && TreeView_GetItem(_hwndTree, &tvi))
  307. {
  308. BOOL bScreenReaderEnabled = IsScreenReaderEnabled();
  309. HUSKEY huskey = (HUSKEY)tvi.lParam;
  310. TCHAR szMsg[512];
  311. if (SUCCEEDED(_LoadUSRegUIString(huskey, c_szWarning, szMsg, ARRAYSIZE(szMsg))))
  312. {
  313. BOOL bDefaultState, bCurrentState = (tvi.iImage == IDCHECKED) || (tvi.iImage == IDRADIOON);
  314. if (ERROR_SUCCESS == _GetCheckStatus(huskey, &bDefaultState, TRUE))
  315. {
  316. // trying to change the current state to the non recomended state?
  317. if (bDefaultState == bCurrentState)
  318. {
  319. if (MLShellMessageBox(_hwndTree, szMsg, MAKEINTRESOURCE(IDS_WARNING), (MB_YESNO | MB_DEFBUTTON2 | MB_ICONEXCLAMATION)) != IDYES)
  320. {
  321. return S_FALSE;
  322. }
  323. }
  324. }
  325. }
  326. if (tvi.iImage == IDUNCHECKED)
  327. {
  328. tvi.iImage = IDCHECKED;
  329. tvi.iSelectedImage = IDCHECKED;
  330. //See if we need to add status text
  331. if (bScreenReaderEnabled)
  332. {
  333. AppendStatus(szText, ARRAYSIZE(szText), TRUE);
  334. }
  335. TraceMsg(TF_GENERAL, "rto::ToggleItem() - Checked!");
  336. }
  337. else if (tvi.iImage == IDCHECKED)
  338. {
  339. tvi.iImage = IDUNCHECKED;
  340. tvi.iSelectedImage = IDUNCHECKED;
  341. //See if we need to add status text
  342. if (bScreenReaderEnabled)
  343. {
  344. AppendStatus(szText, ARRAYSIZE(szText), FALSE);
  345. }
  346. TraceMsg(TF_GENERAL, "rto::ToggleItem() - Unchecked!");
  347. }
  348. else if ((tvi.iImage == IDRADIOON) || (tvi.iImage == IDRADIOOFF))
  349. {
  350. HTREEITEM htvi;
  351. TV_ITEM otvi; // other tvi-s
  352. TCHAR szOtext[MAX_PATH];
  353. // change all the "on" radios to "off"
  354. htvi = TreeView_GetParent(_hwndTree, tvi.hItem);
  355. htvi = TreeView_GetChild(_hwndTree, htvi);
  356. // hunt for the "on"s
  357. while (htvi)
  358. {
  359. // get info about item
  360. otvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
  361. otvi.hItem = htvi;
  362. otvi.pszText = szOtext;
  363. otvi.cchTextMax = ARRAYSIZE(szOtext);
  364. if (TreeView_GetItem(_hwndTree, &otvi))
  365. {
  366. // is it a radio button that is on?
  367. if (otvi.iImage == IDRADIOON)
  368. { // yes.. turn it off
  369. otvi.iImage = IDRADIOOFF;
  370. otvi.iSelectedImage = IDRADIOOFF;
  371. //See if we need to add status text
  372. if (bScreenReaderEnabled)
  373. {
  374. AppendStatus(szOtext,ARRAYSIZE(szOtext), FALSE);
  375. }
  376. TreeView_SetItem(_hwndTree, &otvi);
  377. }
  378. }
  379. // find the next child
  380. htvi = TreeView_GetNextSibling(_hwndTree, htvi);
  381. }
  382. // turn on the item that was hit
  383. tvi.iImage = IDRADIOON;
  384. tvi.iSelectedImage = IDRADIOON;
  385. //See if we need to add status text
  386. if (bScreenReaderEnabled)
  387. {
  388. AppendStatus(szText,ARRAYSIZE(szText), TRUE);
  389. }
  390. }
  391. // change only if it is a checkbox or radio item
  392. if (tvi.iImage <= IDUNKNOWN)
  393. {
  394. TreeView_SetItem(_hwndTree, &tvi);
  395. }
  396. }
  397. return S_OK;
  398. }
  399. HRESULT CRegTreeOptions::ShowHelp(HTREEITEM hti, DWORD dwFlags)
  400. {
  401. TV_ITEM tvi;
  402. tvi.mask = TVIF_HANDLE | TVIF_PARAM;
  403. tvi.hItem = hti;
  404. if (hti && TreeView_GetItem(_hwndTree, &tvi))
  405. {
  406. HUSKEY huskey = (HUSKEY)tvi.lParam;
  407. TCHAR szHelpID[MAX_PATH+10]; // max path for helpfile + 10 for the help id
  408. DWORD cbHelpID = sizeof(szHelpID);
  409. if (SHRegQueryUSValue(huskey, c_szHelpID, NULL, szHelpID, &cbHelpID, FALSE, NULL, 0) == ERROR_SUCCESS)
  410. {
  411. LPTSTR psz = StrChr(szHelpID, TEXT('#'));
  412. if (psz)
  413. {
  414. DWORD mapIDCToIDH[4];
  415. *psz++ = 0; // NULL the '#'
  416. mapIDCToIDH[0] = GetDlgCtrlID(_hwndTree);
  417. mapIDCToIDH[1] = StrToInt(psz);
  418. mapIDCToIDH[2] = 0;
  419. mapIDCToIDH[3] = 0;
  420. SHWinHelpOnDemandWrap(_hwndTree, szHelpID, dwFlags, (DWORD_PTR)mapIDCToIDH);
  421. return S_OK;
  422. }
  423. }
  424. }
  425. return E_FAIL;
  426. }
  427. int CRegTreeOptions::_DefaultIconImage(HUSKEY huskey, int iImage)
  428. {
  429. TCHAR szIcon[MAX_PATH + 10]; // 10 = ",XXXX" plus some more
  430. DWORD cb = sizeof(szIcon);
  431. if (ERROR_SUCCESS == SHRegQueryUSValue(huskey, c_szDefaultBitmap, NULL, szIcon, &cb, FALSE, NULL, 0))
  432. {
  433. LPTSTR psz = StrRChr(szIcon, szIcon + lstrlen(szIcon), TEXT(','));
  434. ASSERT(psz); // shouldn't be zero
  435. if (!psz)
  436. return iImage;
  437. *psz++ = 0; // terminate and move over
  438. int image = StrToInt(psz); // get ID
  439. HICON hicon = NULL;
  440. if (!*szIcon)
  441. {
  442. hicon = (HICON)LoadIcon(g_hinst, (LPCTSTR)(INT_PTR)image);
  443. }
  444. else
  445. {
  446. // get the bitmap from the library
  447. ExtractIconEx(szIcon, (UINT)(-1*image), NULL, &hicon, 1);
  448. if (!hicon)
  449. ExtractIconEx(szIcon, (UINT)(-1*image), &hicon, NULL, 1);
  450. }
  451. if (hicon)
  452. {
  453. iImage = ImageList_AddIcon(_hIml, (HICON)hicon);
  454. // NOTE: The docs say you don't need to do a delete object on icons loaded by LoadIcon, but
  455. // you do for CreateIcon. It doesn't say what to do for ExtractIcon, so we'll just call it anyway.
  456. DestroyIcon(hicon);
  457. }
  458. }
  459. return iImage;
  460. }
  461. //
  462. // The CLSID can either be a service ID (which we will QS for) or a CLSID
  463. // that we CoCreateInstance.
  464. //
  465. DWORD CRegTreeOptions::_GetSetByCLSID(REFCLSID clsid, BOOL* pbData, BOOL fGet)
  466. {
  467. IRegTreeItem *pti;
  468. HRESULT hr;
  469. if (SUCCEEDED(hr = IUnknown_QueryService(_punkSite, clsid, IID_PPV_ARG(IRegTreeItem, &pti))) ||
  470. SUCCEEDED(hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IRegTreeItem, &pti))))
  471. {
  472. hr = fGet ? pti->GetCheckState(pbData) : pti->SetCheckState(*pbData);
  473. pti->Release();
  474. }
  475. return SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_BAD_FORMAT;
  476. }
  477. DWORD CRegTreeOptions::_GetSetByRegKey(HUSKEY husKey, DWORD *pType, LPBYTE pData, DWORD *pcbData, REG_CMD cmd)
  478. {
  479. // support for masks
  480. DWORD dwMask;
  481. DWORD cb = sizeof(dwMask);
  482. dwMask = 0xFFFFFFFF; // Default value
  483. BOOL fMask = (SHRegQueryUSValue(husKey, c_szMask, NULL, &dwMask, &cb, FALSE, NULL, 0) == ERROR_SUCCESS);
  484. // support for structures
  485. DWORD dwOffset;
  486. cb = sizeof(dwOffset);
  487. dwOffset = 0; // Default value
  488. BOOL fOffset = (SHRegQueryUSValue(husKey, c_szOffset, NULL, &dwOffset, &cb, FALSE, NULL, 0) == ERROR_SUCCESS);
  489. HKEY hkRoot = HKEY_CURRENT_USER; // Preinitialize to keep Win64 happy
  490. cb = sizeof(DWORD); // DWORD, not sizeof(HKEY) or Win64 will get mad
  491. DWORD dwError = SHRegQueryUSValue(husKey, c_szHKeyRoot, NULL, &hkRoot, &cb, FALSE, NULL, 0);
  492. hkRoot = (HKEY) LongToHandle(HandleToLong(hkRoot));
  493. if (dwError != ERROR_SUCCESS)
  494. {
  495. // use default
  496. hkRoot = HKEY_CURRENT_USER;
  497. }
  498. // allow "RegPath9x" to override "RegPath" when running on Win9x
  499. TCHAR szPath[MAX_PATH];
  500. cb = sizeof(szPath);
  501. if (!g_fRunningOnNT)
  502. {
  503. dwError = SHRegQueryUSValue(husKey, TEXT("RegPath9x"), NULL, szPath, &cb, FALSE, NULL, 0);
  504. if (ERROR_SUCCESS != dwError)
  505. {
  506. cb = sizeof(szPath);
  507. dwError = SHRegQueryUSValue(husKey, TEXT("RegPath"), NULL, szPath, &cb, FALSE, NULL, 0);
  508. }
  509. }
  510. else
  511. {
  512. dwError = SHRegQueryUSValue(husKey, TEXT("RegPath"), NULL, szPath, &cb, FALSE, NULL, 0);
  513. }
  514. TCHAR szBuf[MAX_PATH];
  515. LPTSTR pszPath;
  516. if (ERROR_SUCCESS == dwError)
  517. {
  518. if (_pszParam)
  519. {
  520. HRESULT hr = StringCchPrintf(szBuf, ARRAYSIZE(szBuf), szPath, _pszParam);
  521. if (FAILED(hr))
  522. {
  523. return ERROR_INSUFFICIENT_BUFFER;
  524. }
  525. pszPath = szBuf;
  526. }
  527. else
  528. {
  529. pszPath = szPath;
  530. }
  531. }
  532. else
  533. {
  534. if (cmd == REG_GET)
  535. return SHRegQueryUSValue(husKey, c_szDefaultValue, pType, pData, pcbData, FALSE, NULL, 0);
  536. else
  537. return dwError;
  538. }
  539. TCHAR szName[MAX_PATH];
  540. cb = sizeof(szName);
  541. dwError = SHRegQueryUSValue(husKey, c_szValueName, NULL, szName, &cb, FALSE, NULL, 0);
  542. if (dwError == ERROR_SUCCESS)
  543. {
  544. HKEY hKeyReal;
  545. DWORD dw;
  546. REGSAM samDesired = KEY_QUERY_VALUE;
  547. if (cmd == REG_SET)
  548. {
  549. samDesired |= KEY_SET_VALUE;
  550. }
  551. dwError = RegCreateKeyEx(hkRoot, pszPath, 0, NULL, 0, samDesired, NULL, &hKeyReal, &dw);
  552. if (dwError == ERROR_SUCCESS)
  553. {
  554. switch (cmd)
  555. {
  556. case REG_SET:
  557. if (fOffset || fMask)
  558. {
  559. DWORD cbData;
  560. // Note: It so happens that the Valuename maynot be in the registry so we
  561. // to make sure that we have the valuename already in the registry.
  562. //Try to do a SHRegQueryValue
  563. dwError = SHQueryValueEx(hKeyReal, szName, NULL, NULL, NULL, &cbData);
  564. //Does the Value exists ?
  565. if (dwError == ERROR_FILE_NOT_FOUND)
  566. {
  567. //We dont have the Valuename in the registry so create it.
  568. DWORD dwTypeDefault, dwDefault, cbDefault = sizeof(dwDefault);
  569. dwError = SHRegQueryUSValue(husKey, c_szDefaultValue, &dwTypeDefault, &dwDefault, &cbDefault, FALSE, NULL, 0);
  570. //This should succeed . if not then someone messed up the registry setting
  571. if (dwError == ERROR_SUCCESS)
  572. {
  573. dwError = SHSetValue(hKeyReal, NULL, szName, dwTypeDefault, &dwDefault, cbDefault);
  574. //By setting this value we dont have to do the failed (see above) Query again
  575. cbData = cbDefault;
  576. }
  577. }
  578. // Now we know for sure that the value exists in the registry.
  579. // Do the usual stuff.
  580. // grab the size of the entry
  581. if (dwError == ERROR_SUCCESS)
  582. {
  583. // alloc enough space for it
  584. DWORD *pdwData = (DWORD *)LocalAlloc(LPTR, cbData);
  585. if (pdwData)
  586. {
  587. // get the data
  588. dwError = SHQueryValueEx(hKeyReal, szName, NULL, pType, pdwData, &cbData);
  589. if (dwError == ERROR_SUCCESS && dwOffset < cbData / sizeof(DWORD))
  590. {
  591. // NOTE: offset defaults to 0 and mask defaults to 0xffffffff, so if there's only
  592. // a mask or only an offset, we'll do the right thing
  593. *(pdwData + dwOffset) &= ~dwMask; // clear the bits
  594. *(pdwData + dwOffset) |= *((DWORD *)pData); // set the bits
  595. dwError = SHSetValue(hKeyReal, NULL, szName, *pType, pdwData, cbData);
  596. }
  597. LocalFree(pdwData);
  598. }
  599. else
  600. return ERROR_NOT_ENOUGH_MEMORY;
  601. }
  602. }
  603. else
  604. {
  605. dwError = SHSetValue(hKeyReal, NULL, szName, *pType, pData, *pcbData);
  606. }
  607. break;
  608. case REG_GET:
  609. // grab the value that we have
  610. if (fOffset)
  611. {
  612. DWORD cbData;
  613. if (SHQueryValueEx(hKeyReal, szName, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS)
  614. {
  615. DWORD *pdwData = (DWORD*)LocalAlloc(LPTR, cbData);
  616. if (pdwData)
  617. {
  618. dwError = SHQueryValueEx(hKeyReal, szName, NULL, pType, pdwData, &cbData);
  619. if (dwOffset < cbData / sizeof(DWORD))
  620. *((DWORD *)pData) = *(pdwData + dwOffset);
  621. else
  622. *((DWORD *)pData) = 0; // Invalid offset, return something vague
  623. *pcbData = sizeof(DWORD);
  624. LocalFree(pdwData);
  625. }
  626. else
  627. return ERROR_NOT_ENOUGH_MEMORY;
  628. }
  629. }
  630. else
  631. {
  632. dwError = SHQueryValueEx(hKeyReal, szName, NULL, pType, pData, pcbData);
  633. }
  634. if ((dwError == ERROR_SUCCESS) && fMask)
  635. {
  636. *((DWORD *)pData) &= dwMask;
  637. }
  638. break;
  639. }
  640. RegCloseKey(hKeyReal);
  641. }
  642. }
  643. if ((cmd == REG_GET) && (dwError != ERROR_SUCCESS))
  644. {
  645. // get the default setting
  646. dwError = SHRegQueryUSValue(husKey, c_szDefaultValue, pType, pData, pcbData, FALSE, NULL, 0);
  647. }
  648. return dwError;
  649. }
  650. DWORD CRegTreeOptions::_RegGetSetSetting(HUSKEY husKey, DWORD *pType, LPBYTE pData, DWORD *pcbData, REG_CMD cmd)
  651. {
  652. UINT uiAction;
  653. DWORD cbAction = sizeof(uiAction);
  654. TCHAR szCLSID[80];
  655. DWORD cbCLSID = sizeof(szCLSID);
  656. if (cmd == REG_GETDEFAULT)
  657. {
  658. return SHRegQueryUSValue(husKey, c_szDefaultValue, pType, pData, pcbData, FALSE, NULL, 0);
  659. }
  660. else if (SHRegQueryUSValue(husKey, (cmd == REG_GET) ? c_szSPIActionGet : c_szSPIActionSet,
  661. NULL, &uiAction, &cbAction, FALSE, NULL, 0) == ERROR_SUCCESS)
  662. {
  663. *pcbData = sizeof(DWORD);
  664. *pType = REG_DWORD;
  665. SHBoolSystemParametersInfo(uiAction, (DWORD*)pData);
  666. return ERROR_SUCCESS;
  667. }
  668. else if (SHRegQueryUSValue(husKey, c_szCLSID, NULL, &szCLSID, &cbCLSID, FALSE, NULL, 0) == ERROR_SUCCESS)
  669. {
  670. *pcbData = sizeof(DWORD);
  671. *pType = REG_DWORD;
  672. CLSID clsid;
  673. GUIDFromString(szCLSID, &clsid);
  674. return _GetSetByCLSID(clsid, (BOOL*)pData, (cmd == REG_GET));
  675. }
  676. else
  677. {
  678. return _GetSetByRegKey(husKey, pType, pData, pcbData, cmd);
  679. }
  680. }
  681. DWORD CRegTreeOptions::_GetCheckStatus(HUSKEY huskey, BOOL *pbChecked, BOOL bUseDefault)
  682. {
  683. DWORD dwError, cbData, dwType;
  684. BYTE rgData[32];
  685. DWORD cbDataCHK, dwTypeCHK;
  686. BYTE rgDataCHK[32];
  687. BOOL bCompCHK = TRUE;
  688. // first, get the setting from the specified location.
  689. cbData = sizeof(rgData);
  690. dwError = _RegGetSetSetting(huskey, &dwType, rgData, &cbData, bUseDefault ? REG_GETDEFAULT : REG_GET);
  691. if (dwError == ERROR_SUCCESS)
  692. {
  693. // second, get the value for the "checked" state and compare.
  694. cbDataCHK = sizeof(rgDataCHK);
  695. dwError = SHRegQueryUSValue(huskey, c_szCheckedValue, &dwTypeCHK, rgDataCHK, &cbDataCHK, FALSE, NULL, 0);
  696. if (dwError != ERROR_SUCCESS)
  697. {
  698. // ok, we couldn't find the "checked" value, is it because
  699. // it's platform dependent?
  700. cbDataCHK = sizeof(rgDataCHK);
  701. dwError = SHRegQueryUSValue(huskey,
  702. g_fRunningOnNT ? c_szCheckedValueNT : c_szCheckedValueW95,
  703. &dwTypeCHK, rgDataCHK, &cbDataCHK, FALSE, NULL, 0);
  704. }
  705. if (dwError == ERROR_SUCCESS)
  706. {
  707. // make sure two value types match.
  708. if ((dwType != dwTypeCHK) &&
  709. (((dwType == REG_BINARY) && (dwTypeCHK == REG_DWORD) && (cbData != 4))
  710. || ((dwType == REG_DWORD) && (dwTypeCHK == REG_BINARY) && (cbDataCHK != 4))))
  711. return ERROR_BAD_FORMAT;
  712. switch (dwType) {
  713. case REG_DWORD:
  714. *pbChecked = (*((DWORD*)rgData) == *((DWORD*)rgDataCHK));
  715. break;
  716. case REG_SZ:
  717. if (cbData == cbDataCHK)
  718. *pbChecked = !lstrcmp((LPTSTR)rgData, (LPTSTR)rgDataCHK);
  719. else
  720. *pbChecked = FALSE;
  721. break;
  722. case REG_BINARY:
  723. if (cbData == cbDataCHK)
  724. *pbChecked = !memcmp(rgData, rgDataCHK, cbData);
  725. else
  726. *pbChecked = FALSE;
  727. break;
  728. default:
  729. return ERROR_BAD_FORMAT;
  730. }
  731. }
  732. }
  733. return dwError;
  734. }
  735. DWORD CRegTreeOptions::_SaveCheckStatus(HUSKEY huskey, BOOL bChecked)
  736. {
  737. DWORD dwError, cbData, dwType;
  738. BYTE rgData[32];
  739. cbData = sizeof(rgData);
  740. dwError = SHRegQueryUSValue(huskey, bChecked ? c_szCheckedValue : c_szUncheckedValue, &dwType, rgData, &cbData, FALSE, NULL, 0);
  741. if (dwError != ERROR_SUCCESS) // was it because of a platform specific value?
  742. {
  743. cbData = sizeof(rgData);
  744. dwError = SHRegQueryUSValue(huskey, bChecked ? (g_fRunningOnNT ? c_szCheckedValueNT : c_szCheckedValueW95) : c_szUncheckedValue,
  745. &dwType, rgData, &cbData, FALSE, NULL, 0);
  746. }
  747. if (dwError == ERROR_SUCCESS)
  748. {
  749. dwError = _RegGetSetSetting(huskey, &dwType, rgData, &cbData, REG_SET);
  750. }
  751. return dwError;
  752. }
  753. HTREEITEM Tree_AddItem(HTREEITEM hParent, LPTSTR pszText, HTREEITEM hInsAfter,
  754. int iImage, HWND hwndTree, HUSKEY huskey, BOOL *pbExisted)
  755. {
  756. HTREEITEM hItem;
  757. TV_ITEM tvI;
  758. TV_INSERTSTRUCT tvIns;
  759. TCHAR szText[MAX_URL_STRING];
  760. ASSERT(pszText != NULL);
  761. HRESULT hr = StringCchCopy(szText, ARRAYSIZE(szText), pszText);
  762. if (FAILED(hr))
  763. {
  764. return NULL;
  765. }
  766. // NOTE:
  767. // This code segment is disabled because we only enum explorer
  768. // tree in HKCU, so there won't be any duplicates.
  769. // Re-able this code if we start to also enum HKLM that could potentially
  770. // result in duplicates.
  771. // We only want to add an item if it is not already there.
  772. // We do this to handle reading out of HKCU and HKLM.
  773. //
  774. TCHAR szKeyName[MAX_KEY_NAME];
  775. tvI.mask = TVIF_HANDLE | TVIF_TEXT;
  776. tvI.pszText = szKeyName;
  777. tvI.cchTextMax = ARRAYSIZE(szKeyName);
  778. for (hItem = TreeView_GetChild(hwndTree, hParent);
  779. hItem != NULL;
  780. hItem = TreeView_GetNextSibling(hwndTree, hItem)
  781. )
  782. {
  783. tvI.hItem = hItem;
  784. if (TreeView_GetItem(hwndTree, &tvI))
  785. {
  786. if (!StrCmp(tvI.pszText, szText))
  787. {
  788. // We found a match!
  789. //
  790. *pbExisted = TRUE;
  791. return hItem;
  792. }
  793. }
  794. }
  795. // Create the item
  796. tvI.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  797. tvI.iImage = iImage;
  798. tvI.iSelectedImage = iImage;
  799. tvI.pszText = szText;
  800. tvI.cchTextMax = lstrlen(szText);
  801. // lParam contains the HUSKEY for this item:
  802. tvI.lParam = (LPARAM)huskey;
  803. // Create insert item
  804. tvIns.item = tvI;
  805. tvIns.hInsertAfter = hInsAfter;
  806. tvIns.hParent = hParent;
  807. // Insert the item into the tree.
  808. hItem = (HTREEITEM) SendMessage(hwndTree, TVM_INSERTITEM, 0,
  809. (LPARAM)(LPTV_INSERTSTRUCT)&tvIns);
  810. *pbExisted = FALSE;
  811. return (hItem);
  812. }
  813. BOOL _IsValidKey(HKEY hkeyRoot, LPCTSTR pszSubKey, LPCTSTR pszValue)
  814. {
  815. TCHAR szPath[MAX_PATH];
  816. DWORD dwType, cbSize = sizeof(szPath);
  817. if (ERROR_SUCCESS == SHGetValue(hkeyRoot, pszSubKey, pszValue, &dwType, szPath, &cbSize))
  818. {
  819. // Zero in the DWORD case or NULL in the string case
  820. // indicates that this item is not available.
  821. if (dwType == REG_DWORD)
  822. return *((DWORD *)szPath) != 0;
  823. else
  824. return szPath[0] != 0;
  825. }
  826. return FALSE;
  827. }
  828. #define REGSTR_POLICIES_EXPLORER TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer")
  829. BOOL CRegTreeOptions::_RegIsRestricted(HUSKEY hussubkey)
  830. {
  831. HUSKEY huskey;
  832. BOOL fRet = FALSE;
  833. // Does a "Policy" Sub key exist?
  834. if (SHRegOpenUSKey(TEXT("Policy"), KEY_ENUMERATE_SUB_KEYS, hussubkey, &huskey, FALSE) == ERROR_SUCCESS)
  835. {
  836. // Yes; Enumerate this key. The Values are Policy keys or
  837. // Full reg paths.
  838. DWORD cb;
  839. TCHAR szKeyName[MAX_KEY_NAME];
  840. for (int i=0;
  841. cb = ARRAYSIZE(szKeyName),
  842. ERROR_SUCCESS == SHRegEnumUSKey(huskey, i, szKeyName, &cb, SHREGENUM_HKLM)
  843. && !fRet; i++)
  844. {
  845. TCHAR szPath[MAXIMUM_SUB_KEY_LENGTH];
  846. DWORD dwType, cbSize = sizeof(szPath);
  847. HUSKEY huskeyTemp;
  848. if (ERROR_SUCCESS == SHRegOpenUSKey(szKeyName, KEY_QUERY_VALUE, huskey, &huskeyTemp, FALSE))
  849. {
  850. if (ERROR_SUCCESS == SHRegQueryUSValue(huskeyTemp, TEXT("RegKey"), &dwType, szPath, &cbSize, FALSE, NULL, 0))
  851. {
  852. if (_IsValidKey(HKEY_LOCAL_MACHINE, szPath, szKeyName))
  853. {
  854. fRet = TRUE;
  855. break;
  856. }
  857. }
  858. SHRegCloseUSKey(huskeyTemp);
  859. }
  860. // It's not a full Key, try off of policies
  861. if (_IsValidKey(HKEY_LOCAL_MACHINE, REGSTR_POLICIES_EXPLORER, szKeyName) ||
  862. _IsValidKey(HKEY_CURRENT_USER, REGSTR_POLICIES_EXPLORER, szKeyName))
  863. {
  864. fRet = TRUE;
  865. break;
  866. }
  867. }
  868. SHRegCloseUSKey(huskey);
  869. }
  870. return fRet;
  871. }
  872. void CRegTreeOptions::_RegEnumTree(HUSKEY huskey, HTREEITEM htviparent, HTREEITEM htvins)
  873. {
  874. TCHAR szKeyName[MAX_KEY_NAME];
  875. DWORD cb;
  876. BOOL bScreenReaderEnabled = IsScreenReaderEnabled();
  877. // we must search all the sub-keys
  878. for (int i=0; // always start with 0
  879. cb=ARRAYSIZE(szKeyName), // string size
  880. ERROR_SUCCESS == SHRegEnumUSKey(huskey, i, szKeyName, &cb, SHREGENUM_HKLM);
  881. i++) // get next entry
  882. {
  883. HUSKEY hussubkey;
  884. // get more info on the entry
  885. if (ERROR_SUCCESS == SHRegOpenUSKey(szKeyName, KEY_QUERY_VALUE, huskey, &hussubkey, FALSE))
  886. {
  887. HUSKEY huskeySave = NULL;
  888. if (!_RegIsRestricted(hussubkey))
  889. {
  890. TCHAR szTemp[MAX_PATH];
  891. // Get the type of items under this root
  892. cb = ARRAYSIZE(szTemp);
  893. if (ERROR_SUCCESS == SHRegQueryUSValue(hussubkey, c_szType, NULL, szTemp, &cb, FALSE, NULL, 0))
  894. {
  895. int iImage;
  896. BOOL bChecked;
  897. DWORD dwError = ERROR_SUCCESS;
  898. // get the type of node
  899. DWORD dwTreeType = RegTreeType(szTemp);
  900. // get some more info about the this item
  901. switch (dwTreeType)
  902. {
  903. case TREE_GROUP:
  904. iImage = _DefaultIconImage(hussubkey, IDUNKNOWN);
  905. huskeySave = hussubkey;
  906. break;
  907. case TREE_CHECKBOX:
  908. dwError = _GetCheckStatus(hussubkey, &bChecked, FALSE);
  909. if (dwError == ERROR_SUCCESS)
  910. {
  911. iImage = bChecked ? IDCHECKED : IDUNCHECKED;
  912. huskeySave = hussubkey;
  913. }
  914. break;
  915. case TREE_RADIO:
  916. dwError = _GetCheckStatus(hussubkey, &bChecked, FALSE);
  917. if (dwError == ERROR_SUCCESS)
  918. {
  919. iImage = bChecked ? IDRADIOON : IDRADIOOFF;
  920. huskeySave = hussubkey;
  921. }
  922. break;
  923. default:
  924. dwError = ERROR_INVALID_PARAMETER;
  925. }
  926. if (dwError == ERROR_SUCCESS)
  927. {
  928. BOOL bItemExisted = FALSE;
  929. LPTSTR pszText;
  930. // try to get the plugUI enabled text
  931. // otherwise we want the old data from a
  932. // different value
  933. int cch = ARRAYSIZE(szTemp);
  934. HRESULT hr = _LoadUSRegUIString(hussubkey, c_szPlugUIText, szTemp, cch);
  935. if (SUCCEEDED(hr) && szTemp[0] != TEXT('@'))
  936. {
  937. pszText = szTemp;
  938. }
  939. else
  940. {
  941. // try to get the old non-plugUI enabled text
  942. hr = _LoadUSRegUIString(hussubkey, c_szText, szTemp, cch);
  943. if (SUCCEEDED(hr))
  944. {
  945. pszText = szTemp;
  946. }
  947. else
  948. {
  949. // if all else fails, the key name itself
  950. // is a little more useful than garbage
  951. pszText = szKeyName;
  952. cch = ARRAYSIZE(szKeyName);
  953. }
  954. }
  955. //See if we need to add status text
  956. if (bScreenReaderEnabled && (dwTreeType != TREE_GROUP))
  957. {
  958. AppendStatus(pszText, cch, bChecked);
  959. }
  960. // add root node
  961. HTREEITEM htviroot = Tree_AddItem(htviparent, pszText, htvins, iImage, _hwndTree, huskeySave, &bItemExisted);
  962. if (htviroot != NULL)
  963. {
  964. if (bItemExisted)
  965. huskeySave = NULL;
  966. if (dwTreeType == TREE_GROUP)
  967. {
  968. HUSKEY huskeySubTree;
  969. if (ERROR_SUCCESS == SHRegOpenUSKey(szKeyName, KEY_ENUMERATE_SUB_KEYS, huskey, &huskeySubTree, FALSE))
  970. {
  971. _RegEnumTree(huskeySubTree, htviroot, TVI_FIRST);
  972. SHRegCloseUSKey(huskeySubTree);
  973. }
  974. TreeView_Expand(_hwndTree, htviroot, TVE_EXPAND);
  975. }
  976. }
  977. } // if (dwError == ERROR_SUCCESS
  978. }
  979. } // if (!_RegIsRestricted(hsubkey))
  980. if (huskeySave != hussubkey)
  981. SHRegCloseUSKey(hussubkey);
  982. }
  983. }
  984. // Sort all keys under htviparent
  985. SendMessage(_hwndTree, TVM_SORTCHILDREN, 0, (LPARAM)htviparent);
  986. }
  987. BOOL CRegTreeOptions::_WalkTreeRecursive(HTREEITEM htvi, WALK_TREE_CMD cmd)
  988. {
  989. // step through the children
  990. HTREEITEM hctvi = TreeView_GetChild(_hwndTree, htvi);
  991. while (hctvi)
  992. {
  993. _WalkTreeRecursive(hctvi, cmd);
  994. hctvi = TreeView_GetNextSibling(_hwndTree, hctvi);
  995. }
  996. TV_ITEM tvi = {0};
  997. // get ourselves
  998. tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  999. tvi.hItem = htvi;
  1000. TreeView_GetItem(_hwndTree, &tvi);
  1001. HUSKEY huskey;
  1002. switch (cmd)
  1003. {
  1004. case WALK_TREE_DELETE:
  1005. // if we are destroying the tree...
  1006. // do we have something to clean up?
  1007. if (tvi.lParam)
  1008. {
  1009. // close the reg key
  1010. SHRegCloseUSKey((HUSKEY)tvi.lParam);
  1011. }
  1012. break;
  1013. case WALK_TREE_SAVE:
  1014. huskey = (HUSKEY)tvi.lParam;
  1015. // now save ourselves (if needed)
  1016. // what are we?
  1017. if (tvi.iImage == IDCHECKED || tvi.iImage == IDRADIOON)
  1018. {
  1019. // checkbox or radio that is checked
  1020. _SaveCheckStatus(huskey, TRUE);
  1021. }
  1022. else if (tvi.iImage == IDUNCHECKED)
  1023. {
  1024. // checkbox that is unchecked
  1025. _SaveCheckStatus(huskey, FALSE);
  1026. }
  1027. // else radio that is "off" is ignored
  1028. // else icons are ignored
  1029. break;
  1030. case WALK_TREE_RESTORE:
  1031. case WALK_TREE_REFRESH:
  1032. huskey = (HUSKEY)tvi.lParam;
  1033. if ((tvi.iImage == IDCHECKED) ||
  1034. (tvi.iImage == IDUNCHECKED) ||
  1035. (tvi.iImage == IDRADIOON) ||
  1036. (tvi.iImage == IDRADIOOFF))
  1037. {
  1038. BOOL bChecked = FALSE;
  1039. _GetCheckStatus(huskey, &bChecked, cmd == WALK_TREE_RESTORE ? TRUE : FALSE);
  1040. tvi.iImage = (tvi.iImage == IDCHECKED) || (tvi.iImage == IDUNCHECKED) ?
  1041. (bChecked ? IDCHECKED : IDUNCHECKED) :
  1042. (bChecked ? IDRADIOON : IDRADIOOFF);
  1043. tvi.iSelectedImage = tvi.iImage;
  1044. TreeView_SetItem(_hwndTree, &tvi);
  1045. }
  1046. break;
  1047. }
  1048. return TRUE; // success?
  1049. }
  1050. DWORD RegTreeType(LPCTSTR pszType)
  1051. {
  1052. for (int i = 0; i < ARRAYSIZE(c_aTreeTypes); i++)
  1053. {
  1054. if (!lstrcmpi(pszType, c_aTreeTypes[i].name))
  1055. return c_aTreeTypes[i].type;
  1056. }
  1057. return TREE_UNKNOWN;
  1058. }
  1059. BOOL AppendStatus(LPTSTR pszText,UINT cchText, BOOL fOn)
  1060. {
  1061. LPTSTR pszTemp;
  1062. UINT cchStrLen , cchStatusLen;
  1063. //if there's no string specified then return
  1064. if (!pszText)
  1065. return FALSE;
  1066. //Calculate the string lengths
  1067. cchStrLen = lstrlen(pszText);
  1068. cchStatusLen = fOn ? lstrlen(TEXT("-ON")) : lstrlen(TEXT("-OFF"));
  1069. //Remove the old status appended
  1070. pszTemp = StrRStrI(pszText,pszText + cchStrLen, TEXT("-ON"));
  1071. if(pszTemp)
  1072. {
  1073. *pszTemp = (TCHAR)0;
  1074. cchStrLen = lstrlen(pszText);
  1075. }
  1076. pszTemp = StrRStrI(pszText,pszText + cchStrLen, TEXT("-OFF"));
  1077. if(pszTemp)
  1078. {
  1079. *pszTemp = (TCHAR)0;
  1080. cchStrLen = lstrlen(pszText);
  1081. }
  1082. //check if we append status text, we'll explode or not
  1083. if (cchStrLen + cchStatusLen > cchText)
  1084. {
  1085. //We'll explode
  1086. return FALSE;
  1087. }
  1088. if (fOn)
  1089. {
  1090. StringCchCat(pszText, cchText, TEXT("-ON"));
  1091. }
  1092. else
  1093. {
  1094. StringCchCat(pszText, cchText, TEXT("-OFF"));
  1095. }
  1096. return TRUE;
  1097. }
  1098. BOOL IsScreenReaderEnabled()
  1099. {
  1100. BOOL bRet = FALSE;
  1101. SystemParametersInfoA(SPI_GETSCREENREADER, 0, &bRet, 0);
  1102. return bRet;
  1103. }