2928 lines
76 KiB
C++
2928 lines
76 KiB
C++
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 2000 Microsoft Corporation
|
|
//
|
|
// Module: ConnMgr.cpp
|
|
//
|
|
// Author: Dan Elliott
|
|
//
|
|
// Abstract:
|
|
//
|
|
// Environment:
|
|
// Neptune
|
|
//
|
|
// Revision History:
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Include files
|
|
//
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <netcon.h>
|
|
#include <wininet.h>
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#include <devguid.h>
|
|
#include <mswsock.h>
|
|
#include <util.h>
|
|
#include <commerr.h>
|
|
#include "connmgr.h"
|
|
#include "msobcomm.h"
|
|
|
|
#define STRSAFE_NO_DEPRECATE
|
|
#include <strsafe.h>
|
|
|
|
const static int MAX_NUM_NET_COMPONENTS = 128;
|
|
const static int MAX_GUID_LEN = 40;
|
|
|
|
const DWORD CConnectionManager::RAS_AUTODIAL_ENABLED = 0;
|
|
const DWORD CConnectionManager::RAS_AUTODIAL_DISABLED = 1;
|
|
const DWORD CConnectionManager::RAS_AUTODIAL_DONT_KNOW = 2;
|
|
|
|
////////////////////////////////
|
|
// Wininet/URL Helpers
|
|
////////////////////////////////
|
|
|
|
STDAPI InternetOpenWrap(
|
|
LPCTSTR pszAgent,
|
|
DWORD dwAccessType,
|
|
LPCTSTR pszProxy,
|
|
LPCTSTR pszProxyBypass,
|
|
DWORD dwFlags,
|
|
HINTERNET * phFileHandle
|
|
);
|
|
|
|
STDAPI InternetOpenUrlWrap(
|
|
HINTERNET hInternet,
|
|
LPCTSTR pszUrl,
|
|
LPCTSTR pszHeaders,
|
|
DWORD dwHeadersLength,
|
|
DWORD dwFlags,
|
|
DWORD_PTR dwContext,
|
|
HINTERNET * phFileHandle
|
|
);
|
|
|
|
STDAPI HttpQueryInfoWrap(
|
|
HINTERNET hRequest,
|
|
DWORD dwInfoLevel,
|
|
LPVOID lpvBuffer,
|
|
LPDWORD lpdwBufferLength,
|
|
LPDWORD lpdwIndex
|
|
);
|
|
|
|
BOOL
|
|
IsGlobalOffline(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
SetOffline(
|
|
IN BOOL fOffline
|
|
);
|
|
|
|
STDAPI PingWebServer(
|
|
HINTERNET hInternet,
|
|
LPCTSTR pszUrl,
|
|
BOOL* pfConnected
|
|
);
|
|
|
|
static NLA_BLOB* _NLABlobNext(
|
|
IN NLA_BLOB* pnlaBlob
|
|
);
|
|
|
|
static int _AllocWSALookupServiceNext(
|
|
IN HANDLE hQuery,
|
|
IN DWORD dwControlFlags,
|
|
OUT LPWSAQUERYSET* ppResults
|
|
);
|
|
|
|
static int StringCmpGUID(
|
|
IN LPCWSTR szGuid,
|
|
IN const GUID* pguid
|
|
);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CConnectionManager
|
|
//
|
|
// Default constructor
|
|
//
|
|
// parameters:
|
|
// None.
|
|
//
|
|
// returns:
|
|
// Nothing.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
CConnectionManager::CConnectionManager()
|
|
: m_dwConnectionCapabilities(CONNECTIONTYPE_INVALID),
|
|
m_dwPreferredConnection(CONNECTIONTYPE_INVALID),
|
|
m_pPreferredConnection(NULL),
|
|
m_cLanConnections(0),
|
|
m_cPhoneConnections(0),
|
|
m_hInternetPing(NULL),
|
|
m_bProxySaved(FALSE),
|
|
m_bProxyApplied(FALSE),
|
|
m_bUseProxy(FALSE),
|
|
m_dwRasAutodialDisable(RAS_AUTODIAL_DONT_KNOW),
|
|
m_bForceOnline(FALSE),
|
|
m_bExclude1394(FALSE)
|
|
{
|
|
ZeroMemory(&m_CurrentProxySettings, sizeof(m_CurrentProxySettings));
|
|
} // CConnectionManager::CConnectionManager
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ~CConnectionManager
|
|
//
|
|
// Destructor.
|
|
//
|
|
// parameters:
|
|
// None.
|
|
//
|
|
// returns:
|
|
// Nothing.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
CConnectionManager::~CConnectionManager()
|
|
{
|
|
if (m_hInternetPing)
|
|
{
|
|
InternetCloseHandle(m_hInternetPing);
|
|
}
|
|
|
|
if (m_bProxySaved)
|
|
{
|
|
RestoreProxySettings();
|
|
FreeProxyOptionList(&m_CurrentProxySettings);
|
|
}
|
|
|
|
if (m_bForceOnline)
|
|
{
|
|
SetOffline(TRUE);
|
|
TRACE(L"Set wininet back to offline");
|
|
}
|
|
|
|
if (m_pPreferredConnection)
|
|
{
|
|
m_pPreferredConnection->Release();
|
|
}
|
|
} // CConnectionManager::~CConnectionManager
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetCapabilities
|
|
//
|
|
// Queries the system for network connection capabilities. In addition, the
|
|
// number of phone and LAN connections are counted and a preferred connection
|
|
// type is determined.
|
|
//
|
|
// parameters:
|
|
// None.
|
|
//
|
|
// returns:
|
|
// A bitmask indicating the capabilities that are present.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CConnectionManager::GetCapabilities(
|
|
DWORD* pdwCapabilities
|
|
)
|
|
{
|
|
TRACE(L"CConnectionManager::GetCapabilities\n");
|
|
HRESULT hr = S_OK;
|
|
|
|
if (NULL == pdwCapabilities)
|
|
{
|
|
MYASSERT(NULL != pdwCapabilities);
|
|
return E_POINTER;
|
|
}
|
|
|
|
#ifndef CONNMGR_INITFROMREGISTRY
|
|
// The #else part of this directive contains test code that retrieves
|
|
// connection capabilities and preference settings from the registry
|
|
//
|
|
|
|
DWORD m_cLanConnections = 0;
|
|
DWORD m_cPhoneConnections = 0;
|
|
|
|
// Initialize the net connection enumeration. For each interface
|
|
// retrieved, SetProxyBlanket must be called to set the authentication for
|
|
// the interface proxy handle because the Network Connection Manager lives
|
|
// in a remote process with a different security context.
|
|
//
|
|
INetConnectionManager* pmgr = NULL;
|
|
|
|
if ( SUCCEEDED(hr = CoCreateInstance(
|
|
CLSID_ConnectionManager,
|
|
NULL,
|
|
CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
|
|
IID_PPV_ARG(INetConnectionManager, &pmgr)
|
|
)
|
|
)
|
|
&& SUCCEEDED(hr = SetProxyBlanket(pmgr))
|
|
)
|
|
{
|
|
TRACE(L"INetConnectionManager\n");
|
|
IEnumNetConnection* penum = NULL;
|
|
if ( SUCCEEDED(hr = pmgr->EnumConnections(NCME_DEFAULT, &penum))
|
|
&& SUCCEEDED(hr = SetProxyBlanket(penum))
|
|
)
|
|
{
|
|
TRACE(L"IEnumNetConnection\n");
|
|
|
|
hr = penum->Reset();
|
|
while (S_OK == hr)
|
|
{
|
|
INetConnection* pnc = NULL;
|
|
ULONG ulRetrieved;
|
|
if ( S_OK == (hr = penum->Next(1, &pnc, &ulRetrieved))
|
|
&& SUCCEEDED(hr = SetProxyBlanket(pnc))
|
|
)
|
|
{
|
|
NETCON_PROPERTIES* pprops = NULL;
|
|
hr = pnc->GetProperties(&pprops);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Log the network connectivity detected
|
|
TRACE4(L"INetConnection: %s--%s--%d--%d\n",
|
|
pprops->pszwName,
|
|
pprops->pszwDeviceName,
|
|
pprops->MediaType,
|
|
pprops->Status);
|
|
|
|
if (IsEnabledConnection(pprops))
|
|
{
|
|
switch(pprops->MediaType)
|
|
{
|
|
case NCM_LAN:
|
|
m_cLanConnections++;
|
|
if (! (HasConnection(
|
|
CONNECTIONTYPE_LAN_INDETERMINATE
|
|
)
|
|
)
|
|
)
|
|
{
|
|
if (HasBroadband())
|
|
{
|
|
AddConnectionCapability(
|
|
CONNECTIONTYPE_LAN_INDETERMINATE
|
|
);
|
|
ClearConnectionCapability(
|
|
CONNECTIONTYPE_LAN_BROADBAND
|
|
);
|
|
}
|
|
else
|
|
{
|
|
AddConnectionCapability(
|
|
CONNECTIONTYPE_LAN_BROADBAND
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
case NCM_SHAREDACCESSHOST_LAN:
|
|
case NCM_SHAREDACCESSHOST_RAS:
|
|
// Do not increment LAN connection count here.
|
|
// This media type is in addition to the NCM_LAN
|
|
// for the NIC.
|
|
//
|
|
AddConnectionCapability(CONNECTIONTYPE_LAN_ICS);
|
|
break;
|
|
case NCM_PHONE:
|
|
#ifdef BLACKCOMB
|
|
// For Whistler, determination of modem capability is done via
|
|
// CObCommunicationManager::CheckDialReady.
|
|
m_cPhoneConnections++;
|
|
AddConnectionCapability(CONNECTIONTYPE_MODEM);
|
|
#endif // BLACKCOMB
|
|
break;
|
|
case NCM_ISDN:
|
|
case NCM_PPPOE:
|
|
AddConnectionCapability(CONNECTIONTYPE_OTHER);
|
|
break;
|
|
} // switch
|
|
}
|
|
NcFreeNetconProperties(pprops);
|
|
}
|
|
}
|
|
|
|
if (NULL != pnc)
|
|
{
|
|
pnc->Release();
|
|
}
|
|
}
|
|
|
|
if (S_FALSE == hr)
|
|
{
|
|
// IEnumNetConnection::Next returned S_FALSE to indicate
|
|
// that no more elements were available.
|
|
hr = S_OK;
|
|
}
|
|
|
|
}
|
|
|
|
if (NULL != penum)
|
|
{
|
|
penum->Release();
|
|
}
|
|
}
|
|
|
|
if (NULL != pmgr)
|
|
{
|
|
pmgr->Release();
|
|
}
|
|
|
|
DeterminePreferredConnection();
|
|
|
|
#else
|
|
HKEY hKey = NULL;
|
|
DWORD dwSize;
|
|
|
|
if(ERROR_SUCCESS == (lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
OOBE_MAIN_REG_KEY,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey)
|
|
)
|
|
)
|
|
{
|
|
dwSize = sizeof(DWORD);
|
|
if (ERROR_SUCCESS != (lResult = RegQueryValueEx(hKey,
|
|
L"ConnectionCapabilities",
|
|
0,
|
|
NULL,
|
|
(LPBYTE)&m_dwConnectionCapabilities,
|
|
&dwSize)
|
|
)
|
|
)
|
|
{
|
|
m_dwConnectionCapabilities = CONNECTIONTYPE_INVALID;
|
|
}
|
|
if (ERROR_SUCCESS != (lResult = RegQueryValueEx(hKey,
|
|
L"PreferredConnection",
|
|
0,
|
|
NULL,
|
|
(LPBYTE)&m_dwPreferredConnection,
|
|
&dwSize
|
|
)
|
|
)
|
|
)
|
|
{
|
|
m_dwPreferredConnection = CONNECTIONTYPE_INVALID;
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
else
|
|
{
|
|
m_dwConnectionCapabilities = CONNECTIONTYPE_INVALID;
|
|
m_dwPreferredConnection = CONNECTIONTYPE_INVALID;
|
|
}
|
|
#endif // CONNMGR_INITFROMREGISTRY
|
|
TRACE(L"Exiting CConnectionManager::GetCapabilities\n");
|
|
*pdwCapabilities = m_dwConnectionCapabilities;
|
|
return hr;
|
|
|
|
} // CConnectionManager::GetCapabilities
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetPreferredConnection
|
|
//
|
|
// Set the preferred connection type. This allows an override of the
|
|
// internally determined preference.
|
|
//
|
|
// parameters:
|
|
// dwType one of the CONNECTIONTYPE_* values from obcomm.h.
|
|
//
|
|
// returns:
|
|
// Boolean indicating whether the preferred connection was set.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CConnectionManager::SetPreferredConnection(
|
|
const DWORD dwType,
|
|
BOOL* pfSupportedType
|
|
)
|
|
{
|
|
BOOL fSupportedType = FALSE;
|
|
|
|
switch (dwType)
|
|
{
|
|
case CONNECTIONTYPE_NONE:
|
|
fSupportedType = TRUE;
|
|
break;
|
|
case CONNECTIONTYPE_MODEM:
|
|
#ifdef BLACKCOMB
|
|
// Modem capability for Whistler is handled via
|
|
// CObCommunicationManager::CheckDialReady. However, CONNECTIONTYPE_MODEM is a
|
|
// valid enum value to pass to this function so we don't want to hit the
|
|
// default and assert. Hence, the case and break aren't ifdef'd.
|
|
if (HasModem())
|
|
{
|
|
fSupportedType = TRUE;
|
|
}
|
|
#endif // BLACKCOMB
|
|
break;
|
|
case CONNECTIONTYPE_LAN_ICS:
|
|
if (HasIcs())
|
|
{
|
|
fSupportedType = TRUE;
|
|
}
|
|
break;
|
|
case CONNECTIONTYPE_LAN_BROADBAND:
|
|
if (HasBroadband())
|
|
{
|
|
fSupportedType = TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
// Unsupported connection type or multiple connection types
|
|
MYASSERT(FALSE);
|
|
} // switch
|
|
|
|
if (fSupportedType)
|
|
{
|
|
TRACE1(L"SetPreferredConnection %d", dwType);
|
|
|
|
m_dwPreferredConnection = dwType;
|
|
GetPreferredConnection();
|
|
}
|
|
else
|
|
{
|
|
TRACE1(L"Unsupported Connection type %d", dwType);
|
|
}
|
|
|
|
if (NULL != pfSupportedType)
|
|
{
|
|
*pfSupportedType = fSupportedType;
|
|
}
|
|
|
|
return fSupportedType;
|
|
|
|
} // CConnectionManager::SetPreferredConnection
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ConnectedToInternet
|
|
//
|
|
// Determines whether the system is currently connected to the Internet.
|
|
//
|
|
// parameters:
|
|
// pfConnected pointer to a buffer that will receive the boolean
|
|
// indicating whether the connection exists.
|
|
//
|
|
// returns:
|
|
// TRUE if system is connected to the internet via LAN or
|
|
// dial-up or can be connected via dial-up
|
|
// FALSE otherwise
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CConnectionManager::ConnectedToInternet(
|
|
BOOL* pfConnected
|
|
)
|
|
{
|
|
DWORD dwFlags;
|
|
|
|
if (NULL == pfConnected)
|
|
{
|
|
MYASSERT(NULL != pfConnected);
|
|
return E_POINTER;
|
|
}
|
|
|
|
*pfConnected = InternetGetConnectedState(&dwFlags, 0);
|
|
|
|
// Log the network connectivity detected
|
|
TRACE2(L"InternetGetConnectedState %d, 0x%08lx", *pfConnected, dwFlags);
|
|
|
|
return S_OK;
|
|
} // CConnectionManager::ConnectedToInternet
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// SetPreferredConnectionTcpipProperties
|
|
//
|
|
STDMETHODIMP
|
|
CConnectionManager::SetPreferredConnectionTcpipProperties(
|
|
BOOL fAutoIpAddress,
|
|
DWORD StaticIp_A,
|
|
DWORD StaticIp_B,
|
|
DWORD StaticIp_C,
|
|
DWORD StaticIp_D,
|
|
DWORD SubnetMask_A,
|
|
DWORD SubnetMask_B,
|
|
DWORD SubnetMask_C,
|
|
DWORD SubnetMask_D,
|
|
DWORD DefGateway_A,
|
|
DWORD DefGateway_B,
|
|
DWORD DefGateway_C,
|
|
DWORD DefGateway_D,
|
|
BOOL fAutoDns,
|
|
DWORD DnsPref_A,
|
|
DWORD DnsPref_B,
|
|
DWORD DnsPref_C,
|
|
DWORD DnsPref_D,
|
|
DWORD DnsAlt_A,
|
|
DWORD DnsAlt_B,
|
|
DWORD DnsAlt_C,
|
|
DWORD DnsAlt_D
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
REMOTE_IPINFO ipInfo;
|
|
struct in_addr inaddr;
|
|
WCHAR rgchStaticIp[INET_ADDRSTRLEN];
|
|
WCHAR rgchSubnetMask[INET_ADDRSTRLEN];
|
|
WCHAR rgchDefGateway[2 * INET_ADDRSTRLEN] = L"DefGw=";
|
|
WCHAR rgchGatewayMetric[2 * INET_ADDRSTRLEN] = L"GwMetric=";
|
|
WCHAR rgchDnsAddr[3 * INET_ADDRSTRLEN] = L"DNS=";
|
|
WCHAR* pch = NULL;
|
|
NETCON_PROPERTIES* pncProps = NULL;
|
|
|
|
memset(&ipInfo, 0, sizeof(REMOTE_IPINFO));
|
|
|
|
hr = m_pPreferredConnection->GetProperties(&pncProps);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE1(L"Failed to retrieve preferred connection properties (0x%08X)\n", hr);
|
|
goto SetPreferredConnectionTcpipPropertiesExit;
|
|
}
|
|
|
|
ipInfo.dwEnableDhcp = fAutoIpAddress;
|
|
|
|
if (! fAutoIpAddress)
|
|
{
|
|
// if a static ip address was specified, convert it to a string and add
|
|
// it to the REMOTE_IPINFO structure
|
|
//
|
|
memset(&inaddr, 0, sizeof(struct in_addr));
|
|
inaddr.S_un.S_un_b.s_b1 = (BYTE)StaticIp_A;
|
|
inaddr.S_un.S_un_b.s_b2 = (BYTE)StaticIp_B;
|
|
inaddr.S_un.S_un_b.s_b3 = (BYTE)StaticIp_C;
|
|
inaddr.S_un.S_un_b.s_b4 = (BYTE)StaticIp_D;
|
|
if (! INetNToW(inaddr, rgchStaticIp))
|
|
{
|
|
hr = E_FAIL;
|
|
TRACE1(L"Failed to create ip address string (0x%08X)\n", hr);
|
|
goto SetPreferredConnectionTcpipPropertiesExit;
|
|
}
|
|
|
|
ipInfo.pszwIpAddrList = rgchStaticIp;
|
|
|
|
memset(&inaddr, 0, sizeof(struct in_addr));
|
|
inaddr.S_un.S_un_b.s_b1 = (BYTE)SubnetMask_A;
|
|
inaddr.S_un.S_un_b.s_b2 = (BYTE)SubnetMask_B;
|
|
inaddr.S_un.S_un_b.s_b3 = (BYTE)SubnetMask_C;
|
|
inaddr.S_un.S_un_b.s_b4 = (BYTE)SubnetMask_D;
|
|
|
|
if (! INetNToW(inaddr, rgchSubnetMask))
|
|
{
|
|
hr = E_FAIL;
|
|
TRACE1(L"Failed to create ip address string (0x%08X)\n", hr);
|
|
goto SetPreferredConnectionTcpipPropertiesExit;
|
|
}
|
|
|
|
ipInfo.pszwSubnetMaskList = rgchSubnetMask;
|
|
|
|
pch = rgchDefGateway + lstrlen(rgchDefGateway);
|
|
memset(&inaddr, 0, sizeof(struct in_addr));
|
|
inaddr.S_un.S_un_b.s_b1 = (BYTE)DefGateway_A;
|
|
inaddr.S_un.S_un_b.s_b2 = (BYTE)DefGateway_B;
|
|
inaddr.S_un.S_un_b.s_b3 = (BYTE)DefGateway_C;
|
|
inaddr.S_un.S_un_b.s_b4 = (BYTE)DefGateway_D;
|
|
|
|
if (! INetNToW(inaddr, pch))
|
|
{
|
|
hr = E_FAIL;
|
|
TRACE1(L"Failed to create ip address string (0x%08X)\n", hr);
|
|
goto SetPreferredConnectionTcpipPropertiesExit;
|
|
}
|
|
lstrcat(rgchGatewayMetric, L"1");
|
|
|
|
|
|
TRACE4(L"Tcpip StaticIp %d.%d.%d.%d",
|
|
StaticIp_A, StaticIp_B, StaticIp_C, StaticIp_D);
|
|
|
|
TRACE4(L"Tcpip SubnetMask %d.%d.%d.%d",
|
|
SubnetMask_A, SubnetMask_B, SubnetMask_C, SubnetMask_D);
|
|
|
|
TRACE4(L"Tcpip DefGateway %d.%d.%d.%d",
|
|
DefGateway_A, DefGateway_B, DefGateway_C, DefGateway_D);
|
|
|
|
//ipInfo.pszwIpAddrList = rgchDefGateway;
|
|
|
|
}
|
|
|
|
if (! fAutoDns)
|
|
{
|
|
// if dns addresses were specified, convert them to strings and add
|
|
// them to the REMOTE_IPINFO structure
|
|
//
|
|
|
|
pch = rgchDnsAddr + lstrlen(rgchDnsAddr);
|
|
|
|
memset(&inaddr, 0, sizeof(struct in_addr));
|
|
inaddr.S_un.S_un_b.s_b1 = (BYTE)DnsPref_A;
|
|
inaddr.S_un.S_un_b.s_b2 = (BYTE)DnsPref_B;
|
|
inaddr.S_un.S_un_b.s_b3 = (BYTE)DnsPref_C;
|
|
inaddr.S_un.S_un_b.s_b4 = (BYTE)DnsPref_D;
|
|
if (! INetNToW(inaddr, pch))
|
|
{
|
|
hr = E_FAIL;
|
|
TRACE1(L"Failed to create dns address string (0x%08X)\n", hr);
|
|
goto SetPreferredConnectionTcpipPropertiesExit;
|
|
}
|
|
pch += lstrlen(pch);
|
|
*pch++ = L',';
|
|
|
|
inaddr.S_un.S_un_b.s_b1 = (BYTE)DnsAlt_A;
|
|
inaddr.S_un.S_un_b.s_b2 = (BYTE)DnsAlt_B;
|
|
inaddr.S_un.S_un_b.s_b3 = (BYTE)DnsAlt_C;
|
|
inaddr.S_un.S_un_b.s_b4 = (BYTE)DnsAlt_D;
|
|
if (! INetNToW(inaddr, pch))
|
|
{
|
|
hr = E_FAIL;
|
|
TRACE1(L"Failed to create alternate dns address string (0x%08X)\n", hr);
|
|
goto SetPreferredConnectionTcpipPropertiesExit;
|
|
}
|
|
|
|
TRACE4(L"Tcpip DnsPref %d.%d.%d.%d",
|
|
DnsPref_A, DnsPref_B, DnsPref_C, DnsPref_D);
|
|
|
|
TRACE4(L"Tcpip DnsAlt %d.%d.%d.%d",
|
|
DnsAlt_A, DnsAlt_B, DnsAlt_C, DnsAlt_D);
|
|
|
|
}
|
|
|
|
// plus 4 for 3 semi-colons and the null-terminator
|
|
ipInfo.pszwOptionList = (WCHAR*) malloc((lstrlen(rgchDefGateway)
|
|
+ lstrlen(rgchGatewayMetric)
|
|
+ lstrlen(rgchDnsAddr)
|
|
+ 4)
|
|
* sizeof(WCHAR)
|
|
);
|
|
if (NULL == ipInfo.pszwOptionList)
|
|
{
|
|
TRACE(L"Failed to allocate memory for option list\n");
|
|
goto SetPreferredConnectionTcpipPropertiesExit;
|
|
}
|
|
|
|
wsprintf(ipInfo.pszwOptionList, L"%s;%s;%s;",
|
|
rgchDefGateway, rgchGatewayMetric, rgchDnsAddr
|
|
);
|
|
|
|
hr = SetTcpipProperties(pncProps->guidId, &ipInfo);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE1(L"Failed to set TCPIP info (0x%08X)\n", hr);
|
|
}
|
|
|
|
SetPreferredConnectionTcpipPropertiesExit:
|
|
|
|
if (NULL != ipInfo.pszwOptionList)
|
|
{
|
|
free(ipInfo.pszwOptionList);
|
|
ipInfo.pszwOptionList = NULL;
|
|
}
|
|
|
|
if (NULL != pncProps)
|
|
{
|
|
NcFreeNetconProperties(pncProps);
|
|
pncProps = NULL;
|
|
}
|
|
|
|
return hr;
|
|
|
|
} // CObCommunicationManager::SetPreferredConnectionTcpipProperties
|
|
|
|
|
|
///////////////////////////////////////////////////////////
|
|
//
|
|
// SetTcpipProperties
|
|
//
|
|
HRESULT
|
|
CConnectionManager::SetTcpipProperties(
|
|
GUID guid,
|
|
REMOTE_IPINFO* pipInfo
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
INetCfg* pNetCfg = NULL;
|
|
ITcpipProperties* pTcpipProps = NULL;
|
|
|
|
hr = GetNetCfgInterface(TRUE, &pNetCfg);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = GetTcpipPrivateInterface(pNetCfg, &pTcpipProps);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pTcpipProps->SetIpInfoForAdapter(&guid, pipInfo);
|
|
TRACE1(L"SetIpInfoForAdapter 0x%08lx", hr);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pNetCfg->Apply();
|
|
TRACE1(L"INetCfg::Apply 0x%08lx", hr);
|
|
}
|
|
pTcpipProps->Release();
|
|
}
|
|
ReleaseNetCfgInterface(pNetCfg, TRUE);
|
|
}
|
|
|
|
return hr;
|
|
|
|
} // CObCommunicationManager::SetTcpipProperties
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// LanConnectionReady
|
|
//
|
|
// Determines whether the system has a LAN connection that is connected to the
|
|
// Internet.
|
|
//
|
|
// parameters:
|
|
// None.
|
|
//
|
|
// returns:
|
|
// Boolean indicating whether or not their is a ready connection.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
CConnectionManager::LanConnectionReady()
|
|
{
|
|
BOOL fReady = FALSE;
|
|
|
|
#ifndef CONNMGR_INITFROMREGISTRY
|
|
if (HasBroadband() || HasIcs())
|
|
{
|
|
DWORD dwFlags = 0;
|
|
if ( InternetGetConnectedState(&dwFlags, 0)
|
|
&& (INTERNET_CONNECTION_LAN & dwFlags)
|
|
)
|
|
{
|
|
fReady = TRUE;
|
|
}
|
|
}
|
|
#else
|
|
DWORD dwLanConnectionReady;
|
|
DWORD dwSize = sizeof(DWORD);
|
|
if(ERROR_SUCCESS == (lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
OOBE_MAIN_REG_KEY,
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey)
|
|
)
|
|
)
|
|
{
|
|
lResult = RegQueryValueEx(hKey,
|
|
L"LanConnectionReady",
|
|
0,
|
|
NULL,
|
|
(LPBYTE)&dwLanConnectionReady,
|
|
&dwSize
|
|
);
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
fReady = (ERROR_SUCCESS == lResult) ? (BOOL)dwLanConnectionReady : FALSE;
|
|
#endif // CONNMGR_INITFROMREGISTRY
|
|
|
|
return fReady;
|
|
|
|
} // CConnectionManager::LanConnectionReady
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SetProxyBlanket
|
|
//
|
|
// Set the authentication settings for the binding handle for the
|
|
// interface proxy. This is necessary for setting up security for interface
|
|
// pointers returned by a remote process, such as the Network Connections
|
|
// Manager (netman.dll).
|
|
//
|
|
// parameters:
|
|
// pUnk pointer to the interface for which the proxy will be
|
|
// bound.
|
|
//
|
|
// returns:
|
|
// HRESULT returned by CoSetProxyBlanket.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CConnectionManager::SetProxyBlanket(
|
|
IUnknown* pUnk
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
hr = CoSetProxyBlanket (
|
|
pUnk,
|
|
RPC_C_AUTHN_WINNT, // use NT default security
|
|
RPC_C_AUTHZ_NONE, // use NT default authentication
|
|
NULL, // must be null if default
|
|
RPC_C_AUTHN_LEVEL_CALL, // call
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
NULL, // use process token
|
|
EOAC_NONE);
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
IUnknown * pUnkSet = NULL;
|
|
hr = pUnk->QueryInterface(IID_PPV_ARG(IUnknown, &pUnkSet));
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
hr = CoSetProxyBlanket (
|
|
pUnkSet,
|
|
RPC_C_AUTHN_WINNT, // use NT default security
|
|
RPC_C_AUTHZ_NONE, // use NT default authentication
|
|
NULL, // must be null if default
|
|
RPC_C_AUTHN_LEVEL_CALL, // call
|
|
RPC_C_IMP_LEVEL_IMPERSONATE,
|
|
NULL, // use process token
|
|
EOAC_NONE);
|
|
pUnkSet->Release();
|
|
}
|
|
}
|
|
return hr;
|
|
} // CConnectionManager::SetProxyBlanket
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DeterminePreferredConnection
|
|
//
|
|
// Determine the preferred connection. The order of preference is
|
|
// * ICS
|
|
// * Broadband (DSL, cable modem, etc.)
|
|
// * Modem
|
|
//
|
|
// parameters:
|
|
// None.
|
|
//
|
|
// returns:
|
|
// Nothing.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
CConnectionManager::DeterminePreferredConnection()
|
|
{
|
|
// REVIEW: Differences between full-screen and desktop in using default
|
|
// connectoid.
|
|
//
|
|
if (HasIcs())
|
|
{
|
|
m_dwPreferredConnection = CONNECTIONTYPE_LAN_ICS;
|
|
}
|
|
else if (HasBroadband())
|
|
{
|
|
m_dwPreferredConnection = CONNECTIONTYPE_LAN_BROADBAND;
|
|
}
|
|
#ifdef BLACKCOMB
|
|
// Modem capability for Whistler is handled via
|
|
// CObCommunicationManager::CheckDialReady
|
|
else if (HasModem())
|
|
{
|
|
m_dwPreferredConnection = CONNECTIONTYPE_MODEM;
|
|
}
|
|
#endif // BLACKCOMB
|
|
else // CONNECTIONTYPE_NONE || CONNECTIONTYPE_LAN_INDETERMINATE
|
|
{
|
|
m_dwPreferredConnection = CONNECTIONTYPE_NONE;
|
|
}
|
|
|
|
GetPreferredConnection();
|
|
|
|
} // CConnectionManager::DeterminePreferredConnection
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetPreferredConnection
|
|
//
|
|
// Determine the name of the connectoid for the preferred connection.
|
|
//
|
|
// parameters:
|
|
// None.
|
|
//
|
|
// returns:
|
|
// Nothing.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
CConnectionManager::GetPreferredConnection()
|
|
{
|
|
HRESULT hr;
|
|
NETCON_MEDIATYPE ncMediaType = NCM_NONE; // assume no connection
|
|
|
|
switch (m_dwPreferredConnection)
|
|
{
|
|
case CONNECTIONTYPE_LAN_ICS:
|
|
ncMediaType = NCM_SHAREDACCESSHOST_LAN;
|
|
break;
|
|
case CONNECTIONTYPE_LAN_BROADBAND:
|
|
ncMediaType = NCM_LAN;
|
|
break;
|
|
} // switch(m_dwPreferredConnection)
|
|
|
|
// Free up previous preferred connection properties
|
|
//
|
|
if (NULL != m_pPreferredConnection)
|
|
{
|
|
m_pPreferredConnection->Release();
|
|
m_pPreferredConnection = NULL;
|
|
}
|
|
|
|
if (NCM_NONE != ncMediaType)
|
|
{
|
|
|
|
INetConnectionManager* pmgr = NULL;
|
|
|
|
if ( SUCCEEDED(hr = CoCreateInstance(
|
|
CLSID_ConnectionManager,
|
|
NULL,
|
|
CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
|
|
IID_PPV_ARG(INetConnectionManager, &pmgr)
|
|
)
|
|
)
|
|
&& SUCCEEDED(hr = SetProxyBlanket(pmgr))
|
|
)
|
|
{
|
|
TRACE(L"INetConnectionManager\n");
|
|
IEnumNetConnection* penum = NULL;
|
|
if ( SUCCEEDED(hr = pmgr->EnumConnections(NCME_DEFAULT, &penum))
|
|
&& SUCCEEDED(hr = SetProxyBlanket(penum))
|
|
)
|
|
{
|
|
TRACE(L"IEnumNetConnection\n");
|
|
|
|
MYASSERT(NULL == m_pPreferredConnection);
|
|
hr = penum->Reset();
|
|
|
|
// Find the first connection matching the preferred type. This
|
|
// works because the only types we are concerned with are
|
|
// broadband and ICS. By definition, we should not be here if
|
|
// there are more than 1 of these connections. If there are
|
|
// more than 1 of these we should be deferring to the HomeNet
|
|
// Wizard.
|
|
//
|
|
// ONCE THIS OBJECT SUPPORTS MODEM CONNECTIONS OR MULTIPLE
|
|
// BROADBAND CONNECTIONS we'll need a more sophisticated method
|
|
// of determining that we've found the correct connection.
|
|
//
|
|
while (S_OK == hr && NULL == m_pPreferredConnection)
|
|
{
|
|
INetConnection* pnc = NULL;
|
|
ULONG ulRetrieved;
|
|
if ( S_OK == (hr = penum->Next(1, &pnc, &ulRetrieved))
|
|
&& SUCCEEDED(hr = SetProxyBlanket(pnc))
|
|
)
|
|
{
|
|
NETCON_PROPERTIES* pprops = NULL;
|
|
hr = pnc->GetProperties(&pprops);
|
|
|
|
// Log the network connectivity detected
|
|
TRACE4(L"INetConnection: %s--%s--%d--%d\n",
|
|
pprops->pszwName,
|
|
pprops->pszwDeviceName,
|
|
pprops->MediaType,
|
|
pprops->Status);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (IsEnabledConnection(pprops))
|
|
{
|
|
if (ncMediaType == pprops->MediaType)
|
|
{
|
|
m_pPreferredConnection = pnc;
|
|
pnc = NULL;
|
|
}
|
|
}
|
|
NcFreeNetconProperties(pprops);
|
|
}
|
|
}
|
|
|
|
if (NULL != pnc)
|
|
{
|
|
pnc->Release();
|
|
}
|
|
}
|
|
|
|
if (S_FALSE == hr)
|
|
{
|
|
// IEnumNetConnection::Next returned S_FALSE to indicate
|
|
// that no more elements were available.
|
|
hr = S_OK;
|
|
}
|
|
|
|
}
|
|
|
|
if (NULL != penum)
|
|
{
|
|
penum->Release();
|
|
}
|
|
}
|
|
|
|
if (NULL != pmgr)
|
|
{
|
|
pmgr->Release();
|
|
}
|
|
}
|
|
} // CConnectionManager::GetPreferredConnection
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetPreferredConnectionName
|
|
//
|
|
// Fills in a user-allocated buffer with the name of the connectoid for the
|
|
// preferred connection.
|
|
//
|
|
// parameters:
|
|
// szConnectionName buffer that will recieve the name of the preferred
|
|
// connectoid
|
|
// cchConnectionName count of characters that the buffer can hold
|
|
//
|
|
// returns:
|
|
// S_OK if the name is retrieved successfully
|
|
// S_FALSE if there is no default connectoid
|
|
// E_INVALIDARG if there is no buffer or if the buffer size is 0
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CConnectionManager::GetPreferredConnectionName(
|
|
LPWSTR szConnectionName,
|
|
DWORD cchConnectionName
|
|
)
|
|
{
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
if (NULL == szConnectionName || 0 == cchConnectionName)
|
|
{
|
|
MYASSERT(NULL != szConnectionName);
|
|
MYASSERT(0 < cchConnectionName);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (NULL != m_pPreferredConnection)
|
|
{
|
|
NETCON_PROPERTIES* pprops = NULL;
|
|
hr = m_pPreferredConnection->GetProperties(&pprops);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
MYASSERT(NULL != pprops);
|
|
if (NULL == pprops->pszwName)
|
|
{
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
lstrcpyn(szConnectionName,
|
|
pprops->pszwName,
|
|
cchConnectionName
|
|
);
|
|
}
|
|
NcFreeNetconProperties(pprops);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
|
|
} // CConnectionManager::GetPreferredConnectionName
|
|
|
|
HRESULT
|
|
CConnectionManager::GetNetCfgInterface(
|
|
BOOL fNeedWriteLock,
|
|
INetCfg** ppNetCfg
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
INetCfg* pNetCfg = NULL;
|
|
|
|
if (NULL == ppNetCfg)
|
|
{
|
|
ASSERT(NULL != ppNetCfg);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*ppNetCfg = NULL;
|
|
|
|
hr = CoCreateInstance(CLSID_CNetCfg,
|
|
NULL,
|
|
CLSCTX_SERVER,
|
|
IID_INetCfg,
|
|
(LPVOID*)&pNetCfg
|
|
);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
INetCfgLock* pNetCfgLock = NULL;
|
|
if (fNeedWriteLock)
|
|
{
|
|
hr = pNetCfg->QueryInterface(IID_INetCfgLock, (VOID**)&pNetCfgLock);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pNetCfgLock->AcquireWriteLock(
|
|
5, // millisec timeout
|
|
L"Out-of-Box Experience",
|
|
NULL // name of previous holder
|
|
);
|
|
if (S_FALSE == hr)
|
|
{
|
|
hr = NETCFG_E_NO_WRITE_LOCK;
|
|
TRACE(L"AcquireWriteLock failed");
|
|
}
|
|
pNetCfgLock->Release();
|
|
}
|
|
else
|
|
{
|
|
TRACE1(L"QueryInterface IID_INetCfgLock 0x%08lx", hr);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pNetCfg->Initialize(NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*ppNetCfg = pNetCfg;
|
|
}
|
|
else
|
|
{
|
|
TRACE1(L"INetCfg Initialize 0x%08lx", hr);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRACE1(L"CoCreateInstance CLSID_CNetCfg IID_INetCfg 0x%08lx", hr);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
if (pNetCfg != NULL)
|
|
{
|
|
pNetCfg->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
|
|
} // CConnectionManager::GetNetCfgInterface
|
|
|
|
void
|
|
CConnectionManager::ReleaseNetCfgInterface(
|
|
INetCfg* pNetCfg,
|
|
BOOL fHasWriteLock
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (NULL != pNetCfg)
|
|
{
|
|
hr = pNetCfg->Uninitialize();
|
|
|
|
INetCfgLock* pNetCfgLock = NULL;
|
|
if (fHasWriteLock)
|
|
{
|
|
hr = pNetCfg->QueryInterface(IID_INetCfgLock, (VOID**)&pNetCfgLock);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pNetCfgLock->ReleaseWriteLock();
|
|
pNetCfgLock->Release();
|
|
}
|
|
}
|
|
pNetCfg->Release();
|
|
}
|
|
|
|
|
|
} // CConnectionManager::ReleaseNetCfgInterface
|
|
|
|
HRESULT
|
|
CConnectionManager::GetTcpipPrivateInterface(
|
|
INetCfg* pNetCfg,
|
|
ITcpipProperties** ppTcpipProperties
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL == ppTcpipProperties)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
INetCfgClass* pncclass = NULL;
|
|
|
|
hr = pNetCfg->QueryNetCfgClass(&GUID_DEVCLASS_NETTRANS,
|
|
IID_INetCfgClass,
|
|
(void**)&pncclass
|
|
);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
INetCfgComponent* pnccItem = NULL;
|
|
|
|
hr = pncclass->FindComponent(NETCFG_TRANS_CID_MS_TCPIP, &pnccItem);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
INetCfgComponentPrivate* pinccp = NULL;
|
|
hr = pnccItem->QueryInterface(IID_INetCfgComponentPrivate,
|
|
(void**) &pinccp
|
|
);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pinccp->QueryNotifyObject(IID_ITcpipProperties,
|
|
(void**) ppTcpipProperties
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
TRACE1(L"QueryNotifyObject IID_ITcpipProperties 0x%08lx", hr);
|
|
}
|
|
pinccp->Release();
|
|
pinccp = NULL;
|
|
}
|
|
else
|
|
{
|
|
TRACE1(L"QueryInterface IID_INetCfgComponentPrivate 0x%08lx", hr);
|
|
}
|
|
|
|
pnccItem->Release();
|
|
pnccItem = NULL;
|
|
}
|
|
else
|
|
{
|
|
TRACE1(L"FindComponent NETCFG_TRANS_CID_MS_TCPIP 0x%08lx", hr);
|
|
}
|
|
|
|
pncclass->Release();
|
|
pncclass = NULL;
|
|
}
|
|
else
|
|
{
|
|
TRACE1(L"QueryNetCfgClass IID_INetCfgClass 0x%08lx", hr);
|
|
}
|
|
|
|
return hr;
|
|
} // CConnectionManager::GetTcpipPrivateInterface
|
|
|
|
STDAPI InternetOpenWrap(
|
|
LPCTSTR pszAgent,
|
|
DWORD dwAccessType,
|
|
LPCTSTR pszProxy,
|
|
LPCTSTR pszProxyBypass,
|
|
DWORD dwFlags,
|
|
HINTERNET * phFileHandle
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwError = 0;
|
|
|
|
*phFileHandle = InternetOpen(pszAgent, dwAccessType, pszProxy, pszProxyBypass, dwFlags);
|
|
if (!*phFileHandle)
|
|
{
|
|
dwError = GetLastError();
|
|
TRACE1(L"InternetOpen failed (WININET Error %d)", dwError);
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
STDAPI InternetOpenUrlWrap(
|
|
HINTERNET hInternet,
|
|
LPCTSTR pszUrl,
|
|
LPCTSTR pszHeaders,
|
|
DWORD dwHeadersLength,
|
|
DWORD dwFlags,
|
|
DWORD_PTR dwContext,
|
|
HINTERNET * phFileHandle
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD dwError = 0;
|
|
|
|
*phFileHandle = InternetOpenUrl(hInternet, pszUrl, pszHeaders, dwHeadersLength, dwFlags, dwContext);
|
|
if (!*phFileHandle)
|
|
{
|
|
dwError = GetLastError();
|
|
TRACE1(L"InternetOpenUrl failed (WININET Error %d)", dwError);
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDAPI HttpQueryInfoWrap(
|
|
HINTERNET hRequest,
|
|
DWORD dwInfoLevel,
|
|
LPVOID lpvBuffer,
|
|
LPDWORD lpdwBufferLength,
|
|
LPDWORD lpdwIndex
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!HttpQueryInfo(hRequest, dwInfoLevel, lpvBuffer, lpdwBufferLength, lpdwIndex))
|
|
{
|
|
DWORD dwError;
|
|
|
|
dwError = GetLastError();
|
|
TRACE1(L"HttpQueryInfo failed (WININET Error %d)", dwError);
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL
|
|
IsGlobalOffline(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines whether wininet is in global offline mode
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
TRUE - offline
|
|
FALSE - online
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwState = 0;
|
|
DWORD dwSize = sizeof(DWORD);
|
|
BOOL fRet = FALSE;
|
|
|
|
if(InternetQueryOption(
|
|
NULL,
|
|
INTERNET_OPTION_CONNECTED_STATE,
|
|
&dwState,
|
|
&dwSize
|
|
))
|
|
{
|
|
if (dwState & INTERNET_STATE_DISCONNECTED_BY_USER)
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SetOffline(
|
|
IN BOOL fOffline
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets wininet's offline mode
|
|
|
|
Arguments:
|
|
|
|
fOffline - online or offline
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
INTERNET_CONNECTED_INFO ci;
|
|
|
|
memset(&ci, 0, sizeof(ci));
|
|
|
|
if (fOffline)
|
|
{
|
|
ci.dwConnectedState = INTERNET_STATE_DISCONNECTED_BY_USER;
|
|
ci.dwFlags = ISO_FORCE_DISCONNECTED;
|
|
} else
|
|
{
|
|
ci.dwConnectedState = INTERNET_STATE_CONNECTED;
|
|
}
|
|
|
|
InternetSetOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci));
|
|
}
|
|
|
|
STDAPI PingWebServer(
|
|
HINTERNET hInternet,
|
|
LPCTSTR pszUrl,
|
|
BOOL* pfConnected
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
HINTERNET hOpenUrlSession;
|
|
|
|
*pfConnected = FALSE;
|
|
|
|
hr = InternetOpenUrlWrap(
|
|
hInternet,
|
|
pszUrl,
|
|
NULL,
|
|
0,
|
|
INTERNET_FLAG_NO_UI |
|
|
INTERNET_FLAG_PRAGMA_NOCACHE |
|
|
INTERNET_FLAG_NO_CACHE_WRITE |
|
|
INTERNET_FLAG_RELOAD,
|
|
NULL,
|
|
&hOpenUrlSession);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD dwSize = sizeof(DWORD);
|
|
DWORD dwStatusCode;
|
|
|
|
hr = HttpQueryInfoWrap(
|
|
hOpenUrlSession,
|
|
HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_STATUS_CODE,
|
|
(LPVOID) &dwStatusCode,
|
|
&dwSize,
|
|
NULL);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// HTTP status code greater than or equal to 500 means server
|
|
// or network problem occur
|
|
*pfConnected = (dwStatusCode < 500);
|
|
|
|
TRACE1(L"HTTP status code from WPA HTTP server %d", dwStatusCode);
|
|
}
|
|
|
|
InternetCloseHandle(hOpenUrlSession);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
BOOL
|
|
CConnectionManager::GetInternetHandleForPinging(
|
|
HINTERNET* phInternet
|
|
)
|
|
{
|
|
static const WCHAR OOBE_HTTP_AGENT_NAME[] =
|
|
L"Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 5.1)";
|
|
static const int TIMEOUT_IN_MILLISEC = 30000;
|
|
|
|
if (m_hInternetPing == NULL)
|
|
{
|
|
HINTERNET hInternet;
|
|
|
|
if (SUCCEEDED(InternetOpenWrap(
|
|
OOBE_HTTP_AGENT_NAME,
|
|
PRE_CONFIG_INTERNET_ACCESS,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
&hInternet
|
|
)))
|
|
{
|
|
DWORD dwValue;
|
|
|
|
dwValue = TIMEOUT_IN_MILLISEC;
|
|
InternetSetOption(
|
|
hInternet,
|
|
INTERNET_OPTION_CONNECT_TIMEOUT,
|
|
&dwValue,
|
|
sizeof(DWORD));
|
|
|
|
m_hInternetPing = hInternet;
|
|
}
|
|
|
|
}
|
|
|
|
*phInternet = m_hInternetPing;
|
|
|
|
return (m_hInternetPing != NULL);
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ConnectedToInternetEx
|
|
//
|
|
// Determines whether the system is currently connected to the Internet.
|
|
//
|
|
// parameters:
|
|
// pfConnected pointer to a buffer that will receive the boolean
|
|
// indicating whether the connection exists.
|
|
//
|
|
// returns:
|
|
// TRUE if the system is connected to the internet. Note it may
|
|
// trigger autodial if it is enabled and no connection is
|
|
// available when this is called
|
|
// FALSE otherwise
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CConnectionManager::ConnectedToInternetEx(
|
|
BOOL* pfConnected
|
|
)
|
|
{
|
|
const WCHAR MS_URL[] = L"http://WPA.one.microsoft.com";
|
|
|
|
HINTERNET hInternet;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
*pfConnected = FALSE;
|
|
|
|
TRACE(L"tries to connect to the WPA HTTP server");
|
|
|
|
if (IsGlobalOffline())
|
|
{
|
|
SetOffline(FALSE);
|
|
m_bForceOnline = TRUE;
|
|
TRACE(L"Force wininet to go online");
|
|
}
|
|
|
|
DisableRasAutodial();
|
|
|
|
//
|
|
// Try to use the proxy settings from winnt32.exe first because it is
|
|
// quite likely a proper configuration. If the settings
|
|
// is not available or if we failed to connect to the web server
|
|
// using these settings, use the original settings and check the web
|
|
// server connectivity once more.
|
|
//
|
|
|
|
if (GetInternetHandleForPinging(&hInternet))
|
|
{
|
|
DWORD dwDisable = 0;
|
|
DWORD dwSize = sizeof(DWORD);
|
|
DWORD dwOrigDisable;
|
|
|
|
if (!InternetQueryOption(
|
|
hInternet,
|
|
INTERNET_OPTION_DISABLE_AUTODIAL,
|
|
(LPVOID) &dwOrigDisable,
|
|
&dwSize))
|
|
{
|
|
// Assume the orginal state is autodial-enabled.
|
|
dwOrigDisable = 0;
|
|
}
|
|
|
|
// InternetSetOption for INTERNET_OPTION_DISABLE_AUTODIAL affects the
|
|
// behavior of an application, e.g. it cause InternetAutodial
|
|
// elsewhere to fail. It does not affect other applications, however.
|
|
dwDisable = 1;
|
|
InternetSetOption(
|
|
hInternet,
|
|
INTERNET_OPTION_DISABLE_AUTODIAL,
|
|
&dwDisable,
|
|
sizeof(DWORD));
|
|
|
|
if (m_bUseProxy)
|
|
{
|
|
//
|
|
// If we have already applied or we can successfully apply the
|
|
// proxy settings
|
|
//
|
|
if (ApplyWinntProxySettings())
|
|
{
|
|
// User or we may have update the proxy and other settings in
|
|
// registry
|
|
InternetSetOption(
|
|
hInternet,
|
|
INTERNET_OPTION_REFRESH,
|
|
NULL,
|
|
0);
|
|
|
|
hr = PingWebServer(hInternet, MS_URL, pfConnected);
|
|
}
|
|
}
|
|
|
|
if (*pfConnected == FALSE)
|
|
{
|
|
//
|
|
// Restore proxy setting if it is already applied
|
|
//
|
|
if (m_bUseProxy)
|
|
{
|
|
// Don't revert the change by SetProxySettings call.
|
|
RestoreProxySettings();
|
|
}
|
|
|
|
// User or we may have update the proxy and other settings in
|
|
// registry
|
|
InternetSetOption(
|
|
hInternet,
|
|
INTERNET_OPTION_REFRESH,
|
|
NULL,
|
|
0);
|
|
|
|
hr = PingWebServer(hInternet, MS_URL, pfConnected);
|
|
}
|
|
|
|
InternetSetOption(
|
|
hInternet,
|
|
INTERNET_OPTION_DISABLE_AUTODIAL,
|
|
&dwOrigDisable,
|
|
sizeof(DWORD));
|
|
}
|
|
|
|
RestoreRasAutoDial();
|
|
|
|
TRACE1(L"%s connect to WPA HTTP server",
|
|
(*pfConnected) ? L"could" : L"could not");
|
|
|
|
return hr;
|
|
} // CConnectionManager::ConnectedToInternetEx
|
|
|
|
typedef struct tagConnmgrPARAM
|
|
{
|
|
HWND hwnd;
|
|
CConnectionManager *pConnmgr;
|
|
} CONNMGRPARAM, *PCONNMGRPARAM;
|
|
|
|
DWORD WINAPI ConnectedToInternetExThread(LPVOID vpParam)
|
|
{
|
|
BOOL fConnected = FALSE;
|
|
PCONNMGRPARAM pParam = (PCONNMGRPARAM) vpParam;
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = pParam->pConnmgr->ConnectedToInternetEx(&fConnected);
|
|
|
|
PostMessage(pParam->hwnd, WM_OBCOMM_NETCHECK_DONE, fConnected, hr);
|
|
|
|
GlobalFree(pParam);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AsyncConnectedToInternetEx
|
|
//
|
|
// Determines whether the system is currently connected to the Internet.
|
|
//
|
|
// parameters:
|
|
// pfConnected pointer to a buffer that will receive the boolean
|
|
// indicating whether the connection exists.
|
|
//
|
|
// returns:
|
|
// TRUE if the system is connected to the internet. Note it may
|
|
// trigger autodial if it is enabled and no connection is
|
|
// available when this is called
|
|
// FALSE otherwise
|
|
//
|
|
// note:
|
|
// Deprecated.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
STDMETHODIMP
|
|
CConnectionManager::AsyncConnectedToInternetEx(
|
|
const HWND hwnd
|
|
)
|
|
{
|
|
DWORD threadId;
|
|
HANDLE hThread;
|
|
PCONNMGRPARAM pParam = NULL;
|
|
HRESULT hr = S_OK;
|
|
DWORD dwError;
|
|
|
|
pParam = (PCONNMGRPARAM) GlobalAlloc(GPTR, sizeof(CONNMGRPARAM));
|
|
if (pParam)
|
|
{
|
|
pParam->hwnd = hwnd;
|
|
pParam->pConnmgr = this;
|
|
|
|
hThread = CreateThread(NULL, 0, ConnectedToInternetExThread, pParam, 0, &threadId);
|
|
if (hThread == NULL)
|
|
{
|
|
dwError = GetLastError();
|
|
hr = HRESULT_FROM_WIN32(dwError);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
// Notify the script so that it won't hang
|
|
PostMessage(hwnd, WM_OBCOMM_NETCHECK_DONE, FALSE, hr);
|
|
}
|
|
|
|
return hr;
|
|
} // CConnectionManager::AsyncConnectedToInternetEx
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// IsEnabledConnection
|
|
//
|
|
// Determines whether a connection should be considered as having Internet
|
|
// capability or not, based on its media type and current status.
|
|
//
|
|
// parameters:
|
|
// ncMedia The media type of the connection
|
|
// ncStatus The current status of the connection
|
|
//
|
|
// returns:
|
|
// TRUE We should not considered it as having Internet capability
|
|
// FALSE otherwise
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
CConnectionManager::IsEnabledConnection(
|
|
NETCON_PROPERTIES* pprops
|
|
)
|
|
{
|
|
BOOL bRet;
|
|
|
|
switch (pprops->MediaType)
|
|
{
|
|
case NCM_LAN:
|
|
bRet = (pprops->Status != NCS_DISCONNECTED);
|
|
if (bRet && m_bExclude1394 && Is1394Adapter(&(pprops->guidId)))
|
|
{
|
|
TRACE1(L"%s not considered as LAN", pprops->pszwName);
|
|
bRet = FALSE;
|
|
}
|
|
break;
|
|
|
|
case NCM_SHAREDACCESSHOST_LAN:
|
|
case NCM_SHAREDACCESSHOST_RAS:
|
|
bRet = (pprops->Status != NCS_DISCONNECTED);
|
|
break;
|
|
default:
|
|
bRet = TRUE;
|
|
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SaveProxySettings
|
|
//
|
|
// Save existing proxy settings for current user.
|
|
//
|
|
// returns:
|
|
// TRUE The value is successfully saved
|
|
// FALSE otherwise
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
CConnectionManager::SaveProxySettings()
|
|
{
|
|
if (!m_bProxySaved)
|
|
{
|
|
TRACE(TEXT("try to save the existing proxy settings"));
|
|
|
|
if (AllocProxyOptionList(&m_CurrentProxySettings))
|
|
{
|
|
DWORD dwBufferLength = sizeof(m_CurrentProxySettings);
|
|
|
|
if (InternetQueryOption(
|
|
NULL,
|
|
INTERNET_OPTION_PER_CONNECTION_OPTION,
|
|
&m_CurrentProxySettings,
|
|
&dwBufferLength
|
|
))
|
|
{
|
|
m_bProxySaved = TRUE;
|
|
TRACE(TEXT("successfully save the proxy settings"));
|
|
}
|
|
else
|
|
{
|
|
FreeProxyOptionList(&m_CurrentProxySettings);
|
|
}
|
|
}
|
|
|
|
if (!m_bProxySaved)
|
|
{
|
|
TRACE1(
|
|
TEXT("fail to save the proxy settings (Error %d)"),
|
|
GetLastError()
|
|
);
|
|
}
|
|
}
|
|
|
|
return m_bProxySaved;
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RestoreProxySettings
|
|
//
|
|
// Restore the setting captured by SaveProxySettings.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
CConnectionManager::RestoreProxySettings()
|
|
{
|
|
|
|
BOOL bRestored = FALSE;
|
|
|
|
if (m_bProxyApplied)
|
|
{
|
|
TRACE(TEXT("try to restore the original proxy settings"));
|
|
|
|
bRestored = InternetSetOption(
|
|
NULL,
|
|
INTERNET_OPTION_PER_CONNECTION_OPTION,
|
|
&m_CurrentProxySettings,
|
|
sizeof(m_CurrentProxySettings)
|
|
);
|
|
|
|
if (bRestored)
|
|
{
|
|
m_bProxyApplied = FALSE;
|
|
TRACE(TEXT("successfully restored the proxy settings"));
|
|
}
|
|
else
|
|
{
|
|
TRACE1(
|
|
TEXT("failed to restore the proxy settings (WININET Error %d)"),
|
|
GetLastError()
|
|
);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
static LPTSTR
|
|
pDuplicateString(
|
|
LPCTSTR szText
|
|
)
|
|
{
|
|
int cchText;
|
|
LPTSTR szOutText;
|
|
|
|
if (szText == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
cchText = lstrlen(szText);
|
|
szOutText = (LPTSTR) GlobalAlloc(GPTR, sizeof(TCHAR) * (cchText + 1));
|
|
if (szOutText)
|
|
{
|
|
lstrcpyn(szOutText, szText, cchText + 1);
|
|
}
|
|
|
|
return szOutText;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// ApplyWinntProxySettings
|
|
//
|
|
// Apply the proxy settings for NIC saved during winnt32.exe to the current user.
|
|
// Before the values is applied, it makes sure that existing settings is saved.
|
|
//
|
|
// returns:
|
|
// TRUE the proxy settings was successfully applied
|
|
// FALSE otherwise
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
CConnectionManager::ApplyWinntProxySettings()
|
|
{
|
|
#define MAX_URL_LENGTH 2048
|
|
|
|
DWORD dwProxyFlags = 0;
|
|
LPTSTR szProxyList = NULL;
|
|
TCHAR szWinntPath[MAX_PATH];
|
|
|
|
//
|
|
// Save proxy settings if it has not been saved.
|
|
//
|
|
SaveProxySettings();
|
|
|
|
//
|
|
// Apply proxy settings if it has not been applied.
|
|
//
|
|
if (m_bProxySaved && !m_bProxyApplied)
|
|
{
|
|
TRACE1(TEXT("tries to apply proxy settings, saved in %s"),
|
|
WINNT_INF_FILENAME);
|
|
|
|
if (GetCanonicalizedPath(szWinntPath, WINNT_INF_FILENAME))
|
|
{
|
|
DWORD dwEnableOobeProxy;
|
|
|
|
dwEnableOobeProxy = GetPrivateProfileInt(
|
|
OOBE_PROXY_SECTION,
|
|
OOBE_ENABLE_OOBY_PROXY,
|
|
0,
|
|
szWinntPath
|
|
);
|
|
|
|
if (dwEnableOobeProxy)
|
|
{
|
|
INTERNET_PER_CONN_OPTION_LIST PrevProxySettings;
|
|
|
|
if (AllocProxyOptionList(&PrevProxySettings))
|
|
{
|
|
INTERNET_PER_CONN_OPTION* pOption = PrevProxySettings.pOptions;
|
|
DWORD dwBufferLength = sizeof(PrevProxySettings);
|
|
TCHAR szBuffer[MAX_URL_LENGTH];
|
|
|
|
pOption[0].Value.dwValue = GetPrivateProfileInt(
|
|
OOBE_PROXY_SECTION,
|
|
OOBE_FLAGS,
|
|
0,
|
|
szWinntPath
|
|
);
|
|
|
|
if (GetPrivateProfileString(
|
|
OOBE_PROXY_SECTION,
|
|
OOBE_PROXY_SERVER,
|
|
TEXT(""),
|
|
szBuffer,
|
|
MAX_URL_LENGTH,
|
|
szWinntPath
|
|
))
|
|
{
|
|
pOption[1].Value.pszValue = pDuplicateString(szBuffer);
|
|
}
|
|
|
|
if (GetPrivateProfileString(
|
|
OOBE_PROXY_SECTION,
|
|
OOBE_PROXY_BYPASS,
|
|
TEXT(""),
|
|
szBuffer,
|
|
MAX_URL_LENGTH,
|
|
szWinntPath
|
|
))
|
|
{
|
|
pOption[2].Value.pszValue = pDuplicateString(szBuffer);
|
|
}
|
|
|
|
if (GetPrivateProfileString(
|
|
OOBE_PROXY_SECTION,
|
|
OOBE_AUTOCONFIG_URL,
|
|
TEXT(""),
|
|
szBuffer,
|
|
MAX_URL_LENGTH,
|
|
szWinntPath
|
|
))
|
|
{
|
|
pOption[3].Value.pszValue = pDuplicateString(szBuffer);
|
|
}
|
|
|
|
pOption[4].Value.dwValue = GetPrivateProfileInt(
|
|
OOBE_PROXY_SECTION,
|
|
OOBE_AUTODISCOVERY_FLAGS,
|
|
0,
|
|
szWinntPath
|
|
);
|
|
|
|
if (GetPrivateProfileString(
|
|
OOBE_PROXY_SECTION,
|
|
OOBE_AUTOCONFIG_SECONDARY_URL,
|
|
TEXT(""),
|
|
szBuffer,
|
|
MAX_URL_LENGTH,
|
|
szWinntPath
|
|
))
|
|
{
|
|
pOption[5].Value.pszValue = pDuplicateString(szBuffer);
|
|
}
|
|
|
|
m_bProxyApplied = InternetSetOption(
|
|
NULL,
|
|
INTERNET_OPTION_PER_CONNECTION_OPTION,
|
|
&PrevProxySettings,
|
|
sizeof(PrevProxySettings)
|
|
);
|
|
|
|
FreeProxyOptionList(&PrevProxySettings);
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (m_bProxyApplied)
|
|
{
|
|
TRACE(TEXT("successfully load the proxy settings"));
|
|
}
|
|
else
|
|
{
|
|
TRACE1(TEXT("could not load the proxy settings (WIN32 Error %d)"),
|
|
GetLastError());
|
|
}
|
|
}
|
|
|
|
return m_bProxyApplied;
|
|
}
|
|
|
|
void
|
|
CConnectionManager::UseWinntProxySettings()
|
|
{
|
|
m_bUseProxy = TRUE;
|
|
}
|
|
|
|
void
|
|
CConnectionManager::DisableWinntProxySettings()
|
|
{
|
|
TCHAR szWinntPath[MAX_PATH];
|
|
|
|
if (GetCanonicalizedPath(szWinntPath, WINNT_INF_FILENAME))
|
|
{
|
|
WritePrivateProfileString(
|
|
OOBE_PROXY_SECTION,
|
|
OOBE_ENABLE_OOBY_PROXY,
|
|
TEXT("0"),
|
|
szWinntPath
|
|
);
|
|
|
|
TRACE1(TEXT("disabled the proxy settings in %s"),
|
|
WINNT_INF_FILENAME);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CConnectionManager::AllocProxyOptionList(
|
|
INTERNET_PER_CONN_OPTION_LIST *pList
|
|
)
|
|
{
|
|
INTERNET_PER_CONN_OPTION* pOption;
|
|
|
|
pOption = (INTERNET_PER_CONN_OPTION*) GlobalAlloc(
|
|
GPTR,
|
|
sizeof(INTERNET_PER_CONN_OPTION) * NUM_PROXY_OPTIONS);
|
|
|
|
if (pOption)
|
|
{
|
|
pList->dwSize = sizeof(*pList);
|
|
pList->pszConnection = NULL;
|
|
pList->dwOptionCount = NUM_PROXY_OPTIONS;
|
|
pList->pOptions = pOption;
|
|
|
|
pOption[0].dwOption = INTERNET_PER_CONN_FLAGS;
|
|
pOption[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
|
|
pOption[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
|
|
pOption[3].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL;
|
|
pOption[4].dwOption = INTERNET_PER_CONN_AUTODISCOVERY_FLAGS;
|
|
pOption[5].dwOption = INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL;
|
|
}
|
|
else
|
|
{
|
|
pList->pOptions = NULL;
|
|
}
|
|
|
|
return (pOption != NULL);
|
|
}
|
|
|
|
void
|
|
CConnectionManager::FreeProxyOptionList(
|
|
INTERNET_PER_CONN_OPTION_LIST *pList
|
|
)
|
|
{
|
|
INTERNET_PER_CONN_OPTION* pOption = pList->pOptions;
|
|
if (pOption)
|
|
{
|
|
if (pOption[1].Value.pszValue)
|
|
{
|
|
GlobalFree(pOption[1].Value.pszValue);
|
|
}
|
|
|
|
if (pOption[2].Value.pszValue)
|
|
{
|
|
GlobalFree(pOption[2].Value.pszValue);
|
|
}
|
|
|
|
if (pOption[3].Value.pszValue)
|
|
{
|
|
GlobalFree(pOption[3].Value.pszValue);
|
|
}
|
|
|
|
if (pOption[5].Value.pszValue)
|
|
{
|
|
GlobalFree(pOption[5].Value.pszValue);
|
|
}
|
|
|
|
GlobalFree(pOption);
|
|
|
|
pList->pOptions = NULL;
|
|
}
|
|
}
|
|
|
|
void CConnectionManager::DisableRasAutodial()
|
|
{
|
|
DWORD dwValue = RAS_AUTODIAL_DISABLED;
|
|
|
|
if (m_dwRasAutodialDisable == RAS_AUTODIAL_DONT_KNOW)
|
|
{
|
|
DWORD dwSize = sizeof(m_dwRasAutodialDisable);
|
|
|
|
if (RasGetAutodialParam(
|
|
RASADP_LoginSessionDisable,
|
|
&m_dwRasAutodialDisable,
|
|
&dwSize
|
|
) != ERROR_SUCCESS)
|
|
{
|
|
m_dwRasAutodialDisable = RAS_AUTODIAL_ENABLED;
|
|
}
|
|
else
|
|
{
|
|
TRACE1(
|
|
L"Save value of RASADP_LoginSessionDisable %d",
|
|
m_dwRasAutodialDisable
|
|
);
|
|
}
|
|
}
|
|
|
|
if (RasSetAutodialParam(
|
|
RASADP_LoginSessionDisable,
|
|
&dwValue,
|
|
sizeof(dwValue)
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
TRACE(L"Disabled RAS Autodial for current logon session");
|
|
}
|
|
}
|
|
|
|
void CConnectionManager::RestoreRasAutoDial()
|
|
{
|
|
if (m_dwRasAutodialDisable != RAS_AUTODIAL_DONT_KNOW)
|
|
{
|
|
if (RasSetAutodialParam(
|
|
RASADP_LoginSessionDisable,
|
|
&m_dwRasAutodialDisable,
|
|
sizeof(m_dwRasAutodialDisable)
|
|
) == ERROR_SUCCESS)
|
|
{
|
|
TRACE(L"Restore value of RAS Autodial for current logon session");
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT CConnectionManager::GetProxySettings(
|
|
BOOL* pbUseAuto,
|
|
BOOL* pbUseScript,
|
|
BSTR* pszScriptUrl,
|
|
BOOL* pbUseProxy,
|
|
BSTR* pszProxy
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// Save proxy settings if it has not been saved.
|
|
//
|
|
SaveProxySettings();
|
|
|
|
if (m_bProxySaved)
|
|
{
|
|
INTERNET_PER_CONN_OPTION* pOption = m_CurrentProxySettings.pOptions;
|
|
|
|
*pbUseAuto = pOption[0].Value.dwValue & PROXY_TYPE_AUTO_DETECT;
|
|
*pbUseScript = pOption[0].Value.dwValue & PROXY_TYPE_AUTO_PROXY_URL;
|
|
*pbUseProxy = pOption[0].Value.dwValue & PROXY_TYPE_PROXY;
|
|
|
|
if (pOption[1].Value.pszValue)
|
|
{
|
|
*pszProxy = SysAllocString(pOption[1].Value.pszValue);
|
|
}
|
|
else
|
|
{
|
|
*pszProxy = NULL;
|
|
}
|
|
|
|
if (pOption[3].Value.pszValue)
|
|
{
|
|
*pszScriptUrl = SysAllocString(pOption[3].Value.pszValue);
|
|
}
|
|
else
|
|
{
|
|
*pszScriptUrl = NULL;
|
|
}
|
|
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
HRESULT CConnectionManager::SetProxySettings(
|
|
BOOL bUseAuto,
|
|
BOOL bUseScript,
|
|
BSTR szScriptUrl,
|
|
BOOL bUseProxy,
|
|
BSTR szProxy
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//
|
|
// We don't behavior correctly in this->ConnectedToInternetEx if we
|
|
// also use proxy settings saved in winnt32.
|
|
//
|
|
MYASSERT(!m_bUseProxy);
|
|
|
|
//
|
|
// Save proxy settings if it has not been saved.
|
|
//
|
|
SaveProxySettings();
|
|
|
|
if (m_bProxySaved)
|
|
{
|
|
INTERNET_PER_CONN_OPTION_LIST ProxySettings;
|
|
|
|
if (AllocProxyOptionList(&ProxySettings))
|
|
{
|
|
INTERNET_PER_CONN_OPTION* pOption = ProxySettings.pOptions;
|
|
|
|
pOption[0].Value.dwValue = PROXY_TYPE_DIRECT;
|
|
if (bUseAuto)
|
|
{
|
|
pOption[0].Value.dwValue |= PROXY_TYPE_AUTO_DETECT;
|
|
}
|
|
if (bUseScript)
|
|
{
|
|
pOption[0].Value.dwValue |= PROXY_TYPE_AUTO_PROXY_URL;
|
|
}
|
|
if (bUseProxy)
|
|
{
|
|
pOption[0].Value.dwValue |= PROXY_TYPE_PROXY;
|
|
}
|
|
|
|
pOption[1].Value.pszValue = szProxy;
|
|
|
|
pOption[2].Value.pszValue = NULL;
|
|
|
|
pOption[3].Value.pszValue = szScriptUrl;
|
|
|
|
pOption[4].Value.dwValue = m_CurrentProxySettings.pOptions[4].Value.dwValue;
|
|
if (bUseAuto)
|
|
{
|
|
pOption[4].Value.dwValue |= AUTO_PROXY_FLAG_USER_SET;
|
|
}
|
|
|
|
pOption[5].Value.pszValue = m_CurrentProxySettings.pOptions[5].Value.pszValue;
|
|
|
|
TRACE5(TEXT("tries to set LAN proxy: %d, %s, %s, %d"),
|
|
pOption[0].Value.dwValue,
|
|
pOption[1].Value.pszValue,
|
|
pOption[3].Value.pszValue,
|
|
pOption[4].Value.dwValue,
|
|
pOption[5].Value.pszValue
|
|
);
|
|
|
|
if (InternetSetOption(
|
|
NULL,
|
|
INTERNET_OPTION_PER_CONNECTION_OPTION,
|
|
&ProxySettings,
|
|
sizeof(ProxySettings)
|
|
))
|
|
{
|
|
m_bProxyApplied = TRUE;
|
|
hr = S_OK;
|
|
}
|
|
|
|
// so that we don't free the memory from the caller in
|
|
// FreeProxyOptionList
|
|
pOption[1].Value.pszValue = NULL;
|
|
pOption[3].Value.pszValue = NULL;
|
|
pOption[5].Value.pszValue = NULL;
|
|
|
|
FreeProxyOptionList(&ProxySettings);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
TRACE(TEXT("successfully set the proxy settings"));
|
|
}
|
|
else
|
|
{
|
|
TRACE1(TEXT("could not set the proxy settings (WIN32 Error %d)"),
|
|
GetLastError());
|
|
}
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CConnectionManager::GetPublicLanCount(int* pcPublicLan)
|
|
{
|
|
PSTRINGLIST PubList = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
EnumPublicAdapters(&PubList);
|
|
|
|
int i = 0;
|
|
|
|
for (PSTRINGLIST p = PubList; p; p = p->Next)
|
|
{
|
|
i++;
|
|
}
|
|
|
|
*pcPublicLan = i;
|
|
|
|
if (PubList)
|
|
{
|
|
DestroyList(PubList);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CConnectionManager::Enum1394Adapters(
|
|
OUT PSTRINGLIST* pList
|
|
)
|
|
{
|
|
|
|
UINT i;
|
|
INetCfgComponent* arrayComp[MAX_NUM_NET_COMPONENTS];
|
|
IEnumNetCfgComponent* pEnum = NULL;
|
|
INetCfgClass* pNetCfgClass = NULL;
|
|
INetCfgComponent* pNetCfgComp = NULL;
|
|
LPWSTR szPnpId = NULL;
|
|
HRESULT hr = S_OK;
|
|
DWORD dwCharacteristics = 0;
|
|
ULONG iCount = 0;
|
|
PSTRINGLIST List = NULL;
|
|
PSTRINGLIST Cell = NULL;
|
|
GUID guidInstance;
|
|
WCHAR szInstanceGuid[MAX_GUID_LEN + 1] = L"";
|
|
INetCfg* pNetCfg = NULL;
|
|
|
|
ZeroMemory(arrayComp, sizeof(arrayComp));
|
|
|
|
hr = GetNetCfgInterface(FALSE, &pNetCfg);
|
|
if (FAILED(hr))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Obtain the INetCfgClass interface pointer
|
|
//
|
|
|
|
hr = pNetCfg->QueryNetCfgClass( &GUID_DEVCLASS_NET,
|
|
IID_INetCfgClass,
|
|
(void**)&pNetCfgClass );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Retrieve the enumerator interface
|
|
//
|
|
|
|
hr = pNetCfgClass->EnumComponents( &pEnum );
|
|
if( FAILED( hr ) )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
hr = pEnum->Next( MAX_NUM_NET_COMPONENTS, &arrayComp[0], &iCount );
|
|
if( FAILED( hr ) )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
MYASSERT( iCount <= MAX_NUM_NET_COMPONENTS );
|
|
if ( iCount > MAX_NUM_NET_COMPONENTS )
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
goto cleanup;
|
|
}
|
|
|
|
for( i = 0; i < iCount; i++ )
|
|
{
|
|
pNetCfgComp = arrayComp[i];
|
|
|
|
hr = pNetCfgComp->GetCharacteristics( &dwCharacteristics );
|
|
if( FAILED( hr ) )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// If this is a physical adapter
|
|
//
|
|
|
|
if( dwCharacteristics & NCF_PHYSICAL )
|
|
{
|
|
hr = pNetCfgComp->GetId( &szPnpId );
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// If this is a 1394 network adapter
|
|
//
|
|
|
|
if (!lstrcmpi(szPnpId, L"v1394\\nic1394"))
|
|
{
|
|
hr = pNetCfgComp->GetInstanceGuid(&guidInstance);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!StringFromGUID2(guidInstance, szInstanceGuid, MAX_GUID_LEN))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
Cell = CreateStringCell(szInstanceGuid);
|
|
|
|
if (!Cell)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
InsertList(&List, Cell);
|
|
|
|
Cell = NULL;
|
|
|
|
}
|
|
|
|
CoTaskMemFree( szPnpId );
|
|
|
|
szPnpId = NULL;
|
|
}
|
|
}
|
|
|
|
*pList = List;
|
|
List = NULL;
|
|
|
|
cleanup:
|
|
|
|
if (List)
|
|
{
|
|
DestroyList(List);
|
|
}
|
|
|
|
if (Cell)
|
|
{
|
|
DeleteStringCell(Cell);
|
|
}
|
|
|
|
if (szPnpId)
|
|
{
|
|
CoTaskMemFree(szPnpId);
|
|
}
|
|
|
|
for (i = 0; i < iCount; i++)
|
|
{
|
|
if (arrayComp[i])
|
|
{
|
|
arrayComp[i]->Release();
|
|
}
|
|
}
|
|
|
|
if (pNetCfgClass)
|
|
{
|
|
pNetCfgClass->Release();
|
|
}
|
|
|
|
if (pEnum)
|
|
{
|
|
pEnum->Release();
|
|
}
|
|
|
|
if (pNetCfg)
|
|
{
|
|
ReleaseNetCfgInterface(pNetCfg, FALSE);
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
BOOL
|
|
CConnectionManager::Is1394Adapter(
|
|
GUID* pguid
|
|
)
|
|
{
|
|
PSTRINGLIST List = NULL;
|
|
PSTRINGLIST p;
|
|
BOOL bRet = FALSE;
|
|
|
|
Enum1394Adapters(&List);
|
|
|
|
if (List)
|
|
{
|
|
for (p = List; p; p = p->Next)
|
|
{
|
|
if (!StringCmpGUID(p->String, pguid))
|
|
{
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
DestroyList(List);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
HRESULT
|
|
CConnectionManager::EnumPublicConnections(
|
|
OUT PSTRINGLIST* pList
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
PSTRINGLIST PubList = NULL;
|
|
|
|
TRACE(L"Begin EnumPublicConnections ...");
|
|
|
|
EnumPublicAdapters(&PubList);
|
|
|
|
if (!PubList)
|
|
{
|
|
*pList = NULL;
|
|
return hr;
|
|
}
|
|
|
|
// Initialize the net connection enumeration. For each interface
|
|
// retrieved, SetProxyBlanket must be called to set the authentication for
|
|
// the interface proxy handle because the Network Connection Manager lives
|
|
// in a remote process with a different security context.
|
|
//
|
|
INetConnectionManager* pmgr = NULL;
|
|
IEnumNetConnection* penum = NULL;
|
|
NETCON_PROPERTIES* pprops = NULL;
|
|
INetConnection* pnc = NULL;
|
|
PSTRINGLIST List = NULL;
|
|
PSTRINGLIST p = NULL;
|
|
PSTRINGLIST Cell = NULL;
|
|
ULONG ulRetrieved;
|
|
|
|
hr = CoCreateInstance(
|
|
CLSID_ConnectionManager,
|
|
NULL,
|
|
CLSCTX_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
|
|
IID_INetConnectionManager,
|
|
(VOID**) &pmgr
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
hr = SetProxyBlanket(pmgr);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
hr = pmgr->EnumConnections(NCME_DEFAULT, &penum);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
hr = SetProxyBlanket(penum);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
hr = penum->Reset();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
hr = penum->Next(1, &pnc, &ulRetrieved);
|
|
|
|
while (S_OK == hr)
|
|
{
|
|
|
|
hr = SetProxyBlanket(pnc);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
hr = pnc->GetProperties(&pprops);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if (pprops->MediaType == NCM_LAN && pprops->Status != NCS_DISCONNECTED)
|
|
{
|
|
for (p = PubList; p; p = p->Next)
|
|
{
|
|
if (!StringCmpGUID(p->String, &(pprops->guidId)))
|
|
{
|
|
Cell = CreateStringCell(pprops->pszwName);
|
|
if (Cell)
|
|
{
|
|
TRACE1(L" + %s", pprops->pszwName);
|
|
InsertList(&List, Cell);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NcFreeNetconProperties(pprops);
|
|
|
|
pprops = NULL;
|
|
|
|
pnc->Release();
|
|
|
|
pnc = NULL;
|
|
|
|
hr = penum->Next(1, &pnc, &ulRetrieved);
|
|
|
|
}
|
|
|
|
if (hr != S_FALSE)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
// IEnumNetConnection::Next returned S_FALSE to indicate
|
|
// that no more elements were available.
|
|
|
|
hr = S_OK;
|
|
|
|
*pList = List;
|
|
|
|
List = NULL;
|
|
|
|
|
|
cleanup:
|
|
|
|
if (List)
|
|
{
|
|
DestroyList(List);
|
|
}
|
|
|
|
if (NULL != pprops)
|
|
{
|
|
NcFreeNetconProperties(pprops);
|
|
}
|
|
|
|
if (NULL != pnc)
|
|
{
|
|
pnc->Release();
|
|
}
|
|
|
|
if (NULL != penum)
|
|
{
|
|
penum->Release();
|
|
}
|
|
|
|
if (NULL != pmgr)
|
|
{
|
|
pmgr->Release();
|
|
}
|
|
|
|
TRACE1(L"End EnumPublicConnections (0x%08lx)", hr);
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CConnectionManager::EnumPublicAdapters(
|
|
OUT PSTRINGLIST* pList
|
|
)
|
|
{
|
|
static GUID g_guidNLAServiceClass = NLA_SERVICE_CLASS_GUID;
|
|
static const int MAX_ADAPTER_NAME_LEN = 256;
|
|
|
|
WSADATA wsaData;
|
|
int error;
|
|
PSTRINGLIST AdapterList = NULL;
|
|
PSTRINGLIST ExcludeList = NULL;
|
|
|
|
TRACE(L"Begin EnumPublicAdapters ...");
|
|
|
|
if (m_bExclude1394)
|
|
{
|
|
Enum1394Adapters(&ExcludeList);
|
|
}
|
|
|
|
if (0 == (error = WSAStartup(MAKEWORD(2, 2), &wsaData)))
|
|
{
|
|
// Init query for network names
|
|
WSAQUERYSET restrictions = {0};
|
|
restrictions.dwSize = sizeof(restrictions);
|
|
restrictions.lpServiceClassId = &g_guidNLAServiceClass;
|
|
restrictions.dwNameSpace = NS_NLA;
|
|
|
|
HANDLE hQuery;
|
|
|
|
// Make sure we do not ask for the (chicken) blobs that take a long time to get
|
|
if (0 == (error = WSALookupServiceBegin(&restrictions, LUP_NOCONTAINERS | LUP_DEEP, &hQuery)))
|
|
{
|
|
PWSAQUERYSET pqsResults = NULL;
|
|
|
|
while (0 == _AllocWSALookupServiceNext(hQuery, 0, &pqsResults))
|
|
{
|
|
if (NULL != pqsResults->lpBlob)
|
|
{
|
|
NLA_BLOB* pnlaBlob = (NLA_BLOB*) pqsResults->lpBlob->pBlobData;
|
|
WCHAR szAdapterWide[MAX_ADAPTER_NAME_LEN] = L"";
|
|
NLA_INTERNET nlaInternet = NLA_INTERNET_UNKNOWN;
|
|
|
|
while (NULL != pnlaBlob)
|
|
{
|
|
switch (pnlaBlob->header.type)
|
|
{
|
|
case NLA_INTERFACE:
|
|
MultiByteToWideChar(
|
|
CP_ACP,
|
|
0,
|
|
pnlaBlob->data.interfaceData.adapterName,
|
|
-1,
|
|
szAdapterWide,
|
|
ARRAYSIZE(szAdapterWide)
|
|
);
|
|
break;
|
|
case NLA_CONNECTIVITY:
|
|
nlaInternet = pnlaBlob->data.connectivity.internet;
|
|
break;
|
|
}
|
|
pnlaBlob = _NLABlobNext(pnlaBlob);
|
|
}
|
|
|
|
if (nlaInternet == NLA_INTERNET_YES && szAdapterWide[0])
|
|
{
|
|
PSTRINGLIST p = NULL;
|
|
|
|
for (p = ExcludeList; p; p = p->Next)
|
|
{
|
|
if (!lstrcmpi(p->String, szAdapterWide))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if the adapter is excluded.
|
|
//
|
|
|
|
if (!p)
|
|
{
|
|
PSTRINGLIST Cell = CreateStringCell(szAdapterWide);
|
|
if (Cell)
|
|
{
|
|
TRACE1(L" + %s", szAdapterWide);
|
|
InsertList(&AdapterList, Cell);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
LocalFree(pqsResults);
|
|
}
|
|
|
|
|
|
WSALookupServiceEnd(pqsResults);
|
|
}
|
|
|
|
WSACleanup();
|
|
|
|
if (error == 0)
|
|
{
|
|
*pList = AdapterList;
|
|
}
|
|
else
|
|
{
|
|
if (AdapterList)
|
|
{
|
|
DestroyList(AdapterList);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
TRACE1(L"End EnumPublicAdapters (%d)", error);
|
|
|
|
return HRESULT_FROM_WIN32(error);
|
|
}
|
|
|
|
NLA_BLOB* _NLABlobNext(
|
|
IN NLA_BLOB* pnlaBlob
|
|
)
|
|
{
|
|
NLA_BLOB* pNext = NULL;
|
|
|
|
if (pnlaBlob->header.nextOffset)
|
|
{
|
|
pNext = (NLA_BLOB*) (((BYTE*) pnlaBlob) + pnlaBlob->header.nextOffset);
|
|
}
|
|
|
|
return pNext;
|
|
}
|
|
|
|
int _AllocWSALookupServiceNext(
|
|
IN HANDLE hQuery,
|
|
IN DWORD dwControlFlags,
|
|
OUT LPWSAQUERYSET* ppResults
|
|
)
|
|
{
|
|
*ppResults = NULL;
|
|
|
|
DWORD cb = 0;
|
|
int error = 0;
|
|
if (SOCKET_ERROR == WSALookupServiceNext(hQuery, dwControlFlags, &cb, NULL))
|
|
{
|
|
error = WSAGetLastError();
|
|
if (WSAEFAULT == error)
|
|
{
|
|
assert(cb);
|
|
*ppResults = (LPWSAQUERYSET) LocalAlloc(LPTR, cb);
|
|
|
|
if (NULL != *ppResults)
|
|
{
|
|
error = 0;
|
|
if (SOCKET_ERROR == WSALookupServiceNext(hQuery, dwControlFlags, &cb, *ppResults))
|
|
{
|
|
error = WSAGetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error = WSA_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
// May as well map outdated error code while we're here.
|
|
if (WSAENOMORE == error)
|
|
{
|
|
error = WSA_E_NO_MORE;
|
|
}
|
|
|
|
if (error && (*ppResults))
|
|
{
|
|
LocalFree(*ppResults);
|
|
*ppResults = NULL;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
static int StringCmpGUID(
|
|
IN LPCWSTR szGuid,
|
|
IN const GUID* pguid
|
|
)
|
|
{
|
|
WCHAR szGuid1[MAX_GUID_LEN + 1];
|
|
|
|
if (!StringFromGUID2(*pguid, szGuid1, MAX_GUID_LEN))
|
|
{
|
|
// consider it as szGuid is greater than pguid
|
|
return 1;
|
|
}
|
|
|
|
return lstrcmpi(szGuid, szGuid1);
|
|
}
|
|
|