// --------------------------------------------------------------------------- // MAIN.CPP // --------------------------------------------------------------------------- // Copyright (c) 1999 Microsoft Corporation // // Migration DLL for Outlook Express and Windows Address Book moving from // Win9X to NT5. // // --------------------------------------------------------------------------- #include "pch.hxx" #include #include #include "resource.h" #include "detect.h" #include "main.h" // Used for resources static HMODULE s_hInst = NULL; // These settings are init'd during Initialize9x and used later static LPSTR s_pszMigratePath = NULL; static TCHAR s_szOEVer[VERLEN] = ""; static SETUPVER s_svOEInterimVer = VER_NONE; static TCHAR s_szWABVer[VERLEN] = ""; static SETUPVER s_svWABInterimVer = VER_NONE; static const char c_szMigrateINF[] = "migrate.inf"; // Dll Entry point INT WINAPI DllMain(IN HINSTANCE hInstance, IN DWORD dwReason, PVOID pvReserved) { UNREFERENCED_PARAMETER(pvReserved); // Validate Params Assert(hInstance); switch (dwReason) { case DLL_PROCESS_ATTACH : DisableThreadLibraryCalls(hInstance); // Open Error Log. FALSE indicates that any current // log is not deleted. Use SetupErrorLog() to record // any errors encountered within the Migration DLL. //SetupOpenLog(FALSE); // Need this global to figure out the others s_hInst = hInstance; break; case DLL_PROCESS_DETACH : //SetupCloseLog(); if (s_pszMigratePath) { GlobalFree(s_pszMigratePath); s_pszMigratePath = NULL; } break; default: break; } return TRUE; } //////////////////////////////////// // QueryVersion() EXPORT_FUNCTION LONG CALLBACK QueryVersion(OUT LPCSTR *ppcszProductID, OUT UINT *pnDllVersion, OUT INT **ppnCodePageArray, // Optional OUT LPCSTR *ppcszExeNamesBuf, // Optional OUT VENDORINFO **ppVendorInfo) { // These need to be static as their addresses are given to setup // - ie. they need to live as long as they can. static CHAR s_szProductID[CCHMAX_STRINGRES] = ""; static CHAR s_szCompany[CCHMAX_STRINGRES] = ""; static CHAR s_szPhone[CCHMAX_STRINGRES] = ""; static CHAR s_szURL[CCHMAX_STRINGRES] = ""; static CHAR s_szInstructions[CCHMAX_STRINGRES] = ""; static VENDORINFO s_VendInfo; // Validate Params Assert(ppcszProductID); Assert(pnDllVersion); Assert(ppnCodePageArray); Assert(ppcszExeNamesBuf); Assert(ppVendorInfo); // Validate global state Assert(s_hInst); // Initialize statics LoadStringA(s_hInst, IDS_PRODUCTID, s_szProductID, ARRAYSIZE(s_szProductID)); LoadStringA(s_hInst, IDS_COMPANY, s_szCompany, ARRAYSIZE(s_szCompany)); LoadStringA(s_hInst, IDS_PHONE, s_szPhone, ARRAYSIZE(s_szPhone)); LoadStringA(s_hInst, IDS_URL, s_szURL, ARRAYSIZE(s_szURL)); LoadStringA(s_hInst, IDS_INSTRUCTIONS, s_szInstructions, ARRAYSIZE(s_szInstructions)); StrCpyN(s_VendInfo.CompanyName, s_szCompany, ARRAYSIZE(s_VendInfo.CompanyName)); StrCpyN(s_VendInfo.SupportNumber, s_szPhone, ARRAYSIZE(s_VendInfo.SupportNumber)); StrCpyN(s_VendInfo.SupportUrl, s_szURL, ARRAYSIZE(s_VendInfo.SupportNumber)); StrCpyN(s_VendInfo.InstructionsToUser, s_szInstructions, ARRAYSIZE(s_VendInfo.InstructionsToUser)); // Return information *ppcszProductID = s_szProductID; *pnDllVersion = MIGDLL_VERSION; // We don't have locale-specific migration work *ppnCodePageArray = NULL; // We don't need setup to locate any exes for us *ppcszExeNamesBuf = NULL; *ppVendorInfo = &s_VendInfo; return ERROR_SUCCESS; } //////////////////////////////////// // Initialize9x() EXPORT_FUNCTION LONG CALLBACK Initialize9x (IN LPCSTR pszWorkingDir, IN LPCSTR pszSourceDirs, LPVOID pvReserved) { BOOL fWABInstalled = FALSE; BOOL fOEInstalled = FALSE; INT nLen; INT nLenEnd; INT nLenSlash; LONG lRet = ERROR_NOT_INSTALLED; UNREFERENCED_PARAMETER(pszSourceDirs); UNREFERENCED_PARAMETER(pvReserved); // Validate Params Assert(pszWorkingDir); Assert(pszSourceDirs); // See if either the WAB or OE is installed fOEInstalled = LookForApp(APP_OE, s_szOEVer, ARRAYSIZE(s_szOEVer), s_svOEInterimVer); fWABInstalled = LookForApp(APP_WAB, s_szWABVer, ARRAYSIZE(s_szWABVer), s_svWABInterimVer); // If OE is installed, WAB better be too Assert(!fOEInstalled || fWABInstalled); if (fWABInstalled || fOEInstalled) { // Validate global state Assert(NULL == s_pszMigratePath); // ---- Figure out largest needed size and slash terminate // Parameter length (without null) nLenEnd = lstrlenA(pszWorkingDir); // Space for a slash if (*CharPrev(pszWorkingDir, pszWorkingDir + nLenEnd) != '\\') nLenSlash = 1; else nLenSlash = 0; // Space for migrate.inf and a NULL (null is incl in ARRAYSIZE) nLen = nLenEnd + nLenSlash + ARRAYSIZE(c_szMigrateINF); // Allocate the space s_pszMigratePath = (LPSTR)GlobalAlloc(GMEM_FIXED, nLen * sizeof(*s_pszMigratePath)); if (NULL != s_pszMigratePath) { // Build path from working dir, slash and filename StrCpyN(s_pszMigratePath, pszWorkingDir, nLen); if (nLenSlash) s_pszMigratePath[nLenEnd] = '\\'; StrCpyN(&s_pszMigratePath[nLenEnd+nLenSlash], c_szMigrateINF, nLen - (nLenEnd+nLenSlash)); lRet = ERROR_SUCCESS; } } // Return ERROR_NOT_INSTALLED to stop further calls to this DLL. return lRet; } //////////////////////////////////// // MigrateUser9x() EXPORT_FUNCTION LONG CALLBACK MigrateUser9x (IN HWND hwndParent, IN LPCSTR pcszAnswerFile, IN HKEY hkeyUser, IN LPCSTR pcszUserName, LPVOID pvReserved) { UNREFERENCED_PARAMETER(hwndParent); UNREFERENCED_PARAMETER(pcszAnswerFile); UNREFERENCED_PARAMETER(hkeyUser); UNREFERENCED_PARAMETER(pcszUserName); UNREFERENCED_PARAMETER(pvReserved); // Validate Params Assert(pcszAnswerFile); Assert(hkeyUser); Assert(pcszUserName); // We will migrate per-user settings in the per-user stub // Nothing to do now return ERROR_NOT_INSTALLED; } //////////////////////////////////// // MigrateSystem9x() EXPORT_FUNCTION LONG CALLBACK MigrateSystem9x(IN HWND hwndParent, IN LPCSTR pcszAnswerFile, LPVOID pvReserved) { UNREFERENCED_PARAMETER(hwndParent); UNREFERENCED_PARAMETER(pcszAnswerFile); UNREFERENCED_PARAMETER(pvReserved); // Validate Params Assert(pcszAnswerFile); // Validate global state Assert(s_pszMigratePath); Assert(s_pszMigratePath[0]); // Record Version info if (s_szOEVer[0]) WritePrivateProfileString("Outlook-Express", "PreviousVer", s_szOEVer, s_pszMigratePath); if (VER_NONE != s_svOEInterimVer) WritePrivateProfileStruct("Outlook-Express", "InterimVer", (LPVOID)&s_svOEInterimVer, sizeof(s_svOEInterimVer), s_pszMigratePath); if (s_szWABVer[0]) WritePrivateProfileString("Windows-Address-Book", "PreviousVer", s_szWABVer, s_pszMigratePath); if (VER_NONE != s_svWABInterimVer) WritePrivateProfileStruct("Windows-Address-Book", "InterimVer", (LPVOID)&s_svWABInterimVer, sizeof(s_svWABInterimVer), s_pszMigratePath); // Modify Migrate.INF appropriately. Consider adding entries to // the following sections : // [HANDLED] - Files, Paths, and Registry entries you migrate (causing setup to leave files and paths alone; registry entries placed here are not copied into the NT5 registry automatically) // [MOVED] - Indicate Files that are moved, renamed, or deleted. Setup updates shell links to these files. // [INCOMPATIBLE MESSAGES] - Used to create a incompatibility report for this application. User will be provided the opportunity to read this before committing to the upgrade. // TODO : return ERROR_NOT_INSTALLED if your application requires no system wide changes. return (s_szOEVer[0] || s_szWABVer[0]) ? ERROR_SUCCESS : ERROR_NOT_INSTALLED; } //////////////////////////////////// // InitializeNT() EXPORT_FUNCTION LONG CALLBACK InitializeNT (IN LPCWSTR pcwszWorkingDir, IN LPCWSTR pcwszSourceDirs, LPVOID pvReserved) { int cb, cch; LONG lErr = ERROR_SUCCESS; UNREFERENCED_PARAMETER(pcwszSourceDirs); UNREFERENCED_PARAMETER(pvReserved); // Validate Params Assert(pcwszWorkingDir); Assert(pcwszSourceDirs); // Validate global state Assert(NULL == s_pszMigratePath); // Strings sent on NT side of setup are Unicode // How big a buffer do we need? cb = WideCharToMultiByte(CP_ACP, 0, pcwszWorkingDir, -1, NULL, 0, NULL, NULL); if (0 == cb) { // This will fail the entire OE/WAB migration lErr = GetLastError(); goto exit; } // Try to alloc the buffer // Allow space for possible slash (+1) and migrate.inf (ARRAYSIZE - 1 for null) // NULL was included in WideCharToMultiByte's count s_pszMigratePath = (LPSTR)GlobalAlloc(GMEM_FIXED, cb + ((1+(ARRAYSIZE(c_szMigrateINF)-1))*sizeof(*s_pszMigratePath))); // Set cch to the number of characters that can be contained in s_pszMigratePath cch = cb / sizeof(*s_pszMigratePath) + (1+(ARRAYSIZE(c_szMigrateINF)-1)); if (NULL == s_pszMigratePath) { // This will fail the entire OE/WAB migration lErr = ERROR_NOT_ENOUGH_MEMORY; goto exit; } // Do the conversion cb = WideCharToMultiByte(CP_ACP, 0, pcwszWorkingDir, -1, s_pszMigratePath, cb, NULL, NULL); if (0 == cb) { // This will fail the entire OE/WAB migration lErr = GetLastError(); goto exit; } // WideCharToMultiByte includes NULL in count cb--; // Append a backslash if needed if ('\\' != *CharPrev(s_pszMigratePath, s_pszMigratePath + cb)) s_pszMigratePath[cb++] = '\\'; // Append the name of the inf StrCpyN(&s_pszMigratePath[cb], "migrate.inf", cch - cb); exit: return lErr; } //////////////////////////////////// // MigrateUserNT() EXPORT_FUNCTION LONG CALLBACK MigrateUserNT(IN HINF hinfAnswerFile, IN HKEY hkeyUser, IN LPCWSTR pcwszUserName, LPVOID pvReserved) { UNREFERENCED_PARAMETER(hinfAnswerFile); UNREFERENCED_PARAMETER(hkeyUser); UNREFERENCED_PARAMETER(pcwszUserName); UNREFERENCED_PARAMETER(pvReserved); // Validate Params Assert(hinfAnswerFile); Assert(hkeyUser); // pcwszUserName can be NULL // We will migrate per-user settings in the per-user stub // Nothing to do now return ERROR_SUCCESS; } //////////////////////////////////// // MigrateSystemNT() EXPORT_FUNCTION LONG CALLBACK MigrateSystemNT(IN HINF hinfAnswerFile, LPVOID pvReserved) { HKEY hkey; DWORD dwDisp; UNREFERENCED_PARAMETER(hinfAnswerFile); UNREFERENCED_PARAMETER(pvReserved); // Validate params Assert(hinfAnswerFile); // Validate global state Assert(s_pszMigratePath); Assert(s_pszMigratePath[0]); // Read information we gathered from Win9x GetPrivateProfileString("Outlook-Express", "PreviousVer", "", s_szOEVer, ARRAYSIZE(s_szOEVer), s_pszMigratePath); GetPrivateProfileStruct("Outlook-Express", "InterimVer", (LPVOID)&s_svOEInterimVer, sizeof(s_svOEInterimVer), s_pszMigratePath); GetPrivateProfileString("Windows-Address-Book", "PreviousVer", "", s_szWABVer, ARRAYSIZE(s_szWABVer), s_pszMigratePath); GetPrivateProfileStruct("Windows-Address-Book", "InterimVer", (LPVOID)&s_svWABInterimVer, sizeof(s_svWABInterimVer), s_pszMigratePath); // Update machine with information if (s_szOEVer[0]) { if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szRegVerInfo, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, &dwDisp)) { RegSetValueEx(hkey, c_szRegPrevVer, 0, REG_SZ, (LPBYTE)s_szOEVer, lstrlenA(s_szOEVer)+1); if (s_svOEInterimVer != VER_NONE) RegSetValueEx(hkey, c_szRegInterimVer, 0, REG_DWORD, (LPBYTE)&s_svOEInterimVer, sizeof(s_svOEInterimVer)); RegCloseKey(hkey); } } if (s_szWABVer[0]) { if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szRegWABVerInfo, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, &dwDisp)) { RegSetValueEx(hkey, c_szRegPrevVer, 0, REG_SZ, (LPBYTE)s_szWABVer, lstrlenA(s_szWABVer)+1); if (s_svWABInterimVer != VER_NONE) RegSetValueEx(hkey, c_szRegInterimVer, 0, REG_DWORD, (LPBYTE)&s_svWABInterimVer, sizeof(s_svWABInterimVer)); RegCloseKey(hkey); } } return ERROR_SUCCESS; }