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

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation
//
// File: migrate.cpp
// xiaoyuw @ 2001/09
//
//--------------------------------------------------------------------------
#include <stdio.h>
#include <windows.h>
#include <setupapi.h>
#include <shlwapi.h>
// migration DLL version information
typedef struct {
CHAR CompanyName[256];
CHAR SupportNumber[256];
CHAR SupportUrl[256];
CHAR InstructionsToUser[1024];
} VENDORINFO, *PVENDORINFO;
typedef struct {
SIZE_T Size;
PCSTR StaticProductIdentifier;
UINT DllVersion;
PINT CodePageArray;
UINT SourceOs;
UINT TargetOs;
PCSTR * NeededFileList;
PVENDORINFO VendorInfo;
} MIGRATIONINFOA, *PMIGRATIONINFOA;
typedef enum {
OS_WINDOWS9X = 0,
OS_WINDOWSNT4X = 1,
OS_WINDOWS2000 = 2,
OS_WINDOWSWHISTLER = 3
} OS_TYPES, *POS_TYPES;
PMIGRATIONINFOA g_MigrationInfo;
const char g_szProductId[] = "Microsoft MSI Migration DLL v2.0";
VENDORINFO g_VendorInfo = { "Microsoft", "", "", "" };
const static CHAR pszAsmCache[] = "%windir%\\MsiAsmCache";
const static WCHAR pwszAsmCache[]= L"%windir%\\MsiAsmCache\\*.*";
typedef HRESULT (__stdcall *LPDLLGETVERSION)(DLLVERSIONINFO *);
BOOL IsThereAssembliesForMigrate()
{
TCHAR buf[MAX_PATH];
DWORD cch;
BOOL fAssemblyExist = FALSE;
cch = ExpandEnvironmentStrings(pszAsmCache, buf, MAX_PATH);
if (( cch == 0 ) || (cch > MAX_PATH))
{
#if DBG
MessageBoxA(NULL, "ExpandEnvironmentStrings return 0 or > MAX_PATH", "mig_Error", MB_OK);
#endif
goto Exit;
}
DWORD attrib = GetFileAttributes(buf);
if ((attrib == INVALID_FILE_ATTRIBUTES) || (!(attrib & FILE_ATTRIBUTE_DIRECTORY)))
{
#if DBG
MessageBoxA(NULL, "no MsiAsmCache directory ", "mig_info", MB_OK);
#endif
goto Exit;
}
fAssemblyExist = TRUE;
Exit:
return fAssemblyExist;
}
void DbgPrintMessageBox(PCSTR pszFunc)
{
#if DBG
MessageBox(NULL, pszFunc, "migrate", MB_OK);
#endif
}
void DbgPrintMessageBox(PCSTR formatStr, PWSTR para)
{
#if DBG
CHAR str[3 * MAX_PATH];
sprintf(str, formatStr, para);
MessageBox(NULL, str, "migrate", MB_OK);
#endif
}
void DbgPrintMessageBox(PCSTR formatStr, PWSTR para, DWORD dw)
{
#if DBG
CHAR str[3 * MAX_PATH];
sprintf(str, formatStr, para, dw);
MessageBox(NULL, str, "migrate", MB_OK);
#endif
}
#include "sxsapi.h"
BOOL IsDotOrDotDot(WCHAR cFileName[])
{
if ((cFileName[0] == L'.') && (cFileName[1] == L'\0'))
return TRUE;
if ((cFileName[0] == L'.') && (cFileName[1] == L'.') && (cFileName[2] == L'\0'))
return TRUE;
return FALSE;
}
const char szRunOnceMsiAsmCacheName[] = "Cleanup Msi-Installed-Fusion-Win32-Assembly Migration";
const char szRunOnceMsiAsmCacheRegKey[]= "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
const char szRunOnceValueCommandLine[]="rundll32.exe sxs.dll,SxspRunDllDeleteDirectory %S";
LONG MigrateMSIInstalledWin32Assembly()
{
LONG lResult = ERROR_SUCCESS;
HMODULE hSxs = NULL;
PSXS_INSTALL_W pfnSxsInstallW = NULL;
PSXS_BEGIN_ASSEMBLY_INSTALL pfnSxsBeginAssemblyInstall = NULL;
PSXS_END_ASSEMBLY_INSTALL pfnSxsEndAssemblyInstall = NULL;
BOOL fSuccess = FALSE;
PVOID SxsContext = NULL;
WCHAR AsmDirInAsmCache[MAX_PATH];
WCHAR Buf[MAX_PATH];
DWORD cchBuf;
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAW finddata;
SXS_INSTALLW InstallData = {sizeof(InstallData)};
SXS_INSTALL_REFERENCEW InstallReference = {sizeof(InstallReference)};
cchBuf= ExpandEnvironmentStringsW(pwszAsmCache, Buf, MAX_PATH); // including trailing NULL
if ((cchBuf == 0 ) || (cchBuf > MAX_PATH))
{
DbgPrintMessageBox("::Expand windir\\MsiAsmCache\\*.* return 0 or > MAX_PATH::");
lResult = GetLastError();
goto Exit;
}
#ifdef MSI_MIG_TEST
hSxs = ::LoadLibraryA("..\\..\\..\\..\\..\\dll\\whistler\\obj\\i386\\sxs.dll");
#else
hSxs = ::LoadLibraryA("sxs.dll");
#endif
if ((!hSxs) || (hSxs == INVALID_HANDLE_VALUE))
{
DbgPrintMessageBox("::Load Sxs.dll failed::");
lResult = GetLastError();
goto Exit;
}
pfnSxsInstallW = (PSXS_INSTALL_W)GetProcAddress(hSxs, SXS_INSTALL_W);
pfnSxsBeginAssemblyInstall = (PSXS_BEGIN_ASSEMBLY_INSTALL)GetProcAddress(hSxs, SXS_BEGIN_ASSEMBLY_INSTALL);
pfnSxsEndAssemblyInstall = (PSXS_END_ASSEMBLY_INSTALL)GetProcAddress(hSxs, SXS_END_ASSEMBLY_INSTALL);
if ((pfnSxsInstallW == NULL) || (pfnSxsBeginAssemblyInstall == NULL) || (pfnSxsEndAssemblyInstall == NULL))
{
DbgPrintMessageBox("::Find SxsInstall APIs failed::");
lResult = GetLastError();
goto Exit;
}
//
// !!!!! below is the code copied From base\ntsetup\syssetup\copy.c
//
//
// we do not use INSTALL_RECURSIVELY because the name of directory and structures always like
// c:\WINNT\winsxs\x86_blahblah\x86_blahblah.man
//
if (!pfnSxsBeginAssemblyInstall(
SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_NOT_TRANSACTIONAL
| SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_NO_VERIFY
| SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_REPLACE_EXISTING |
SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_FROM_DIRECTORY |
SXS_BEGIN_ASSEMBLY_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE, // I have to add this flag for old sxs!SxsInstallW parameter check
NULL,
NULL, // callback context
NULL, // impersonation callback
NULL, // impersonation context
&SxsContext
))
{
DbgPrintMessageBox("::pfnSxsBeginAssemblyInstall failed::");
lResult = GetLastError();
goto Exit;
}
hFind = FindFirstFileW(Buf, &finddata);
if (hFind == INVALID_HANDLE_VALUE)
{
DbgPrintMessageBox("::FindFirstFileW for MsiAsmCache failed::");
lResult = GetLastError();
goto Exit;
}
while (1) {
if ((wcscmp(finddata.cFileName, L"..") == 0) || (wcscmp(finddata.cFileName, L".") == 0))
goto GetNext;
if (!(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
// if it is not a directory, ignore it
goto GetNext;
}
// this must be a subdir of an asm, which is in the format of
// %windir\MsiAsmCache\x86_ms-sxstest-simple_75e377300ab7b886_1.0.10.0_en_61E9D7DC,
// otherwise, there is an error;
// the following calculation is used to decide the directory name. it must be a very long filename but
// MAX_PATH should be fine; and since Buf contains "*.*", it should cover the trailing NULL and extra back-slash.
if ((wcslen(Buf) + wcslen(finddata.cFileName)) > (sizeof(AsmDirInAsmCache) / sizeof(WCHAR)))
{
DbgPrintMessageBox("::filename %S under MsiAsmCache is too long, will be ignored::", finddata.cFileName);
goto GetNext;
}
wcscpy(AsmDirInAsmCache, Buf);
AsmDirInAsmCache[wcslen(Buf) - wcslen(L"*.*")] = L'\0'; // contain a trailing NULL
wcscat(AsmDirInAsmCache, finddata.cFileName);
//
// Set up the reference data to indicate that all of these are OS-installed
// assemblies.
//
ZeroMemory(&InstallReference, sizeof(InstallReference));
InstallReference.cbSize = sizeof(InstallReference);
InstallReference.dwFlags = 0;
#ifdef MSI_MIG_TEST
InstallReference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_SXS_INSTALL_ASSEMBLY;
#else
InstallReference.guidScheme = SXS_INSTALL_REFERENCE_SCHEME_OSINSTALL;
#endif
//
// Set up the structure to call off to the installer
//
memset(&InstallData, 0, sizeof(InstallData));
InstallData.cbSize = sizeof(InstallData);
InstallData.dwFlags =
SXS_INSTALL_FLAG_REFERENCE_VALID |
SXS_INSTALL_FLAG_REFRESH_PROMPT_VALID |
SXS_INSTALL_FLAG_INSTALL_COOKIE_VALID |
SXS_INSTALL_FLAG_CODEBASE_URL_VALID |
SXS_INSTALL_FLAG_FROM_DIRECTORY |
SXS_INSTALL_FLAG_FROM_DIRECTORY_RECURSIVE
;
InstallData.lpReference = &InstallReference;
InstallData.lpRefreshPrompt = L"migrated from downlevel, no source";
InstallData.pvInstallCookie = SxsContext;
InstallData.lpCodebaseURL = AsmDirInAsmCache;
InstallData.lpManifestPath = AsmDirInAsmCache;
fSuccess = pfnSxsInstallW(&InstallData);
if (fSuccess == FALSE)
{
DbgPrintMessageBox("::pfnSxsInstallW failed for %S, ignore the error and just continue::", AsmDirInAsmCache);
}else
{
DbgPrintMessageBox("::pfnSxsInstallW succeed for %S, Great!!!::", AsmDirInAsmCache);
}
GetNext:
if ( FALSE == FindNextFileW(hFind, &finddata))
{
if ( GetLastError() == ERROR_NO_MORE_FILES)
DbgPrintMessageBox("::FindNextFileW ends well ::");
else
DbgPrintMessageBox("::FindNextFileW failed::");
break;
}else
{
DbgPrintMessageBox("::FindNextFileW find next file::");
}
}
lResult = ERROR_SUCCESS;
{
//
// set RunOnce Key to delete MsiAsmCache Directory
//
HKEY hk = NULL;
if ( ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, szRunOnceMsiAsmCacheRegKey, 0, NULL, 0, KEY_SET_VALUE, NULL, &hk, NULL))
{
// we do not care it success or fail, we could live with it
CHAR buf[MAX_PATH * 2];
sprintf(buf, szRunOnceValueCommandLine, Buf);
if ( ERROR_SUCCESS != RegSetValueEx(hk, szRunOnceMsiAsmCacheName, 0, REG_SZ, (CONST BYTE *)buf, strlen(buf) + 1))
{
DbgPrintMessageBox("::SetRunOnceKey failed::");
}
}
RegCloseKey(hk);
}
Exit:
if ( SxsContext != NULL)
{
pfnSxsEndAssemblyInstall(
SxsContext,
fSuccess ? SXS_END_ASSEMBLY_INSTALL_FLAG_COMMIT : SXS_END_ASSEMBLY_INSTALL_FLAG_ABORT,
NULL);
}
if ( hSxs != NULL)
FreeLibrary(hSxs);
if (hFind != INVALID_HANDLE_VALUE)
CloseHandle(hFind);
// return the result from the actual migration call
return lResult;
}
///////////////////////////////////////////////////////////////////////
//
// API of WIN-NT MIGRATION Dll
//
///////////////////////////////////////////////////////////////////////
LONG CALLBACK QueryMigrationInfoA(PMIGRATIONINFOA * VersionInfo)
{
DbgPrintMessageBox("in QueryMigrationInfo");
if (IsThereAssembliesForMigrate() == FALSE)
{
return ERROR_NOT_INSTALLED; // no further migration
}
// only work for Win98 and win2k upgrade to winxp !!!
if (VersionInfo != NULL)
{
if (g_MigrationInfo == NULL)
{
g_MigrationInfo = (PMIGRATIONINFOA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MIGRATIONINFOA));
if (g_MigrationInfo == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
g_MigrationInfo->Size = sizeof(MIGRATIONINFOA);
g_MigrationInfo->StaticProductIdentifier = g_szProductId;
g_MigrationInfo->DllVersion = 200;
g_MigrationInfo->CodePageArray = NULL;
g_MigrationInfo->SourceOs = OS_WINDOWS2000;
g_MigrationInfo->TargetOs = OS_WINDOWSWHISTLER;
g_MigrationInfo->NeededFileList = NULL;
g_MigrationInfo->VendorInfo = &g_VendorInfo;
*VersionInfo = g_MigrationInfo;
}
}
return ERROR_SUCCESS;
}
LONG InitializeOnSource()
{
return ERROR_SUCCESS;
}
///////////////////////////////////////////////////////////////////////
LONG __stdcall InitializeSrcA(LPCSTR WorkingDirectory, LPCSTR SourceDirectories, LPCSTR MediaDirectory, PVOID Reserved)
{
DbgPrintMessageBox("in InitializeSrcA");
return InitializeOnSource();
}
/////////////////////////////////////////////////////////////////////////////
LONG CALLBACK GatherUserSettingsA(LPCSTR AnswerFile, HKEY UserRegKey, LPCSTR UserName, LPVOID Reserved)
{
DbgPrintMessageBox("in GatherUserSettingsA");
return ERROR_SUCCESS;
}
LONG CALLBACK GatherSystemSettingsA(LPCSTR AnswerFile, LPVOID Reserved)
{
DbgPrintMessageBox("in GatherSystemSettingsA");
return ERROR_SUCCESS;
}
///////////////////////////////////////////////////////////////////////
// Initialization routine on WinNT. Just stores of the migration
// working directory.
LONG CALLBACK InitializeDstA(LPCSTR WorkingDirectory, LPCSTR SourceDirectories, LPVOID Reserved)
{
DbgPrintMessageBox("in InitializeDstA");
return ERROR_SUCCESS;
}
///////////////////////////////////////////////////////////////////////
LONG CALLBACK ApplyUserSettingsA(
HINF AnswerFileHandle,
HKEY UserRegKey,
LPCSTR UserName,
LPCSTR UserDomain,
LPCSTR FixedUserName,
LPVOID Reserved)
{
DbgPrintMessageBox("in ApplyUserSettingsA");
return ERROR_SUCCESS;
}
///////////////////////////////////////////////////////////////////////
// Called once on NT
LONG CALLBACK ApplySystemSettingsA(HINF UnattendInfHandle, LPVOID Reserved)
{
DbgPrintMessageBox("in ApplySystemSettingsA");
if (ERROR_SUCCESS != MigrateMSIInstalledWin32Assembly())
{
// just display on chk version, no bother to return to setup
DbgPrintMessageBox("the return value of MigrateMSIInstalledWin32Assembly isnot totally successful.\n");
}
return ERROR_SUCCESS;
}
BOOL
WINAPI
DllMain(
HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved
)
{
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
g_MigrationInfo = NULL;
break;
case DLL_PROCESS_DETACH:
if (g_MigrationInfo != NULL)
{
if (lpvReserved != NULL)
{
HeapFree(GetProcessHeap(), 0, g_MigrationInfo);
}
g_MigrationInfo = NULL;
}
break;
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////
//
// API of WIN9X MIGRATION Dll
//
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// called by setup to extract migration DLL version and support
// information.
LONG CALLBACK QueryVersion(LPCSTR *ProductID, LPUINT DllVersion, LPINT *CodePageArray, LPCSTR *ExeNamesBuf, PVENDORINFO *VendorInfo)
{
DbgPrintMessageBox("QueryVersion");
if (IsThereAssembliesForMigrate() == FALSE)
{
return ERROR_NOT_INSTALLED; // no further migration
}
// product ID information
*ProductID = g_szProductId;
*DllVersion = 200;
// DLL is language independent.
*CodePageArray = NULL;
// no EXE search is required
*ExeNamesBuf = NULL;
// vendor information
*VendorInfo = &g_VendorInfo;
return ERROR_SUCCESS;
}
///////////////////////////////////////////////////////////////////////
LONG __stdcall Initialize9x(LPCSTR WorkingDirectory, LPCSTR SourceDirectories, LPCSTR MediaDirectory)
{
DbgPrintMessageBox("Initialize9x");
return InitializeOnSource();
}
/////////////////////////////////////////////////////////////////////////////
LONG CALLBACK MigrateUser9x(HWND ParentWnd, LPCSTR AnswerFile, HKEY UserRegKey, LPCSTR UserName, LPVOID Reserved)
{
DbgPrintMessageBox("MigrateUser9x");
return ERROR_SUCCESS;
}
LONG CALLBACK MigrateSystem9x(HWND ParentWnd, LPCSTR AnswerFile, LPVOID Reserved)
{
DbgPrintMessageBox("MigrateSystem9x");
return ERROR_SUCCESS;
}
///////////////////////////////////////////////////////////////////////
LONG CALLBACK InitializeNT(LPCWSTR WorkingDirectory, LPCWSTR SourceDirectories, LPVOID Reserved)
{
DbgPrintMessageBox("InitializeNT");
return ERROR_SUCCESS;
}
///////////////////////////////////////////////////////////////////////
LONG CALLBACK MigrateUserNT(HINF AnswerFileHandle, HKEY UserRegKey, LPCWSTR UserName, LPVOID Reserved)
{
DbgPrintMessageBox("MigrateUserNT");
return ERROR_SUCCESS;
}
typedef HRESULT (_stdcall * PFN_MigrateFusionWin32AssemblyToXP)(PCWSTR pszInstallerDir);
///////////////////////////////////////////////////////////////////////
LONG CALLBACK MigrateSystemNT(HINF UnattendInfHandle, LPVOID Reserved)
{
DbgPrintMessageBox("MigrateSystemNT");
if (ERROR_SUCCESS != MigrateMSIInstalledWin32Assembly())
{
// just display on chk version, no bother to return to setup
DbgPrintMessageBox("the return value of MigrateMSIInstalledWin32Assembly isnot totally successful.\n");
}
return ERROR_SUCCESS;
}