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.

395 lines
10 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. DeleteSpecifiedFiles.cpp
  5. Abstract:
  6. This SHIM renames the MFC42loc.dll that is installed by the APP in the
  7. %windir%\system32 directory and sets up the temporary file for destruction.
  8. Notes:
  9. This app. places the MFC42loc.dll into the %windir%\system32 directory even on a English language
  10. locale thereby forcing some APPS to use it and thereby some 'Dialogs' and 'Message boxes' are messed up.
  11. History:
  12. 08/21/2000 prashkud Created
  13. --*/
  14. #include "precomp.h"
  15. #include "CharVector.h"
  16. #include <new> // for inplace new
  17. IMPLEMENT_SHIM_BEGIN(DeleteSpecifiedFiles)
  18. #include "ShimHookMacro.h"
  19. APIHOOK_ENUM_BEGIN
  20. APIHOOK_ENUM_END
  21. class FILENAME_PATH
  22. {
  23. public:
  24. CString FileName;
  25. CString FileVersion;
  26. BOOL bPresent;
  27. FILENAME_PATH()
  28. {
  29. bPresent = FALSE;
  30. }
  31. };
  32. class FileNamePathList : public VectorT<FILENAME_PATH>
  33. {
  34. };
  35. VectorT<FILENAME_PATH> *g_StFileNamePath = NULL;
  36. /*++
  37. This function checks the 'FileVersion' of the first variable 'szFileName'
  38. matches that of the 2nd parameter 'szFileVersion' and if it matches returns
  39. TRUE else returns FALSE.
  40. --*/
  41. BOOL
  42. FileCheckVersion(
  43. const CString & csFileName,
  44. const CString & csFileVersion
  45. )
  46. {
  47. DWORD dwDummy;
  48. PVOID pVersionInfo;
  49. UINT cbTranslate, i;
  50. WCHAR SubBlock[100];
  51. LPWSTR lpBuffer;
  52. DWORD dwBytes;
  53. WORD wLangID;
  54. struct LANGANDCODEPAGE
  55. {
  56. WORD wLanguage;
  57. WORD wCodePage;
  58. } *lpTranslate;
  59. DWORD dwVersionInfoSize;
  60. //
  61. // There is no File Version specified. So, no point in going ahead. Return TRUE.
  62. //
  63. if (csFileVersion.IsEmpty())
  64. {
  65. return TRUE;
  66. }
  67. dwVersionInfoSize = GetFileVersionInfoSizeW((LPWSTR)csFileName.Get(), &dwDummy);
  68. if (dwVersionInfoSize > 0)
  69. {
  70. pVersionInfo = malloc(dwVersionInfoSize);
  71. if (pVersionInfo)
  72. {
  73. if (0 != GetFileVersionInfoW(
  74. (LPWSTR)csFileName.Get(),
  75. 0,
  76. dwVersionInfoSize,
  77. pVersionInfo
  78. ))
  79. {
  80. // Now, pVersionInfo contains the required version block.
  81. // Use it with VerQueryValue to get the
  82. // the language info that is needed
  83. // Get System locale before and note down the language for the system
  84. // Read the list of languages and code pages.
  85. if (VerQueryValueW(
  86. pVersionInfo,
  87. L"\\VarFileInfo\\Translation",
  88. (LPVOID*)&lpTranslate,
  89. &cbTranslate
  90. ))
  91. {
  92. //
  93. // Read the language string each language and code page.
  94. //
  95. for (i=0; i < (cbTranslate/sizeof(struct LANGANDCODEPAGE)); i++)
  96. {
  97. wsprintf(
  98. SubBlock,
  99. L"\\StringFileInfo\\%04x%04x\\FileVersion",
  100. lpTranslate[i].wLanguage,
  101. lpTranslate[i].wCodePage
  102. );
  103. //
  104. // Retrieve FileVersion for language and code page "i" from the pVersionInfo.
  105. //
  106. if (VerQueryValueW(
  107. pVersionInfo,
  108. SubBlock,
  109. (LPVOID*)&lpBuffer,
  110. (UINT*)&dwBytes))
  111. {
  112. if (!(csFileVersion.Compare(lpBuffer)))
  113. {
  114. DPFN(
  115. eDbgLevelInfo,
  116. "Version string for current file is %S,%S",
  117. lpBuffer, csFileVersion.Get());
  118. free(pVersionInfo);
  119. return TRUE;
  120. }
  121. }
  122. } // for loop
  123. }
  124. }
  125. free(pVersionInfo);
  126. }
  127. }
  128. return FALSE;
  129. }
  130. /*++
  131. This function as the name suggests deletes the file or if it is in use moves
  132. it to the 'Temp' folder.
  133. --*/
  134. VOID
  135. DeleteFiles()
  136. {
  137. for (int i = 0; i < g_StFileNamePath->Size(); ++i)
  138. {
  139. const FILENAME_PATH & fnp = g_StFileNamePath->Get(i);
  140. DPFN( eDbgLevelSpew, "DeleteFiles file(%S) version(%S)", fnp.FileName.Get(), fnp.FileVersion.Get());
  141. if (!fnp.bPresent)
  142. {
  143. //
  144. // CheckFileVersion
  145. //
  146. if (FileCheckVersion(fnp.FileName, fnp.FileVersion))
  147. {
  148. LOGN(eDbgLevelError,"Deleting file %S.", fnp.FileName.Get());
  149. // Delete the file..
  150. if (!DeleteFileW(fnp.FileName))
  151. {
  152. CString csTempDir;
  153. CString csTempPath;
  154. LOGN(eDbgLevelError,"Moving file %S.", fnp.FileName.Get());
  155. //
  156. // Could not delete.Retry by renaming it and then deleting it.
  157. // New file is %windir%\Temp
  158. //
  159. csTempDir.GetTempPathW();
  160. csTempPath.GetTempFileNameW(csTempDir, L"XXXX", 0);
  161. if (MoveFileExW( fnp.FileName, csTempPath, MOVEFILE_REPLACE_EXISTING ))
  162. {
  163. SetFileAttributesW(
  164. csTempPath,
  165. FILE_ATTRIBUTE_ARCHIVE |
  166. FILE_ATTRIBUTE_TEMPORARY);
  167. DeleteFileW(csTempPath);
  168. }
  169. }
  170. }
  171. }
  172. }
  173. }
  174. /*++
  175. This function checks for the existence of the file specified on the commandline .
  176. This is called during the DLL_PROCESS_ATTACH notification
  177. --*/
  178. BOOL
  179. CheckFileExistence()
  180. {
  181. // If any among the list is not present, mark it as 'Not Present' and only those marked as
  182. // 'Not present' will be deleted.
  183. BOOL bFileDoesNotExist = FALSE;
  184. WIN32_FIND_DATAW StWin32FileData;
  185. for (int i = 0; i < g_StFileNamePath->Size(); ++i)
  186. {
  187. FILENAME_PATH & fnp = g_StFileNamePath->Get(i);
  188. DPFN( eDbgLevelSpew, "CheckFileExistence file(%S) version(%S)", fnp.FileName.Get(), fnp.FileVersion.Get());
  189. HANDLE hTempFile = FindFirstFileW(fnp.FileName, &StWin32FileData);
  190. if (INVALID_HANDLE_VALUE != hTempFile)
  191. {
  192. FindClose(hTempFile);
  193. //
  194. // File is present. Check its version if given.
  195. //
  196. if (FileCheckVersion(fnp.FileName, fnp.FileVersion))
  197. {
  198. fnp.bPresent = TRUE;
  199. }
  200. else
  201. {
  202. bFileDoesNotExist = TRUE;
  203. fnp.bPresent = FALSE;
  204. }
  205. }
  206. else
  207. {
  208. bFileDoesNotExist = TRUE;
  209. fnp.bPresent = FALSE;
  210. }
  211. }
  212. return bFileDoesNotExist;
  213. }
  214. /*++
  215. The command line can contain FileName:Path:VersionString,FileName1:Path1:VersionString1 etc....
  216. Eg. Ole2.dll:system:604.5768.94567,MFC42.dll:0:,Foo.dll:d:\program Files\DisneyInteractive etc..
  217. 'system' implies the %windir%. '0' implies that the filename itself is a fully qualified path
  218. OR one has the option of giving the path seperately OR it can be left blank.
  219. --*/
  220. BOOL
  221. ParseCommandLine(LPCSTR lpszCommandLine)
  222. {
  223. CSTRING_TRY
  224. {
  225. g_StFileNamePath = new VectorT<FILENAME_PATH>;
  226. if (!g_StFileNamePath)
  227. {
  228. return FALSE;
  229. }
  230. CStringToken csCommandLine(COMMAND_LINE, ":,;");
  231. CString csTok;
  232. DWORD dwState = 0;
  233. while (csCommandLine.GetToken(csTok))
  234. {
  235. FILENAME_PATH fnp;
  236. switch(dwState)
  237. {
  238. case 0:
  239. dwState++;
  240. fnp.FileName = csTok;
  241. break;
  242. case 1:
  243. if (csTok.CompareNoCase(L"system") == 0)
  244. {
  245. fnp.FileName.GetSystemDirectoryW();
  246. fnp.FileName.AppendPath(fnp.FileName);
  247. }
  248. else
  249. {
  250. fnp.FileName = csTok;
  251. }
  252. dwState++;
  253. break;
  254. case 2:
  255. dwState = 0;
  256. fnp.FileVersion = csTok;
  257. DPFN( eDbgLevelInfo, "ParseCommandLine file(%S) version(%S)", fnp.FileName.Get(), fnp.FileVersion.Get());
  258. // Found all three states, add it to the list
  259. if (!g_StFileNamePath->AppendConstruct(fnp))
  260. {
  261. // Append failed, stop parsing
  262. return FALSE;
  263. }
  264. break;
  265. }
  266. }
  267. }
  268. CSTRING_CATCH
  269. {
  270. return FALSE;
  271. }
  272. return TRUE;
  273. }
  274. /*++
  275. Register hooked functions
  276. --*/
  277. BOOL
  278. NOTIFY_FUNCTION(
  279. DWORD fdwReason
  280. )
  281. {
  282. static BOOL fDidNotExist = FALSE;
  283. switch (fdwReason)
  284. {
  285. case SHIM_STATIC_DLLS_INITIALIZED:
  286. {
  287. if (ParseCommandLine(COMMAND_LINE))
  288. {
  289. //
  290. // Ok...CommandLine is in place...Now Check for those Files...
  291. // If any one file exists, then we are not responsible. We bail out..
  292. //
  293. fDidNotExist = CheckFileExistence();
  294. }
  295. break;
  296. }
  297. case DLL_PROCESS_DETACH:
  298. {
  299. //
  300. // Check for the specified file at the specified location. If it existed prior to
  301. // to this in PROCESS_DLL_ATTACH, it is not installed us...Just bail out !
  302. // If the file did not exist before, it is our problem and we should remove them.
  303. //
  304. if (fDidNotExist)
  305. {
  306. DeleteFiles();
  307. }
  308. break;
  309. }
  310. }
  311. return TRUE;
  312. }
  313. HOOK_BEGIN
  314. CALL_NOTIFY_FUNCTION
  315. HOOK_END
  316. IMPLEMENT_SHIM_END