Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1281 lines
39 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 "Userenv.h"
  21. #include <stdio.h>
  22. namespace ShimLib
  23. {
  24. /*++
  25. A simple string class.
  26. Mostly to ease the pain and drudgery of string manipulation in StringISub
  27. --*/
  28. class SimpleString
  29. {
  30. protected:
  31. DWORD dwLen; // String Length
  32. DWORD dwSize; // String Data size
  33. WCHAR * lpData; // String Data
  34. bool Resize(DWORD dwSize); // Make buffer large enough for dwSize characters (not bytes)
  35. public:
  36. SimpleString();
  37. ~SimpleString();
  38. //
  39. // Note, this ctor should only be used for const.
  40. //
  41. SimpleString(LPCWSTR pwsz, DWORD dwLen)
  42. {
  43. lpData = (LPWSTR)pwsz;
  44. this->dwLen = dwLen;
  45. dwSize = 0;
  46. }
  47. DWORD Length() const; // Number of characters in string
  48. bool Append(const SimpleString & string);
  49. BOOL Set(const WCHAR * string);
  50. BOOL SetN(const WCHAR * string, DWORD dwStringLen);
  51. const WCHAR * Get() const;
  52. BOOL StringISub(const SimpleString & ssMatch, const SimpleString & ssReplace);
  53. WCHAR * ReleaseString(); // Caller now owns the string
  54. operator const WCHAR * () const;
  55. SimpleString & operator = (const SimpleString & string);
  56. static WCHAR * ReplaceAllStringsAllocW(const WCHAR * lpOrig, const StringPairW * ReplaceList, DWORD dwReplaceListSize);
  57. };
  58. typedef const SimpleString ConstSimpleString;
  59. /*++
  60. Constructor, init all values
  61. --*/
  62. SimpleString::SimpleString()
  63. {
  64. dwLen = 0;
  65. dwSize = 0;
  66. lpData = NULL;
  67. }
  68. /*++
  69. Destructor, free memory
  70. --*/
  71. SimpleString::~SimpleString()
  72. {
  73. if (lpData && dwSize)
  74. free(lpData);
  75. }
  76. /*++
  77. Return the number of char in the string
  78. --*/
  79. DWORD SimpleString::Length() const
  80. {
  81. return dwLen;
  82. }
  83. /*++
  84. Make the string large enough to hold size characters.
  85. Note: size should include EOS at the end.
  86. --*/
  87. bool SimpleString::Resize(DWORD size)
  88. {
  89. if (size > dwSize)
  90. {
  91. lpData = (WCHAR *) realloc(lpData, size * sizeof(WCHAR));
  92. dwSize = size;
  93. }
  94. return(size == 0) || (lpData != NULL);
  95. }
  96. /*++
  97. Append string onto the end of this.
  98. --*/
  99. bool SimpleString::Append(const SimpleString & string)
  100. {
  101. bool stringSafe = Resize(Length() + string.Length() + 1);
  102. if (stringSafe)
  103. {
  104. wcscat(lpData, string);
  105. dwLen = Length() + string.Length();
  106. }
  107. return stringSafe;
  108. }
  109. /*++
  110. Initialize this with a char string
  111. --*/
  112. BOOL SimpleString::Set(const WCHAR * string)
  113. {
  114. return SetN(string, wcslen(string));
  115. }
  116. /*++
  117. Return a pointer to the string, class still owns pointer.
  118. --*/
  119. const WCHAR * SimpleString::Get() const
  120. {
  121. return lpData;
  122. }
  123. /*++
  124. Initialize this with the first stringLen chars in string.
  125. --*/
  126. BOOL SimpleString::SetN(const WCHAR * string, DWORD stringLen)
  127. {
  128. BOOL bAllocGood = Resize(stringLen + 1);
  129. if (bAllocGood)
  130. {
  131. dwLen = stringLen;
  132. wcsncpy(lpData, string, stringLen);
  133. lpData[stringLen] = 0;
  134. }
  135. return bAllocGood;
  136. }
  137. /*++
  138. Release ownership of the string.
  139. Caller is now responsible for calling free()
  140. --*/
  141. WCHAR * SimpleString::ReleaseString()
  142. {
  143. WCHAR * lpOwner = lpData;
  144. dwLen = 0;
  145. dwSize = 0;
  146. lpData = NULL;
  147. return lpOwner;
  148. }
  149. /*++
  150. String substitution, replace all ssMatch with ssReplace
  151. --*/
  152. BOOL SimpleString::StringISub(const SimpleString & ssMatch, const SimpleString & ssReplace)
  153. {
  154. // Look to see if the match string exists
  155. WCHAR * lpMatchInString = wcsistr( lpData, ssMatch );
  156. if (lpMatchInString != NULL)
  157. {
  158. // The remainder of the uncorrected string
  159. SimpleString strRemainder;
  160. if (!strRemainder.Set(lpMatchInString + ssMatch.Length()))
  161. return FALSE;
  162. BOOL stringRemainderReplaced = strRemainder.StringISub(ssMatch, ssReplace);
  163. if (!SetN(lpData, (DWORD)(lpMatchInString - lpData)))
  164. return FALSE;
  165. if (!Append(ssReplace))
  166. return FALSE;
  167. if (!Append(strRemainder))
  168. return FALSE;
  169. return stringRemainderReplaced;
  170. }
  171. else
  172. {
  173. return FALSE;
  174. }
  175. }
  176. /*++
  177. Return a const pointer to the string.
  178. --*/
  179. SimpleString::operator const WCHAR * () const
  180. {
  181. return lpData;
  182. }
  183. /*++
  184. Assignment operator, safely make a duplicate.
  185. --*/
  186. SimpleString & SimpleString::operator = (const SimpleString & string)
  187. {
  188. SetN(string.lpData, string.dwLen);
  189. return *this;
  190. }
  191. /*++
  192. Func: ReplaceAllStringsAllocW
  193. Params: lpOrig Original string
  194. ReplaceList Array of string old/new pairs
  195. dwReplaceListSize Number of entries in ReplaceList
  196. Return: WCHAR * Newly allocated string containing (possibly) modified string
  197. Desc: For each entry in ReplaceList replace the string in lpOrig, placing the result into lpCorrected.
  198. --*/
  199. WCHAR * SimpleString::ReplaceAllStringsAllocW(
  200. const WCHAR * lpOrig,
  201. const StringPairW * ReplaceList,
  202. DWORD dwReplaceListSize)
  203. {
  204. //DPF("SimpleString", eDbgLevelInfo, "\nReplaceAllStringsAllocW(%S)\n", lpOrig);
  205. SimpleString ssReplaced;
  206. if (ssReplaced.Set(lpOrig))
  207. {
  208. for (DWORD i = 0; i < dwReplaceListSize; ++i)
  209. {
  210. // Attempt a string substitution
  211. ssReplaced.StringISub(
  212. ConstSimpleString(ReplaceList[i].lpOld, ReplaceList[i].dwLenOld),
  213. ConstSimpleString(ReplaceList[i].lpNew, ReplaceList[i].dwLenNew));
  214. //DPF("SimpleString", eDbgLevelInfo, "Old(%S)\n", ReplaceList[i].lpOld);
  215. //DPF("SimpleString", eDbgLevelInfo, "New(%S)\n", ReplaceList[i].lpNew);
  216. //DPF("SimpleString", eDbgLevelInfo, "Val(%S)\n", ssReplaced.Get());
  217. }
  218. }
  219. return ssReplaced.ReleaseString();
  220. }
  221. //-------------------------------------------------------------------------------------------------------------
  222. EnvironmentValues::EnvironmentValues()
  223. {
  224. bInitialized = FALSE;
  225. }
  226. EnvironmentValues::~EnvironmentValues()
  227. {
  228. // Clear the list
  229. Erase();
  230. }
  231. // Given an CLSIDL, create an environment variable and its two variants
  232. // CSIDL_WINDOWS would add c:\windows, \windows and windows
  233. void EnvironmentValues::Add_Variants(const WCHAR * lpEnvName, const WCHAR * lpEnvValue, eAddNameEnum addName, eAddNoDLEnum noDL)
  234. {
  235. CSTRING_TRY
  236. {
  237. CString csEnvName(lpEnvName);
  238. CString csEnvValue(lpEnvValue);
  239. csEnvName.Format(L"%%%s%%", lpEnvName);
  240. AddEnvironmentValue(csEnvName, csEnvValue);
  241. // Remove the drive letter and the colon.
  242. if (noDL == eAddNoDL)
  243. {
  244. CString csNoDL(csEnvValue);
  245. csNoDL.Delete(0, 2);
  246. csEnvName.Format(L"%%%s_NODL%%", lpEnvName);
  247. AddEnvironmentValue(csEnvName, csNoDL);
  248. }
  249. // Use the last path component as the name.
  250. if (addName == eAddName)
  251. {
  252. CString csName;
  253. csEnvValue.GetLastPathComponent(csName);
  254. csEnvName.Format(L"%%%s_NAME%%", lpEnvName);
  255. AddEnvironmentValue(csEnvName, csName);
  256. }
  257. }
  258. CSTRING_CATCH
  259. {
  260. // Do Nothing
  261. }
  262. }
  263. // Given an CLSIDL, create an environment variable and its two variants
  264. // CSIDL_WINDOWS would add c:\windows, \windows and windows
  265. void EnvironmentValues::Add_CSIDL(const WCHAR * lpEnvName, int nFolder, eAddNameEnum addName, eAddNoDLEnum noDL)
  266. {
  267. CSTRING_TRY
  268. {
  269. CString csPath;
  270. SHGetSpecialFolderPathW(csPath, nFolder);
  271. if (csPath.GetLength() > 0)
  272. {
  273. Add_Variants(lpEnvName, csPath, addName, noDL);
  274. }
  275. }
  276. CSTRING_CATCH
  277. {
  278. // Do Nothing
  279. }
  280. }
  281. // Add all _CSIDL values as environment variables.
  282. void EnvironmentValues::AddAll_CSIDL()
  283. {
  284. Add_CSIDL(L"CSIDL_APPDATA", CSIDL_APPDATA, eAddName, eAddNoDL);
  285. Add_CSIDL(L"CSIDL_COMMON_ADMINTOOLS", CSIDL_COMMON_ADMINTOOLS, eAddName, eAddNoDL);
  286. Add_CSIDL(L"CSIDL_COMMON_APPDATA", CSIDL_COMMON_APPDATA, eAddName, eAddNoDL);
  287. Add_CSIDL(L"CSIDL_COMMON_DESKTOPDIRECTORY", CSIDL_COMMON_DESKTOPDIRECTORY, eAddName, eAddNoDL);
  288. Add_CSIDL(L"CSIDL_COMMON_DOCUMENTS", CSIDL_COMMON_DOCUMENTS, eAddName, eAddNoDL);
  289. Add_CSIDL(L"CSIDL_COMMON_FAVORITES", CSIDL_COMMON_FAVORITES, eAddName, eAddNoDL);
  290. Add_CSIDL(L"CSIDL_COMMON_MUSIC", CSIDL_COMMON_MUSIC, eAddName, eAddNoDL);
  291. Add_CSIDL(L"CSIDL_COMMON_PICTURES", CSIDL_COMMON_PICTURES, eAddName, eAddNoDL);
  292. Add_CSIDL(L"CSIDL_COMMON_PROGRAMS", CSIDL_COMMON_PROGRAMS, eAddName, eAddNoDL);
  293. Add_CSIDL(L"CSIDL_COMMON_STARTMENU", CSIDL_COMMON_STARTMENU, eAddName, eAddNoDL);
  294. Add_CSIDL(L"CSIDL_COMMON_STARTUP", CSIDL_COMMON_STARTUP, eAddName, eAddNoDL);
  295. Add_CSIDL(L"CSIDL_COMMON_TEMPLATES", CSIDL_COMMON_TEMPLATES, eAddName, eAddNoDL);
  296. Add_CSIDL(L"CSIDL_COOKIES", CSIDL_COOKIES, eAddName, eAddNoDL);
  297. Add_CSIDL(L"CSIDL_DESKTOPDIRECTORY", CSIDL_DESKTOPDIRECTORY, eAddName, eAddNoDL);
  298. Add_CSIDL(L"CSIDL_FAVORITES", CSIDL_FAVORITES, eAddName, eAddNoDL);
  299. Add_CSIDL(L"CSIDL_FONTS", CSIDL_FONTS, eAddName, eAddNoDL);
  300. Add_CSIDL(L"CSIDL_HISTORY", CSIDL_HISTORY, eAddName, eAddNoDL);
  301. Add_CSIDL(L"CSIDL_INTERNET_CACHE", CSIDL_INTERNET_CACHE, eAddName, eAddNoDL);
  302. Add_CSIDL(L"CSIDL_LOCAL_APPDATA", CSIDL_LOCAL_APPDATA, eAddName, eAddNoDL);
  303. Add_CSIDL(L"CSIDL_MYMUSIC", CSIDL_MYMUSIC, eAddName, eAddNoDL);
  304. Add_CSIDL(L"CSIDL_MYPICTURES", CSIDL_MYPICTURES, eAddName, eAddNoDL);
  305. Add_CSIDL(L"CSIDL_NETHOOD", CSIDL_NETHOOD, eAddName, eAddNoDL);
  306. Add_CSIDL(L"CSIDL_PERSONAL", CSIDL_PERSONAL, eAddName, eAddNoDL);
  307. Add_CSIDL(L"CSIDL_PRINTHOOD", CSIDL_PRINTHOOD, eAddName, eAddNoDL);
  308. Add_CSIDL(L"CSIDL_PROFILE", CSIDL_PROFILE, eAddName, eAddNoDL);
  309. Add_CSIDL(L"CSIDL_PROGRAM_FILES", CSIDL_PROGRAM_FILES, eAddName, eAddNoDL);
  310. Add_CSIDL(L"CSIDL_PROGRAM_FILES_COMMON", CSIDL_PROGRAM_FILES_COMMON, eAddName, eAddNoDL);
  311. Add_CSIDL(L"CSIDL_PROGRAMS", CSIDL_PROGRAMS, eAddName, eAddNoDL);
  312. Add_CSIDL(L"CSIDL_RECENT", CSIDL_RECENT, eAddName, eAddNoDL);
  313. Add_CSIDL(L"CSIDL_SENDTO", CSIDL_SENDTO, eAddName, eAddNoDL);
  314. Add_CSIDL(L"CSIDL_STARTMENU", CSIDL_STARTMENU, eAddName, eAddNoDL);
  315. Add_CSIDL(L"CSIDL_STARTUP", CSIDL_STARTUP, eAddName, eAddNoDL);
  316. Add_CSIDL(L"CSIDL_SYSTEM", CSIDL_SYSTEM, eAddName, eAddNoDL);
  317. Add_CSIDL(L"CSIDL_TEMPLATES", CSIDL_TEMPLATES, eAddName, eAddNoDL);
  318. Add_CSIDL(L"CSIDL_WINDOWS", CSIDL_WINDOWS, eAddName, eAddNoDL);
  319. }
  320. void EnvironmentValues::Initialize()
  321. {
  322. if (bInitialized == FALSE)
  323. {
  324. bInitialized = TRUE;
  325. WCHAR lpDir[MAX_PATH];
  326. DWORD dwSize;
  327. HRESULT result;
  328. DWORD dwChars;
  329. BOOL bResult;
  330. dwChars = GetWindowsDirectoryW(lpDir, MAX_PATH);
  331. if (dwChars != 0)
  332. {
  333. AddEnvironmentValue( L"%WinDir%", lpDir );
  334. AddEnvironmentValue( L"%SystemRoot%", lpDir );
  335. lpDir[2] = 0;
  336. AddEnvironmentValue( L"%SystemDrive%", lpDir );
  337. }
  338. dwChars = GetSystemDirectoryW( lpDir, MAX_PATH);
  339. if (dwChars != 0)
  340. {
  341. AddEnvironmentValue( L"%SystemDir%", lpDir );
  342. }
  343. dwSize = MAX_PATH;
  344. bResult = GetUserNameW(lpDir, &dwSize);
  345. if (bResult)
  346. {
  347. AddEnvironmentValue( L"%Username%", lpDir );
  348. }
  349. result = SHGetFolderPathW( NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  350. if (SUCCEEDED(result))
  351. {
  352. AddEnvironmentValue( L"%ProgramFiles%", lpDir );
  353. }
  354. result = SHGetFolderPathW( NULL, CSIDL_STARTMENU, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  355. if (SUCCEEDED(result))
  356. {
  357. AddEnvironmentValue( L"%UserStartMenu%", lpDir );
  358. }
  359. result = SHGetFolderPathW( NULL, CSIDL_COMMON_STARTMENU, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  360. if (SUCCEEDED(result))
  361. {
  362. AddEnvironmentValue( L"%AllStartMenu%", lpDir );
  363. }
  364. result = SHGetFolderPathW( NULL, CSIDL_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  365. if (SUCCEEDED(result))
  366. {
  367. AddEnvironmentValue( L"%UserDesktop%", lpDir );
  368. }
  369. result = SHGetFolderPathW( NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  370. if (SUCCEEDED(result))
  371. {
  372. AddEnvironmentValue( L"%AllDesktop%", lpDir );
  373. }
  374. result = SHGetFolderPathW( NULL, CSIDL_FAVORITES, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  375. if (SUCCEEDED(result))
  376. {
  377. AddEnvironmentValue( L"%UserFavorites%", lpDir );
  378. }
  379. result = SHGetFolderPathW( NULL, CSIDL_COMMON_FAVORITES, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  380. if (SUCCEEDED(result))
  381. {
  382. AddEnvironmentValue( L"%AllFavorites%", lpDir );
  383. }
  384. result = SHGetFolderPathW( NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  385. if (SUCCEEDED(result))
  386. {
  387. AddEnvironmentValue( L"%UserAppData%", lpDir );
  388. }
  389. result = SHGetFolderPathW( NULL, CSIDL_COMMON_APPDATA, NULL, SHGFP_TYPE_DEFAULT, lpDir );
  390. if (SUCCEEDED(result))
  391. {
  392. AddEnvironmentValue( L"%AllAppData%", lpDir );
  393. }
  394. // C:\Documents and Settings\All Users
  395. dwSize = MAX_PATH;
  396. bResult = GetAllUsersProfileDirectoryW(lpDir, &dwSize);
  397. if (bResult)
  398. {
  399. Add_Variants( L"AllUsersProfile", lpDir, eAddName, eAddNoDL); // same as real Env var
  400. }
  401. // C:\Documents and Settings\owner
  402. HANDLE hProcessHandle = GetCurrentProcess();
  403. HANDLE hUserToken;
  404. if (OpenProcessToken(hProcessHandle, TOKEN_QUERY, &hUserToken))
  405. {
  406. dwSize = MAX_PATH;
  407. bResult = GetUserProfileDirectoryW(hUserToken, lpDir, &dwSize);
  408. if (bResult)
  409. {
  410. Add_Variants( L"UserProfile", lpDir, eAddName, eAddNoDL);
  411. }
  412. }
  413. // Add the new CLSIDL variables (some have duplicate values to above)
  414. AddAll_CSIDL();
  415. }
  416. }
  417. WCHAR * EnvironmentValues::ExpandEnvironmentValueW(const WCHAR * lpOld)
  418. {
  419. Initialize();
  420. // Replace all the "environment" values into their real values
  421. WCHAR * lpMassagedOld = SimpleString::ReplaceAllStringsAllocW(lpOld, vectorList, nVectorListMax );
  422. return lpMassagedOld;
  423. }
  424. char * EnvironmentValues::ExpandEnvironmentValueA(const char * lpOld)
  425. {
  426. Initialize();
  427. char * lpMassagedOld = NULL;
  428. WCHAR * lpOldWide = ToUnicode(lpOld);
  429. if (lpOldWide)
  430. {
  431. WCHAR * lpMassagedOldWide = SimpleString::ReplaceAllStringsAllocW(lpOldWide, vectorList, nVectorListMax );
  432. if (lpMassagedOldWide)
  433. {
  434. lpMassagedOld = ToAnsi(lpMassagedOldWide);
  435. free(lpMassagedOldWide);
  436. }
  437. free(lpOldWide);
  438. }
  439. return lpMassagedOld;
  440. }
  441. void EnvironmentValues::AddEnvironmentValue(const WCHAR * lpOld, const WCHAR * lpNew)
  442. {
  443. Initialize();
  444. StringPairW appendThis(lpOld, lpNew);
  445. if (Append(appendThis))
  446. {
  447. DPF("EnvironmentValues", eDbgLevelInfo, "AddEnvironmentValue: (%S) to (%S)\n", appendThis.lpOld, appendThis.lpNew );
  448. }
  449. }
  450. //-------------------------------------------------------------------------------------------------------------
  451. CorrectPathChangesBase::CorrectPathChangesBase()
  452. {
  453. lpEnvironmentValues = new EnvironmentValues;
  454. dwKnownPathFixesCount = 0;
  455. lpKnownPathFixes = (StringPairW *)malloc(sizeof(StringPairW)); // prime the pump for realloc later
  456. bInitialized = FALSE;
  457. bEnabled = TRUE;
  458. InitializeCriticalSection(&csCritical);
  459. }
  460. CorrectPathChangesBase::~CorrectPathChangesBase()
  461. {
  462. if (lpEnvironmentValues)
  463. delete lpEnvironmentValues;
  464. if (lpKnownPathFixes)
  465. free(lpKnownPathFixes);
  466. DeleteCriticalSection(&csCritical);
  467. }
  468. void CorrectPathChangesBase::EnterCS()
  469. {
  470. EnterCriticalSection(&csCritical);
  471. }
  472. void CorrectPathChangesBase::LeaveCS()
  473. {
  474. LeaveCriticalSection(&csCritical);
  475. }
  476. /*++
  477. Func: AddEnvironmentValue
  478. Params: dwIndex
  479. lpOld Name of "environment" variable
  480. lpNew Value of "environment" variable
  481. --*/
  482. void CorrectPathChangesBase::AddEnvironmentValue(const WCHAR * lpOld, const WCHAR * lpNew )
  483. {
  484. if (lpEnvironmentValues)
  485. {
  486. lpEnvironmentValues->AddEnvironmentValue(lpOld, lpNew);
  487. }
  488. }
  489. /*++
  490. Func: InsertPathChangeW
  491. Params:
  492. lpOld Old Win9x path
  493. lpNew New Win2000 path
  494. Desc: Insert the Old/New string pair into lpKnownPathFixes
  495. making sure the list is large enough.
  496. --*/
  497. void CorrectPathChangesBase::InsertPathChangeW( const WCHAR * lpOld, const WCHAR * lpNew )
  498. {
  499. // Ignore identical strings
  500. if (lstrcmpiW(lpOld, lpNew) == 0)
  501. return;
  502. // Ignore duplicates
  503. int i;
  504. for (i = 0; i < dwKnownPathFixesCount; ++i)
  505. {
  506. if (_wcsicmp(lpKnownPathFixes[i].lpOld, lpOld) == 0)
  507. {
  508. DPF("CorrectPathChangesBase", eDbgLevelSpew, "Duplicate PathChange (%S) to (%S)\n", lpOld, lpNew );
  509. return;
  510. }
  511. }
  512. // Grow the list
  513. size_t oldListSize = dwKnownPathFixesCount * sizeof(StringPairW);
  514. lpKnownPathFixes = (StringPairW *)realloc(lpKnownPathFixes, oldListSize + sizeof(StringPairW));
  515. if (lpKnownPathFixes == NULL)
  516. {
  517. // Alloc failed, don't add anymore
  518. return;
  519. }
  520. DWORD dwLenOld = wcslen(lpOld);
  521. wcsncpy( lpKnownPathFixes[dwKnownPathFixesCount].lpOld, lpOld, dwLenOld + 1);
  522. lpKnownPathFixes[dwKnownPathFixesCount].dwLenOld = dwLenOld;
  523. DWORD dwLenNew = wcslen(lpNew);
  524. wcsncpy( lpKnownPathFixes[dwKnownPathFixesCount].lpNew, lpNew, dwLenNew + 1);
  525. lpKnownPathFixes[dwKnownPathFixesCount].dwLenNew = dwLenNew;
  526. DPF("CorrectPathChangesBase", eDbgLevelInfo, "PathChange (%S) to (%S)\n", lpKnownPathFixes[dwKnownPathFixesCount].lpOld, lpKnownPathFixes[dwKnownPathFixesCount].lpNew );
  527. dwKnownPathFixesCount += 1;
  528. }
  529. /*++
  530. Func: AddPathChangeW
  531. Params:
  532. lpOld Old Win9x path
  533. lpNew New Win2000 path
  534. Desc: Add lpOld/lpNew combo to the list, two times:
  535. first: lpOld/short(lpNew)
  536. second: short(lpOld)/short(lpNew)
  537. --*/
  538. void CorrectPathChangesBase::AddPathChangeW( const WCHAR * lpOld, const WCHAR * lpNew )
  539. {
  540. InitializeCorrectPathChanges();
  541. // Replace all the "environment" values into their real values
  542. WCHAR * lpExpandedOld = ExpandEnvironmentValueW(lpOld);
  543. WCHAR * lpExpandedNew = ExpandEnvironmentValueW(lpNew);
  544. const WCHAR * lpNewShort = lpExpandedNew;
  545. // Convert lpNew to its short name
  546. WCHAR lpNewShortBuffer[MAX_PATH];
  547. DWORD status = GetShortPathNameW(lpExpandedNew, lpNewShortBuffer, MAX_PATH);
  548. if (status > 0 && status < MAX_PATH)
  549. {
  550. lpNewShort = lpNewShortBuffer;
  551. }
  552. // first: lpOld/short(lpNew)
  553. InsertPathChangeW(lpExpandedOld, lpNewShort);
  554. // Convert lpOld to its short name
  555. WCHAR lpOldShort[MAX_PATH];
  556. status = GetShortPathNameW(lpExpandedOld, lpOldShort, MAX_PATH);
  557. if (status > 0 && status < MAX_PATH) // successfully got the short path
  558. {
  559. if (_wcsicmp(lpOld, lpOldShort) != 0)
  560. {
  561. // second: short(lpOld)/short(lpNew)
  562. InsertPathChangeW( lpOldShort, lpNewShort );
  563. }
  564. }
  565. free(lpExpandedOld);
  566. free(lpExpandedNew);
  567. }
  568. /*++
  569. Func: ExpandEnvironmentValueA
  570. Params: lpOld string with environment vars
  571. Desc: Return a pointer to a malloc() string with all internal env values expanded.
  572. --*/
  573. char * CorrectPathChangesBase::ExpandEnvironmentValueA(const char * lpOld)
  574. {
  575. WCHAR * lpOldWide = ToUnicode(lpOld);
  576. // Replace all the "environment" values into their real values
  577. WCHAR * lpExpandedOldWide = ExpandEnvironmentValueW(lpOldWide);
  578. char * lpExpandedOld = ToAnsi(lpExpandedOldWide);
  579. free(lpOldWide);
  580. free(lpExpandedOldWide);
  581. return lpExpandedOld;
  582. }
  583. /*++
  584. Func: ExpandEnvironmentValueW
  585. Params: lpOld string with environment vars
  586. Desc: Return a pointer to a malloc() string with all internal env values expanded.
  587. --*/
  588. WCHAR * CorrectPathChangesBase::ExpandEnvironmentValueW(const WCHAR * lpOld)
  589. {
  590. WCHAR * lpMassagedOld = NULL;
  591. InitializeCorrectPathChanges();
  592. if (lpEnvironmentValues)
  593. {
  594. lpMassagedOld = lpEnvironmentValues->ExpandEnvironmentValueW(lpOld);
  595. }
  596. return lpMassagedOld;
  597. }
  598. /*++
  599. Func: InitializeEnvironmentValuesW
  600. Params: None, applies changes to lpEnvironmentValues
  601. Desc: This function sets the "environment" values to their explicit values
  602. --*/
  603. void CorrectPathChangesBase::InitializeEnvironmentValuesW( )
  604. {
  605. if (lpEnvironmentValues)
  606. {
  607. lpEnvironmentValues->Initialize();
  608. }
  609. }
  610. /*++
  611. Func: InitializePathFixes
  612. Params: None, applies changes to lpEnvironmentValues
  613. Desc: This function sets the "environment" values to their explicit values
  614. --*/
  615. void CorrectPathChangesBase::InitializePathFixes( )
  616. {
  617. }
  618. /*++
  619. Func: InitializeCorrectPathChanges
  620. Params: None.
  621. Desc: Initialize the CorrectPathChangesBase values, both A and W versions.
  622. This *must* be called prior to calling either CorrectPathChangesA or CorrectPathChangesW
  623. --*/
  624. void CorrectPathChangesBase::InitializeCorrectPathChanges( )
  625. {
  626. // This seems a little odd, but we wanted to minimize the amount of time spent
  627. // attempting to enter the critical section. The simple code is:
  628. // EnterCS();
  629. // if (!bInitialized)
  630. // {
  631. // BOOL isEnabled = bEnabled; // remember previous enabled state
  632. //
  633. // This would enter the critical section every time we make sure
  634. // the class is initialized.
  635. if (!bInitialized)
  636. {
  637. EnterCS();
  638. if (!bInitialized)
  639. {
  640. BOOL isEnabled = bEnabled; // remember previous enabled state
  641. // We must not be enabled while we are initializing, otherwise
  642. // we can (and do!) hook routines that we are trying to use while
  643. // grabbing values from the system.
  644. bEnabled = FALSE;
  645. bInitialized = TRUE;
  646. InitializeEnvironmentValuesW();
  647. InitializePathFixes();
  648. bEnabled = isEnabled;
  649. }
  650. LeaveCS();
  651. }
  652. }
  653. /*++
  654. Helper routine to call CorrectPathA, allocates necessary buffer space and returns a pointer
  655. to the corrected path. Caller is responsible for releasing the memory by calling free().
  656. --*/
  657. char * CorrectPathChangesBase::CorrectPathAllocA(const char * str)
  658. {
  659. if (str == NULL)
  660. return NULL;
  661. // Convert lpOrig to WCHAR, correct the WCHAR path, then convert back to char
  662. WCHAR * strWide = ToUnicode(str);
  663. // Correct
  664. WCHAR * strCorrectedWide = CorrectPathAllocW(strWide);
  665. char * strCorrected = ToAnsi(strCorrectedWide);
  666. free(strWide);
  667. free(strCorrectedWide);
  668. return strCorrected;
  669. }
  670. /*++
  671. Helper routine to call CorrectPathW, allocates necessary buffer space and returns a pointer
  672. to the corrected path. Caller is responsible for releasing the memory by calling free().
  673. --*/
  674. WCHAR * CorrectPathChangesBase::CorrectPathAllocW(const WCHAR * str)
  675. {
  676. if (str == NULL)
  677. return NULL;
  678. // Make sure the paths have been initialized.
  679. InitializeCorrectPathChanges();
  680. if (bEnabled)
  681. {
  682. WCHAR * strCorrected = SimpleString::ReplaceAllStringsAllocW(str, lpKnownPathFixes, dwKnownPathFixesCount);
  683. return strCorrected;
  684. }
  685. else
  686. {
  687. return StringDuplicateW(str);
  688. }
  689. }
  690. void CorrectPathChangesBase::AddFromToPairW(const WCHAR * lpFromToPair )
  691. {
  692. // Make sure the paths have been initialized.
  693. InitializeCorrectPathChanges();
  694. WCHAR * FromPath = NULL;
  695. WCHAR * ToPath = NULL;
  696. const WCHAR * PathBegin = NULL;
  697. char argSeperator = 0; // Stop parsing the string when we reach this char
  698. SkipBlanksW(lpFromToPair);
  699. // Malformed input, stop processing
  700. if (*lpFromToPair == 0)
  701. goto AllDone;
  702. // If the beginning of the string is a quote, look for the matching close quote
  703. if (*lpFromToPair == '"')
  704. {
  705. argSeperator = L'"';
  706. lpFromToPair += 1;
  707. }
  708. // The beginning of the From path
  709. PathBegin = lpFromToPair;
  710. // Search for the first from/to seperator, this is end of the From path
  711. while (*lpFromToPair != L';')
  712. {
  713. // Malformed input, stop processing
  714. if (*lpFromToPair == 0)
  715. goto AllDone;
  716. lpFromToPair += 1;
  717. }
  718. // Malformed input, stop processing
  719. if (lpFromToPair == PathBegin)
  720. goto AllDone;
  721. // Copy into our From string
  722. FromPath = StringNDuplicateW(PathBegin, (int)(lpFromToPair - PathBegin));
  723. lpFromToPair += 1; // Skip the from/to seperator
  724. // The beginning of the To path
  725. PathBegin = lpFromToPair;
  726. // Search for argSeperator, this is end of the To path
  727. while (*lpFromToPair != argSeperator)
  728. {
  729. // Found the end of the string, To path is definately complete
  730. if (*lpFromToPair == 0)
  731. break;
  732. lpFromToPair += 1;
  733. }
  734. // Malformed input, stop processing
  735. if (lpFromToPair == PathBegin)
  736. goto AllDone;
  737. // Copy into our To string
  738. ToPath = StringNDuplicateW(PathBegin, (int)(lpFromToPair - PathBegin));
  739. lpFromToPair += 1; // Skip the argSeperator
  740. // Success!
  741. AddPathChangeW(FromPath, ToPath);
  742. AllDone:
  743. free(FromPath);
  744. free(ToPath);
  745. }
  746. /*++
  747. Take a single string containing (multiple) path change pairs,
  748. split them up and call AddPathChangeW.
  749. The from/to pair is seperated by a : (colon)
  750. If a path contains spaces, the entire pair must be surrounded by quotes
  751. Example:
  752. "%windir%\Goofy Location:%SystemDir%\CorrectLocation" %windir%\Goofy2:%SystemDir%\CorrectLocation2
  753. will call
  754. AddPathChangeW("%windir%\Goofy Location", "%SystemDir%\CorrectLocation");
  755. AddPathChangeW("%windir%\Goofy2", "%SystemDir%\CorrectLocation2");
  756. --*/
  757. void CorrectPathChangesBase::AddCommandLineW(const WCHAR * lpCommandLine )
  758. {
  759. if (!lpCommandLine || *lpCommandLine == 0)
  760. return;
  761. DPF("CorrectPathChangesBase", eDbgLevelInfo, "AddCommandLine(%S)\n", lpCommandLine);
  762. int argc;
  763. LPWSTR * argv = _CommandLineToArgvW(lpCommandLine, &argc);
  764. if (!argv)
  765. return;
  766. for (int i = 0; i < argc; ++i)
  767. {
  768. AddFromToPairW(argv[i]);
  769. }
  770. free(argv);
  771. }
  772. /*++
  773. Simply widen the string and call AddCommandLineW
  774. --*/
  775. void CorrectPathChangesBase::AddCommandLineA(const char * lpCommandLine )
  776. {
  777. if (!lpCommandLine || *lpCommandLine == 0)
  778. return;
  779. WCHAR * wszCommandLine = ToUnicode(lpCommandLine);
  780. AddCommandLineW(wszCommandLine);
  781. free(wszCommandLine);
  782. }
  783. // Get the full path to wordpad.exe from the registry
  784. BOOL GetWordpadPath(CString & csWordpad)
  785. {
  786. csWordpad.Truncate(0);
  787. DWORD dwRegType;
  788. LONG lStatus = RegQueryValueExW(csWordpad,
  789. HKEY_CLASSES_ROOT,
  790. L"Applications\\wordpad.exe\\shell\\open\\command",
  791. NULL, // default key
  792. &dwRegType);
  793. if (ERROR_SUCCESS == lStatus &&
  794. (dwRegType == REG_SZ || dwRegType == REG_EXPAND_SZ))
  795. {
  796. // String is of the form "wordpad path" "%1"
  797. // We want to grab all the stuff between the first pair of quotes
  798. if (csWordpad[0] == L'"')
  799. {
  800. int nNextQuote = csWordpad.Find(L'"', 1);
  801. if (nNextQuote > 0)
  802. {
  803. csWordpad.Truncate(nNextQuote);
  804. csWordpad.Delete(0, 1);
  805. if (dwRegType == REG_EXPAND_SZ)
  806. {
  807. csWordpad.ExpandEnvironmentStringsW();
  808. }
  809. return TRUE;
  810. }
  811. }
  812. }
  813. return FALSE;
  814. }
  815. void CorrectPathChangesUser::InitializePathFixes()
  816. {
  817. // The order of this list is important. Early entries may create paths that are modified by later entries.
  818. // Hardcoded bad path
  819. AddPathChangeW( L"c:\\windows", L"%WinDir%" );
  820. // robkenny 4/2/2001 Do not redirect Program Files, because it is common to
  821. // create this directory on many hard drives, especially when c:\ is nearly full
  822. // AddPathChangeW( L"c:\\program files", L"%ProgramFiles%" );
  823. // Moved system applications
  824. AddPathChangeW( L"%WinDir%\\rundll32.exe", L"%SystemDir%\\rundll32.exe" );
  825. AddPathChangeW( L"%WinDir%\\rundll.exe", L"%SystemDir%\\rundll32.exe" );
  826. AddPathChangeW( L"%WinDir%\\write.exe", L"%SystemDir%\\write.exe" );
  827. AddPathChangeW( L"%WinDir%\\dxdiag.exe", L"%SystemDir%\\dxdiag.exe" );
  828. CSTRING_TRY
  829. {
  830. CString csWordpad;
  831. if (GetWordpadPath(csWordpad))
  832. {
  833. AddPathChangeW( L"%WinDir%\\wordpad.exe", csWordpad);
  834. AddPathChangeW( L"%ProgramFiles%\\Accessories\\wordpad.exe", csWordpad);
  835. }
  836. }
  837. CSTRING_CATCH
  838. {
  839. // Do nothing
  840. }
  841. // Win9x single user locations (also default)
  842. AddPathChangeW( L"%WinDir%\\Start Menu", L"%UserStartMenu%" );
  843. AddPathChangeW( L"%WinDir%\\Desktop", L"%UserDesktop%" );
  844. AddPathChangeW( L"%WinDir%\\Favorites", L"%UserFavorites%" );
  845. // These locations are properly internationalized. Duplicates of above for English
  846. AddPathChangeW( L"%WinDir%\\%CSIDL_STARTMENU_NAME%", L"%UserStartMenu%" );
  847. AddPathChangeW( L"%WinDir%\\%CSIDL_DESKTOPDIRECTORY_NAME%", L"%UserDesktop%" );
  848. AddPathChangeW( L"%WinDir%\\%CSIDL_FAVORITES_NAME%", L"%UserFavorites%" );
  849. // Win9x & WinNT multi user locations
  850. AddPathChangeW( L"%WinDir%\\Profiles\\%Username%\\Start Menu", L"%UserStartMenu%" );
  851. AddPathChangeW( L"%WinDir%\\Profiles\\%Username%\\Desktop", L"%UserDesktop%" );
  852. AddPathChangeW( L"%WinDir%\\Profiles\\%Username%\\Favorites", L"%UserFavorites%" );
  853. // These locations are properly internationalized. Duplicates of above for English
  854. AddPathChangeW( L"%WinDir%\\Profiles\\%Username%\\%CSIDL_STARTMENU_NAME%", L"%UserStartMenu%" );
  855. AddPathChangeW( L"%WinDir%\\Profiles\\%Username%\\%CSIDL_DESKTOPDIRECTORY_NAME%", L"%UserDesktop%" );
  856. AddPathChangeW( L"%WinDir%\\Profiles\\%Username%\\%CSIDL_FAVORITES_NAME%", L"%UserFavorites%" );
  857. // WinNT all user location
  858. AddPathChangeW( L"%WinDir%\\Profiles\\All Users\\Start Menu", L"%AllStartMenu%" );
  859. AddPathChangeW( L"%WinDir%\\Profiles\\All Users\\Desktop", L"%AllDesktop%" );
  860. AddPathChangeW( L"%WinDir%\\Profiles\\All Users\\Favorites", L"%UserFavorites%" ); // Should be %AllFavorites%, but IE 5.0 doesn't look there.
  861. // These locations are properly internationalized. Duplicates of above for English
  862. AddPathChangeW( L"%WinDir%\\Profiles\\%AllUsersProfile_NAME%\\%CSIDL_STARTMENU_NAME%", L"%AllStartMenu%" );
  863. AddPathChangeW( L"%WinDir%\\Profiles\\%AllUsersProfile_NAME%\\%CSIDL_DESKTOPDIRECTORY_NAME%", L"%AllDesktop%" );
  864. AddPathChangeW( L"%WinDir%\\Profiles\\%AllUsersProfile_NAME%\\%CSIDL_FAVORITES_NAME%", L"%UserFavorites%" ); // Should be %AllFavorites%, but IE 5.0 doesn't look there.
  865. // Win9x deleted DirectX files
  866. AddPathChangeW( L"ddhelp.exe", L"ddraw.dll" );
  867. AddPathChangeW( L"ddraw16.dll", L"ddraw.dll" );
  868. AddPathChangeW( L"dsound.vxd", L"ddraw.dll" );
  869. }
  870. // Does the current process have permission to write into this directory?
  871. BOOL CanWriteHere(DWORD clsid)
  872. {
  873. BOOL bCanWriteHere = FALSE;
  874. WCHAR wszDir[MAX_PATH];
  875. HRESULT result = SHGetFolderPathW( NULL, clsid, NULL, SHGFP_TYPE_DEFAULT, wszDir );
  876. if (SUCCEEDED(result))
  877. {
  878. WCHAR wszTempFile[MAX_PATH];
  879. // We do not use GetTempFileName() to test if we have permission
  880. // to the directory even though it does all that we need. Unfortunately
  881. // the temp file will appear in the start menu since it is not hidden.
  882. // Emulate the behaviour of GetTempFileName but use our file attributes.
  883. // Loop a bunch of times attempting to create a temp file,
  884. // If we can create this file return immediately,
  885. // If we have insuffient permission return immediately
  886. // certain other errors will return immediately
  887. // otherwise we'll attempt to open the next temp file name
  888. // 100 is totally arbitrary: just need to attempt this a bunch of times
  889. static const int MaxTempFileAttempts = 100;
  890. int i;
  891. for (i = 0; i < MaxTempFileAttempts; ++i)
  892. {
  893. swprintf(wszTempFile, L"%s\\CFP%08x.tmp", wszDir, i);
  894. DPF("CanWriteHere", eDbgLevelSpew, "File(%S)\n", wszTempFile);
  895. HANDLE hTempFile = CreateFileW(
  896. wszTempFile,
  897. GENERIC_WRITE | DELETE,
  898. 0, // no sharing
  899. NULL,
  900. CREATE_NEW,
  901. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
  902. NULL
  903. );
  904. if (hTempFile != INVALID_HANDLE_VALUE)
  905. {
  906. DPF("CanWriteHere", eDbgLevelSpew, "success\n");
  907. CloseHandle(hTempFile);
  908. return TRUE;
  909. }
  910. else
  911. {
  912. // Borrowed this code from GetTempFileName:
  913. DWORD LastError = GetLastError();
  914. DPF("CanWriteHere", eDbgLevelSpew, "Error(0x%08x)\n", LastError);
  915. switch (LastError)
  916. {
  917. case ERROR_INVALID_PARAMETER :
  918. case ERROR_WRITE_PROTECT :
  919. case ERROR_FILE_NOT_FOUND :
  920. case ERROR_BAD_PATHNAME :
  921. case ERROR_INVALID_NAME :
  922. case ERROR_PATH_NOT_FOUND :
  923. case ERROR_NETWORK_ACCESS_DENIED :
  924. case ERROR_DISK_CORRUPT :
  925. case ERROR_FILE_CORRUPT :
  926. case ERROR_DISK_FULL :
  927. // An error from which we cannot recover...
  928. return FALSE;
  929. case ERROR_ACCESS_DENIED :
  930. // It's possible for us to hit this if there's a
  931. // directory with the name we're trying; in that
  932. // case, we can usefully continue.
  933. // CreateFile() uses BaseSetLastNTError() to set
  934. // LastStatusValue to the actual NT error in the
  935. // TEB; we just need to check it, and only abort
  936. // if it's not a directory.
  937. // This was bug #397477.
  938. if (NtCurrentTeb()->LastStatusValue != STATUS_FILE_IS_A_DIRECTORY)
  939. {
  940. // Insuffient permission
  941. return FALSE;
  942. }
  943. }
  944. }
  945. }
  946. }
  947. return bCanWriteHere;
  948. }
  949. void CorrectPathChangesAllUser::InitializePathFixes()
  950. {
  951. CorrectPathChangesUser::InitializePathFixes();
  952. // The choice to put these values into All Users instead of <UserName>
  953. // was not taken lightly. The problem is: some apps create ...\All Users\Start Menu\folder
  954. // then attempt to place files into c:\windows\Start Menu\folder or username\Start Menu\folder.
  955. // Yes the apps are WRONG, but we want them to work. By directing all of these paths
  956. // to All Users we *know* where the files will be placed and can make sure they all are the same place.
  957. // Another note, IE 5.0 does *not* look in All Users\Favorites for links,
  958. // so we force all favorites to end up in the user favorites. Sheesh.
  959. // We add these changes twice, the first to convert any long path names to the All User dir,
  960. // the second to convert any short path names to All User.
  961. if (CanWriteHere(CSIDL_COMMON_STARTMENU))
  962. {
  963. AddPathChangeW( L"%UserStartMenu%", L"%AllStartMenu%" );
  964. }
  965. else
  966. {
  967. DPF("CorrectPathChangesAllUser", eDbgLevelInfo, "*NOT* forcing %UserStartMenu% to %AllStartMenu% -- insufficient permission");
  968. }
  969. /*
  970. // 05/11/2001 robkenny:
  971. // We are nolonger modifying the Desktop directory
  972. if (CanWriteHere(CSIDL_COMMON_DESKTOPDIRECTORY))
  973. {
  974. AddPathChangeW( L"%UserDesktop%", L"%AllDesktop%" );
  975. }
  976. else
  977. {
  978. DPF("CorrectPathChangesAllUser", eDbgLevelInfo, "*NOT* forcing %UserDesktop% to %AllDesktop% -- insufficient permission");
  979. }
  980. */
  981. /*
  982. // IE 5.0/5.5 doesn't use All Users
  983. if (CanWriteHere(CSIDL_COMMON_FAVORITES))
  984. {
  985. AddPathChangeW( L"%UserFavorites%", L"%AllFavorites%" ); // IE 5.0 doesn't use All Users
  986. }
  987. else
  988. {
  989. DPF("CorrectPathChangesAllUser", eDbgLevelInfo, "*NOT* forcing %UserFavorites% to %AllFavorites% -- insufficient permission");
  990. }
  991. */
  992. }
  993. }; // end of namespace ShimLib