396 lines
14 KiB
C++
396 lines
14 KiB
C++
// ---------------------------------------------------------------------------
|
|
// 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 <setupapi.h>
|
|
#include <strings.h>
|
|
#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;
|
|
}
|