📄 netchck.cpp
字号:
return HXR_OK;
}
//******************************************************************************
//
// Method: CHXNetCheck::Init
//
// Purpose: Sets up the CHXNetCheck object with a context.
//
//
// Notes: n/a
//
//******************************************************************************
HX_RESULT
CHXNetCheck::Init(IUnknown *pContext)
{
HX_RESULT result = HXR_OK;
if (!pContext)
return HXR_FAILED;
m_pContext = pContext;
m_pContext->AddRef();
return result;
}
//******************************************************************************
//
// Method: CHXNetCheck::FInternetAvailable
//
// Purpose: The function checks if we can attempt a connection without
// being prompted to connect.
// Returns true if we can, false otherwise.
//
// Notes: There is no single function for determining if a machine is
// connected to the internet, and it is impossible to reliably
// determine what is happening without side effects - such as
// automatic network connections taking place.
//
// MSDN article -
// "HOWTO: Detecting If you have a Connection to the Internet"
//
// "Usually the best way to determine if you have a connection
// to a particular computer is to attempt the connection. If the
// autodial feature of Windows is enabled then attempting the
// connection may cause the default Internet dialup connectoid
// to be opened, and you will be prompted with your credentials to connect.
//
// To avoid having the default Internet connectoid dialed,
// the InternetGetConnectedState function can be used to determine
// if there is a default Internet dialup connectoid configured and
// whether it is currently active or not. If there is a default
// Internet dialup connectoid configured and it is not currently
// active then InternetGetConnectedState will return FALSE.
// If InternetGetConnectedState returns TRUE then you can attempt
// to connect to the Internet resource without fear of being prompted
// to connect to another Internet Service Provider.
//
// You cannot rely solely on the fact that InternetGetConnectedState
// returning TRUE means that you have a valid active Internet
// connection. It is impossible for InternetGetConnectedState
// to determine if the entire connection to the Internet is
// functioning without sending a request to a server. This is why
// you need to send a request to determine if you are really connected
// or not. You can be assured however that if InternetGetConnectedState
// returns TRUE, that attempting your connection will NOT cause you
// to be prompted to connect to the default Internet Service Provider.
//
// Be aware that InternetGetConnectedState only reports the status
// of the default Internet connectoid on Internet Explorer 4.x.
// If a nondefault connectoid is connected, InternetGetConnectedState
// always returns FALSE (unless a LAN connection is used).
// With Internet Explorer 4.x configured to use a LAN connection,
// InternetGetConectedState always returns TRUE.
//
// Internet Explorer 5 behaves differently. If you are currently dialed
// into a different dial-up in Internet Explorer 5, InternetGetConnectedState
// reports dial-up connection status as long as any connectoid is dialed
// or an active LAN connection exists."
//
//******************************************************************************
BOOL
CHXNetCheck::FInternetAvailable(BOOL fPing, BOOL fProxy)
{
using namespace NetDetectLog;
NetDetectLogLib logLib;
BOOL fRet = FALSE;
UINT16 nPort = DEF_HTTP_PORT;
#ifndef _WIN16
WRITE_LOG0("FInternetAvailable fc entered...");
HKEY hKey = 0 ;
DWORD fAutoDial = 0 ;
DWORD regType = 0 ;
DWORD cbBuf;
#if !defined(WIN32_PLATFORM_PSPC)
// set the error mode since we'll do some DLL loading and we want the OS to be
// quiet whhen we do this
UINT oldErrorMode = ::SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
#endif /* !defined(WIN32_PLATFORM_PSPC) */
// XXXSO - agreed to use InternetGetConnectedState function only.
// The rest of the code should be called when this function is not available.
BOOL fConnected = FALSE;
if( SUCCEEDED( WinInetGetConnected( fConnected )))
{
fRet = fPing ? SmartPing() : fConnected;
goto Ret;
}
// XXXKM - agreed to remove proxy impact on net detect; instead let the following code determine
// if we are connected or not - doing so will alleviate issues with proxy and dialup
#if 0
if (fProxy)
return TRUE;
#endif
WRITE_LOG0("Old algorithm entered ... ");
WRITE_LOG0("Checking autodial flag ...");
// XXXKM - check this early; if autodial is set, then return FALSE temporarily
// check the autodial bit in the registry.
cbBuf = sizeof(fAutoDial);
if (RegOpenKey(HKEY_CURRENT_USER, OS_STRING("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"),
&hKey) == ERROR_SUCCESS)
{
OSVERSIONINFO osv;
memset(&osv, 0, sizeof(osv));
osv.dwOSVersionInfoSize = sizeof(osv);
GetVersionEx(&osv);
if (osv.dwPlatformId != VER_PLATFORM_WIN32_NT)
{
WRITE_LOG0("Checking Win95/98 EnableAutodial flag in HKCU/Software/Microsoft/Windows"
"/Current Version/Internet Settings...");
// check for the Win95/98 flag
RegQueryValueEx(hKey, OS_STRING("EnableAutodial"), NULL, ®Type, (BYTE *) &fAutoDial, &cbBuf);
}
else
{
WRITE_LOG0("Checking for the RAS key on NT.");
// XXXKM - check for the RAS key on NT; only way I could find around the assert/crash in rasapi32.dll
// in situations where the dll existed, but ras was disabled/removed on the machine
HKEY hRasKey = 0;
if (::RegOpenKey(HKEY_LOCAL_MACHINE, OS_STRING("SOFTWARE\\Microsoft\\RAS"), &hRasKey) == ERROR_SUCCESS)
{
// close the ras key
::RegCloseKey(hRasKey);
// initialize to FALSE so this works the way it always has if something doesn't go right
fAutoDial = FALSE;
if (!m_hRasApiModule)
m_hRasApiModule = ::LoadLibrary(OS_STRING("rasapi32.dll"));
if (m_hRasApiModule)
{
WRITE_LOG0("rasapi32.dll loaded...");
// try and get the API to enumerate RAS devices
FPRASENUMDEVICES fpRasEnumDevices = (FPRASENUMDEVICES)GetProcAddress(m_hRasApiModule,
OS_STRING("RasEnumDevicesA"));
if (!fpRasEnumDevices)
{
fpRasEnumDevices = (FPRASENUMDEVICES)GetProcAddress(m_hRasApiModule,
OS_STRING("RasEnumDevicesW"));
}
// we use this to see if there is a RAS enabled device on this system and also to
// check for initialization of the RAS subsystem since it will return an error if
// RAS is disabled or fails to initialize for whatever reason
// XXXKM - this was added to prevent crashing on Win NT systems in the EnumEntries call
// on machines where RAS has been disabled due to hardware profiles
if (fpRasEnumDevices)
{
WRITE_LOG0("Checking the RAS enabled devices...");
RASDEVINFO rasDevInfo[1];
rasDevInfo[0].dwSize = sizeof(rasDevInfo);
DWORD bufferSize = sizeof(rasDevInfo);
DWORD numEntries = 0;
DWORD retVal = fpRasEnumDevices(rasDevInfo, &bufferSize, &numEntries);
// check if there was actually a RAS enabled device; this API will return an error
// if there are no RAS devices enabled, or if the RAS subsystem couldn't be initialized
if (retVal == ERROR_BUFFER_TOO_SMALL || retVal == ERROR_SUCCESS && numEntries == 1)
{
// find the right entrypoint in the rasapi32.dll
FPRASENUMENTRIES fpRasEnumEntries = (FPRASENUMENTRIES)GetProcAddress(m_hRasApiModule,
OS_STRING("RasEnumEntriesA"));
if (!fpRasEnumEntries)
{
fpRasEnumEntries = (FPRASENUMENTRIES)GetProcAddress(m_hRasApiModule,
OS_STRING("RasEnumEntriesW"));
}
// if we've got the RAS entries function, then call it
if (fpRasEnumEntries)
{
WRITE_LOG0("Calling RasEnumEntries function...");
// setup the RAS entry structure for a single dialup item
RASENTRYNAME rasEntryName[1];
rasEntryName[0].dwSize = sizeof(rasEntryName);
bufferSize = sizeof(rasEntryName);
numEntries = 0;
// call the function to see how many dialup entries there are
retVal = fpRasEnumEntries(NULL, NULL, rasEntryName, &bufferSize, &numEntries);
// if our buffer is too small (i.e. there are more than one phone book entries)
// or we get a single item, then we have dialup, so set autodial to TRUE so
// we'll tread lightly
if (retVal == ERROR_BUFFER_TOO_SMALL || (numEntries == 1 && retVal == ERROR_SUCCESS))
fAutoDial = TRUE;
}
}
}
}
}
}
// close the key when we're done with it
::RegCloseKey(hKey);
}
WRITE_LOG1("Checked AUTODIAL flag = %d.", fAutoDial);
// XXXKM - only check netcard active status if autodial is not on; if it's on, then
// assume we are doing stuff through RAS connection only and ignore netcard for now;
// only temporary
if (!fAutoDial && FNetCardActive())
{
WRITE_LOG0("FNetCardActive fc returned TRUE. goto exit ...");
fRet = TRUE;
goto Ret;
}
if (!fAutoDial) // if it's not set, go ahead and try the network
{
if (fPing)
fRet = SmartPing();
else
fRet = TRUE;
goto Ret;
}
else // See if we have an active RAS connection
{
WRITE_LOG0("Any active RAS connection?");
DWORD cRasConns = 0;
RASCONN rgRasConn[5];
DWORD cb = sizeof(rgRasConn);
if (!m_hRasApiModule)
m_hRasApiModule= LoadLibrary(OS_STRING("rasapi32.dll"));
// add this code if this ever gets into win16; win16 will return nonnull on error from load library #if _WIN16 if (m_handle < HINSTANCE_ERROR) m_handle = NULL; #endif
if (!m_hRasApiModule) // Dialup networking is not installed.
{
WRITE_LOG0("Dialup networking not installed ...");
if (fPing)
fRet = SmartPing();
else
fRet = TRUE;
goto Ret;
}
if (!m_pRasEnumConnections)
m_pRasEnumConnections =
(FPRASENUMCONNECTIONS)GetProcAddress(m_hRasApiModule,OS_STRING("RasEnumConnectionsA"));
if (!m_pRasEnumConnections) // Dialup networking is not installed.
{
WRITE_LOG0("Cannot load RasEnumConnections fc...");
if (fPing)
fRet = SmartPing();
else
fRet = TRUE;
goto Ret;
}
rgRasConn[0].dwSize = sizeof(RASCONN);
m_pRasEnumConnections(rgRasConn, &cb, &cRasConns);
WRITE_LOG1("RasEnumConnections found %d connections...", cRasConns);
if (cRasConns)
{
if (fPing)
fRet = SmartPing();
else
fRet = TRUE;
goto Ret;
}
else
{
fRet = FALSE;
goto Ret;
}
}
Ret:
// free up the library if loaded
if (m_hRasApiModule)
{
::FreeLibrary(m_hRasApiModule);
m_hRasApiModule = NULL;
}
#if !defined(WIN32_PLATFORM_PSPC)
// reset the error mode to the old value
::SetErrorMode(oldErrorMode);
#endif /* !defined(WIN32_PLATFORM_PSPC) */
WRITE_LOG1("FInternetAvailable terminated with %s value...",
fRet ? "TRUE" : "FALSE");
return(fRet);
#else
// Win16 section
// =-=w16.0 for win16 always returns true, since there is no popup dialog in the way
return (TRUE);
#endif
}
//******************************************************************************
//
// Method: CHXNetCheck::Ping
//
// Purpose: Tests to see if we can open a TCP connection to the given hostname.
// if fAynchronous is true, we call back a response object provided by
// the caller (through Init). Otherwise we block.
//
//
// Notes: n/a
//
//******************************************************************************
BOOL CHXNetCheck::Ping(const char *szHostName, UINT16 nPort, BOOL fAsynchronous)
{
ULONG32 ulStartTime, ulCurrentTime, ulElapsedTime;
BOOL fRet = FALSE;
// If we don't have the network services interface yet than try and get it here
if (m_pContext && !m_pRmaNetServices)
m_pContext->QueryInterface(IID_IHXNetworkServices, (void**)&m_pRmaNetServices);
if (!m_pRmaTCPSocket && m_pRmaNetServices)
m_pRmaNetServices->CreateTCPSocket(&m_pRmaTCPSocket);
if (!m_pRmaTCPSocket)
return FALSE;
m_fFailed = m_fConnected = FALSE;
m_pRmaTCPSocket->Init(this);
m_pRmaTCPSocket->Connect(szHostName, nPort);
ulElapsedTime = 0;
// Get start time
ulStartTime = HX_GET_TICKCOUNT();
while (!m_fFailed && !m_fConnected && (ulElapsedTime < m_Timeout))
{
SleepWell(1000);
ulCurrentTime = HX_GET_TICKCOUNT();
ulElapsedTime = CALCULATE_ELAPSED_TICKS(ulStartTime, ulCurrentTime);
}
fRet = m_fConnected;
m_pRmaTCPSocket->Release();
m_pRmaTCPSocket = NULL;
return (fRet);
}
//******************************************************************************
//
// Method: CHXNetCheck::SleepWell
//
// Purpose: This method sleeps but continues to pump messages. This allows us to
// block properly, even under such platforms as Win16.
//
//
// Notes: n/a
//
//******************************************************************************
void CHXNetCheck::SleepWell(ULONG32 ulInterval)
{
ULONG32 ulStartTime, ulCurrentTime;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -