// // 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(szValue), &dwSize); if ((ERROR_SUCCESS == dwRet) && (dwType == REG_SZ)) { fIcsInstalled = 0 == lstrcmpA(szValue, "ICSMGR.EXE"); } RegCloseKey ( hKey ); } return (fIcsInstalled); }