windows-nt/Source/XPSP1/NT/base/ntsetup/win95upg/migdlls/devupgrd/migrate.c
2020-09-26 16:20:57 +08:00

527 lines
13 KiB
C

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
migrate.c
Abstract:
This source file implements the windows 9x DEVUPGRD migration dll.
Author:
Marc R. Whitten (marcw) 07-January-2000
Revision History:
Ovidiu Temereanca (ovidiut) 04-Aug-2000 Fixed bugs and support for INF-less paths
--*/
#include "pch.h"
VENDORINFO g_VendorInfo = {"", "", "", ""};
CHAR g_ProductId [MAX_PATH];
PCSTR g_MigrateInfPath = NULL;
HINF g_MigrateInf = INVALID_HANDLE_VALUE;
HANDLE g_hHeap;
HINSTANCE g_hInst;
TCHAR g_DllDir[MAX_TCHAR_PATH];
#define D_DLLVERSION 2
#undef DEFMAC
#define MEMDB_CATEGORY_DLLENTRIES "MigDllEntries"
#define S_ACTIVE "Active"
#define DBG_MIGDLL "SMIGDLL"
//
// the temp file that records original sources location
//
#define S_MIGRATEDATA "migrate.dat"
#define S_MIGRATEDATW L"migrate.dat"
#define S_SECTION_DATAA "Data"
#define S_SECTION_DATAW L"Data"
#define S_KEY_SOURCESA "Sources"
#define S_KEY_SOURCESW L"Sources"
PCSTR g_WorkingDir = NULL;
PCSTR g_DataFileA = NULL;
PCWSTR g_DataFileW = NULL;
typedef BOOL (WINAPI INITROUTINE_PROTOTYPE)(HINSTANCE, DWORD, LPVOID);
INITROUTINE_PROTOTYPE MigUtil_Entry;
POOLHANDLE g_GlobalPool;
#define DEVREGKEY "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup\\UpgradeDrivers"
BOOL
WINAPI
DllMain (
IN HINSTANCE DllInstance,
IN ULONG ReasonForCall,
IN LPVOID Reserved
)
{
PSTR p;
BOOL result = TRUE;
switch (ReasonForCall) {
case DLL_PROCESS_ATTACH:
//
// We don't need DLL_THREAD_ATTACH or DLL_THREAD_DETACH messages
//
DisableThreadLibraryCalls (DllInstance);
//
// Global init
//
g_hHeap = GetProcessHeap();
g_hInst = DllInstance;
//
// Init common controls
//
InitCommonControls();
//
// Get DLL path and strip directory
//
GetModuleFileNameA (DllInstance, g_DllDir, MAX_TCHAR_PATH);
p = strrchr (g_DllDir, '\\');
MYASSERT (p);
if (p) {
*p = 0;
}
if (!MigUtil_Entry (DllInstance, DLL_PROCESS_ATTACH, NULL)) {
return FALSE;
}
//
// Allocate a global pool
//
g_GlobalPool = PoolMemInitNamedPool ("Global Pool");
break;
case DLL_PROCESS_DETACH:
if (g_MigrateInfPath) {
FreePathStringA (g_MigrateInfPath);
g_MigrateInfPath = NULL;
}
if (g_MigrateInf != INVALID_HANDLE_VALUE) {
InfCloseInfFile (g_MigrateInf);
g_MigrateInf = INVALID_HANDLE_VALUE;
}
//
// Free standard pools
//
if (g_GlobalPool) {
PoolMemDestroyPool (g_GlobalPool);
g_GlobalPool = NULL;
}
MigUtil_Entry (DllInstance, DLL_PROCESS_DETACH, NULL);
break;
}
return result;
}
LONG
CALLBACK
QueryVersion (
OUT PCSTR *ProductID,
OUT PUINT DllVersion,
OUT PINT *CodePageArray, OPTIONAL
OUT PCSTR *ExeNamesBuf, OPTIONAL
OUT PVENDORINFO *VendorInfo
)
{
LONG result = ERROR_NOT_INSTALLED;
PCSTR tempStr;
HANDLE h;
//
// Fill the data.
//
tempStr = GetStringResourceA (MSG_PRODUCT_ID);
if (tempStr) {
StringCopyByteCountA (g_ProductId, tempStr, MAX_PATH);
FreeStringResourceA (tempStr);
}
*ProductID = g_ProductId;
*DllVersion = D_DLLVERSION;
*CodePageArray = NULL;
*VendorInfo = &g_VendorInfo;
// now get the VendorInfo data from resources
tempStr = GetStringResourceA (MSG_VI_COMPANY_NAME);
if (tempStr) {
StringCopyByteCountA (g_VendorInfo.CompanyName, tempStr, 256);
FreeStringResourceA (tempStr);
}
tempStr = GetStringResourceA (MSG_VI_SUPPORT_NUMBER);
if (tempStr) {
StringCopyByteCountA (g_VendorInfo.SupportNumber, tempStr, 256);
FreeStringResourceA (tempStr);
}
tempStr = GetStringResourceA (MSG_VI_SUPPORT_URL);
if (tempStr) {
StringCopyByteCountA (g_VendorInfo.SupportUrl, tempStr, 256);
FreeStringResourceA (tempStr);
}
tempStr = GetStringResourceA (MSG_VI_INSTRUCTIONS);
if (tempStr) {
StringCopyByteCountA (g_VendorInfo.InstructionsToUser, tempStr, 1024);
FreeStringResourceA (tempStr);
}
*ExeNamesBuf = NULL;
//
// See if the registry key exists. If it does not, return ERROR_NOT_INSTALLED.
//
h = OpenRegKeyStr (DEVREGKEY);
if (h && h != INVALID_HANDLE_VALUE) {
result = ERROR_SUCCESS;
CloseRegKey (h);
}
return result;
}
LONG
CALLBACK
Initialize9x (
IN PCSTR WorkingDirectory,
IN PCSTR SourceDirectories,
IN PCSTR MediaDir
)
{
//
// remember source directory, so it can be removed on cleanup
//
g_DataFileA = JoinPathsExA (g_GlobalPool, WorkingDirectory, S_MIGRATEDATA);
WritePrivateProfileStringA (S_SECTION_DATAA, S_KEY_SOURCESA, MediaDir, g_DataFileA);
g_WorkingDir = DuplicatePathString (WorkingDirectory, 0);
g_MigrateInfPath = JoinPathsExA (g_GlobalPool, WorkingDirectory, S_MIGRATE_INF);
g_MigrateInf = InfOpenInfFileA (g_MigrateInfPath);
return ERROR_SUCCESS;
}
LONG
CALLBACK
MigrateUser9x (
IN HWND ParentWnd,
IN PCSTR UnattendFile,
IN HKEY UserRegKey,
IN PCSTR UserName,
PVOID Reserved
)
{
return ERROR_SUCCESS;
}
LONG
CALLBACK
MigrateSystem9x (
IN HWND ParentWnd,
IN PCSTR UnattendFile,
PVOID Reserved
)
{
HANDLE h;
REGVALUE_ENUM eValue;
REGTREE_ENUM eTree;
BOOL found;
PSTR value;
PSTR p;
PSTR end;
PSTR dir;
CHAR deviceInf [MEMDB_MAX];
HASHTABLE table;
PSTR pnpId;
DWORD attr;
table = HtAllocWithData (sizeof (PSTR));
if (!table) {
return ERROR_OUTOFMEMORY;
}
__try {
//
// Gather list of pnpids registered on this machine.
//
h = OpenRegKeyStrA (DEVREGKEY);
if (!h || h == INVALID_HANDLE_VALUE) {
return ERROR_NOT_INSTALLED;
}
if (EnumFirstRegValue (&eValue, h)) {
do {
p = GetRegValueStringA (h, eValue.ValueName);
if (!p) {
continue;
}
value = PoolMemDuplicateStringA (g_GlobalPool, p);
MemFree (g_hHeap, 0, p);
if (!value) {
return ERROR_OUTOFMEMORY;
}
HtAddStringAndDataA (table, eValue.ValueName, &value);
} while (EnumNextRegValue (&eValue));
}
CloseRegKey (h);
//
// Now, enumerate the registry.
//
if (EnumFirstRegKeyInTreeA (&eTree, "HKLM\\Enum")) {
do {
//
// For each registry key, look to see if we have a compatible id or hardware id
// that is in our hash table.
//
found = FALSE;
value = GetRegValueStringA (eTree.CurrentKey->KeyHandle, "HardwareId");
if (value) {
if (HtFindStringAndDataA (table, value, &dir)) {
found = TRUE;
pnpId = PoolMemDuplicateStringA (g_GlobalPool, value);
} else {
p = value;
while (p && !found) {
end = _mbschr (p, ',');
if (end) {
*end = 0;
}
if (HtFindStringAndDataA (table, p, &dir)) {
found = TRUE;
pnpId = PoolMemDuplicateStringA (g_GlobalPool, p);
}
else {
p = end;
if (p) {
p++;
}
}
}
}
MemFree (g_hHeap, 0, value);
}
if (!found) {
value = GetRegValueStringA (eTree.CurrentKey->KeyHandle, "CompatibleIds");
if (value) {
if (HtFindStringAndDataA (table, value, &dir)) {
found = TRUE;
pnpId = PoolMemDuplicateStringA (g_GlobalPool, value);
}
p = value;
while (p && !found) {
end = _mbschr (p, ',');
if (end) {
*end = 0;
}
if (HtFindStringAndDataA (table, p, &dir)) {
found = TRUE;
pnpId = PoolMemDuplicateStringA (g_GlobalPool, p);
}
else {
p = end;
if (p) {
p++;
}
}
}
MemFree (g_hHeap, 0, value);
}
}
if (found) {
//
// build path to deviceInf (no OriginalInstallMedia since the directory will be blown away)
//
lstrcpyA (deviceInf, dir);
//
// GUI setup expects a path to the actual INF, not a directory,
// so let's fix it if this is the case
//
attr = GetFileAttributesA (deviceInf);
if (attr == (DWORD)-1) {
//
// invalid path spec; ignore it
//
continue;
}
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
//
// just pick up the first INF
//
HANDLE h;
WIN32_FIND_DATAA fd;
PSTR pattern;
pattern = JoinPathsExA (g_GlobalPool, deviceInf, "*.inf");
h = FindFirstFileA (pattern, &fd);
if (h == INVALID_HANDLE_VALUE) {
//
// no INF found here; skip
//
continue;
}
FindClose (h);
//
// build path to the INF; also handle the case when deviceInf ends with a \
//
pattern = JoinPathsExA (g_GlobalPool, deviceInf, fd.cFileName);
lstrcpyA (deviceInf, pattern);
}
//
// Handle the key (remove the message from the compatibility report).
//
WritePrivateProfileStringA (
"HANDLED",
eTree.FullKeyName,
"REGISTRY",
g_MigrateInfPath
);
//
// Add to the appropriate section of the SIF file.
//
WritePrivateProfileString (
"DeviceDrivers",
pnpId,
deviceInf,
UnattendFile
);
//
// Flush to disk.
//
WritePrivateProfileString (NULL, NULL, NULL, g_MigrateInfPath);
WritePrivateProfileString (NULL, NULL, NULL, UnattendFile);
}
} while (EnumNextRegKeyInTree (&eTree));
}
}
__finally {
//
// Clean up resources.
//
HtFree (table);
}
return ERROR_SUCCESS;
}
LONG
CALLBACK
InitializeNT (
IN PCWSTR WorkingDirectory,
IN PCWSTR SourceDirectories,
PVOID Reserved
)
{
g_DataFileW = JoinPathsExW (g_GlobalPool, WorkingDirectory, S_MIGRATEDATW);
return ERROR_SUCCESS;
}
LONG
CALLBACK
MigrateUserNT (
IN HINF UnattendInfHandle,
IN HKEY UserRegKey,
IN PCWSTR UserName,
PVOID Reserved
)
{
return ERROR_SUCCESS;
}
LONG
CALLBACK
MigrateSystemNT (
IN HINF UnattendInfHandle,
PVOID Reserved
)
{
WCHAR SourceDirectory[MAX_PATH + 2];
//
// remove original sources directories
//
if (GetPrivateProfileStringW (
S_SECTION_DATAW,
S_KEY_SOURCESW,
L"",
SourceDirectory,
MAX_PATH + 2,
g_DataFileW
)) {
RemoveCompleteDirectoryW (SourceDirectory);
}
return ERROR_SUCCESS;
}