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.

400 lines
14 KiB

  1. /* (C) Copyright Microsoft Corporation 1991-1994. All Rights Reserved */
  2. /*-----------------------------------------------------------------------------+
  3. | FIXREG.C |
  4. | |
  5. | Publisher and Video For Windows make evil changes to the registry |
  6. | when they are installed. Look for these changes. If they are spotted |
  7. | then put up a message box to warn the user and offer the user the chance to |
  8. | correct them (i.e. stuff our version back in) |
  9. | |
  10. | (C) Copyright Microsoft Corporation 1994. All rights reserved. |
  11. | |
  12. | Revision History |
  13. | 10-Aug-1994 Lauriegr Created. |
  14. | |
  15. +-----------------------------------------------------------------------------*/
  16. #include <windows.h>
  17. #include <mmsystem.h>
  18. #include <soundrec.h>
  19. #include <reg.h>
  20. #include <fixreg.h>
  21. #include <string.h>
  22. #include <tchar.h>
  23. #define RC_INVOKED
  24. #include <o2base.hxx>
  25. #include <srs.hxx>
  26. #undef RC_INVOKED
  27. /* The idea is to call CheckRegValues(hinst) on a separate thread
  28. (sort of backgroundy thing) and have it just die
  29. quietly if there's no problem. If on the other hand there is a problem
  30. then we need to get the message box up - and it's a VERY BAD IDEA to
  31. try to put a message box up on anything other than the thread that's doing
  32. all the UI (otherwise ScottLu will get you with a weasle word - guaranteed).
  33. So the background thread should PostMessage (Post, don't Send - more weasles)
  34. to the main thread a message to say "WM_BADREG". The main thread should then
  35. wack up the dialog box by calling FixRegValues.
  36. Suggested coding in main thread:
  37. BackgroundRegCheck(hwndmain);
  38. in window proc for hwndmain:
  39. case WM_HEYUP:
  40. FixReg(hwndmain, title);
  41. */
  42. /* These are the things we check up.
  43. First define them as static strings, since the compiler's not smart enough
  44. to spot common strings.
  45. NOTE - these values are NOT LOCALISED
  46. */
  47. /* These are for Sound Recorder - Let's try to fix it all while we're here. */
  48. TCHAR szSoundRec[] = TEXT("SoundRec");
  49. TCHAR szSoundRec_CLSID[] = TEXT("SoundRec\\CLSID");
  50. TCHAR szSROLE2GUID[] = TEXT("{00020C01-0000-0000-C000-000000000046}");
  51. TCHAR szSROLE1GUID[] = TEXT("{0003000D-0000-0000-C000-000000000046}");
  52. TCHAR szSRCLSID_OLE2GUID[] = TEXT("CLSID\\{00020C01-0000-0000-C000-000000000046}");
  53. TCHAR szSRStdExecute_Server[] = TEXT("SoundRec\\protocol\\StdExecute\\server");
  54. TCHAR szSR32[] = TEXT("sndrec32.exe");
  55. TCHAR szSRStdFileEdit_Server[] = TEXT("SoundRec\\protocol\\StdFileEditing\\server");
  56. TCHAR szSRShell_Open_Command[] = TEXT("SoundRec\\shell\\open\\command");
  57. TCHAR szSR32Cmd[] = TEXT("sndrec32.exe %1");
  58. TCHAR szSRStdFileEdit_verb_0[] = TEXT("SoundRec\\protocol\\StdFileEditing\\verb\\0");
  59. TCHAR szSRStdFileEdit_verb_1[] = TEXT("SoundRec\\protocol\\StdFileEditing\\verb\\1");
  60. TCHAR szSRStdFileEdit_verb_2[] = TEXT("SoundRec\\protocol\\StdFileEditing\\verb\\2");
  61. TCHAR sz_Open[] = TEXT("&Open");
  62. /* Array of registry value-data pairs to check:
  63. */
  64. #define RES_STR_LEN 40 /* Should be enough as a maximum resource string. */
  65. TCHAR szSound[RES_STR_LEN]; // IDS_CLASSROOT in resources
  66. TCHAR sz_Play[RES_STR_LEN]; // IDS_PLAYVERB in resources
  67. TCHAR sz_Edit[RES_STR_LEN]; // IDS_EDITVERB in resources
  68. /*
  69. * Check for explicit equivalence.
  70. * These are absolutely necessary.
  71. */
  72. LPTSTR RegValuesExplicit[] =
  73. {
  74. szSoundRec, szSound, // Primary name for object
  75. szSoundRec_CLSID, szSROLE2GUID, // CLSID, very important
  76. szSRStdFileEdit_verb_0, sz_Play, // verb, very important
  77. szSRStdFileEdit_verb_1, sz_Edit // verb, very important
  78. // szSRCLSID_OLE2GUID, szSound, // not too important
  79. };
  80. /*
  81. * Check for valid substring
  82. * These are OK if the substring exists, i.e:
  83. *
  84. * "ntsd.exe sndrec32.exe"
  85. * or "sndrec32.exe /play" are OK.
  86. *
  87. * "qrecord.exe" is NOT ok.
  88. */
  89. LPTSTR RegValuesSubstring[] =
  90. {
  91. szSRStdExecute_Server, szSR32, szSR32,
  92. szSRStdFileEdit_Server, szSR32, szSR32
  93. // szSRShell_Open_Command, szSR32Cmd,szSR32 // user can change this
  94. };
  95. /*
  96. * Check that a REG_SZ value in the registry has the value that it should do
  97. * Return TRUE if it does, FALSE if it doesn't.
  98. */
  99. BOOL CheckRegValue(HKEY RootKey, LPTSTR KeyName, LPTSTR ShouldBe, LPTSTR CouldBe)
  100. {
  101. DWORD Type;
  102. TCHAR Data[100];
  103. DWORD cData = sizeof(Data);
  104. LONG lRet;
  105. HKEY hkey;
  106. if (ERROR_SUCCESS!=RegOpenKeyEx( RootKey
  107. , KeyName
  108. , 0 /* reserved */
  109. , KEY_QUERY_VALUE
  110. , &hkey
  111. )
  112. )
  113. return FALSE; /* couldn't even open the key */
  114. lRet=RegQueryValueEx( hkey
  115. , NULL /* ValueName */
  116. , NULL /* reserved */
  117. , &Type
  118. , (LPBYTE)Data
  119. , &cData
  120. );
  121. RegCloseKey(hkey); /* no idea what to do if this fails */
  122. if (ERROR_SUCCESS!=lRet) return FALSE; /* couldn't query it */
  123. /* Data, cData and Type give the data, length and type */
  124. if (Type!=REG_SZ) return FALSE;
  125. //
  126. // if Data == ShouldBe, then lRet = 0
  127. //
  128. lRet = lstrcmp(Data, ShouldBe); /* capture lRet to make debug easier */
  129. if (lRet && CouldBe != NULL)
  130. {
  131. //
  132. // if Couldbe in Data, lRet = 0
  133. //
  134. lRet = (_tcsstr(Data, CouldBe) == NULL);
  135. }
  136. return 0==lRet;
  137. } /* CheckRegValue */
  138. #define ARRAY_SIZE(x) (sizeof((x))/sizeof((x)[0]))
  139. /* check the registry for anything evil. Return TRUE if it's OK else FALSE */
  140. BOOL CheckRegValues(void)
  141. {
  142. HKEY HCL = HKEY_CLASSES_ROOT; /* save typing! */
  143. DWORD i;
  144. if( !( LoadString( ghInst, IDS_USERTYPESHORT, szSound, SIZEOF(szSound) )
  145. && LoadString( ghInst, IDS_PLAYVERB, sz_Play, SIZEOF(sz_Play))
  146. && LoadString( ghInst, IDS_EDITVERB, sz_Edit, SIZEOF(sz_Edit) ) ) )
  147. /* If any of the strings fails to load, forget it:
  148. */
  149. return TRUE;
  150. for( i = 0; i < ARRAY_SIZE(RegValuesExplicit); i+=2 )
  151. {
  152. if( !CheckRegValue( HCL
  153. , RegValuesExplicit[i]
  154. , RegValuesExplicit[i+1]
  155. , NULL ) )
  156. return FALSE;
  157. }
  158. for(i = 0; i < ARRAY_SIZE(RegValuesSubstring); i+=3)
  159. {
  160. if( !CheckRegValue( HCL
  161. , RegValuesSubstring[i]
  162. , RegValuesSubstring[i+1]
  163. , RegValuesSubstring[i+2] ) )
  164. return FALSE;
  165. }
  166. return TRUE;
  167. } /* CheckRegValues */
  168. /* start this thread to get the registry checked out.
  169. * hwnd is typed as a LPVOID because that's what CreateThread wants.
  170. */
  171. DWORD RegCheckThread(LPVOID hwnd)
  172. {
  173. if (!CheckRegValues())
  174. PostMessage((HWND)hwnd, WM_BADREG, 0, 0);
  175. return 0; /* end of thread! */
  176. }
  177. /* Call this with the hwnd that you want a WM_BADREG message posted to
  178. * It will check the registry. No news is good news.
  179. * It does the work on a separate thread, so this should return quickly.
  180. */
  181. void BackgroundRegCheck(HWND hwnd)
  182. {
  183. HANDLE hThread;
  184. DWORD thid;
  185. hThread = CreateThread( NULL /* no special security */
  186. , 0 /* default stack size */
  187. , (LPTHREAD_START_ROUTINE)RegCheckThread
  188. , (LPVOID)hwnd
  189. , 0 /* start running at once */
  190. , &thid
  191. );
  192. if (hThread!=NULL) CloseHandle(hThread); /* we don't need this any more */
  193. /* Else we're in some sort of trouble - dunno what to do.
  194. Can't think of an intelligible message to give to the user.
  195. Too bad. Creep home quietly.
  196. */
  197. } /* BackgroundRegCheck */
  198. /* returns TRUE if it worked. Dunno what to do if it didn't
  199. */
  200. BOOL SetRegValue(HKEY RootKey, LPTSTR KeyName, LPTSTR ValueName, LPTSTR ShouldBe)
  201. {
  202. HKEY hkey;
  203. if (ERROR_SUCCESS!=RegOpenKeyEx( RootKey
  204. , KeyName
  205. , 0 /* reserved */
  206. , KEY_SET_VALUE
  207. , &hkey
  208. )
  209. ) {
  210. /* Maybe the key has been DELETED - we've seen that */
  211. DWORD dwDisp;
  212. if (ERROR_SUCCESS!=RegCreateKeyEx( RootKey
  213. , KeyName
  214. , 0 /* reserved */
  215. , TEXT("") /* class */
  216. , REG_OPTION_NON_VOLATILE
  217. , KEY_SET_VALUE
  218. , NULL /* SecurityAttributes */
  219. , &hkey
  220. , &dwDisp
  221. )
  222. ) /* well we're really in trouble */
  223. return FALSE;
  224. else /* So now it exists, but we now have to open it */
  225. if (ERROR_SUCCESS!=RegOpenKeyEx( RootKey
  226. , KeyName
  227. , 0 /* reserved */
  228. , KEY_SET_VALUE
  229. , &hkey
  230. )
  231. ) /* Give up */
  232. return FALSE;
  233. }
  234. if (ERROR_SUCCESS!=RegSetValueEx( hkey
  235. , ValueName
  236. , 0 // reserved
  237. , REG_SZ
  238. , (LPBYTE)ShouldBe
  239. , (lstrlen(ShouldBe)+1)*sizeof(TCHAR) //BYTES
  240. )
  241. )
  242. return FALSE; /* couldn't set it */
  243. if ( ERROR_SUCCESS!=RegCloseKey(hkey) )
  244. /* no idea what to do!*/ ; // couldn't set it
  245. // I'm NOT calling RegFlushKey. They'll get there eventually
  246. return TRUE;
  247. } /* SetRegValue */
  248. /*
  249. * SetRegValues
  250. * Update the registry with the correct values. Return TRUE if everything
  251. * succeeds
  252. * */
  253. BOOL SetRegValues(void)
  254. {
  255. HKEY HCL = HKEY_CLASSES_ROOT; /* save typing! */
  256. DWORD i;
  257. for( i = 0; i < ARRAY_SIZE(RegValuesExplicit); i+=2 )
  258. {
  259. // Do another check to see whether this one needs changing,
  260. // to avoid gratuitous changes, and to avoid the slim chance
  261. // that an unnecessary SetRegValue might fail:
  262. //
  263. if( !CheckRegValue( HCL
  264. , RegValuesExplicit[i]
  265. , RegValuesExplicit[i+1]
  266. , NULL ) )
  267. {
  268. if( !SetRegValue( HCL
  269. , RegValuesExplicit[i]
  270. , NULL
  271. , RegValuesExplicit[i+1] ) )
  272. return FALSE;
  273. }
  274. }
  275. for( i = 0; i < ARRAY_SIZE(RegValuesSubstring); i+=3 )
  276. {
  277. // Do another check to see whether this one needs changing,
  278. // to avoid gratuitous changes, and to avoid the slim chance
  279. // that an unnecessary SetRegValue might fail:
  280. //
  281. if( !CheckRegValue( HCL
  282. , RegValuesSubstring[i]
  283. , RegValuesSubstring[i+1]
  284. , RegValuesSubstring[i+2] ) )
  285. {
  286. if( !SetRegValue( HCL
  287. , RegValuesSubstring[i]
  288. , NULL
  289. , RegValuesSubstring[i+1] ) )
  290. return FALSE;
  291. }
  292. }
  293. return TRUE;
  294. } /* SetRegValues */
  295. /*
  296. * FixReg
  297. * */
  298. void FixReg(HWND hwnd)
  299. {
  300. int r;
  301. // Error is confusing and can be caused simply by incomplete localization
  302. // (see bug # 34330). I removed the error so that we fix the registry
  303. // automatically and fixed this bug.
  304. r = IDYES;
  305. // r = ErrorResBox(hwnd
  306. // , NULL
  307. // , MB_ICONEXCLAMATION | MB_YESNO
  308. // , IDS_APPTITLE
  309. // , IDS_BADREG) ;
  310. switch (r)
  311. {
  312. case IDYES:
  313. if (!SetRegValues())
  314. ErrorResBox(ghwndApp
  315. , ghInst
  316. , MB_ICONEXCLAMATION | MB_OK
  317. , IDS_APPTITLE
  318. , IDS_FIXREGERROR
  319. , FALSE );
  320. break;
  321. case IDNO:
  322. case IDCANCEL:
  323. /* else sneak away quietly */
  324. default:
  325. break;
  326. }
  327. } /* FixReg */
  328. const TCHAR aszOptionsSection[] = TEXT("Options");
  329. const TCHAR aszIgnoreRegistryCheck[] = TEXT("Ignore Registry Check");
  330. BOOL IgnoreRegCheck()
  331. {
  332. DWORD fIgnore = 0L;
  333. ReadRegistryData((LPTSTR)aszOptionsSection
  334. , (LPTSTR)aszIgnoreRegistryCheck
  335. , NULL
  336. , (LPBYTE)&fIgnore
  337. , sizeof fIgnore);
  338. return (fIgnore != 0L);
  339. }