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.

1035 lines
34 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. CorrectPathChangesBase.cpp
  5. Abstract:
  6. Several paths were changed between Win9x and WinNT. This routine defines
  7. the CorrectPathChangesBase routines that is called with a Win9x path and returns
  8. the corresponding WinNT path.
  9. History:
  10. 03-Mar-00 robkenny Converted CorrectPathChanges.cpp to this class.
  11. 21-Mar-00 robkenny StringISub("abc", "abcd") now works
  12. 06/20/2000 robkenny EnvironmentValues::Initialize now checks the return status of the system calls
  13. 12/12/2000 mnikkel Some apps look for ddhelp.exe to exist to confirm directx is installed,
  14. set this to look for ddraw.dll since ddhelp.exe no longer exists in directx.
  15. 02/13/2001 robkenny/a-larrsh Added AllProfile and UserProfile to EnvironmentValues
  16. 03/22/2001 robkenny Do not redirect files to directories that the user does not have permission.
  17. 08/14/2001 robkenny Moved code inside the ShimLib namespace.
  18. --*/
  19. #include "ClassCFP.h"
  20. #include "StrSafe.h"
  21. #include "Userenv.h"
  22. #include <stdio.h>
  23. namespace ShimLib
  24. {
  25. WCHAR *
  26. ReplaceAllStringsAllocW(const WCHAR * lpOrig,
  27. const VectorT<StringPairW> & pathFixes)
  28. {
  29. CSTRING_TRY
  30. {
  31. CString csReplaced(lpOrig);
  32. for (DWORD i = 0; i < pathFixes.Size(); ++i)
  33. {
  34. const StringPairW & stringPair = pathFixes[i];
  35. // Attempt a string substitution
  36. csReplaced.ReplaceI(stringPair.lpOld, stringPair.lpNew);
  37. }
  38. // Wasteful, but all calling routines expect ownership of the return value.
  39. return StringDuplicateW(csReplaced);
  40. }
  41. CSTRING_CATCH
  42. {
  43. // Fall thru
  44. }
  45. return NULL;
  46. }
  47. //-------------------------------------------------------------------------------------------------------------
  48. EnvironmentValues::EnvironmentValues()
  49. {
  50. bInitialized = FALSE;
  51. }
  52. EnvironmentValues::~EnvironmentValues()
  53. {
  54. // Clear the list
  55. Erase();
  56. }
  57. // Given an CLSIDL, create an environment variable and its two variants
  58. // CSIDL_WINDOWS would add c:\windows, \windows and windows
  59. void EnvironmentValues::Add_Variants(const WCHAR * lpEnvName, const WCHAR * lpEnvValue, eAddNameEnum addName, eAddNoDLEnum noDL)
  60. {
  61. CSTRING_TRY
  62. {
  63. CString csEnvName;
  64. CString csEnvValue(lpEnvValue);
  65. csEnvName.Format(L"%%%s%%", lpEnvName);
  66. AddEnvironmentValue(csEnvName, csEnvValue);
  67. // Remove the drive letter and the colon.
  68. if (noDL == eAddNoDL)
  69. {
  70. CString csNoDL(csEnvValue);
  71. csNoDL.Delete(0, 2);
  72. csEnvName.Format(L"%%%s_NODL%%", lpEnvName);
  73. AddEnvironmentValue(csEnvName, csNoDL);
  74. }
  75. // Use the last path component as the name.
  76. if (addName == eAddName)
  77. {
  78. CString csName;
  79. csEnvValue.GetLastPathComponent(csName);
  80. csEnvName.Format(L"%%%s_NAME%%", lpEnvName);
  81. AddEnvironmentValue(csEnvName, csName);
  82. }
  83. }
  84. CSTRING_CATCH
  85. {
  86. // Do Nothing
  87. }
  88. }
  89. // Given an CLSIDL, create an environment variable and its two variants
  90. // CSIDL_WINDOWS would add c:\windows, \windows and windows
  91. void EnvironmentValues::Add_CSIDL(const WCHAR * lpEnvName, int nFolder, eAddNameEnum addName, eAddNoDLEnum noDL)
  92. {
  93. CSTRING_TRY
  94. {
  95. CString csPath;
  96. SHGetSpecialFolderPathW(csPath, nFolder);
  97. if (csPath.GetLength() > 0)
  98. {
  99. Add_Variants(lpEnvName, csPath, addName, noDL);
  100. }
  101. }
  102. CSTRING_CATCH
  103. {
  104. // Do Nothing
  105. }
  106. }
  107. // Add all _CSIDL values as environment variables.
  108. void EnvironmentValues::AddAll_CSIDL()
  109. {
  110. Add_CSIDL(L"CSIDL_APPDATA", CSIDL_APPDATA, eAddName, eAddNoDL);
  111. Add_CSIDL(L"CSIDL_COMMON_ADMINTOOLS", CSIDL_COMMON_ADMINTOOLS, eAddName, eAddNoDL);
  112. Add_CSIDL(L"CSIDL_COMMON_APPDATA", CSIDL_COMMON_APPDATA, eAddName, eAddNoDL);
  113. Add_CSIDL(L"CSIDL_COMMON_DESKTOPDIRECTORY", CSIDL_COMMON_DESKTOPDIRECTORY, eAddName, eAddNoDL);
  114. Add_CSIDL(L"CSIDL_COMMON_DOCUMENTS", CSIDL_COMMON_DOCUMENTS, eAddName, eAddNoDL);
  115. Add_CSIDL(L"CSIDL_COMMON_FAVORITES", CSIDL_COMMON_FAVORITES, eAddName, eAddNoDL);
  116. Add_CSIDL(L"CSIDL_COMMON_MUSIC", CSIDL_COMMON_MUSIC, eAddName, eAddNoDL);
  117. Add_CSIDL(L"CSIDL_COMMON_PICTURES", CSIDL_COMMON_PICTURES, eAddName, eAddNoDL);
  118. Add_CSIDL(L"CSIDL_COMMON_PROGRAMS", CSIDL_COMMON_PROGRAMS, eAddName, eAddNoDL);
  119. Add_CSIDL(L"CSIDL_COMMON_STARTMENU", CSIDL_COMMON_STARTMENU, eAddName, eAddNoDL);
  120. Add_CSIDL(L"CSIDL_COMMON_STARTUP", CSIDL_COMMON_STARTUP, eAddName, eAddNoDL);
  121. Add_CSIDL(L"CSIDL_COMMON_TEMPLATES", CSIDL_COMMON_TEMPLATES, eAddName, eAddNoDL);
  122. Add_CSIDL(L"CSIDL_COOKIES", CSIDL_COOKIES, eAddName, eAddNoDL);
  123. Add_CSIDL(L"CSIDL_DESKTOPDIRECTORY", CSIDL_DESKTOPDIRECTORY, eAddName, eAddNoDL);
  124. Add_CSIDL(L"CSIDL_FAVORITES", CSIDL_FAVORITES, eAddName, eAddNoDL);
  125. Add_CSIDL(L"CSIDL_FONTS", CSIDL_FONTS, eAddName, eAddNoDL);
  126. Add_CSIDL(L"CSIDL_HISTORY", CSIDL_HISTORY, eAddName, eAddNoDL);
  127. Add_CSIDL(L"CSIDL_INTERNET_CACHE", CSIDL_INTERNET_CACHE, eAddName, eAddNoDL);
  128. Add_CSIDL(L"CSIDL_LOCAL_APPDATA", CSIDL_LOCAL_APPDATA, eAddName, eAddNoDL);
  129. Add_CSIDL(L"CSIDL_MYMUSIC", CSIDL_MYMUSIC, eAddName, eAddNoDL);
  130. Add_CSIDL(L"CSIDL_MYPICTURES", CSIDL_MYPICTURES, eAddName, eAddNoDL);
  131. Add_CSIDL(L"CSIDL_NETHOOD", CSIDL_NETHOOD, eAddName, eAddNoDL);
  132. Add_CSIDL(L"CSIDL_PERSONAL", CSIDL_PERSONAL, eAddName, eAddNoDL);
  133. Add_CSIDL(L"CSIDL_PRINTHOOD", CSIDL_PRINTHOOD, eAddName, eAddNoDL);
  134. Add_CSIDL(L"CSIDL_PROFILE", CSIDL_PROFILE, eAddName, eAddNoDL);
  135. Add_CSIDL(L"CSIDL_PROGRAM_FILES", CSIDL_PROGRAM_FILES, eAddName, eAddNoDL);
  136. Add_CSIDL(L"CSIDL_PROGRAM_FILES_COMMON", CSIDL_PROGRAM_FILES_COMMON, eAddName, eAddNoDL);
  137. Add_CSIDL(L"CSIDL_PROGRAMS", CSIDL_PROGRAMS, eAddName, eAddNoDL);
  138. Add_CSIDL(L"CSIDL_RECENT", CSIDL_RECENT, eAddName, eAddNoDL);
  139. Add_CSIDL(L"CSIDL_SENDTO", CSIDL_SENDTO, eAddName, eAddNoDL);
  140. Add_CSIDL(L"CSIDL_STARTMENU", CSIDL_STARTMENU, eAddName, eAddNoDL);
  141. Add_CSIDL(L"CSIDL_STARTUP", CSIDL_STARTUP, eAddName, eAddNoDL);
  142. Add_CSIDL(L"CSIDL_SYSTEM", CSIDL_SYSTEM, eAddName, eAddNoDL);
  143. Add_CSIDL(L"CSIDL_TEMPLATES", CSIDL_TEMPLATES, eAddName, eAddNoDL);
  144. Add_CSIDL(L"CSIDL_WINDOWS", CSIDL_WINDOWS, eAddName, eAddNoDL);
  145. }
  146. void EnvironmentValues::Initialize()
  147. {
  148. if (bInitialized == FALSE)
  149. {
  150. bInitialized = TRUE;
  151. WCHAR lpDir[MAX_PATH];
  152. DWORD dwSize;
  153. HRESULT result;
  154. DWORD dwChars;
  155. BOOL bResult;
  156. dwChars = GetWindowsDirectoryW(lpDir, MAX_PATH);
  157. if (dwChars > 0 && dwChars <= MAX_PATH)
  158. {
  159. AddEnvironmentValue( L"%WinDir%", lpDir );
  160. AddEnvironmentValue( L"%SystemRoot%", lpDir );
  161. lpDir[2] = 0;
  162. AddEnvironmentValue( L"%SystemDrive%", lpDir );
  163. }
  164. dwChars = GetSystemDirectoryW( lpDir, MAX_PATH);
  165. if (dwChars > 0 && dwChars <= MAX_PATH)
  166. {
  167. AddEnvironmentValue( L"%SystemDir%", lpDir );
  168. }
  169. dwSize = ARRAYSIZE(lpDir);
  170. bResult = GetUserNameW(lpDir, &dwSize);
  171. if (bResult)
  172. {
  173. AddEnvironmentValue( L"%Username%", lpDir );
  174. }
  175. result = SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  176. if (SUCCEEDED(result))
  177. {
  178. AddEnvironmentValue( L"%ProgramFiles%", lpDir );
  179. }
  180. result = SHGetFolderPathW( NULL, CSIDL_STARTMENU, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  181. if (SUCCEEDED(result))
  182. {
  183. AddEnvironmentValue( L"%UserStartMenu%", lpDir );
  184. }
  185. result = SHGetFolderPathW( NULL, CSIDL_COMMON_STARTMENU, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  186. if (SUCCEEDED(result))
  187. {
  188. AddEnvironmentValue( L"%AllStartMenu%", lpDir );
  189. }
  190. result = SHGetFolderPathW( NULL, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  191. if (SUCCEEDED(result))
  192. {
  193. AddEnvironmentValue( L"%UserDesktop%", lpDir );
  194. }
  195. result = SHGetFolderPathW( NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  196. if (SUCCEEDED(result))
  197. {
  198. AddEnvironmentValue( L"%AllDesktop%", lpDir );
  199. }
  200. result = SHGetFolderPathW( NULL, CSIDL_FAVORITES, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  201. if (SUCCEEDED(result))
  202. {
  203. AddEnvironmentValue( L"%UserFavorites%", lpDir );
  204. }
  205. result = SHGetFolderPathW( NULL, CSIDL_COMMON_FAVORITES, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  206. if (SUCCEEDED(result))
  207. {
  208. AddEnvironmentValue( L"%AllFavorites%", lpDir );
  209. }
  210. result = SHGetFolderPathW( NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  211. if (SUCCEEDED(result))
  212. {
  213. AddEnvironmentValue( L"%UserAppData%", lpDir );
  214. }
  215. result = SHGetFolderPathW( NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  216. if (SUCCEEDED(result))
  217. {
  218. AddEnvironmentValue( L"%AllAppData%", lpDir );
  219. }
  220. // C:\Documents and Settings\All Users
  221. dwSize = ARRAYSIZE(lpDir);
  222. bResult = GetAllUsersProfileDirectoryW(lpDir, &dwSize);
  223. if (bResult)
  224. {
  225. Add_Variants( L"AllUsersProfile", lpDir, eAddName, eAddNoDL); // same as real Env var
  226. }
  227. // C:\Documents and Settings\owner
  228. HANDLE hProcessHandle = GetCurrentProcess();
  229. HANDLE hUserToken;
  230. if (OpenProcessToken(hProcessHandle, TOKEN_QUERY, &hUserToken))
  231. {
  232. dwSize = MAX_PATH;
  233. bResult = GetUserProfileDirectoryW(hUserToken, lpDir, &dwSize);
  234. if (bResult)
  235. {
  236. Add_Variants( L"UserProfile", lpDir, eAddName, eAddNoDL);
  237. }
  238. }
  239. // Add the new CLSIDL variables (some have duplicate values to above)
  240. AddAll_CSIDL();
  241. }
  242. }
  243. WCHAR * EnvironmentValues::ExpandEnvironmentValueW(const WCHAR * lpOld)
  244. {
  245. Initialize();
  246. // Replace all the "environment" values into their real values
  247. const VectorT<StringPairW> & stringPairVector = *this;
  248. WCHAR * lpMassagedOld = ReplaceAllStringsAllocW(lpOld, stringPairVector);
  249. return lpMassagedOld;
  250. }
  251. char * EnvironmentValues::ExpandEnvironmentValueA(const char * lpOld)
  252. {
  253. Initialize();
  254. char * lpMassagedOld = NULL;
  255. WCHAR * lpOldWide = ToUnicode(lpOld);
  256. if (lpOldWide)
  257. {
  258. const VectorT<StringPairW> & stringPairVector = *this;
  259. WCHAR * lpMassagedOldWide = ReplaceAllStringsAllocW(lpOldWide, stringPairVector);
  260. if (lpMassagedOldWide)
  261. {
  262. lpMassagedOld = ToAnsi(lpMassagedOldWide);
  263. free(lpMassagedOldWide);
  264. }
  265. free(lpOldWide);
  266. }
  267. return lpMassagedOld;
  268. }
  269. void EnvironmentValues::AddEnvironmentValue(const WCHAR * lpOld, const WCHAR * lpNew)
  270. {
  271. Initialize();
  272. StringPairW appendThis(lpOld, lpNew);
  273. if (AppendConstruct(appendThis))
  274. {
  275. DPF("EnvironmentValues",
  276. eDbgLevelInfo,
  277. "AddEnvironmentValue: (%S) to (%S)\n",
  278. appendThis.lpOld.Get(),
  279. appendThis.lpNew.Get() );
  280. }
  281. }
  282. //-------------------------------------------------------------------------------------------------------------
  283. CorrectPathChangesBase::CorrectPathChangesBase()
  284. {
  285. lpEnvironmentValues = NULL;
  286. bInitialized = FALSE;
  287. bEnabled = TRUE;
  288. }
  289. CorrectPathChangesBase::~CorrectPathChangesBase()
  290. {
  291. if (lpEnvironmentValues)
  292. delete lpEnvironmentValues;
  293. // Call the destructor on each item in the vector list.
  294. for (int i = 0; i < vKnownPathFixes.Size(); ++i)
  295. {
  296. StringPairW & stringPair = vKnownPathFixes[i];
  297. // Call the destuctor explicitly
  298. stringPair.~StringPairW();
  299. }
  300. }
  301. BOOL CorrectPathChangesBase::ClassInit()
  302. {
  303. lpEnvironmentValues = new EnvironmentValues;
  304. return lpEnvironmentValues != NULL;
  305. }
  306. /*++
  307. Func: AddEnvironmentValue
  308. Params: dwIndex
  309. lpOld Name of "environment" variable
  310. lpNew Value of "environment" variable
  311. --*/
  312. void CorrectPathChangesBase::AddEnvironmentValue(const WCHAR * lpOld, const WCHAR * lpNew )
  313. {
  314. if (lpEnvironmentValues)
  315. {
  316. lpEnvironmentValues->AddEnvironmentValue(lpOld, lpNew);
  317. }
  318. }
  319. /*++
  320. Func: InsertPathChangeW
  321. Params:
  322. lpOld Old Win9x path
  323. lpNew New Win2000 path
  324. Desc: Insert the Old/New string pair into lpKnownPathFixes
  325. making sure the list is large enough.
  326. --*/
  327. void CorrectPathChangesBase::InsertPathChangeW( const WCHAR * lpOld, const WCHAR * lpNew )
  328. {
  329. // Ignore identical strings
  330. if (lstrcmpiW(lpOld, lpNew) == 0)
  331. return;
  332. // Ignore duplicates
  333. int i;
  334. for (i = 0; i < vKnownPathFixes.Size(); ++i)
  335. {
  336. StringPairW & stringPair = vKnownPathFixes[i];
  337. if (stringPair.lpOld.CompareNoCase(lpOld) == 0)
  338. {
  339. DPF("CorrectPathChangesBase", eDbgLevelSpew, "Duplicate PathChange (%S) to (%S)\n", lpOld, lpNew );
  340. return;
  341. }
  342. }
  343. CSTRING_TRY
  344. {
  345. StringPairW appendThis(lpOld, lpNew);
  346. if (vKnownPathFixes.AppendConstruct(appendThis))
  347. {
  348. DPF("CorrectPathChangesBase", eDbgLevelInfo, "PathChange (%S) to (%S)\n", lpOld, lpNew);
  349. }
  350. }
  351. CSTRING_CATCH
  352. {
  353. // Do nothing.
  354. }
  355. }
  356. /*++
  357. Func: AddPathChangeW
  358. Params:
  359. lpOld Old Win9x path
  360. lpNew New Win2000 path
  361. Desc: Add lpOld/lpNew combo to the list, two times:
  362. first: lpOld/short(lpNew)
  363. second: short(lpOld)/short(lpNew)
  364. --*/
  365. void CorrectPathChangesBase::AddPathChangeW( const WCHAR * lpOld, const WCHAR * lpNew )
  366. {
  367. InitializeCorrectPathChanges();
  368. // Replace all the "environment" values into their real values
  369. WCHAR * lpExpandedOld = ExpandEnvironmentValueW(lpOld);
  370. WCHAR * lpExpandedNew = ExpandEnvironmentValueW(lpNew);
  371. const WCHAR * lpNewShort = lpExpandedNew;
  372. // Convert lpNew to its short name
  373. WCHAR lpNewShortBuffer[MAX_PATH];
  374. DWORD status = GetShortPathNameW(lpExpandedNew, lpNewShortBuffer, MAX_PATH);
  375. if (status > 0 && status < MAX_PATH)
  376. {
  377. lpNewShort = lpNewShortBuffer;
  378. }
  379. // first: lpOld/short(lpNew)
  380. InsertPathChangeW(lpExpandedOld, lpNewShort);
  381. // Convert lpOld to its short name
  382. WCHAR lpOldShort[MAX_PATH];
  383. status = GetShortPathNameW(lpExpandedOld, lpOldShort, MAX_PATH);
  384. if (status > 0 && status < MAX_PATH) // successfully got the short path
  385. {
  386. if (_wcsicmp(lpOld, lpOldShort) != 0)
  387. {
  388. // second: short(lpOld)/short(lpNew)
  389. InsertPathChangeW( lpOldShort, lpNewShort );
  390. }
  391. }
  392. free(lpExpandedOld);
  393. free(lpExpandedNew);
  394. }
  395. /*++
  396. Func: ExpandEnvironmentValueA
  397. Params: lpOld string with environment vars
  398. Desc: Return a pointer to a malloc() string with all internal env values expanded.
  399. --*/
  400. char * CorrectPathChangesBase::ExpandEnvironmentValueA(const char * lpOld)
  401. {
  402. WCHAR * lpOldWide = ToUnicode(lpOld);
  403. // Replace all the "environment" values into their real values
  404. WCHAR * lpExpandedOldWide = ExpandEnvironmentValueW(lpOldWide);
  405. char * lpExpandedOld = ToAnsi(lpExpandedOldWide);
  406. free(lpOldWide);
  407. free(lpExpandedOldWide);
  408. return lpExpandedOld;
  409. }
  410. /*++
  411. Func: ExpandEnvironmentValueW
  412. Params: lpOld string with environment vars
  413. Desc: Return a pointer to a malloc() string with all internal env values expanded.
  414. --*/
  415. WCHAR * CorrectPathChangesBase::ExpandEnvironmentValueW(const WCHAR * lpOld)
  416. {
  417. WCHAR * lpMassagedOld = NULL;
  418. InitializeCorrectPathChanges();
  419. if (lpEnvironmentValues)
  420. {
  421. lpMassagedOld = lpEnvironmentValues->ExpandEnvironmentValueW(lpOld);
  422. }
  423. return lpMassagedOld;
  424. }
  425. /*++
  426. Func: InitializeEnvironmentValuesW
  427. Params: None, applies changes to lpEnvironmentValues
  428. Desc: This function initializes the Environment strings
  429. --*/
  430. void CorrectPathChangesBase::InitializeEnvironmentValuesW( )
  431. {
  432. if (lpEnvironmentValues)
  433. {
  434. lpEnvironmentValues->Initialize();
  435. }
  436. }
  437. /*++
  438. Func: InitializePathFixes
  439. Params: None, applies changes to lpEnvironmentValues
  440. Desc: This function initializes the built-in path changes
  441. --*/
  442. void CorrectPathChangesBase::InitializePathFixes( )
  443. {
  444. }
  445. /*++
  446. Func: InitializeCorrectPathChanges
  447. Params: None.
  448. Desc: Initialize the CorrectPathChangesBase values, both A and W versions.
  449. This *must* be called prior to calling either CorrectPathChangesA or CorrectPathChangesW
  450. --*/
  451. void CorrectPathChangesBase::InitializeCorrectPathChanges( )
  452. {
  453. if (!bInitialized)
  454. {
  455. BOOL isEnabled = bEnabled; // remember previous enabled state
  456. // We must not be enabled while we are initializing, otherwise
  457. // we can (and do!) hook routines that we are trying to use while
  458. // grabbing values from the system.
  459. bEnabled = FALSE;
  460. bInitialized = TRUE;
  461. InitializeEnvironmentValuesW();
  462. InitializePathFixes();
  463. bEnabled = isEnabled;
  464. }
  465. }
  466. /*++
  467. Helper routine to call CorrectPathA, allocates necessary buffer space and returns a pointer
  468. to the corrected path. Caller is responsible for releasing the memory by calling free().
  469. --*/
  470. char * CorrectPathChangesBase::CorrectPathAllocA(const char * str)
  471. {
  472. if (str == NULL)
  473. return NULL;
  474. // Convert lpOrig to WCHAR, correct the WCHAR path, then convert back to char
  475. WCHAR * strWide = ToUnicode(str);
  476. // Correct
  477. WCHAR * strCorrectedWide = CorrectPathAllocW(strWide);
  478. char * strCorrected = ToAnsi(strCorrectedWide);
  479. free(strWide);
  480. free(strCorrectedWide);
  481. return strCorrected;
  482. }
  483. /*++
  484. Helper routine to call CorrectPathW, allocates necessary buffer space and returns a pointer
  485. to the corrected path. Caller is responsible for releasing the memory by calling free().
  486. --*/
  487. WCHAR * CorrectPathChangesBase::CorrectPathAllocW(const WCHAR * str)
  488. {
  489. if (str == NULL)
  490. return NULL;
  491. // Make sure the paths have been initialized.
  492. InitializeCorrectPathChanges();
  493. if (bEnabled)
  494. {
  495. WCHAR * strCorrected = ReplaceAllStringsAllocW(str, vKnownPathFixes);
  496. return strCorrected;
  497. }
  498. else
  499. {
  500. return StringDuplicateW(str);
  501. }
  502. }
  503. void CorrectPathChangesBase::AddFromToPairW(const WCHAR * lpFromToPair )
  504. {
  505. // Make sure the paths have been initialized.
  506. InitializeCorrectPathChanges();
  507. WCHAR * FromPath = NULL;
  508. WCHAR * ToPath = NULL;
  509. const WCHAR * PathBegin = NULL;
  510. char argSeperator = 0; // Stop parsing the string when we reach this char
  511. SkipBlanksW(lpFromToPair);
  512. // Malformed input, stop processing
  513. if (*lpFromToPair == 0)
  514. goto AllDone;
  515. // If the beginning of the string is a quote, look for the matching close quote
  516. if (*lpFromToPair == '"')
  517. {
  518. argSeperator = L'"';
  519. lpFromToPair += 1;
  520. }
  521. // The beginning of the From path
  522. PathBegin = lpFromToPair;
  523. // Search for the first from/to seperator, this is end of the From path
  524. while (*lpFromToPair != L';')
  525. {
  526. // Malformed input, stop processing
  527. if (*lpFromToPair == 0)
  528. goto AllDone;
  529. lpFromToPair += 1;
  530. }
  531. // Malformed input, stop processing
  532. if (lpFromToPair == PathBegin)
  533. goto AllDone;
  534. // Copy into our From string
  535. FromPath = StringNDuplicateW(PathBegin, (int)(lpFromToPair - PathBegin));
  536. lpFromToPair += 1; // Skip the from/to seperator
  537. // The beginning of the To path
  538. PathBegin = lpFromToPair;
  539. // Search for argSeperator, this is end of the To path
  540. while (*lpFromToPair != argSeperator)
  541. {
  542. // Found the end of the string, To path is definately complete
  543. if (*lpFromToPair == 0)
  544. break;
  545. lpFromToPair += 1;
  546. }
  547. // Malformed input, stop processing
  548. if (lpFromToPair == PathBegin)
  549. goto AllDone;
  550. // Copy into our To string
  551. ToPath = StringNDuplicateW(PathBegin, (int)(lpFromToPair - PathBegin));
  552. // Success!
  553. AddPathChangeW(FromPath, ToPath);
  554. AllDone:
  555. free(FromPath);
  556. free(ToPath);
  557. }
  558. /*++
  559. Take a single string containing (multiple) path change pairs,
  560. split them up and call AddPathChangeW.
  561. The from/to pair is seperated by a : (colon)
  562. If a path contains spaces, the entire pair must be surrounded by quotes
  563. Example:
  564. "%windir%\Goofy Location:%SystemDir%\CorrectLocation" %windir%\Goofy2:%SystemDir%\CorrectLocation2
  565. will call
  566. AddPathChangeW("%windir%\Goofy Location", "%SystemDir%\CorrectLocation");
  567. AddPathChangeW("%windir%\Goofy2", "%SystemDir%\CorrectLocation2");
  568. --*/
  569. void CorrectPathChangesBase::AddCommandLineW(const WCHAR * lpCommandLine )
  570. {
  571. if (!lpCommandLine || *lpCommandLine == 0)
  572. return;
  573. DPF("CorrectPathChangesBase", eDbgLevelInfo, "AddCommandLine(%S)\n", lpCommandLine);
  574. int argc;
  575. LPWSTR * argv = _CommandLineToArgvW(lpCommandLine, &argc);
  576. if (!argv)
  577. return;
  578. for (int i = 0; i < argc; ++i)
  579. {
  580. AddFromToPairW(argv[i]);
  581. }
  582. free(argv);
  583. }
  584. /*++
  585. Simply widen the string and call AddCommandLineW
  586. --*/
  587. void CorrectPathChangesBase::AddCommandLineA(const char * lpCommandLine )
  588. {
  589. if (!lpCommandLine || *lpCommandLine == 0)
  590. return;
  591. WCHAR * wszCommandLine = ToUnicode(lpCommandLine);
  592. AddCommandLineW(wszCommandLine);
  593. free(wszCommandLine);
  594. }
  595. // Get the full path to wordpad.exe from the registry
  596. BOOL GetWordpadPath(CString & csWordpad)
  597. {
  598. CSTRING_TRY
  599. {
  600. csWordpad.Truncate(0);
  601. LONG lStatus = RegQueryValueExW(csWordpad,
  602. HKEY_CLASSES_ROOT,
  603. L"Applications\\wordpad.exe\\shell\\open\\command",
  604. NULL);
  605. if (ERROR_SUCCESS == lStatus)
  606. {
  607. // String is of the form "wordpad path" "%1"
  608. // We want to grab all the stuff between the first pair of quotes
  609. if (csWordpad[0] == L'"')
  610. {
  611. int nNextQuote = csWordpad.Find(L'"', 1);
  612. if (nNextQuote > 0)
  613. {
  614. csWordpad.Truncate(nNextQuote);
  615. csWordpad.Delete(0, 1);
  616. return TRUE;
  617. }
  618. }
  619. }
  620. }
  621. CSTRING_CATCH
  622. {
  623. // Fall thru
  624. }
  625. return FALSE;
  626. }
  627. void CorrectPathChangesUser::InitializePathFixes()
  628. {
  629. // The order of this list is important. Early entries may create paths that are modified by later entries.
  630. // Hardcoded bad path
  631. AddPathChangeW( L"c:\\windows", L"%WinDir%" );
  632. // robkenny 4/2/2001 Do not redirect Program Files, because it is common to
  633. // create this directory on many hard drives, especially when c:\ is nearly full
  634. // AddPathChangeW( L"c:\\program files", L"%ProgramFiles%" );
  635. // Moved system applications
  636. AddPathChangeW( L"%WinDir%\\rundll32.exe", L"%SystemDir%\\rundll32.exe" );
  637. AddPathChangeW( L"%WinDir%\\rundll.exe", L"%SystemDir%\\rundll32.exe" );
  638. AddPathChangeW( L"%WinDir%\\write.exe", L"%SystemDir%\\write.exe" );
  639. AddPathChangeW( L"%WinDir%\\dxdiag.exe", L"%SystemDir%\\dxdiag.exe" );
  640. CSTRING_TRY
  641. {
  642. CString csWordpad;
  643. if (GetWordpadPath(csWordpad))
  644. {
  645. AddPathChangeW( L"%WinDir%\\wordpad.exe", csWordpad);
  646. AddPathChangeW( L"%ProgramFiles%\\Accessories\\wordpad.exe", csWordpad);
  647. }
  648. }
  649. CSTRING_CATCH
  650. {
  651. // Do nothing
  652. }
  653. // Win9x single user locations (also default)
  654. AddPathChangeW( L"%WinDir%\\Start Menu", L"%UserStartMenu%" );
  655. AddPathChangeW( L"%WinDir%\\Desktop", L"%UserDesktop%" );
  656. AddPathChangeW( L"%WinDir%\\Favorites", L"%UserFavorites%" );
  657. // These locations are properly internationalized. Duplicates of above for English
  658. AddPathChangeW( L"%WinDir%\\%CSIDL_STARTMENU_NAME%", L"%UserStartMenu%" );
  659. AddPathChangeW( L"%WinDir%\\%CSIDL_DESKTOPDIRECTORY_NAME%", L"%UserDesktop%" );
  660. AddPathChangeW( L"%WinDir%\\%CSIDL_FAVORITES_NAME%", L"%UserFavorites%" );
  661. // Win9x & WinNT multi user locations
  662. AddPathChangeW( L"%WinDir%\\Profiles\\%Username%\\Start Menu", L"%UserStartMenu%" );
  663. AddPathChangeW( L"%WinDir%\\Profiles\\%Username%\\Desktop", L"%UserDesktop%" );
  664. AddPathChangeW( L"%WinDir%\\Profiles\\%Username%\\Favorites", L"%UserFavorites%" );
  665. // These locations are properly internationalized. Duplicates of above for English
  666. AddPathChangeW( L"%WinDir%\\Profiles\\%Username%\\%CSIDL_STARTMENU_NAME%", L"%UserStartMenu%" );
  667. AddPathChangeW( L"%WinDir%\\Profiles\\%Username%\\%CSIDL_DESKTOPDIRECTORY_NAME%", L"%UserDesktop%" );
  668. AddPathChangeW( L"%WinDir%\\Profiles\\%Username%\\%CSIDL_FAVORITES_NAME%", L"%UserFavorites%" );
  669. // WinNT all user location
  670. AddPathChangeW( L"%WinDir%\\Profiles\\All Users\\Start Menu", L"%AllStartMenu%" );
  671. AddPathChangeW( L"%WinDir%\\Profiles\\All Users\\Desktop", L"%AllDesktop%" );
  672. AddPathChangeW( L"%WinDir%\\Profiles\\All Users\\Favorites", L"%UserFavorites%" ); // Should be %AllFavorites%, but IE 5.0 doesn't look there.
  673. // These locations are properly internationalized. Duplicates of above for English
  674. AddPathChangeW( L"%WinDir%\\Profiles\\%AllUsersProfile_NAME%\\%CSIDL_STARTMENU_NAME%", L"%AllStartMenu%" );
  675. AddPathChangeW( L"%WinDir%\\Profiles\\%AllUsersProfile_NAME%\\%CSIDL_DESKTOPDIRECTORY_NAME%", L"%AllDesktop%" );
  676. AddPathChangeW( L"%WinDir%\\Profiles\\%AllUsersProfile_NAME%\\%CSIDL_FAVORITES_NAME%", L"%UserFavorites%" ); // Should be %AllFavorites%, but IE 5.0 doesn't look there.
  677. // Win9x deleted DirectX files
  678. AddPathChangeW( L"ddhelp.exe", L"ddraw.dll" );
  679. AddPathChangeW( L"ddraw16.dll", L"ddraw.dll" );
  680. AddPathChangeW( L"dsound.vxd", L"ddraw.dll" );
  681. }
  682. // Does the current process have permission to write into this directory?
  683. BOOL CanWriteHere(DWORD clsid)
  684. {
  685. WCHAR wszDir[MAX_PATH];
  686. HRESULT result = SHGetFolderPathW( NULL, clsid, NULL, SHGFP_TYPE_DEFAULT, wszDir );
  687. if (SUCCEEDED(result))
  688. {
  689. //WCHAR wszTempFile[MAX_PATH];
  690. // We do not use GetTempFileName() to test if we have permission
  691. // to the directory even though it does all that we need. Unfortunately
  692. // the temp file will appear in the start menu since it is not hidden.
  693. // Emulate the behaviour of GetTempFileName but use our file attributes.
  694. // Loop a bunch of times attempting to create a temp file,
  695. // If we can create this file return immediately,
  696. // If we have insuffient permission return immediately
  697. // certain other errors will return immediately
  698. // otherwise we'll attempt to open the next temp file name
  699. // 100 is totally arbitrary: just need to attempt this a bunch of times
  700. static const int MaxTempFileAttempts = 100;
  701. int i;
  702. for (i = 0; i < MaxTempFileAttempts; ++i)
  703. {
  704. HANDLE hTempFile = INVALID_HANDLE_VALUE;
  705. CSTRING_TRY
  706. {
  707. CString csTempFile;
  708. csTempFile.Format(L"%s\\CFP%08x.tmp", wszDir, i);
  709. DPF("CanWriteHere", eDbgLevelSpew, "File(%S)\n", csTempFile.Get());
  710. hTempFile = CreateFileW(
  711. csTempFile,
  712. GENERIC_WRITE | DELETE,
  713. 0, // no sharing
  714. NULL,
  715. CREATE_NEW,
  716. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
  717. NULL
  718. );
  719. }
  720. CSTRING_CATCH
  721. {
  722. // do nothing
  723. }
  724. if (hTempFile != INVALID_HANDLE_VALUE)
  725. {
  726. DPF("CanWriteHere", eDbgLevelSpew, "success\n");
  727. CloseHandle(hTempFile);
  728. return TRUE;
  729. }
  730. else
  731. {
  732. // Borrowed this code from GetTempFileName:
  733. DWORD LastError = GetLastError();
  734. DPF("CanWriteHere", eDbgLevelSpew, "Error(0x%08x)\n", LastError);
  735. switch (LastError)
  736. {
  737. case ERROR_INVALID_PARAMETER :
  738. case ERROR_WRITE_PROTECT :
  739. case ERROR_FILE_NOT_FOUND :
  740. case ERROR_BAD_PATHNAME :
  741. case ERROR_INVALID_NAME :
  742. case ERROR_PATH_NOT_FOUND :
  743. case ERROR_NETWORK_ACCESS_DENIED :
  744. case ERROR_DISK_CORRUPT :
  745. case ERROR_FILE_CORRUPT :
  746. case ERROR_DISK_FULL :
  747. // An error from which we cannot recover...
  748. return FALSE;
  749. case ERROR_ACCESS_DENIED :
  750. // It's possible for us to hit this if there's a
  751. // directory with the name we're trying; in that
  752. // case, we can usefully continue.
  753. // CreateFile() uses BaseSetLastNTError() to set
  754. // LastStatusValue to the actual NT error in the
  755. // TEB; we just need to check it, and only abort
  756. // if it's not a directory.
  757. // This was bug #397477.
  758. if (NtCurrentTeb()->LastStatusValue != STATUS_FILE_IS_A_DIRECTORY)
  759. {
  760. // Insuffient permission
  761. return FALSE;
  762. }
  763. }
  764. }
  765. }
  766. }
  767. return FALSE;
  768. }
  769. void CorrectPathChangesAllUser::InitializePathFixes()
  770. {
  771. CorrectPathChangesUser::InitializePathFixes();
  772. // The choice to put these values into All Users instead of <UserName>
  773. // was not taken lightly. The problem is: some apps create ...\All Users\Start Menu\folder
  774. // then attempt to place files into c:\windows\Start Menu\folder or username\Start Menu\folder.
  775. // Yes the apps are WRONG, but we want them to work. By directing all of these paths
  776. // to All Users we *know* where the files will be placed and can make sure they all are the same place.
  777. // Another note, IE 5.0 does *not* look in All Users\Favorites for links,
  778. // so we force all favorites to end up in the user favorites. Sheesh.
  779. // We add these changes twice, the first to convert any long path names to the All User dir,
  780. // the second to convert any short path names to All User.
  781. if (CanWriteHere(CSIDL_COMMON_STARTMENU))
  782. {
  783. AddPathChangeW( L"%UserStartMenu%", L"%AllStartMenu%" );
  784. }
  785. else
  786. {
  787. DPF("CorrectPathChangesAllUser", eDbgLevelInfo, "*NOT* forcing %UserStartMenu% to %AllStartMenu% -- insufficient permission");
  788. }
  789. /*
  790. // 05/11/2001 robkenny:
  791. // We are nolonger modifying the Desktop directory
  792. if (CanWriteHere(CSIDL_COMMON_DESKTOPDIRECTORY))
  793. {
  794. AddPathChangeW( L"%UserDesktop%", L"%AllDesktop%" );
  795. }
  796. else
  797. {
  798. DPF("CorrectPathChangesAllUser", eDbgLevelInfo, "*NOT* forcing %UserDesktop% to %AllDesktop% -- insufficient permission");
  799. }
  800. */
  801. /*
  802. // IE 5.0/5.5 doesn't use All Users
  803. if (CanWriteHere(CSIDL_COMMON_FAVORITES))
  804. {
  805. AddPathChangeW( L"%UserFavorites%", L"%AllFavorites%" ); // IE 5.0 doesn't use All Users
  806. }
  807. else
  808. {
  809. DPF("CorrectPathChangesAllUser", eDbgLevelInfo, "*NOT* forcing %UserFavorites% to %AllFavorites% -- insufficient permission");
  810. }
  811. */
  812. }
  813. }; // end of namespace ShimLib