4809 lines
110 KiB
C
4809 lines
110 KiB
C
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
winntsif.c
|
|
|
|
Abstract:
|
|
|
|
winntsif.c is responsible for filling in the nt setup answer file with data from
|
|
the win9xupg system being upgraded. This data is then used during unattended setup
|
|
to control the installation of various portions of the winnt system.
|
|
|
|
This is a rewrite and rationalization of the old unattend.c file.
|
|
|
|
|
|
Author:
|
|
|
|
Marc R. Whitten (marcw) 16-Feb-1998
|
|
|
|
Revision History:
|
|
|
|
ovidiut 14-Mar-2000 Added random admin password for GUI setup
|
|
marcw 29-Aug-1999 ID mapping for NICs.
|
|
marcw 08-Mar-1999 Migration dlls can handle section\keys.
|
|
marcw 23-Sep-1998 DLC fix
|
|
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
#define DBG_WINNTSIF "WinntSif"
|
|
|
|
/*++
|
|
|
|
Macro Expansion List Description:
|
|
|
|
WINNTSIF_SECTIONS lists all of the sections in winnt.sif that will be populated by the
|
|
winntsif processing code. The engine will enumerate each section in this list and then
|
|
process the settings associated with that section.
|
|
|
|
|
|
|
|
Line Syntax:
|
|
|
|
STRSECTION(SectionName,SettingsList)
|
|
FUNSECTION(SectionFunction,SettingsList)
|
|
|
|
Arguments:
|
|
|
|
SectionName - This is a string containing the name of the section that is processed.
|
|
|
|
SectionFunction - This is an enumeration function that is called for sections that will
|
|
have multiple instances. This function returns a new section name each
|
|
time it is called, until there are no more instances to process.
|
|
At that time, this function returns NULL, ending the processing if the
|
|
associated section settings.
|
|
|
|
SettingsList - A list of settings associated with each function. Each of these settings
|
|
will be processed for the given section (or multiple sections in the case
|
|
of FUNSECTION lines..) See the description of the <X>_SECTION_SETTINGS
|
|
macro for more details on these settings.
|
|
|
|
|
|
Variables Generated From List:
|
|
|
|
g_SectionList
|
|
|
|
--*/
|
|
|
|
/*++
|
|
|
|
Macro Expansion List Description:
|
|
|
|
<X>_SECTION_SETTINGS lists the settings to be processed for the section X. Each section in the
|
|
WINNTSIF_SECTIONS macro above contains a list of these settings..
|
|
|
|
Line Syntax:
|
|
|
|
FUNDATA(CreationFunction,SettingName,DataFunction)
|
|
STRDATA(CreationFunction,SettingName,DataString)
|
|
REGDATA(CreationFunction,SettingName,RegKey,RegValue)
|
|
|
|
|
|
Arguments:
|
|
|
|
CreationFunction - This is an optional boolean function which returns TRUE if the setting should
|
|
be written, FALSE if it should be skipped.
|
|
|
|
SettingName - A string containing the name of the setting being processed.
|
|
|
|
DataFunction - A Function which returns the string data to be written for the specified setting,
|
|
or NULL if nothing is to be written.
|
|
|
|
DataString - The actual string to write for the data of the setting.
|
|
|
|
RegKey/RegValue - The Key and value to use to retrieve the data to be written for the setting from
|
|
the registry.
|
|
|
|
Variables Generated From List:
|
|
|
|
Used with WINNTSIF_SECTIONS to generate g_SectionList.
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#define WINNTSIF_SECTIONS \
|
|
STRSECTION(WINNT_DATA,DATA_SECTION_SETTINGS) \
|
|
STRSECTION(S_UNATTENDED,UNATTENDED_SECTION_SETTINGS) \
|
|
STRSECTION(S_GUIUNATTENDED,GUIUNATTENDED_SECTION_SETTINGS) \
|
|
STRSECTION(S_USERDATA,USERDATA_SECTION_SETTINGS) \
|
|
STRSECTION(S_DISPLAY,DISPLAY_SECTION_SETTINGS) \
|
|
FUNSECTION(pNetAdapterSections,FUNDATA(NULL,S_INFID,pGetNetAdapterPnpId)) \
|
|
STRSECTION(S_NETWORKING,NETWORKING_SECTION_SETTINGS) \
|
|
STRSECTION(S_PAGE_IDENTIFICATION,IDENTIFICATION_SECTION_SETTINGS) \
|
|
STRSECTION(S_PAGE_NETPROTOCOLS,NETPROTOCOLS_SECTION_SETTINGS) \
|
|
STRSECTION(S_MS_NWIPX,FUNDATA(NULL,S_ADAPTERSECTIONS,pGetAdaptersWithIpxBindings)) \
|
|
FUNSECTION(pIpxAdapterSections,IPX_ADAPTER_SECTION_SETTINGS) \
|
|
FUNSECTION(pHomenetSection, HOMENET_SECTION_SETTINGS) \
|
|
STRSECTION(S_MS_TCPIP,TCPIP_SECTION_SETTINGS) \
|
|
FUNSECTION(pTcpAdapterSections,TCP_ADAPTER_SECTION_SETTINGS) \
|
|
STRSECTION(S_PAGE_NETCLIENTS,NETCLIENTS_SECTION_SETTINGS) \
|
|
STRSECTION(S_SERVICESTARTTYPES,SERVICESTARTTYPES_SECTION_SETTINGS) \
|
|
STRSECTION(S_PAGE_NETSERVICES,NETSERVICES_SECTION_SETTINGS) \
|
|
STRSECTION(S_NETOPTIONALCOMPONENTS,NETOPTIONALCOMPONENTS_SECTION_SETTINGS) \
|
|
STRSECTION(S_MSRASCLI,STRDATA(pIsRasInstalled,S_PARAMSSECTION,S_PARAMSRASCLI)) \
|
|
STRSECTION(S_PARAMSRASCLI,PARAMSRASCLI_SECTION_SETTINGS) \
|
|
FUNSECTION(pRasPortSections,RASPORT_SECTION_SETTINGS) \
|
|
STRSECTION(S_MS_NWCLIENT,NWCLIENT_SECTION_SETTINGS) \
|
|
FUNSECTION(pBindingSections,FUNDATA(NULL,NULL,NULL)) \
|
|
STRSECTION(S_REGIONALSETTINGS,REGIONALSETTINGS_SECTION_SETTINGS) \
|
|
|
|
#if 0
|
|
|
|
// this was moved to winnt32 dll as part of Setup components update
|
|
STRSECTION(WINNT_WIN95UPG_95_DIR_A,FUNDATA(NULL,WINNT_WIN95UPG_NTKEY_A,pGetReplacementDll)) \
|
|
|
|
#endif
|
|
|
|
//
|
|
// [Data]
|
|
//
|
|
#define DATA_SECTION_SETTINGS \
|
|
FUNDATA(NULL,WINNT_D_MIGTEMPDIR,pGetTempDir) \
|
|
FUNDATA(NULL,WINNT_D_WIN9XSIF,pGetWin9xSifDir) \
|
|
STRDATA(NULL,WINNT_U_UNATTENDMODE,WINNT_A_DEFAULTHIDE) \
|
|
FUNDATA(NULL,WINNT_D_INSTALLDIR,pGetWinDir) \
|
|
FUNDATA(NULL,WINNT_D_WIN9XBOOTDRIVE,pGetWin9xBootDrive) \
|
|
FUNDATA(NULL,WINNT_D_GUICODEPAGEOVERRIDE,pGetGuiCodePage) \
|
|
FUNDATA(NULL,WINNT_D_BACKUP_LIST,pBackupFileList) \
|
|
FUNDATA(NULL,WINNT_D_ROLLBACK_MOVE,pUninstallMoveFileList) \
|
|
FUNDATA(NULL,WINNT_D_ROLLBACK_DELETE,pUninstallDelFileList) \
|
|
FUNDATA(NULL,WINNT_D_ROLLBACK_DELETE_DIR,pUninstallDelDirList) \
|
|
FUNDATA(NULL,S_ROLLBACK_MK_DIRS,pUninstallMkDirList) \
|
|
|
|
//
|
|
// [Unattended]
|
|
//
|
|
#define UNATTENDED_SECTION_SETTINGS \
|
|
STRDATA(NULL,S_NOWAITAFTERTEXTMODE,S_ONE) \
|
|
STRDATA(NULL,S_NOWAITAFTERGUIMODE,S_ONE) \
|
|
STRDATA(NULL,S_CONFIRMHARDWARE,S_NO) \
|
|
FUNDATA(NULL,S_KEYBOARDLAYOUT,pGetKeyboardLayout) \
|
|
FUNDATA(NULL,S_KEYBOARDHARDWARE,pGetKeyboardHardware)
|
|
|
|
//
|
|
// [GuiUnattended]
|
|
//
|
|
#define GUIUNATTENDED_SECTION_SETTINGS \
|
|
FUNDATA(NULL,S_TIMEZONE,pGetTimeZone) \
|
|
STRDATA(NULL,S_SERVERTYPE,S_STANDALONE) \
|
|
FUNDATA(NULL,WINNT_US_ADMINPASS,pSetAdminPassword)
|
|
|
|
|
|
//
|
|
// [UserData]
|
|
//
|
|
#define USERDATA_SECTION_SETTINGS \
|
|
FUNDATA(NULL,S_FULLNAME,pGetFullName) \
|
|
REGDATA(NULL,S_ORGNAME,S_WINDOWS_CURRENTVERSION,S_REGISTEREDORGANIZATION) \
|
|
FUNDATA(NULL,S_COMPUTERNAME,pGetComputerName) \
|
|
|
|
//
|
|
// [Display]
|
|
//
|
|
#define DISPLAY_SECTION_SETTINGS \
|
|
FUNDATA(NULL,S_BITSPERPEL,pGetBitsPerPixel) \
|
|
FUNDATA(NULL,S_XRESOLUTION,pGetXResolution) \
|
|
FUNDATA(NULL,S_YRESOLUTION,pGetYResolution) \
|
|
FUNDATA(NULL,S_VREFRESH,pGetVerticalRefreshRate) \
|
|
|
|
//
|
|
// [Networking]
|
|
//
|
|
#define NETWORKING_SECTION_SETTINGS \
|
|
STRDATA(pIsNetworkingInstalled,S_PROCESSPAGESECTIONS,S_YES) \
|
|
STRDATA(pIsNetworkingInstalled,S_UPGRADEFROMPRODUCT,S_WINDOWS95) \
|
|
FUNDATA(pIsNetworkingInstalled,S_BUILDNUMBER,pGetBuildNumber)
|
|
|
|
//
|
|
// [Identification]
|
|
//
|
|
#define IDENTIFICATION_SECTION_SETTINGS \
|
|
FUNDATA(pIsNetworkingInstalled,S_JOINDOMAIN,pGetUpgradeDomainName) \
|
|
FUNDATA(pIsNetworkingInstalled,S_JOINWORKGROUP,pGetUpgradeWorkgroupName)
|
|
|
|
//
|
|
// [NetProtocols]
|
|
//
|
|
#define NETPROTOCOLS_SECTION_SETTINGS \
|
|
STRDATA(pIsNwIpxInstalled,S_MS_NWIPX,S_MS_NWIPX) \
|
|
STRDATA(pIsTcpIpInstalled,S_MS_TCPIP,S_MS_TCPIP) \
|
|
|
|
//
|
|
// These protocols were removed from Whistler, don't migrate settings for them
|
|
//
|
|
// STRDATA(pIsNetBeuiInstalled,S_MS_NETBEUI,S_MS_NETBEUI) \
|
|
// STRDATA(pIsMsDlcInstalled,S_MS_DLC,S_MS_DLC) \
|
|
|
|
//
|
|
// [Adapter<x>.ipx]
|
|
//
|
|
#define IPX_ADAPTER_SECTION_SETTINGS \
|
|
FUNDATA(NULL,S_SPECIFICTO,pSpecificTo) \
|
|
FUNDATA(NULL,S_PKTTYPE,pGetIpxPacketType) \
|
|
FUNDATA(NULL,S_NETWORKNUMBER,pGetIpxNetworkNumber) \
|
|
|
|
|
|
//
|
|
// [MS_TCPIP]
|
|
//
|
|
#define TCPIP_SECTION_SETTINGS \
|
|
FUNDATA(pIsTcpIpInstalled,S_ADAPTERSECTIONS,pGetAdaptersWithTcpBindings) \
|
|
FUNDATA(pIsTcpIpInstalled,S_DNS,pGetDnsStatus) \
|
|
REGDATA(pIsDnsEnabled,S_DNSHOST,S_MSTCP_KEY,S_HOSTNAMEVAL) \
|
|
FUNDATA(pIsDnsEnabled,S_DNSSUFFIXSEARCHORDER,pGetDnsSuffixSearchOrder) \
|
|
REGDATA(pIsTcpIpInstalled,S_SCOPEID,S_MSTCP_KEY,S_SCOPEID) \
|
|
REGDATA(pIsTcpIpInstalled,S_IMPORTLMHOSTSFILE,S_MSTCP_KEY,S_LMHOSTS) \
|
|
|
|
//
|
|
// [Adapter<x>.tcpip]
|
|
//
|
|
#define TCP_ADAPTER_SECTION_SETTINGS \
|
|
FUNDATA(NULL,S_SPECIFICTO,pSpecificTo) \
|
|
FUNDATA(NULL,S_DHCP,pGetDhcpStatus) \
|
|
STRDATA(NULL,S_NETBIOSOPTION,S_ONE) \
|
|
FUNDATA(pHasStaticIpAddress,S_IPADDRESS,pGetIpAddress) \
|
|
FUNDATA(pHasStaticIpAddress,S_SUBNETMASK,pGetSubnetMask) \
|
|
FUNDATA(NULL,S_DEFAULTGATEWAY,pGetGateway) \
|
|
FUNDATA(pIsDnsEnabled,S_DNSSERVERSEARCHORDER,pGetDnsServerSearchOrder) \
|
|
REGDATA(pIsDnsEnabled,S_DNSDOMAIN,S_MSTCP_KEY,S_DOMAINVAL) \
|
|
FUNDATA(NULL,S_WINS,pGetWinsStatus) \
|
|
FUNDATA(NULL,S_WINSSERVERLIST,pGetWinsServers)
|
|
|
|
|
|
#define HOMENET_SECTION_SETTINGS \
|
|
FUNDATA(pExternalIsAdapter,S_EXTERNAL_ADAPTER, pIcsExternalAdapter) \
|
|
FUNDATA(pExternalIsRasConn,S_EXTERNAL_CONNECTION_NAME, pIcsExternalConnectionName) \
|
|
FUNDATA(NULL, S_INTERNAL_IS_BRIDGE, pInternalIsBridge) \
|
|
FUNDATA(pHasInternalAdapter, S_INTERNAL_ADAPTER, pInternalAdapter) \
|
|
FUNDATA(pHasBridge, S_BRIDGE, pBridge) \
|
|
FUNDATA(NULL, S_DIAL_ON_DEMAND, pDialOnDemand) \
|
|
REGDATA(NULL, S_ENABLEICS, S_ICS_KEY, S_ENABLED) \
|
|
REGDATA(NULL, S_SHOW_TRAY_ICON, S_ICS_KEY, S_SHOW_TRAY_ICON) \
|
|
STRDATA(NULL, S_ISW9XUPGRADE, S_YES)
|
|
|
|
|
|
//
|
|
// [NetClients]
|
|
//
|
|
#define NETCLIENTS_SECTION_SETTINGS \
|
|
STRDATA(pIsWkstaInstalled,S_MS_NETCLIENT,S_MS_NETCLIENT) \
|
|
STRDATA(pIsNwClientInstalled,S_MS_NWCLIENT,S_MS_NWCLIENT) \
|
|
|
|
//
|
|
// [ServiceStartTypes]
|
|
//
|
|
#define SERVICESTARTTYPES_SECTION_SETTINGS \
|
|
STRDATA(pDisableBrowserService,S_BROWSER,TEXT("3")) \
|
|
|
|
|
|
//
|
|
// [NetServices]
|
|
//
|
|
#define NETSERVICES_SECTION_SETTINGS \
|
|
STRDATA(pInstallMsServer,S_MS_SERVER,S_MS_SERVER) \
|
|
STRDATA(pIsRasInstalled,S_MSRASCLI,S_MSRASCLI)
|
|
|
|
//
|
|
// [NetOptionalComponents]
|
|
//
|
|
#define NETOPTIONALCOMPONENTS_SECTION_SETTINGS \
|
|
STRDATA(pIsSnmpInstalled,S_SNMP,S_ONE) \
|
|
STRDATA(pIsUpnpInstalled,S_UPNP,S_ONE)
|
|
|
|
//
|
|
// [params.rascli]
|
|
//
|
|
#define PARAMSRASCLI_SECTION_SETTINGS \
|
|
STRDATA(pIsRasInstalled,S_DIALOUTPROTOCOLS,S_ALL) \
|
|
FUNDATA(pIsRasInstalled,S_PORTSECTIONS,pGetRasPorts)
|
|
|
|
//
|
|
// [com<x>]
|
|
//
|
|
#define RASPORT_SECTION_SETTINGS \
|
|
FUNDATA(NULL,S_PORTNAME,pRasPortName) \
|
|
STRDATA(NULL,S_PORTUSAGE,S_CLIENT)
|
|
|
|
//
|
|
// [NwClient]
|
|
//
|
|
#define NWCLIENT_SECTION_SETTINGS \
|
|
REGDATA(pIsNwClientInstalled,S_PREFERREDSERVER,S_AUTHAGENTREG,S_AUTHENTICATINGAGENT) \
|
|
REGDATA(pIsNwClientInstalled,S_DEFAULTCONTEXT,S_NWREDIRREG,S_DEFAULTNAMECONTEXT) \
|
|
REGDATA(pIsNwClientInstalled,S_DEFAULTTREE,S_NWREDIRREG,S_PREFERREDNDSTREE) \
|
|
FUNDATA(pIsNwClientInstalled,S_LOGONSCRIPT,pGetScriptProcessingStatus) \
|
|
|
|
|
|
#define REGIONALSETTINGS_SECTION_SETTINGS \
|
|
FUNDATA(NULL,S_LANGUAGEGROUP,pGetLanguageGroups) \
|
|
REGDATA(NULL,S_LANGUAGE,S_SYSTEMLOCALEREG,TEXT("")) \
|
|
|
|
|
|
|
|
//
|
|
// typedefs for the various functions prototypes used by the winntsif code.
|
|
//
|
|
typedef BOOL (* CREATION_FUNCTION) (VOID);
|
|
typedef PCTSTR (* DATA_FUNCTION) (VOID);
|
|
typedef PCTSTR (* SECTION_FUNCTION) (VOID);
|
|
|
|
//
|
|
// The SETTING_TYPE enum contains all of the possible Types of settings which
|
|
// may occur in the macro expansion list above.
|
|
//
|
|
typedef enum {
|
|
FUNCTION_SETTING = 1,
|
|
STRING_SETTING,
|
|
REGISTRY_SETTING,
|
|
LAST_SETTING
|
|
} SETTING_TYPE;
|
|
|
|
|
|
//
|
|
// This structure wraps a key and a value inside a single structure. It is accessed
|
|
// within the union below.
|
|
//
|
|
typedef struct {
|
|
PCTSTR Key;
|
|
PCTSTR Value;
|
|
} REGKEYANDVALUE, *PREGKEYANDVALUE;
|
|
|
|
//
|
|
// SETTING contains the information to create a single setting within
|
|
// a winntsif file.
|
|
//
|
|
typedef struct {
|
|
|
|
SETTING_TYPE SettingType;
|
|
CREATION_FUNCTION CreationFunction;
|
|
PCTSTR KeyName;
|
|
|
|
|
|
|
|
//
|
|
// The data depends on the SETTING_TYPE above.
|
|
//
|
|
union {
|
|
REGKEYANDVALUE Registry;
|
|
DATA_FUNCTION Function;
|
|
PCTSTR String;
|
|
} Data;
|
|
|
|
} SETTING, *PSETTING;
|
|
|
|
|
|
//
|
|
// Section is the toplevel hierarchy used for the winntsif file.
|
|
// Each section contains a list of settings that will be processed and
|
|
// possibly written for that section.
|
|
//
|
|
#define MAX_SETTINGS 16
|
|
typedef struct {
|
|
|
|
PTSTR SectionString;
|
|
SECTION_FUNCTION SectionFunction;
|
|
SETTING SettingList[MAX_SETTINGS];
|
|
|
|
} SECTION, *PSECTION;
|
|
|
|
#define FUNDATA(create,key,datafunction) {FUNCTION_SETTING, (create), (key), {(PTSTR) (datafunction), NULL}},
|
|
#define STRDATA(create,key,datastring) {STRING_SETTING, (create), (key), {(PTSTR) (datastring), NULL}},
|
|
#define REGDATA(create,key,regkey,regvalue) {REGISTRY_SETTING, (create), (key), {(regkey), (regvalue)}},
|
|
|
|
#define STRSECTION(section,list) {(section),NULL,{list /*,*/ {LAST_SETTING,NULL,NULL,{NULL,NULL}}}},
|
|
#define FUNSECTION(function,list) {NULL,(function),{list /*,*/ {LAST_SETTING,NULL,NULL,{NULL,NULL}}}},
|
|
|
|
|
|
typedef struct {
|
|
|
|
PCTSTR Text;
|
|
BOOL Installed;
|
|
|
|
|
|
} BINDINGPART, *PBINDINGPART;
|
|
|
|
#define NUM_PROTOCOLS 4
|
|
#define NUM_CLIENTS 2
|
|
|
|
typedef struct {
|
|
|
|
BINDINGPART Clients[NUM_CLIENTS];
|
|
BINDINGPART Protocols[NUM_PROTOCOLS];
|
|
|
|
} BINDINGINFO, *PBINDINGINFO;
|
|
|
|
BINDINGINFO g_BindingInfo =
|
|
{{{S_MS_NETCLIENT, FALSE},{S_MS_NWCLIENT, FALSE}},{{S_MS_TCPIP, FALSE},{S_MS_NWIPX, FALSE},{S_MS_NETBEUI, FALSE}, {S_MS_DLC, FALSE}}};
|
|
|
|
|
|
|
|
TCHAR g_CurrentAdapter[MEMDB_MAX]; // During adapter/section enumeration, contains current adapter name.
|
|
TCHAR g_CurrentSection[MEMDB_MAX]; // During some section enums, contains current section name.
|
|
TCHAR g_TempBuffer[MEMDB_MAX]; // Contains the current value returned from pGetRegistryValue
|
|
MEMDB_ENUM g_TempEnum; // A global enumerator that may be used by various section functions.
|
|
HINF g_IntlInf;
|
|
INFSTRUCT g_InfStruct = INITINFSTRUCT_POOLHANDLE;
|
|
POOLHANDLE g_LocalePool;
|
|
HASHTABLE g_LocaleTable;
|
|
|
|
BOOL g_fIcsAdapterInPlace = FALSE;
|
|
BOOL g_fHasIcsExternalAdapter = FALSE;
|
|
TCHAR g_IcsAdapter[MEMDB_MAX] = {0};
|
|
TCHAR g_IcsExternalAdapter[MEMDB_MAX] = {0};
|
|
BOOL g_fIcsInternalIsBridge = FALSE;
|
|
|
|
#define S_REGIONALSETTINGS TEXT("RegionalSettings")
|
|
|
|
#define CLEARBUFFER() ZeroMemory(g_TempBuffer,MEMDB_MAX * sizeof (TCHAR));
|
|
//
|
|
// Helper and Miscellaneous functions..
|
|
//
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetRegistryValue is a utility wrapper used for getting data out of the
|
|
registry. Because winntsif processing requires frequent and very similar
|
|
reads from the registry, this wrapper is modified to be a little friendlier
|
|
to this type of processing than the normal functions in reg.h. This
|
|
function reads the data from the registry, and packs it into a multisz. It
|
|
is capable of handling REG_DWORD, REG_MULTI_SZ, and REG_SZ style registry
|
|
data. The data is stored in g_TempBuffer as well as being passed back
|
|
through the return value. If the specified Key/Value does not exist in the
|
|
registry, or the function is unable to retrieve a value, NULL is returned.
|
|
|
|
Arguments:
|
|
|
|
KeyString - Contains the Key to be read from the registry.
|
|
ValueString - Contains the Value to be read from the registry.
|
|
|
|
Return Value:
|
|
|
|
A pointer to a multisz containing the data if it could be read from the
|
|
registry, NULL otherwise.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetRegistryValue (
|
|
IN PCTSTR KeyString,
|
|
IN PCTSTR ValueString
|
|
)
|
|
{
|
|
PCTSTR rString = NULL;
|
|
HKEY key = NULL;
|
|
PBYTE data = NULL;
|
|
DWORD type = REG_NONE;
|
|
LONG rc = ERROR_SUCCESS;
|
|
PTSTR end;
|
|
|
|
MYASSERT(KeyString && ValueString);
|
|
|
|
//
|
|
// Open registry key.
|
|
//
|
|
key = OpenRegKeyStr(KeyString);
|
|
|
|
if (!key) {
|
|
DEBUGMSG((DBG_WINNTSIF, "Key %s does not exist.",KeyString));
|
|
return NULL;
|
|
}
|
|
__try {
|
|
//
|
|
// Get type of data
|
|
//
|
|
rc = RegQueryValueExA (key, ValueString, NULL, &type, NULL, NULL);
|
|
if (rc != ERROR_SUCCESS) {
|
|
DEBUGMSG((DBG_WINNTSIF,"RegQueryValueEx failed for %s[%s]. Value may not exist.",KeyString,ValueString));
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
MYASSERT(type == REG_DWORD || type == REG_MULTI_SZ || type == REG_SZ);
|
|
|
|
//
|
|
// Get data and move it to a multistring
|
|
//
|
|
data = GetRegValueData (key, ValueString);
|
|
|
|
if (!data) {
|
|
DEBUGMSG((DBG_WHOOPS,"pGetRegistryValue: RegQueryValueEx succeeded, but GetRegValueData failed...Could be a problem."));
|
|
return NULL;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
|
|
|
|
switch (type) {
|
|
|
|
case REG_DWORD:
|
|
wsprintf(g_TempBuffer,"%u", *(DWORD*) data);
|
|
break;
|
|
case REG_SZ:
|
|
StringCopy(g_TempBuffer,(PCTSTR) data);
|
|
//
|
|
// some data is stored as REG_SZ, but is actually a comma separated multisz
|
|
// append one more NULL to the end
|
|
//
|
|
end = GetEndOfString (g_TempBuffer) + 1;
|
|
*end = 0;
|
|
break;
|
|
case REG_MULTI_SZ:
|
|
|
|
end = (PTSTR) data;
|
|
while (*end) {
|
|
end = GetEndOfString (end) + 1;
|
|
}
|
|
memcpy(g_TempBuffer,data,(LONG)end - (LONG)data);
|
|
break;
|
|
default:
|
|
LOG ((LOG_ERROR,"Unexpected registry type found while creating Setup answer file."));
|
|
break;
|
|
};
|
|
|
|
} __finally {
|
|
|
|
//
|
|
// Clean up resources.
|
|
//
|
|
CloseRegKey(key);
|
|
if (data) {
|
|
MemFree(g_hHeap, 0, data);
|
|
}
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
BOOL
|
|
CALLBACK
|
|
pEnumLocalesFunc (
|
|
IN PTSTR Locale
|
|
)
|
|
{
|
|
|
|
PTSTR group = NULL;
|
|
PTSTR directory = NULL;
|
|
|
|
|
|
//
|
|
// Get the language group.
|
|
//
|
|
if (InfFindFirstLine (g_IntlInf, S_LOCALES, Locale, &g_InfStruct)) {
|
|
|
|
group = InfGetStringField (&g_InfStruct, 3);
|
|
|
|
if (group) {
|
|
group = PoolMemDuplicateString (g_LocalePool, group);
|
|
|
|
}
|
|
ELSE_DEBUGMSG ((DBG_WARNING, "Unable to retrieve group data for locale %s.", Locale));
|
|
}
|
|
|
|
//
|
|
// Get the language directory.
|
|
//
|
|
if (group && InfFindFirstLine (g_IntlInf, S_LANGUAGEGROUPS, group, &g_InfStruct)) {
|
|
|
|
directory = InfGetStringField (&g_InfStruct, 2);
|
|
if (directory) {
|
|
directory = PoolMemDuplicateString (g_LocalePool, directory);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Save the information into the locale hash table.
|
|
//
|
|
if (group) {
|
|
|
|
HtAddStringAndData (g_LocaleTable, group, &directory);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
pBuildLanguageData (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
//
|
|
// Allocate needed resources.
|
|
//
|
|
g_LocaleTable = HtAllocWithData (sizeof (PTSTR));
|
|
g_LocalePool = PoolMemInitNamedPool (TEXT("Locale Pool"));
|
|
|
|
|
|
//
|
|
// Read data in from intl.inf. This is used to gather
|
|
// the necessary information we need for each installed
|
|
// locale.
|
|
//
|
|
g_IntlInf = InfOpenInfInAllSources (S_INTLINF);
|
|
|
|
if (g_IntlInf != INVALID_HANDLE_VALUE) {
|
|
|
|
EnumSystemLocales (pEnumLocalesFunc, LCID_INSTALLED);
|
|
InfCloseInfFile (g_IntlInf);
|
|
}
|
|
|
|
InfCleanUpInfStruct (&g_InfStruct);
|
|
|
|
}
|
|
|
|
PTSTR
|
|
GetNeededLangDirs (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
UINT bytes = 0;
|
|
PTSTR rDirs = NULL;
|
|
HASHTABLE_ENUM e;
|
|
GROWBUFFER buf = GROWBUF_INIT;
|
|
PTSTR dir;
|
|
//
|
|
// Gather language data.
|
|
//
|
|
pBuildLanguageData ();
|
|
if (EnumFirstHashTableString (&e, g_LocaleTable)) {
|
|
do {
|
|
|
|
if (e.ExtraData) {
|
|
dir = *((PTSTR *) e.ExtraData);
|
|
}
|
|
else {
|
|
dir = NULL;
|
|
}
|
|
|
|
//
|
|
// Some language groups do not require an optional dir.
|
|
//
|
|
if (dir && *dir) {
|
|
MultiSzAppend (&buf, dir);
|
|
}
|
|
|
|
} while (EnumNextHashTableString (&e));
|
|
}
|
|
|
|
if (buf.Buf) {
|
|
bytes = SizeOfMultiSz (buf.Buf);
|
|
}
|
|
if (bytes) {
|
|
rDirs = PoolMemGetMemory (g_LocalePool, bytes);
|
|
CopyMemory (rDirs, buf.Buf, bytes);
|
|
}
|
|
|
|
FreeGrowBuffer (&buf);
|
|
|
|
return rDirs;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This simple helper function determines wether a specific net component has
|
|
bindings or not.
|
|
|
|
Arguments:
|
|
|
|
NetComponent - Contains the Networking component to enumerate.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the specified Networking Component has bindings, FALSE
|
|
otherwise.
|
|
|
|
|
|
--*/
|
|
|
|
|
|
BOOL
|
|
pDoesNetComponentHaveBindings (
|
|
IN PCTSTR NetComponent
|
|
)
|
|
{
|
|
PTSTR keyString = NULL;
|
|
REGKEY_ENUM e;
|
|
|
|
|
|
keyString = JoinPaths(S_ENUM_NETWORK_KEY,NetComponent);
|
|
|
|
if (!EnumFirstRegKeyStr (&e, keyString)) {
|
|
FreePathString(keyString);
|
|
return FALSE;
|
|
}
|
|
|
|
FreePathString(keyString);
|
|
AbortRegKeyEnum (&e);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGatherNetAdapterInfo is responsible for preprocessing the NetAdapter
|
|
information in the registry in order to build up a tree of information
|
|
about these adapters in memdb. This tree contains information about each
|
|
adapter, including its pnpid, its network bindings, and the nettrans keys
|
|
for each of those bindings.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
|
|
VOID
|
|
pGatherNetAdapterInfo (
|
|
VOID
|
|
)
|
|
{
|
|
NETCARD_ENUM eNetCard;
|
|
REGVALUE_ENUM eRegVal;
|
|
UINT curAdapter = 1;
|
|
UINT offset = 0;
|
|
TCHAR adapterString[30];
|
|
PCTSTR bindingsKey = NULL;
|
|
PCTSTR networkKey = NULL;
|
|
PCTSTR netTransKey = NULL;
|
|
PTSTR p = NULL;
|
|
HKEY hKey;
|
|
BOOL fBoundToTCP = FALSE;
|
|
|
|
|
|
ZeroMemory(g_IcsAdapter, sizeof(g_IcsAdapter));
|
|
//
|
|
// Enumerate all net cards, we'll create
|
|
// entries for all of the non-dialup PNP adapters
|
|
// with the following proviso: If more than one net card is specified,
|
|
//
|
|
|
|
if (EnumFirstNetCard(&eNetCard)) {
|
|
|
|
__try {
|
|
|
|
do {
|
|
|
|
fBoundToTCP = FALSE;
|
|
//
|
|
// Skip the Dial-Up Adapter.
|
|
//
|
|
if (StringIMatch(eNetCard.Description,S_DIALUP_ADAPTER_DESC)) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Create the adapter section name for this adapter.
|
|
//
|
|
wsprintf(adapterString,TEXT("Adapter%u"),curAdapter);
|
|
|
|
//
|
|
// Next, we need to enumerate all of the bindings for this adapter
|
|
// and create nettrans keys for each.
|
|
//
|
|
|
|
bindingsKey = JoinPaths(eNetCard.CurrentKey,S_BINDINGS);
|
|
|
|
//
|
|
// Open this key and enumerate the bindings underneath it.
|
|
//
|
|
if ((hKey = OpenRegKeyStr(bindingsKey)) != NULL) {
|
|
if (EnumFirstRegValue(&eRegVal,hKey)) {
|
|
|
|
do {
|
|
|
|
//
|
|
// For each protocol entry, build up the nettrans key.
|
|
//
|
|
networkKey = JoinPaths(S_NETWORK_BRANCH,eRegVal.ValueName);
|
|
netTransKey = JoinPaths(S_SERVICECLASS,pGetRegistryValue(networkKey,S_DRIVERVAL));
|
|
|
|
//
|
|
// Save this key into memdb.
|
|
//
|
|
MemDbSetValueEx(
|
|
MEMDB_CATEGORY_NETTRANSKEYS,
|
|
adapterString,
|
|
netTransKey,
|
|
NULL,
|
|
0,
|
|
&offset
|
|
);
|
|
|
|
|
|
//
|
|
// link it into the adapters section.
|
|
//
|
|
|
|
p = _tcschr(eRegVal.ValueName,TEXT('\\'));
|
|
if (p) {
|
|
*p = 0;
|
|
}
|
|
|
|
MemDbSetValueEx(
|
|
MEMDB_CATEGORY_NETADAPTERS,
|
|
adapterString,
|
|
S_BINDINGS,
|
|
eRegVal.ValueName,
|
|
offset,
|
|
NULL
|
|
);
|
|
|
|
if ((!fBoundToTCP) && 0 == lstrcmpi(eRegVal.ValueName, S_MSTCP))
|
|
{
|
|
fBoundToTCP = TRUE;
|
|
}
|
|
|
|
FreePathString(networkKey);
|
|
FreePathString(netTransKey);
|
|
|
|
} while (EnumNextRegValue(&eRegVal));
|
|
}
|
|
|
|
CloseRegKey(hKey);
|
|
}
|
|
|
|
//
|
|
// Finally, store the pnpid for this card into memdb.
|
|
//
|
|
|
|
|
|
MemDbSetValueEx(
|
|
MEMDB_CATEGORY_NETADAPTERS,
|
|
adapterString,
|
|
MEMDB_FIELD_PNPID,
|
|
eNetCard.HardwareId && *eNetCard.HardwareId ? eNetCard.HardwareId : eNetCard.CompatibleIDs,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
//store the driver key for this card into memdb
|
|
MemDbSetValueEx(
|
|
MEMDB_CATEGORY_NETADAPTERS,
|
|
adapterString,
|
|
MEMDB_FIELD_DRIVER,
|
|
eNetCard.HardwareEnum.Driver,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if (fBoundToTCP && 0 == lstrcmp(eNetCard.CompatibleIDs, S_ICSHARE))
|
|
{
|
|
//Save the ICSHARE adapter name for further use
|
|
lstrcpyn(g_IcsAdapter, adapterString, sizeof(g_IcsAdapter)/sizeof(g_IcsAdapter[0]));
|
|
}
|
|
|
|
FreePathString(bindingsKey);
|
|
|
|
curAdapter++;
|
|
|
|
} while (EnumNextNetCard(&eNetCard));
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
EnumNetCardAbort(&eNetCard);
|
|
LOG ((LOG_ERROR,"Caught exception while gathering data about network adapters."));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pEnumFirstAdapterByBinding and pEnumNextAdapterByBinding are memdb enumeration wrapperz
|
|
that are used by several functions to enumerate based upon a certain protocol. This is
|
|
necessary in order to build the per-adapter portions of the winnt.sif file.
|
|
|
|
Arguments:
|
|
|
|
Enum - A pointer to a valid MEMDB_ENUM structure.
|
|
Binding - Contains the binding to enumerate upon.
|
|
|
|
Return Value:
|
|
|
|
TRUE if an adapter was found with the specified binding, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
|
|
BOOL
|
|
pEnumFirstAdapterByBinding (
|
|
IN PMEMDB_ENUM Enum,
|
|
IN PCTSTR Binding
|
|
)
|
|
{
|
|
|
|
BOOL rBindingFound = FALSE;
|
|
TCHAR key[MEMDB_MAX];
|
|
UINT unused;
|
|
|
|
|
|
if (MemDbEnumItems(Enum,MEMDB_CATEGORY_NETADAPTERS)) {
|
|
|
|
do {
|
|
|
|
MemDbBuildKey(key,MEMDB_CATEGORY_NETADAPTERS,Enum -> szName,S_BINDINGS,Binding);
|
|
rBindingFound = MemDbGetValue(key,&unused);
|
|
|
|
} while(!rBindingFound && MemDbEnumNextValue(Enum));
|
|
}
|
|
|
|
return rBindingFound;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pEnumNextAdapterByBinding (
|
|
IN OUT PMEMDB_ENUM Enum,
|
|
IN PCTSTR Binding
|
|
)
|
|
{
|
|
|
|
BOOL rBindingFound = FALSE;
|
|
TCHAR key[MEMDB_MAX];
|
|
UINT unused;
|
|
|
|
while(!rBindingFound && MemDbEnumNextValue(Enum)) {
|
|
|
|
MemDbBuildKey(key,MEMDB_CATEGORY_NETADAPTERS,Enum -> szName,S_BINDINGS,Binding);
|
|
rBindingFound = MemDbGetValue(key,&unused);
|
|
|
|
}
|
|
|
|
return rBindingFound;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetNetTransBinding returns the registry key to the Network Transport
|
|
settings for a specified Adapter and Protocol.
|
|
|
|
Arguments:
|
|
|
|
Adapter - Contains the adapter to use to retrieve nettrans key information.
|
|
Protocol - Contains the protocol to use to retrieve NetTrans Key
|
|
information.
|
|
|
|
Return Value:
|
|
|
|
The NetTrans Key if successful, NULL otherwise.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetNetTransBinding(
|
|
IN PCTSTR Adapter,
|
|
IN PCTSTR Protocol
|
|
)
|
|
{
|
|
TCHAR key[MEMDB_MAX];
|
|
UINT netTransOffset;
|
|
|
|
MemDbBuildKey(key,MEMDB_CATEGORY_NETADAPTERS,Adapter,S_BINDINGS,Protocol);
|
|
if (!MemDbGetValue(key,&netTransOffset)) {
|
|
LOG ((LOG_ERROR,"Adapter %s does not have a binding to %s.",Adapter,Protocol));
|
|
return NULL;
|
|
}
|
|
|
|
if (!MemDbBuildKeyFromOffset(netTransOffset,g_TempBuffer,2,NULL)) {
|
|
DEBUGMSG((DBG_ERROR,"Error building net trans key..Adapter: %s Protocol: %s",Adapter,Protocol));
|
|
return NULL;
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pListAdaptersWithBinding is used to create a multisz of adapter section
|
|
names for adapters that have bindings to a specific networking component.
|
|
Several winntsif sections require data in this form.
|
|
|
|
Arguments:
|
|
|
|
Binding - The Binding to use as a filter in listing the adapter sections.
|
|
Suffix - an optional suffix which is attached to each adapter section
|
|
name. This is useful for building sections such as: adapter1.ipx
|
|
adapter2.ipx, etc etc.
|
|
|
|
Return Value:
|
|
|
|
The list of adapters with the specified network component binding if any,
|
|
NULL otherwise.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pListAdaptersWithBinding (
|
|
IN PCTSTR Binding,
|
|
IN PCTSTR Suffix OPTIONAL
|
|
)
|
|
{
|
|
|
|
PCTSTR rAdapterSections = NULL;
|
|
PTSTR string = g_TempBuffer;
|
|
MEMDB_ENUM e;
|
|
|
|
*string = 0;
|
|
|
|
//
|
|
// Enumerate all adapters, and create an entry for each adapter that has
|
|
// IPX bindings.
|
|
//
|
|
|
|
if (pEnumFirstAdapterByBinding(&e,Binding)) {
|
|
|
|
rAdapterSections = g_TempBuffer;
|
|
|
|
do {
|
|
|
|
//
|
|
// Add this adapter into the multistring.
|
|
//
|
|
StringCopy(string,e.szName);
|
|
if (Suffix) {
|
|
StringCat(string,Suffix);
|
|
}
|
|
string = GetEndOfString(string) + 1;
|
|
|
|
|
|
|
|
} while (pEnumNextAdapterByBinding(&e,Binding));
|
|
|
|
++string;
|
|
*string = 0;
|
|
|
|
}
|
|
|
|
return rAdapterSections;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Section Functions
|
|
//
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Each Section Function is used to build n number of sections within the
|
|
winntsif file. This is necessary for information which has multiple
|
|
sections based upon some criteria. As an example, pNetAdapterSections
|
|
returns a valid section for each adapter found on the system. When there
|
|
are no more sections needed, these functions return NULL.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
A valid section name if one is necessary or NULL otherwise.
|
|
|
|
--*/
|
|
|
|
|
|
|
|
PCTSTR
|
|
pNetAdapterSections (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
static BOOL firstTime = TRUE;
|
|
PCTSTR rSection = NULL;
|
|
BOOL moreNetAdapterInfo = FALSE;
|
|
|
|
|
|
//
|
|
// The first time this function is called it causes all net adapter information
|
|
// to be prescanned into memdb and starts an enumeration. Afterwards,
|
|
// the function simply continues the enumeration.
|
|
//
|
|
|
|
if (firstTime) {
|
|
|
|
firstTime = FALSE;
|
|
|
|
//
|
|
// The first thing we need to do is gather all of the necessary net card
|
|
// information that will be needed during winntsif processing and store
|
|
// it in a reasonable manner.
|
|
//
|
|
pGatherNetAdapterInfo();
|
|
|
|
//
|
|
// After pre-scanning all of the network adapter information into
|
|
// memdb, we simply enumerate the adapters and return the section
|
|
// names.
|
|
//
|
|
moreNetAdapterInfo = MemDbEnumItems(&g_TempEnum,MEMDB_CATEGORY_NETADAPTERS);
|
|
}
|
|
else {
|
|
|
|
moreNetAdapterInfo = MemDbEnumNextValue(&g_TempEnum);
|
|
}
|
|
|
|
if (moreNetAdapterInfo) {
|
|
|
|
StringCopy(g_CurrentAdapter,g_TempEnum.szName);
|
|
rSection = g_CurrentAdapter;
|
|
//
|
|
// We have a minor hack here. The [NetAdapters] Section is a little unique
|
|
// and doesn't fit our overall scheme. We secretly fill it in inside this
|
|
// function.
|
|
//
|
|
WriteInfKey(S_PAGE_NETADAPTERS,g_TempEnum.szName,g_TempEnum.szName);
|
|
|
|
}
|
|
|
|
return rSection;
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pIpxAdapterSections (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
static firstTime = TRUE;
|
|
PCTSTR rSectionName = NULL;
|
|
BOOL moreIpxAdapterSections;
|
|
|
|
if (firstTime) {
|
|
|
|
firstTime = FALSE;
|
|
|
|
moreIpxAdapterSections = pEnumFirstAdapterByBinding(&g_TempEnum,S_NWLINK);
|
|
}
|
|
else {
|
|
|
|
moreIpxAdapterSections = pEnumNextAdapterByBinding(&g_TempEnum,S_NWLINK);
|
|
}
|
|
|
|
|
|
if (moreIpxAdapterSections) {
|
|
|
|
StringCopy(g_CurrentAdapter,g_TempEnum.szName);
|
|
StringCopy(g_CurrentSection,g_TempEnum.szName);
|
|
StringCat(g_CurrentSection,S_IPX_SUFFIX);
|
|
rSectionName = g_CurrentSection;
|
|
}
|
|
|
|
|
|
return rSectionName;
|
|
|
|
}
|
|
|
|
PCTSTR
|
|
pTcpAdapterSections (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
static firstTime = TRUE;
|
|
PCTSTR rSectionName = NULL;
|
|
BOOL moreTcpAdapterSections;
|
|
|
|
g_fIcsAdapterInPlace = FALSE;
|
|
|
|
if (firstTime) {
|
|
|
|
firstTime = FALSE;
|
|
|
|
moreTcpAdapterSections = pEnumFirstAdapterByBinding(&g_TempEnum,S_MSTCP);
|
|
}
|
|
else {
|
|
|
|
moreTcpAdapterSections = pEnumNextAdapterByBinding(&g_TempEnum,S_MSTCP);
|
|
}
|
|
|
|
|
|
if (moreTcpAdapterSections) {
|
|
|
|
StringCopy(g_CurrentAdapter,g_TempEnum.szName);
|
|
StringCopy(g_CurrentSection,g_TempEnum.szName);
|
|
StringCat(g_CurrentSection,S_TCPIP_SUFFIX);
|
|
rSectionName = g_CurrentSection;
|
|
|
|
//if ICS is installed, in Win9x, the external LAN adapter uses the TCP settings of
|
|
//the virtual adapter -- ICSHARE. So when we save the TCP settings of this LAN
|
|
//adapter, we should save the settings of ICSHARE adapter. That's why
|
|
//we replace the g_CurrentAdapter with g_IcsAdapter
|
|
if (g_fHasIcsExternalAdapter &&
|
|
lstrcmp(g_CurrentAdapter, g_IcsExternalAdapter) == 0)
|
|
{
|
|
StringCopy(g_CurrentAdapter, g_IcsAdapter);
|
|
g_fIcsAdapterInPlace = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
return rSectionName;
|
|
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pRasPortSections (
|
|
VOID
|
|
)
|
|
{
|
|
static BOOL firstTime = TRUE;
|
|
static REGKEY_ENUM e;
|
|
static UINT modemNum = 1;
|
|
BOOL moreRasPortSections;
|
|
PCTSTR rSectionName = NULL;
|
|
|
|
|
|
|
|
if (firstTime) {
|
|
firstTime = FALSE;
|
|
moreRasPortSections = HwComp_DialUpAdapterFound() && EnumFirstRegKeyStr(&e,S_MODEMS);
|
|
}
|
|
else {
|
|
|
|
moreRasPortSections = EnumNextRegKey(&e);
|
|
|
|
}
|
|
|
|
if (moreRasPortSections) {
|
|
|
|
wsprintf(g_CurrentSection,TEXT("COM%u"),modemNum);
|
|
modemNum++;
|
|
rSectionName = g_CurrentSection;
|
|
}
|
|
|
|
return rSectionName;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
pInitializeBindingInfo (
|
|
HASHTABLE Table
|
|
)
|
|
{
|
|
MEMDB_ENUM e;
|
|
UINT i;
|
|
UINT j;
|
|
TCHAR buffer[MEMDB_MAX];
|
|
BOOL enabled=FALSE;
|
|
|
|
//
|
|
// This function will enumerate all possible binding paths on the machine and add them to
|
|
// the provided string table. Later on, specifically enabled bindings will be removed.
|
|
//
|
|
if (MemDbEnumItems (&e, MEMDB_CATEGORY_NETADAPTERS)) {
|
|
|
|
do {
|
|
|
|
for (i = 0; i < NUM_CLIENTS; i++) {
|
|
if (!g_BindingInfo.Clients[i].Installed) {
|
|
continue;
|
|
}
|
|
|
|
for (j = 0; j < NUM_PROTOCOLS; j++) {
|
|
|
|
if (g_BindingInfo.Protocols[j].Installed) {
|
|
|
|
|
|
//
|
|
// Add this client/protocl/adapter possibility to
|
|
// the hash table.
|
|
//
|
|
wsprintf (
|
|
buffer,
|
|
TEXT("%s,%s,%s"),
|
|
g_BindingInfo.Clients[i].Text,
|
|
g_BindingInfo.Protocols[j].Text,
|
|
e.szName
|
|
);
|
|
|
|
|
|
HtAddStringAndData (Table, buffer, &enabled);
|
|
|
|
|
|
|
|
DEBUGMSG ((DBG_VERBOSE, "DISABLED BINDING: %s", buffer));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < NUM_PROTOCOLS; j++) {
|
|
|
|
//
|
|
// Add the protocol adapter mapping into the table.
|
|
//
|
|
if (g_BindingInfo.Protocols[j].Installed) {
|
|
|
|
wsprintf (buffer, TEXT("%s,%s"), g_BindingInfo.Protocols[j].Text, e.szName);
|
|
HtAddStringAndData (Table, buffer, &enabled);
|
|
DEBUGMSG ((DBG_VERBOSE, "DISABLED BINDING: %s", buffer));
|
|
}
|
|
}
|
|
|
|
} while(MemDbEnumNextValue (&e));
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
pResolveEnabledBindings (
|
|
HASHTABLE Table
|
|
)
|
|
{
|
|
//
|
|
// This function removes enabled binding paths from the hash table provided
|
|
// (previously initialized with all of the binding possibilities that could
|
|
// exist on the machine..)
|
|
//
|
|
NETCARD_ENUM eCard;
|
|
REGVALUE_ENUM eValues;
|
|
REGVALUE_ENUM eProtocolValues;
|
|
UINT curAdapter = 1;
|
|
TCHAR adapterString[30];
|
|
PTSTR bindingsPath = NULL;
|
|
PTSTR protocolBindingsPath = NULL;
|
|
PTSTR protocol = NULL;
|
|
PTSTR client = NULL;
|
|
HKEY key;
|
|
HKEY protocolsKey;
|
|
TCHAR buffer[MEMDB_MAX];
|
|
HASHITEM index;
|
|
BOOL enabled=TRUE;
|
|
|
|
|
|
|
|
if (EnumFirstNetCard (&eCard)) {
|
|
|
|
__try {
|
|
|
|
do {
|
|
|
|
//
|
|
// Skip the Dial-Up Adapter.
|
|
//
|
|
if (StringIMatch (eCard.Description, S_DIALUP_ADAPTER_DESC)) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Create the adapter section name for this adapter.
|
|
//
|
|
wsprintf (adapterString, TEXT("Adapter%u"), curAdapter);
|
|
curAdapter++;
|
|
bindingsPath = JoinPaths(eCard.CurrentKey,S_BINDINGS);
|
|
|
|
key = OpenRegKeyStr (bindingsPath);
|
|
FreePathString (bindingsPath);
|
|
if (!key) {
|
|
continue;
|
|
}
|
|
|
|
if (EnumFirstRegValue (&eValues, key)) {
|
|
do {
|
|
|
|
protocol = NULL;
|
|
|
|
/*
|
|
if (IsPatternMatch (TEXT("NETBEUI*"), eValues.ValueName)) {
|
|
protocol = S_MS_NETBEUI;
|
|
} else if (IsPatternMatch (TEXT("MSDLC*"), eValues.ValueName)) {
|
|
protocol = S_MS_DLC;
|
|
}
|
|
*/
|
|
|
|
if (IsPatternMatch (TEXT("NWLINK*"), eValues.ValueName)) {
|
|
protocol = S_MS_NWIPX;
|
|
}
|
|
else if (IsPatternMatch (TEXT("MSTCP*"), eValues.ValueName)) {
|
|
protocol = S_MS_TCPIP;
|
|
|
|
}
|
|
|
|
if (!protocol) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Enable protocol <-> adapter binding.
|
|
//
|
|
|
|
wsprintf (buffer, TEXT("%s,%s"), protocol, adapterString);
|
|
index = HtFindString (Table, buffer);
|
|
|
|
if (index) {
|
|
HtSetStringData (Table, index, (PBYTE) &enabled);
|
|
|
|
}
|
|
DEBUGMSG ((DBG_VERBOSE, "ENABLED BINDING: %s", buffer));
|
|
|
|
//
|
|
// Search the bindings and enable protocol <-> client bindings
|
|
//
|
|
|
|
protocolBindingsPath = JoinPaths (S_NETWORK_BRANCH, eValues.ValueName);
|
|
bindingsPath = JoinPaths (protocolBindingsPath, S_BINDINGS);
|
|
FreePathString(protocolBindingsPath);
|
|
|
|
protocolsKey = OpenRegKeyStr (bindingsPath);
|
|
FreePathString (bindingsPath);
|
|
|
|
if (!protocolsKey) {
|
|
continue;
|
|
}
|
|
|
|
if (EnumFirstRegValue (&eProtocolValues, protocolsKey)) {
|
|
|
|
do {
|
|
client = NULL;
|
|
|
|
|
|
if (IsPatternMatch (TEXT("NWREDIR*"), eProtocolValues.ValueName) ||
|
|
IsPatternMatch (TEXT("NWLINK*"), eProtocolValues.ValueName) ||
|
|
IsPatternMatch (TEXT("NOVELLIPX32*"), eProtocolValues.ValueName) ||
|
|
IsPatternMatch (TEXT("IPXODI*"), eProtocolValues.ValueName) ||
|
|
IsPatternMatch (TEXT("NOVELL32*"), eProtocolValues.ValueName)) {
|
|
client = S_MS_NWCLIENT;
|
|
}
|
|
else if (IsPatternMatch (TEXT("VREDIR*"), eProtocolValues.ValueName)) {
|
|
client = S_MS_NETCLIENT;
|
|
}
|
|
|
|
if (client) {
|
|
//
|
|
// We can now remove a path from the bindings table -- we've got an
|
|
// enabled one.
|
|
//
|
|
wsprintf (buffer, TEXT("%s,%s,%s"), client, protocol, adapterString);
|
|
|
|
index = HtFindString (Table, buffer);
|
|
if (index) {
|
|
HtSetStringData (Table, index, (PBYTE) &enabled);
|
|
}
|
|
|
|
DEBUGMSG ((DBG_VERBOSE, "ENABLED BINDING: %s", buffer));
|
|
}
|
|
|
|
} while (EnumNextRegValue (&eProtocolValues));
|
|
}
|
|
|
|
CloseRegKey (protocolsKey);
|
|
|
|
} while (EnumNextRegValue (&eValues));
|
|
}
|
|
|
|
CloseRegKey (key);
|
|
} while (EnumNextNetCard (&eCard));
|
|
|
|
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
|
|
|
EnumNetCardAbort(&eCard);
|
|
LOG ((LOG_ERROR,"Caught exception while gathering data about network adapters."));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
pSplitBindingPathIntoComponents (
|
|
IN OUT PTSTR BindingPath,
|
|
OUT PCTSTR * Client,
|
|
OUT PCTSTR * Protocol,
|
|
OUT PCTSTR * Adapter
|
|
)
|
|
{
|
|
PTSTR p;
|
|
|
|
p = BindingPath;
|
|
*Client = p;
|
|
|
|
p = _tcschr (p, TEXT(','));
|
|
MYASSERT (p);
|
|
if (!p) {
|
|
return FALSE;
|
|
}
|
|
|
|
*p = 0;
|
|
p = _tcsinc (p);
|
|
*Protocol = p;
|
|
|
|
p = _tcschr (p, TEXT(','));
|
|
|
|
if (!p) {
|
|
|
|
//
|
|
// Only Adapter and Protocol specified.
|
|
//
|
|
*Adapter = *Protocol;
|
|
*Protocol = *Client;
|
|
*Client = NULL;
|
|
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Adapter/Protocol/Client specified.
|
|
//
|
|
*p = 0;
|
|
p = _tcsinc (p);
|
|
*Adapter = p;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pBindingSections (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
HASHTABLE disabledBindings;
|
|
HASHTABLE_ENUM e;
|
|
TCHAR bindingString[MEMDB_MAX];
|
|
PTSTR client = NULL;
|
|
PTSTR protocol = NULL;
|
|
PTSTR adapter = NULL;
|
|
DWORD keyVal = 0;
|
|
|
|
disabledBindings = HtAllocWithData (sizeof(BOOL));
|
|
|
|
|
|
if (!disabledBindings) {
|
|
return NULL;
|
|
}
|
|
|
|
pInitializeBindingInfo (disabledBindings);
|
|
pResolveEnabledBindings (disabledBindings);
|
|
|
|
//
|
|
// Simply enumerate the table and blast each disabled setting
|
|
// to winnt.sif.
|
|
//
|
|
if (EnumFirstHashTableString (&e, disabledBindings)) {
|
|
|
|
do {
|
|
|
|
if (!*((PBOOL) e.ExtraData)) {
|
|
|
|
StringCopy (bindingString, e.String);
|
|
if (!pSplitBindingPathIntoComponents (bindingString, &client, &protocol, &adapter)) {
|
|
continue;
|
|
}
|
|
|
|
MYASSERT (protocol && adapter);
|
|
|
|
//
|
|
// Write full path..
|
|
//
|
|
keyVal = 0;
|
|
if (client) {
|
|
keyVal = WriteInfKeyEx (S_NETBINDINGS, S_DISABLED, client, keyVal, TRUE);
|
|
}
|
|
|
|
keyVal = WriteInfKeyEx (S_NETBINDINGS, S_DISABLED, protocol, keyVal, TRUE);
|
|
keyVal = WriteInfKeyEx (S_NETBINDINGS, S_DISABLED, adapter, keyVal, TRUE);
|
|
|
|
DEBUGMSG ((DBG_VERBOSE, "DISABLED BINDING: %s", e.String));
|
|
}
|
|
|
|
} while (EnumNextHashTableString (&e));
|
|
}
|
|
|
|
HtFree (disabledBindings);
|
|
|
|
//
|
|
// All of the binding information is handled outside the normal winntsif proceessing. Therefore, we always return
|
|
// NULL here (winntsif processing continues on...)
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Creation Functions
|
|
//
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Each Creation function is responsible for determining wether a specific
|
|
winntsif setting should be processed or
|
|
not. The purpose of most of these functions is obvious.
|
|
|
|
pIsNetworkingInstalled -
|
|
returns TRUE if the machine has networking installed.
|
|
|
|
pIsNetBeuiInstalled -
|
|
TRUE if NETBEUI is installed on the machine.
|
|
|
|
pIsMsDlcInstalled -
|
|
TRUE if MSDLC or MSDLC32 is installed on the machine.
|
|
|
|
pIsNwIpxInstalled -
|
|
TRUE if the machine is running the IPX protocol.
|
|
|
|
pIsTcpIpInstalled -
|
|
TRUE if the machine is running the TCPIP protocol.
|
|
|
|
pIsDnsEnabled -
|
|
TRUE DNS support is enabled.
|
|
|
|
pIsRasInstalled
|
|
TRUE if the machine uses Remote Access.
|
|
|
|
pIsWkstaInstalled
|
|
TRUE if the Workstation Service is installed.
|
|
|
|
pIsNwClientInstalled
|
|
TRUE if the NWLINK is installed.
|
|
|
|
pHasStaticIpAddress
|
|
TRUE if the machine has a static IP address.
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the winntsif engine should process the setting, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
|
|
BOOL
|
|
pIsNetworkingInstalled (
|
|
VOID
|
|
)
|
|
{
|
|
static BOOL firstTime = TRUE;
|
|
static BOOL rCreate = FALSE;
|
|
|
|
if (firstTime) {
|
|
|
|
firstTime = FALSE;
|
|
rCreate =
|
|
HwComp_DialUpAdapterFound() ||
|
|
MemDbGetEndpointValueEx(
|
|
MEMDB_CATEGORY_NETADAPTERS,
|
|
TEXT("Adapter1"),
|
|
MEMDB_FIELD_PNPID,
|
|
g_TempBuffer
|
|
);
|
|
}
|
|
|
|
return rCreate;
|
|
}
|
|
|
|
BOOL
|
|
pInstallMsServer (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
if (MemDbGetEndpointValueEx(
|
|
MEMDB_CATEGORY_NETADAPTERS,
|
|
TEXT("Adapter1"),
|
|
MEMDB_FIELD_PNPID,
|
|
g_TempBuffer
|
|
)) {
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
BOOL
|
|
pIsNetBeuiInstalled (
|
|
VOID
|
|
)
|
|
{
|
|
static BOOL rCreate = FALSE;
|
|
static BOOL firstTime = TRUE;
|
|
UINT i;
|
|
|
|
if (firstTime) {
|
|
rCreate = pIsNetworkingInstalled() && pDoesNetComponentHaveBindings(S_NETBEUI);
|
|
if (rCreate) {
|
|
//
|
|
// Need to make sure tcp/ip is taken care of when processing bindings.
|
|
//
|
|
for (i=0;i<NUM_PROTOCOLS;i++) {
|
|
if (StringIMatch (g_BindingInfo.Protocols[i].Text, S_MS_NETBEUI)) {
|
|
g_BindingInfo.Protocols[i].Installed = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
firstTime = FALSE;
|
|
}
|
|
|
|
|
|
|
|
return rCreate;
|
|
|
|
}
|
|
|
|
#define S_IBMDLC TEXT("IBMDLC")
|
|
#define S_IBMDLC_REG TEXT("HKLM\\Enum\\Network\\IBMDLC")
|
|
|
|
BOOL
|
|
pIsMsDlcInstalled (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
static BOOL rCreate = FALSE;
|
|
static BOOL firstTime = TRUE;
|
|
UINT i;
|
|
|
|
|
|
if (firstTime) {
|
|
firstTime = FALSE;
|
|
|
|
|
|
if (!pIsNetworkingInstalled()) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check to se if MS client is installed.
|
|
//
|
|
if (pDoesNetComponentHaveBindings(S_MSDLC) || pDoesNetComponentHaveBindings(S_MSDLC32)) {
|
|
|
|
rCreate = TRUE;
|
|
}
|
|
|
|
//
|
|
// Check to see if IBM DLC client is installed (and hasn't been handled by a migration dll..)
|
|
// If so, we'll install the MS DLC client. IBM needs to write a migration dll to handle the
|
|
// migration of their client. In the migration dll, they can handle this registry key, and
|
|
// we will not install the protocol.
|
|
//
|
|
if (!rCreate && pDoesNetComponentHaveBindings(S_IBMDLC) && !Is95RegKeySuppressed (S_IBMDLC_REG)) {
|
|
|
|
rCreate = TRUE;
|
|
}
|
|
|
|
|
|
if (rCreate) {
|
|
|
|
for (i=0;i<NUM_PROTOCOLS;i++) {
|
|
if (StringIMatch (g_BindingInfo.Protocols[i].Text, S_MS_DLC)) {
|
|
g_BindingInfo.Protocols[i].Installed = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return rCreate;
|
|
}
|
|
|
|
BOOL
|
|
pIsNwIpxInstalled (
|
|
VOID
|
|
)
|
|
{
|
|
static BOOL firstTime = TRUE;
|
|
static BOOL rCreate = FALSE;
|
|
UINT i;
|
|
|
|
|
|
if (firstTime) {
|
|
rCreate = pIsNetworkingInstalled() && pDoesNetComponentHaveBindings(S_NWLINK);
|
|
if (rCreate) {
|
|
//
|
|
// Need to make sure tcp/ip is taken care of when processing bindings.
|
|
//
|
|
for (i=0;i<NUM_PROTOCOLS;i++) {
|
|
if (StringIMatch (g_BindingInfo.Protocols[i].Text,S_MS_NWIPX)) {
|
|
g_BindingInfo.Protocols[i].Installed = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
firstTime = FALSE;
|
|
}
|
|
|
|
|
|
return rCreate;
|
|
|
|
}
|
|
|
|
BOOL
|
|
pIsTcpIpInstalled (
|
|
VOID
|
|
)
|
|
{
|
|
static BOOL firstTime = TRUE;
|
|
static BOOL rCreate = FALSE;
|
|
UINT i;
|
|
|
|
if (firstTime) {
|
|
|
|
firstTime = FALSE;
|
|
rCreate = pIsNetworkingInstalled() && pDoesNetComponentHaveBindings(S_MSTCP);
|
|
|
|
//
|
|
// Need to make sure tcp/ip is taken care of when processing bindings.
|
|
//
|
|
for (i=0;i<NUM_PROTOCOLS;i++) {
|
|
if (StringIMatch (g_BindingInfo.Protocols[i].Text, S_MS_TCPIP)) {
|
|
g_BindingInfo.Protocols[i].Installed = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return rCreate;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
pIsDnsEnabled (
|
|
VOID
|
|
)
|
|
{
|
|
return pGetRegistryValue (S_MSTCP_KEY, S_ENABLEDNS) && *g_TempBuffer == TEXT('1');
|
|
}
|
|
|
|
BOOL
|
|
pIsRasInstalled (
|
|
VOID
|
|
)
|
|
{
|
|
return HwComp_DialUpAdapterFound();
|
|
}
|
|
|
|
|
|
BOOL
|
|
pIsSnmpInstalled (
|
|
VOID
|
|
)
|
|
{
|
|
return pDoesNetComponentHaveBindings (S_SNMP);
|
|
}
|
|
|
|
BOOL
|
|
pIsUpnpInstalled (
|
|
VOID
|
|
)
|
|
{
|
|
HKEY key;
|
|
BOOL b = FALSE;
|
|
|
|
key = OpenRegKey (HKEY_LOCAL_MACHINE, S_REGKEY_UPNP);
|
|
if (key) {
|
|
b = TRUE;
|
|
CloseRegKey (key);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
pIsWkstaInstalled (
|
|
VOID
|
|
)
|
|
{
|
|
static BOOL firstTime = TRUE;
|
|
static BOOL rCreate = FALSE;
|
|
UINT i;
|
|
|
|
if (firstTime) {
|
|
|
|
firstTime = FALSE;
|
|
rCreate = pDoesNetComponentHaveBindings(S_VREDIR);
|
|
|
|
|
|
if (rCreate) {
|
|
//
|
|
// Need to make sure tcp/ip is taken care of when processing bindings.
|
|
//
|
|
for (i=0;i<NUM_CLIENTS;i++) {
|
|
if (StringIMatch (g_BindingInfo.Clients[i].Text, S_MS_NETCLIENT)) {
|
|
g_BindingInfo.Clients[i].Installed = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return rCreate;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pDisableBrowserService (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
if (pIsWkstaInstalled () && !pDoesNetComponentHaveBindings (S_VSERVER)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#define S_IPXODI TEXT("IPXODI")
|
|
#define S_IPXODI_REG TEXT("HKLM\\Enum\\Network\\IPXODI")
|
|
#define S_NOVELLIPX32 TEXT("NOVELLIPX32")
|
|
#define S_NOVELL32 TEXT("NOVELL32")
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
pIsNwClientInstalled (
|
|
VOID
|
|
)
|
|
{
|
|
static BOOL firstTime = TRUE;
|
|
static BOOL rCreate = FALSE;
|
|
UINT i;
|
|
|
|
if (firstTime) {
|
|
|
|
firstTime = FALSE;
|
|
rCreate = pDoesNetComponentHaveBindings(S_NWREDIR) ||
|
|
pDoesNetComponentHaveBindings(S_NOVELLIPX32) ||
|
|
pDoesNetComponentHaveBindings(S_NOVELL32) ||
|
|
(pDoesNetComponentHaveBindings(S_IPXODI) && !Is95RegKeySuppressed (S_IPXODI_REG));
|
|
|
|
|
|
if (rCreate) {
|
|
|
|
//
|
|
// Need to make sure tcp/ip is taken care of when processing bindings.
|
|
//
|
|
for (i=0;i<NUM_CLIENTS;i++) {
|
|
if (StringIMatch (g_BindingInfo.Clients[i].Text, S_MS_NWCLIENT)) {
|
|
g_BindingInfo.Clients[i].Installed = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return rCreate;
|
|
}
|
|
|
|
BOOL
|
|
pHasStaticIpAddress (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
PCTSTR netTrans = NULL;
|
|
netTrans = pGetNetTransBinding (g_CurrentAdapter, S_MSTCP);
|
|
|
|
|
|
return netTrans != NULL &&
|
|
pGetRegistryValue (netTrans, S_IPADDRVAL) != NULL &&
|
|
!StringMatch (g_TempBuffer, TEXT("0.0.0.0"));
|
|
|
|
}
|
|
//
|
|
// Data Functions
|
|
//
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetTempDir returns the temporary directory used by the win9xupg code.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz contaiining the win9xupg directory, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetTempDir (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
|
|
//
|
|
// Necessary for winntsif.exe tool.
|
|
//
|
|
if (!g_TempDir) {
|
|
return NULL;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
StringCopy(g_TempBuffer,g_TempDir);
|
|
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetWin9xBootDrive returns the win9x boot drive letter used by the win9xupg code.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz contaiining the win9x boot drive letter, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetWin9xBootDrive (
|
|
VOID
|
|
)
|
|
{
|
|
CLEARBUFFER();
|
|
wsprintf(g_TempBuffer,TEXT("%c:"),g_BootDriveLetter);
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetGuiCodePage adds the code page override data for GUI mode to run in.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz contaiining the code page GUI mode should run in or NULL if it could not be
|
|
retrieved or isn't needed.
|
|
|
|
--*/
|
|
|
|
PCTSTR
|
|
pGetGuiCodePage (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
HKEY key;
|
|
PCTSTR systemCodePage;
|
|
PCTSTR winntCodePage;
|
|
INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
|
|
PCTSTR rCodePage = NULL;
|
|
TCHAR nlsFile[MAX_TCHAR_PATH];
|
|
TCHAR nlsFileCompressed[MAX_TCHAR_PATH];
|
|
PTSTR p;
|
|
UINT i;
|
|
BOOL cpExists = FALSE;
|
|
|
|
|
|
|
|
key = OpenRegKeyStr (TEXT("HKLM\\System\\CurrentControlSet\\Control\\Nls\\CodePage"));
|
|
if (!key) {
|
|
return NULL;
|
|
}
|
|
|
|
__try {
|
|
|
|
//
|
|
// Get the ACP of the currently running system.
|
|
//
|
|
systemCodePage = GetRegValueString (key, TEXT("ACP"));
|
|
if (!systemCodePage || InfFindFirstLine (g_Win95UpgInf, S_CODEPAGESTOIGNORE, systemCodePage, &is)) {
|
|
|
|
//
|
|
// Either the code page doesn't exist, or we intentionally skip it.
|
|
//
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Get the code page of our infs.
|
|
//
|
|
if (InfFindFirstLine (g_Win95UpgInf, S_VERSION, TEXT("LANGUAGE"), &is)) {
|
|
|
|
winntCodePage = InfGetStringField (&is,1);
|
|
|
|
if (!winntCodePage) {
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
if (StringIMatch (winntCodePage, systemCodePage)) {
|
|
|
|
//
|
|
// Nothing to do if they are the same.
|
|
//
|
|
|
|
__leave;
|
|
}
|
|
|
|
if (!InfFindFirstLine (g_Win95UpgInf, S_ALLOWEDCODEPAGEOVERRIDES, winntCodePage, &is)) {
|
|
|
|
//
|
|
// We don't allow code page overrides from this winnt code page.
|
|
//
|
|
__leave;
|
|
}
|
|
|
|
|
|
//
|
|
// See if this nls file exists in the source directories.
|
|
//
|
|
wsprintf(nlsFileCompressed, TEXT("c_%s.nl_"), systemCodePage);
|
|
wsprintf(nlsFile, TEXT("c_%s.nls"), systemCodePage);
|
|
|
|
for (i = 0; i < SOURCEDIRECTORYCOUNT(); i++) {
|
|
|
|
p = JoinPaths (SOURCEDIRECTORY(i), nlsFileCompressed);
|
|
if (DoesFileExist (p)) {
|
|
cpExists = TRUE;
|
|
}
|
|
else {
|
|
FreePathString (p);
|
|
p = JoinPaths (SOURCEDIRECTORY(i), nlsFile);
|
|
if (DoesFileExist (p)) {
|
|
cpExists = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
FreePathString (p);
|
|
}
|
|
|
|
if (!cpExists) {
|
|
wsprintf(nlsFile, TEXT("c_%s.nls"), systemCodePage);
|
|
|
|
for (i = 0; i < SOURCEDIRECTORYCOUNT(); i++) {
|
|
|
|
p = JoinPaths (SOURCEDIRECTORY(i), nlsFile);
|
|
if (DoesFileExist (p)) {
|
|
cpExists = TRUE;
|
|
}
|
|
|
|
FreePathString (p);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Codepage exists. We can and should override this for GUI mode.
|
|
//
|
|
if (cpExists) {
|
|
|
|
CLEARBUFFER();
|
|
StringCopy (g_TempBuffer, systemCodePage);
|
|
rCodePage = g_TempBuffer;
|
|
DEBUGMSG ((DBG_VERBOSE, "Overriding code page %s with %s during GUI mode.", winntCodePage, systemCodePage));
|
|
|
|
}
|
|
|
|
}
|
|
__finally {
|
|
|
|
if (systemCodePage) {
|
|
MemFree (g_hHeap, 0, systemCodePage);
|
|
}
|
|
|
|
InfCleanUpInfStruct (&is);
|
|
CloseRegKey (key);
|
|
}
|
|
|
|
|
|
return rCodePage;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pBackupImageList writes a path to winnt.sif listing the files to backup.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the backup path, or NULL if it isn't needed.
|
|
|
|
--*/
|
|
|
|
PCTSTR
|
|
pBackupFileList (
|
|
VOID
|
|
)
|
|
{
|
|
if (TRISTATE_NO == g_ConfigOptions.EnableBackup) {
|
|
return NULL;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
|
|
StringCopy (g_TempBuffer, g_TempDir);
|
|
StringCopy (AppendWack (g_TempBuffer), TEXT("backup.txt"));
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pUninstallMoveFileList (
|
|
VOID
|
|
)
|
|
{
|
|
if (!g_ConfigOptions.EnableBackup) {
|
|
return NULL;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
|
|
StringCopy (g_TempBuffer, g_TempDir);
|
|
StringCopy (AppendWack (g_TempBuffer), S_UNINSTALL_TEMP_DIR TEXT("\\") S_ROLLBACK_MOVED_TXT);
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pUninstallDelDirList (
|
|
VOID
|
|
)
|
|
{
|
|
if (!g_ConfigOptions.EnableBackup) {
|
|
return NULL;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
|
|
StringCopy (g_TempBuffer, g_TempDir);
|
|
StringCopy (AppendWack (g_TempBuffer), S_UNINSTALL_TEMP_DIR TEXT("\\") S_ROLLBACK_DELDIRS_TXT);
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pUninstallDelFileList (
|
|
VOID
|
|
)
|
|
{
|
|
if (!g_ConfigOptions.EnableBackup) {
|
|
return NULL;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
|
|
StringCopy (g_TempBuffer, g_TempDir);
|
|
StringCopy (AppendWack (g_TempBuffer), S_UNINSTALL_TEMP_DIR TEXT("\\") S_ROLLBACK_DELFILES_TXT);
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pUninstallMkDirList (
|
|
VOID
|
|
)
|
|
{
|
|
if (!g_ConfigOptions.EnableBackup) {
|
|
return NULL;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
|
|
StringCopy (g_TempBuffer, g_TempDir);
|
|
StringCopy (AppendWack (g_TempBuffer), S_UNINSTALL_TEMP_DIR TEXT("\\") S_ROLLBACK_MKDIRS_TXT);
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetWin9xSifDir returns the directory containing the filemove and filedel
|
|
files.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz contaiining the win9xsifdir directory, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
PCTSTR
|
|
pGetWin9xSifDir (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
//
|
|
// Necessary for winntsif.exe tool.
|
|
//
|
|
if (!g_Win9xSifDir) {
|
|
return NULL;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
StringCopy(g_TempBuffer,g_Win9xSifDir);
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetWinDir returns the windows directory of the machine being upgraded.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz contaiining the windows directory, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
PCTSTR
|
|
pGetWinDir (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
//
|
|
// Necessary for winntsif.exe tool.
|
|
//
|
|
if (!g_WinDir) {
|
|
return NULL;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
StringCopy(g_TempBuffer,g_WinDir);
|
|
return g_TempBuffer;
|
|
|
|
}
|
|
|
|
#if 0
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If the upgrade is running in unattended mode, this function returns "1",
|
|
otherwise it returns "0". This is used to control wether GUI mode setup pauses
|
|
at the final wizard screen or reboots automatically.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz contaiining the GUI mode pause state.
|
|
|
|
--*/
|
|
PCTSTR
|
|
pNoWaitAfterGuiMode (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
CLEARBUFFER();
|
|
StringCopy(g_TempBuffer,UNATTENDED() ? S_ONE : S_ZERO);
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
#endif
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetKeyboardLayout retrieves the keyboard layout to write to the winntsif file.
|
|
This is done by retrieving the name of the layout being used by win9x and matching it
|
|
against the keyboard layouts in txtsetup.sif.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the keyboard layout, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
PCTSTR
|
|
pGetKeyboardLayout (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
TCHAR buffer[MAX_KEYBOARDLAYOUT];
|
|
INFCONTEXT ic;
|
|
|
|
GetKeyboardLayoutName(buffer);
|
|
|
|
//
|
|
// Because some brilliant developer added ["Keyboard Layout"] instead of
|
|
// just [Keyboard Layout], we cannot use GetPrivateProfileString.
|
|
// We must use setup APIs.
|
|
//
|
|
|
|
if (SetupFindFirstLine (g_TxtSetupSif, S_QUOTEDKEYBOARDLAYOUT, buffer, &ic)) {
|
|
if (SetupGetOemStringField (&ic, 1, g_TempBuffer, sizeof (g_TempBuffer), NULL)) {
|
|
return g_TempBuffer;
|
|
}
|
|
}
|
|
|
|
DEBUGMSG((DBG_WINNTSIF,"Keyboard layout %s not found in txtsetup.sif.",buffer));
|
|
|
|
return NULL;
|
|
}
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetKeyboardHardware retrives the keyboard hardware id of the machine running
|
|
the upgrade.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz contaiining the win9xupg directory, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
PCTSTR
|
|
pGetKeyboardHardware (
|
|
VOID
|
|
)
|
|
{
|
|
CLEARBUFFER();
|
|
|
|
if (GetLegacyKeyboardId (g_TempBuffer,sizeof(g_TempBuffer))) {
|
|
return g_TempBuffer;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This rather laborious function retrieves the correct index to write to
|
|
the winntsif file for the timezone being used on the machine. To do this,
|
|
it is necessary to munge through several parts of the registry in order
|
|
to find the correct string to match with and then match that string against
|
|
the timezone mappings contained in win95upg.inf to come up with the actual
|
|
index.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the index to write to the winntsif file, or NULL if it
|
|
could not be retrieved.
|
|
|
|
--*/
|
|
PCTSTR
|
|
pGetTimeZone (
|
|
VOID
|
|
)
|
|
{
|
|
TIMEZONE_ENUM e;
|
|
PCTSTR component = NULL;
|
|
PCTSTR warning = NULL;
|
|
PCTSTR args[1];
|
|
|
|
if (EnumFirstTimeZone (&e, TZFLAG_USE_FORCED_MAPPINGS) || EnumFirstTimeZone(&e, TZFLAG_ENUM_ALL)) {
|
|
|
|
if (e.MapCount != 1) {
|
|
|
|
//
|
|
// Ambigous timezone situation. Add an incompatibility message.
|
|
//
|
|
args[0] = e.CurTimeZone;
|
|
|
|
component = GetStringResource (MSG_TIMEZONE_COMPONENT);
|
|
|
|
if (*e.CurTimeZone) {
|
|
warning = ParseMessageID (MSG_TIMEZONE_WARNING, args);
|
|
}
|
|
else {
|
|
warning = GetStringResource (MSG_TIMEZONE_WARNING_UNKNOWN);
|
|
}
|
|
|
|
MYASSERT (component);
|
|
MYASSERT (warning);
|
|
|
|
MsgMgr_ObjectMsg_Add (TEXT("*TIMEZONE"), component, warning);
|
|
FreeStringResource (component);
|
|
FreeStringResource (warning);
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
StringCopy (g_TempBuffer, e.MapIndex);
|
|
return g_TempBuffer;
|
|
}
|
|
else {
|
|
LOG ((LOG_ERROR, "Unable to get timezone. User will have to enter timezone in GUI mode."));
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetFullName returns the full name of the owner of the machine running
|
|
the upgrade. This function first searches the registry and then, if that
|
|
does not provide the needed information, calls GetUserName.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
PCTSTR
|
|
pGetFullName (
|
|
VOID
|
|
)
|
|
{
|
|
UINT size;
|
|
INVALID_NAME_ENUM e;
|
|
|
|
if (!pGetRegistryValue(S_WINDOWS_CURRENTVERSION,S_REGISTEREDOWNER)) {
|
|
size = MEMDB_MAX;
|
|
if (GetUserName (g_TempBuffer,&size)) {
|
|
MYASSERT (g_TempBuffer[size - 1] == 0);
|
|
g_TempBuffer[size] = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// check if this name is:
|
|
// 1. Empty - what do we do in this case?
|
|
// 2. A reserved NT name: then we'll use the new name (user was informed about this)
|
|
//
|
|
if (*g_TempBuffer) {
|
|
if (EnumFirstInvalidName (&e)) {
|
|
do {
|
|
if (StringIMatch (e.OriginalName, g_TempBuffer)) {
|
|
//
|
|
// the buffer is actually interpreted as a MULTISZ, so make sure
|
|
// it's terminated with 2 zeroes
|
|
//
|
|
if (SizeOfString (e.NewName) + sizeof (TCHAR) <= sizeof (g_TempBuffer)) {
|
|
//
|
|
// we surely have space for an extra 0
|
|
//
|
|
StringCopy (g_TempBuffer, e.NewName);
|
|
*(GetEndOfString (g_TempBuffer) + 1) = 0;
|
|
break;
|
|
}
|
|
}
|
|
} while (EnumNextInvalidName (&e));
|
|
}
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetFullName returns the computer name of the machine running the
|
|
upgrade.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
PCTSTR
|
|
pGetComputerName (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
CLEARBUFFER();
|
|
if (!GetUpgradeComputerName(g_TempBuffer)) {
|
|
return NULL;
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetXResolution and pGetYResolution return the x and y resolution for
|
|
the machine running the upgrade.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
PCTSTR
|
|
pGetXResolution (
|
|
VOID
|
|
)
|
|
{
|
|
/*
|
|
PTSTR s = NULL;
|
|
|
|
if (!pGetRegistryValue(S_DISPLAYSETTINGS,S_RESOLUTION)) {
|
|
LOG ((LOG_ERROR, "No Resolution settings."));
|
|
return NULL;
|
|
}
|
|
|
|
s = _tcschr(g_TempBuffer,TEXT(','));
|
|
if (s) {
|
|
*s = 0;
|
|
s++;
|
|
*s = 0;
|
|
}
|
|
*/
|
|
wsprintf (g_TempBuffer, TEXT("%u%c"), GetSystemMetrics (SM_CXSCREEN), 0);
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pGetYResolution (
|
|
VOID
|
|
)
|
|
{
|
|
/*
|
|
PTSTR s = NULL;
|
|
|
|
if (!pGetRegistryValue(S_DISPLAYSETTINGS,S_RESOLUTION)) {
|
|
LOG ((LOG_ERROR, "WinntSif: No Resolution settings."));
|
|
return NULL;
|
|
}
|
|
|
|
s = _tcschr(g_TempBuffer,TEXT(','));
|
|
if (s) {
|
|
s++;
|
|
}
|
|
return s;
|
|
*/
|
|
wsprintf (g_TempBuffer, TEXT("%u%c"), GetSystemMetrics (SM_CYSCREEN), 0);
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pGetBitsPerPixel (
|
|
VOID
|
|
)
|
|
{
|
|
DEVMODE dm;
|
|
|
|
if (!EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &dm) ||
|
|
!dm.dmBitsPerPel
|
|
) {
|
|
return NULL;
|
|
}
|
|
|
|
wsprintf (g_TempBuffer, TEXT("%lu%c"), dm.dmBitsPerPel, 0);
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
PCTSTR
|
|
pGetVerticalRefreshRate (
|
|
VOID
|
|
)
|
|
{
|
|
DEVMODE dm;
|
|
|
|
if (!EnumDisplaySettings (NULL, ENUM_CURRENT_SETTINGS, &dm) ||
|
|
!dm.dmDisplayFrequency
|
|
) {
|
|
return NULL;
|
|
}
|
|
|
|
wsprintf (g_TempBuffer, TEXT("%lu%c"), dm.dmDisplayFrequency, 0);
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the PNP id for the current adapter being worked with.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
PCTSTR
|
|
pGetNetAdapterPnpId (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
PCTSTR rPnpId = NULL;
|
|
PTSTR p = NULL;
|
|
INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
|
|
|
|
CLEARBUFFER();
|
|
|
|
rPnpId = g_TempBuffer;
|
|
|
|
if (!MemDbGetEndpointValueEx(
|
|
MEMDB_CATEGORY_NETADAPTERS,
|
|
g_CurrentAdapter,
|
|
MEMDB_FIELD_PNPID,
|
|
g_TempBuffer
|
|
)) {
|
|
|
|
*g_TempBuffer = TEXT('*');
|
|
|
|
}
|
|
else {
|
|
p = _tcschr(g_TempBuffer,TEXT(','));
|
|
if (p) {
|
|
*p = 0;
|
|
p++;
|
|
*p = 0;
|
|
}
|
|
|
|
//
|
|
// We may need to map this id.
|
|
//
|
|
if (InfFindFirstLine (g_Win95UpgInf, S_NICIDMAP, g_TempBuffer, &is)) {
|
|
|
|
//
|
|
// This pnp id needs to be mapped.
|
|
//
|
|
p = InfGetStringField (&is, 1);
|
|
if (p) {
|
|
CLEARBUFFER();
|
|
StringCopy (g_TempBuffer, p);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return rPnpId;
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pSpecificTo simply copies the current adapter into the the temporary
|
|
buffer and returns it. This is necessary for the various adapter sections.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
PCTSTR
|
|
pSpecificTo (
|
|
VOID
|
|
)
|
|
{
|
|
CLEARBUFFER();
|
|
//if this is ICS external adapter and we are saving tcpip settings, then the g_CurrentAdapter
|
|
//actually contains name of the ICSHARE adapter intead of the real LAN adapter.
|
|
//However, "SpecificTo" still needs to point to the real LAN adapter
|
|
StringCopy(g_TempBuffer, (g_fIcsAdapterInPlace) ? g_IcsExternalAdapter : g_CurrentAdapter);
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetBuildNumber simply packs the buildnumber into a string and passes
|
|
it back.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetBuildNumber (
|
|
VOID
|
|
)
|
|
{
|
|
CLEARBUFFER();
|
|
|
|
wsprintf(g_TempBuffer,"%u",BUILDNUMBER());
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetUpgradeDomainName returns the upgrade domain name.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetUpgradeDomainName (
|
|
VOID
|
|
)
|
|
{
|
|
PCTSTR rDomainName = NULL;
|
|
|
|
CLEARBUFFER();
|
|
|
|
if (GetUpgradeDomainName(g_TempBuffer)) {
|
|
|
|
rDomainName = g_TempBuffer;
|
|
|
|
//
|
|
// Need to save some state information for use in GUI mode.
|
|
//
|
|
MemDbSetValueEx (
|
|
MEMDB_CATEGORY_STATE,
|
|
MEMDB_ITEM_MSNP32,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//
|
|
// If /#u:ForceWorkgroup is specified, force to workgroup
|
|
//
|
|
|
|
if (g_ConfigOptions.ForceWorkgroup) {
|
|
return NULL;
|
|
}
|
|
|
|
return rDomainName;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetUpgradeWorkgroupName returns the upgrade domain name.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetUpgradeWorkgroupName (
|
|
VOID
|
|
)
|
|
{
|
|
PCTSTR rWorkGroupName = NULL;
|
|
|
|
|
|
//
|
|
// Don't write workgroup settings if domain settings already exist.
|
|
//
|
|
if (pGetUpgradeDomainName()) {
|
|
return NULL;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
|
|
#ifdef PRERELEASE
|
|
|
|
//
|
|
// If /#U:STRESS was specified, hardcode ntdev.
|
|
//
|
|
if (g_Stress) {
|
|
|
|
StringCopy(g_TempBuffer,TEXT("ntdev"));
|
|
rWorkGroupName = g_TempBuffer;
|
|
} else
|
|
|
|
#endif
|
|
|
|
//
|
|
// If /#u:ForceWorkgroup is specified, force to workgroup
|
|
//
|
|
if (!GetUpgradeWorkgroupName(g_TempBuffer) && !GetUpgradeDomainName(g_TempBuffer)) {
|
|
|
|
PCTSTR Buf = GetStringResource (MSG_DEFAULT_WORKGROUP);
|
|
MYASSERT(Buf);
|
|
StringCopy (g_TempBuffer, Buf);
|
|
FreeStringResource (Buf);
|
|
}
|
|
|
|
rWorkGroupName = g_TempBuffer;
|
|
|
|
return rWorkGroupName;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetAdaptersWithIpxBindings and pGetAdaptersWithTcpBindings simply return a
|
|
multisz list of adapter sections names for per-adapter sections of winnt.sif
|
|
data for IPX and TCP settings respectively.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetAdaptersWithIpxBindings (
|
|
VOID
|
|
)
|
|
{
|
|
return pListAdaptersWithBinding(S_NWLINK,S_IPX_SUFFIX);
|
|
}
|
|
|
|
PCTSTR
|
|
pGetAdaptersWithTcpBindings (
|
|
VOID
|
|
)
|
|
{
|
|
return pListAdaptersWithBinding(S_MSTCP,S_TCPIP_SUFFIX);
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetIpxPacketType maps the frame type found in the win9x registry to the
|
|
packet types that are possible in the winnt.sif file.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
PCTSTR
|
|
pGetIpxPacketType (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
PCTSTR frameType = NULL;
|
|
PCTSTR netTrans = NULL;
|
|
|
|
CLEARBUFFER();
|
|
|
|
netTrans = pGetNetTransBinding (g_CurrentAdapter, S_NWLINK);
|
|
if (netTrans) {
|
|
frameType = pGetRegistryValue(netTrans, S_FRAME_TYPE);
|
|
}
|
|
|
|
//
|
|
// We must map the win9x frame type onto the compatible NT frame type.
|
|
//
|
|
if (frameType) {
|
|
|
|
g_TempBuffer[1] = 0;
|
|
|
|
switch(*frameType) {
|
|
|
|
case TEXT('0'):
|
|
*g_TempBuffer = TEXT('1'); // 802.3
|
|
break;
|
|
case TEXT('1'):
|
|
*g_TempBuffer = TEXT('2'); // 802.2
|
|
break;
|
|
case TEXT('2'):
|
|
*g_TempBuffer = TEXT('0'); // ETHERNET II
|
|
break;
|
|
case TEXT('3'):
|
|
*g_TempBuffer = TEXT('3'); // ETHERNET SNAP
|
|
break;
|
|
default:
|
|
//
|
|
// If we find anything else, we'll just set it to AUTODETECT.
|
|
//
|
|
StringCopy(g_TempBuffer,TEXT("FF"));
|
|
|
|
//
|
|
// Lets log this to setupact.log.
|
|
//
|
|
LOG ((LOG_WARNING, (PCTSTR) MSG_AUTODETECT_FRAMETYPE));
|
|
}
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pGetIpxNetworkNumber (
|
|
VOID
|
|
)
|
|
{
|
|
PCTSTR netTrans = NULL;
|
|
CLEARBUFFER();
|
|
|
|
netTrans = pGetNetTransBinding (g_CurrentAdapter, S_NWLINK);
|
|
|
|
if (netTrans) {
|
|
return pGetRegistryValue (netTrans, S_NETWORK_ID);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetDNSStatus returns "Yes" If DNS is enabled on the win9xupg machine,
|
|
"No" otherwise.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetDnsStatus (
|
|
VOID
|
|
)
|
|
{
|
|
CLEARBUFFER();
|
|
StringCopy(g_TempBuffer,pIsDnsEnabled() ? S_YES : S_NO);
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetScriptProcessingStatus returns "Yes" if logon script processing is enabled,
|
|
"No" otherwise.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetScriptProcessingStatus (
|
|
VOID
|
|
)
|
|
{
|
|
PBYTE p = NULL;
|
|
HKEY key;
|
|
|
|
CLEARBUFFER();
|
|
key = OpenRegKeyStr(S_NETWORKLOGON);
|
|
|
|
if (key && key != INVALID_HANDLE_VALUE) {
|
|
|
|
p = GetRegValueBinary(key,S_PROCESSLOGINSCRIPT);
|
|
StringCopy(g_TempBuffer,p && *p == 0x01 ? S_YES : S_NO);
|
|
CloseRegKey(key);
|
|
|
|
}
|
|
else {
|
|
DEBUGMSG((DBG_WARNING,"pGetScriptProcessingStatus could not open key %s.",S_NETWORKLOGON));
|
|
StringCopy(g_TempBuffer,S_NO);
|
|
}
|
|
|
|
if (p) {
|
|
|
|
MemFree(g_hHeap,0,p);
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetIpAddress returns the IP Address of the win9xupg machine being upgraded,
|
|
if it exists.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetIpAddress (
|
|
VOID
|
|
)
|
|
{
|
|
PTSTR p;
|
|
PCTSTR netTrans;
|
|
CLEARBUFFER();
|
|
|
|
|
|
netTrans = pGetNetTransBinding (g_CurrentAdapter, S_MSTCP);
|
|
|
|
if (!netTrans || !pGetRegistryValue(netTrans, S_IPADDRVAL)) {
|
|
return NULL;
|
|
}
|
|
else {
|
|
p = g_TempBuffer;
|
|
while (p && *p) {
|
|
p = _tcschr(p,TEXT(','));
|
|
if (p) {
|
|
*p = 0;
|
|
p = _tcsinc(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetDHCPStatus returns "Yes" if DHCP is enabled, "No" otherwise.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetDhcpStatus (
|
|
VOID
|
|
)
|
|
{
|
|
BOOL rStatus = !pHasStaticIpAddress();
|
|
|
|
CLEARBUFFER();
|
|
StringCopy(g_TempBuffer,rStatus ? S_YES : S_NO);
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetSubnetMask returns the subnet mask in dotted decimal notation for the
|
|
machine being upgraded.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
|
|
PCTSTR
|
|
pGetSubnetMask (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
PTSTR p;
|
|
PCTSTR netTrans = NULL;
|
|
CLEARBUFFER();
|
|
|
|
netTrans = pGetNetTransBinding (g_CurrentAdapter, S_MSTCP);
|
|
if (!netTrans || !pGetRegistryValue (netTrans, S_SUBNETVAL)) {
|
|
return NULL;
|
|
}
|
|
else {
|
|
p = g_TempBuffer;
|
|
while (p && *p) {
|
|
p = _tcschr(p,TEXT(','));
|
|
if (p) {
|
|
*p = 0;
|
|
p = _tcsinc(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetGateway returns the gateway(s) in dotted decimal notation for the
|
|
machine being upgraded. If the machine doesn't have a static IP address,
|
|
the Gateway settings are NOT migrated.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetGateway (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
PTSTR p;
|
|
PCTSTR netTrans = NULL;
|
|
CLEARBUFFER();
|
|
|
|
|
|
if (!pHasStaticIpAddress()) {
|
|
return NULL;
|
|
}
|
|
|
|
netTrans = pGetNetTransBinding (g_CurrentAdapter, S_MSTCP);
|
|
if (!netTrans || !pGetRegistryValue (netTrans, S_DEFGATEWAYVAL)) {
|
|
return NULL;
|
|
}
|
|
else {
|
|
p = g_TempBuffer;
|
|
while (p && *p) {
|
|
p = _tcschr(p,TEXT(','));
|
|
if (p) {
|
|
*p = 0;
|
|
p = _tcsinc(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
|
|
}
|
|
|
|
PCTSTR
|
|
pGetDnsSuffixSearchOrder (
|
|
VOID
|
|
)
|
|
{
|
|
PTSTR p;
|
|
CLEARBUFFER();
|
|
|
|
if (!pGetRegistryValue(S_MSTCP_KEY,S_SEARCHLIST)) {
|
|
return NULL;
|
|
}
|
|
else {
|
|
p = g_TempBuffer;
|
|
while (p && *p) {
|
|
p = _tcschr(p,TEXT(','));
|
|
if (p) {
|
|
*p = 0;
|
|
p = _tcsinc(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pGetDnsServerSearchOrder (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
PTSTR p;
|
|
CLEARBUFFER();
|
|
|
|
|
|
if (!pGetRegistryValue(S_MSTCP_KEY,S_NAMESERVERVAL)) {
|
|
return NULL;
|
|
}
|
|
else {
|
|
p = g_TempBuffer;
|
|
while (p && *p) {
|
|
p = _tcschr(p,TEXT(','));
|
|
if (p) {
|
|
*p = 0;
|
|
p = _tcsinc(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetWinsStatus returns "Yes" if WINS servers are enabled, "No" otehrwise.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetWinsStatus (
|
|
VOID
|
|
)
|
|
{
|
|
PCTSTR status;
|
|
PCTSTR netTrans = NULL;
|
|
|
|
netTrans = pGetNetTransBinding (g_CurrentAdapter, S_MSTCP);
|
|
|
|
if (!netTrans) {
|
|
status = S_NO;
|
|
}
|
|
else {
|
|
|
|
status =
|
|
(!pGetRegistryValue (netTrans, S_NODEVAL) &&
|
|
!pGetRegistryValue (S_MSTCP_KEY, S_NODEVAL))
|
|
? S_NO : S_YES;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
StringCopy(g_TempBuffer,status);
|
|
|
|
return g_TempBuffer;
|
|
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetWinsServers returns the primary and secondary wins servers in dotted decimal
|
|
notation for the machine being upgraded.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetWinsServers (
|
|
VOID
|
|
)
|
|
{
|
|
TCHAR winsServer2[MEMDB_MAX] = {""};
|
|
TCHAR netTrans[MAX_PATH];
|
|
PTSTR p;
|
|
PCTSTR q;
|
|
CLEARBUFFER ();
|
|
|
|
q = pGetNetTransBinding (g_CurrentAdapter, S_MSTCP);
|
|
if (!q) {
|
|
return NULL;
|
|
}
|
|
|
|
StringCopy (netTrans, q);
|
|
|
|
if (pGetRegistryValue (netTrans, S_NAMESERVER2VAL)) {
|
|
StringCopy (winsServer2, g_TempBuffer);
|
|
} else if (pGetRegistryValue (S_MSTCP_KEY, S_NAMESERVER2VAL)) {
|
|
StringCopy (winsServer2, g_TempBuffer);
|
|
}
|
|
|
|
if (pGetRegistryValue (netTrans, S_NAMESERVER1VAL) ||
|
|
pGetRegistryValue(S_MSTCP_KEY, S_NAMESERVER1VAL)) {
|
|
|
|
p = GetEndOfString (g_TempBuffer) + 1;
|
|
StringCopy (p, winsServer2);
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetRasPorts returns a multisz containing all of the ras ports for the
|
|
machine being upgraded.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
PCTSTR
|
|
pGetRasPorts (
|
|
VOID
|
|
)
|
|
{
|
|
REGKEY_ENUM e;
|
|
PTSTR p;
|
|
UINT modemNum = 1;
|
|
|
|
CLEARBUFFER();
|
|
|
|
if (EnumFirstRegKeyStr(&e,S_MODEMS)) {
|
|
|
|
p = g_TempBuffer;
|
|
do {
|
|
|
|
wsprintf(p,TEXT("COM%u"),modemNum);
|
|
modemNum++;
|
|
p = GetEndOfString (p) + 1;
|
|
|
|
} while (EnumNextRegKey(&e));
|
|
}
|
|
else {
|
|
//
|
|
// Apparently no modems.. Just return NULL.
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pRasPortName returns the current ras port name for the ras section
|
|
currently being processed.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pRasPortName (
|
|
VOID
|
|
)
|
|
{
|
|
CLEARBUFFER();
|
|
StringCopy(g_TempBuffer,g_CurrentSection);
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetLanguageGroups returns the list of language groups to be installed
|
|
during GUI mode setup. Note that any additional directories will have
|
|
been communicated to Setup as optional directories earlier.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
retrieved.
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetLanguageGroups (
|
|
VOID
|
|
)
|
|
{
|
|
|
|
HASHTABLE_ENUM e;
|
|
PTSTR p;
|
|
|
|
if (!g_LocaleTable) {
|
|
DEBUGMSG ((DBG_WARNING, "No information in Locale Hash Table."));
|
|
return NULL;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
p = g_TempBuffer;
|
|
|
|
if (EnumFirstHashTableString (&e, g_LocaleTable)) {
|
|
do {
|
|
|
|
StringCopy (p, e.String);
|
|
p = GetEndOfString (p) + 1;
|
|
|
|
} while (EnumNextHashTableString (&e));
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
#if 0
|
|
|
|
BOOL
|
|
pFileVersionLesser (
|
|
IN PCTSTR FileName,
|
|
IN DWORD FileVerMS,
|
|
IN DWORD FileVerLS
|
|
)
|
|
{
|
|
DWORD dwLength, dwTemp;
|
|
UINT DataLength;
|
|
PVOID lpData;
|
|
VS_FIXEDFILEINFO *VsInfo;
|
|
BOOL b = TRUE;
|
|
|
|
if(dwLength = GetFileVersionInfoSize ((PTSTR)FileName, &dwTemp)) {
|
|
lpData = PoolMemGetMemory (g_GlobalPool, dwLength);
|
|
if(GetFileVersionInfo((PTSTR)FileName, 0, dwLength, lpData)) {
|
|
if (VerQueryValue(lpData, TEXT("\\"), &VsInfo, &DataLength)) {
|
|
b = VsInfo->dwFileVersionMS < FileVerMS ||
|
|
(VsInfo->dwFileVersionMS == FileVerMS &&
|
|
VsInfo->dwFileVersionLS <= FileVerLS);
|
|
}
|
|
}
|
|
PoolMemReleaseMemory (g_GlobalPool, lpData);
|
|
}
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
pNewerW95upgntOnCD (
|
|
IN PCTSTR ReplacementDll
|
|
)
|
|
{
|
|
DWORD dwLength, dwTemp;
|
|
PVOID lpData = NULL;
|
|
VS_FIXEDFILEINFO *VsInfo;
|
|
UINT DataLength;
|
|
DWORD result;
|
|
UINT u;
|
|
PCTSTR pathCDdllSource = NULL;
|
|
PCTSTR pathCDdllTarget = NULL;
|
|
DWORD FileVerMS;
|
|
DWORD FileVerLS;
|
|
BOOL b = TRUE;
|
|
|
|
__try {
|
|
|
|
for (u = 0; u < SOURCEDIRECTORYCOUNT(); u++) {
|
|
pathCDdllSource = JoinPaths (SOURCEDIRECTORY(u), WINNT_WIN95UPG_NTKEY);
|
|
if (DoesFileExist (pathCDdllSource)) {
|
|
break;
|
|
}
|
|
FreePathString (pathCDdllSource);
|
|
pathCDdllSource = NULL;
|
|
}
|
|
if (!pathCDdllSource) {
|
|
__leave;
|
|
}
|
|
|
|
pathCDdllTarget = JoinPaths (g_TempDir, WINNT_WIN95UPG_NTKEY);
|
|
SetFileAttributes (pathCDdllTarget, FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFile (pathCDdllTarget);
|
|
|
|
result = SetupDecompressOrCopyFile (pathCDdllSource, pathCDdllTarget, 0);
|
|
if (result != ERROR_SUCCESS) {
|
|
LOG ((
|
|
LOG_ERROR,
|
|
"pGetW95UpgNTCDFileVersion: Unable to decompress %s",
|
|
pathCDdllSource
|
|
));
|
|
__leave;
|
|
}
|
|
|
|
if (dwLength = GetFileVersionInfoSize ((PTSTR)pathCDdllTarget, &dwTemp)) {
|
|
lpData = PoolMemGetMemory (g_GlobalPool, dwLength);
|
|
if (GetFileVersionInfo ((PTSTR)pathCDdllTarget, 0, dwLength, lpData)) {
|
|
if (VerQueryValue (lpData, TEXT("\\"), &VsInfo, &DataLength)) {
|
|
b = pFileVersionLesser (
|
|
ReplacementDll,
|
|
VsInfo->dwFileVersionMS,
|
|
VsInfo->dwFileVersionLS
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__finally {
|
|
if (lpData) {
|
|
PoolMemReleaseMemory (g_GlobalPool, lpData);
|
|
}
|
|
if (pathCDdllSource) {
|
|
FreePathString (pathCDdllSource);
|
|
}
|
|
if (pathCDdllTarget) {
|
|
SetFileAttributes (pathCDdllTarget, FILE_ATTRIBUTE_NORMAL);
|
|
DeleteFile (pathCDdllTarget);
|
|
FreePathString (pathCDdllTarget);
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetReplacementDll is responsible for scanning the registry for an NT side
|
|
win9x replacement dll and putting it into the answer file if found.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
a multisz containing the required data, or NULL if it could not be
|
|
found.
|
|
|
|
|
|
--*/
|
|
|
|
|
|
PCTSTR
|
|
pGetReplacementDll (
|
|
VOID
|
|
)
|
|
{
|
|
HKEY key = NULL;
|
|
PTSTR val = NULL;
|
|
BOOL b = FALSE;
|
|
|
|
key = OpenRegKey (HKEY_LOCAL_MACHINE, WINNT_WIN95UPG_REPLACEMENT);
|
|
|
|
if (!key) {
|
|
return NULL;
|
|
}
|
|
|
|
__try {
|
|
|
|
val = GetRegValueString (key, WINNT_WIN95UPG_NTKEY);
|
|
if (!val) {
|
|
__leave;
|
|
}
|
|
|
|
if (pNewerW95upgntOnCD (val)) {
|
|
__leave;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
StringCopy (g_TempBuffer, val);
|
|
|
|
b = TRUE;
|
|
|
|
} __finally {
|
|
CloseRegKey (key);
|
|
if (val) {
|
|
MemFree (g_hHeap, 0, val);
|
|
}
|
|
}
|
|
|
|
return b ? g_TempBuffer : NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
VOID
|
|
pGenerateRandomPassword (
|
|
OUT PTSTR Password
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGenerateRandomPassword creates a password of upper-case, lower-case and
|
|
numeric letters. The password has a length between 8 and 14
|
|
characters.
|
|
|
|
Arguments:
|
|
|
|
Password - Receives the generated password
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
INT Length;
|
|
TCHAR Offset;
|
|
INT Limit;
|
|
PTSTR p;
|
|
|
|
//
|
|
// Generate a random length based on the tick count
|
|
//
|
|
|
|
srand (GetTickCount());
|
|
|
|
Length = (rand() % 6) + 8;
|
|
|
|
p = Password;
|
|
while (Length) {
|
|
Limit = rand() % 3;
|
|
Offset = TEXT(' ');
|
|
|
|
if (Limit == 0) {
|
|
Limit = 10;
|
|
Offset = TEXT('0');
|
|
} else if (Limit == 1) {
|
|
Limit = 26;
|
|
Offset = TEXT('a');
|
|
} else if (Limit == 2) {
|
|
Limit = 26;
|
|
Offset = TEXT('A');
|
|
}
|
|
|
|
*p = Offset + (rand() % Limit);
|
|
p++;
|
|
|
|
Length--;
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
DEBUGMSG ((DBG_WINNTSIF, "Generated password: %s", Password));
|
|
}
|
|
|
|
|
|
PCTSTR
|
|
pSetAdminPassword (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pSetAdminPassword retrieves the AdminPassword as specified in the unattend file, if present.
|
|
Otherwise it generates a random one.
|
|
This information is stored in memdb to be available later.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the admin password.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOL attribs = 0;
|
|
TCHAR node[MEMDB_MAX];
|
|
BOOL blank = FALSE;
|
|
|
|
if (!g_UnattendScriptFile ||
|
|
!*g_UnattendScriptFile ||
|
|
!GetPrivateProfileString (
|
|
S_GUIUNATTENDED,
|
|
WINNT_US_ADMINPASS,
|
|
TEXT(""),
|
|
g_TempBuffer,
|
|
MEMDB_MAX,
|
|
*g_UnattendScriptFile
|
|
)
|
|
) {
|
|
|
|
if (g_PersonalSKU) {
|
|
//
|
|
// for Personal set an empty admin password
|
|
//
|
|
StringCopy (g_TempBuffer, TEXT("*"));
|
|
} else {
|
|
pGenerateRandomPassword (g_TempBuffer);
|
|
attribs = PASSWORD_ATTR_RANDOM;
|
|
}
|
|
|
|
} else {
|
|
if (GetPrivateProfileString (
|
|
S_GUIUNATTENDED,
|
|
WINNT_US_ENCRYPTEDADMINPASS,
|
|
TEXT(""),
|
|
node,
|
|
MEMDB_MAX,
|
|
*g_UnattendScriptFile
|
|
)) {
|
|
if (StringIMatch (node, S_YES) || StringIMatch (node, TEXT("1"))) {
|
|
attribs = PASSWORD_ATTR_ENCRYPTED;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (StringMatch (g_TempBuffer, TEXT("*"))) {
|
|
blank = TRUE;
|
|
*g_TempBuffer = 0;
|
|
}
|
|
MemDbBuildKey (node, MEMDB_CATEGORY_STATE, MEMDB_ITEM_ADMIN_PASSWORD, g_TempBuffer, NULL);
|
|
MemDbSetValue (node, attribs);
|
|
if (blank) {
|
|
wsprintf (g_TempBuffer, TEXT("*%c"), 0);
|
|
}
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
//ICS upgrade functions
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pGetNetAdapterSectionNameBasedOnDriverID retrieves the net adapter name (for example, "Adapter1") based on the ID of
|
|
the driver of this adapter. For example, "0001" is the ID for the driver under
|
|
HKLM\System\CurrentControlSet\Services\Class\Net\0001.
|
|
|
|
Arguments:
|
|
|
|
String of the driver ID
|
|
|
|
Return Value:
|
|
|
|
A pointer to the adapter name
|
|
|
|
--*/
|
|
PCTSTR
|
|
pGetNetAdapterSectionNameBasedOnDriverID(
|
|
PCTSTR pszDriverID
|
|
)
|
|
{
|
|
TCHAR szID[256];
|
|
PCTSTR rAdapterSections = NULL;
|
|
PTSTR string = g_TempBuffer;
|
|
PCSTR pReturn = NULL;
|
|
MEMDB_ENUM e;
|
|
|
|
|
|
//first cache the string for the driver ID
|
|
lstrcpyn(szID, pszDriverID, sizeof(szID)/sizeof(szID[0]));
|
|
|
|
*string = 0;
|
|
|
|
//
|
|
// Enumerate all adapters, and create an entry for each adapter that has
|
|
// TCP bindings.
|
|
//
|
|
|
|
if (pEnumFirstAdapterByBinding(&e, S_MSTCP)) {
|
|
|
|
do {
|
|
|
|
//
|
|
// check whether the driver ID of the card
|
|
//
|
|
|
|
MemDbGetEndpointValueEx(
|
|
MEMDB_CATEGORY_NETADAPTERS,
|
|
e.szName,
|
|
MEMDB_FIELD_DRIVER,
|
|
g_TempBuffer
|
|
);
|
|
|
|
string = _tcsstr(g_TempBuffer, S_NET_PREFIX);
|
|
if (string)
|
|
{
|
|
string += TcharCount(S_NET_PREFIX);
|
|
if (0 == StringICompare(string, szID))
|
|
{
|
|
pReturn = e.szName;
|
|
break;
|
|
}
|
|
}
|
|
|
|
} while (pEnumNextAdapterByBinding(&e,S_MSTCP));
|
|
}
|
|
|
|
return pReturn;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pHomenetSection is used to control whether the "ICSharing" section should show up in the
|
|
answer file or not.
|
|
|
|
If the ICS (Internet Connection Sharing) is installed, then we return "ICSharing" string for
|
|
the first time of this call, otherwise always return NULL. In such way, we can ensure the
|
|
"ICSharing" section will show up in the answer file ONLY when ICS is installed.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
A pointer to "ICSharing" string if ICS is installed.
|
|
Otherwise, return NULL.
|
|
|
|
--*/
|
|
PCTSTR
|
|
pHomenetSection(
|
|
VOID
|
|
)
|
|
{
|
|
static BOOL firstTime = TRUE;
|
|
|
|
PCTSTR pReturn = NULL;
|
|
|
|
if (firstTime && NULL != pGetRegistryValue (S_ICS_KEY, S_EXTERNAL_ADAPTER))
|
|
{
|
|
firstTime = FALSE;
|
|
StringCopy(g_CurrentSection, S_HOMENET);
|
|
pReturn = g_CurrentSection;
|
|
}
|
|
|
|
return pReturn;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pExternalIsAdapter detects whether the External connection of ICS is a LAN connection
|
|
|
|
--*/
|
|
BOOL
|
|
pExternalIsAdapter(
|
|
void
|
|
)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
if (NULL == pGetRegistryValue (S_ICS_KEY, S_EXTERNAL_ADAPTER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return (NULL != pGetNetAdapterSectionNameBasedOnDriverID(g_TempBuffer));
|
|
|
|
return fRet;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pExternalIsRasConn detects whether the External connection of ICS is a RAS connection
|
|
|
|
--*/
|
|
BOOL
|
|
pExternalIsRasConn(
|
|
void
|
|
)
|
|
{
|
|
if (NULL == pGetRegistryValue (S_ICS_KEY, S_EXTERNAL_ADAPTER))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return NULL == pGetNetAdapterSectionNameBasedOnDriverID(g_TempBuffer);
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pHasInternalAdapter detects whether the first Internal Adapter is specified for ICS
|
|
|
|
--*/
|
|
BOOL
|
|
pHasInternalAdapter(
|
|
void
|
|
)
|
|
{
|
|
//To have the "InternalAdapter" key, two conditions have to be statisfy:
|
|
//(1) there is "InternalAdapter" AND
|
|
//(2) this is the only internal adapter, i.e. internal is NOT bridge
|
|
return (NULL != pGetRegistryValue (S_ICS_KEY, S_INTERNAL_ADAPTER) &&
|
|
(!g_fIcsInternalIsBridge));
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pHasBridge detects whether there are two ICS Internal Adapters. If so, we
|
|
need to bridge those two adapter together
|
|
|
|
--*/
|
|
pHasBridge(
|
|
void
|
|
)
|
|
{
|
|
return g_fIcsInternalIsBridge;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pIcsExternalAdapter retrieves the adapter name (for example, "Adapter1")
|
|
for external ICS connection
|
|
|
|
--*/
|
|
PCTSTR
|
|
pIcsExternalAdapter (
|
|
VOID
|
|
)
|
|
{
|
|
PCSTR pszAdapter;
|
|
|
|
if (NULL == pGetRegistryValue(S_ICS_KEY, S_EXTERNAL_ADAPTER))
|
|
return NULL;
|
|
|
|
pszAdapter = pGetNetAdapterSectionNameBasedOnDriverID(g_TempBuffer);
|
|
|
|
if (NULL == pszAdapter)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//ICSHARE adapter's TCP setting overwrite the TCP setting of the external adapter
|
|
//We remember all the info here and will use it when saving the TCP setting of this adapter
|
|
if (0 != lstrlen(g_IcsAdapter))
|
|
{
|
|
//this flag will be used to upgrade the TCP/IP settings of the ICSHARE adapter
|
|
g_fHasIcsExternalAdapter = TRUE;
|
|
lstrcpyn(g_IcsExternalAdapter,
|
|
pszAdapter,
|
|
sizeof(g_IcsExternalAdapter)/sizeof(g_IcsExternalAdapter[0]));
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
StringCopy(g_TempBuffer, pszAdapter);
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pIcsExternalConnectionName retrieves the name (for example, "My Dial-up Connection")
|
|
for external ICS RAS connection
|
|
|
|
--*/
|
|
PCSTR
|
|
pIcsExternalConnectionName (
|
|
VOID
|
|
)
|
|
{
|
|
TCHAR szKey[MEMDB_MAX * 2]; // Contains the current value returned from pGetRegistryValue
|
|
PCSTR pReturn = NULL;
|
|
|
|
if (NULL == pGetRegistryValue(S_ICS_KEY, S_EXTERNAL_ADAPTER))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
StringCopy(szKey, S_NET_DRIVER_KEY);
|
|
StringCat(szKey, _T("\\"));
|
|
StringCat(szKey, g_TempBuffer);
|
|
|
|
//The "DriverDesc" value has to be "Dial-Up Adapter"
|
|
if (NULL == pGetRegistryValue(szKey, S_DRIVERDESC) && 0 != StringCompare(g_TempBuffer, S_DIALUP_ADAPTER_DESC))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//the default ras connection should be the external one. The reg location of the connection name is at
|
|
//HKCU\RemoteAccess\Default
|
|
return pGetRegistryValue(S_REMOTEACCESS_KEY, S_RAS_DEFAULT);
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pInternalIsBridge detects whether there are two ICS Internal Adapters. If so, we
|
|
need to bridge those two adapter together
|
|
|
|
--*/
|
|
PCSTR
|
|
pInternalIsBridge(
|
|
VOID
|
|
)
|
|
{
|
|
g_fIcsInternalIsBridge = (NULL != pGetRegistryValue (S_ICS_KEY, S_INTERNAL_ADAPTER) &&
|
|
NULL != pGetRegistryValue (S_ICS_KEY, S_INTERNAL_ADAPTER2));
|
|
|
|
CLEARBUFFER();
|
|
StringCopy(g_TempBuffer, (g_fIcsInternalIsBridge) ? S_YES : S_NO);
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pInternalAdapter retrieves the adapter name (for example, "Adapter1") for first internal ICS connection
|
|
NOTE: internal connections has to be LAN conncections
|
|
|
|
--*/
|
|
PCSTR
|
|
pInternalAdapter(
|
|
VOID
|
|
)
|
|
{
|
|
PCSTR pszAdapter;
|
|
|
|
if (NULL == pGetRegistryValue(S_ICS_KEY, S_INTERNAL_ADAPTER))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
pszAdapter = pGetNetAdapterSectionNameBasedOnDriverID(g_TempBuffer);
|
|
if (NULL == pszAdapter)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
CLEARBUFFER();
|
|
StringCopy(g_TempBuffer, pszAdapter);
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pBridge retrieves name the two internal adapter names (for example, "Adapter2")
|
|
|
|
--*/
|
|
PCSTR
|
|
pBridge(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
TCHAR szBuff[MEMDB_MAX] = {0};
|
|
TCHAR * psz = szBuff;
|
|
PCSTR pszAdapter;
|
|
|
|
if (NULL == pGetRegistryValue(S_ICS_KEY, S_INTERNAL_ADAPTER))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
pszAdapter = pGetNetAdapterSectionNameBasedOnDriverID(g_TempBuffer);
|
|
if (NULL == pszAdapter)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
StringCopy(psz, pszAdapter);
|
|
psz = GetEndOfString(szBuff) + 1;
|
|
|
|
if (NULL == pGetRegistryValue(S_ICS_KEY, S_INTERNAL_ADAPTER2))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
pszAdapter = pGetNetAdapterSectionNameBasedOnDriverID(g_TempBuffer);
|
|
if (NULL == pszAdapter)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
StringCopy(psz, pszAdapter);
|
|
psz = GetEndOfString(psz) + 1;
|
|
*psz = 0;
|
|
|
|
CLEARBUFFER();
|
|
memcpy(g_TempBuffer, szBuff,
|
|
sizeof(szBuff) < sizeof(g_TempBuffer) ? sizeof(szBuff) : sizeof(g_TempBuffer));
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pDialOnDemand retrieves the dial-on-demand feature
|
|
for ICS connection
|
|
|
|
--*/
|
|
PCSTR
|
|
pDialOnDemand(
|
|
VOID
|
|
)
|
|
{
|
|
PCTSTR KeyString = S_INET_SETTINGS;
|
|
PCTSTR ValueString = S_ENABLE_AUTODIAL;
|
|
PCTSTR rString = NULL;
|
|
HKEY key = NULL;
|
|
PBYTE data = NULL;
|
|
DWORD type = REG_NONE;
|
|
DWORD BufferSize = 0;
|
|
LONG rc = ERROR_SUCCESS;
|
|
PCTSTR end;
|
|
|
|
|
|
//
|
|
//
|
|
// Open registry key.
|
|
//
|
|
key = OpenRegKeyStr(KeyString);
|
|
|
|
if (!key) {
|
|
DEBUGMSG((DBG_WINNTSIF, "Key %s does not exist.",KeyString));
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Get type of data
|
|
//
|
|
rc = RegQueryValueExA (key, ValueString, NULL, &type, NULL, &BufferSize);
|
|
if (rc != ERROR_SUCCESS) {
|
|
DEBUGMSG((DBG_WINNTSIF,"RegQueryValueEx failed for %s[%s]. Value may not exist.",KeyString,ValueString));
|
|
CloseRegKey(key);
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
if (0 == BufferSize ||
|
|
(REG_DWORD != type && REG_BINARY != type))
|
|
{
|
|
DEBUGMSG((DBG_WINNTSIF,"EnableAutoDial is not a DWORD, nor a Binary."));
|
|
CloseRegKey(key);
|
|
return NULL;
|
|
}
|
|
|
|
if (REG_BINARY == type && sizeof(DWORD) != BufferSize)
|
|
{
|
|
DEBUGMSG((DBG_WINNTSIF,"EnableAutoDial is a binary, but the buffer size is not 4."));
|
|
CloseRegKey(key);
|
|
return NULL;
|
|
}
|
|
|
|
data = (PBYTE) MemAlloc (g_hHeap, 0, BufferSize);
|
|
if (NULL == data)
|
|
{
|
|
DEBUGMSG((DBG_WINNTSIF,"Alloc failed. Out of memory."));
|
|
CloseRegKey(key);
|
|
return NULL;
|
|
}
|
|
|
|
rc = RegQueryValueExA (key, ValueString, NULL, NULL, data, &BufferSize);
|
|
if (rc != ERROR_SUCCESS) {
|
|
DEBUGMSG((DBG_WINNTSIF,"RegQueryValueEx failed for %s[%s]. Value may not exist.",KeyString,ValueString));
|
|
MemFree(g_hHeap, 0, data);
|
|
data = NULL;
|
|
CloseRegKey(key);
|
|
SetLastError (rc);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
CLEARBUFFER();
|
|
|
|
wsprintf(g_TempBuffer,"%u",*((DWORD*) data));
|
|
|
|
//
|
|
// Clean up resources.
|
|
//
|
|
CloseRegKey(key);
|
|
if (data) {
|
|
MemFree(g_hHeap, 0, data);
|
|
data = NULL;
|
|
}
|
|
|
|
|
|
return g_TempBuffer;
|
|
}
|
|
|
|
|
|
//
|
|
// Processing functions
|
|
//
|
|
|
|
//
|
|
// g_SectionList contains the list of all winntsif sections that will be enumerated and processed by BuildWinntSifFile.
|
|
//
|
|
SECTION g_SectionList[] = {WINNTSIF_SECTIONS /*,*/ {NULL,NULL,{{LAST_SETTING,NULL,NULL,{NULL,NULL}}}}};
|
|
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
pProcessSectionSettings is responsible for processing a single section
|
|
worth of data. For this section, it will process all of the settings in the
|
|
settinglist passed in.
|
|
|
|
Arguments:
|
|
|
|
SectionName - The name of the section being processed.
|
|
SettingsList - a list of settings to be processed for this sections.
|
|
|
|
Return Value:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
BOOL
|
|
pProcessSectionSettings (
|
|
IN PCTSTR SectionName,
|
|
IN PSETTING SettingsList
|
|
)
|
|
{
|
|
|
|
PSETTING curSetting = SettingsList;
|
|
PTSTR data = NULL;
|
|
PTSTR p;
|
|
MULTISZ_ENUM e;
|
|
UINT index = 0;
|
|
TCHAR key[MEMDB_MAX];
|
|
|
|
|
|
MYASSERT(curSetting);
|
|
MYASSERT(SectionName);
|
|
|
|
DEBUGMSG((DBG_WINNTSIF,"pProcessSectionSettings: Processing [%s] Section...",SectionName));
|
|
|
|
//
|
|
// The last setting in the list is a null setting with the type LAST_SETTING. We use this as the
|
|
// break condition of our loop.
|
|
//
|
|
while (curSetting -> SettingType != LAST_SETTING) {
|
|
|
|
if (!curSetting -> CreationFunction || curSetting -> CreationFunction()) {
|
|
|
|
//
|
|
// Any setting that gets to this point MUST have a key name.
|
|
// Since this data is static, we just assert this.
|
|
//
|
|
MYASSERT(curSetting -> KeyName);
|
|
|
|
//
|
|
// We must still get the data for this particular setting. How we get that data is determined by
|
|
// the SettingType of the current setting. If at the end, data is NULL, we will write nothing.
|
|
//
|
|
switch (curSetting -> SettingType) {
|
|
|
|
case FUNCTION_SETTING:
|
|
|
|
data = (PTSTR) curSetting -> Data.Function();
|
|
break;
|
|
|
|
case STRING_SETTING:
|
|
|
|
StringCopy(g_TempBuffer,curSetting -> Data.String);
|
|
p = GetEndOfString (g_TempBuffer) + 1;
|
|
*p = 0;
|
|
data = g_TempBuffer;
|
|
break;
|
|
|
|
case REGISTRY_SETTING:
|
|
data = (PTSTR) pGetRegistryValue(curSetting -> Data.Registry.Key, curSetting -> Data.Registry.Value);
|
|
break;
|
|
|
|
default:
|
|
DEBUGMSG((
|
|
DBG_WHOOPS,
|
|
"pProcessSectionSettings: Unexpected Setting Type for Section %s, Key %s. (Type: %u)",
|
|
SectionName,
|
|
curSetting -> KeyName,
|
|
curSetting -> SettingType
|
|
));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If we found data, go ahead and create the setting. All data is stored in multi strings, typically only one string long.
|
|
//
|
|
if (data) {
|
|
|
|
//
|
|
// Make sure this isn't suppressed.
|
|
//
|
|
MemDbBuildKey (
|
|
key,
|
|
MEMDB_CATEGORY_SUPPRESS_ANSWER_FILE_SETTINGS,
|
|
SectionName,
|
|
curSetting->KeyName,
|
|
NULL
|
|
);
|
|
|
|
|
|
if (MemDbGetPatternValue (key, NULL)) {
|
|
|
|
DEBUGMSG ((DBG_WINNTSIF, "Answer File Section is suppressed: [%s] %s", SectionName, curSetting->KeyName));
|
|
}
|
|
else {
|
|
|
|
DEBUGMSG((DBG_WINNTSIF,"Creating WinntSif Entry: Section: %s, Key: %s.",SectionName, curSetting -> KeyName));
|
|
|
|
|
|
|
|
if (EnumFirstMultiSz(&e,data)) {
|
|
index = 0;
|
|
do {
|
|
|
|
index = WriteInfKeyEx(SectionName, curSetting -> KeyName, e.CurrentString, index, FALSE);
|
|
DEBUGMSG_IF((
|
|
!index,
|
|
DBG_ERROR,
|
|
"pProcessSectionSettings: WriteInfKeyEx Failed. Section: %s Key: %s Value: %s",
|
|
SectionName,
|
|
curSetting -> KeyName,
|
|
e.CurrentString
|
|
));
|
|
DEBUGMSG_IF((index,DBG_WINNTSIF,"Value: %s",e.CurrentString));
|
|
|
|
} while (EnumNextMultiSz(&e));
|
|
}
|
|
}
|
|
}
|
|
ELSE_DEBUGMSG((DBG_WARNING,"pProcessSectionSettings: No data for Section %s, Key %s.",SectionName, curSetting -> KeyName));
|
|
}
|
|
|
|
curSetting++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
BuildWinntSifFile is responsible for writing all of the necessary unattend
|
|
settings to the winnt.sif file. The Win9xUpg code uses these unattended
|
|
settings to control the behavior of text mode and GUI mode setup so that
|
|
the settings gathered from win9x are incorporated into the new NT
|
|
system.
|
|
|
|
The settings to be written are kept in the global list g_SettingL
|
|
ist which is itself built from macro expansion lists. This function cycles
|
|
through these settings, calculating wether each setting should be written
|
|
and if so, with what data.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the function returned successfully, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
|
|
BOOL
|
|
pBuildWinntSifFile (
|
|
VOID
|
|
)
|
|
{
|
|
BOOL rSuccess = TRUE;
|
|
PSECTION curSection = g_SectionList;
|
|
PCTSTR sectionName = NULL;
|
|
|
|
while (curSection -> SectionString || curSection -> SectionFunction) {
|
|
|
|
|
|
sectionName = curSection -> SectionString ? curSection -> SectionString : curSection -> SectionFunction();
|
|
|
|
while (sectionName) {
|
|
|
|
if (!pProcessSectionSettings (sectionName,curSection -> SettingList)) {
|
|
LOG ((LOG_ERROR,"Unable to process answer file settings for %s Section.",sectionName));
|
|
rSuccess = FALSE;
|
|
}
|
|
|
|
//
|
|
// If the section name was from a static string, we set the sectionName to NULL, exiting this loop.
|
|
// If the section name was from a function, we call the function again. If there is another
|
|
// section to build, it will return a new name, otherwise, it will return NULL.
|
|
//
|
|
sectionName = curSection -> SectionString ? NULL : curSection -> SectionFunction();
|
|
}
|
|
|
|
//
|
|
// Go to the next setting.
|
|
//
|
|
curSection++;
|
|
}
|
|
return rSuccess;
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD
|
|
BuildWinntSifFile (
|
|
DWORD Request
|
|
)
|
|
{
|
|
switch (Request) {
|
|
case REQUEST_QUERYTICKS:
|
|
return TICKS_BUILD_UNATTEND;
|
|
case REQUEST_RUN:
|
|
if (!pBuildWinntSifFile ()) {
|
|
return GetLastError ();
|
|
}
|
|
else {
|
|
return ERROR_SUCCESS;
|
|
}
|
|
default:
|
|
DEBUGMSG ((DBG_ERROR, "Bad parameter in BuildWinntSif"));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
VOID
|
|
TerminateWinntSifBuilder (
|
|
VOID
|
|
)
|
|
{
|
|
if (g_LocalePool) {
|
|
HtFree (g_LocaleTable);
|
|
PoolMemDestroyPool (g_LocalePool);
|
|
|
|
g_LocaleTable = NULL;
|
|
g_LocalePool = NULL;
|
|
}
|
|
}
|