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.
1198 lines
32 KiB
1198 lines
32 KiB
/****************************Module*Header******************************\
|
|
* Module Name: ICMUPG.C
|
|
*
|
|
* Module Descripton: This file has code that upgrades Win9x ICM to
|
|
* Memphis and NT 5.0
|
|
*
|
|
* Warnings:
|
|
*
|
|
* Issues:
|
|
*
|
|
* Public Routines:
|
|
*
|
|
* Created: 14 November 1996
|
|
* Author: Srinivasan Chandrasekar [srinivac]
|
|
*
|
|
* Copyright (c) 1996, 1997 Microsoft Corporation
|
|
\***********************************************************************/
|
|
|
|
#include "icmupg.h"
|
|
#include "msg.h"
|
|
#include <setupapi.h>
|
|
#include <stdio.h>
|
|
|
|
|
|
//#define ICM_MIG_DEBUG
|
|
|
|
#ifdef UNICODE
|
|
error.
|
|
This dll needs to be built with ANSI, not UNICODE because it must run on
|
|
Win95, Win98 and on Windows 2000
|
|
#endif
|
|
|
|
|
|
//
|
|
// Local typedefs
|
|
//
|
|
|
|
typedef struct tagMANUMODELIDS {
|
|
DWORD dwManuID;
|
|
DWORD dwModelID;
|
|
} MANUMODELIDS, *PMANUMODELIDS;
|
|
|
|
typedef struct tagREGDATA {
|
|
DWORD dwRefCount;
|
|
DWORD dwManuID;
|
|
DWORD dwModelID;
|
|
} REGDATA, *PREGDATA;
|
|
|
|
typedef BOOL (WINAPI *PFNINSTALLCOLORPROFILEA)(PSTR, PSTR);
|
|
typedef BOOL (WINAPI *PFNINSTALLCOLORPROFILE)(LPCTSTR, LPCTSTR);
|
|
typedef BOOL (WINAPI *PFNENUMCOLORPROFILES)(PCTSTR, PENUMTYPE, PBYTE, PDWORD, PDWORD);
|
|
|
|
typedef struct {
|
|
CHAR CompanyName[256];
|
|
CHAR SupportNumber[256];
|
|
CHAR SupportUrl[256];
|
|
CHAR InstructionsToUser[1024];
|
|
} VENDORINFO, *PVENDORINFO;
|
|
|
|
|
|
//
|
|
// Global variables
|
|
//
|
|
|
|
TCHAR const gszICMRegPath[] = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ICM";
|
|
TCHAR const gszProfile[] = "profile";
|
|
TCHAR const gszMSCMSdll[] = "mscms.dll";
|
|
|
|
char const gszProductID[] = "Microsoft Color Management System";
|
|
|
|
char const gszInstallColorProfile[] = "InstallColorProfileA";
|
|
char const gszGetColorDirectory[] = "GetColorDirectoryA";
|
|
char const gszEnumColorProfiles[] = "EnumColorProfilesA";
|
|
VENDORINFO gVendorInfo;
|
|
char gszMigInf[MAX_PATH];
|
|
char const gszFullICMRegPath[] = "\"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ICM\"";
|
|
|
|
char const gszInstallColorProfileA[] = "InstallColorProfileA";
|
|
|
|
|
|
//BOOL gbWin98 = FALSE;
|
|
|
|
#if DBG
|
|
DWORD gdwDebugControl;
|
|
#endif
|
|
TCHAR szValue[MAX_PATH];
|
|
TCHAR szName[MAX_PATH];
|
|
|
|
PFNINSTALLCOLORPROFILEA pInstallColorProfileA = NULL;
|
|
PFNINSTALLCOLORPROFILE pInstallColorProfile = NULL;
|
|
PFNENUMCOLORPROFILES pEnumColorProfiles = NULL;
|
|
|
|
//
|
|
// Local functions
|
|
//
|
|
|
|
VOID InternalUpgradeICM();
|
|
VOID UpgradeClass(HKEY);
|
|
BOOL AssociateMonitorProfile();
|
|
BOOL AssociatePrinterProfiles(HKEY);
|
|
VOID InstallProfiles();
|
|
VOID DeleteOldICMKey();
|
|
void GetManuAndModelIDs(PTSTR, DWORD*, DWORD*);
|
|
int lstrcmpn(PTSTR, PTSTR, DWORD);
|
|
|
|
HINSTANCE hinstMigDll;
|
|
|
|
|
|
BOOL WINAPI
|
|
DllEntryPoint(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved) {
|
|
if(dwReason==DLL_PROCESS_ATTACH) {
|
|
hinstMigDll = hinstDll;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* QueryVersion
|
|
*
|
|
* Function:
|
|
* This function is called to get the DLL version information.
|
|
*
|
|
* Arguments:
|
|
* pszProductID - Fill in a unique string identifying us.
|
|
* puDllVersion - Our DLL version
|
|
*
|
|
* None of the other arguments are used
|
|
*
|
|
* Returns:
|
|
* ERROR_SUCCESS to indicate success
|
|
*
|
|
******************************************************************************/
|
|
|
|
LONG
|
|
CALLBACK
|
|
QueryVersion(
|
|
OUT LPCSTR *pszProductID,
|
|
OUT LPUINT puDllVersion,
|
|
OUT LPINT *pCodePageArray, OPTIONAL
|
|
OUT LPCSTR *ppszExeNamesBuf, OPTIONAL
|
|
OUT PVENDORINFO *ppVendorInfo
|
|
)
|
|
{
|
|
*pszProductID = gszProductID;
|
|
*puDllVersion = 1;
|
|
*ppszExeNamesBuf = NULL;
|
|
*pCodePageArray = NULL;
|
|
*ppVendorInfo = &gVendorInfo;
|
|
memset(&gVendorInfo, 0, sizeof(VENDORINFO));
|
|
FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_HMODULE,
|
|
hinstMigDll,
|
|
MSG_VI_COMPANY_NAME,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
gVendorInfo.CompanyName,
|
|
sizeof(gVendorInfo.CompanyName),
|
|
NULL
|
|
);
|
|
|
|
FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_HMODULE,
|
|
hinstMigDll,
|
|
MSG_VI_SUPPORT_NUMBER,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
gVendorInfo.SupportNumber,
|
|
sizeof(gVendorInfo.SupportNumber),
|
|
NULL
|
|
);
|
|
|
|
FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_HMODULE,
|
|
hinstMigDll,
|
|
MSG_VI_SUPPORT_URL,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
gVendorInfo.SupportUrl,
|
|
sizeof(gVendorInfo.SupportUrl),
|
|
NULL
|
|
);
|
|
|
|
FormatMessageA(
|
|
FORMAT_MESSAGE_FROM_HMODULE,
|
|
hinstMigDll,
|
|
MSG_VI_INSTRUCTIONS,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
gVendorInfo.InstructionsToUser,
|
|
sizeof(gVendorInfo.InstructionsToUser),
|
|
NULL
|
|
);
|
|
WARNING((__TEXT("QueryVersion called\n")));
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* Initialize9x
|
|
*
|
|
* Function:
|
|
* This function is called when upgrading to NT 5.0 from Win9x on the
|
|
* Win9x side.
|
|
*
|
|
* Arguments:
|
|
* pszWorkingDir - Directory where migrate.inf will be found
|
|
*
|
|
* Returns:
|
|
* ERROR_SUCCESS to indicate success
|
|
*
|
|
******************************************************************************/
|
|
|
|
LONG
|
|
CALLBACK
|
|
Initialize9x(
|
|
IN LPCSTR pszWorkingDir,
|
|
IN LPCSTR pszSourceDir,
|
|
IN LPVOID pvReserved
|
|
)
|
|
{
|
|
//
|
|
// Lets figure out if we're on a Win98 or Win95 system
|
|
// We don't migrate Win95 because Win95 doesn't have a
|
|
// profile database to migrate.
|
|
//
|
|
|
|
/* OSVERSIONINFO osVer;
|
|
|
|
osVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
GetVersionEx(&osVer);
|
|
gbWin98 =
|
|
(osVer.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
|
|
( (osVer.dwMajorVersion > 4) ||
|
|
( (osVer.dwMajorVersion == 4) && (osVer.dwMinorVersion > 0) ) );
|
|
*/
|
|
WARNING((__TEXT("Initialize9x called\n")));
|
|
|
|
lstrcpyA(gszMigInf, pszWorkingDir);
|
|
lstrcatA(gszMigInf, "\\migrate.inf");
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* MigrateUser9x
|
|
*
|
|
* Function:
|
|
* This function is called on Win9x to upgrade per user settings.
|
|
*
|
|
* Arguments:
|
|
* None of the arguments are used
|
|
*
|
|
* Returns:
|
|
* ERROR_SUCCES to indicate success
|
|
*
|
|
******************************************************************************/
|
|
|
|
LONG
|
|
CALLBACK
|
|
MigrateUser9x(
|
|
IN HWND hwndParent,
|
|
IN LPCSTR pszUnattendFile,
|
|
IN HKEY hUserRegKey,
|
|
IN LPCSTR pszUserName,
|
|
LPVOID pvReserved
|
|
)
|
|
{
|
|
//
|
|
// Nothing to do
|
|
//
|
|
|
|
WARNING((__TEXT("MigrateUser9x called\n")));
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* MigrateSystem9x
|
|
*
|
|
* Function:
|
|
* This function is called on the Win9x to upgrade system settings.
|
|
*
|
|
* Arguments:
|
|
* None of the arguments are used
|
|
*
|
|
* Returns:
|
|
* ERROR_SUCCES to indicate success
|
|
*
|
|
******************************************************************************/
|
|
|
|
LONG
|
|
CALLBACK
|
|
MigrateSystem9x(
|
|
IN HWND hwndParent,
|
|
IN LPCSTR pszUnattendFile,
|
|
LPVOID pvReserved
|
|
)
|
|
{
|
|
DWORD nProfiles;
|
|
DWORD dwSize;
|
|
char szColorDir[MAX_PATH];
|
|
char szNewColorDir[MAX_PATH];
|
|
char szDrive[2];
|
|
HMODULE hModule;
|
|
ENUMTYPE et = {sizeof (ENUMTYPE), ENUM_TYPE_VERSION, 0, NULL};
|
|
PBYTE pBuffer;
|
|
PSTR pstrBuffer;
|
|
PSTR pstrTraversal;
|
|
|
|
WARNING((__TEXT("MigrateSystem9x called\n")));
|
|
|
|
//
|
|
// Produce the Win9x Color Directory.
|
|
//
|
|
|
|
if(GetWindowsDirectoryA(szColorDir, MAX_PATH)==0)
|
|
{
|
|
// If we can't get the windows directory during an upgrade, we can't do anything
|
|
return ERROR_BAD_PATHNAME;
|
|
}
|
|
|
|
if (szColorDir[lstrlenA(szColorDir)-1] != '\\')
|
|
{
|
|
lstrcatA(szColorDir,"\\");
|
|
}
|
|
lstrcatA(szColorDir, "system\\color\\");
|
|
|
|
if(GetWindowsDirectoryA(szNewColorDir, MAX_PATH)==0)
|
|
{
|
|
// If we can't get the windows directory during an upgrade, we can't do anything
|
|
return ERROR_BAD_PATHNAME;
|
|
}
|
|
if (szNewColorDir[lstrlenA(szNewColorDir)-1] != '\\')
|
|
{
|
|
lstrcatA(szNewColorDir,"\\");
|
|
}
|
|
lstrcatA(szNewColorDir, "system32\\spool\\drivers\\color\\");
|
|
|
|
|
|
//
|
|
// If this is a Win95 system we have nothing to do because
|
|
// Win95 doesn't have a color profile database.
|
|
//
|
|
|
|
|
|
//
|
|
// We can't have mscms as an implib because when they try to load us in
|
|
// Win95, they won't find mscms.dll and reject us.
|
|
//
|
|
|
|
hModule = LoadLibrary(gszMSCMSdll);
|
|
if (hModule) {
|
|
#ifdef ICM_MIG_DEBUG
|
|
WritePrivateProfileStringA("ICM Debug", "hModule", "not NULL", gszMigInf);
|
|
WritePrivateProfileStringA("ICM Debug", "gbWin98", "TRUE", gszMigInf);
|
|
#endif
|
|
|
|
pEnumColorProfiles = (PFNENUMCOLORPROFILES)GetProcAddress(hModule, gszEnumColorProfiles);
|
|
if (pEnumColorProfiles) {
|
|
|
|
#ifdef ICM_MIG_DEBUG
|
|
WritePrivateProfileStringA("ICM Debug", "pEnumColorProfiles", "not NULL", gszMigInf);
|
|
#endif
|
|
|
|
//
|
|
// Compute the size of the EnumColorProfiles buffer.
|
|
//
|
|
|
|
dwSize = 0;
|
|
pEnumColorProfiles(NULL, &et, NULL, &dwSize, &nProfiles);
|
|
|
|
if(dwSize==0)
|
|
{
|
|
#ifdef ICM_MIG_DEBUG
|
|
WritePrivateProfileStringA("ICM Debug", "dwSize", "0", gszMigInf);
|
|
#endif
|
|
//
|
|
// Need to exit - nothing to do if there are no profiles installed,
|
|
// except to move the directory and registry settings.
|
|
//
|
|
WARNING((__TEXT("No profiles installed\n")));
|
|
goto EndMigrateSystem9x;
|
|
}
|
|
|
|
|
|
//
|
|
// Enumerate all the currently installed color profiles.
|
|
//
|
|
|
|
#ifdef ICM_MIG_DEBUG
|
|
WritePrivateProfileStringA("ICM Debug", "Enumerate", "Start", gszMigInf);
|
|
#endif
|
|
|
|
pBuffer = (BYTE *)malloc(dwSize);
|
|
pstrBuffer = (PSTR)pBuffer;
|
|
|
|
#ifdef ICM_MIG_DEBUG
|
|
WritePrivateProfileStringA("ICM Debug", "Enumerate", "TRUE", gszMigInf);
|
|
#endif
|
|
|
|
if(pEnumColorProfiles(NULL, &et, pBuffer, &dwSize, &nProfiles))
|
|
{
|
|
#ifdef ICM_MIG_DEBUG
|
|
WritePrivateProfileStringA("ICM Debug", "Enumerate", "for", gszMigInf);
|
|
#endif
|
|
|
|
for(pstrTraversal = pstrBuffer;
|
|
nProfiles--;
|
|
pstrTraversal += 1 + lstrlenA(pstrTraversal)) {
|
|
|
|
//
|
|
// Write the fact into the Migration Information file.
|
|
//
|
|
|
|
WritePrivateProfileStringA("Installed ICM Profiles", pstrTraversal, "1", gszMigInf);
|
|
}
|
|
}
|
|
free(pBuffer);
|
|
}
|
|
#ifdef ICM_MIG_DEBUG
|
|
else {
|
|
WritePrivateProfileStringA("ICM Debug", "pEnumColorProfiles", "NULL", gszMigInf);
|
|
}
|
|
#endif
|
|
|
|
|
|
EndMigrateSystem9x:
|
|
if (hModule)
|
|
{
|
|
FreeLibrary(hModule);
|
|
}
|
|
}
|
|
#ifdef ICM_MIG_DEBUG
|
|
else {
|
|
WritePrivateProfileStringA("ICM Debug", "hModule", "NULL", gszMigInf);
|
|
WritePrivateProfileStringA("ICM Debug", "gbWin98", "FALSE", gszMigInf);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// We'll handle the ICM branch of the registry
|
|
//
|
|
|
|
WritePrivateProfileStringA("Handled", gszFullICMRegPath, "Registry", gszMigInf);
|
|
|
|
|
|
//
|
|
// We'll be moving the entire subdirectory.
|
|
//
|
|
|
|
WritePrivateProfileStringA("Moved", szColorDir, szNewColorDir, gszMigInf);
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* InitializeNT
|
|
*
|
|
* Function:
|
|
* This function is called when upgrading to NT 5.0 from Win9x on the NT
|
|
* side. Its main purpose is to initialize us.
|
|
*
|
|
* Arguments:
|
|
* None of the arguments are used
|
|
*
|
|
* Returns:
|
|
* ERROR_SUCCESS to indicate success
|
|
*
|
|
******************************************************************************/
|
|
|
|
LONG
|
|
CALLBACK
|
|
InitializeNT(
|
|
IN LPCWSTR pszWorkingDir,
|
|
IN LPCWSTR pszSourceDir,
|
|
LPVOID pvReserved
|
|
)
|
|
{
|
|
SetupOpenLog(FALSE);
|
|
SetupLogError("ICM Migration: InitializeNT called\r\n", LogSevInformation);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* MigrateUserNT
|
|
*
|
|
* Function:
|
|
* This function is called on the NT to upgrade per user settings.
|
|
*
|
|
* Arguments:
|
|
* None of the arguments are used
|
|
*
|
|
* Returns:
|
|
* ERROR_SUCCES to indicate success
|
|
*
|
|
******************************************************************************/
|
|
|
|
LONG
|
|
CALLBACK
|
|
MigrateUserNT(
|
|
IN HANDLE hUnattendInf,
|
|
IN HKEY hUserRegKey,
|
|
IN LPCWSTR pszUserName,
|
|
LPVOID pvReserved
|
|
)
|
|
{
|
|
SetupLogError("ICM Migration: MigrateUserNT called\r\n", LogSevInformation);
|
|
|
|
//
|
|
// Nothing to do
|
|
//
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* MigrateSystemNT
|
|
*
|
|
* Function:
|
|
* This function is called on the Win9x to upgrade system settings. This
|
|
* is where we upgrade ICM 2.0
|
|
*
|
|
* Arguments:
|
|
* None of the other arguments are used
|
|
*
|
|
* Returns:
|
|
* ERROR_SUCCES to indicate success
|
|
*
|
|
******************************************************************************/
|
|
|
|
LONG
|
|
CALLBACK
|
|
MigrateSystemNT(
|
|
IN HANDLE hUnattendInf,
|
|
LPVOID pvReserved
|
|
)
|
|
{
|
|
HINSTANCE hModule;
|
|
LONG rc = ERROR_FILE_NOT_FOUND;
|
|
CHAR szMessage[MAX_PATH];
|
|
|
|
SetupLogError("ICM Migration: MigrateSystemNT called\r\n", LogSevInformation);
|
|
|
|
//
|
|
// We can't have mscms as an implib because when they try to load us in
|
|
// Win95, they won't find mscms.dll and reject us.
|
|
//
|
|
|
|
hModule = LoadLibrary(gszMSCMSdll);
|
|
if (!hModule)
|
|
{
|
|
sprintf(szMessage, "ICM Migration: Fatal Error, cannot load mscms.dll. Error %d\r\n", GetLastError());
|
|
SetupLogError(szMessage, LogSevFatalError);
|
|
return rc;
|
|
}
|
|
|
|
pInstallColorProfileA = (PFNINSTALLCOLORPROFILEA)GetProcAddress(hModule, gszInstallColorProfileA);
|
|
pInstallColorProfile = (PFNINSTALLCOLORPROFILE)GetProcAddress(hModule, gszInstallColorProfile);
|
|
|
|
if (!pInstallColorProfile || !pInstallColorProfileA)
|
|
{
|
|
SetupLogError("ICM Migration: Fatal Error, cannot find mscms functions. \r\n", LogSevFatalError);
|
|
goto EndMigrateSystemNT;
|
|
}
|
|
|
|
InternalUpgradeICM(); // Upgrade over Win9x
|
|
InstallProfiles(); // Install all profiles in the old color directory
|
|
DeleteOldICMKey();
|
|
|
|
rc = ERROR_SUCCESS;
|
|
|
|
EndMigrateSystemNT:
|
|
|
|
if (hModule)
|
|
{
|
|
FreeLibrary(hModule);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* DeleteOldICMKey
|
|
*
|
|
* Function:
|
|
* This function deletes the ICM key and subkeys from the Windows branch.
|
|
*
|
|
* Arguments:
|
|
* None
|
|
*
|
|
* Returns:
|
|
* Nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
DeleteOldICMKey()
|
|
{
|
|
HKEY hkICM = NULL; // key to ICM branch in registry
|
|
DWORD nSubkeys, i;
|
|
TCHAR szKeyName[32];
|
|
|
|
//
|
|
// Open the registry path where profiles used to be kept
|
|
//
|
|
|
|
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, gszICMRegPath, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
|
|
NULL, &hkICM, NULL) != ERROR_SUCCESS)
|
|
{
|
|
|
|
SetupLogError("ICM Migration: Cannot open ICM branch of registry\r\n", LogSevError);
|
|
return;
|
|
}
|
|
|
|
if (RegQueryInfoKey(hkICM, NULL, NULL, 0, &nSubkeys, NULL, NULL,
|
|
NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
|
|
{
|
|
SetupLogError("ICM Migration: Cannot enumerate ICM branch of registry\r\n", LogSevError);
|
|
goto EndDeleteOldICMKey;
|
|
}
|
|
|
|
//
|
|
// Go through all the device classes and delete all subkeys - this should
|
|
// only be one level deep
|
|
//
|
|
|
|
for (i=nSubkeys; i>0; i--)
|
|
{
|
|
RegEnumKey(hkICM, i-1, szKeyName, sizeof(szKeyName));
|
|
RegDeleteKey(hkICM, szKeyName);
|
|
}
|
|
|
|
EndDeleteOldICMKey:
|
|
if (hkICM)
|
|
{
|
|
RegCloseKey(hkICM);
|
|
}
|
|
RegDeleteKey(HKEY_LOCAL_MACHINE, gszICMRegPath);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Move directory with contents.
|
|
// Note this is not recursive.
|
|
// The purpose of this routine is to move the old color directory to the
|
|
// new color directory. During setup the new color directory may have already
|
|
// been created and populated with files. Vendor apps may have populated the
|
|
// old color directory with private subdirectories and files which will not
|
|
// appear in the new directory created by setup. This routine is designed
|
|
// to move those files.
|
|
//
|
|
// Note it'll fail to move a subdirectory of the old color directory if
|
|
// a similar subdirectory exists in the new color directory - this should not
|
|
// be the case.
|
|
//
|
|
// s and d should have the trailing slash.
|
|
//
|
|
|
|
void MyMoveDir(char *s, char *d) {
|
|
WIN32_FIND_DATA rf;
|
|
HANDLE hf;
|
|
char s2[MAX_PATH];
|
|
char s_[MAX_PATH];
|
|
char d_[MAX_PATH];
|
|
char err[MAX_PATH];
|
|
|
|
//
|
|
// If MoveFileEx succeeds, we're done.
|
|
//
|
|
|
|
if(!MoveFileEx(s, d, MOVEFILE_REPLACE_EXISTING)) {
|
|
sprintf(s2, "%s*", s);
|
|
hf = FindFirstFile(s2, &rf);
|
|
do {
|
|
// don't move . and ..
|
|
if(!(strcmp(".", rf.cFileName)==0 ||
|
|
strcmp("..", rf.cFileName)==0) ) {
|
|
sprintf(s_, "%s%s", s, rf.cFileName);
|
|
sprintf(d_, "%s%s", d, rf.cFileName);
|
|
if(!MoveFileEx(s_, d_, MOVEFILE_REPLACE_EXISTING)) {
|
|
int e = GetLastError();
|
|
sprintf(err, "ICM Migration: Failed the move of %s with %d\r\n", s_, e);
|
|
SetupLogError(err, LogSevError);
|
|
} else {
|
|
sprintf(err, "ICM Migration: Moved %s to %s\n", s_, d_);
|
|
SetupLogError(err, LogSevInformation);
|
|
}
|
|
}
|
|
|
|
} while(FindNextFile(hf, &rf));
|
|
FindClose(hf);
|
|
}
|
|
|
|
//
|
|
// source directory should theoretically be empty at this point
|
|
// If there are errors, we'll leave files behind and report this in
|
|
// the setup log as a LogSevError.
|
|
//
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* InstallProfiles
|
|
*
|
|
* Function:
|
|
* This function installs all profiles in %windir%\system\color.
|
|
* This is used when upgrading from Win9x to NT 5.0.
|
|
*
|
|
* Arguments:
|
|
* None
|
|
*
|
|
* Returns:
|
|
* Nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
InstallProfiles()
|
|
{
|
|
WIN32_FIND_DATAA wfd;
|
|
PSTR pNewColorDirEnd;
|
|
HANDLE hFindFile;
|
|
CHAR szOldColorDir[MAX_PATH];
|
|
CHAR szNewColorDir[MAX_PATH];
|
|
CHAR szReturnString[2];
|
|
CHAR szDefaultString[2];
|
|
CHAR szMessage[2*MAX_PATH+100];
|
|
|
|
if(GetWindowsDirectoryA(szOldColorDir, MAX_PATH)==0)
|
|
{
|
|
// If we can't get the windows directory during an upgrade, we can't do anything
|
|
sprintf(szMessage, "ICM Migration: GetWindowsDirectory() failed with code %d\r\n", GetLastError());
|
|
SetupLogError(szMessage, LogSevFatalError);
|
|
return;
|
|
}
|
|
|
|
if (szOldColorDir[lstrlenA(szOldColorDir)-1] != '\\')
|
|
lstrcatA(szOldColorDir, "\\");
|
|
lstrcatA(szOldColorDir, "system\\color\\");
|
|
|
|
|
|
if(GetWindowsDirectoryA(szNewColorDir, MAX_PATH)==0)
|
|
{
|
|
// If we can't get the windows directory during an upgrade, we can't do anything
|
|
sprintf(szMessage, "ICM Migration: GetWindowsDirectory() failed with code %d\r\n", GetLastError());
|
|
SetupLogError(szMessage, LogSevFatalError);
|
|
return;
|
|
}
|
|
|
|
if (szNewColorDir[lstrlenA(szNewColorDir)-1] != '\\')
|
|
{
|
|
lstrcatA(szNewColorDir, "\\");
|
|
}
|
|
lstrcatA(szNewColorDir, "system32\\spool\\drivers\\color\\");
|
|
|
|
ASSERT(pInstallColorProfileA != NULL);
|
|
|
|
|
|
//
|
|
// Eat any errors on the MoveFile. This is just in case the migration
|
|
// was stopped after a previous move and now the source doesn't exist.
|
|
//
|
|
|
|
MyMoveDir(szOldColorDir, szNewColorDir);
|
|
|
|
//
|
|
// Now we have presumably moved everything so run through the list of
|
|
// previously installed profiles and install those in the new directory
|
|
// (if we find them).
|
|
//
|
|
|
|
pNewColorDirEnd = szNewColorDir + lstrlenA(szNewColorDir);
|
|
lstrcatA(szNewColorDir, "*.*");
|
|
|
|
szDefaultString[0]='0';
|
|
szDefaultString[1]=0;
|
|
hFindFile = FindFirstFileA(szNewColorDir, &wfd);
|
|
|
|
|
|
if (hFindFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
do
|
|
{
|
|
lstrcpyA(pNewColorDirEnd, wfd.cFileName);
|
|
|
|
//
|
|
// Check to see if the profile was installed on Win9x
|
|
//
|
|
|
|
GetPrivateProfileStringA("Installed ICM Profiles", wfd.cFileName, szDefaultString, szReturnString, 2, gszMigInf);
|
|
|
|
//
|
|
// If it was installed, attempt to install it on NT
|
|
//
|
|
|
|
if(szReturnString[0]=='1') {
|
|
if (!(*pInstallColorProfileA)(NULL, szNewColorDir))
|
|
{
|
|
sprintf(szMessage, "ICM Migration: Error %d installing profile %s\r\n", GetLastError(), szNewColorDir);
|
|
SetupLogError(szMessage, LogSevError);
|
|
}
|
|
else
|
|
{
|
|
sprintf(szMessage, "ICM Migration: Installed profile %s\r\n", szNewColorDir);
|
|
SetupLogError(szMessage, LogSevInformation);
|
|
}
|
|
}
|
|
|
|
} while (FindNextFileA(hFindFile, &wfd));
|
|
|
|
FindClose(hFindFile);
|
|
}
|
|
else
|
|
{
|
|
SetupLogError("ICM Migration: FindFirstFile returned an invalid handle\r\n", LogSevFatalError);
|
|
}
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* InternalUpgradeICM
|
|
*
|
|
* Function:
|
|
* This function forms the core of the upgrade code. It installs all
|
|
* profiles in the regsitry, and associates with the right devices
|
|
*
|
|
* Arguments:
|
|
* None
|
|
*
|
|
* Returns:
|
|
* Nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
InternalUpgradeICM()
|
|
{
|
|
HKEY hkICM = NULL; // key to ICM branch in registry
|
|
HKEY hkDevice = NULL; // key to ICM device branch in registry
|
|
int i; // counter variable
|
|
TCHAR *pszClasses[] = { // different profile classes
|
|
__TEXT("mntr"),
|
|
__TEXT("prtr"),
|
|
__TEXT("scnr"),
|
|
__TEXT("link"),
|
|
__TEXT("abst"),
|
|
__TEXT("spac"),
|
|
__TEXT("nmcl")
|
|
};
|
|
CHAR szMessage[MAX_PATH];
|
|
LONG errcode;
|
|
|
|
//
|
|
// Open the registry path where profiles are kept
|
|
//
|
|
|
|
if (errcode = RegCreateKeyEx(HKEY_LOCAL_MACHINE, gszICMRegPath, 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
|
|
&hkICM, NULL) != ERROR_SUCCESS)
|
|
{
|
|
sprintf(szMessage, "ICM Migration: Fatal Error, cannot open registry entry (%s) code:%d\r\n",
|
|
gszICMRegPath, errcode);
|
|
SetupLogError(szMessage, LogSevFatalError);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Go through all the device classes and install the profiles
|
|
//
|
|
|
|
for (i=0; i<sizeof(pszClasses)/sizeof(PTSTR); i++)
|
|
{
|
|
if (RegOpenKeyEx(hkICM, pszClasses[i], 0, KEY_ALL_ACCESS, &hkDevice) != ERROR_SUCCESS)
|
|
{
|
|
continue; // go to next key
|
|
}
|
|
|
|
sprintf(szMessage, "ICM Migration: Upgrading %s\r\n", pszClasses[i]);
|
|
SetupLogError(szMessage, LogSevInformation);
|
|
UpgradeClass(hkDevice);
|
|
|
|
RegCloseKey(hkDevice);
|
|
}
|
|
|
|
//
|
|
// Set default monitor profile
|
|
//
|
|
|
|
// AssociateMonitorProfile(); - Not needed for Memphis
|
|
// If Pnp moves everything from Win9x PnP S/W section to NT 5.0 PnP S/W
|
|
// section, then we don't need this for NT either
|
|
|
|
if (hkICM)
|
|
{
|
|
RegCloseKey(hkICM);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* UpgradeClass
|
|
*
|
|
* Function:
|
|
* This function recursively calls itself to go down a registry path
|
|
* till it reaches the leaf, and installs all profiles it finds there
|
|
*
|
|
* Arguments:
|
|
* hKey - registry key for root node
|
|
*
|
|
* Returns:
|
|
* Nothing
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
UpgradeClass(
|
|
HKEY hKey
|
|
)
|
|
{
|
|
HKEY hSubkey;
|
|
DWORD nSubkeys, nValues, i, cbName, cbValue;
|
|
TCHAR szKeyName[32];
|
|
CHAR szMessage[MAX_PATH];
|
|
|
|
//
|
|
// If there is an error, return
|
|
//
|
|
|
|
if (RegQueryInfoKey(hKey, NULL, NULL, 0, &nSubkeys, NULL, NULL,
|
|
&nValues, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (nSubkeys > 0)
|
|
{
|
|
//
|
|
// This is not the leaf node, recurse
|
|
//
|
|
|
|
for (i=nSubkeys; i>0; i--)
|
|
{
|
|
RegEnumKey(hKey, i-1, szKeyName, sizeof(szKeyName));
|
|
if (RegOpenKeyEx(hKey, szKeyName, 0, KEY_ALL_ACCESS, &hSubkey) == ERROR_SUCCESS)
|
|
{
|
|
UpgradeClass(hSubkey);
|
|
RegCloseKey(hSubkey);
|
|
RegDeleteKey(hKey, szKeyName);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is the leaf node - install all the profiles registered
|
|
//
|
|
|
|
ASSERT(pInstallColorProfile != NULL);
|
|
|
|
for (i=nValues; i>0; i--)
|
|
{
|
|
cbName = MAX_PATH;
|
|
cbValue = MAX_PATH;
|
|
if (RegEnumValue(hKey, i-1, szName, &cbName, 0, NULL, (LPBYTE)szValue,
|
|
&cbValue) == ERROR_SUCCESS)
|
|
{
|
|
if (! lstrcmpn(szName, (PTSTR)gszProfile, lstrlen(gszProfile)))
|
|
{
|
|
if (! (*pInstallColorProfile)(NULL, szValue))
|
|
{
|
|
sprintf(szMessage, "ICM Migration: Error installing profile %s\r\n", szValue);
|
|
SetupLogError(szMessage, LogSevError);
|
|
}
|
|
else
|
|
{
|
|
sprintf(szMessage, "ICM Migration: Installed profile %s\r\n", szValue);
|
|
SetupLogError(szMessage, LogSevInformation);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PTSTR pProfile;
|
|
|
|
//
|
|
// We might be upgrading over Memphis or later
|
|
// In Memphis it is "file name" "value" instead of
|
|
// "profilexx" "value" in Win95 & OSR2
|
|
//
|
|
|
|
if (szName[1] == ':')
|
|
{
|
|
//
|
|
// Assume full path name
|
|
//
|
|
|
|
pProfile = szName;
|
|
|
|
}
|
|
else
|
|
{
|
|
GetWindowsDirectory(szValue, MAX_PATH);
|
|
if (szValue[lstrlen(szValue)-1] != '\\')
|
|
lstrcat(szValue, __TEXT("\\"));
|
|
lstrcat(szValue, __TEXT("system\\color\\"));
|
|
lstrcat(szValue, szName);
|
|
pProfile = szValue;
|
|
}
|
|
|
|
if (! (*pInstallColorProfile)(NULL, pProfile))
|
|
{
|
|
sprintf(szMessage, "ICM Migration: Error installing profile %s\r\n", pProfile);
|
|
SetupLogError(szMessage, LogSevError);
|
|
}
|
|
else
|
|
{
|
|
sprintf(szMessage, "ICM Migration: Installed Profile %s\r\n", pProfile);
|
|
SetupLogError(szMessage, LogSevInformation);
|
|
}
|
|
}
|
|
RegDeleteValue(hKey, szName);
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
*
|
|
* lstrcmpn
|
|
*
|
|
* Function:
|
|
* This function compares dwLen characters of two strings and decides if
|
|
* they are equal
|
|
*
|
|
* Arguments:
|
|
* pStr1 - pointer to string 1
|
|
* pStr2 - pointer to string 2
|
|
* dwLen - number of characters to compare
|
|
*
|
|
* Returns:
|
|
* Zero if the strings are equal, non zero otherwise
|
|
*
|
|
******************************************************************************/
|
|
|
|
int
|
|
lstrcmpn(
|
|
PTSTR pStr1,
|
|
PTSTR pStr2,
|
|
DWORD dwLen
|
|
)
|
|
{
|
|
//
|
|
// Assume no NULL strings
|
|
//
|
|
|
|
while (*pStr1 && *pStr2 && --dwLen)
|
|
{
|
|
if (*pStr1 != *pStr2)
|
|
break;
|
|
|
|
pStr1++;
|
|
pStr2++;
|
|
}
|
|
|
|
return (int)(*pStr1 - *pStr2);
|
|
}
|
|
#if DBG
|
|
|
|
/******************************************************************************
|
|
*
|
|
* MyDebugPrint
|
|
*
|
|
* Function:
|
|
* This function takes a format string and paramters, composes a string
|
|
* and sends it out to the debug port. Available only in debug build.
|
|
*
|
|
* Arguments:
|
|
* pFormat - pointer to format string
|
|
* ....... - parameters based on the format string like printf()
|
|
*
|
|
* Returns:
|
|
* No return value
|
|
*
|
|
******************************************************************************/
|
|
|
|
VOID
|
|
MyDebugPrintA(
|
|
PSTR pFormat,
|
|
...
|
|
)
|
|
{
|
|
char szBuffer[256];
|
|
va_list arglist;
|
|
|
|
va_start(arglist, pFormat);
|
|
wvsprintfA(szBuffer, pFormat, arglist);
|
|
va_end(arglist);
|
|
|
|
OutputDebugStringA(szBuffer);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
MyDebugPrintW(
|
|
PWSTR pFormat,
|
|
...
|
|
)
|
|
{
|
|
WCHAR szBuffer[256];
|
|
va_list arglist;
|
|
|
|
va_start(arglist, pFormat);
|
|
wvsprintfW(szBuffer, pFormat, arglist);
|
|
va_end(arglist);
|
|
|
|
OutputDebugStringW(szBuffer);
|
|
|
|
return;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* StripDirPrefixA
|
|
*
|
|
* Function:
|
|
* This function takes a path name and returns a pointer to the filename
|
|
* part. This is availabel only for the debug build.
|
|
*
|
|
* Arguments:
|
|
* pszPathName - path name of file (can be file name alone)
|
|
*
|
|
* Returns:
|
|
* A pointer to the file name
|
|
*
|
|
******************************************************************************/
|
|
|
|
PSTR
|
|
StripDirPrefixA(
|
|
PSTR pszPathName
|
|
)
|
|
{
|
|
DWORD dwLen = lstrlenA(pszPathName);
|
|
|
|
pszPathName += dwLen - 1; // go to the end
|
|
|
|
while (*pszPathName != '\\' && dwLen--)
|
|
{
|
|
pszPathName--;
|
|
}
|
|
|
|
return pszPathName + 1;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef STANDALONE
|
|
|
|
//
|
|
// For testing
|
|
//
|
|
|
|
main()
|
|
{
|
|
UpgradeICM(NULL, NULL, NULL, 0);
|
|
|
|
TCHAR buffer[MAX_PATH];
|
|
MigrateInit(buffer, NULL, 0, NULL, NULL);
|
|
MigrateInit(NULL, NULL, 0, NULL, NULL);
|
|
MigrateLocalMachine(NULL, NULL);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|