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.

1281 lines
42 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 cbText, 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_READ, 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_ALL, 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. wnsprintf(szBuf, ARRAYSIZE(szBuf), szPath, _pszParam);
  521. pszPath = szBuf;
  522. }
  523. else
  524. {
  525. pszPath = szPath;
  526. }
  527. }
  528. else
  529. {
  530. if (cmd == REG_GET)
  531. return SHRegQueryUSValue(husKey, c_szDefaultValue, pType, pData, pcbData, FALSE, NULL, 0);
  532. else
  533. return dwError;
  534. }
  535. TCHAR szName[MAX_PATH];
  536. cb = sizeof(szName);
  537. dwError = SHRegQueryUSValue(husKey, c_szValueName, NULL, szName, &cb, FALSE, NULL, 0);
  538. if (dwError == ERROR_SUCCESS)
  539. {
  540. HKEY hKeyReal;
  541. DWORD dw;
  542. dwError = RegCreateKeyEx(hkRoot, pszPath, 0, NULL, 0, KEY_READ | KEY_WRITE, NULL, &hKeyReal, &dw);
  543. if (dwError == ERROR_SUCCESS)
  544. {
  545. switch (cmd)
  546. {
  547. case REG_SET:
  548. if (fOffset || fMask)
  549. {
  550. DWORD cbData;
  551. // Note: It so happens that the Valuename maynot be in the registry so we
  552. // to make sure that we have the valuename already in the registry.
  553. //Try to do a SHRegQueryValue
  554. dwError = SHQueryValueEx(hKeyReal, szName, NULL, NULL, NULL, &cbData);
  555. //Does the Value exists ?
  556. if (dwError == ERROR_FILE_NOT_FOUND)
  557. {
  558. //We dont have the Valuename in the registry so create it.
  559. DWORD dwTypeDefault, dwDefault, cbDefault = sizeof(dwDefault);
  560. dwError = SHRegQueryUSValue(husKey, c_szDefaultValue, &dwTypeDefault, &dwDefault, &cbDefault, FALSE, NULL, 0);
  561. //This should succeed . if not then someone messed up the registry setting
  562. if (dwError == ERROR_SUCCESS)
  563. {
  564. dwError = SHSetValue(hKeyReal, NULL, szName, dwTypeDefault, &dwDefault, cbDefault);
  565. //By setting this value we dont have to do the failed (see above) Query again
  566. cbData = cbDefault;
  567. }
  568. }
  569. // Now we know for sure that the value exists in the registry.
  570. // Do the usual stuff.
  571. // grab the size of the entry
  572. if (dwError == ERROR_SUCCESS)
  573. {
  574. // alloc enough space for it
  575. DWORD *pdwData = (DWORD *)LocalAlloc(LPTR, cbData);
  576. if (pdwData)
  577. {
  578. // get the data
  579. dwError = SHQueryValueEx(hKeyReal, szName, NULL, pType, pdwData, &cbData);
  580. if (dwError == ERROR_SUCCESS && dwOffset < cbData / sizeof(DWORD))
  581. {
  582. // NOTE: offset defaults to 0 and mask defaults to 0xffffffff, so if there's only
  583. // a mask or only an offset, we'll do the right thing
  584. *(pdwData + dwOffset) &= ~dwMask; // clear the bits
  585. *(pdwData + dwOffset) |= *((DWORD *)pData); // set the bits
  586. dwError = SHSetValue(hKeyReal, NULL, szName, *pType, pdwData, cbData);
  587. }
  588. LocalFree(pdwData);
  589. }
  590. else
  591. return ERROR_NOT_ENOUGH_MEMORY;
  592. }
  593. }
  594. else
  595. {
  596. dwError = SHSetValue(hKeyReal, NULL, szName, *pType, pData, *pcbData);
  597. }
  598. break;
  599. case REG_GET:
  600. // grab the value that we have
  601. if (fOffset)
  602. {
  603. DWORD cbData;
  604. if (SHQueryValueEx(hKeyReal, szName, NULL, NULL, NULL, &cbData) == ERROR_SUCCESS)
  605. {
  606. DWORD *pdwData = (DWORD*)LocalAlloc(LPTR, cbData);
  607. if (pdwData)
  608. {
  609. dwError = SHQueryValueEx(hKeyReal, szName, NULL, pType, pdwData, &cbData);
  610. if (dwOffset < cbData / sizeof(DWORD))
  611. *((DWORD *)pData) = *(pdwData + dwOffset);
  612. else
  613. *((DWORD *)pData) = 0; // Invalid offset, return something vague
  614. *pcbData = sizeof(DWORD);
  615. LocalFree(pdwData);
  616. }
  617. else
  618. return ERROR_NOT_ENOUGH_MEMORY;
  619. }
  620. }
  621. else
  622. {
  623. dwError = SHQueryValueEx(hKeyReal, szName, NULL, pType, pData, pcbData);
  624. }
  625. if ((dwError == ERROR_SUCCESS) && fMask)
  626. {
  627. *((DWORD *)pData) &= dwMask;
  628. }
  629. break;
  630. }
  631. RegCloseKey(hKeyReal);
  632. }
  633. }
  634. if ((cmd == REG_GET) && (dwError != ERROR_SUCCESS))
  635. {
  636. // get the default setting
  637. dwError = SHRegQueryUSValue(husKey, c_szDefaultValue, pType, pData, pcbData, FALSE, NULL, 0);
  638. }
  639. return dwError;
  640. }
  641. DWORD CRegTreeOptions::_RegGetSetSetting(HUSKEY husKey, DWORD *pType, LPBYTE pData, DWORD *pcbData, REG_CMD cmd)
  642. {
  643. UINT uiAction;
  644. DWORD cbAction = sizeof(uiAction);
  645. TCHAR szCLSID[80];
  646. DWORD cbCLSID = sizeof(szCLSID);
  647. if (cmd == REG_GETDEFAULT)
  648. {
  649. return SHRegQueryUSValue(husKey, c_szDefaultValue, pType, pData, pcbData, FALSE, NULL, 0);
  650. }
  651. else if (SHRegQueryUSValue(husKey, (cmd == REG_GET) ? c_szSPIActionGet : c_szSPIActionSet,
  652. NULL, &uiAction, &cbAction, FALSE, NULL, 0) == ERROR_SUCCESS)
  653. {
  654. *pcbData = sizeof(DWORD);
  655. *pType = REG_DWORD;
  656. SHBoolSystemParametersInfo(uiAction, (DWORD*)pData);
  657. return ERROR_SUCCESS;
  658. }
  659. else if (SHRegQueryUSValue(husKey, c_szCLSID, NULL, &szCLSID, &cbCLSID, FALSE, NULL, 0) == ERROR_SUCCESS)
  660. {
  661. *pcbData = sizeof(DWORD);
  662. *pType = REG_DWORD;
  663. CLSID clsid;
  664. GUIDFromString(szCLSID, &clsid);
  665. return _GetSetByCLSID(clsid, (BOOL*)pData, (cmd == REG_GET));
  666. }
  667. else
  668. {
  669. return _GetSetByRegKey(husKey, pType, pData, pcbData, cmd);
  670. }
  671. }
  672. DWORD CRegTreeOptions::_GetCheckStatus(HUSKEY huskey, BOOL *pbChecked, BOOL bUseDefault)
  673. {
  674. DWORD dwError, cbData, dwType;
  675. BYTE rgData[32];
  676. DWORD cbDataCHK, dwTypeCHK;
  677. BYTE rgDataCHK[32];
  678. BOOL bCompCHK = TRUE;
  679. // first, get the setting from the specified location.
  680. cbData = sizeof(rgData);
  681. dwError = _RegGetSetSetting(huskey, &dwType, rgData, &cbData, bUseDefault ? REG_GETDEFAULT : REG_GET);
  682. if (dwError == ERROR_SUCCESS)
  683. {
  684. // second, get the value for the "checked" state and compare.
  685. cbDataCHK = sizeof(rgDataCHK);
  686. dwError = SHRegQueryUSValue(huskey, c_szCheckedValue, &dwTypeCHK, rgDataCHK, &cbDataCHK, FALSE, NULL, 0);
  687. if (dwError != ERROR_SUCCESS)
  688. {
  689. // ok, we couldn't find the "checked" value, is it because
  690. // it's platform dependent?
  691. cbDataCHK = sizeof(rgDataCHK);
  692. dwError = SHRegQueryUSValue(huskey,
  693. g_fRunningOnNT ? c_szCheckedValueNT : c_szCheckedValueW95,
  694. &dwTypeCHK, rgDataCHK, &cbDataCHK, FALSE, NULL, 0);
  695. }
  696. if (dwError == ERROR_SUCCESS)
  697. {
  698. // make sure two value types match.
  699. if ((dwType != dwTypeCHK) &&
  700. (((dwType == REG_BINARY) && (dwTypeCHK == REG_DWORD) && (cbData != 4))
  701. || ((dwType == REG_DWORD) && (dwTypeCHK == REG_BINARY) && (cbDataCHK != 4))))
  702. return ERROR_BAD_FORMAT;
  703. switch (dwType) {
  704. case REG_DWORD:
  705. *pbChecked = (*((DWORD*)rgData) == *((DWORD*)rgDataCHK));
  706. break;
  707. case REG_SZ:
  708. if (cbData == cbDataCHK)
  709. *pbChecked = !lstrcmp((LPTSTR)rgData, (LPTSTR)rgDataCHK);
  710. else
  711. *pbChecked = FALSE;
  712. break;
  713. case REG_BINARY:
  714. if (cbData == cbDataCHK)
  715. *pbChecked = !memcmp(rgData, rgDataCHK, cbData);
  716. else
  717. *pbChecked = FALSE;
  718. break;
  719. default:
  720. return ERROR_BAD_FORMAT;
  721. }
  722. }
  723. }
  724. return dwError;
  725. }
  726. DWORD CRegTreeOptions::_SaveCheckStatus(HUSKEY huskey, BOOL bChecked)
  727. {
  728. DWORD dwError, cbData, dwType;
  729. BYTE rgData[32];
  730. cbData = sizeof(rgData);
  731. dwError = SHRegQueryUSValue(huskey, bChecked ? c_szCheckedValue : c_szUncheckedValue, &dwType, rgData, &cbData, FALSE, NULL, 0);
  732. if (dwError != ERROR_SUCCESS) // was it because of a platform specific value?
  733. {
  734. cbData = sizeof(rgData);
  735. dwError = SHRegQueryUSValue(huskey, bChecked ? (g_fRunningOnNT ? c_szCheckedValueNT : c_szCheckedValueW95) : c_szUncheckedValue,
  736. &dwType, rgData, &cbData, FALSE, NULL, 0);
  737. }
  738. if (dwError == ERROR_SUCCESS)
  739. {
  740. dwError = _RegGetSetSetting(huskey, &dwType, rgData, &cbData, REG_SET);
  741. }
  742. return dwError;
  743. }
  744. HTREEITEM Tree_AddItem(HTREEITEM hParent, LPTSTR pszText, HTREEITEM hInsAfter,
  745. int iImage, HWND hwndTree, HUSKEY huskey, BOOL *pbExisted)
  746. {
  747. HTREEITEM hItem;
  748. TV_ITEM tvI;
  749. TV_INSERTSTRUCT tvIns;
  750. TCHAR szText[MAX_URL_STRING];
  751. ASSERT(pszText != NULL);
  752. StrCpyN(szText, pszText, ARRAYSIZE(szText));
  753. // NOTE:
  754. // This code segment is disabled because we only enum explorer
  755. // tree in HKCU, so there won't be any duplicates.
  756. // Re-able this code if we start to also enum HKLM that could potentially
  757. // result in duplicates.
  758. // We only want to add an item if it is not already there.
  759. // We do this to handle reading out of HKCU and HKLM.
  760. //
  761. TCHAR szKeyName[MAX_KEY_NAME];
  762. tvI.mask = TVIF_HANDLE | TVIF_TEXT;
  763. tvI.pszText = szKeyName;
  764. tvI.cchTextMax = ARRAYSIZE(szKeyName);
  765. for (hItem = TreeView_GetChild(hwndTree, hParent);
  766. hItem != NULL;
  767. hItem = TreeView_GetNextSibling(hwndTree, hItem)
  768. )
  769. {
  770. tvI.hItem = hItem;
  771. if (TreeView_GetItem(hwndTree, &tvI))
  772. {
  773. if (!StrCmp(tvI.pszText, szText))
  774. {
  775. // We found a match!
  776. //
  777. *pbExisted = TRUE;
  778. return hItem;
  779. }
  780. }
  781. }
  782. // Create the item
  783. tvI.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  784. tvI.iImage = iImage;
  785. tvI.iSelectedImage = iImage;
  786. tvI.pszText = szText;
  787. tvI.cchTextMax = lstrlen(szText);
  788. // lParam contains the HUSKEY for this item:
  789. tvI.lParam = (LPARAM)huskey;
  790. // Create insert item
  791. tvIns.item = tvI;
  792. tvIns.hInsertAfter = hInsAfter;
  793. tvIns.hParent = hParent;
  794. // Insert the item into the tree.
  795. hItem = (HTREEITEM) SendMessage(hwndTree, TVM_INSERTITEM, 0,
  796. (LPARAM)(LPTV_INSERTSTRUCT)&tvIns);
  797. *pbExisted = FALSE;
  798. return (hItem);
  799. }
  800. BOOL _IsValidKey(HKEY hkeyRoot, LPCTSTR pszSubKey, LPCTSTR pszValue)
  801. {
  802. TCHAR szPath[MAX_PATH];
  803. DWORD dwType, cbSize = sizeof(szPath);
  804. if (ERROR_SUCCESS == SHGetValue(hkeyRoot, pszSubKey, pszValue, &dwType, szPath, &cbSize))
  805. {
  806. // Zero in the DWORD case or NULL in the string case
  807. // indicates that this item is not available.
  808. if (dwType == REG_DWORD)
  809. return *((DWORD *)szPath) != 0;
  810. else
  811. return szPath[0] != 0;
  812. }
  813. return FALSE;
  814. }
  815. #define REGSTR_POLICIES_EXPLORER TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer")
  816. BOOL CRegTreeOptions::_RegIsRestricted(HUSKEY hussubkey)
  817. {
  818. HUSKEY huskey;
  819. BOOL fRet = FALSE;
  820. // Does a "Policy" Sub key exist?
  821. if (SHRegOpenUSKey(TEXT("Policy"), KEY_READ, hussubkey, &huskey, FALSE) == ERROR_SUCCESS)
  822. {
  823. // Yes; Enumerate this key. The Values are Policy keys or
  824. // Full reg paths.
  825. DWORD cb;
  826. TCHAR szKeyName[MAX_KEY_NAME];
  827. for (int i=0;
  828. cb = ARRAYSIZE(szKeyName),
  829. ERROR_SUCCESS == SHRegEnumUSKey(huskey, i, szKeyName, &cb, SHREGENUM_HKLM)
  830. && !fRet; i++)
  831. {
  832. TCHAR szPath[MAXIMUM_SUB_KEY_LENGTH];
  833. DWORD dwType, cbSize = sizeof(szPath);
  834. HUSKEY huskeyTemp;
  835. if (ERROR_SUCCESS == SHRegOpenUSKey(szKeyName, KEY_READ, huskey, &huskeyTemp, FALSE))
  836. {
  837. if (ERROR_SUCCESS == SHRegQueryUSValue(huskeyTemp, TEXT("RegKey"), &dwType, szPath, &cbSize, FALSE, NULL, 0))
  838. {
  839. if (_IsValidKey(HKEY_LOCAL_MACHINE, szPath, szKeyName))
  840. {
  841. fRet = TRUE;
  842. break;
  843. }
  844. }
  845. SHRegCloseUSKey(huskeyTemp);
  846. }
  847. // It's not a full Key, try off of policies
  848. if (_IsValidKey(HKEY_LOCAL_MACHINE, REGSTR_POLICIES_EXPLORER, szKeyName) ||
  849. _IsValidKey(HKEY_CURRENT_USER, REGSTR_POLICIES_EXPLORER, szKeyName))
  850. {
  851. fRet = TRUE;
  852. break;
  853. }
  854. }
  855. SHRegCloseUSKey(huskey);
  856. }
  857. return fRet;
  858. }
  859. void CRegTreeOptions::_RegEnumTree(HUSKEY huskey, HTREEITEM htviparent, HTREEITEM htvins)
  860. {
  861. TCHAR szKeyName[MAX_KEY_NAME];
  862. DWORD cb;
  863. BOOL bScreenReaderEnabled = IsScreenReaderEnabled();
  864. // we must search all the sub-keys
  865. for (int i=0; // always start with 0
  866. cb=ARRAYSIZE(szKeyName), // string size
  867. ERROR_SUCCESS == SHRegEnumUSKey(huskey, i, szKeyName, &cb, SHREGENUM_HKLM);
  868. i++) // get next entry
  869. {
  870. HUSKEY hussubkey;
  871. // get more info on the entry
  872. if (ERROR_SUCCESS == SHRegOpenUSKey(szKeyName, KEY_READ, huskey, &hussubkey, FALSE))
  873. {
  874. HUSKEY huskeySave = NULL;
  875. if (!_RegIsRestricted(hussubkey))
  876. {
  877. TCHAR szTemp[MAX_PATH];
  878. // Get the type of items under this root
  879. cb = ARRAYSIZE(szTemp);
  880. if (ERROR_SUCCESS == SHRegQueryUSValue(hussubkey, c_szType, NULL, szTemp, &cb, FALSE, NULL, 0))
  881. {
  882. int iImage;
  883. BOOL bChecked;
  884. DWORD dwError = ERROR_SUCCESS;
  885. // get the type of node
  886. DWORD dwTreeType = RegTreeType(szTemp);
  887. // get some more info about the this item
  888. switch (dwTreeType)
  889. {
  890. case TREE_GROUP:
  891. iImage = _DefaultIconImage(hussubkey, IDUNKNOWN);
  892. huskeySave = hussubkey;
  893. break;
  894. case TREE_CHECKBOX:
  895. dwError = _GetCheckStatus(hussubkey, &bChecked, FALSE);
  896. if (dwError == ERROR_SUCCESS)
  897. {
  898. iImage = bChecked ? IDCHECKED : IDUNCHECKED;
  899. huskeySave = hussubkey;
  900. }
  901. break;
  902. case TREE_RADIO:
  903. dwError = _GetCheckStatus(hussubkey, &bChecked, FALSE);
  904. if (dwError == ERROR_SUCCESS)
  905. {
  906. iImage = bChecked ? IDRADIOON : IDRADIOOFF;
  907. huskeySave = hussubkey;
  908. }
  909. break;
  910. default:
  911. dwError = ERROR_INVALID_PARAMETER;
  912. }
  913. if (dwError == ERROR_SUCCESS)
  914. {
  915. BOOL bItemExisted = FALSE;
  916. LPTSTR pszText;
  917. // try to get the plugUI enabled text
  918. // otherwise we want the old data from a
  919. // different value
  920. int cch = ARRAYSIZE(szTemp);
  921. HRESULT hr = _LoadUSRegUIString(hussubkey, c_szPlugUIText, szTemp, cch);
  922. if (SUCCEEDED(hr) && szTemp[0] != TEXT('@'))
  923. {
  924. pszText = szTemp;
  925. }
  926. else
  927. {
  928. // try to get the old non-plugUI enabled text
  929. hr = _LoadUSRegUIString(hussubkey, c_szText, szTemp, cch);
  930. if (SUCCEEDED(hr))
  931. {
  932. pszText = szTemp;
  933. }
  934. else
  935. {
  936. // if all else fails, the key name itself
  937. // is a little more useful than garbage
  938. pszText = szKeyName;
  939. cch = ARRAYSIZE(szKeyName);
  940. }
  941. }
  942. //See if we need to add status text
  943. if (bScreenReaderEnabled && (dwTreeType != TREE_GROUP))
  944. {
  945. AppendStatus(pszText, cch, bChecked);
  946. }
  947. // add root node
  948. HTREEITEM htviroot = Tree_AddItem(htviparent, pszText, htvins, iImage, _hwndTree, huskeySave, &bItemExisted);
  949. if (bItemExisted)
  950. huskeySave = NULL;
  951. if (dwTreeType == TREE_GROUP)
  952. {
  953. HUSKEY huskeySubTree;
  954. if (ERROR_SUCCESS == SHRegOpenUSKey(szKeyName, KEY_READ, huskey, &huskeySubTree, FALSE))
  955. {
  956. _RegEnumTree(huskeySubTree, htviroot, TVI_FIRST);
  957. SHRegCloseUSKey(huskeySubTree);
  958. }
  959. TreeView_Expand(_hwndTree, htviroot, TVE_EXPAND);
  960. }
  961. } // if (dwError == ERROR_SUCCESS
  962. }
  963. } // if (!_RegIsRestricted(hsubkey))
  964. if (huskeySave != hussubkey)
  965. SHRegCloseUSKey(hussubkey);
  966. }
  967. }
  968. // Sort all keys under htviparent
  969. SendMessage(_hwndTree, TVM_SORTCHILDREN, 0, (LPARAM)htviparent);
  970. }
  971. BOOL CRegTreeOptions::_WalkTreeRecursive(HTREEITEM htvi, WALK_TREE_CMD cmd)
  972. {
  973. // step through the children
  974. HTREEITEM hctvi = TreeView_GetChild(_hwndTree, htvi);
  975. while (hctvi)
  976. {
  977. _WalkTreeRecursive(hctvi, cmd);
  978. hctvi = TreeView_GetNextSibling(_hwndTree, hctvi);
  979. }
  980. TV_ITEM tvi = {0};
  981. // get ourselves
  982. tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
  983. tvi.hItem = htvi;
  984. TreeView_GetItem(_hwndTree, &tvi);
  985. HUSKEY huskey;
  986. switch (cmd)
  987. {
  988. case WALK_TREE_DELETE:
  989. // if we are destroying the tree...
  990. // do we have something to clean up?
  991. if (tvi.lParam)
  992. {
  993. // close the reg key
  994. SHRegCloseUSKey((HUSKEY)tvi.lParam);
  995. }
  996. break;
  997. case WALK_TREE_SAVE:
  998. huskey = (HUSKEY)tvi.lParam;
  999. // now save ourselves (if needed)
  1000. // what are we?
  1001. if (tvi.iImage == IDCHECKED || tvi.iImage == IDRADIOON)
  1002. {
  1003. // checkbox or radio that is checked
  1004. _SaveCheckStatus(huskey, TRUE);
  1005. }
  1006. else if (tvi.iImage == IDUNCHECKED)
  1007. {
  1008. // checkbox that is unchecked
  1009. _SaveCheckStatus(huskey, FALSE);
  1010. }
  1011. // else radio that is "off" is ignored
  1012. // else icons are ignored
  1013. break;
  1014. case WALK_TREE_RESTORE:
  1015. case WALK_TREE_REFRESH:
  1016. huskey = (HUSKEY)tvi.lParam;
  1017. if ((tvi.iImage == IDCHECKED) ||
  1018. (tvi.iImage == IDUNCHECKED) ||
  1019. (tvi.iImage == IDRADIOON) ||
  1020. (tvi.iImage == IDRADIOOFF))
  1021. {
  1022. BOOL bChecked = FALSE;
  1023. _GetCheckStatus(huskey, &bChecked, cmd == WALK_TREE_RESTORE ? TRUE : FALSE);
  1024. tvi.iImage = (tvi.iImage == IDCHECKED) || (tvi.iImage == IDUNCHECKED) ?
  1025. (bChecked ? IDCHECKED : IDUNCHECKED) :
  1026. (bChecked ? IDRADIOON : IDRADIOOFF);
  1027. tvi.iSelectedImage = tvi.iImage;
  1028. TreeView_SetItem(_hwndTree, &tvi);
  1029. }
  1030. break;
  1031. }
  1032. return TRUE; // success?
  1033. }
  1034. DWORD RegTreeType(LPCTSTR pszType)
  1035. {
  1036. for (int i = 0; i < ARRAYSIZE(c_aTreeTypes); i++)
  1037. {
  1038. if (!lstrcmpi(pszType, c_aTreeTypes[i].name))
  1039. return c_aTreeTypes[i].type;
  1040. }
  1041. return TREE_UNKNOWN;
  1042. }
  1043. BOOL AppendStatus(LPTSTR pszText,UINT cbText, BOOL fOn)
  1044. {
  1045. LPTSTR pszTemp;
  1046. UINT cbStrLen , cbStatusLen;
  1047. //if there's no string specified then return
  1048. if (!pszText)
  1049. return FALSE;
  1050. //Calculate the string lengths
  1051. cbStrLen = lstrlen(pszText);
  1052. cbStatusLen = fOn ? lstrlen(TEXT("-ON")) : lstrlen(TEXT("-OFF"));
  1053. //Remove the old status appended
  1054. pszTemp = StrRStrI(pszText,pszText + cbStrLen, TEXT("-ON"));
  1055. if(pszTemp)
  1056. {
  1057. *pszTemp = (TCHAR)0;
  1058. cbStrLen = lstrlen(pszText);
  1059. }
  1060. pszTemp = StrRStrI(pszText,pszText + cbStrLen, TEXT("-OFF"));
  1061. if(pszTemp)
  1062. {
  1063. *pszTemp = (TCHAR)0;
  1064. cbStrLen = lstrlen(pszText);
  1065. }
  1066. //check if we append status text, we'll explode or not
  1067. if (cbStrLen + cbStatusLen > cbText)
  1068. {
  1069. //We'll explode
  1070. return FALSE;
  1071. }
  1072. if (fOn)
  1073. {
  1074. StrCat(pszText, TEXT("-ON"));
  1075. }
  1076. else
  1077. {
  1078. StrCat(pszText, TEXT("-OFF"));
  1079. }
  1080. return TRUE;
  1081. }
  1082. BOOL IsScreenReaderEnabled()
  1083. {
  1084. BOOL bRet = FALSE;
  1085. SystemParametersInfoA(SPI_GETSCREENREADER, 0, &bRet, 0);
  1086. return bRet;
  1087. }