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

611 lines
22 KiB

  1. #include <windows.h>
  2. #include <winuserp.h>
  3. #include <tchar.H>
  4. #include <stdio.h>
  5. #include "shmgdefs.h"
  6. #include <regstr.h>
  7. // structure used to store a scheme in the registry
  8. #define SCHEME_VERSION_16 1
  9. #define LF_FACESIZE16 32
  10. #pragma pack(1)
  11. typedef struct {
  12. SHORT lfHeight;
  13. SHORT lfWidth;
  14. SHORT lfEscapement;
  15. SHORT lfOrientation;
  16. SHORT lfWeight;
  17. BYTE lfItalic;
  18. BYTE lfUnderline;
  19. BYTE lfStrikeOut;
  20. BYTE lfCharSet;
  21. BYTE lfOutPrecision;
  22. BYTE lfClipPrecision;
  23. BYTE lfQuality;
  24. BYTE lfPitchAndFamily;
  25. char lfFaceName[LF_FACESIZE16];
  26. } LOGFONT16;
  27. typedef LOGFONT16 *LPLOGFONT16;
  28. typedef struct {
  29. SHORT version;
  30. NONCLIENTMETRICSA ncm;
  31. LOGFONT16 lfIconTitle;
  32. COLORREF rgb[COLOR_MAX];
  33. } SCHEMEDATA16;
  34. typedef SCHEMEDATA16 *PSCHEMEDATA16;
  35. #pragma pack()
  36. // structure used to store a scheme in the registry
  37. #define SCHEME_VERSION_NT 2
  38. typedef struct {
  39. SHORT version;
  40. WORD wDummy; // for alignment
  41. NONCLIENTMETRICSW ncm;
  42. LOGFONTW lfIconTitle;
  43. COLORREF rgb[COLOR_MAX];
  44. } SCHEMEDATAW;
  45. typedef SCHEMEDATAW *PSCHEMEDATAW;
  46. typedef TCHAR FILEPATH[MAX_PATH];
  47. typedef struct tagSZNODE {
  48. TCHAR *psz;
  49. struct tagSZNODE *next;
  50. } SZNODE;
  51. TCHAR szApprSchemes[] = TEXT("Control Panel\\Appearance\\Schemes");
  52. TCHAR szNTCsrSchemes[] = TEXT("Control Panel\\Cursor Schemes");
  53. TCHAR szWinCsrSchemes[] = TEXT("Control Panel\\Cursors\\Schemes");
  54. TCHAR szSystemRoot[] = TEXT("%SystemRoot%\\System32\\");
  55. const TCHAR szWinCursors[] = TEXT("Control Panel\\Cursors");
  56. const TCHAR szSchemes[] = TEXT("Schemes");
  57. const TCHAR szDaytonaSchemes[] = REGSTR_PATH_SETUP TEXT("\\Control Panel\\Cursors\\Schemes");
  58. #define ID_NONE_SCHEME 0 //
  59. #define ID_USER_SCHEME 1 // These are the possible values of "Scheme Source" as define for the
  60. #define ID_OS_SCHEME 2 // mouse pointer applet
  61. /***********************************************************************\
  62. *
  63. * CONVERSION ROUTINES
  64. *
  65. * NOTE: Although ConvertLF16to32 appears to be identical to ConvertLFAtoW
  66. * they are actually different once compiled: the size of the individual
  67. * fields for a LOGFONT16 and a LOGFONTA are different.
  68. *
  69. \***********************************************************************/
  70. void ConvertLF16to32( LPLOGFONTW plfwDst, UNALIGNED LOGFONT16 *plfaSrc ) {
  71. plfwDst->lfHeight = plfaSrc->lfHeight;
  72. plfwDst->lfWidth = plfaSrc->lfWidth;
  73. plfwDst->lfEscapement = plfaSrc->lfEscapement;
  74. plfwDst->lfOrientation = plfaSrc->lfOrientation;
  75. plfwDst->lfWeight = plfaSrc->lfWeight;
  76. plfwDst->lfItalic = plfaSrc->lfItalic;
  77. plfwDst->lfUnderline = plfaSrc->lfUnderline;
  78. plfwDst->lfStrikeOut = plfaSrc->lfStrikeOut;
  79. plfwDst->lfCharSet = plfaSrc->lfCharSet;
  80. plfwDst->lfOutPrecision = plfaSrc->lfOutPrecision;
  81. plfwDst->lfClipPrecision = plfaSrc->lfClipPrecision;
  82. plfwDst->lfQuality = plfaSrc->lfQuality;
  83. plfwDst->lfPitchAndFamily = plfaSrc->lfPitchAndFamily;
  84. MultiByteToWideChar(CP_ACP, 0, plfaSrc->lfFaceName, -1, plfwDst->lfFaceName, ARRAYSIZE(plfwDst->lfFaceName));
  85. }
  86. void ConvertLFAtoW( LPLOGFONTW plfwDst, UNALIGNED LOGFONTA *plfaSrc ) {
  87. plfwDst->lfHeight = plfaSrc->lfHeight;
  88. plfwDst->lfWidth = plfaSrc->lfWidth;
  89. plfwDst->lfEscapement = plfaSrc->lfEscapement;
  90. plfwDst->lfOrientation = plfaSrc->lfOrientation;
  91. plfwDst->lfWeight = plfaSrc->lfWeight;
  92. plfwDst->lfItalic = plfaSrc->lfItalic;
  93. plfwDst->lfUnderline = plfaSrc->lfUnderline;
  94. plfwDst->lfStrikeOut = plfaSrc->lfStrikeOut;
  95. plfwDst->lfCharSet = plfaSrc->lfCharSet;
  96. plfwDst->lfOutPrecision = plfaSrc->lfOutPrecision;
  97. plfwDst->lfClipPrecision = plfaSrc->lfClipPrecision;
  98. plfwDst->lfQuality = plfaSrc->lfQuality;
  99. plfwDst->lfPitchAndFamily = plfaSrc->lfPitchAndFamily;
  100. MultiByteToWideChar(CP_ACP, 0, plfaSrc->lfFaceName, -1, plfwDst->lfFaceName, ARRAYSIZE(plfwDst->lfFaceName));
  101. }
  102. void ConvertNCMAtoW( LPNONCLIENTMETRICSW pncmwDst, UNALIGNED NONCLIENTMETRICSA *pncmaSrc ) {
  103. pncmwDst->cbSize = sizeof(*pncmwDst);
  104. pncmwDst->iBorderWidth = pncmaSrc->iBorderWidth;
  105. pncmwDst->iScrollWidth = pncmaSrc->iScrollWidth;
  106. pncmwDst->iScrollHeight = pncmaSrc->iScrollHeight;
  107. pncmwDst->iCaptionWidth = pncmaSrc->iCaptionWidth;
  108. pncmwDst->iCaptionHeight = pncmaSrc->iCaptionHeight;
  109. pncmwDst->iSmCaptionWidth = pncmaSrc->iSmCaptionWidth;
  110. pncmwDst->iSmCaptionHeight = pncmaSrc->iSmCaptionHeight;
  111. pncmwDst->iMenuWidth = pncmaSrc->iMenuWidth;
  112. pncmwDst->iMenuHeight = pncmaSrc->iMenuHeight;
  113. ConvertLFAtoW( &(pncmwDst->lfCaptionFont), &(pncmaSrc->lfCaptionFont) );
  114. ConvertLFAtoW( &(pncmwDst->lfSmCaptionFont), &(pncmaSrc->lfSmCaptionFont) );
  115. ConvertLFAtoW( &(pncmwDst->lfMenuFont), &(pncmaSrc->lfMenuFont) );
  116. ConvertLFAtoW( &(pncmwDst->lfStatusFont), &(pncmaSrc->lfStatusFont) );
  117. ConvertLFAtoW( &(pncmwDst->lfMessageFont), &(pncmaSrc->lfMessageFont) );
  118. }
  119. void CvtDeskCPL_Win95ToSUR( void ) {
  120. HKEY hk = NULL;
  121. DWORD cchClass, cb, cch, cSubk, cchMaxSubk, cchMaxCls, iVal, cchMaxVName;
  122. DWORD cbMaxVData, cbSecDes, dwType;
  123. FILETIME pfLstWr;
  124. TCHAR szClass[4];
  125. LONG lRet;
  126. PVOID pvVData = NULL;
  127. LPTSTR pszVName = NULL;
  128. LONG erc;
  129. FILETIME ftLstWr;
  130. // Open the key (Appearence\Schemes)
  131. if (RegOpenKeyEx(HKEY_CURRENT_USER, szApprSchemes, 0, KEY_READ | KEY_WRITE, &hk) != ERROR_SUCCESS)
  132. goto ErrorExit;
  133. cchClass = ARRAYSIZE(szClass);
  134. erc = RegQueryInfoKey(hk, szClass, &cchClass, NULL, &cSubk, &cchMaxSubk,
  135. &cchMaxCls, &iVal, &cchMaxVName, &cbMaxVData, &cbSecDes, &ftLstWr);
  136. if( erc != ERROR_SUCCESS && erc != ERROR_MORE_DATA)
  137. goto ErrorExit;
  138. cchMaxVName += 1;
  139. pszVName = LocalAlloc(LMEM_FIXED, cchMaxVName * SIZEOF(TCHAR));
  140. pvVData = LocalAlloc(LMEM_FIXED, cbMaxVData);
  141. if (pvVData == NULL || pszVName == NULL)
  142. goto ErrorExit;
  143. // for each value in the key
  144. iVal = 0;
  145. for(;;) {
  146. PSCHEMEDATA16 psda;
  147. SCHEMEDATAW sdw;
  148. cch = cchMaxVName;
  149. cb = cbMaxVData;
  150. if( RegEnumValue(hk, iVal++, pszVName, &cch, NULL, &dwType, pvVData, &cb ) != ERROR_SUCCESS )
  151. break;
  152. // check if it has been converted yet
  153. psda = pvVData;
  154. if (psda->version != SCHEME_VERSION_16)
  155. continue;
  156. // if not, convert ANSI font names to UNICODE and tag the structure
  157. // as converted
  158. sdw.version = SCHEME_VERSION_NT;
  159. sdw.wDummy = 0;
  160. ASSERT(sizeof(psda->rgb) == sizeof(sdw.rgb));
  161. CopyMemory(sdw.rgb, psda->rgb, sizeof(sdw.rgb));
  162. ConvertNCMAtoW( &(sdw.ncm), &(psda->ncm) );
  163. ConvertLF16to32( &(sdw.lfIconTitle), &(psda->lfIconTitle) );
  164. // write the new data back out
  165. RegSetValueEx(hk, pszVName, 0L, dwType, (LPBYTE)&sdw, SIZEOF(sdw));
  166. }
  167. ErrorExit:
  168. // close the key
  169. if (hk)
  170. RegCloseKey(hk);
  171. if (pvVData)
  172. LocalFree(pvVData);
  173. if (pszVName)
  174. LocalFree(pszVName);
  175. }
  176. #ifdef LATER
  177. void CvtDeskCPL_DaytonaToSur( void ) {
  178. }
  179. #endif
  180. //
  181. // NOTE! These enums MUST be in the same order that the names will appear in the registry string
  182. enum { arrow,help,appstart,wait,cross,ibeam,pen,no,sizens,sizewe,sizenwse,sizenesw,move,altsel, C_CURSORS } ID_CURSORS;
  183. FILEPATH aszCurs[C_CURSORS];
  184. TCHAR szOut[(C_CURSORS * (MAX_PATH+1)) + 1];
  185. void CvtCursorsCPL_DaytonaToSUR( void ) {
  186. HKEY hkIn = NULL, hkOut = NULL;
  187. DWORD cchClass;
  188. LONG erc;
  189. DWORD dwType;
  190. DWORD cSubk;
  191. DWORD cchMaxSubk;
  192. DWORD cchMaxCls;
  193. DWORD iVal;
  194. DWORD cchMaxVName;
  195. DWORD cbMaxVData;
  196. DWORD cbSecDes;
  197. FILETIME ftLstWr;
  198. DWORD cch;
  199. DWORD cb;
  200. TCHAR szClass[4];
  201. PVOID pvVData = NULL;
  202. LPTSTR pszVName = NULL;
  203. // Open the source registry key (Cursor Schemes)
  204. if (RegOpenKeyEx(HKEY_CURRENT_USER, szNTCsrSchemes, 0, KEY_READ, &hkIn) != ERROR_SUCCESS)
  205. goto ErrorExit;
  206. // Open/create the dest registry key (Cursors\Schemes)
  207. if (RegCreateKeyEx(HKEY_CURRENT_USER, szWinCsrSchemes, 0, TEXT(""), REG_OPTION_NON_VOLATILE,
  208. KEY_QUERY_VALUE | KEY_SET_VALUE, NULL, &hkOut, NULL) != ERROR_SUCCESS) {
  209. goto ErrorExit;
  210. }
  211. // for each value in the source key
  212. cchClass = ARRAYSIZE(szClass);
  213. erc = RegQueryInfoKey(hkIn, szClass, &cchClass, NULL, &cSubk, &cchMaxSubk,
  214. &cchMaxCls, &iVal, &cchMaxVName, &cbMaxVData, &cbSecDes, &ftLstWr);
  215. if( erc != ERROR_SUCCESS && erc != ERROR_MORE_DATA)
  216. goto ErrorExit;
  217. cchMaxVName += 1;
  218. pszVName = LocalAlloc(LMEM_FIXED, cchMaxVName * SIZEOF(TCHAR));
  219. pvVData = LocalAlloc(LMEM_FIXED, cbMaxVData + sizeof(TCHAR));
  220. if (pvVData == NULL || pszVName == NULL)
  221. goto ErrorExit;
  222. iVal = 0;
  223. for(;;) {
  224. DWORD cbData;
  225. LPTSTR pszOut;
  226. int i;
  227. cch = cchMaxVName;
  228. cb = cbMaxVData;
  229. if( RegEnumValue(hkIn, iVal++, pszVName, &cch, NULL, &dwType, pvVData, &cb ) != ERROR_SUCCESS )
  230. break;
  231. // if the name already exists in the new key then skip this one
  232. if (RegQueryValueEx(hkOut, pszVName, NULL, NULL, NULL, &cbData ) == ERROR_SUCCESS && cbData != 0)
  233. continue;
  234. if (dwType != REG_EXPAND_SZ && dwType != REG_SZ)
  235. continue;
  236. *(TCHAR *)((LPBYTE)pvVData+cb) = TEXT('\0'); // Make sure nul terminated
  237. // convert the data to SUR format
  238. for( i = 0; i < C_CURSORS; i++ ) {
  239. *aszCurs[i] = TEXT('\0');
  240. }
  241. //arrow,wait,appstart,no,ibeam,cross,ns,ew,nwse,nesw,move
  242. _stscanf(pvVData, TEXT("%[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,]"),
  243. aszCurs[arrow],aszCurs[wait],aszCurs[appstart],aszCurs[no],
  244. aszCurs[ibeam],aszCurs[cross],aszCurs[sizens],aszCurs[sizewe],
  245. aszCurs[sizenwse],aszCurs[sizenesw],aszCurs[move]);
  246. szOut[0] = TEXT('\0');
  247. pszOut = szOut;
  248. for( i = 0; i < C_CURSORS; i++ ) {
  249. if (!HasPath(aszCurs[i]))
  250. pszOut += mystrcpy( pszOut, szSystemRoot, TEXT('\0') );
  251. pszOut += mystrcpy( pszOut, aszCurs[i], TEXT('\0') );
  252. *pszOut++ = TEXT(',');
  253. }
  254. *(pszOut-1) = TEXT('\0');
  255. // write the new data back out
  256. RegSetValueEx(hkOut, pszVName, 0L, REG_EXPAND_SZ, (LPBYTE)szOut, (DWORD)(sizeof(TCHAR)*(pszOut - szOut)));
  257. }
  258. ErrorExit:
  259. // close the registry keys
  260. if (hkIn)
  261. RegCloseKey(hkIn);
  262. if (hkOut)
  263. RegCloseKey(hkOut);
  264. if (pvVData)
  265. LocalFree(pvVData);
  266. if (pszVName)
  267. LocalFree(pszVName);
  268. }
  269. void FixupCursorSchemePaths( void ) {
  270. HKEY hk = NULL;
  271. DWORD cchClass, cb, cch, cSubk, cchMaxSubk, cchMaxCls, iVal, cchMaxVName;
  272. DWORD cbMaxVData, cbSecDes, dwType;
  273. FILETIME pfLstWr;
  274. TCHAR szClass[4];
  275. LONG lRet;
  276. PVOID pvVData = NULL;
  277. LPTSTR pszVName = NULL;
  278. LONG erc;
  279. FILETIME ftLstWr;
  280. // Open the key (Appearence\Schemes)
  281. if (RegOpenKeyEx(HKEY_CURRENT_USER, szWinCsrSchemes, 0, KEY_READ | KEY_WRITE, &hk) != ERROR_SUCCESS)
  282. goto ErrorExit;
  283. cchClass = ARRAYSIZE(szClass);
  284. erc = RegQueryInfoKey(hk, szClass, &cchClass, NULL, &cSubk, &cchMaxSubk,
  285. &cchMaxCls, &iVal, &cchMaxVName, &cbMaxVData, &cbSecDes, &ftLstWr);
  286. if( erc != ERROR_SUCCESS && erc != ERROR_MORE_DATA)
  287. goto ErrorExit;
  288. cchMaxVName += 1;
  289. DPRINT(( TEXT("cchName:%d cbData:%d\n"), cchMaxVName, cbMaxVData ));
  290. pszVName = LocalAlloc(LMEM_FIXED, cchMaxVName * SIZEOF(TCHAR));
  291. pvVData = LocalAlloc(LMEM_FIXED, cbMaxVData + sizeof(TCHAR));
  292. if (pvVData == NULL || pszVName == NULL)
  293. goto ErrorExit;
  294. // for each value in the key
  295. iVal = 0;
  296. for(;;) {
  297. LPTSTR pszIn, pszOut;
  298. BOOL fFixed;
  299. TCHAR szTmp[MAX_PATH];
  300. cch = cchMaxVName;
  301. cb = cbMaxVData;
  302. DPRINT(( TEXT("\n\n>>>>>>>>>>>>>>>>>>>Getting scheme %d "), iVal ));
  303. if( RegEnumValue(hk, iVal++, pszVName, &cch, NULL, &dwType, pvVData, &cb ) != ERROR_SUCCESS )
  304. break;
  305. if (dwType != REG_EXPAND_SZ && dwType != REG_SZ)
  306. continue;
  307. *(TCHAR *)((LPBYTE)pvVData+cb) = TEXT('\0'); // Make sure nul terminated
  308. // check if it has been converted yet
  309. DPRINT(( TEXT("Scheme : %s = [%s]"), pszVName, pvVData ));
  310. fFixed = FALSE;
  311. pszOut = szOut;
  312. pszIn = pvVData;
  313. pszIn--; // prime pszIn for first comma skip
  314. do {
  315. pszIn++; // skip over comma separator
  316. pszIn += mystrcpy( szTmp, pszIn, TEXT(',') ); // bump ptr by length of token
  317. DPRINT((TEXT("\n\t%s"), szTmp));
  318. if (!HasPath(szTmp)) {
  319. fFixed = TRUE;
  320. DPRINT((TEXT(" <fixed...")));
  321. pszOut += mystrcpy( pszOut, szSystemRoot, TEXT('\0') );
  322. DPRINT((TEXT(">")));
  323. }
  324. pszOut += mystrcpy( pszOut, szTmp, TEXT('\0') );
  325. *pszOut++ = TEXT(',');
  326. #ifdef SHMG_DBG
  327. *pszOut = TEXT('\0');
  328. DPRINT((TEXT("\nszOut so far: '%s'"), szOut ));
  329. #endif
  330. } while ( *pszIn );
  331. *(pszOut-1) = TEXT('\0');
  332. DPRINT((TEXT("\n\n******** Findal szOut: [%s]"), szOut ));
  333. // write the new data back out
  334. if (fFixed) {
  335. DPRINT((TEXT(" (Saving back to reg)")));
  336. RegSetValueEx(hk, pszVName, 0L, REG_EXPAND_SZ, (LPBYTE)szOut, (DWORD)(sizeof(TCHAR)*(pszOut - szOut)));
  337. }
  338. }
  339. ErrorExit:
  340. DPRINT(( TEXT("\n\n **EXITING FN()**\n" )));
  341. // close the key
  342. if (hk)
  343. RegCloseKey(hk);
  344. if (pvVData)
  345. LocalFree(pvVData);
  346. if (pszVName)
  347. LocalFree(pszVName);
  348. }
  349. // this function will remove entries from HKCU\Control Panel\Cursors\Schemes which are identical to
  350. // schemes found in HKLM\%Current Version%\Control Panel\Cursors\Schemes
  351. //
  352. // HKCU\Control Panel\Cursors
  353. // This key contains the users currently selected cursor scheme
  354. // HKCU\Control Panel\Cursors "Scheme Source"
  355. // This is a new key which will be added if not present. The key indicates if the currently
  356. // select user scheme is user defined or system defined.
  357. // HKCU\Control Panel\Cursors\Schemes <Scheme name> <file list>
  358. // This is the location for user defined schemes. If any of these schemes have both the same
  359. // scheme name and the same file list as a system defined scheme then that key will be
  360. // removed from the user list. If the currently selected cursor scheme is removed then
  361. // "Scheme Source" will be updated to reflect the new location.
  362. // HKLM\%Current Version%\Control Panel\Cursors\Schemes <Scheme name>
  363. // Under the new optional component model, optional components are installed on a per-machine
  364. // basis into this location instead of the old per-user basis. This allows floating profiles
  365. // to use system pointer schemes on multiple machines and simplifies component installation.
  366. void CvtCursorSchemesToMultiuser( void )
  367. {
  368. HKEY hkOldCursors, hkOldSchemes;
  369. HKEY hkNewSchemes;
  370. DWORD iSchemeLocation;
  371. DWORD iType;
  372. TCHAR szDefaultScheme[MAX_PATH+1];
  373. const TCHAR szSchemeSource[] = TEXT("Scheme Source");
  374. SZNODE *pnHead = NULL;
  375. SZNODE *pnTail = NULL;
  376. // open a key to the original cursors location
  377. if (RegOpenKeyEx(HKEY_CURRENT_USER, szWinCursors, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkOldCursors) == ERROR_SUCCESS)
  378. {
  379. DWORD len = sizeof( szDefaultScheme );
  380. if (SHRegGetValue(hkOldCursors, NULL, NULL, SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND, NULL, szDefaultScheme, &len ) != ERROR_SUCCESS)
  381. {
  382. szDefaultScheme[0] = TEXT('\0'); // if the default key isn't set, the user has the default cursors
  383. }
  384. // try to read the value of "Scheme Source"
  385. len = sizeof( iSchemeLocation );
  386. if ( RegQueryValueEx( hkOldCursors, szSchemeSource, 0, &iType, (BYTE *)&iSchemeLocation, &len )
  387. != ERROR_SUCCESS )
  388. {
  389. iSchemeLocation = ID_USER_SCHEME; // if the value isn't there then it's a user scheme
  390. RegSetValueEx( hkOldCursors, szSchemeSource, 0, REG_DWORD, (BYTE *)&iSchemeLocation,
  391. sizeof( iSchemeLocation ) );
  392. }
  393. // now open the schemes subkey, this is what we're interested in
  394. if (RegOpenKeyEx( hkOldCursors, szSchemes, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkOldSchemes ) == ERROR_SUCCESS )
  395. {
  396. TCHAR szOldKeyName[MAX_PATH+1];
  397. TCHAR szOldKeyValue[C_CURSORS*(MAX_PATH+1)+1];
  398. TCHAR szNewKeyValue[C_CURSORS*(MAX_PATH+1)+1];
  399. long iLenName; // the length of the name of the old key
  400. long iLenValue; // the length of the value of the old key
  401. DWORD iLenNewKey; // the length of the new key's value
  402. int iIndex;
  403. // now we are ready to enum the user defined schemes, but first lets make sure we can
  404. // open the new location, if we can't open it then we bail out.
  405. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, szDaytonaSchemes, 0, KEY_READ, &hkNewSchemes ) != ERROR_SUCCESS )
  406. goto bailOut;
  407. DPRINT(( TEXT("Opened key %s"), szDaytonaSchemes ));
  408. // now we start reading the new schemes
  409. for (iIndex = 0;;)
  410. {
  411. // read next scheme
  412. iLenName = ARRAYSIZE(szOldKeyName); // these must be reset each time around
  413. iLenValue = sizeof( szOldKeyValue );
  414. if (RegEnumValue( hkOldSchemes, iIndex++, szOldKeyName, &iLenName, NULL, NULL,
  415. (BYTE *)szOldKeyValue, &iLenValue ) != ERROR_SUCCESS )
  416. {
  417. // we fail if we are out of data, which means we're done
  418. break;
  419. }
  420. else
  421. {
  422. szOldKeyValue[ARRAYSIZE(szOldKeyValue)-1] = TEXT('\0'); // ensure NULL-terminated
  423. }
  424. DPRINT(( TEXT("Opened key: %s\n"), szOldKeyName ));
  425. // now we try to find a key with the same name in the new location
  426. iLenNewKey = sizeof( szNewKeyValue );
  427. if (SHRegGetValue(hkNewSchemes, NULL, szOldKeyName, SRRF_RT_REG_SZ | SRRF_RT_REG_EXPAND_SZ | SRRF_NOEXPAND, NULL, szNewKeyValue, &iLenNewKey)
  428. == ERROR_SUCCESS )
  429. {
  430. // if the new key exists, compare the values
  431. DPRINT(( TEXT(" Key exists in HKLM.\n") ));
  432. DPRINT(( TEXT(" Old=%s\n New=%s\n"), szOldKeyValue, szNewKeyValue ));
  433. if ( lstrcmpi(szOldKeyValue, szNewKeyValue) == 0 )
  434. {
  435. // if the values are the same, see if this is the currently selected scheme
  436. if ( lstrcmp(szOldKeyName, szDefaultScheme) == 0 )
  437. {
  438. // since we're going to delete the user defined scheme and the system scheme
  439. // has the same name and value we simply change the value of "Scheme Source"
  440. iSchemeLocation = ID_OS_SCHEME;
  441. RegSetValueEx( hkOldCursors, szSchemeSource, 0, REG_DWORD, (unsigned char *)&iSchemeLocation,
  442. sizeof( iSchemeLocation ) );
  443. }
  444. // remove the user key
  445. DPRINT(( TEXT(" Tagging user key for removal.\n") ));
  446. if ( pnTail == NULL )
  447. {
  448. pnTail = (SZNODE *)LocalAlloc( LMEM_FIXED, sizeof( SZNODE ) );
  449. pnHead = pnTail;
  450. if (!pnTail) // not enough memory
  451. break;
  452. }
  453. else
  454. {
  455. pnTail->next = (SZNODE *)LocalAlloc( LMEM_FIXED, sizeof( SZNODE ) );
  456. pnTail = pnTail->next;
  457. if (!pnTail) // not enough memory
  458. break;
  459. }
  460. pnTail->next = NULL;
  461. pnTail->psz = LocalAlloc( LMEM_FIXED, ARRAYSIZE(szOldKeyName) * sizeof(TCHAR) );
  462. if (pnTail->psz)
  463. {
  464. StringCchCopy(pnTail->psz, ARRAYSIZE(szOldKeyName), szOldKeyName);
  465. }
  466. else
  467. {
  468. break; // not enough memory
  469. }
  470. }
  471. }
  472. }
  473. // If we tagged any keys for deletion they will be stored in our list
  474. while (pnHead)
  475. {
  476. if (pnHead->psz) // if we ran out of memory, this could be NULL
  477. {
  478. DPRINT(( TEXT("Deleting key %s\n"), pnHead->psz ));
  479. RegDeleteValue( hkOldSchemes, pnHead->psz );
  480. LocalFree( pnHead->psz ); // Clean up the list as we go
  481. }
  482. pnTail = pnHead;
  483. pnHead = pnHead->next;
  484. LocalFree( pnTail ); // Clean up as we go
  485. }
  486. // now we are finished removing the duplicate keys, clean up and exit
  487. RegCloseKey( hkNewSchemes );
  488. bailOut:
  489. RegCloseKey( hkOldSchemes );
  490. }
  491. // else: no schemes are defined for current user so there's nothing to do
  492. RegCloseKey( hkOldCursors );
  493. }
  494. // else: no cursor key exists for current user so there's nothing to do
  495. }