587 lines
16 KiB
C++
587 lines
16 KiB
C++
//
|
|
// ICSInst.cpp
|
|
//
|
|
// ICS (Internet Connection Sharing) installation functions and thunk
|
|
// layer.
|
|
//
|
|
// History:
|
|
//
|
|
// 9/27/1999 RayRicha Created
|
|
// 11/01/1999 KenSh Store function ptrs in array rather than globals
|
|
// 12/09/1999 KenSh Check for 3rd party NATs
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "ICSInst.h"
|
|
#include "TheApp.h"
|
|
#include "Config.h"
|
|
#include "DefConn.h"
|
|
#include "NetConn.h"
|
|
#include "Util.h"
|
|
#include "netapi.h"
|
|
extern "C" {
|
|
#include "icsapi.h"
|
|
}
|
|
|
|
// these are the Command Line parameters to CreateProcess for running a first time install and a reconfig
|
|
static const TCHAR c_szUpdateDriverBindings[] = _T("rundll.exe ISSETUP.DLL,UpdateDriverBindings");
|
|
static const TCHAR c_szInstallICS[] = _T("rundll.exe ISSETUP.DLL,InstallOptionalComponent ICS");
|
|
static const TCHAR c_szUninstall[] = _T("rundll.exe ISSETUP.DLL,ExtUninstall");
|
|
static const TCHAR c_szICSSettingsKey[] = _T("System\\CurrentControlSet\\Services\\ICSharing\\Settings\\General");
|
|
static const TCHAR c_szICSInt[] = _T("System\\CurrentControlSet\\Services\\ICSharing\\Settings\\General\\InternalAdapters");
|
|
static const TCHAR c_szInternalAdapters[] = _T("InternalAdapters");
|
|
static const TCHAR c_szRunServices[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\RunServices");
|
|
#define c_szIcsRegVal_ShowTrayIcon _T("ShowTrayIcon")
|
|
|
|
#define SZ_UNINSTALL_KEY _T("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall")
|
|
|
|
|
|
static void (PASCAL FAR * g_pfInstallOptionalComponent)(HWND, HINSTANCE, LPSTR, int);
|
|
HHOOK g_hSupressRebootHook = NULL;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Helper functions
|
|
|
|
BOOL RunNetworkInstall(BOOL* pfRebootRequired)
|
|
{
|
|
PROCESS_INFORMATION ProcessInfo;
|
|
STARTUPINFO si;
|
|
DWORD dwExitCode = 0xffffffffL;
|
|
BOOL fSuccess;
|
|
|
|
memset((char *)&si, 0, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
si.wShowWindow = SW_SHOW;
|
|
|
|
fSuccess = CreateProcess(NULL, (LPTSTR)c_szUpdateDriverBindings, NULL, NULL, FALSE,
|
|
0, NULL, NULL, &si, &ProcessInfo);
|
|
|
|
if (fSuccess)
|
|
{
|
|
HANDLE hProcess = ProcessInfo.hProcess;
|
|
|
|
CloseHandle(ProcessInfo.hThread);
|
|
|
|
//
|
|
// wait for update driver bindings to complete
|
|
//
|
|
|
|
WaitForSingleObject(hProcess, INFINITE);
|
|
|
|
GetExitCodeProcess(hProcess, &dwExitCode);
|
|
CloseHandle(hProcess);
|
|
|
|
*pfRebootRequired = TRUE;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// check for 3rd party NATs - returns TRUE if any are installed
|
|
BOOL IsOtherNATAlreadyInstalled(LPTSTR pszOtherNatDescription, int cchOtherNatDescription)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
CRegistry reg;
|
|
LPCTSTR pszUninstallKey = NULL;
|
|
|
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szRunServices, KEY_READ))
|
|
{
|
|
if (0 != reg.GetValueSize(_T("SyGateService")))
|
|
{
|
|
bRet = TRUE;
|
|
pszUninstallKey = _T("SyGate");
|
|
}
|
|
else if (0 != reg.GetValueSize(_T("WinGate Service")))
|
|
{
|
|
bRet = TRUE;
|
|
pszUninstallKey = _T("WinGate");
|
|
}
|
|
else if (0 != reg.GetValueSize(_T("ENSApServer"))) // Intel AnyPoint
|
|
{
|
|
bRet = TRUE;
|
|
pszUninstallKey = _T("Intel AnyPoint Network Software");
|
|
}
|
|
else if (0 != reg.GetValueSize(_T("WinNATService"))) // Diamond HomeFree
|
|
{
|
|
bRet = TRUE;
|
|
pszUninstallKey = _T("WinNAT");
|
|
}
|
|
}
|
|
|
|
// WinProxy has to be launched manually, and requires a static IP. Just check
|
|
// to see if it's installed - the user might not even be running it.
|
|
//
|
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, SZ_UNINSTALL_KEY _T("\\WinProxy"), KEY_READ))
|
|
{
|
|
bRet = TRUE;
|
|
pszUninstallKey = _T("WinProxy");
|
|
}
|
|
|
|
if (pszOtherNatDescription != NULL)
|
|
{
|
|
*pszOtherNatDescription = _T('\0');
|
|
|
|
if (bRet) // Get the friendly name of the conflicting service from uninstall key
|
|
{
|
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, SZ_UNINSTALL_KEY, KEY_READ))
|
|
{
|
|
if (reg.OpenSubKey(pszUninstallKey, KEY_READ))
|
|
{
|
|
reg.QueryStringValue(_T("DisplayName"), pszOtherNatDescription, cchOtherNatDescription);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// CICSInst
|
|
|
|
CICSInst::CICSInst()
|
|
{
|
|
m_option = ICS_NOACTION;
|
|
m_pszHostName = theApp.LoadStringAlloc(IDS_ICS_HOST);
|
|
m_bInstalledElsewhere = FALSE;
|
|
|
|
m_bShowTrayIcon = TRUE;
|
|
CRegistry reg;
|
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey, KEY_READ))
|
|
{
|
|
TCHAR szTrayIcon[10];
|
|
if (reg.QueryStringValue(c_szIcsRegVal_ShowTrayIcon, szTrayIcon, _countof(szTrayIcon)))
|
|
{
|
|
if (!StrCmp(szTrayIcon, _T("0")))
|
|
{
|
|
m_bShowTrayIcon = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CICSInst::~CICSInst()
|
|
{
|
|
free(m_pszHostName);
|
|
}
|
|
|
|
BOOL
|
|
CICSInst::InitICSAPI()
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
// UpdateIcsTrayIcon
|
|
//
|
|
// Updates the registry values that affect the ICS tray icon, and
|
|
// immediately updates the icon to reflect the new values.
|
|
//
|
|
// 2/04/2000 KenSh Created
|
|
//
|
|
void CICSInst::UpdateIcsTrayIcon()
|
|
{
|
|
CRegistry reg;
|
|
if (reg.CreateKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey))
|
|
{
|
|
// Update the tray icon setting in the registry
|
|
TCHAR szVal[2];
|
|
szVal[0] = m_bShowTrayIcon ? _T('1') : _T('0');
|
|
szVal[1] = _T('\0');
|
|
reg.SetStringValue(c_szIcsRegVal_ShowTrayIcon, szVal);
|
|
}
|
|
|
|
// Show or hide the icon immediately
|
|
HWND hwndTray = ::FindWindow(_T("ICSTrayWnd"), NULL);
|
|
if (hwndTray != NULL)
|
|
{
|
|
// Post a custom message to the ICS manager window (icshare\util\icsmgr\trayicon.c)
|
|
//
|
|
// This message shows or hides the tray icon according to the value in
|
|
// the registry.
|
|
//
|
|
// wParam: enable/disable accordint to value in registry
|
|
// lParam: unused
|
|
//
|
|
UINT uUpdateMsg = RegisterWindowMessage(_T("ICSTaskbarUpdate"));
|
|
PostMessage(hwndTray, uUpdateMsg, FALSE, 0L);
|
|
}
|
|
}
|
|
|
|
void CICSInst::DoInstallOption(BOOL* pfRebootRequired, UINT ipaInternal)
|
|
{
|
|
BOOL bIcsInstalled = ::IsIcsInstalled();
|
|
|
|
// Force uninstall if internal or external NIC is not valid
|
|
if ((m_option == ICS_UNINSTALL && TRUE == bIcsInstalled)||
|
|
(bIcsInstalled && m_option == ICS_NOACTION && !this->IsInstalled()))
|
|
{
|
|
Uninstall(pfRebootRequired);
|
|
bIcsInstalled = FALSE;
|
|
}
|
|
|
|
// Force tray icon to show up, if ICS is currently installed
|
|
m_bShowTrayIcon = TRUE;
|
|
UpdateIcsTrayIcon();
|
|
|
|
switch (m_option)
|
|
{
|
|
case ICS_INSTALL:
|
|
if(FALSE == IsInstalled())
|
|
{
|
|
Install(pfRebootRequired, ipaInternal);
|
|
}
|
|
break;
|
|
|
|
case ICS_UPDATEBINDINGS:
|
|
UpdateBindings(pfRebootRequired, ipaInternal);
|
|
break;
|
|
|
|
case ICS_UNINSTALL:
|
|
// Already handled above
|
|
break;
|
|
|
|
case ICS_ENABLE:
|
|
Enable();
|
|
break;
|
|
|
|
case ICS_DISABLE:
|
|
Disable();
|
|
break;
|
|
|
|
case ICS_CLIENTSETUP:
|
|
SetupClient();
|
|
break;
|
|
|
|
case ICS_NOACTION:
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
// Similar steps from here as Win98SE ConfigureICS (without UI)
|
|
void CICSInst::UpdateBindings(BOOL* pfRebootRequired, UINT ipaInternal)
|
|
{
|
|
CConfig rghConfig;
|
|
|
|
// TODO: remove hardcoded values!
|
|
StrCpy(rghConfig.m_HangupTimer, _T("300"));
|
|
|
|
SetInternetConnection();
|
|
SetHomeConnection(ipaInternal);
|
|
|
|
// REVIEW: is there a case where these values should be set differently?
|
|
rghConfig.m_EnableICS = TRUE;
|
|
rghConfig.m_EnableDialOnDemand = TRUE;
|
|
rghConfig.m_EnableDHCP = TRUE;
|
|
rghConfig.m_ShowTrayIcon = m_bShowTrayIcon;
|
|
|
|
rghConfig.InitWizardResult();
|
|
// Set to TRUE until we see a need to differentiate between new install and update
|
|
rghConfig.WriteWizardCode(TRUE);
|
|
|
|
int iSaveStatus = rghConfig.SaveConfig();
|
|
|
|
// TODO: determine if we need to check for binding changes
|
|
//if ( iSaveStatus == BINDINGS_NEEDED )
|
|
//{
|
|
RunNetworkInstall(pfRebootRequired);
|
|
//}
|
|
}
|
|
|
|
void CICSInst::Install(BOOL* pfRebootRequired, UINT ipaInternal)
|
|
{
|
|
PROCESS_INFORMATION ProcessInfo;
|
|
STARTUPINFO si;
|
|
BOOL fSuccess;
|
|
|
|
// Check for conflicting 3rd party NAT
|
|
{
|
|
TCHAR szConflictingNAT[260];
|
|
if (IsOtherNATAlreadyInstalled(szConflictingNAT, _countof(szConflictingNAT)))
|
|
{
|
|
if (szConflictingNAT[0] == _T('\0'))
|
|
{
|
|
LPTSTR pszDefault1 = theApp.LoadStringAlloc(IDS_OTHERNAT_GENERIC);
|
|
LPTSTR pszDefault2 = theApp.LoadStringAlloc(IDS_OTHERNAT_GENERIC_THE);
|
|
if (pszDefault1 && pszDefault2)
|
|
theApp.MessageBoxFormat(MB_ICONEXCLAMATION | MB_OK, IDS_ERR_OTHERNAT, pszDefault1, pszDefault2);
|
|
free(pszDefault2);
|
|
free(pszDefault1);
|
|
}
|
|
else
|
|
{
|
|
theApp.MessageBoxFormat(MB_ICONEXCLAMATION | MB_OK, IDS_ERR_OTHERNAT, szConflictingNAT, szConflictingNAT);
|
|
}
|
|
|
|
return; // block ICS installation
|
|
}
|
|
}
|
|
|
|
ZeroMemory(&si, sizeof(si));
|
|
si.cb = sizeof(si);
|
|
si.wShowWindow = SW_SHOW;
|
|
|
|
fSuccess = CreateProcess(NULL, (LPTSTR)c_szInstallICS, NULL, NULL, FALSE,
|
|
0, NULL, NULL, &si, &ProcessInfo);
|
|
if (fSuccess)
|
|
{
|
|
HANDLE hProcess = ProcessInfo.hProcess;
|
|
CloseHandle(ProcessInfo.hThread);
|
|
|
|
//
|
|
// wait for update driver bindings to complete
|
|
//
|
|
|
|
WaitForSingleObject(hProcess, INFINITE);
|
|
|
|
CloseHandle(hProcess);
|
|
UpdateBindings(pfRebootRequired, ipaInternal);
|
|
|
|
// Need to reboot
|
|
*pfRebootRequired = TRUE;
|
|
}
|
|
}
|
|
|
|
LRESULT CALLBACK SupressRebootDialog(int nCode, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT lResult = 0;
|
|
if (nCode == HCBT_CREATEWND)
|
|
{
|
|
HWND hwnd = (HWND)wParam;
|
|
CBT_CREATEWND* pCW = (CBT_CREATEWND*)lParam;
|
|
|
|
LPCREATESTRUCT pCreateStruct = pCW->lpcs;
|
|
|
|
|
|
lResult = 1; // prevent window creation
|
|
}
|
|
else
|
|
{
|
|
lResult = CallNextHookEx(g_hSupressRebootHook, nCode, wParam, lParam);
|
|
}
|
|
|
|
return lResult;
|
|
|
|
}
|
|
|
|
void CICSInst::Uninstall(BOOL* pfRebootRequired)
|
|
{
|
|
g_hSupressRebootHook = SetWindowsHookEx(WH_CBT, SupressRebootDialog, NULL, GetCurrentThreadId()); // not thread safe, should be OK
|
|
|
|
IcsUninstall();
|
|
|
|
if(NULL != g_hSupressRebootHook)
|
|
{
|
|
UnhookWindowsHookEx(g_hSupressRebootHook );
|
|
}
|
|
|
|
*pfRebootRequired = TRUE;
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL CICSInst::IsInstalled()
|
|
{
|
|
// Make sure ICS is installed correctly by checking Internet and Home connection.
|
|
return (IsIcsInstalled() && GetICSConnections(NULL, NULL) && IsHomeConnectionValid());
|
|
}
|
|
|
|
BOOL CICSInst::IsEnabled()
|
|
{
|
|
return IsIcsEnabled();
|
|
}
|
|
|
|
BOOL CICSInst::IsInstalledElsewhere()
|
|
{
|
|
if (m_bInstalledElsewhere || IsIcsAvailable())
|
|
{
|
|
//MessageBox(theApp.m_hWndMain, "IsIcsAvailable returned TRUE", "Test", MB_OK);
|
|
|
|
// Note: if we knew the name of the ICS host, here's where we'd set m_pszHostName.
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
//MessageBox(theApp.m_hWndMain, "IsIcsAvailable returned FALSE", "Test", MB_OK);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
void CICSInst::SetInternetConnection()
|
|
{
|
|
/*
|
|
if (-1 != theApp.m_uExternalAdapter)
|
|
{
|
|
TCHAR szClassKey[MAX_KEY_SIZE];
|
|
StrCpy(szClassKey, FindFileTitle(theApp.m_pCachedNetAdapters[theApp.m_uExternalAdapter].szClassKey));
|
|
|
|
CRegistry reg;
|
|
reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey);
|
|
reg.SetStringValue(_T("ExternalAdapter"), szClassKey);
|
|
reg.SetStringValue(_T("ExternalAdapterReg"), szClassKey);
|
|
}
|
|
*/
|
|
}
|
|
|
|
BOOL CICSInst::GetICSConnections(LPTSTR szExternalConnection, LPTSTR szInternalConnection)
|
|
{
|
|
CRegistry reg;
|
|
TCHAR szEntry[10];
|
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey, KEY_READ))
|
|
{
|
|
if (reg.QueryStringValue(_T("ExternalAdapterReg"), szEntry, _countof(szEntry)) &&
|
|
lstrlen(szEntry))
|
|
{
|
|
if (szExternalConnection)
|
|
{
|
|
StrCpy(szExternalConnection, szEntry);
|
|
}
|
|
|
|
if (reg.QueryStringValue(_T("InternalAdapterReg"), szEntry, _countof(szEntry)) &&
|
|
lstrlen(szEntry))
|
|
{
|
|
if (szInternalConnection)
|
|
{
|
|
StrCpy(szInternalConnection, szEntry);
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void CICSInst::SetHomeConnection(UINT ipaInternal)
|
|
{
|
|
int cInternalAdapter = 0; // hack for one adapter
|
|
TCHAR szNumber[5];
|
|
wnsprintf(szNumber, ARRAYSIZE(szNumber), TEXT("%04d"), cInternalAdapter);
|
|
|
|
const NETADAPTER* pAdapterArray;
|
|
EnumCachedNetAdapters(&pAdapterArray);
|
|
const NETADAPTER* pAdapter = &pAdapterArray[ipaInternal];
|
|
|
|
TCHAR szClassKey[MAX_KEY_SIZE];
|
|
StrCpy(szClassKey, FindFileTitle((LPCTSTR)pAdapter->szClassKey));
|
|
|
|
LPTSTR* prgBindings;
|
|
int cBindings = EnumMatchingNetBindings(pAdapter->szEnumKey, SZ_PROTOCOL_TCPIP, (LPWSTR**)&prgBindings);
|
|
|
|
CRegistry reg2(HKEY_LOCAL_MACHINE, c_szICSInt);
|
|
reg2.CreateSubKey(szNumber);
|
|
reg2.SetStringValue(_T("InternalAdapterReg"), szClassKey);
|
|
reg2.SetStringValue(_T("InternalAdapter"), szClassKey);
|
|
|
|
// Assume that adapter is only bound to one TCP/IP instance
|
|
reg2.SetStringValue(_T("InternalBinding"), prgBindings[0]);
|
|
|
|
TCHAR szIPAddress[30];
|
|
wnsprintf(szIPAddress, ARRAYSIZE(szIPAddress), TEXT("192.168.%d.1,255.255.255.0"), cInternalAdapter);
|
|
reg2.SetStringValue(_T("IntranetInfo"), szIPAddress);
|
|
|
|
// TODO: remove
|
|
// Put the first adapter in the "old location" to support legacy config
|
|
CRegistry reg;
|
|
reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey);
|
|
reg.DeleteSubKey(c_szInternalAdapters);
|
|
reg.CreateSubKey(c_szInternalAdapters);
|
|
|
|
reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey);
|
|
reg.SetStringValue(_T("InternalAdapterReg"), szClassKey);
|
|
reg.SetStringValue(_T("InternalAdapter"), szClassKey);
|
|
|
|
// Assume that adapter is only bound to one TCP/IP instance
|
|
reg.SetStringValue(_T("InternalBinding"), prgBindings[0]);
|
|
reg.SetStringValue(_T("IntranetInfo"), szIPAddress);
|
|
}
|
|
|
|
// TODO: expand with support for multiple adapters
|
|
BOOL CICSInst::IsHomeConnectionValid()
|
|
{
|
|
CRegistry reg;
|
|
TCHAR szEntry[10];
|
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSSettingsKey, KEY_READ))
|
|
{
|
|
if (reg.QueryStringValue(_T("InternalAdapterReg"), szEntry, _countof(szEntry)) &&
|
|
lstrlen(szEntry))
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Check for valid multiple-adapter scenario
|
|
if (reg.OpenKey(HKEY_LOCAL_MACHINE, c_szICSInt) &&
|
|
reg.OpenSubKey(_T("0000")) &&
|
|
reg.QueryStringValue(_T("InternalAdapterReg"), szEntry, _countof(szEntry)) &&
|
|
lstrlen(szEntry))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CICSInst::Enable()
|
|
{
|
|
if (InitICSAPI())
|
|
{
|
|
IcsEnable(0);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
// return (!IcsEnable(0));
|
|
}
|
|
|
|
BOOL CICSInst::Disable()
|
|
{
|
|
if (InitICSAPI())
|
|
{
|
|
IcsDisable(0);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
// return (!IcsDisable(0));
|
|
}
|
|
|
|
void CICSInst::SetupClient()
|
|
{
|
|
// Move this functionality to WizPages.cpp and Install.cpp for now
|
|
//::SetDefaultDialupConnection(NULL);
|
|
}
|
|
|
|
BOOLEAN APIENTRY IsIcsInstalled(VOID) // API not available on Win98 so implement it here
|
|
{
|
|
BOOLEAN fIcsInstalled = FALSE;
|
|
|
|
HKEY hKey;
|
|
DWORD dwRet = RegOpenKeyEx (HKEY_LOCAL_MACHINE, REGSTR_PATH_RUN, (DWORD)0, KEY_READ, &hKey);
|
|
if (ERROR_SUCCESS == dwRet)
|
|
{
|
|
|
|
DWORD dwType;
|
|
char szValue[128];
|
|
DWORD dwSize = sizeof(szValue) / sizeof(char);
|
|
|
|
dwRet = RegQueryValueExA(hKey, "ICSMGR", NULL, &dwType, reinterpret_cast<LPBYTE>(szValue), &dwSize);
|
|
if ((ERROR_SUCCESS == dwRet) && (dwType == REG_SZ))
|
|
{
|
|
fIcsInstalled = 0 == lstrcmpA(szValue, "ICSMGR.EXE");
|
|
}
|
|
|
|
RegCloseKey ( hKey );
|
|
}
|
|
|
|
return (fIcsInstalled);
|
|
}
|