[toc]
win com类和接口说明
1. INetworkListManager
INetworkListManager 接口提供了一组用于执行网络列表管理功能的方法。
[通过com组件获取系统网卡] INetworkListManager接口
| INetworkListManager::ClearSimulatedProfileInfo 清除以前通过 SetSimulatedProfileInfo 应用于 Internet 连接配置文件的连接配置文件值。 下一个 Internet 连接查询(通过 GetInternetConnectionProfile)将使用系统信息。 |
|---|
| INetworkListManager::get_IsConnected get_IsConnected 属性指定本地计算机是否具有网络连接。 |
| INetworkListManager::get_IsConnectedToInternet get_IsConnectedToInternet 属性指定本地计算机是否具有 Internet 连接。 |
| INetworkListManager::GetConnectivity GetConnectivity 方法返回计算机的整体连接状态。 |
| INetworkListManager::GetNetwork GetNetwork 方法基于提供的网络 ID 检索网络。 |
| INetworkListManager::GetNetworkConnection GetNetworkConnection 方法基于提供的网络连接 ID 检索网络。 |
| INetworkListManager::GetNetworkConnections GetNetworkConnections 方法枚举已建立的网络连接的完整列表。 |
| INetworkListManager::GetNetworks GetNetworks 方法检索本地计算机上可用的网络列表。 |
| INetworkListManager::SetSimulatedProfileInfo SetSimulatedProfileInfo 方法将一组特定的连接配置文件值应用于 Internet 连接配置文件,以支持特定按流量计费的 Internet 连接条件模拟。 |
使用参考:
...
IUnknown* pUnknown = NULL;
HRESULT Result = CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL, IID_IUnknown, (void**)&pUnknown);
if (SUCCEEDED(Result))
{
INetworkListManager* pNetworkListManager = NULL;
Result = pUnknown->QueryInterface(IID_INetworkListManager, (void**)&pNetworkListManager);
if (SUCCEEDED(Result))
{
}
...2. INetConnectionManager
3. IConnectionPointContainer
支持可连接对象的连接点。
| IConnectionPointContainer::EnumConnectionPoints 创建枚举器对象以循环访问可连接对象中支持的所有连接点,每个传出 IID 一个连接点。 |
|---|
| IConnectionPointContainer::FindConnectionPoint 如果 IID 描述支持的传出接口,则返回指向指定 IID 的连接点的 IConnectionPoint 接口的指针。 |
使用参考:
...
IConnectionPointContainer* pCPContainer = NULL;
Result = pNetworkListManager->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPContainer);
if (SUCCEEDED(Result))
{
IConnectionPoint* pConnectPoint = NULL;
Result = pCPContainer->FindConnectionPoint(IID_INetworkListManagerEvents, &pConnectPoint); // 查找 IID 对应的连接点
if (SUCCEEDED(Result))
{
}
}
...4. IConnectionPoint
支持可连接对象的连接点。通过
IConnectionPointContainer::FindConnectionPoint获取。通过其函数Advise可以建立连接点对象与客户端接收器之间的连接。也就是可以通过此接口实现网络事件的监控。
- 第一个参数参考 netListmgr.h
使用参考:
...
IConnectionPoint* pConnectPoint = NULL;
Result = pCPContainer->FindConnectionPoint(IID_INetworkListManagerEvents, &pConnectPoint);
if (SUCCEEDED(Result))
{
DWORD Cookie = NULL;
CNetworkMonitor networkMonitor;
std::function<void(bool)> monitorFunc = std::bind(&CNetworkMonitor::NetworkStatusChangedCallback, networkMonitor, std::placeholders::_1);
// CNetworkListManagerEvent 为继承自 INetworkListManagerEvents 的类,重载了 ConnectivityChanged 函数
CNetworkListManagerEvent* pNetEvent = new(std::nothrow) CNetworkListManagerEvent(monitorFunc);
if (pNetEvent)
{
Result = pConnectPoint->Advise((IUnknown*)pNetEvent, &Cookie);
...5. INetConnection
https://learn.microsoft.com/en-us/windows/win32/api/netcon/nn-netcon-inetconnection
使用示例 1:
监控网络状态,同时可以监控wife的网络质量
#include <string>
#include <iostream>
#include <memory>
#include <thread>
#include <vector>
#include <algorithm>
#include <locale>
#include <codecvt>
#include <functional>
#include <Windows.h>
#include <netlistmgr.h>
#include <atlbase.h>
#include <objbase.h>
#include <wtypes.h>
#include <wlanapi.h>
#include <netcon.h>
#include <IPHlpApi.h>
#include <comutil.h>
#pragma comment(lib, "comsuppwd.lib")
#pragma comment(lib, "ole32.lib")
#pragma comment(lib, "wlanapi.lib")
#pragma comment(lib, "Iphlpapi.lib")
static std::string WCharToMByte(LPCWSTR lpcwszStr)
{
std::string str;
DWORD dwMinSize = 0;
LPSTR lpszStr = NULL;
dwMinSize = WideCharToMultiByte(CP_OEMCP, NULL, lpcwszStr, -1, NULL, 0, NULL, FALSE);
if (0 == dwMinSize)
{
return FALSE;
}
lpszStr = new char[dwMinSize];
WideCharToMultiByte(CP_OEMCP, NULL, lpcwszStr, -1, lpszStr, dwMinSize, NULL, FALSE);
str = lpszStr;
delete[] lpszStr;
return str;
}
static std::wstring GUIDToString(const GUID& guid)
{
OLECHAR guidString[40] = { 0 };
::StringFromGUID2(guid, guidString, sizeof(guidString));
return guidString;
}
static std::string UnicodeToUTF8(const std::wstring& wstr)
{
std::string ret;
try
{
std::wstring_convert< std::codecvt_utf8<wchar_t> > wcv;
ret = wcv.to_bytes(wstr);
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return ret;
}
class NetWorkEvent : public INetworkConnectionEvents
{
private:
LONG _ref;
std::function<void()> _callback;
public:
NetWorkEvent(const std::function<void()>& cb);
virtual HRESULT STDMETHODCALLTYPE NetworkConnectionConnectivityChanged(
/* [in] */ GUID connectionId,
/* [in] */ NLM_CONNECTIVITY newConnectivity);
virtual HRESULT STDMETHODCALLTYPE NetworkConnectionPropertyChanged(
/* [in] */ GUID connectionId,
/* [in] */ NLM_CONNECTION_PROPERTY_CHANGE flags);
STDMETHODIMP QueryInterface(REFIID refIID, void** pIFace);
virtual ULONG __stdcall AddRef(void);
virtual ULONG __stdcall Release(void);
};
NetWorkEvent::NetWorkEvent(const std::function<void()>& cb)
: _callback(cb)
{
}
HRESULT NetWorkEvent::NetworkConnectionConnectivityChanged(GUID connectionId, NLM_CONNECTIVITY newConnectivity)
{
std::wcout << GUIDToString(connectionId) << " | NUL_CONNECTIVITY : " << newConnectivity << std::endl;
if (_callback)
{
_callback();
}
return S_OK;
}
HRESULT NetWorkEvent::NetworkConnectionPropertyChanged(GUID connectionId, NLM_CONNECTION_PROPERTY_CHANGE flags)
{
return S_OK;
}
STDMETHODIMP NetWorkEvent::QueryInterface(REFIID refIID, void** pIFace)
{
HRESULT hr = S_OK;
*pIFace = NULL;
if (IsEqualIID(refIID, IID_IUnknown))
{
*pIFace = (IUnknown*)this;
((IUnknown*)*pIFace)->AddRef();
}
else if (IsEqualIID(refIID, IID_INetworkConnectionEvents))
{
*pIFace = (INetworkConnectionEvents*)this;
((IUnknown*)*pIFace)->AddRef();
}
else
{
hr = E_NOINTERFACE;
}
return hr;
}
ULONG NetWorkEvent::AddRef(void)
{
return (ULONG)InterlockedIncrement(&_ref);
}
ULONG NetWorkEvent::Release(void)
{
LONG Result = InterlockedDecrement(&_ref);
if (Result == 0)
delete this;
return (ULONG)Result;
}
enum NetworkType
{
NotNetwork,
Ethernet,
Wlan,
};
enum WiFiQuality
{
Weak, // (-INF, -70dBm)
Fair, // [-70dBm, -60dBm)
Good, // [-60dBm, -50dBm)
Excellent // [-50dBm, +INF)
};
struct ConnectionInfo
{
std::wstring guid;
NetworkType type;
};
class NetworkMonitor
{
friend void OnNotificationCallback(PWLAN_NOTIFICATION_DATA Data, PVOID context);
public:
NetworkMonitor();
~NetworkMonitor();
std::vector<ConnectionInfo> GetNetworkConnections();
NetworkType GetNetAdpaterType(const std::wstring& guid);
void OnNetworkStatusChange();
WiFiQuality GetWiFiSignalQuality(const std::wstring& guid);
void OnWiFiQualityChange(const GUID& guid);
void ShowNetworkStatus();
private:
std::unique_ptr<NetWorkEvent> _networkEvent;
DWORD _cookie;
CComPtr<INetworkListManager> _pNLM;
CComPtr<IConnectionPointContainer> _pCpc;
CComPtr<IConnectionPoint> _pConnectionPoint;
HANDLE _wlanHandle;
};
static NetworkMonitor* InstanceOfNetworkMonitor()
{
static NetworkMonitor instance;
return &instance;
}
NetworkMonitor::NetworkMonitor()
{
CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
HRESULT hr = CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL, IID_INetworkListManager, (LPVOID*)&_pNLM);
hr = _pNLM->QueryInterface(IID_IConnectionPointContainer, (void**)&_pCpc);
hr = _pCpc->FindConnectionPoint(IID_INetworkConnectionEvents, &_pConnectionPoint);
_networkEvent = std::make_unique<NetWorkEvent>(std::bind(&NetworkMonitor::OnNetworkStatusChange, this));
hr = _pConnectionPoint->Advise((IUnknown*)_networkEvent.get(), &_cookie);
}
NetworkMonitor::~NetworkMonitor()
{
if (_pConnectionPoint)
{
_pConnectionPoint->Unadvise(_cookie);
}
CloseHandle(_wlanHandle);
CoUninitialize();
}
void OnNotificationCallback(PWLAN_NOTIFICATION_DATA Data, PVOID context)
{
if (Data != NULL &&
Data->NotificationSource == WLAN_NOTIFICATION_SOURCE_MSM &&
Data->NotificationCode == wlan_notification_msm_signal_quality_change)
{
WLAN_SIGNAL_QUALITY Qality = (WLAN_SIGNAL_QUALITY)Data->pData;
std::cout << "WiFi OnNotification Qality : " << Qality << std::endl;
InstanceOfNetworkMonitor()->OnWiFiQualityChange(Data->InterfaceGuid);
}
}
std::vector<ConnectionInfo> NetworkMonitor::GetNetworkConnections()
{
std::vector<ConnectionInfo> result;
CComPtr<IEnumNetworkConnections> enumConnectons;
if (FAILED(_pNLM->GetNetworkConnections(&enumConnectons)))
{
std::cerr << "GetNetworkConnections error : " << GetLastError() << std::endl;
return result;
}
if (enumConnectons)
{
ULONG lFetch;
INetworkConnection* connection = nullptr;
while (SUCCEEDED(enumConnectons->Next(1, &connection, &lFetch)) && nullptr != connection)
{
// 判断是否当前连接网卡
/*
VARIANT_BOOL isConnectInternet = VARIANT_FALSE;
connection->get_IsConnectedToInternet(&isConnectInternet);
if (isConnectInternet == VARIANT_FALSE)
{
continue;
}
*/
ConnectionInfo item;
GUID guid;
INetwork* network;
BSTR strNetWorkName = nullptr;
if (SUCCEEDED(connection->GetNetwork(&network)) && network != nullptr)
{
network->GetName(&strNetWorkName);
}
std::string strName = _com_util::ConvertBSTRToString(strNetWorkName);
if (strName.compare("TRustAgent VNIC") != 0)
{
continue;
}
// 获取 GUID
connection->GetAdapterId(&guid);
item.guid = GUIDToString(guid);
result.push_back(item);
}
if (connection)
{
connection->Release();
}
}
for (auto it = result.begin(); it != result.end(); ++it)
{
it->type = GetNetAdpaterType(it->guid);
}
std::partition(result.begin(), std::partition(result.begin(), result.end(), [](const ConnectionInfo& info)
{
return info.type != NetworkType::NotNetwork;
}), [](const ConnectionInfo& info)
{
return info.type == NetworkType::Ethernet;
});
for (auto it = result.begin(); it != result.end(); ++it)
{
std::wcout << "connect network guid : " << it->guid << " | type : " << it->type << std::endl;
}
return result;
}
NetworkType NetworkMonitor::GetNetAdpaterType(const std::wstring& guid)
{
unsigned long unSize = sizeof(IP_ADAPTER_INFO);
std::unique_ptr<uint8_t[]> data = std::make_unique<uint8_t[]>(unSize);
bool find = false;
unsigned long unResult = GetAdaptersInfo(reinterpret_cast<PIP_ADAPTER_INFO>(data.get()), &unSize);
if (ERROR_BUFFER_OVERFLOW == unResult)
{
data = std::make_unique<uint8_t[]>(unSize);
unResult = GetAdaptersInfo(reinterpret_cast<PIP_ADAPTER_INFO>(data.get()), &unSize);
}
if (ERROR_SUCCESS == unResult)
{
PIP_ADAPTER_INFO pIpAdapterInfo = reinterpret_cast<PIP_ADAPTER_INFO>(data.get());
while (pIpAdapterInfo)
{
if (UnicodeToUTF8(guid) == pIpAdapterInfo->AdapterName)
{
return MIB_IF_TYPE_ETHERNET == pIpAdapterInfo->Type ? NetworkType::Ethernet :
IF_TYPE_IEEE80211 == pIpAdapterInfo->Type ? NetworkType::Wlan : NetworkType::NotNetwork;
}
pIpAdapterInfo = pIpAdapterInfo->Next;
}
}
return NetworkType::NotNetwork;
}
void NetworkMonitor::OnNetworkStatusChange()
{
ShowNetworkStatus();
}
WiFiQuality NetworkMonitor::GetWiFiSignalQuality(const std::wstring& guid)
{
WiFiQuality result = WiFiQuality::Weak;
DWORD dwMaxClient = 2;
DWORD dwCurVersion = 0;
DWORD dwResult = 0;
unsigned int i, j;
PWLAN_INTERFACE_INFO_LIST pIfList = NULL;
PWLAN_INTERFACE_INFO pIfInfo = NULL;
PWLAN_AVAILABLE_NETWORK_LIST pBssList = NULL;
PWLAN_AVAILABLE_NETWORK pBssEntry = NULL;
int iRSSI = 0;
if (_wlanHandle == NULL)
{
dwResult = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &_wlanHandle);
if (dwResult != ERROR_SUCCESS)
{
std::cerr << "WlanOpenHandle failed with error: " << dwResult << std::endl;
return result;
}
dwResult = WlanRegisterNotification(_wlanHandle, WLAN_NOTIFICATION_SOURCE_ALL, TRUE, WLAN_NOTIFICATION_CALLBACK(OnNotificationCallback), NULL, NULL, NULL);
if (dwResult != ERROR_SUCCESS)
{
std::cerr << "WlanRegisterNotification failed with error: " << dwResult << std::endl;
return result;
}
}
dwResult = WlanEnumInterfaces(_wlanHandle, NULL, &pIfList);
if (dwResult != ERROR_SUCCESS)
{
std::cerr << "WlanEnumInterfaces failed with error: " << dwResult << std::endl;
return result;
}
for (i = 0; i < (int)pIfList->dwNumberOfItems; i++)
{
pIfInfo = (WLAN_INTERFACE_INFO*)&pIfList->InterfaceInfo[i];
if (guid != GUIDToString(pIfInfo->InterfaceGuid) || pIfInfo->isState != wlan_interface_state_connected)
{
continue;
}
dwResult = WlanGetAvailableNetworkList(_wlanHandle,
&pIfInfo->InterfaceGuid,
0,
NULL,
&pBssList);
if (dwResult != ERROR_SUCCESS)
{
std::cerr << "WlanGetAvailableNetworkList failed with error:" << dwResult << std::endl;
return result;
}
for (j = 0; j < pBssList->dwNumberOfItems; j++)
{
pBssEntry = (WLAN_AVAILABLE_NETWORK*)&pBssList->Network[j];
if (pBssEntry->bNetworkConnectable && (pBssEntry->dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED))
{
if (pBssEntry->wlanSignalQuality == 0)
iRSSI = -100;
else if (pBssEntry->wlanSignalQuality == 100)
iRSSI = -50;
else
iRSSI = -100 + (pBssEntry->wlanSignalQuality / 2);
std::cout << "Signal Quality:\t " << pBssEntry->wlanSignalQuality << " (RSSI: " << iRSSI << " dBm)" << std::endl;
result = iRSSI < -70 ? WiFiQuality::Weak :
iRSSI < -60 ? WiFiQuality::Fair :
iRSSI < -50 ? WiFiQuality::Good : WiFiQuality::Excellent;
}
}
}
if (pBssList != NULL)
{
WlanFreeMemory(pBssList);
pBssList = NULL;
}
if (pIfList != NULL)
{
WlanFreeMemory(pIfList);
pIfList = NULL;
}
return result;
}
void NetworkMonitor::OnWiFiQualityChange(const GUID& guid)
{
auto nowQuality = GetWiFiSignalQuality(GUIDToString(guid));
std::cout << "WiFi signal quality now : " << nowQuality << std::endl;
ShowNetworkStatus();
}
void NetworkMonitor::ShowNetworkStatus()
{
NetworkType type;
WiFiQuality quality;
auto connections = GetNetworkConnections();
if (connections.empty())
{
type = NetworkType::NotNetwork;
}
else
{
type = connections.front().type;
if (type == NetworkType::Wlan)
{
quality = GetWiFiSignalQuality(connections.front().guid);
}
}
std::cout << "====== Notify ======" << std::endl;
std::cout << "* Type : " << (type == NetworkType::NotNetwork ? "NetworkError" : type == NetworkType::Ethernet ? "Ethernet" : "WiFi") << std::endl;
if (type == NetworkType::Wlan)
{
std::cout << "* Signal : " << quality + 1 << std::endl;
}
std::cout << std::endl;
}
int main()
{
InstanceOfNetworkMonitor()->ShowNetworkStatus();
while (true) std::this_thread::sleep_for(std::chrono::hours(10));
return 0;
}使用示例2
监控网络连接状态
#include <netlistmgr.h>
#include "sp_log.h"
#include <atomic>
#include <thread>
#include <mutex>
#include <string>
#include <vector>
#include <netcon.h>
#include <Shlwapi.h>
#include <TLHELP32.H>
#include <UserEnv.h>
#include <iphlpapi.h>
#pragma comment(lib,"shlwapi.lib")
#pragma comment(lib,"Iphlpapi.lib")
class CNetworkListManagerEvent : public INetworkListManagerEvents
{
public:
CNetworkListManagerEvent(std::function<void(bool)> netChangedHandler)
: m_ref(1)
, netChangedHandler_(netChangedHandler)
{
}
~CNetworkListManagerEvent()
{
}
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject)
{
HRESULT Result = S_OK;
if (IsEqualIID(riid, IID_IUnknown))
{
*ppvObject = (IUnknown*)this;
}
else if (IsEqualIID(riid, IID_INetworkListManagerEvents))
{
*ppvObject = (INetworkListManagerEvents*)this;
}
else
{
Result = E_NOINTERFACE;
}
return Result;
}
ULONG STDMETHODCALLTYPE AddRef()
{
return (ULONG)InterlockedIncrement(&m_ref);
}
ULONG STDMETHODCALLTYPE Release()
{
LONG Result = InterlockedDecrement(&m_ref);
if (Result == 0)
delete this;
return (ULONG)Result;
}
virtual HRESULT STDMETHODCALLTYPE ConnectivityChanged(
/* [in] */ NLM_CONNECTIVITY newConnectivity)
{
if (newConnectivity == NLM_CONNECTIVITY_DISCONNECTED)
{
SP_DEV_LOGT("internet status changed. connect closed");
// 网络断开
netChangedHandler_(false);
}
else if ((newConnectivity & NLM_CONNECTIVITY_IPV4_INTERNET) || (newConnectivity & NLM_CONNECTIVITY_IPv6_INTERNET))
{
SP_DEV_LOGT("internet status changed. connect success");
// 网络连接成功
netChangedHandler_(true);
}
return S_OK;
}
private:
LONG m_ref;
std::function<void(bool)> netChangedHandler_;
};
class CNetworkMonitor
{
public:
CNetworkMonitor() {};
~CNetworkMonitor() {};
private:
// 监控网络状态变化
static void InitNetworkMonitor()
{
SP_DEV_LOGT("InitNetworkMonitor");
bool bSuccess = false;
CoInitialize(NULL);
//
// 通过NLA接口获取网络状态
//
IUnknown* pUnknown = NULL;
HRESULT Result = CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL, IID_IUnknown, (void**)&pUnknown);
if (SUCCEEDED(Result))
{
INetworkListManager* pNetworkListManager = NULL;
Result = pUnknown->QueryInterface(IID_INetworkListManager, (void**)&pNetworkListManager);
if (SUCCEEDED(Result))
{
VARIANT_BOOL IsConnect = VARIANT_FALSE;
Result = pNetworkListManager->get_IsConnectedToInternet(&IsConnect);
if (SUCCEEDED(Result))
{
printf("connect to internet:%s", IsConnect == VARIANT_TRUE ? "TRUE" : "FALSE");
}
IConnectionPointContainer* pCPContainer = NULL;
Result = pNetworkListManager->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPContainer);
if (SUCCEEDED(Result))
{
IConnectionPoint* pConnectPoint = NULL;
Result = pCPContainer->FindConnectionPoint(IID_INetworkListManagerEvents, &pConnectPoint);
if (SUCCEEDED(Result))
{
DWORD Cookie = NULL;
CNetworkMonitor networkMonitor;
std::function<void(bool)> monitorFunc = std::bind(&CNetworkMonitor::NetworkStatusChangedCallback, networkMonitor, std::placeholders::_1);
CNetworkListManagerEvent* pNetEvent = new(std::nothrow) CNetworkListManagerEvent(monitorFunc);
if (pNetEvent)
{
Result = pConnectPoint->Advise((IUnknown*)pNetEvent, &Cookie);
if (SUCCEEDED(Result))
{
printf("InitNetworkMonitor success");
bSuccess = true;
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
{
break;
}
}
pConnectPoint->Unadvise(Cookie);
pConnectPoint->Release();
}
}
}
pCPContainer->Release();
}
pNetworkListManager->Release();
}
pUnknown->Release();
}
CoUninitialize();
}
void NetworkStatusChangedCallback(bool status)
{
g_bNetWorkOnline = status;
if (status)
{
if (g_sp_trust_model.get())
{
if (g_sp_trust_model->IsOnline())
{
//休眠唤醒后网络连接成功,自动发送一次心跳
printf("Sleep wakes up and automatically triggers a heartbeat");
}
else
{
printf("No login, will not rebuild trust nc");
}
}
else
{
printf("rebuild trust nc - g_sp_trust_model is null");
}
}
}
public:
void StartMonitor()
{
std::thread monitorThread(&InitNetworkMonitor);
monitorThread.detach();
}
};