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.

3425 lines
115 KiB

  1. /* REGUTILS.C
  2. Resident Code Segment // Tweak: make non-resident?
  3. Routines for reading and writing to the system registry and our .THM files.
  4. GatherThemeToFile()
  5. ApplyThemeFile()
  6. Frosting: Master Theme Selector for Windows '95
  7. Copyright (c) 1994-1999 Microsoft Corporation. All rights reserved.
  8. */
  9. // ---------------------------------------------
  10. // Brief file history:
  11. // Alpha:
  12. // Beta:
  13. // Bug fixes
  14. // ---------
  15. //
  16. // ---------------------------------------------
  17. //
  18. // Critique 2/1/95 jdk at dvw
  19. //
  20. // The design intends to have everything work transparently from
  21. // the KEYS.H file. The tables there specify all of the fields
  22. // in the registry that we want to save to a theme file and to set
  23. // from a theme file, along with flags for how to treat each field,
  24. // etc. It works in nice abstract loops that just save/set what
  25. // you tell it. You can add and change elements that you care to
  26. // have in the theme by adjusting the KEYS.H file, without touching
  27. // your code. Clean.
  28. //
  29. // Unfortunately, once you've set everything in the registry, you
  30. // still need to hand-code how you make many of the elements take
  31. // effect in the system in the current user session. This involves
  32. // wildly divergent APIs/parameters. This blows the abstraction noted
  33. // above. Everytime you change something in the KEYS.H file, you have
  34. // to hand-code changes here, too.
  35. //
  36. // I've isolated the non-abstract, item-specific code in HandPumpSystem()
  37. // below. Looking back on it now, there is some redundancy here. If
  38. // we started by doing everything by hand, then we could do the registry
  39. // and system settings together. Now you may end up reading, writing,
  40. // and later rereading the same string -- with attendant Reg open/closes
  41. // as well.
  42. #include "windows.h"
  43. #include "frost.h"
  44. #include "global.h"
  45. #include "keys.h" // only this files refers to list of keys
  46. #include "shlobj.h" // for SHChangeNotify() and flag
  47. #include "loadimag.h"
  48. #include "Bkgd.h"
  49. #include "adutil.h"
  50. #include "schedule.h"
  51. #include "mmsystem.h"
  52. // Stuff in bkgd.c
  53. extern void GetPlusBitmapName(LPTSTR szPlus);
  54. extern HBITMAP LoadWallpaper(LPTSTR szWallpaper, LPTSTR szTheme, BOOL fPreview);
  55. // Externs in NC.C
  56. extern BOOL FAR GatherIconMetricsByHand();
  57. extern BOOL FAR GatherNonClientMetricsByHand();
  58. extern VOID FAR SetIconMetricsByHand(BOOL, BOOL);
  59. extern VOID FAR SetNonClientMetricsByHand(BOOL, BOOL);
  60. // Local Routines
  61. BOOL GatherSubkeys(HKEY, FROST_SUBKEY *, int, LPTSTR);
  62. BOOL DatumRegisterToFile(HKEY, FROST_VALUE, LPTSTR, LPTSTR);
  63. BOOL FAR WriteBytesToFile(LPTSTR, LPTSTR, BYTE *, int, LPTSTR);
  64. BOOL ApplySubkeys(HKEY, FROST_SUBKEY *, int, LPTSTR, BOOL);
  65. BOOL DatumFileToRegister(HKEY, FROST_VALUE, LPTSTR, LPTSTR, BOOL);
  66. BOOL WriteBytesToRegister(HKEY, LPTSTR, int, LPTSTR);
  67. int FAR WriteBytesToBuffer(LPTSTR);
  68. BOOL IsTrashFull();
  69. BOOL ApplyCurrentTrash(BOOL, LPTSTR);
  70. BOOL HandPumpSystem();
  71. BOOL GatherSysColorsByHand(LPTSTR);
  72. BOOL SetSysColorsByHand();
  73. BOOL GatherWallpaperBitsByHand(LPTSTR);
  74. VOID AbstractPath(LPTSTR, int);
  75. BOOL GatherICONS(LPCTSTR);
  76. BOOL ApplyWebView(LPCTSTR);
  77. BOOL GatherWebView(LPCTSTR);
  78. BOOL ExtractWVResource(LPCTSTR, LPCTSTR);
  79. VOID ExpandSZ(LPTSTR);
  80. extern TCHAR szCursors[];
  81. #define DEF_SCREENSAVETIMEOUT 15 * 60 // default time to screen saver in seconds
  82. //
  83. // Local Globals
  84. //
  85. TCHAR pValue[MAX_VALUELEN+1]; // multi-use buffer: char, hex string, etc.
  86. BOOL bReadOK, bWroteOK; // Save: read from reg/sys, write to file
  87. // Apply: not implemented since ignoring results anyway
  88. // strings for grody screen saver case
  89. TCHAR szSS_Section[] = TEXT("boot");
  90. TCHAR szSS_Key[] = TEXT("SCRNSAVE.EXE");
  91. TCHAR szSS_File[] = TEXT("SYSTEM.INI"); // this worked in disp cpl code with no path....
  92. TCHAR szCP_Clr[] = TEXT("Control Panel\\Colors");
  93. TCHAR szCP_Appearance[] = TEXT("Control Panel\\Appearance");
  94. TCHAR szCP_SoundSchemes[] = TEXT("AppEvents\\Schemes");
  95. extern TCHAR szCP_DT[];
  96. TCHAR szSS_Active[] = TEXT("ScreenSaveActive");
  97. TCHAR szCurrent[] = TEXT("Current");
  98. extern TCHAR szTileWP[];
  99. TCHAR szWPStyle[] = TEXT("WallpaperStyle");
  100. //
  101. // For DoSysColors() and GetThemeColors() and others
  102. //
  103. // Important that these two arrays are the same length, and that they
  104. // are kept in the same order together during any change.
  105. //
  106. // SYNCHRONIZATION ALERT! -- Keep INDEX_* defines in FROST.H in
  107. // sync with this array. Keep NUM_COLORS define in FAKEWIN.H
  108. // in sync with this array.
  109. TCHAR *pRegColors[] = {
  110. TEXT("ActiveTitle"),
  111. TEXT("Background"),
  112. TEXT("Hilight"),
  113. TEXT("HilightText"),
  114. TEXT("TitleText"),
  115. TEXT("Window"),
  116. TEXT("WindowText"),
  117. TEXT("Scrollbar"),
  118. TEXT("InactiveTitle"),
  119. TEXT("Menu"),
  120. TEXT("WindowFrame"),
  121. TEXT("MenuText"),
  122. TEXT("ActiveBorder"),
  123. TEXT("InactiveBorder"),
  124. TEXT("AppWorkspace"),
  125. TEXT("ButtonFace"),
  126. TEXT("ButtonShadow"),
  127. TEXT("GrayText"),
  128. TEXT("ButtonText"),
  129. TEXT("InactiveTitleText"),
  130. TEXT("ButtonHilight"),
  131. TEXT("ButtonDkShadow"),
  132. TEXT("ButtonLight"),
  133. TEXT("InfoText"),
  134. TEXT("InfoWindow"),
  135. // These next two are bogus -- just here to pad the array. They
  136. // should be something like the "ButtonAlternateFace" (not sure
  137. // about that one) and "HotTrackingColor".
  138. TEXT("GradientActiveTitle"),
  139. TEXT("GradientInactiveTitle"),
  140. // These next two are the real deal for the gradient title bars
  141. TEXT("GradientActiveTitle"),
  142. TEXT("GradientInactiveTitle")
  143. };
  144. int iSysColorIndices[] = {
  145. COLOR_ACTIVECAPTION,
  146. COLOR_DESKTOP,
  147. COLOR_HIGHLIGHT,
  148. COLOR_HIGHLIGHTTEXT,
  149. COLOR_CAPTIONTEXT,
  150. COLOR_WINDOW,
  151. COLOR_WINDOWTEXT,
  152. COLOR_SCROLLBAR,
  153. COLOR_INACTIVECAPTION,
  154. COLOR_MENU,
  155. COLOR_WINDOWFRAME,
  156. COLOR_MENUTEXT,
  157. COLOR_ACTIVEBORDER,
  158. COLOR_INACTIVEBORDER,
  159. COLOR_APPWORKSPACE,
  160. COLOR_3DFACE,
  161. COLOR_3DSHADOW,
  162. COLOR_GRAYTEXT,
  163. COLOR_BTNTEXT,
  164. COLOR_INACTIVECAPTIONTEXT,
  165. COLOR_3DHILIGHT,
  166. COLOR_3DDKSHADOW,
  167. COLOR_3DLIGHT,
  168. COLOR_INFOTEXT,
  169. COLOR_INFOBK,
  170. // These next two are bogus -- just here to pad the array. They
  171. // should be something like the "COLOR_3DFACE" (not sure about
  172. // that one) and "COLOR_HOTLIGHT".
  173. COLOR_GRADIENTACTIVECAPTION,
  174. COLOR_GRADIENTINACTIVECAPTION,
  175. // These next two are the real deal for the gradient title bars
  176. COLOR_GRADIENTACTIVECAPTION,
  177. COLOR_GRADIENTINACTIVECAPTION
  178. };
  179. __inline int _atoi(char *sz)
  180. {
  181. int i=0;
  182. while (*sz && *sz >= '0' && *sz <= '9')
  183. i = i*10 + *sz++ -'0';
  184. return i;
  185. }
  186. //
  187. // GetRegString
  188. //
  189. void GetRegString(HKEY hkey, LPCTSTR szKey, LPCTSTR szValue, LPCTSTR szDefault, LPTSTR szBuffer, UINT cbBuffer)
  190. {
  191. if (szDefault)
  192. lstrcpy(szBuffer, szDefault);
  193. else
  194. szBuffer[0] = 0;
  195. if (RegOpenKey(hkey, szKey, &hkey) == 0)
  196. {
  197. RegQueryValueEx(hkey, szValue, NULL, NULL, (LPBYTE)szBuffer, &cbBuffer);
  198. RegCloseKey(hkey);
  199. }
  200. }
  201. //
  202. // GetRegInt
  203. //
  204. int GetRegInt(HKEY hkey, LPCTSTR szKey, LPCTSTR szValue, int def)
  205. {
  206. TCHAR ach[40];
  207. #ifdef UNICODE
  208. CHAR szTempA[40];
  209. #endif
  210. GetRegString(hkey, szKey, szValue, NULL, ach, sizeof(ach));
  211. if (ach[0])
  212. #ifdef UNICODE
  213. // Need to do conversion to ANSI for _atoi to work.
  214. {
  215. wcstombs(szTempA, (wchar_t *)ach, sizeof(szTempA));
  216. return _atoi(szTempA);
  217. }
  218. #else // !UNICODE
  219. return _atoi(ach);
  220. #endif
  221. else
  222. return def;
  223. }
  224. //
  225. // GatherThemeToFile
  226. //
  227. // This is one of the workhorse routines of the package.
  228. // For the whole list of theme items that we care about, go check the
  229. // cur Windows system settings in the registry. Copy those settings to
  230. // a new file with the given full pathname.
  231. //
  232. // Oh, and umh then: for the two sets of things we do by hand --
  233. // rather than by reading (and later writing) directly from (to)
  234. // the registry -- go off and do the special case code for them.
  235. // That is, Icon metrics and Nonclient metrics.
  236. //
  237. // Uses: global szCurDir to get theme directory
  238. // resets szCurThemeFile if successful writing to file
  239. //
  240. // Returns: BOOL success writing to file
  241. //
  242. BOOL FAR GatherThemeToFile(LPTSTR lpszFullPath)
  243. {
  244. int imaxkey;
  245. BOOL bRet, bOK = TRUE;
  246. //
  247. // init global error flags
  248. bReadOK = bWroteOK = TRUE;
  249. //
  250. // first do the ICON subkeys
  251. // OLD Plus95 code for gathering icon information has been replaced
  252. // by GatherICONS() function below.
  253. //imaxkey = sizeof(fsRoot)/sizeof(FROST_SUBKEY);
  254. //bOK = GatherSubkeys(HKEY_CLASSES_ROOT, fsRoot, imaxkey, lpszFullPath);
  255. bOK = GatherICONS(lpszFullPath);
  256. //
  257. // then do the CURRENT_USER subkeys
  258. imaxkey = sizeof(fsCurUser)/sizeof(FROST_SUBKEY);
  259. bRet = GatherSubkeys(HKEY_CURRENT_USER, fsCurUser, imaxkey, lpszFullPath);
  260. bOK = bOK && bRet;
  261. //
  262. // Now do the special cases
  263. bRet = GatherIconMetricsByHand(lpszFullPath);
  264. bOK = bOK && bRet;
  265. bRet = GatherNonClientMetricsByHand(lpszFullPath);
  266. bOK = bOK && bRet;
  267. bRet = GatherSysColorsByHand(lpszFullPath);
  268. bOK = bOK && bRet;
  269. bRet = GatherWallpaperBitsByHand(lpszFullPath);
  270. bOK = bOK && bRet;
  271. //
  272. // then do the Screen Saver setting, off in its own world
  273. // get cur
  274. GetPrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
  275. (LPTSTR)szNULL,
  276. (LPTSTR)pValue, MAX_VALUELEN,
  277. (LPTSTR)szSS_File);
  278. // abstract out variable path if appropriate
  279. AbstractPath((LPTSTR)pValue, MAX_VALUELEN);
  280. // and save it to the theme
  281. bRet = WritePrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
  282. (LPTSTR)pValue, lpszFullPath);
  283. bOK = bOK && bRet;
  284. if (!bRet) bWroteOK = FALSE;
  285. // Collect the WebView settings -- don't think we really care
  286. // if this fails...
  287. GatherWebView(lpszFullPath);
  288. //
  289. // then write magic number for file verification
  290. bRet = WritePrivateProfileString((LPTSTR)szFrostSection,
  291. (LPTSTR)szMagic,
  292. (LPTSTR)szVerify,
  293. lpszFullPath);
  294. bOK = bOK && bRet;
  295. if (!bRet) bWroteOK = FALSE;
  296. //
  297. // cleanup
  298. Assert(bOK, TEXT("didn't gather theme to file successfully\n"));
  299. return (bOK);
  300. }
  301. //
  302. // GatherSubkeys
  303. //
  304. // OK, read this carefully.
  305. //
  306. // This routine takes a handle to a currently open Registry key.
  307. // Then it takes a pointer to an array of FROST_SUBKEYs that identifies
  308. // subkey name strings of the open key. Then for those subkey names
  309. // each FROST_SUBKEY also points to another array of value names. This
  310. // is the final leaf of the Registry scheme. With a key, a subkey and a
  311. // specific value name, you can get an actual value. The actual query and
  312. // writing to a file happens in the DatumRegisterToFile() routine below.
  313. //
  314. // So here's the scheme:
  315. // for each subkey
  316. // open the subkey to get a key handle
  317. // for each value of this subkey that we care about
  318. // pass all the info to DatumRegisterToFile() to write one value
  319. //
  320. // Returns: BOOL success writing to file
  321. //
  322. BOOL GatherSubkeys(HKEY hKeyRoot, FROST_SUBKEY *fsEnum, int iMaxKey, LPTSTR lpszFile)
  323. {
  324. HKEY hKey; // cur open key
  325. int ikey, ival;
  326. LONG lret;
  327. BOOL bRet, bOK = TRUE;
  328. // loop through each subkey
  329. for (ikey = 0; ikey < iMaxKey; ikey++) {
  330. // open this subkey
  331. lret = RegOpenKeyEx( hKeyRoot, (LPTSTR)fsEnum[ikey].szSubKey,
  332. (DWORD)0, KEY_QUERY_VALUE, (PHKEY)&hKey );
  333. // check that you got a good key here
  334. if (lret != ERROR_SUCCESS) {
  335. Assert(FALSE, TEXT("problem on RegOpenKey (read) of subkey "));
  336. Assert(FALSE, fsEnum[ikey].szSubKey);
  337. Assert(FALSE, TEXT("\n"));
  338. // OK, you couldn't open the key to even look at the values.
  339. // *****************************************************************
  340. // based on the sketchy documentation we have for this Reg* and Error
  341. // stuff, we're guessing that you've ended up here because this
  342. // totally standard, Windows-defined subkey name just doesn't happen
  343. // to be defined for the current user.
  344. // *****************************************************************
  345. // SO: just write empty strings to the THM file for each valuename
  346. // you have for this subkey. You have then faithfully recorded that
  347. // there was nothing there.
  348. // still successful so long as all the empty strings are written out
  349. // with the value names to the THM file. also do default string if
  350. // appropriate.
  351. // (null loop if default string only)
  352. for (ival = 0; ival < fsEnum[ikey].iNumVals; ival++) {
  353. bRet = WritePrivateProfileString(
  354. fsEnum[ikey].szSubKey,
  355. (LPTSTR)fsEnum[ikey].fvVals[ival].szValName,
  356. (LPTSTR)szNULL, lpszFile
  357. );
  358. Assert(bRet, TEXT("couldn't write empty value string to THM file\n"));
  359. bOK = bOK && bRet;
  360. if (!bRet) bWroteOK = FALSE;
  361. }
  362. if (fsEnum[ikey].fValues != FV_LIST) { // either def or list+def
  363. bRet = WritePrivateProfileString(
  364. fsEnum[ikey].szSubKey,
  365. (LPTSTR)FROST_DEFSTR,
  366. (LPTSTR)szNULL, lpszFile
  367. );
  368. Assert(bRet, TEXT("couldn't write empty default string to THM file\n"));
  369. bOK = bOK && bRet;
  370. if (!bRet) bWroteOK = FALSE;
  371. }
  372. continue; // Open (read) subkey problem EXIT
  373. }
  374. // treat depending on type of values for this subkey
  375. switch (fsEnum[ikey].fValues) {
  376. case FV_LIST:
  377. case FV_LISTPLUSDEFAULT:
  378. // loop through each value in the list for this subkey
  379. for (ival = 0; ival < fsEnum[ikey].iNumVals; ival++) {
  380. bRet = DatumRegisterToFile(hKey, fsEnum[ikey].fvVals[ival],
  381. lpszFile,
  382. (LPTSTR)(fsEnum[ikey].szSubKey) );
  383. bOK = bOK && bRet;
  384. }
  385. // check if just list or list plus default
  386. if (FV_LIST == fsEnum[ikey].fValues)
  387. break; // normal EXIT
  388. // else fall through and do default, too
  389. case FV_DEFAULT:
  390. //
  391. // Default string: There are no "valuenames" to search for under
  392. // this key. Like the old INI file routines, it's just
  393. //
  394. // get default string:
  395. // this is a little messy to include here and get it right
  396. { // variable scope
  397. DWORD dwSize;
  398. DWORD dwType;
  399. LONG lret;
  400. BOOL bDefault = TRUE;
  401. // first do paranoid check of data size
  402. lret = RegQueryValueEx(hKey, (LPTSTR)szNULL, // null str to get default
  403. (LPDWORD)NULL,
  404. (LPDWORD)&dwType,
  405. (LPBYTE)NULL,
  406. (LPDWORD)&dwSize );
  407. if (ERROR_SUCCESS == lret) { // saw something there
  408. // here's the size check before getting the data
  409. if (dwSize > (DWORD)(MAX_VALUELEN * sizeof(TCHAR))) {
  410. Assert(FALSE, TEXT("Humongous default entry string in registry...\n"));
  411. bDefault = FALSE; // can't read, so very bad news
  412. bReadOK = FALSE;
  413. }
  414. else { // size is acceptable
  415. // now really get the value
  416. lret = RegQueryValueEx(hKey, (LPTSTR)szNULL,// null str to get default
  417. (LPDWORD)NULL,
  418. (LPDWORD)&dwType,
  419. (LPBYTE)pValue, // getting actual def value
  420. (LPDWORD)&dwSize);
  421. // If the value is an EXPAND_SZ we need to expand it...
  422. if (REG_EXPAND_SZ == dwType) ExpandSZ(pValue);
  423. Assert(lret == ERROR_SUCCESS, TEXT("bad return on default entry string\n"));
  424. Assert(((dwType == (DWORD)REG_SZ) || (dwType == (DWORD)REG_EXPAND_SZ)), TEXT("unexpected default entry type\n"));
  425. if (ERROR_SUCCESS != lret)
  426. // couldn't read somehow, so use null string
  427. *pValue = 0;
  428. }
  429. }
  430. else
  431. // couldn't even find the default string, so use null string
  432. *pValue = 0;
  433. // be sure to remember if couldn't get a value as above
  434. bOK = bOK && bDefault;
  435. } // end variable scope
  436. //
  437. // OK, if this is a path/filename, see about xlating to relative path
  438. if (fsEnum[ikey].bDefRelPath)
  439. AbstractPath((LPTSTR)pValue, MAX_VALUELEN);
  440. //
  441. // Phew, finally:write single default value
  442. //
  443. bRet = WritePrivateProfileString((LPTSTR)(fsEnum[ikey].szSubKey),
  444. (LPTSTR)FROST_DEFSTR,
  445. (LPTSTR)pValue, lpszFile);
  446. Assert(bRet, TEXT("couldn't write default string to THM file.\n"));
  447. bOK = bOK && bRet;
  448. if (!bRet) bWroteOK = FALSE;
  449. break;
  450. default:
  451. Assert(FALSE, TEXT("Unlisted .fValues value in Gather!\n"));
  452. break;
  453. }
  454. // close this key
  455. RegCloseKey(hKey);
  456. }
  457. // CLEANUP
  458. Assert(bOK, TEXT("didn't GatherSubkeys well\n"));
  459. return (bOK);
  460. }
  461. //
  462. // DatumRegisterToFile
  463. //
  464. // This is the atomic operation: a single datum from the registry to the file.
  465. // The technique varies a little by type of datum.
  466. //
  467. // Returns: BOOL success writing to file
  468. // Note that sucess doesn't depend on reading value from registry;
  469. // could be a value that's not set. Only reason to fail is: value
  470. // was too big to read, or the write itself failed.
  471. //
  472. BOOL DatumRegisterToFile(
  473. HKEY hQueryKey,
  474. FROST_VALUE fvQuery,
  475. LPTSTR lpszFile, // full pathname for output file
  476. LPTSTR lpszKeyname )
  477. {
  478. DWORD dwSize;
  479. DWORD dwType;
  480. LONG lret;
  481. BOOL bOK = TRUE;
  482. BOOL bSkipReadingWP = FALSE;
  483. // First off, if this is the Wallpaper and ActiveDesktop is on we
  484. // need to read the current wallpaper setting from the IActiveDesktop
  485. // interface instead of from the registry.
  486. bSkipReadingWP = FALSE;
  487. if ((lstrcmpi(fvQuery.szValName,TEXT("Wallpaper")) == 0) && IsActiveDesktopOn()) {
  488. if (GetADWallpaper(pValue)) {
  489. bSkipReadingWP = TRUE;
  490. dwType = REG_SZ; // Set dwType as if we read a SZ from the reg
  491. lret = ERROR_SUCCESS;
  492. }
  493. // Couldn't read the wallpaper from IActiveDesktop so go ahead and
  494. // try reading it from the registry.
  495. }
  496. // Else, if this is the Wallpaper Pattern and ActiveDesktop is on we
  497. // need to read the current Pattern setting from the IActiveDesktop
  498. // interface instead of from the registry.
  499. else if ((lstrcmpi(fvQuery.szValName,TEXT("Pattern")) == 0) &&
  500. IsActiveDesktopOn()) {
  501. if (GetADWPPattern(pValue)) {
  502. bSkipReadingWP = TRUE;
  503. dwType = REG_SZ; // Set dwType as if we read a SZ from the reg
  504. lret = ERROR_SUCCESS;
  505. }
  506. // Couldn't read the Pattern from IActiveDesktop so go ahead and
  507. // try reading it from the registry.
  508. }
  509. if (!bSkipReadingWP) {
  510. // first do paranoid check of data size
  511. lret = RegQueryValueEx(hQueryKey, fvQuery.szValName, (LPDWORD)NULL,
  512. (LPDWORD)&dwType, (LPBYTE)NULL, (LPDWORD)&dwSize);
  513. if (ERROR_SUCCESS == lret) {
  514. // here's the size check before getting the data
  515. if (dwSize > (DWORD)(MAX_VALUELEN*sizeof(TCHAR))) {
  516. Assert(FALSE, TEXT("Humongous entry in registry...\n"));
  517. bReadOK = FALSE;
  518. return (FALSE); // incredibly unlikely mammoth entry EXIT
  519. }
  520. //
  521. // now really get the value
  522. //
  523. lret = RegQueryValueEx(hQueryKey, fvQuery.szValName, (LPDWORD)NULL,
  524. (LPDWORD)&dwType, (LPBYTE)pValue, (LPDWORD)&dwSize);
  525. // If EXPAND_SZ type we need to expand it
  526. if (REG_EXPAND_SZ == dwType)
  527. {
  528. ExpandSZ(pValue);
  529. dwType = REG_SZ; // Fudge this to make that assert happy
  530. }
  531. Assert(lret == ERROR_SUCCESS, TEXT("bad return on datum retrieval\n"));
  532. Assert(dwType == (DWORD)fvQuery.iValType, TEXT("unexpected datum type\n"));
  533. }
  534. }
  535. //
  536. // if you got something, go ahead and write it
  537. if (ERROR_SUCCESS == lret) {
  538. // switch on value type to get how to write it
  539. switch ((int)dwType) {
  540. case REG_SZ:
  541. case REG_EXPAND_SZ:
  542. // before writing, if this is a path/filename,
  543. // see about xlating to relative path
  544. //
  545. // even before that, see if it is a bitmap
  546. // and find out what compressed file it came from --
  547. // that is if it's not an HTM/HTML wallpaper.
  548. if ((lstrcmpi(fvQuery.szValName, TEXT("Wallpaper")) == 0) &&
  549. (lstrcmpi(FindExtension(pValue), TEXT(".htm")) != 0) &&
  550. (lstrcmpi(FindExtension(pValue), TEXT(".html")) !=0)) {
  551. GetImageTitle(pValue, pValue, sizeof(pValue));
  552. }
  553. if (fvQuery.bValRelPath)
  554. AbstractPath((LPTSTR)pValue, MAX_VALUELEN);
  555. bOK = WritePrivateProfileString(lpszKeyname,
  556. (LPTSTR)fvQuery.szValName,
  557. (LPTSTR)pValue, lpszFile);
  558. Assert(bOK, TEXT("couldn't write value string to THM file.\n"));
  559. if (!bOK) bWroteOK = FALSE;
  560. break;
  561. //
  562. // these two cases are both just treated as binary output
  563. case REG_DWORD:
  564. case REG_BINARY:
  565. bOK = WriteBytesToFile(lpszKeyname, (LPTSTR)fvQuery.szValName,
  566. (BYTE *)pValue, (int)dwSize, lpszFile);
  567. Assert(bOK, TEXT("couldn't write value bytes to THM file.\n"));
  568. if (!bOK) bWroteOK = FALSE; // pretty unitary write function
  569. break;
  570. default:
  571. Assert(FALSE, TEXT("unexpected REG_* data type read from registry\n"));
  572. break;
  573. }
  574. }
  575. // EITHER: couldn't query size OR couldn't retrieve value
  576. else {
  577. // *****************************************************************
  578. // based on the sketchy documentation we have for this Reg* and Error
  579. // stuff, we're guessing that you've ended up here because this
  580. // totally legitimate, successfully opened key and this totally
  581. // standard, Windows-defined value name just doesn't happen to have
  582. // a value assigned to it for the current user.
  583. // *****************************************************************
  584. // So: just write an empty string to the THM file. Still successful
  585. // so long as the key actually is written to the THM file.
  586. bOK = WritePrivateProfileString(lpszKeyname,
  587. (LPTSTR)fvQuery.szValName,
  588. (LPTSTR)szNULL, lpszFile);
  589. Assert(bOK, TEXT("couldn't write empty string to THM file.\n"));
  590. if (!bOK) bWroteOK = FALSE;
  591. }
  592. // cleanup
  593. Assert(bOK, TEXT("missed a datum from register to file\n"));
  594. return (bOK);
  595. }
  596. //
  597. // WriteBytesToFile
  598. //
  599. // Writes binary data out to the THM file.
  600. // Converts the data byte by byte to ASCII numbers, appends
  601. // them to one long string, writes string to profile.
  602. //
  603. // Returns: success of write to theme file
  604. //
  605. BOOL FAR WriteBytesToFile(LPTSTR lpszProfileSection, LPTSTR lpszProfileKey,
  606. BYTE *pData, int iBytes, LPTSTR lpszProfile)
  607. {
  608. HLOCAL hXlat;
  609. TCHAR *psz;
  610. BOOL bWrote = TRUE;
  611. int iter;
  612. #ifdef UNICODE
  613. char szNumberA[10]; // byte value converted to ANSI
  614. #endif
  615. //
  616. // inits
  617. // alloc and lock memory for translation
  618. hXlat = LocalAlloc(LPTR, 5*sizeof(TCHAR)*iBytes+2);
  619. if (!hXlat) { // couldn't create buffer!!
  620. NoMemMsg(STR_TO_SAVE); // post low mem message!
  621. return (FALSE); // bad news couldn't write EXIT
  622. }
  623. //
  624. // do the translation to a string
  625. psz = (TCHAR *)hXlat; // start at beginning of string buffer
  626. // loop through the bytes
  627. for (iter = 0; iter < iBytes; iter++) {
  628. // translate one byte into our string buffer
  629. #ifdef UNICODE
  630. // With UNICODE we need to use a temporary ANSI buffer
  631. // for the litoa conversion, then convert that string to
  632. // UNICODE when putting it into our main string buffer.
  633. litoa( (int)(pData[iter]), (LPSTR)szNumberA);
  634. mbstowcs((wchar_t *)psz, szNumberA, sizeof(szNumberA));
  635. #else // !UNICODE
  636. litoa( (int)(pData[iter]), (LPSTR)psz);
  637. #endif
  638. // add a space
  639. lstrcat((LPTSTR)psz, TEXT(" "));
  640. // bump pointer up to end of string for next byte
  641. psz = psz + lstrlen((LPTSTR)psz);
  642. }
  643. //
  644. // do the write to the THM file
  645. bWrote = WritePrivateProfileString(lpszProfileSection,
  646. lpszProfileKey,
  647. (LPTSTR)hXlat,
  648. lpszProfile);
  649. //
  650. // cleanup
  651. // free up memory allocated
  652. LocalFree(hXlat);
  653. return (bWrote);
  654. }
  655. //
  656. // ApplyThemeFile
  657. //
  658. // The inverse of GatherThemeToFile(), this routine takes a theme
  659. // file and sets system registry values from the file. It also then
  660. // calls individual APIs to make some of the settings take immediate
  661. // effect.
  662. //
  663. // Goes through the list of theme values and if the controlling checkbox
  664. // is checked, sets the value from the file to the registry. This is
  665. // a nice clean loop using the tables in KEYS.H to match checkboxes to
  666. // registry keys/valuenames.
  667. //
  668. // Then for each checkbox, do the current system settings by hand as
  669. // necessary.
  670. //
  671. // lpszFilename == full pathname
  672. BOOL FAR ApplyThemeFile(LPTSTR lpszFilename)
  673. {
  674. BOOL bRet, bOK = TRUE;
  675. int imaxkey;
  676. BOOL bFullTrash;
  677. extern TCHAR szPlus_CurTheme[];
  678. //
  679. // first apply the ROOT subkeys to the registry: these are the icons
  680. // but first first go check cur registry to see if trash can full or empty
  681. bFullTrash = IsTrashFull();
  682. // OK now apply the root subkeys -- this is where Win95 checks for
  683. // the icons
  684. //imaxkey = sizeof(fsRoot)/sizeof(FROST_SUBKEY);
  685. //bOK = ApplySubkeys(HKEY_CLASSES_ROOT, fsRoot, imaxkey, lpszFilename,
  686. // FALSE); // don't apply null theme entries for icons!
  687. // Now apply the Win98/current user icon keys
  688. imaxkey = sizeof(fsCUIcons)/sizeof(FROST_SUBKEY);
  689. bOK = ApplySubkeys(HKEY_CURRENT_USER, fsCUIcons, imaxkey, lpszFilename,
  690. FALSE); // don't apply null theme entries for icons!
  691. // have to keep setting cursor to wait because someone resets it
  692. WaitCursor();
  693. // now apply the right current trash icon from theme
  694. bRet = ApplyCurrentTrash(bFullTrash, lpszFilename);
  695. bOK = bOK && bRet;
  696. //
  697. // then apply the CURRENT_USER subkeys to the registry
  698. imaxkey = sizeof(fsCurUser)/sizeof(FROST_SUBKEY);
  699. bRet = ApplySubkeys(HKEY_CURRENT_USER, fsCurUser, imaxkey, lpszFilename, TRUE);
  700. bOK = bOK && bRet;
  701. // have to keep setting cursor to wait because someone resets it
  702. WaitCursor();
  703. ApplyWebView(lpszFilename);
  704. WaitCursor();
  705. // just a random place to check this:
  706. Assert(NUM_CURSORS == (sizeof(fvCursors)/sizeof(FROST_VALUE)),
  707. TEXT("DANGER: mismatched number of cursors in fvCursors and NUM_CURSORS constant!\n"));
  708. //
  709. // now try to make everything apply to the system currently
  710. bRet = HandPumpSystem();
  711. // *** DEBUG *** need specific error message here
  712. bOK = bOK && bRet;
  713. //
  714. // cleanup
  715. // save this theme file in the registry as the last one applied
  716. // if you messed with stored CB values for color problem filter
  717. if (bLowColorProblem && (fLowBPPFilter == APPLY_NONE))
  718. SaveCheckboxes(); // then reset from the actual buttons
  719. Assert(bOK, TEXT("didn't apply theme successfully\n"));
  720. return (bOK);
  721. }
  722. //
  723. // ApplySubkeys
  724. //
  725. // This is parallel to the GatherSubkeys() function above, copying
  726. // values instead _from_ the theme file _to_ the Registry. It uses
  727. // the same loop structure, see the comments to GatherSubkeys().
  728. //
  729. // The one change is that on applying values, we check first the
  730. // FC_* flag in the fValCheckbox or fDefCheckbox fields to identify
  731. // the controlling checkbox for that valuename. If the checkbox is
  732. // unchecked, the value is not set. (We already got the checkbox states
  733. // into bCBStates[] in ApplyThemeFile() above.
  734. //
  735. // Returns: success writing to Registry, should be always TRUE.
  736. //
  737. BOOL ApplySubkeys(HKEY hKeyRoot, FROST_SUBKEY *fsEnum, int iMaxKey, LPTSTR lpszFile, BOOL bApplyNull)
  738. {
  739. HKEY hKey; // cur open key
  740. int ikey, ival, iret;
  741. LONG lret;
  742. BOOL bRet, bOK = TRUE;
  743. TCHAR szNTReg[MAX_PATH];
  744. // loop through each subkey
  745. for (ikey = 0; ikey < iMaxKey; ikey++) {
  746. // have to keep setting cursor to wait because someone resets it
  747. WaitCursor();
  748. // If this is NT and the key is for the icons we need to touch
  749. // up the reg pathing
  750. if (IsPlatformNT() && (ikey < MAX_ICON) &&
  751. ((lstrcmpi(fsEnum[ikey].szSubKey, fsCUIcons[ikey].szSubKey) == 0) ||
  752. (lstrcmpi(fsEnum[ikey].szSubKey, fsRoot[ikey].szSubKey) == 0)))
  753. {
  754. lstrcpy(szNTReg, c_szSoftwareClassesFmt);
  755. lstrcat(szNTReg, fsRoot[ikey].szSubKey);
  756. // open this subkey
  757. lret = RegOpenKeyEx( hKeyRoot, (LPTSTR)szNTReg,
  758. (DWORD)0, KEY_SET_VALUE, (PHKEY)&hKey );
  759. }
  760. else
  761. {
  762. // open this subkey
  763. lret = RegOpenKeyEx( hKeyRoot, (LPTSTR)fsEnum[ikey].szSubKey,
  764. (DWORD)0, KEY_SET_VALUE, (PHKEY)&hKey );
  765. }
  766. // check that you got a good key here
  767. if (lret != ERROR_SUCCESS) {
  768. DWORD dwDisposition;
  769. Assert(FALSE, TEXT("problem on RegOpenKey (write) of subkey "));
  770. Assert(FALSE, fsEnum[ikey].szSubKey);
  771. Assert(FALSE, TEXT("\n"));
  772. // OK, you couldn't even open the key !!!
  773. // *****************************************************************
  774. // based on the sketchy documentation we have for this Reg* and Error
  775. // stuff, we're guessing that you've ended up here because this
  776. // totally standard, Windows-defined subkey name just doesn't happen
  777. // to be defined for the current user.
  778. // *****************************************************************
  779. // SO: Just create this subkey for this user, and maybe it will get
  780. // used after you create and set it.
  781. // still successful so long as can create new subkey to write to
  782. if (IsPlatformNT() && (ikey < MAX_ICON) &&
  783. ((lstrcmpi(fsEnum[ikey].szSubKey, fsCUIcons[ikey].szSubKey) == 0) ||
  784. (lstrcmpi(fsEnum[ikey].szSubKey, fsRoot[ikey].szSubKey) == 0)))
  785. {
  786. lret = RegCreateKeyEx( hKeyRoot, (LPTSTR)szNTReg,
  787. (DWORD)0, (LPTSTR)szNULL, REG_OPTION_NON_VOLATILE,
  788. KEY_SET_VALUE, (LPSECURITY_ATTRIBUTES)NULL,
  789. (PHKEY)&hKey, (LPDWORD)&dwDisposition );
  790. }
  791. else
  792. {
  793. lret = RegCreateKeyEx( hKeyRoot, (LPTSTR)fsEnum[ikey].szSubKey,
  794. (DWORD)0, (LPTSTR)szNULL, REG_OPTION_NON_VOLATILE,
  795. KEY_SET_VALUE, (LPSECURITY_ATTRIBUTES)NULL,
  796. (PHKEY)&hKey, (LPDWORD)&dwDisposition );
  797. }
  798. if (lret != ERROR_SUCCESS) {
  799. Assert(FALSE, TEXT("problem even with RegCreateKeyEx (write) of subkey "));
  800. Assert(FALSE, fsEnum[ikey].szSubKey);
  801. Assert(FALSE, TEXT("\n"));
  802. // we are not happy campers
  803. bOK = FALSE;
  804. // but we'll keep on truckin'
  805. continue; // bad subkey EXIT
  806. }
  807. }
  808. // treat depending on type of values for this subkey
  809. switch (fsEnum[ikey].fValues) {
  810. case FV_LIST:
  811. case FV_LISTPLUSDEFAULT:
  812. // loop through each value in the list for this subkey
  813. for (ival = 0; ival < fsEnum[ikey].iNumVals; ival++) {
  814. // if the checkbox that controls this value is checked
  815. if ( bCBStates[ fsEnum[ikey].fvVals[ival].fValCheckbox ] ) {
  816. // then read from theme file and write to registry
  817. bRet = DatumFileToRegister(hKey, fsEnum[ikey].fvVals[ival],
  818. lpszFile,
  819. (LPTSTR)(fsEnum[ikey].szSubKey),
  820. bApplyNull);
  821. bOK = bOK && bRet;
  822. }
  823. }
  824. // check if just list or list plus default
  825. if (FV_LIST == fsEnum[ikey].fValues)
  826. break; // normal EXIT
  827. // else fall through and do default, too
  828. case FV_DEFAULT:
  829. //
  830. // if this subkey's default value's checkbox is checked
  831. if (bCBStates[fsEnum[ikey].fDefCheckbox]) {
  832. //
  833. // Default string: There are no "valuenames" to set under
  834. // this key. Like the old INI file routines, it's just one value.
  835. //
  836. //
  837. // Get default value string
  838. iret = GetPrivateProfileString((LPTSTR)(fsEnum[ikey].szSubKey),
  839. (LPTSTR)FROST_DEFSTR,
  840. (LPTSTR)szNULL,
  841. (LPTSTR)pValue, MAX_VALUELEN, lpszFile);
  842. // no error case; legit null string value is indistinguishable from
  843. // error case...
  844. // If we're reading the ICON strings and we got a NULL return
  845. // then we should try using the "old" Win95 reg keys in case
  846. // this is an old .Theme file
  847. if ((!*pValue) && (ikey < MAX_ICON) &&
  848. (lstrcmpi(fsEnum[ikey].szSubKey, fsCUIcons[ikey].szSubKey) == 0))
  849. {
  850. iret = GetPrivateProfileString((LPTSTR)(fsRoot[ikey].szSubKey),
  851. (LPTSTR)FROST_DEFSTR,
  852. (LPTSTR)szNULL,
  853. (LPTSTR)pValue,
  854. MAX_VALUELEN,
  855. lpszFile);
  856. // PLUS98 bug 1042
  857. // If this is the MyDocs icon and there is no setting for
  858. // it in the Theme file then we need to default to the
  859. // szMyDocsDefault icon.
  860. if ((MYDOC_INDEX == ikey) && (!*pValue)) {
  861. lstrcpy(pValue, MYDOC_DEFSTR);
  862. }
  863. }
  864. // if this value is a relative path filename string,
  865. // first see about making abstract path into current instance
  866. if (fsEnum[ikey].bDefRelPath) {
  867. InstantiatePath((LPTSTR)pValue, MAX_VALUELEN);
  868. // look for and confirm finding the file, with replacement
  869. if (ConfirmFile((LPTSTR)pValue, TRUE) == CF_NOTFOUND) {
  870. *pValue = 0; // if not found, just null out filename
  871. bOK = FALSE; // couldn't apply this file
  872. }
  873. }
  874. //
  875. // sometimes don't want to set a null string to the Registry
  876. if (*pValue || bApplyNull) { // either non-null or OK to set null
  877. // now set the value in the registry
  878. lret = RegSetValueEx(hKey, (LPTSTR)szNULL,// null str to set default value
  879. 0,
  880. (DWORD)REG_SZ,
  881. (LPBYTE)pValue, // getting actual def value
  882. (DWORD)(SZSIZEINBYTES(pValue)));
  883. Assert(lret == ERROR_SUCCESS, TEXT("couldn't write a default entry string!\n"));
  884. bOK = bOK && (lret == ERROR_SUCCESS);
  885. }
  886. } // end if controlling checkbox checked
  887. break;
  888. default:
  889. Assert(FALSE, TEXT("Unlisted .fValues value in Apply!\n"));
  890. break;
  891. }
  892. // close this key
  893. RegCloseKey(hKey);
  894. }
  895. // CLEANUP
  896. Assert(bOK, TEXT("didn't ApplySubkeys well\n"));
  897. return (bOK);
  898. }
  899. //
  900. // DatumFileToRegister
  901. //
  902. // Like DatumRegisterToFile(), this is an atomic operation; in this
  903. // case, move a single datum from theme file to the registry.
  904. // Here, too, technique differs slightly between strings and numbers.
  905. //
  906. // Returns: BOOL success writing to registry
  907. //
  908. BOOL DatumFileToRegister(
  909. HKEY hSetKey,
  910. FROST_VALUE fvSet,
  911. LPTSTR lpszFile, // full pathname for theme file
  912. LPTSTR lpszKeyname,
  913. BOOL bOKtoApplyNull)
  914. {
  915. LONG lret;
  916. int iret;
  917. BOOL bOK = TRUE;
  918. //
  919. // get the saved string from the theme file
  920. iret = GetPrivateProfileString(lpszKeyname,
  921. (LPTSTR)fvSet.szValName,
  922. (LPTSTR)szNULL,
  923. (LPTSTR)pValue, MAX_VALUELEN, lpszFile);
  924. // no error case: can't tell difference between legit null string and default
  925. // If we're reading the TRASH ICON strings and we got a NULL return
  926. // then we should try using the "old" Win95 reg keys in case
  927. // this is an old .Theme file
  928. if ((!*pValue) &&
  929. (lstrcmpi(lpszKeyname, fsCUIcons[TRASH_INDEX].szSubKey) == 0)) {
  930. iret = GetPrivateProfileString((LPTSTR)(fsRoot[TRASH_INDEX].szSubKey),
  931. (LPTSTR)fvSet.szValName,
  932. (LPTSTR)szNULL,
  933. (LPTSTR)pValue,
  934. MAX_VALUELEN,
  935. lpszFile);
  936. }
  937. // not always OK to set null value to registry
  938. if (!bOKtoApplyNull && !(*pValue))
  939. return(TRUE); // no work to do EXIT
  940. // switch on value type to get how to write it
  941. switch (fvSet.iValType) {
  942. case REG_SZ:
  943. // if this value is a relative path filename string,
  944. // first see about making abstract path into current instance
  945. if (fvSet.bValRelPath) {
  946. InstantiatePath((LPTSTR)pValue, MAX_VALUELEN);
  947. // look for and confirm finding the file, with replacement
  948. if (ConfirmFile((LPTSTR)pValue, TRUE) == CF_NOTFOUND) {
  949. *pValue = 0; // if not found, just null out filename
  950. bOK = FALSE; // couldn't apply this file!
  951. }
  952. }
  953. // If this is the Wallpaper setting and it's an .htm or .html
  954. // wallpaper we need to apply this via IActiveDesktop
  955. //
  956. if (lstrcmpi(fvSet.szValName, TEXT("Wallpaper")) == 0 && pValue && *pValue &&
  957. (lstrcmpi(FindExtension(pValue),TEXT(".htm")) == 0 ||
  958. lstrcmpi(FindExtension(pValue),TEXT(".html")) == 0)) {
  959. // First, clear the existing registry wallpaper setting.
  960. // Don't really care if this fails.
  961. lret = RegSetValueEx(hSetKey, fvSet.szValName,
  962. 0,
  963. (DWORD)REG_SZ,
  964. (LPBYTE)TEXT("\0"),
  965. (DWORD)sizeof(TCHAR));
  966. // Now try applying the new wallpaper via ActiveDesktop SetWP.
  967. if (SetADWallpaper(pValue, TRUE /* Force AD on */)) {
  968. bOK = TRUE;
  969. *pValue = 0;
  970. bOKtoApplyNull = FALSE; // Don't want to set Wallpaper string to
  971. // NULL later on because it causes AD to
  972. // forget about the HTML wallpaper!!
  973. }
  974. else {
  975. // Setting the HTML wallpaper failed!
  976. bOK = FALSE;
  977. *pValue = 0;
  978. }
  979. }
  980. //
  981. // if we are applying a compressed image, lets decompress it first
  982. //
  983. // NOTE we can handle the out 'o disk case a little better
  984. //
  985. if (lstrcmpi(fvSet.szValName, TEXT("Wallpaper")) == 0 && pValue && *pValue &&
  986. lstrcmpi(FindExtension(pValue),TEXT(".bmp")) != 0 &&
  987. lstrcmpi(FindExtension(pValue),TEXT(".dib")) != 0 &&
  988. lstrcmpi(FindExtension(pValue),TEXT(".rle")) != 0 ) {
  989. TCHAR plus_bmp[MAX_PATH];
  990. if (g_hbmWall)
  991. {
  992. CacheDeleteBitmap(g_hbmWall);
  993. g_hbmWall = NULL;
  994. }
  995. g_hbmWall = LoadWallpaper(pValue, lpszFile, FALSE);
  996. Assert(g_hbmWall, TEXT("LoadWallpaper failed!\n"));
  997. if (g_hbmWall) {
  998. GetPlusBitmapName(plus_bmp);
  999. bOK = bOK && SaveImageToFile(g_hbmWall, plus_bmp, pValue);
  1000. Assert(bOK, TEXT("unable to save wallpaper to plus!.bmp\n"));
  1001. }
  1002. else {
  1003. bOK = FALSE;
  1004. }
  1005. if (bOK)
  1006. lstrcpy(pValue, plus_bmp);
  1007. else
  1008. *pValue = 0; // if not found, just null out filename
  1009. }
  1010. // not always OK to set null value to registry
  1011. if (!bOKtoApplyNull && !(*pValue))
  1012. return(TRUE); // no work to do EXIT
  1013. // just write the string to the registry
  1014. lret = RegSetValueEx(hSetKey, fvSet.szValName,
  1015. 0,
  1016. (DWORD)REG_SZ,
  1017. (LPBYTE)pValue,
  1018. (DWORD)SZSIZEINBYTES(pValue));
  1019. bOK = bOK && (lret == ERROR_SUCCESS);
  1020. // One last thing -- if this is the Wallpaper and
  1021. // ActiveDesktop is on we need to use the ActiveDesktop
  1022. // interface to set the wallpaper. We do this because
  1023. // we want this wallpaper setting in BOTH the registry
  1024. // and the ActiveDesktop. If you set a BMP wallpaper
  1025. // via the registry w/out also doing it via the AD
  1026. // interface it's possible for the AD/Non-AD desktops
  1027. // to be out of sync on their wallpaper.
  1028. //
  1029. // Note this is the case where the wallpaper is not html.
  1030. // Html wallpapers are set via the ActiveDesktop interface
  1031. // above.
  1032. if ((lstrcmpi(fvSet.szValName, TEXT("Wallpaper")) == 0) &&
  1033. IsActiveDesktopOn()) {
  1034. bOK = SetADWallpaper(pValue, FALSE);
  1035. }
  1036. Assert(bOK, TEXT("couldn't write a string value to registry!\n"));
  1037. break;
  1038. //
  1039. // these two cases are both just treated as binary output
  1040. case REG_DWORD:
  1041. case REG_BINARY:
  1042. bOK = WriteBytesToRegister(hSetKey, (LPTSTR)fvSet.szValName,
  1043. fvSet.iValType,
  1044. (LPTSTR)pValue);
  1045. Assert(bOK, TEXT("couldn't write value bytes to registry.\n"));
  1046. break;
  1047. default:
  1048. Assert(FALSE, TEXT("unexpected REG_* data type from our own tables!\n"));
  1049. break;
  1050. }
  1051. // cleanup
  1052. Assert(bOK, TEXT("missed a datum from register to file\n"));
  1053. return (bOK);
  1054. }
  1055. //
  1056. // WriteBytesToRegister
  1057. //
  1058. // Parallel to WriteBytesToFile() function. This function takes an ASCII
  1059. // string of space-separated 0-255 numbers, translates them into byte
  1060. // number values packed into an output buffer, and then assigns that
  1061. // binary data to the given key/valuename in the registry -- as the data
  1062. // type given.
  1063. //
  1064. // Note that lpByteStr points to the same pValue that we are using as
  1065. // an output buffer. This depends on the numbers compressing as they
  1066. // are translated from ASCII to binary. Uses an itermediary variable so
  1067. // the first translation isn't messed up.
  1068. //
  1069. // ********************************************************************
  1070. // ASSUMPTIONS: You assume that noone has mucked with this theme file
  1071. // manually! In particular, this function depends on no leading blank
  1072. // and exactly one blank between each number in the string, and one
  1073. // trailing blank at the end followed by a null terminator.
  1074. // WHOOPS! BAD ASSUMPTION: trailing blank is stripped by Write/Get
  1075. // PrivateProfileString() functions! So need to watch for end manually.
  1076. // ********************************************************************
  1077. //
  1078. // Uses: writes binary data to global pValue[]
  1079. //
  1080. // Returns: success of write to register
  1081. BOOL WriteBytesToRegister(HKEY hKeySet, LPTSTR lpszValName,
  1082. int iType, LPTSTR lpszByteStr)
  1083. {
  1084. BOOL bOK = TRUE;
  1085. int iBytes;
  1086. LONG lret;
  1087. iBytes = WriteBytesToBuffer(lpszByteStr);
  1088. // set binary data in register file with the right data type
  1089. lret = RegSetValueEx(hKeySet, lpszValName,
  1090. 0,
  1091. (DWORD)iType,
  1092. (LPBYTE)pValue,
  1093. (DWORD)iBytes);
  1094. bOK = (lret == ERROR_SUCCESS);
  1095. Assert(bOK, TEXT("couldn't write a string value to registry!\n"));
  1096. //
  1097. // cleanup
  1098. return (bOK);
  1099. }
  1100. //
  1101. // Utility routine for above; takes ASCII string to binary in
  1102. // global pValue[] buffer.
  1103. //
  1104. // Since the values this guy is manipulating is purely ASCII
  1105. // numerics we should be able to get away with this char pointer
  1106. // arithmetic. If they were not simple ASCII numerics I think
  1107. // we could get into trouble with some DBCS chars
  1108. //
  1109. // Uses: writes binary data to global pValue[]
  1110. //
  1111. int FAR WriteBytesToBuffer(LPTSTR lpszInput)
  1112. {
  1113. LPTSTR lpszCur, lpszNext, lpszEnd;
  1114. BYTE *pbCur;
  1115. int iTemp, iBytes;
  1116. #ifdef UNICODE
  1117. CHAR szTempA[10];
  1118. #endif
  1119. //
  1120. // inits
  1121. lpszNext = lpszInput;
  1122. pbCur = (BYTE *)&pValue;
  1123. iBytes = 0;
  1124. lpszEnd = lpszInput + lstrlen(lpszInput); // points to null term
  1125. //
  1126. // translating loop
  1127. while (*lpszNext && (lpszNext < lpszEnd)) {
  1128. //
  1129. // update str pointers
  1130. // hold onto your starting place
  1131. lpszCur = lpszNext;
  1132. // advance pointer to next and null terminate cur
  1133. while ((TEXT(' ') != *lpszNext) && *lpszNext) { lpszNext++; }
  1134. *lpszNext = 0; lpszNext++;
  1135. // on last number, this leaves lpszNext pointing past lpszEnd
  1136. // translate this string-number into binary number and place in
  1137. // output buffer.
  1138. #ifdef UNICODE
  1139. wcstombs(szTempA, lpszCur, sizeof(szTempA));
  1140. iTemp = latoi(szTempA);
  1141. #else // !UNICODE
  1142. iTemp = latoi(lpszCur);
  1143. #endif
  1144. *pbCur = (BYTE)iTemp;
  1145. pbCur++; // incr byte loc in output buffer
  1146. // keep track of your bytes
  1147. iBytes++;
  1148. }
  1149. //
  1150. // cleanup
  1151. return (iBytes);
  1152. }
  1153. //
  1154. // Trash functions
  1155. //
  1156. // The registry holds three icons for the trash: full, empty, and default.
  1157. // In theory default is always one of the full or empty, and it is the current
  1158. // state of the actual trash.
  1159. //
  1160. // These functions are to query the trash state:
  1161. //
  1162. // IsTrashFull returns BOOL on full state
  1163. //
  1164. // and to apply the correct-state trash icon from
  1165. // the theme file to the default/cur:
  1166. //
  1167. // ApplyCurrentTrash
  1168. //
  1169. #define szCUTrashKey (fsCUIcons[TRASH_INDEX].szSubKey)
  1170. #define szRTrashKey (fsRoot[TRASH_INDEX].szSubKey)
  1171. #define szEmptyTrashVal TEXT("empty")
  1172. #define szFullTrashVal TEXT("full")
  1173. BOOL IsTrashFull()
  1174. {
  1175. TCHAR szEmpty[MAX_PATHLEN+1];
  1176. TCHAR szDefault[MAX_PATHLEN+1];
  1177. TCHAR szNTReg[MAX_PATH];
  1178. // Get the two strings
  1179. // First try the CURRENT_USER branch
  1180. // Then try the CLASSES_ROOT branch
  1181. if (IsPlatformNT())
  1182. {
  1183. lstrcpy(szNTReg, c_szSoftwareClassesFmt);
  1184. lstrcat(szNTReg, szRTrashKey);
  1185. szEmpty[0] = TEXT('\0');
  1186. HandGet(HKEY_CURRENT_USER, szNTReg, szEmptyTrashVal, (LPTSTR)szEmpty);
  1187. if (!*szEmpty) {
  1188. // Didn't get a valid string from CURRENT_USER so try CLASSES_ROOT
  1189. HandGet(HKEY_CLASSES_ROOT, szRTrashKey, szEmptyTrashVal, (LPTSTR)szEmpty);
  1190. }
  1191. szDefault[0] = TEXT('\0');
  1192. HandGet(HKEY_CURRENT_USER, szNTReg, szNULL, (LPTSTR)szDefault);
  1193. if (!*szDefault) {
  1194. // Didn't get a valid string from CURRENT_USER so try CLASSES_ROOT
  1195. HandGet(HKEY_CLASSES_ROOT, szRTrashKey, szNULL, (LPTSTR)szDefault);
  1196. }
  1197. }
  1198. else // Not NT
  1199. {
  1200. szEmpty[0] = TEXT('\0');
  1201. HandGet(HKEY_CURRENT_USER, szCUTrashKey, szEmptyTrashVal, (LPTSTR)szEmpty);
  1202. if (!*szEmpty) {
  1203. // Didn't get a valid string from CURRENT_USER so try CLASSES_ROOT
  1204. HandGet(HKEY_CLASSES_ROOT, szRTrashKey, szEmptyTrashVal, (LPTSTR)szEmpty);
  1205. }
  1206. szDefault[0] = TEXT('\0');
  1207. HandGet(HKEY_CURRENT_USER, szCUTrashKey, szNULL, (LPTSTR)szDefault);
  1208. if (!*szDefault) {
  1209. // Didn't get a valid string from CURRENT_USER so try CLASSES_ROOT
  1210. HandGet(HKEY_CLASSES_ROOT, szRTrashKey, szNULL, (LPTSTR)szDefault);
  1211. }
  1212. }
  1213. // have to keep setting cursor to wait because someone resets it
  1214. WaitCursor();
  1215. // compare strings and return
  1216. return(lstrcmpi((LPTSTR)szEmpty, (LPTSTR)szDefault));
  1217. // lstrcmpi rets 0 for equal strings; equal to empty means FALSE to full
  1218. }
  1219. BOOL ApplyCurrentTrash(BOOL bTrashFull, LPTSTR lpszFile)
  1220. {
  1221. LONG lret;
  1222. HKEY hKey; // cur open key
  1223. TCHAR szNTReg[MAX_PATH];
  1224. //
  1225. // check first that we are even touching the icons
  1226. if (!bCBStates[FC_ICONS])
  1227. return (TRUE); // no trash to apply EXIT
  1228. // have to keep setting cursor to wait because someone resets it
  1229. WaitCursor();
  1230. //
  1231. // inits
  1232. //lret = RegOpenKeyEx( HKEY_CLASSES_ROOT, (LPTSTR)szRTrashKey,
  1233. // (DWORD)0, KEY_SET_VALUE, (PHKEY)&hKey );
  1234. if (IsPlatformNT())
  1235. {
  1236. lstrcpy(szNTReg, c_szSoftwareClassesFmt);
  1237. lstrcat(szNTReg, szRTrashKey);
  1238. lret = RegOpenKeyEx( HKEY_CURRENT_USER, (LPTSTR)szNTReg,
  1239. (DWORD)0, KEY_SET_VALUE, (PHKEY)&hKey );
  1240. }
  1241. else // NOT NT
  1242. {
  1243. lret = RegOpenKeyEx( HKEY_CURRENT_USER, (LPTSTR)szCUTrashKey,
  1244. (DWORD)0, KEY_SET_VALUE, (PHKEY)&hKey );
  1245. }
  1246. if (lret != ERROR_SUCCESS) {
  1247. Assert(FALSE, TEXT("problem on RegOpenKey CURRENT_USER in ApplyCurrentTrash\n"));
  1248. return (FALSE); // nothing else to do EXIT
  1249. }
  1250. // have to keep setting cursor to wait because someone resets it
  1251. WaitCursor();
  1252. // get the right trash icon file
  1253. GetPrivateProfileString((LPTSTR)szCUTrashKey,
  1254. (LPTSTR)(bTrashFull ? szFullTrashVal : szEmptyTrashVal),
  1255. (LPTSTR)szNULL,
  1256. (LPTSTR)pValue, MAX_VALUELEN,
  1257. lpszFile);
  1258. // If we didn't get the value it could be that we've got an old
  1259. // Win95/Plus95 .Theme file. Let's try reading the Theme file
  1260. // using the Win95 reg key:
  1261. if (!*pValue) {
  1262. GetPrivateProfileString((LPTSTR)szRTrashKey,
  1263. (LPTSTR)(bTrashFull ? szFullTrashVal : szEmptyTrashVal),
  1264. (LPTSTR)szNULL,
  1265. (LPTSTR)pValue, MAX_VALUELEN,
  1266. lpszFile);
  1267. }
  1268. InstantiatePath((LPTSTR)pValue, MAX_VALUELEN);
  1269. // look for and confirm finding the file, with replacement
  1270. if (ConfirmFile((LPTSTR)pValue, TRUE) == CF_NOTFOUND) {
  1271. *pValue = 0; // if not found, just null out filename --> ret FALSE
  1272. }
  1273. if (!(*pValue)) {
  1274. Assert(FALSE, TEXT("ApplyCurrentTrash came up with no file\n"));
  1275. RegCloseKey(hKey); // mini-cleanup
  1276. return (FALSE); // no usable icon file, so just EXIT and leave cur
  1277. }
  1278. // have to keep setting cursor to wait because someone resets it
  1279. WaitCursor();
  1280. // Do the deed
  1281. lret = RegSetValueEx(hKey, (LPTSTR)szNULL, // sets default value
  1282. 0,
  1283. (DWORD)REG_SZ,
  1284. (LPBYTE)pValue,
  1285. (DWORD)SZSIZEINBYTES(pValue));
  1286. // have to keep setting cursor to wait because someone resets it
  1287. WaitCursor();
  1288. // cleanup and return
  1289. RegCloseKey(hKey);
  1290. Assert(lret == ERROR_SUCCESS, TEXT("bad return setting current trash\n"));
  1291. return (ERROR_SUCCESS == lret);
  1292. }
  1293. //
  1294. // HandPumpSystem
  1295. //
  1296. // OK. You've applied all of the theme file settings to the registry.
  1297. // Congratulations. Now reboot! HA HA HA! No seriously, most of the
  1298. // settings don't take effect in the current system just by writing
  1299. // them to the registry. You have to make each system change happen
  1300. // by hand. Hand pump it.
  1301. //
  1302. // So here we try to get things actually changing in front of the
  1303. // astonished user's eyes.
  1304. // Of course, assuming the checkbox to request it is checked.
  1305. //
  1306. // First, to be robustly certain that we are setting what is in the
  1307. // registry, actually read the value from the registry. Then use the
  1308. // random API for this element to set it.
  1309. //
  1310. // This is long and messy, the way it has to be. See design critique
  1311. // note at head of file.
  1312. //
  1313. // NOTE that SetSysColors() in SetSysColorsByHand() sends a
  1314. // WM_SYSCOLORCHANGE message. We also need to send a WM_SYSCOLORCHANGE
  1315. // message if we change any of the metrics - since Excel and other apps
  1316. // saw color/metric changes as unitary in 3.1 and would look for color.
  1317. // The extra BOOLs watching color and sys changes are to avoid sending
  1318. // two WM_SYSCOLORCHANGE messages.
  1319. //
  1320. // Uses: global bCBStates[] for checkbox states
  1321. // global szCurThemeFile[], non-encapsulated uncool
  1322. // but this is the grody routine anyway
  1323. //
  1324. BOOL HandPumpSystem()
  1325. {
  1326. BOOL bret, bOK = TRUE, bChangedSettings = FALSE;
  1327. TCHAR szWinMetrics[] = TEXT("WindowMetrics");
  1328. BOOL fClearAppearance = FALSE;
  1329. BOOL bSaverIsNull = FALSE;
  1330. HKEY hKey;
  1331. LONG lret;
  1332. DWORD dwDisposition;
  1333. int screenSaverTimeout = 0; // Screen saver timeout
  1334. BOOL bSkipWP = FALSE; // ActiveDesktop/HTML WP so skip HP WP
  1335. TCHAR szADWP[MAX_PATH]; // Current/ActiveDesktop wallpaper setting
  1336. // FC_SCRSVR
  1337. if (bCBStates[FC_SCRSVR]) {
  1338. // have to keep setting cursor to wait because someone resets it
  1339. WaitCursor();
  1340. // Take a peek at the current SS setting. If it's null we want to
  1341. // force the timeout to 15 minutes iff current timeout is 1 minute
  1342. // per Plus98 bug 1075. The reason for doing this is because Win98
  1343. // sets the timeout to 1 min by default -- so the first time a
  1344. // SS is applied the timeout is very short. Too short in some
  1345. // people's opinion. So we try to detect this one scenario and
  1346. // make the timeout a little bit longer.
  1347. GetPrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
  1348. (LPTSTR)szNULL,
  1349. (LPTSTR)pValue, MAX_VALUELEN,
  1350. (LPTSTR)szSS_File);
  1351. if (!*pValue) bSaverIsNull = TRUE;
  1352. //
  1353. // This one is different: Screen Saver is saved in SYSTEM.INI.
  1354. #ifdef GENTLER
  1355. // get the current value from SYSTEM.INI
  1356. GetPrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
  1357. (LPTSTR)szNULL,
  1358. (LPTSTR)szTemp, MAX_VALUELEN,
  1359. (LPTSTR)szSS_File);
  1360. // now, with cur value as default, get value from theme file
  1361. GetPrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
  1362. (LPTSTR)szTemp, // cur value is default
  1363. (LPTSTR)pValue, MAX_VALUELEN,
  1364. (LPTSTR)szCurThemeFile);
  1365. #endif
  1366. // get scr saver from theme
  1367. GetPrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
  1368. (LPTSTR)szNULL, // NULL is default
  1369. (LPTSTR)pValue, MAX_VALUELEN,
  1370. (LPTSTR)szCurThemeFile);
  1371. // next, translate path variable if necessary
  1372. InstantiatePath((LPTSTR)pValue, MAX_VALUELEN);
  1373. // look for and confirm finding the file, with replacement
  1374. if (ConfirmFile((LPTSTR)pValue, TRUE) == CF_NOTFOUND) {
  1375. *pValue = 0; // if not found, just null out filename
  1376. bOK = FALSE; // couldn't apply this file!
  1377. }
  1378. else { // file's OK, so continue
  1379. // now, MAKE SURE that you only write short filenames to old-fashioned system
  1380. if (FilenameToShort((LPTSTR)pValue, (LPTSTR)szMsg))
  1381. lstrcpy(FileFromPath((LPTSTR)pValue), (LPTSTR)szMsg);
  1382. }
  1383. // and finally, apply value from theme file (or NULL if not in theme)
  1384. WritePrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
  1385. (LPTSTR)pValue, (LPTSTR)szSS_File);
  1386. // and make it live in the system
  1387. SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,
  1388. // set depending on whether scr saver in theme
  1389. // pValue still has scr saver name
  1390. (*pValue ? 1 : 0),
  1391. NULL, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
  1392. // Set screen saver timeout value
  1393. if (!SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &screenSaverTimeout, 0))
  1394. {
  1395. screenSaverTimeout = 0;
  1396. }
  1397. // Plus 98 bug 1075 -- if current screensaver setting is NULL and
  1398. // the timeout is 1 minute, then force timeout to default (15 mins).
  1399. if (bSaverIsNull && (60 == screenSaverTimeout)) screenSaverTimeout = 0;
  1400. if (*pValue && !screenSaverTimeout)
  1401. {
  1402. // There must be a screen saver timeout value, otherwise the system
  1403. // assumes that there is no screen saver selected.
  1404. SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, DEF_SCREENSAVETIMEOUT, NULL,
  1405. SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
  1406. }
  1407. }
  1408. // have to keep setting cursor to wait because someone resets it
  1409. WaitCursor();
  1410. // FC_SOUND
  1411. // already in effect just by setting registry settings
  1412. if (bCBStates[FC_SOUND]) {
  1413. // but need to flush buffer and ensure new sounds used for next events
  1414. sndPlaySound((LPTSTR)NULL, SND_ASYNC | SND_NODEFAULT);
  1415. //
  1416. // Clear the current pointer scheme string from the registry so that Mouse
  1417. // cpl doesn't display a bogus name. Don't care if this fails.
  1418. RegSetValue(HKEY_CURRENT_USER, (LPTSTR) szCP_SoundSchemes, REG_SZ,
  1419. TEXT(".current"), 0);
  1420. }
  1421. // have to keep setting cursor to wait because someone resets it
  1422. WaitCursor();
  1423. // FC_PTRS
  1424. if (bCBStates[FC_PTRS]) {
  1425. SystemParametersInfo( SPI_SETCURSORS, 0, 0, SPIF_SENDCHANGE);
  1426. //
  1427. // Clear the current pointer scheme string from the registry so that Mouse
  1428. // cpl doesn't display a bogus name. Don't care if this fails.
  1429. RegSetValue(HKEY_CURRENT_USER, (LPTSTR) szCP_Appearance, REG_SZ, szNULL, sizeof(TCHAR));
  1430. }
  1431. // have to keep setting cursor to wait because someone resets it
  1432. WaitCursor();
  1433. // FC_WALL
  1434. // If ActiveDesktop is on and we're using an html wallpaper
  1435. // we don't want to do this hand pump stuff for the various
  1436. // wallpaper settings
  1437. bSkipWP = FALSE;
  1438. if (IsActiveDesktopOn()) {
  1439. if (GetADWallpaper(szADWP)) {
  1440. if (lstrcmpi(FindExtension(szADWP), TEXT(".htm")) == 0 ||
  1441. lstrcmpi(FindExtension(szADWP), TEXT(".html")) == 0 ) {
  1442. bSkipWP = TRUE;
  1443. }
  1444. }
  1445. }
  1446. if ((bCBStates[FC_WALL]) && !bSkipWP) {
  1447. //
  1448. // TileWallpaper and WallpaperStyle done by hand here
  1449. //
  1450. lret = RegCreateKeyEx( HKEY_CURRENT_USER, (LPTSTR)szCP_DT,
  1451. (DWORD)0, (LPTSTR)szNULL, REG_OPTION_NON_VOLATILE,
  1452. KEY_SET_VALUE, (LPSECURITY_ATTRIBUTES)NULL,
  1453. (PHKEY)&hKey, (LPDWORD)&dwDisposition );
  1454. if (lret != ERROR_SUCCESS) {
  1455. Assert(FALSE, TEXT("problem on RegCreateKeyEx for CP Desktop in HandPump!\n"));
  1456. bOK = FALSE; // we are not happy campers
  1457. }
  1458. if (ERROR_SUCCESS == lret) { // got an open key; set the two values
  1459. // do TileWallpaper
  1460. GetPrivateProfileString((LPTSTR)szCP_DT, (LPTSTR)szTileWP,
  1461. (LPTSTR)szNULL,
  1462. (LPTSTR)pValue, MAX_VALUELEN,
  1463. (LPTSTR)szCurThemeFile);
  1464. if (*pValue) { // if in theme, set; else leave reg alone!
  1465. lret = RegSetValueEx(hKey,
  1466. (LPTSTR)szTileWP,
  1467. 0,
  1468. (DWORD)REG_SZ,
  1469. (LPBYTE)pValue,
  1470. (DWORD)SZSIZEINBYTES(pValue));
  1471. Assert(lret == ERROR_SUCCESS, TEXT("bad return setting szTileWP in HandPump!\n"));
  1472. if (ERROR_SUCCESS != lret)
  1473. bOK = FALSE;
  1474. }
  1475. // do WallpaperStyle
  1476. GetPrivateProfileString((LPTSTR)szCP_DT, (LPTSTR)szWPStyle,
  1477. (LPTSTR)szNULL,
  1478. (LPTSTR)pValue, MAX_VALUELEN,
  1479. (LPTSTR)szCurThemeFile);
  1480. if (*pValue) { // if in theme, set; else leave reg alone!
  1481. lret = RegSetValueEx(hKey,
  1482. (LPTSTR)szWPStyle,
  1483. 0,
  1484. (DWORD)REG_SZ,
  1485. (LPBYTE)pValue,
  1486. (DWORD)SZSIZEINBYTES(pValue));
  1487. Assert(lret == ERROR_SUCCESS, TEXT("bad return setting WPStyle in HandPump!\n"));
  1488. if (ERROR_SUCCESS != lret)
  1489. bOK = FALSE;
  1490. }
  1491. RegCloseKey(hKey); // mini-cleanup
  1492. }
  1493. //
  1494. // Wallpaper and Pattern are set in reg in ApplySubkeys.
  1495. // Just make them live here
  1496. //
  1497. // get the Wallpaper reset in system
  1498. bret = HandGet(HKEY_CURRENT_USER,
  1499. TEXT("Control Panel\\Desktop"),
  1500. TEXT("Wallpaper"),
  1501. (LPTSTR)pValue);
  1502. SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, pValue,
  1503. SPIF_SENDCHANGE);
  1504. // get the Pattern reset in system
  1505. bret = HandGet(HKEY_CURRENT_USER,
  1506. TEXT("Control Panel\\Desktop"),
  1507. TEXT("Pattern"),
  1508. (LPTSTR)pValue);
  1509. SystemParametersInfo(SPI_SETDESKPATTERN, 0, pValue,
  1510. SPIF_SENDCHANGE);
  1511. // PLUS! 98 Bug 896 -- when switching from an HTML wallpaper
  1512. // to a BMP wallpaper the shell didn't update the WP if the
  1513. // ICONS setting was not checked -- user had to press F5 to
  1514. // refresh the desktop. This fixes that problem.
  1515. SHChangeNotify(SHCNE_ASSOCCHANGED, 0, NULL, NULL);
  1516. // the rest of the wallpaper items seem to be read from registry as needed
  1517. // "TileWallpaper"
  1518. // NIX: "WallpaperStyle"
  1519. // "WallPaperOriginX"
  1520. // "WallPaperOriginY"
  1521. }
  1522. // have to keep setting cursor to wait because someone resets it
  1523. WaitCursor();
  1524. // FC_ICONS
  1525. // already done
  1526. // FC_ICONSIZE and FC_FONTS are NO LONGER intertwined
  1527. // if (bCBStates[FC_FONTS] || bCBStates[FC_ICONSIZE]) {
  1528. // for icons, this is just for the spacing; size already done
  1529. // FC_FONTS
  1530. if (bCBStates[FC_FONTS]) {
  1531. // for fonts, this is the icon fonts
  1532. SetIconMetricsByHand(FALSE, bCBStates[FC_FONTS]);
  1533. fClearAppearance = TRUE;
  1534. }
  1535. // have to keep setting cursor to wait because someone resets it
  1536. WaitCursor();
  1537. // FC_FONTS and FC_BORDERS are intertwined
  1538. if (bCBStates[FC_FONTS] || bCBStates[FC_BORDERS]) {
  1539. SetNonClientMetricsByHand(bCBStates[FC_FONTS], bCBStates[FC_BORDERS]);
  1540. bChangedSettings = TRUE;
  1541. fClearAppearance = TRUE;
  1542. }
  1543. // have to keep setting cursor to wait because someone resets it
  1544. WaitCursor();
  1545. // FC_COLORS
  1546. if (bCBStates[FC_COLORS]) {
  1547. bret = SetSysColorsByHand();
  1548. //
  1549. // THIS SENT A WM_SYSCOLORCHANGE MESSAGE
  1550. //
  1551. bOK = bOK && bret;
  1552. fClearAppearance = TRUE;
  1553. }
  1554. else if (bChangedSettings) // may need to send color msg anyway
  1555. // for Win3.1 app compatibility, need to say COLOR changed if any metrics changed
  1556. PostMessage(HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0);
  1557. // Changed SendMessage to PostMessage to get around Plus! Setup bug
  1558. //
  1559. // cleanup
  1560. // have to keep setting cursor to wait because someone resets it
  1561. WaitCursor();
  1562. // let the world know you've mucked with it all
  1563. if (bChangedSettings)
  1564. SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE,
  1565. SPI_SETNONCLIENTMETRICS, (LPARAM)(LPTSTR)szWinMetrics);
  1566. // have to keep setting cursor to wait because someone resets it
  1567. WaitCursor();
  1568. // if (bCBStates[FC_ICONS] || bCBStates[FC_ICONSIZE]) {
  1569. if (bCBStates[FC_ICONS]) {
  1570. SHChangeNotify(SHCNE_ASSOCCHANGED, 0, NULL, NULL); // should do the trick!
  1571. SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE,
  1572. SPI_SETICONMETRICS, (LPARAM)(LPTSTR)szWinMetrics);
  1573. }
  1574. if (fClearAppearance) {
  1575. //
  1576. // Clear the current appearance string from the registry so that Display cpl
  1577. // doesn't display a bogus name. Don't care if this fails.
  1578. if (RegOpenKeyEx(HKEY_CURRENT_USER, (LPTSTR)szCP_Appearance, (DWORD)0,
  1579. KEY_SET_VALUE, (PHKEY)&hKey ) == ERROR_SUCCESS) {
  1580. RegDeleteValue(hKey, szCurrent);
  1581. RegCloseKey(hKey);
  1582. }
  1583. }
  1584. return (bOK);
  1585. }
  1586. //
  1587. // HandGet
  1588. //
  1589. // Just a little helper routine, gets an individual string value from the
  1590. // registry and returns it to the caller. Takes care of registry headaches,
  1591. // including a paranoid length check before getting the string.
  1592. //
  1593. // NOTE that this function thinks it's getting a string value. If it's
  1594. // another kind, this function will do OK: but the caller may be surprised
  1595. // if expecting a string.
  1596. //
  1597. // Returns: success of string retrieval
  1598. //
  1599. BOOL FAR HandGet(HKEY hKeyRoot, LPTSTR lpszSubKey, LPTSTR lpszValName, LPTSTR lpszRet)
  1600. {
  1601. LONG lret;
  1602. HKEY hKey; // cur open key
  1603. BOOL bOK = TRUE;
  1604. DWORD dwSize;
  1605. DWORD dwType;
  1606. //
  1607. // inits
  1608. // get subkey
  1609. lret = RegOpenKeyEx( hKeyRoot, lpszSubKey,
  1610. (DWORD)0, KEY_QUERY_VALUE, (PHKEY)&hKey );
  1611. if (lret != ERROR_SUCCESS) {
  1612. Assert(FALSE, TEXT("problem on RegOpenKey in HandGet\n"));
  1613. return (FALSE);
  1614. }
  1615. // now do our paranoid check of data size
  1616. lret = RegQueryValueEx(hKey, lpszValName,
  1617. (LPDWORD)NULL,
  1618. (LPDWORD)&dwType,
  1619. (LPBYTE)NULL, // null for size info only
  1620. (LPDWORD)&dwSize );
  1621. if (ERROR_SUCCESS == lret) { // saw something there
  1622. // here's the size check before getting the data
  1623. if (dwSize > (DWORD)(MAX_VALUELEN * sizeof(TCHAR))) { // if string too big
  1624. Assert(FALSE, TEXT("Humongous registry string; can't HandGet...\n"));
  1625. bOK = FALSE; // can't read, so very bad news
  1626. bReadOK = FALSE;
  1627. }
  1628. else { // size is OK to continue
  1629. // now really get the value
  1630. lret = RegQueryValueEx(hKey, lpszValName,
  1631. (LPDWORD)NULL,
  1632. (LPDWORD)&dwType,
  1633. (LPBYTE)lpszRet, // getting actual value
  1634. (LPDWORD)&dwSize);
  1635. // If this is an EXPAND_SZ we need to expand it...
  1636. if (REG_EXPAND_SZ == dwType) ExpandSZ(lpszRet);
  1637. Assert(lret == ERROR_SUCCESS, TEXT("bad return HandGet query\n"));
  1638. Assert(((dwType == (DWORD)REG_SZ) || (dwType == (DWORD)REG_EXPAND_SZ)), TEXT("non-string type in HandGet!\n"));
  1639. if (ERROR_SUCCESS != lret) bOK = FALSE;
  1640. }
  1641. }
  1642. else bOK = FALSE;
  1643. //
  1644. // cleanup
  1645. // close subkey
  1646. RegCloseKey(hKey);
  1647. return (bOK);
  1648. }
  1649. //
  1650. // Gather/SetSysColorsByHand
  1651. //
  1652. // Colors would seem to be the prototypical setting, that we could just
  1653. // read and write directly in the registry. But noooooooo.....
  1654. // A. On initial install, somehow the color settings all remain blank.
  1655. // B. Need to use SetSysColor() anyway to broadcast message.
  1656. //
  1657. // So on both read and write, need to use Get/SetSysColor. On write, still
  1658. // also need to write directly to registry.
  1659. //
  1660. //
  1661. // Uses GetSysColor() rather than reading directly from the Registry.
  1662. // Writes to theme file.
  1663. //
  1664. BOOL GatherSysColorsByHand(LPTSTR lpszTheme)
  1665. {
  1666. int iColor;
  1667. COLORREF crRGB;
  1668. BOOL bRet, bOK = TRUE;
  1669. BOOL bGrad = FALSE; // Are gradient titles enabled?
  1670. // init bGrad
  1671. SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, (LPVOID)&bGrad, 0);
  1672. //
  1673. // inits
  1674. Assert ((sizeof(iSysColorIndices)/sizeof(int)) == (sizeof(pRegColors)/sizeof(TCHAR *)),
  1675. TEXT("mismatched color arrays in GatherSysColorsByHand\n"));
  1676. //
  1677. // main process
  1678. // go through each color in your array
  1679. for (iColor = 0; iColor < (sizeof(pRegColors)/sizeof(TCHAR *)); iColor ++) {
  1680. // If this is the Gradient Caption setting and the system does
  1681. // not currently show gradient captions then don't write them out
  1682. // to the theme file.
  1683. //
  1684. // bGrad == Are gradient captions currently enabled?
  1685. // g_bGradient == Enough colors to show gradients?
  1686. if (((COLOR_GRADIENTACTIVECAPTION == iSysColorIndices[iColor]) ||
  1687. (COLOR_GRADIENTINACTIVECAPTION == iSysColorIndices[iColor])) &&
  1688. (!(bGrad && g_bGradient))) continue;
  1689. // get the system color
  1690. crRGB = GetSysColor(iSysColorIndices[iColor]);
  1691. // ASSUME THAT YOU NEVER GET A BOGUS VALUE FROM THIS FUNCTION!!
  1692. // translate to a string
  1693. ColorToRGBString((LPTSTR)szMsg, crRGB);
  1694. // write to theme file
  1695. bRet = WritePrivateProfileString((LPTSTR)szCP_Clr, (LPTSTR)(pRegColors[iColor]),
  1696. (LPTSTR)szMsg, lpszTheme);
  1697. if (!bRet) bOK = FALSE;
  1698. }
  1699. // cleanup
  1700. if (!bOK) bWroteOK = FALSE;
  1701. return (bOK);
  1702. }
  1703. //
  1704. // Reads from the theme and writes to the Registry.
  1705. // At the same time, does the grody SetSysColor thing:
  1706. // creates an array to set up the call. Makes the call.
  1707. //
  1708. BOOL SetSysColorsByHand()
  1709. {
  1710. LONG lret;
  1711. HKEY hKey; // cur open key
  1712. BOOL bOK = TRUE;
  1713. COLORREF crSet[(sizeof(iSysColorIndices)/sizeof(int))];
  1714. int iColor;
  1715. DWORD dwDisposition;
  1716. //
  1717. // inits
  1718. Assert ((sizeof(iSysColorIndices)/sizeof(int)) == (sizeof(pRegColors)/sizeof(TCHAR *)),
  1719. TEXT("mismatched color arrays in SetSysColorsByHand\n"));
  1720. // have to keep setting cursor to wait because someone resets it
  1721. WaitCursor();
  1722. // Open the color key if it exists, otherwise create it.
  1723. lret = RegCreateKeyEx( HKEY_CURRENT_USER, (LPTSTR)szCP_Clr,
  1724. (DWORD)0, (LPTSTR)szNULL, REG_OPTION_NON_VOLATILE,
  1725. KEY_SET_VALUE, NULL, (PHKEY)&hKey, (LPDWORD)&dwDisposition );
  1726. if (lret != ERROR_SUCCESS) {
  1727. Assert(FALSE, TEXT("problem on RegOpenKey in SetSysColorsByHand\n"));
  1728. return (FALSE);
  1729. }
  1730. //
  1731. // main process
  1732. // go through each color valuename in your array
  1733. for (iColor = 0; iColor < (sizeof(pRegColors)/sizeof(TCHAR *)); iColor ++) {
  1734. // get color string from theme file
  1735. GetPrivateProfileString((LPTSTR)szCP_Clr, (LPTSTR)(pRegColors[iColor]),
  1736. (LPTSTR)szNULL,
  1737. (LPTSTR)pValue, MAX_VALUELEN,
  1738. (LPTSTR)szCurThemeFile);
  1739. // If this is one of the Gradient Title bar settings and the setting
  1740. // doesn't exist in the Theme file, read the non-gradient title setting
  1741. // instead.
  1742. if ((iColor == INDEX_GRADIENTACTIVE) && !*pValue) {
  1743. GetPrivateProfileString((LPTSTR)szCP_Clr,
  1744. (LPTSTR)(pRegColors[INDEX_ACTIVE]),
  1745. (LPTSTR)szNULL,
  1746. (LPTSTR)pValue, MAX_VALUELEN,
  1747. (LPTSTR)szCurThemeFile);
  1748. }
  1749. if ((iColor == INDEX_GRADIENTINACTIVE) && !*pValue) {
  1750. GetPrivateProfileString((LPTSTR)szCP_Clr,
  1751. (LPTSTR)(pRegColors[INDEX_INACTIVE]),
  1752. (LPTSTR)szNULL,
  1753. (LPTSTR)pValue, MAX_VALUELEN,
  1754. (LPTSTR)szCurThemeFile);
  1755. }
  1756. if (!(*pValue)) {
  1757. // if nothing in theme, use cur sys colors
  1758. crSet[iColor] = GetSysColor(iSysColorIndices[iColor]);
  1759. continue; // null color value CONTINUE
  1760. }
  1761. // set color to Registry
  1762. lret = RegSetValueEx(hKey, (LPTSTR)(pRegColors[iColor]),
  1763. 0,
  1764. (DWORD)REG_SZ,
  1765. (LPBYTE)pValue,
  1766. (DWORD)SZSIZEINBYTES(pValue));
  1767. Assert(lret == ERROR_SUCCESS, TEXT("bad return SetSysColorsByHand query\n"));
  1768. if (ERROR_SUCCESS != lret)
  1769. bOK = FALSE;
  1770. // OK, you've got a str version of a COLOR.
  1771. // Translate string and add to COLORREF array.
  1772. crSet[iColor] = RGBStringToColor((LPTSTR)pValue);
  1773. }
  1774. //
  1775. // There. You've finally got an array of color RGB values. Apply liberally.
  1776. SystemParametersInfo(SPI_SETGRADIENTCAPTIONS, 0, IntToPtr(g_bGradient), SPIF_UPDATEINIFILE);
  1777. SetSysColors((sizeof(iSysColorIndices)/sizeof(int)), iSysColorIndices, crSet);
  1778. //
  1779. // Cleanup
  1780. RegCloseKey(hKey);
  1781. return (bOK);
  1782. }
  1783. //
  1784. // RGB to String to RGB utilities.
  1785. //
  1786. COLORREF FAR RGBStringToColor(LPTSTR lpszRGB)
  1787. {
  1788. LPTSTR lpszCur, lpszNext;
  1789. BYTE bRed, bGreen, bBlue;
  1790. #ifdef UNICODE
  1791. CHAR szTempA[10];
  1792. #endif
  1793. // inits
  1794. lpszNext = lpszRGB;
  1795. // set up R for translation
  1796. lpszCur = lpszNext;
  1797. while ((TEXT(' ') != *lpszNext) && *lpszNext) { lpszNext++; }
  1798. *lpszNext = 0; lpszNext++;
  1799. // get Red
  1800. #ifdef UNICODE
  1801. wcstombs(szTempA, (wchar_t *)lpszCur, sizeof(szTempA));
  1802. bRed = (BYTE)latoi(szTempA);
  1803. #else // !UNICODE
  1804. bRed = (BYTE)latoi(lpszCur);
  1805. #endif
  1806. // set up G for translation
  1807. lpszCur = lpszNext;
  1808. while ((TEXT(' ') != *lpszNext) && *lpszNext) { lpszNext++; }
  1809. *lpszNext = 0; lpszNext++;
  1810. // get Green
  1811. #ifdef UNICODE
  1812. wcstombs(szTempA, (wchar_t *)lpszCur, sizeof(szTempA));
  1813. bGreen = (BYTE)latoi(szTempA);
  1814. #else // !UNICODE
  1815. bGreen = (BYTE)latoi(lpszCur);
  1816. #endif
  1817. // set up B for translation
  1818. lpszCur = lpszNext;
  1819. while ((TEXT(' ') != *lpszNext) && *lpszNext) { lpszNext++; }
  1820. *lpszNext = 0; lpszNext++;
  1821. // get Blue
  1822. #ifdef UNICODE
  1823. wcstombs(szTempA, (wchar_t *)lpszCur, sizeof(szTempA));
  1824. bBlue = (BYTE)latoi(szTempA);
  1825. #else // !UNICODE
  1826. bBlue = (BYTE)latoi(lpszCur);
  1827. #endif
  1828. // OK, now combine them all for the big finish.....!
  1829. return(RGB(bRed, bGreen, bBlue));
  1830. }
  1831. void FAR ColorToRGBString(LPTSTR lpszRet, COLORREF crColor)
  1832. {
  1833. int iTemp;
  1834. TCHAR szTemp[12];
  1835. #ifdef UNICODE
  1836. CHAR szTempA[10];
  1837. #endif
  1838. // first do R value
  1839. iTemp = (int) GetRValue(crColor);
  1840. #ifdef UNICODE
  1841. litoa(iTemp, szTempA);
  1842. mbstowcs(lpszRet, szTempA, sizeof(szTempA));
  1843. #else // !UNICODE
  1844. litoa(iTemp, lpszRet);
  1845. #endif
  1846. // add on G value
  1847. lstrcat(lpszRet, TEXT(" "));
  1848. iTemp = (int) GetGValue(crColor);
  1849. #ifdef UNICODE
  1850. litoa(iTemp, szTempA);
  1851. mbstowcs(szTemp, szTempA, sizeof(szTempA));
  1852. #else // !UNICODE
  1853. litoa(iTemp, szTemp);
  1854. #endif
  1855. lstrcat(lpszRet, (LPTSTR)szTemp);
  1856. // add on B value
  1857. lstrcat(lpszRet, TEXT(" "));
  1858. iTemp = (int) GetBValue(crColor);
  1859. #ifdef UNICODE
  1860. litoa(iTemp, szTempA);
  1861. mbstowcs(szTemp, szTempA, sizeof(szTempA));
  1862. #else // !UNICODE
  1863. litoa(iTemp, szTemp);
  1864. #endif
  1865. lstrcat(lpszRet, (LPTSTR)szTemp);
  1866. // OK, you're done now
  1867. }
  1868. BOOL GatherWallpaperBitsByHand(LPTSTR lpszTheme)
  1869. {
  1870. BOOL bret, bOK = TRUE;
  1871. // save TileWallpaper
  1872. bret = HandGet(HKEY_CURRENT_USER, (LPTSTR)szCP_DT, (LPTSTR)szTileWP,(LPTSTR)pValue);
  1873. Assert(bret, TEXT("couldn't get WallpaperStyle from Registry!\n"));
  1874. bOK = bOK && bret;
  1875. bret = WritePrivateProfileString((LPTSTR)szCP_DT, (LPTSTR)szTileWP,
  1876. // only store if got something, else null
  1877. (LPTSTR)(bret ? pValue : szNULL),
  1878. lpszTheme);
  1879. bOK = bOK && bret;
  1880. if (!bret) bWroteOK = FALSE;
  1881. // save Wallpaper Style
  1882. bret = HandGet(HKEY_CURRENT_USER, (LPTSTR)szCP_DT, (LPTSTR)szWPStyle, (LPTSTR)pValue);
  1883. Assert(bret, TEXT("couldn't get WallpaperStyle from Registry!\n"));
  1884. bOK = bOK && bret;
  1885. bret = WritePrivateProfileString((LPTSTR)szCP_DT, (LPTSTR)szWPStyle,
  1886. // only store if got something, else null
  1887. (LPTSTR)(bret ? pValue : szNULL),
  1888. lpszTheme);
  1889. bOK = bOK && bret;
  1890. if (!bret) bWroteOK = FALSE;
  1891. return (bOK);
  1892. }
  1893. //
  1894. // *Path
  1895. //
  1896. // These routines help to make themes transportable between computers.
  1897. // The problem is that the registry keeps filenames for the various
  1898. // theme elements and, of course, these are hard-coded paths that vary
  1899. // from machine to machine.
  1900. //
  1901. // The way we work around this problem is by storing filenames in the
  1902. // theme file as _relative_ paths: relative to the theme file directory
  1903. // or the Windows directory. (Actually, these routines are set up to
  1904. // be relative to any number of directories.) When saving a filename to
  1905. // a theme, we check to see if any relative paths can be abstracted out.
  1906. // When retrieving a filename from a theme, we take the abstract placeholder
  1907. // and replace it with the current sessions instances.
  1908. // these must parallel each other. abstract strs must start with %
  1909. TCHAR *szAbstractDirs[] = {szThemeDir, szWinDir, szWinDir};
  1910. TCHAR *szAbstractStrs[] = {TEXT("%ThemeDir%"), TEXT("%WinDir%"), TEXT("%SystemRoot%")};
  1911. // AbstractPath (see header above)
  1912. //
  1913. // Takes actual full path/filename and takes out a leading substring
  1914. // that matches any of the paths to abstract, if any.
  1915. //
  1916. // lpszPath both input and output; assumes it's huge
  1917. //
  1918. VOID AbstractPath(LPTSTR lpszPath, int imax)
  1919. {
  1920. int iter, iAbstrDirLen;
  1921. TCHAR szTemp[MAX_PATHLEN+1];
  1922. // check easy out first
  1923. if (!lpszPath[0])
  1924. return; // easy out, nothing to change EXIT
  1925. // paranoid init
  1926. szTemp[MAX_PATHLEN] = 0;
  1927. // look for each of the path prefixes we care about in the given string
  1928. for (iter = 0; iter < (sizeof(szAbstractDirs)/sizeof(TCHAR *)); iter++ ) {
  1929. // inits
  1930. iAbstrDirLen = lstrlen((LPTSTR)(szAbstractDirs[iter]));
  1931. // get beginning of passed path string
  1932. lstrcpyn((LPTSTR)szTemp, lpszPath,
  1933. // ********************************
  1934. // LSTRCPYN issue: doc says that N specifies number of chars, not
  1935. // including the terminating null char. Behavior seems to include
  1936. // the null char, so I add one here. If the Win libs are modified
  1937. // to match their doc, then this will become a bug.
  1938. // ********************************
  1939. iAbstrDirLen + 1);
  1940. // compare to path prefix to abstract
  1941. if (!lstrcmpi((LPTSTR)szTemp, (LPTSTR)(szAbstractDirs[iter]))) {
  1942. //
  1943. // GOT A MATCH: now do the substitution
  1944. lstrcpy((LPTSTR)szTemp,
  1945. (LPTSTR)(szAbstractStrs[iter])); // start w/ abstract key
  1946. lstrcat((LPTSTR)szTemp,
  1947. (LPTSTR)(lpszPath + iAbstrDirLen)); // rest of path
  1948. lstrcpy(lpszPath, (LPTSTR)szTemp); // copy the result to ret str
  1949. // now get out
  1950. return; // got yer result now EXIT
  1951. }
  1952. }
  1953. // if you didn't get a match, then you're just returning the same path str
  1954. }
  1955. // InstantiatePath (see header above)
  1956. //
  1957. // Takes theme file's version of path/filename and looks for leading abstraction
  1958. // string that matches any of the known abstractions, replacing it with
  1959. // current system's equivalent if found.
  1960. //
  1961. // lpszPath both input and output; assumes it's huge
  1962. //
  1963. VOID FAR InstantiatePath(LPTSTR lpszPath, int imax)
  1964. {
  1965. int iter, iAbstrStrLen;
  1966. TCHAR szTemp[MAX_PATHLEN+1];
  1967. // easy outs
  1968. if ((TEXT('%') != lpszPath[0]) || !lpszPath[0])
  1969. return; // easy out, nothing to change EXIT
  1970. // paranoid init
  1971. szTemp[MAX_PATHLEN] = 0;
  1972. // look for each of the possible abstraction prefixes in the given string
  1973. for (iter = 0; iter < (sizeof(szAbstractStrs)/sizeof(TCHAR *)); iter++ ) {
  1974. // inits
  1975. iAbstrStrLen = lstrlen((LPTSTR)(szAbstractStrs[iter]));
  1976. // get beginning of passed path string
  1977. lstrcpyn((LPTSTR)szTemp, lpszPath,
  1978. // ********************************
  1979. // LSTRCPYN issue: doc says that N specifies number of chars, not
  1980. // including the terminating null char. Behavior seems to include
  1981. // the null char, so I add one here. If the Win libs are modified
  1982. // to match their doc, then this will become a bug.
  1983. // ********************************
  1984. iAbstrStrLen + 1);
  1985. // compare to this abstraction key string
  1986. if (!lstrcmpi((LPTSTR)szTemp, (LPTSTR)(szAbstractStrs[iter]))) {
  1987. //
  1988. // GOT A MATCH: now do the substitution
  1989. lstrcpy((LPTSTR)szTemp,
  1990. (LPTSTR)(szAbstractDirs[iter])); // actual path prefix
  1991. // Avoid the double backslash problem
  1992. if (lpszPath[iAbstrStrLen] == TEXT('\\')) iAbstrStrLen++;
  1993. lstrcat((LPTSTR)szTemp,
  1994. (LPTSTR)(lpszPath + iAbstrStrLen)); // rest of path
  1995. lstrcpy(lpszPath, (LPTSTR)szTemp); // copy the result to ret str
  1996. // now get out
  1997. return; // got yer result now EXIT
  1998. }
  1999. }
  2000. // On NT there is one more abstraction we need to worry about but
  2001. // we can't add it to the array of abstraction strings -- doing
  2002. // so would cause us to write it out to Theme files which would
  2003. // make the theme files not backward compatible.
  2004. //
  2005. // %SystemDrive%
  2006. //
  2007. if (IsPlatformNT())
  2008. {
  2009. // inits
  2010. iAbstrStrLen = lstrlen((LPTSTR)(TEXT("%SystemDrive%")));
  2011. // get beginning of passed path string
  2012. lstrcpyn((LPTSTR)szTemp, lpszPath,
  2013. // ********************************
  2014. // LSTRCPYN issue: doc says that N specifies number of chars, not
  2015. // including the terminating null char. Behavior seems to include
  2016. // the null char, so I add one here. If the Win libs are modified
  2017. // to match their doc, then this will become a bug.
  2018. // ********************************
  2019. iAbstrStrLen + 1);
  2020. // compare to this abstraction key string
  2021. if (!lstrcmpi((LPTSTR)szTemp, (LPTSTR)(TEXT("%SystemDrive%")))) {
  2022. //
  2023. // GOT A MATCH: now do the substitution
  2024. szTemp[0] = szWinDir[0]; // drive letter 'C'
  2025. szTemp[1] = szWinDir[1]; // colon ':'
  2026. szTemp[2] = TEXT('\0'); // null
  2027. lstrcat((LPTSTR)szTemp,
  2028. (LPTSTR)(lpszPath + iAbstrStrLen)); // rest of path
  2029. lstrcpy(lpszPath, (LPTSTR)szTemp); // copy the result to ret str
  2030. // now get out
  2031. return; // got yer result now EXIT
  2032. }
  2033. }
  2034. // if you didn't get a match, then you're just returning the same path str
  2035. }
  2036. //
  2037. // ConfirmFile
  2038. //
  2039. // This function does the "smart" file searching that's supposed to be
  2040. // built into each resource file reference in applying themes.
  2041. //
  2042. // First see if the full pathname + file given actually exists.
  2043. // If it does not, then try looking for the same filename (stripped from path)
  2044. // in other standard directories, in this order:
  2045. // Current Theme file directory
  2046. // Theme switcher THEMES subdirectory
  2047. // Windows directory
  2048. // Windows/MEDIA directory
  2049. // Windows/CURSORS directory
  2050. // Windows/SYSTEM directory
  2051. //
  2052. // Input: LPTSTR lpszPath full pathname
  2053. // BOOL bUpdate whether to alter the filename string with found file
  2054. // Returns: int flag telling if and how file has been confirmed
  2055. // CF_EXISTS pathname passed in was actual file
  2056. // CF_FOUND file did not exist, but found same filename elsewhere
  2057. // CF_NOTFOUND file did not exist, could not find elsewhere
  2058. //
  2059. int FAR ConfirmFile(LPTSTR lpszPath, BOOL bUpdate)
  2060. {
  2061. TCHAR szWork[MAX_PATHLEN+1];
  2062. TCHAR szTest[MAX_PATHLEN+1];
  2063. int iret = CF_NOTFOUND; // default value
  2064. LPTSTR lpFile;
  2065. LPTSTR lpNumber;
  2066. HANDLE hTest;
  2067. // special case easy return: if it's null, then trivially satisfied.
  2068. if (!*lpszPath) return (CF_EXISTS); // NO WORK EXIT
  2069. //
  2070. // Inits
  2071. // copy pathname to a work string for the function
  2072. lstrcpy((LPTSTR)szWork, lpszPath);
  2073. // input can be of the form foo.dll,13. need to strip off that comma,#
  2074. // but hold onto it to put back at the end if we change the pathname
  2075. lpNumber = FindChar(szWork, TEXT(','));
  2076. if (*lpNumber) { // if there is a comma
  2077. lpFile = lpNumber; // temp
  2078. lpNumber = CharNext(lpNumber);// hold onto number
  2079. *lpFile = 0;
  2080. }
  2081. //
  2082. // Do the checks
  2083. // *** first check if the given file just exists as is
  2084. hTest = CreateFile(szWork, GENERIC_READ, FILE_SHARE_READ,
  2085. (LPSECURITY_ATTRIBUTES)NULL,
  2086. OPEN_EXISTING,
  2087. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  2088. if (hTest != INVALID_HANDLE_VALUE) { // success
  2089. iret = CF_EXISTS; // assign ret value
  2090. // don't need to worry about bUpdate: found with input string
  2091. }
  2092. // otherwise, let's go searching for the same filename in other dirs
  2093. else {
  2094. Assert(FALSE, TEXT("had to go looking for "));
  2095. Assert(FALSE, szWork);
  2096. Assert(FALSE, TEXT("....\n"));
  2097. // get ptr to the filename separated from the path
  2098. lpFile = FileFromPath(szWork);
  2099. // *** try the cur theme file dir
  2100. lstrcpy((LPTSTR)szTest, (LPTSTR)szCurDir);
  2101. lstrcat((LPTSTR)szTest, lpFile);
  2102. hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
  2103. (LPSECURITY_ATTRIBUTES)NULL,
  2104. OPEN_EXISTING,
  2105. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  2106. if (hTest != INVALID_HANDLE_VALUE) { // success
  2107. iret = CF_FOUND; // assign ret value
  2108. Assert(FALSE, TEXT(" OK, found it in cur theme file dir\n"));
  2109. }
  2110. // *** otherwise try the Theme switcher THEMES subdirectory
  2111. else {
  2112. lstrcpy((LPTSTR)szTest, (LPTSTR)szThemeDir);
  2113. lstrcat((LPTSTR)szTest, lpFile);
  2114. hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
  2115. (LPSECURITY_ATTRIBUTES)NULL,
  2116. OPEN_EXISTING,
  2117. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  2118. if (hTest != INVALID_HANDLE_VALUE) { // success
  2119. iret = CF_FOUND; // assign ret value
  2120. Assert(FALSE, TEXT(" OK, found it in themes directory\n"));
  2121. }
  2122. // *** otherwise try the win dir
  2123. else {
  2124. lstrcpy((LPTSTR)szTest, (LPTSTR)szWinDir);
  2125. lstrcat((LPTSTR)szTest, lpFile);
  2126. hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
  2127. (LPSECURITY_ATTRIBUTES)NULL,
  2128. OPEN_EXISTING,
  2129. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  2130. if (hTest != INVALID_HANDLE_VALUE) { // success
  2131. iret = CF_FOUND; // assign ret value
  2132. Assert(FALSE, TEXT(" OK, found it in windows directory\n"));
  2133. }
  2134. // *** otherwise try the win/media dir
  2135. else {
  2136. // can get this one directly from Registry
  2137. HandGet(HKEY_LOCAL_MACHINE,
  2138. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),
  2139. TEXT("MediaPath"), (LPTSTR)szTest);
  2140. #ifdef THEYREMOVEREGSETTING
  2141. lstrcpy((LPTSTR)szTest, (LPTSTR)szWinDir);
  2142. lstrcat((LPTSTR)szTest, TEXT("Media\\"));
  2143. #endif
  2144. lstrcat((LPTSTR)szTest, TEXT("\\"));
  2145. lstrcat((LPTSTR)szTest, lpFile);
  2146. hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
  2147. (LPSECURITY_ATTRIBUTES)NULL,
  2148. OPEN_EXISTING,
  2149. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  2150. if (hTest != INVALID_HANDLE_VALUE) { // success
  2151. iret = CF_FOUND; // assign ret value
  2152. Assert(FALSE, TEXT(" OK, found it in windows media directory\n"));
  2153. }
  2154. // *** otherwise try the win/cursors dir
  2155. else {
  2156. lstrcpy((LPTSTR)szTest, (LPTSTR)szWinDir);
  2157. lstrcat((LPTSTR)szTest, TEXT("CURSORS\\"));
  2158. lstrcat((LPTSTR)szTest, lpFile);
  2159. hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
  2160. (LPSECURITY_ATTRIBUTES)NULL,
  2161. OPEN_EXISTING,
  2162. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  2163. if (hTest != INVALID_HANDLE_VALUE) { // success
  2164. iret = CF_FOUND; // assign ret value
  2165. Assert(FALSE, TEXT(" OK, found it in windows cursors directory\n"));
  2166. }
  2167. // *** otherwise try the win/system dir
  2168. else {
  2169. lstrcpy((LPTSTR)szTest, (LPTSTR)szWinDir);
  2170. lstrcat((LPTSTR)szTest, TEXT("SYSTEM\\"));
  2171. lstrcat((LPTSTR)szTest, lpFile);
  2172. hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
  2173. (LPSECURITY_ATTRIBUTES)NULL,
  2174. OPEN_EXISTING,
  2175. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  2176. if (hTest != INVALID_HANDLE_VALUE) { // success
  2177. iret = CF_FOUND; // assign ret value
  2178. Assert(FALSE, TEXT(" OK, found it in windows system directory\n"));
  2179. }
  2180. // *** otherwise try the win/system32 dir
  2181. else {
  2182. lstrcpy((LPTSTR)szTest, (LPTSTR)szWinDir);
  2183. lstrcat((LPTSTR)szTest, TEXT("SYSTEM32\\"));
  2184. lstrcat((LPTSTR)szTest, lpFile);
  2185. hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
  2186. (LPSECURITY_ATTRIBUTES)NULL,
  2187. OPEN_EXISTING,
  2188. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  2189. if (hTest != INVALID_HANDLE_VALUE) { // success
  2190. iret = CF_FOUND; // assign ret value
  2191. Assert(FALSE, TEXT(" OK, found it in windows system32 directory\n"));
  2192. }
  2193. }
  2194. }
  2195. }
  2196. }
  2197. }
  2198. }
  2199. // if found anywhere other than orig, copy found path/str as requested
  2200. if ((iret == CF_FOUND) && bUpdate) {
  2201. lstrcpy(lpszPath, (LPTSTR)szTest);
  2202. // if we stripped off a number, let's add it back on
  2203. if (*lpNumber) {
  2204. lstrcat(lpszPath, TEXT(","));
  2205. lstrcat(lpszPath, lpNumber);
  2206. }
  2207. } // endif found file by searching
  2208. }
  2209. // cleanup
  2210. Assert(iret != CF_NOTFOUND, TEXT(" But never found it!\n"));
  2211. if (iret != CF_NOTFOUND)
  2212. CloseHandle(hTest); // close file if opened
  2213. return (iret);
  2214. }
  2215. #ifdef ACTUALLY_DOING_THIS
  2216. //
  2217. // SetCheckboxesFromThemeFile
  2218. //
  2219. // After a new theme is selected from the listbox, you have to update
  2220. // the checkboxes in the main dlg window:
  2221. // uncheck and disable those that are not used in the theme
  2222. // check and enable those that are used in the theme
  2223. //
  2224. // Some of the checkboxes will always be enabled.
  2225. // Some of the checkboxes require a check of a sequence of settings
  2226. // (e.g. the sound events) and enabling iff any of them are used.
  2227. //
  2228. void FAR SetCheckboxesFromThemeFile(LPTSTR lpszFilename)
  2229. {
  2230. }
  2231. //
  2232. // SetCheckboxesFromRegistry
  2233. //
  2234. // Similar to SetCheckboxesFromThemeFile(), but for the case of
  2235. // "Current Windows settings" there is no file -- you just query
  2236. // the cur registry to get all the same values.
  2237. //
  2238. void FAR SetCheckboxesFromRegistry()
  2239. {
  2240. }
  2241. #endif
  2242. //
  2243. // CheckSpace
  2244. //
  2245. // Checks if there is enough space on drive to apply theme file.
  2246. //
  2247. BOOL FAR CheckSpace (HWND hWnd, BOOL fComplain)
  2248. {
  2249. //
  2250. // Step 1. Calculate Worst case Space needed
  2251. //
  2252. // 4 48 x 48 hicolor icons (10K each worst case) + (10K theme file) + padding
  2253. // Multiple by 2 for Prev and Curr Themes
  2254. #define FUDGE_SIZE (2L << 16)
  2255. HDC hdc;
  2256. ULONG cHorz;
  2257. ULONG cVert;
  2258. ULONG cPlanes;
  2259. ULONG cBPP;
  2260. ULONG fFlags;
  2261. ULONG cbNeeded;
  2262. ULONG cPalSize;
  2263. ULONG cColorDepth;
  2264. TCHAR szTemp[MAX_MSGLEN+1];
  2265. TCHAR szMsg[MAX_MSGLEN+1];
  2266. HANDLE hFile;
  2267. WIN32_FIND_DATA fd;
  2268. TCHAR chDrive;
  2269. TCHAR szDrive[4];
  2270. ULONG ckNeeded;
  2271. ULONG cbAvail;
  2272. DWORD csCluster;
  2273. DWORD cbSector;
  2274. DWORD ccFree;
  2275. DWORD ccTotal;
  2276. hdc = GetDC (HWND_DESKTOP);
  2277. cHorz = GetDeviceCaps (hdc, HORZRES);
  2278. cVert = GetDeviceCaps (hdc, VERTRES);
  2279. cPlanes = GetDeviceCaps (hdc, PLANES);
  2280. cBPP = GetDeviceCaps (hdc, BITSPIXEL);
  2281. fFlags = GetDeviceCaps (hdc, RASTERCAPS);
  2282. cPalSize = 3L;
  2283. cColorDepth = cPlanes * cBPP;
  2284. if ((fFlags & RC_PALETTE) == RC_PALETTE)
  2285. {
  2286. cPalSize = GetDeviceCaps (hdc, SIZEPALETTE);
  2287. }
  2288. ReleaseDC (HWND_DESKTOP, hdc);
  2289. // Get Worst case size of Plus! bitmap
  2290. cbNeeded = (cHorz * cVert * cColorDepth)/8L;
  2291. // Add in Bitmap File Header
  2292. cbNeeded += sizeof (BITMAPFILEHEADER);
  2293. // Add in Bitmap Info Header
  2294. cbNeeded += sizeof (BITMAPINFOHEADER);
  2295. // Add in worst case palette size
  2296. cbNeeded += sizeof (RGBQUAD) * cPalSize;
  2297. // Add in Fudge factor
  2298. cbNeeded += FUDGE_SIZE;
  2299. //
  2300. // Step 2. Is there a current Plus! bitmap ?!?
  2301. // Subtract it's size from our requirements
  2302. //
  2303. GetPlusBitmapName (szTemp);
  2304. hFile = FindFirstFile(szTemp, &fd);
  2305. if (hFile != INVALID_HANDLE_VALUE)
  2306. {
  2307. // Make sure it isn't larger than we know what to do with
  2308. if (!fd.nFileSizeHigh)
  2309. {
  2310. if (cbNeeded > fd.nFileSizeLow)
  2311. cbNeeded -= fd.nFileSizeLow;
  2312. else
  2313. {
  2314. // Just to be safe we need some space
  2315. cbNeeded = FUDGE_SIZE;
  2316. }
  2317. }
  2318. FindClose (hFile);
  2319. }
  2320. //
  2321. // Step 3. Get Space available on drive
  2322. //
  2323. chDrive = szTemp[0];
  2324. szDrive[0] = chDrive;
  2325. szDrive[1] = TEXT(':');
  2326. szDrive[2] = TEXT('\\');
  2327. szDrive[3] = 0;
  2328. if (! GetDiskFreeSpace (szDrive, &csCluster, &cbSector, &ccFree, &ccTotal))
  2329. return FALSE;
  2330. cbAvail = ccFree * csCluster * cbSector;
  2331. //
  2332. // Step 3. Is there a problem ?!?
  2333. //
  2334. if (cbAvail < cbNeeded)
  2335. {
  2336. // Inform User ?!?
  2337. if (fComplain)
  2338. {
  2339. // Let user know about space problem
  2340. ckNeeded = cbNeeded/1024L;
  2341. LoadString (hInstApp, STR_ERRNEEDSPACE, (LPTSTR)szTemp, MAX_MSGLEN);
  2342. wsprintf ((LPTSTR)szMsg, (LPTSTR)szTemp, chDrive, ckNeeded, chDrive);
  2343. MessageBox((HWND)hWnd, (LPTSTR)szMsg, (LPTSTR)szAppName,
  2344. MB_OK | MB_ICONERROR | MB_APPLMODAL);
  2345. }
  2346. // Don't bother to do any work
  2347. return FALSE;
  2348. }
  2349. return TRUE;
  2350. }
  2351. // GatherICONS
  2352. //
  2353. BOOL GatherICONS(LPCTSTR lpszThemefile)
  2354. {
  2355. DWORD ikey; // index for FROST_SUBKEY arrary
  2356. DWORD dwMaxKey; // number of FROST_SUBKEY's in array
  2357. int ival; // index for FROST_VALUE array
  2358. DWORD dwType; // type of reg key
  2359. DWORD dwSize; // size of reg key
  2360. HKEY hKeyCU; // handle to CURRENT_USER key
  2361. HKEY hKeyR; // handle to CLASSES_ROOT key
  2362. BOOL bGotCU; // Do we have a good CU handle?
  2363. BOOL bGotR; // Do we have a good ROOT handle?
  2364. BOOL bGotValCU; // We got the value from the CU key
  2365. BOOL bGotValR; // We got the value from the R key
  2366. BOOL bRet; // Return from bool function
  2367. BOOL bOK = TRUE; // cumulative return code for this function
  2368. LONG lret; // function result
  2369. TCHAR szNTReg[MAX_PATH]; // Reg path to use for NT
  2370. dwMaxKey = sizeof(fsCUIcons)/sizeof(FROST_SUBKEY);
  2371. // loop through each subkey in the fsCUIcons() enumeration
  2372. for (ikey = 0; ikey < dwMaxKey; ikey++) {
  2373. // The icon information is typically kept in the CURRENT_USER
  2374. // branch, but if we don't find it there we need to check the
  2375. // CLASSES_ROOT branch as well.
  2376. //
  2377. // On the NT Platform we check the c_szSoftwareClassesFmt reg
  2378. // path first (instead of CURRENT_USER/fsCUIcons) then try the
  2379. // CLASSES_ROOT branch.
  2380. // Try to open the appropriate CURRENT_USER subkey for this platform
  2381. if (IsPlatformNT())
  2382. {
  2383. lstrcpy(szNTReg, c_szSoftwareClassesFmt);
  2384. lstrcat(szNTReg, fsRoot[ikey].szSubKey);
  2385. lret = RegOpenKeyEx(HKEY_CURRENT_USER, szNTReg,
  2386. (DWORD)0, KEY_QUERY_VALUE, (PHKEY)&hKeyCU);
  2387. }
  2388. else // Not NT so don't use the touched-up current_user path
  2389. {
  2390. lret = RegOpenKeyEx(HKEY_CURRENT_USER, (LPTSTR)fsCUIcons[ikey].szSubKey,
  2391. (DWORD)0, KEY_QUERY_VALUE, (PHKEY)&hKeyCU);
  2392. }
  2393. if (lret != ERROR_SUCCESS) bGotCU = FALSE;
  2394. else bGotCU = TRUE;
  2395. // Try to open the CLASSES_ROOT subkey
  2396. lret = RegOpenKeyEx(HKEY_CLASSES_ROOT, (LPTSTR)fsRoot[ikey].szSubKey,
  2397. (DWORD)0, KEY_QUERY_VALUE, (PHKEY)&hKeyR);
  2398. if (lret != ERROR_SUCCESS) bGotR = FALSE;
  2399. else bGotR = TRUE;
  2400. // If we couldn't open a key in either the CU or R branch then
  2401. // we should write a null value to the Theme file.
  2402. if (!bGotCU && !bGotR) {
  2403. // (null loop if default string only)
  2404. for (ival = 0; ival < fsCUIcons[ikey].iNumVals; ival++) {
  2405. bRet = WritePrivateProfileString(
  2406. fsCUIcons[ikey].szSubKey,
  2407. (LPTSTR)fsCUIcons[ikey].fvVals[ival].szValName,
  2408. (LPTSTR)szNULL, lpszThemefile);
  2409. bOK = bOK && bRet;
  2410. }
  2411. if (fsCUIcons[ikey].fValues != FV_LIST) { // either def or list+def
  2412. bRet = WritePrivateProfileString(
  2413. fsCUIcons[ikey].szSubKey,
  2414. (LPTSTR)FROST_DEFSTR,
  2415. (LPTSTR)szNULL, lpszThemefile);
  2416. bOK = bOK && bRet;
  2417. }
  2418. continue; // Failed to OPEN reg key so continue on to next ikey
  2419. }
  2420. // Assume that we successfully opened either the CU or R subkey
  2421. // treat depending on type of values for this subkey
  2422. switch (fsCUIcons[ikey].fValues) {
  2423. case FV_LIST:
  2424. case FV_LISTPLUSDEFAULT:
  2425. // loop through each value in the list for this subkey
  2426. for (ival = 0; ival < fsCUIcons[ikey].iNumVals; ival++) {
  2427. bGotValCU = FALSE;
  2428. if (bGotCU) {
  2429. dwSize = (DWORD)(MAX_VALUELEN * sizeof(TCHAR));
  2430. lret = RegQueryValueEx(
  2431. hKeyCU,
  2432. fsCUIcons[ikey].fvVals[ival].szValName,
  2433. (LPDWORD)NULL,
  2434. (LPDWORD)&dwType,
  2435. (LPBYTE)pValue,
  2436. (LPDWORD)&dwSize);
  2437. if (lret == ERROR_SUCCESS)
  2438. {
  2439. bGotValCU = TRUE;
  2440. if (REG_EXPAND_SZ == dwType) ExpandSZ(pValue);
  2441. }
  2442. }
  2443. // If we have a CLASSES_ROOT handle AND:
  2444. //
  2445. // * We failed to read from CU OR
  2446. // * We got a NULL string from CU
  2447. //
  2448. // Try reading from the CR branch instead:
  2449. bGotValR = FALSE;
  2450. if ((bGotR) && (!bGotValCU || !*pValue)) {
  2451. dwSize = (DWORD)(MAX_VALUELEN * sizeof(TCHAR));
  2452. lret = RegQueryValueEx(
  2453. hKeyR,
  2454. fsRoot[ikey].fvVals[ival].szValName,
  2455. (LPDWORD)NULL,
  2456. (LPDWORD)&dwType,
  2457. (LPBYTE)pValue,
  2458. (LPDWORD)&dwSize);
  2459. if (lret == ERROR_SUCCESS)
  2460. {
  2461. bGotValR = TRUE;
  2462. if (REG_EXPAND_SZ == dwType) ExpandSZ(pValue);
  2463. }
  2464. }
  2465. if (!bGotValCU && !bGotValR) {
  2466. // Failed to get value from either CU or R so write
  2467. // a null string to the Theme file
  2468. bRet = WritePrivateProfileString(
  2469. fsCUIcons[ikey].szSubKey,
  2470. (LPTSTR)fsCUIcons[ikey].fvVals[ival].szValName,
  2471. (LPTSTR)szNULL, lpszThemefile);
  2472. bOK = bOK && bRet;
  2473. continue; // Next ival
  2474. }
  2475. // Assume we got the value from either the CU or R key
  2476. // Regardless of which one we *got* it from we'll write it
  2477. // out to the Theme file as if it came from the CURRENT USER
  2478. // branch
  2479. if (fsCUIcons[ikey].fvVals[ival].bValRelPath)
  2480. AbstractPath((LPTSTR)pValue, MAX_VALUELEN);
  2481. bRet = WritePrivateProfileString(
  2482. fsCUIcons[ikey].szSubKey,
  2483. (LPTSTR)fsCUIcons[ikey].fvVals[ival].szValName,
  2484. (LPTSTR)pValue, lpszThemefile);
  2485. bOK = bOK && bRet;
  2486. } // End for ival loop
  2487. // check if just list or list plus default
  2488. if (FV_LIST == fsCUIcons[ikey].fValues)
  2489. break; // normal EXIT
  2490. // else fall through and do default, too
  2491. case FV_DEFAULT:
  2492. //
  2493. // Default string: There are no "valuenames" to search for under
  2494. // this key.
  2495. //
  2496. // First try getting the default string from the CU key
  2497. bGotValCU = FALSE;
  2498. if (bGotCU) {
  2499. dwSize = (DWORD)(MAX_VALUELEN * sizeof(TCHAR));
  2500. lret = RegQueryValueEx(hKeyCU,
  2501. (LPTSTR)szNULL,// null str to get default
  2502. (LPDWORD)NULL,
  2503. (LPDWORD)&dwType,
  2504. (LPBYTE)pValue, // getting actual def value
  2505. (LPDWORD)&dwSize);
  2506. if (ERROR_SUCCESS == lret)
  2507. {
  2508. bGotValCU = TRUE;
  2509. if (REG_EXPAND_SZ == dwType) ExpandSZ(pValue);
  2510. }
  2511. }
  2512. // If we have a CLASSES_ROOT handle AND:
  2513. //
  2514. // * We failed to read from CU OR
  2515. // * We got a NULL string from CU
  2516. //
  2517. // Try reading from the CR branch instead:
  2518. bGotValR = FALSE;
  2519. if ((bGotR) && (!bGotValCU || !*pValue)) {
  2520. dwSize = (DWORD)(MAX_VALUELEN * sizeof(TCHAR));
  2521. lret = RegQueryValueEx(hKeyR,
  2522. (LPTSTR)szNULL,// null str to get default
  2523. (LPDWORD)NULL,
  2524. (LPDWORD)&dwType,
  2525. (LPBYTE)pValue, // getting actual def value
  2526. (LPDWORD)&dwSize);
  2527. if (ERROR_SUCCESS == lret)
  2528. {
  2529. bGotValR = TRUE;
  2530. if (REG_EXPAND_SZ == dwType) ExpandSZ(pValue);
  2531. }
  2532. }
  2533. if (!bGotValCU && !bGotValR) {
  2534. // Failed to get the default value from either the CU or R key
  2535. *pValue = TEXT('\0'); // Set pValue to null string
  2536. }
  2537. // OK, if this is a path/filename, see about xlating to relative path
  2538. if (fsCUIcons[ikey].bDefRelPath)
  2539. AbstractPath((LPTSTR)pValue, MAX_VALUELEN);
  2540. //
  2541. // Phew, finally. Write single default value
  2542. //
  2543. bRet = WritePrivateProfileString((LPTSTR)(fsCUIcons[ikey].szSubKey),
  2544. (LPTSTR)FROST_DEFSTR,
  2545. (LPTSTR)pValue, lpszThemefile);
  2546. bOK = bOK && bRet;
  2547. break;
  2548. default:
  2549. Assert(FALSE, TEXT("Unlisted .fValues value in GatherICONS!\n"));
  2550. break;
  2551. } // End switch
  2552. // close the keys if appropriate
  2553. if (bGotR) RegCloseKey(hKeyR);
  2554. if (bGotCU) RegCloseKey(hKeyCU);
  2555. } // End for ikey
  2556. return bOK;
  2557. }
  2558. // ApplyWebView
  2559. //
  2560. // For each setting in the [WebView] portion of the *.Theme
  2561. // file copy the specified file into the \windir\web directory.
  2562. //
  2563. // If there is no setting, extract the resource from the WEBVW.DLL.
  2564. //
  2565. // [WebView]
  2566. //
  2567. // WVLEFT.BMP = filename.bmp // Webview top left "watermark"
  2568. // WVLINE.GIF = filename.gif // Webview line in top left corner
  2569. // WVLOGO.GIF = filename.gif // Webview gears & win98 logo
  2570. //
  2571. // Params: Full path to *.Theme file.
  2572. //
  2573. // Returns: FALSE if major catastrophe
  2574. // TRUE if things (sort of) went OK
  2575. //
  2576. BOOL ApplyWebView(LPCTSTR szThemefile)
  2577. {
  2578. DWORD dwI = 0; // Index into szWVNames array
  2579. DWORD dwResult = 0; // Result of function call
  2580. TCHAR szWinDirWeb[MAX_PATH]; // Path to \windir\web
  2581. TCHAR szWinDirWebFile[MAX_PATH]; // Full path to WebView art file
  2582. TCHAR szBuffer[MAX_PATH]; // Read from *.Theme file
  2583. TCHAR szTempPath[MAX_PATH]; // Path to temp directory
  2584. TCHAR szTempFile[MAX_PATH]; // Full path to temporary file
  2585. // Initialize the path to the \windir\web directory where we'll
  2586. // put the WebView artwork files
  2587. if (!GetWindowsDirectory(szWinDirWeb, MAX_PATH)) {
  2588. // This is bad -- we can't find the windows directory?! Abandon ship.
  2589. return FALSE;
  2590. }
  2591. lstrcat(szWinDirWeb, TEXT("\\Web\0"));
  2592. // Get a temp filename where we can store the resource we extract
  2593. // out of WEBVW.DLL (if we need to).
  2594. // First the path to temp dir
  2595. if (!GetTempPath(MAX_PATH, szTempPath)) {
  2596. // This is bad -- we can't find the temp directory?! Abandon ship.
  2597. return FALSE;
  2598. }
  2599. // Now a temp filename
  2600. if (!GetTempFileName(szTempPath, TEXT("THM"), 0, szTempFile)) {
  2601. // Couldn't get a temp file? Not likely but if so bail out...
  2602. return FALSE;
  2603. }
  2604. // For each potential [WebView] setting in the Theme file do
  2605. // this stuff...
  2606. for (dwI = 0; dwI < MAX_WVNAMES; dwI++)
  2607. {
  2608. // Get the current setting from the *.Theme file if the setting
  2609. // exists
  2610. GetPrivateProfileString(TEXT("WebView"),
  2611. szWVNames[dwI],
  2612. TEXT("\0"),
  2613. szBuffer,
  2614. MAX_PATH,
  2615. szThemefile);
  2616. // Instantiate the path
  2617. InstantiatePath(szBuffer, MAX_PATH);
  2618. // Now check to see if this file even exists
  2619. dwResult = GetFileAttributes(szBuffer);
  2620. // If GFA failed we need to extract this file from webvw.dll
  2621. if (0xFFFFFFFF == dwResult) {
  2622. if (ExtractWVResource(szWVNames[dwI], szTempFile)) {
  2623. // We successfully extracted the resource into TempFile.
  2624. // Now copy it to the ultimate destination.
  2625. // Create a path to the \windir\web\file
  2626. lstrcpy(szWinDirWebFile, szWinDirWeb);
  2627. lstrcat(szWinDirWebFile, TEXT("\\"));
  2628. lstrcat(szWinDirWebFile, szWVNames[dwI]);
  2629. // Copy the file
  2630. DeleteFile(szWinDirWebFile);
  2631. CopyFile(szTempFile, szWinDirWebFile, FALSE);
  2632. // Delete the temporary file
  2633. DeleteFile(szTempFile);
  2634. }
  2635. } // End if GFA failed
  2636. else {
  2637. // The .Theme file exists so we need to copy it to the Web dir
  2638. // Create a path to the \windir\web\file
  2639. lstrcpy(szWinDirWebFile, szWinDirWeb);
  2640. lstrcat(szWinDirWebFile, TEXT("\\"));
  2641. lstrcat(szWinDirWebFile, szWVNames[dwI]);
  2642. DeleteFile(szWinDirWebFile);
  2643. CopyFile(szBuffer, szWinDirWebFile, FALSE);
  2644. }
  2645. } // End for dwI loop
  2646. // Cleanup the temp file
  2647. DeleteFile(szTempFile);
  2648. return TRUE; // this isn't very meaningful...
  2649. }
  2650. // GatherWebView
  2651. //
  2652. // Collect the current WebView artwork files, store them in the
  2653. // theme dir under the appropriate name, and save the settings
  2654. // in the *.Theme file under the appropriate setting.
  2655. //
  2656. // [WebView]
  2657. //
  2658. // WVLEFT.BMP = Theme name WVLEFT.BMP // Webview top left "watermark"
  2659. // WVLINE.GIF = Theme name WVLINE.GIF // Webview line in top left corner
  2660. // WVLOGO.GIF = Theme name WVLOGO.GIF // Webview gears & win98 logo
  2661. //
  2662. // Params: Full path to *.Theme file.
  2663. //
  2664. // Returns: FALSE if major catastrophe
  2665. // TRUE if things sort of went OK
  2666. //
  2667. BOOL GatherWebView(LPCTSTR szThemefile)
  2668. {
  2669. DWORD dwI = 0; // Index into szWVNames array
  2670. TCHAR szWinDirWeb[MAX_PATH]; // Path to \windir\web
  2671. TCHAR szWinDirWebFile[MAX_PATH]; // Full path to WebView art file
  2672. TCHAR szSaveFile[MAX_PATH]; // Full path to destination file
  2673. // Initialize the path to the \windir\web directory where we'll
  2674. // get the WebView artwork files
  2675. if (!GetWindowsDirectory(szWinDirWeb, MAX_PATH)) {
  2676. // This is bad -- we can't find the windows directory?! Abandon ship.
  2677. return FALSE;
  2678. }
  2679. lstrcat(szWinDirWeb, TEXT("\\Web\0"));
  2680. // For each potential [WebView] setting in the Theme file do
  2681. // this stuff...
  2682. for (dwI = 0; dwI < MAX_WVNAMES; dwI++)
  2683. {
  2684. // Verify that we have a file for the current setting
  2685. lstrcpy(szWinDirWebFile, szWinDirWeb);
  2686. lstrcat(szWinDirWebFile, TEXT("\\"));
  2687. lstrcat(szWinDirWebFile, szWVNames[dwI]);
  2688. if (GetFileAttributes(szWinDirWebFile)) {
  2689. // We've got a file so let's save it to the theme dir
  2690. // under a unique name
  2691. if (GetWVFilename(szThemefile, szWVNames[dwI], szSaveFile)) {
  2692. if (CopyFile(szWinDirWebFile, szSaveFile, FALSE)) {
  2693. SetFileAttributes(szSaveFile, FILE_ATTRIBUTE_ARCHIVE);
  2694. AbstractPath(szSaveFile, MAX_PATH);
  2695. WritePrivateProfileString(TEXT("WebView"),
  2696. szWVNames[dwI],
  2697. szSaveFile,
  2698. szThemefile);
  2699. }
  2700. }
  2701. }
  2702. }
  2703. return TRUE;
  2704. }
  2705. // ExtractWVResource
  2706. //
  2707. // Extracts the specified custom resource from the windir\system\webvw.dll
  2708. // file and stores it in the specified destination file.
  2709. //
  2710. // If the destination file exists it is overwritten.
  2711. //
  2712. // Params: lpszResource -- Resource name to extract (i.e. WVLEFT.BMP)
  2713. // lpszDestination -- File to save resource to
  2714. //
  2715. // Returns: True if successful, False if not.
  2716. //
  2717. BOOL ExtractWVResource(LPCTSTR lpszResource, LPCTSTR lpszDestination)
  2718. {
  2719. HINSTANCE hInstWVDLL = NULL; // Instance handle for WEBVW.DLL
  2720. HRSRC hRsrc = NULL; // Handle to resource in WEBVW.DLL
  2721. HGLOBAL hGlobal = NULL; // Global handle to loaded resource
  2722. LPVOID lpResource = NULL; // Memory pointer to locked resource
  2723. DWORD dwRSize = 0; // Size of resource
  2724. DWORD dwBytesW = 0; // Number of bytes written to dest file
  2725. HANDLE hFile = NULL; // Handle to destination file
  2726. TCHAR szWebVWDLL[MAX_PATH]; // Full path to \windir\system\webvw.dll
  2727. DWORD dwResult; // Result of function call
  2728. // Build full path to \windir\system\webvw.dll
  2729. if (!GetWindowsDirectory(szWebVWDLL, MAX_PATH)) {
  2730. // This is bad -- we can't find the windows directory?! Abandon ship.
  2731. return FALSE;
  2732. }
  2733. if (IsPlatformNT()) {
  2734. lstrcat(szWebVWDLL, TEXT("\\SYSTEM32\\WEBVW.DLL\0"));
  2735. }
  2736. else {
  2737. lstrcat(szWebVWDLL, TEXT("\\SYSTEM\\WEBVW.DLL\0"));
  2738. }
  2739. // Load WEBVW.DLL
  2740. hInstWVDLL = NULL;
  2741. hInstWVDLL = LoadLibrary(szWebVWDLL);
  2742. if (!hInstWVDLL) {
  2743. return FALSE;
  2744. }
  2745. // Find the desired resource in WEBVW.DLL
  2746. hRsrc = NULL;
  2747. hRsrc = FindResource(hInstWVDLL, lpszResource, TEXT("#23") /*Resource Type*/);
  2748. if (!hRsrc) {
  2749. FreeLibrary(hInstWVDLL);
  2750. return FALSE;
  2751. }
  2752. // Load the resource into memory
  2753. hGlobal = NULL;
  2754. hGlobal = LoadResource(hInstWVDLL, hRsrc);
  2755. if (!hGlobal) {
  2756. FreeLibrary(hInstWVDLL);
  2757. return FALSE;
  2758. }
  2759. // Figure out how big the resource is.
  2760. dwRSize = 0;
  2761. dwRSize = SizeofResource(hInstWVDLL, hRsrc);
  2762. if (!dwRSize) {
  2763. FreeLibrary(hInstWVDLL);
  2764. return FALSE;
  2765. }
  2766. // Get a memory pointer to and lock the resource
  2767. lpResource = NULL;
  2768. lpResource = LockResource(hGlobal);
  2769. if (!lpResource) {
  2770. FreeLibrary(hInstWVDLL);
  2771. return FALSE;
  2772. }
  2773. // Get a handle to the destination file
  2774. hFile = CreateFile(lpszDestination,
  2775. GENERIC_WRITE,
  2776. FILE_SHARE_READ,
  2777. NULL,
  2778. CREATE_ALWAYS,
  2779. FILE_ATTRIBUTE_ARCHIVE,
  2780. NULL);
  2781. if (INVALID_HANDLE_VALUE == hFile) {
  2782. FreeLibrary(hInstWVDLL);
  2783. return FALSE;
  2784. }
  2785. // Write the full resource into the destination file
  2786. dwBytesW = 0;
  2787. dwResult = 0;
  2788. dwResult = WriteFile(hFile, lpResource, dwRSize, &dwBytesW, NULL);
  2789. // Problems writing the resource?
  2790. if ((!dwResult) || (dwRSize != dwBytesW)) {
  2791. CloseHandle(hFile);
  2792. DeleteFile(lpszDestination);
  2793. FreeLibrary(hInstWVDLL);
  2794. return FALSE;
  2795. }
  2796. // Cleanup and hit the road
  2797. CloseHandle(hFile);
  2798. FreeLibrary(hInstWVDLL);
  2799. return TRUE;
  2800. }
  2801. // GetWVFilename
  2802. //
  2803. // Given a Themefile (with path info), a WebView file name (i.e. WVLEFT.BMP),
  2804. // and a pointer to a string buffer, build a name for the Theme WebView file.
  2805. //
  2806. // For example:
  2807. //
  2808. // lpszThemefile = C:\Program Files\Plus!\Themes\Sports.Theme
  2809. // lpszWVName = WVLOGO.GIF
  2810. //
  2811. // Result:
  2812. //
  2813. // lpszWVFile = "C:\Program Files\Plus!\Themes\Sports WVLOGO.GIF"
  2814. //
  2815. // NOTE: lpszWVFile does not have the double quotes in it -- I put
  2816. // them in this comment for clarity.
  2817. //
  2818. // Params:
  2819. //
  2820. // lpszThemefile -- path/name of theme file
  2821. // lpszWVName -- name of WebView artwork file
  2822. // lpszWVFile -- destination buffer to hold final file name
  2823. //
  2824. // Returns: TRUE if lpszWVFile is valid name, else FALSE
  2825. BOOL GetWVFilename(LPCTSTR lpszThemefile, LPCTSTR lpszWVName, LPTSTR lpszWVFile)
  2826. {
  2827. LPTSTR lpszThemeName = NULL; // Pointer to Theme filename in path
  2828. LPTSTR Begin;
  2829. LPTSTR Current;
  2830. LPTSTR End;
  2831. // Take the easy out if we got bogus params
  2832. if (!lpszThemefile || !*lpszThemefile || !lpszWVName || !*lpszWVName ||
  2833. !lpszWVFile) {
  2834. return FALSE;
  2835. }
  2836. if (GetFullPathName(lpszThemefile, MAX_PATH, lpszWVFile, &lpszThemeName)) {
  2837. // Remove the extension from the Theme name -- go to the
  2838. // end of the string then back up to the first ".".
  2839. Current = lpszWVFile;
  2840. while (*Current) Current = CharNext(Current);
  2841. End = Current;
  2842. // Current now points to the end of lpszWVFile -- back up to the
  2843. // first '.' (the extension marker).
  2844. Begin = lpszWVFile;
  2845. Current = CharPrev(Begin, Current);
  2846. while ((Current > Begin) && (*Current != TEXT('.'))) Current = CharPrev(Begin, Current);
  2847. if (Current >= Begin) *Current = TEXT('\0');
  2848. // Append a space followed by the WebView file name
  2849. lstrcat(lpszWVFile, TEXT(" "));
  2850. lstrcat(lpszWVFile, lpszWVName);
  2851. }
  2852. return TRUE;
  2853. }
  2854. VOID ExpandSZ(LPTSTR pszSrc)
  2855. {
  2856. LPTSTR pszTmp;
  2857. Assert(FALSE, TEXT("GOT EXPAND_SZ -- Before: "));
  2858. Assert(FALSE, pszSrc);
  2859. Assert(FALSE, TEXT("\n"));
  2860. pszTmp = (LPTSTR)GlobalAlloc(GPTR, (MAX_PATH * sizeof(TCHAR)));
  2861. Assert(pszTmp, TEXT("THEMES: Error allocating memory in ExpandSZ()\n"));
  2862. if (pszTmp)
  2863. {
  2864. if (ExpandEnvironmentStrings(pszSrc, pszTmp, MAX_PATH))
  2865. {
  2866. lstrcpy(pszSrc, pszTmp);
  2867. }
  2868. GlobalFree(pszTmp);
  2869. }
  2870. Assert(FALSE, TEXT("GOT EXPAND_SZ -- After: "));
  2871. Assert(FALSE, pszSrc);
  2872. Assert(FALSE, TEXT("\n"));
  2873. return;
  2874. }