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.

548 lines
17 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation
  6. //
  7. // File: migrate.cpp
  8. // xiaoyuw @ 2001/09
  9. //
  10. //--------------------------------------------------------------------------
  11. #include <stdio.h>
  12. #include <windows.h>
  13. #include <setupapi.h>
  14. #include <shlwapi.h>
  15. // migration DLL version information
  16. typedef struct {
  17. CHAR CompanyName[256];
  18. CHAR SupportNumber[256];
  19. CHAR SupportUrl[256];
  20. CHAR InstructionsToUser[1024];
  21. } VENDORINFO, *PVENDORINFO;
  22. typedef struct {
  23. SIZE_T Size;
  24. PCSTR StaticProductIdentifier;
  25. UINT DllVersion;
  26. PINT CodePageArray;
  27. UINT SourceOs;
  28. UINT TargetOs;
  29. PCSTR * NeededFileList;
  30. PVENDORINFO VendorInfo;
  31. } MIGRATIONINFOA, *PMIGRATIONINFOA;
  32. typedef enum {
  33. OS_WINDOWS9X = 0,
  34. OS_WINDOWSNT4X = 1,
  35. OS_WINDOWS2000 = 2,
  36. OS_WINDOWSWHISTLER = 3
  37. } OS_TYPES, *POS_TYPES;
  38. PMIGRATIONINFOA g_MigrationInfo;
  39. const char g_szProductId[] = "Microsoft MSI Migration DLL v2.0";
  40. VENDORINFO g_VendorInfo = { "Microsoft", "", "", "" };
  41. const static CHAR pszAsmCache[] = "%windir%\\MsiAsmCache";
  42. const static WCHAR pwszAsmCache[]= L"%windir%\\MsiAsmCache\\*.*";
  43. typedef HRESULT (__stdcall *LPDLLGETVERSION)(DLLVERSIONINFO *);
  44. BOOL IsThereAssembliesForMigrate()
  45. {
  46. TCHAR buf[MAX_PATH];
  47. DWORD cch;
  48. BOOL fAssemblyExist = FALSE;
  49. cch = ExpandEnvironmentStrings(pszAsmCache, buf, MAX_PATH);
  50. if (( cch == 0 ) || (cch > MAX_PATH))
  51. {
  52. #if DBG
  53. MessageBoxA(NULL, "ExpandEnvironmentStrings return 0 or > MAX_PATH", "mig_Error", MB_OK);
  54. #endif
  55. goto Exit;
  56. }
  57. DWORD attrib = GetFileAttributes(buf);
  58. if ((attrib == INVALID_FILE_ATTRIBUTES) || (!(attrib & FILE_ATTRIBUTE_DIRECTORY)))
  59. {
  60. #if DBG
  61. MessageBoxA(NULL, "no MsiAsmCache directory ", "mig_info", MB_OK);
  62. #endif
  63. goto Exit;
  64. }
  65. fAssemblyExist = TRUE;
  66. Exit:
  67. return fAssemblyExist;
  68. }
  69. void DbgPrintMessageBox(PCSTR pszFunc)
  70. {
  71. #if DBG
  72. MessageBox(NULL, pszFunc, "migrate", MB_OK);
  73. #endif
  74. }
  75. void DbgPrintMessageBox(PCSTR formatStr, PWSTR para)
  76. {
  77. #if DBG
  78. CHAR str[3 * MAX_PATH];
  79. sprintf(str, formatStr, para);
  80. MessageBox(NULL, str, "migrate", MB_OK);
  81. #endif
  82. }
  83. void DbgPrintMessageBox(PCSTR formatStr, PWSTR para, DWORD dw)
  84. {
  85. #if DBG
  86. CHAR str[3 * MAX_PATH];
  87. sprintf(str, formatStr, para, dw);
  88. MessageBox(NULL, str, "migrate", MB_OK);
  89. #endif
  90. }
  91. #include "sxsapi.h"
  92. BOOL IsDotOrDotDot(WCHAR cFileName[])
  93. {
  94. if ((cFileName[0] == L'.') && (cFileName[1] == L'\0'))
  95. return TRUE;
  96. if ((cFileName[0] == L'.') && (cFileName[1] == L'.') && (cFileName[2] == L'\0'))
  97. return TRUE;
  98. return FALSE;
  99. }
  100. const char szRunOnceMsiAsmCacheName[] = "Cleanup Msi-Installed-Fusion-Win32-Assembly Migration";
  101. const char szRunOnceMsiAsmCacheRegKey[]= "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
  102. const char szRunOnceValueCommandLine[]="rundll32.exe sxs.dll,SxspRunDllDeleteDirectory %S";
  103. LONG MigrateMSIInstalledWin32Assembly()
  104. {
  105. LONG lResult = ERROR_SUCCESS;
  106. HMODULE hSxs = NULL;
  107. PSXS_INSTALL_W pfnSxsInstallW = NULL;
  108. PSXS_BEGIN_ASSEMBLY_INSTALL pfnSxsBeginAssemblyInstall = NULL;
  109. PSXS_END_ASSEMBLY_INSTALL pfnSxsEndAssemblyInstall = NULL;
  110. BOOL fSuccess = FALSE;
  111. PVOID SxsContext = NULL;
  112. WCHAR AsmDirInAsmCache[MAX_PATH];
  113. WCHAR Buf[MAX_PATH];
  114. DWORD cchBuf;
  115. HANDLE hFind = INVALID_HANDLE_VALUE;
  116. WIN32_FIND_DATAW finddata;
  117. SXS_INSTALLW InstallData = {sizeof(InstallData)};
  118. SXS_INSTALL_REFERENCEW InstallReference = {sizeof(InstallReference)};
  119. cchBuf= ExpandEnvironmentStringsW(pwszAsmCache, Buf, MAX_PATH); // including trailing NULL
  120. if ((cchBuf == 0 ) || (cchBuf > MAX_PATH))
  121. {
  122. DbgPrintMessageBox("::Expand windir\\MsiAsmCache\\*.* return 0 or > MAX_PATH::");
  123. lResult = GetLastError();
  124. goto Exit;
  125. }
  126. #ifdef MSI_MIG_TEST
  127. hSxs = ::LoadLibraryA("..\\..\\..\\..\\..\\dll\\whistler\\obj\\i386\\sxs.dll");
  128. #else
  129. hSxs = ::LoadLibraryA("sxs.dll");
  130. #endif
  131. if ((!hSxs) || (hSxs == INVALID_HANDLE_VALUE))
  132. {
  133. DbgPrintMessageBox("::Load Sxs.dll failed::");
  134. lResult = GetLastError();
  135. goto Exit;
  136. }
  137. pfnSxsInstallW = (PSXS_INSTALL_W)GetProcAddress(hSxs, SXS_INSTALL_W);
  138. pfnSxsBeginAssemblyInstall = (PSXS_BEGIN_ASSEMBLY_INSTALL)GetProcAddress(hSxs, SXS_BEGIN_ASSEMBLY_INSTALL);
  139. pfnSxsEndAssemblyInstall = (PSXS_END_ASSEMBLY_INSTALL)GetProcAddress(hSxs, SXS_END_ASSEMBLY_INSTALL);
  140. if ((pfnSxsInstallW == NULL) || (pfnSxsBeginAssemblyInstall == NULL) || (pfnSxsEndAssemblyInstall == NULL))
  141. {
  142. DbgPrintMessageBox("::Find SxsInstall APIs failed::");
  143. lResult = GetLastError();
  144. goto Exit;
  145. }
  146. //
  147. // !!!!! below is the code copied From base\ntsetup\syssetup\copy.c
  148. //
  149. //
  150. // we do not use INSTALL_RECURSIVELY because the name of directory and structures always like
  151. // c:\WINNT\winsxs\x86_blahblah\x86_blahblah.man
  152. //
  153. if (!pfnSxsBeginAssemblyInstall(
  154. SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_NOT_TRANSACTIONAL
  155. | SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_NO_VERIFY
  156. | SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_REPLACE_EXISTING |
  157. SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_FROM_DIRECTORY |
  158. SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE, // I have to add this flag for old sxs!SxsInstallW parameter check
  159. NULL,
  160. NULL, // callback context
  161. NULL, // impersonation callback
  162. NULL, // impersonation context
  163. &SxsContext
  164. ))
  165. {
  166. DbgPrintMessageBox("::pfnSxsBeginAssemblyInstall failed::");
  167. lResult = GetLastError();
  168. goto Exit;
  169. }
  170. hFind = FindFirstFileW(Buf, &finddata);
  171. if (hFind == INVALID_HANDLE_VALUE)
  172. {
  173. DbgPrintMessageBox("::FindFirstFileW for MsiAsmCache failed::");
  174. lResult = GetLastError();
  175. goto Exit;
  176. }
  177. while (1) {
  178. if ((wcscmp(finddata.cFileName, L"..") == 0) || (wcscmp(finddata.cFileName, L".") == 0))
  179. goto GetNext;
  180. if (!(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  181. {
  182. // if it is not a directory, ignore it
  183. goto GetNext;
  184. }
  185. // this must be a subdir of an asm, which is in the format of
  186. // %windir\MsiAsmCache\x86_ms-sxstest-simple_75e377300ab7b886_1.0.10.0_en_61E9D7DC,
  187. // otherwise, there is an error;
  188. // the following calculation is used to decide the directory name. it must be a very long filename but
  189. // MAX_PATH should be fine; and since Buf contains "*.*", it should cover the trailing NULL and extra back-slash.
  190. if ((wcslen(Buf) + wcslen(finddata.cFileName)) > (sizeof(AsmDirInAsmCache) / sizeof(WCHAR)))
  191. {
  192. DbgPrintMessageBox("::filename %S under MsiAsmCache is too long, will be ignored::", finddata.cFileName);
  193. goto GetNext;
  194. }
  195. wcscpy(AsmDirInAsmCache, Buf);
  196. AsmDirInAsmCache[wcslen(Buf) - wcslen(L"*.*")] = L'\0'; // contain a trailing NULL
  197. wcscat(AsmDirInAsmCache, finddata.cFileName);
  198. //
  199. // Set up the reference data to indicate that all of these are OS-installed
  200. // assemblies.
  201. //
  202. ZeroMemory(&InstallReference, sizeof(InstallReference));
  203. InstallReference.cbSize = sizeof(InstallReference);
  204. InstallReference.dwFlags = 0;
  205. #ifdef MSI_MIG_TEST
  206. InstallReference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_SXS_INSTALL_ASSEMBLY;
  207. #else
  208. InstallReference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL;
  209. #endif
  210. //
  211. // Set up the structure to call off to the installer
  212. //
  213. memset(&InstallData, 0, sizeof(InstallData));
  214. InstallData.cbSize = sizeof(InstallData);
  215. InstallData.dwFlags =
  216. SXS_INSTALL_FLAG_REFERENCE_VALID |
  217. SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID |
  218. SXS_INSTALL_FLAG_INSTALL_COOKIE_VALID |
  219. SXS_INSTALL_FLAG_CODEBASE_URL_VALID |
  220. SXS_INSTALL_FLAG_FROM_DIRECTORY |
  221. SXS_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE
  222. ;
  223. InstallData.lpReference = &InstallReference;
  224. InstallData.lpRefreshPrompt = L"migrated from downlevel, no source";
  225. InstallData.pvInstallCookie = SxsContext;
  226. InstallData.lpCodebaseURL = AsmDirInAsmCache;
  227. InstallData.lpManifestPath = AsmDirInAsmCache;
  228. fSuccess = pfnSxsInstallW(&InstallData);
  229. if (fSuccess == FALSE)
  230. {
  231. DbgPrintMessageBox("::pfnSxsInstallW failed for %S, ignore the error and just continue::", AsmDirInAsmCache);
  232. }else
  233. {
  234. DbgPrintMessageBox("::pfnSxsInstallW succeed for %S, Great!!!::", AsmDirInAsmCache);
  235. }
  236. GetNext:
  237. if ( FALSE == FindNextFileW(hFind, &finddata))
  238. {
  239. if ( GetLastError() == ERROR_NO_MORE_FILES)
  240. DbgPrintMessageBox("::FindNextFileW ends well ::");
  241. else
  242. DbgPrintMessageBox("::FindNextFileW failed::");
  243. break;
  244. }else
  245. {
  246. DbgPrintMessageBox("::FindNextFileW find next file::");
  247. }
  248. }
  249. lResult = ERROR_SUCCESS;
  250. {
  251. //
  252. // set RunOnce Key to delete MsiAsmCache Directory
  253. //
  254. HKEY hk = NULL;
  255. if ( ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRunOnceMsiAsmCacheRegKey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hk, NULL))
  256. {
  257. // we do not care it success or fail, we could live with it
  258. CHAR buf[MAX_PATH * 2];
  259. sprintf(buf, szRunOnceValueCommandLine, Buf);
  260. if ( ERROR_SUCCESS != RegSetValueEx(hk, szRunOnceMsiAsmCacheName, 0, REG_SZ, (CONST BYTE *)buf, strlen(buf) + 1))
  261. {
  262. DbgPrintMessageBox("::SetRunOnceKey failed::");
  263. }
  264. }
  265. RegCloseKey(hk);
  266. }
  267. Exit:
  268. if ( SxsContext != NULL)
  269. {
  270. pfnSxsEndAssemblyInstall(
  271. SxsContext,
  272. fSuccess ? SXS_END_ASSEMBLY_INSTALL_FLAG_COMMIT : SXS_END_ASSEMBLY_INSTALL_FLAG_ABORT,
  273. NULL);
  274. }
  275. if ( hSxs != NULL)
  276. FreeLibrary(hSxs);
  277. if (hFind != INVALID_HANDLE_VALUE)
  278. CloseHandle(hFind);
  279. // return the result from the actual migration call
  280. return lResult;
  281. }
  282. ///////////////////////////////////////////////////////////////////////
  283. //
  284. // API of WIN-NT MIGRATION Dll
  285. //
  286. ///////////////////////////////////////////////////////////////////////
  287. LONG CALLBACK QueryMigrationInfoA(PMIGRATIONINFOA * VersionInfo)
  288. {
  289. DbgPrintMessageBox("in QueryMigrationInfo");
  290. if (IsThereAssembliesForMigrate() == FALSE)
  291. {
  292. return ERROR_NOT_INSTALLED; // no further migration
  293. }
  294. // only work for Win98 and win2k upgrade to winxp !!!
  295. if (VersionInfo != NULL)
  296. {
  297. if (g_MigrationInfo == NULL)
  298. {
  299. g_MigrationInfo = (PMIGRATIONINFOA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MIGRATIONINFOA));
  300. if (g_MigrationInfo == NULL)
  301. return ERROR_NOT_ENOUGH_MEMORY;
  302. g_MigrationInfo->Size = sizeof(MIGRATIONINFOA);
  303. g_MigrationInfo->StaticProductIdentifier = g_szProductId;
  304. g_MigrationInfo->DllVersion = 200;
  305. g_MigrationInfo->CodePageArray = NULL;
  306. g_MigrationInfo->SourceOs = OS_WINDOWS2000;
  307. g_MigrationInfo->TargetOs = OS_WINDOWSWHISTLER;
  308. g_MigrationInfo->NeededFileList = NULL;
  309. g_MigrationInfo->VendorInfo = &g_VendorInfo;
  310. *VersionInfo = g_MigrationInfo;
  311. }
  312. }
  313. return ERROR_SUCCESS;
  314. }
  315. LONG InitializeOnSource()
  316. {
  317. return ERROR_SUCCESS;
  318. }
  319. ///////////////////////////////////////////////////////////////////////
  320. LONG __stdcall InitializeSrcA(LPCSTR WorkingDirectory, LPCSTR SourceDirectories, LPCSTR MediaDirectory, PVOID Reserved)
  321. {
  322. DbgPrintMessageBox("in InitializeSrcA");
  323. return InitializeOnSource();
  324. }
  325. /////////////////////////////////////////////////////////////////////////////
  326. LONG CALLBACK GatherUserSettingsA(LPCSTR AnswerFile, HKEY UserRegKey, LPCSTR UserName, LPVOID Reserved)
  327. {
  328. DbgPrintMessageBox("in GatherUserSettingsA");
  329. return ERROR_SUCCESS;
  330. }
  331. LONG CALLBACK GatherSystemSettingsA(LPCSTR AnswerFile, LPVOID Reserved)
  332. {
  333. DbgPrintMessageBox("in GatherSystemSettingsA");
  334. return ERROR_SUCCESS;
  335. }
  336. ///////////////////////////////////////////////////////////////////////
  337. // Initialization routine on WinNT. Just stores of the migration
  338. // working directory.
  339. LONG CALLBACK InitializeDstA(LPCSTR WorkingDirectory, LPCSTR SourceDirectories, LPVOID Reserved)
  340. {
  341. DbgPrintMessageBox("in InitializeDstA");
  342. return ERROR_SUCCESS;
  343. }
  344. ///////////////////////////////////////////////////////////////////////
  345. LONG CALLBACK ApplyUserSettingsA(
  346. HINF AnswerFileHandle,
  347. HKEY UserRegKey,
  348. LPCSTR UserName,
  349. LPCSTR UserDomain,
  350. LPCSTR FixedUserName,
  351. LPVOID Reserved)
  352. {
  353. DbgPrintMessageBox("in ApplyUserSettingsA");
  354. return ERROR_SUCCESS;
  355. }
  356. ///////////////////////////////////////////////////////////////////////
  357. // Called once on NT
  358. LONG CALLBACK ApplySystemSettingsA(HINF UnattendInfHandle, LPVOID Reserved)
  359. {
  360. DbgPrintMessageBox("in ApplySystemSettingsA");
  361. if (ERROR_SUCCESS != MigrateMSIInstalledWin32Assembly())
  362. {
  363. // just display on chk version, no bother to return to setup
  364. DbgPrintMessageBox("the return value of MigrateMSIInstalledWin32Assembly isnot totally successful.\n");
  365. }
  366. return ERROR_SUCCESS;
  367. }
  368. BOOL
  369. WINAPI
  370. DllMain(
  371. HINSTANCE hinstDLL,
  372. DWORD fdwReason,
  373. LPVOID lpvReserved
  374. )
  375. {
  376. switch (fdwReason)
  377. {
  378. case DLL_PROCESS_ATTACH:
  379. g_MigrationInfo = NULL;
  380. break;
  381. case DLL_PROCESS_DETACH:
  382. if (g_MigrationInfo != NULL)
  383. {
  384. if (lpvReserved != NULL)
  385. {
  386. HeapFree(GetProcessHeap(), 0, g_MigrationInfo);
  387. }
  388. g_MigrationInfo = NULL;
  389. }
  390. break;
  391. }
  392. return TRUE;
  393. }
  394. ///////////////////////////////////////////////////////////////////////
  395. //
  396. // API of WIN9X MIGRATION Dll
  397. //
  398. ///////////////////////////////////////////////////////////////////////
  399. ///////////////////////////////////////////////////////////////////////
  400. // called by setup to extract migration DLL version and support
  401. // information.
  402. LONG CALLBACK QueryVersion(LPCSTR *ProductID, LPUINT DllVersion, LPINT *CodePageArray, LPCSTR *ExeNamesBuf, PVENDORINFO *VendorInfo)
  403. {
  404. DbgPrintMessageBox("QueryVersion");
  405. if (IsThereAssembliesForMigrate() == FALSE)
  406. {
  407. return ERROR_NOT_INSTALLED; // no further migration
  408. }
  409. // product ID information
  410. *ProductID = g_szProductId;
  411. *DllVersion = 200;
  412. // DLL is language independent.
  413. *CodePageArray = NULL;
  414. // no EXE search is required
  415. *ExeNamesBuf = NULL;
  416. // vendor information
  417. *VendorInfo = &g_VendorInfo;
  418. return ERROR_SUCCESS;
  419. }
  420. ///////////////////////////////////////////////////////////////////////
  421. LONG __stdcall Initialize9x(LPCSTR WorkingDirectory, LPCSTR SourceDirectories, LPCSTR MediaDirectory)
  422. {
  423. DbgPrintMessageBox("Initialize9x");
  424. return InitializeOnSource();
  425. }
  426. /////////////////////////////////////////////////////////////////////////////
  427. LONG CALLBACK MigrateUser9x(HWND ParentWnd, LPCSTR AnswerFile, HKEY UserRegKey, LPCSTR UserName, LPVOID Reserved)
  428. {
  429. DbgPrintMessageBox("MigrateUser9x");
  430. return ERROR_SUCCESS;
  431. }
  432. LONG CALLBACK MigrateSystem9x(HWND ParentWnd, LPCSTR AnswerFile, LPVOID Reserved)
  433. {
  434. DbgPrintMessageBox("MigrateSystem9x");
  435. return ERROR_SUCCESS;
  436. }
  437. ///////////////////////////////////////////////////////////////////////
  438. LONG CALLBACK InitializeNT(LPCWSTR WorkingDirectory, LPCWSTR SourceDirectories, LPVOID Reserved)
  439. {
  440. DbgPrintMessageBox("InitializeNT");
  441. return ERROR_SUCCESS;
  442. }
  443. ///////////////////////////////////////////////////////////////////////
  444. LONG CALLBACK MigrateUserNT(HINF AnswerFileHandle, HKEY UserRegKey, LPCWSTR UserName, LPVOID Reserved)
  445. {
  446. DbgPrintMessageBox("MigrateUserNT");
  447. return ERROR_SUCCESS;
  448. }
  449. typedef HRESULT (_stdcall * PFN_MigrateFusionWin32AssemblyToXP)(PCWSTR pszInstallerDir);
  450. ///////////////////////////////////////////////////////////////////////
  451. LONG CALLBACK MigrateSystemNT(HINF UnattendInfHandle, LPVOID Reserved)
  452. {
  453. DbgPrintMessageBox("MigrateSystemNT");
  454. if (ERROR_SUCCESS != MigrateMSIInstalledWin32Assembly())
  455. {
  456. // just display on chk version, no bother to return to setup
  457. DbgPrintMessageBox("the return value of MigrateMSIInstalledWin32Assembly isnot totally successful.\n");
  458. }
  459. return ERROR_SUCCESS;
  460. }