【问题标题】:Detect internet connectivity change event programmatically C++ Windows以编程方式检测 Internet 连接更改事件 C++ Windows
【发布时间】:2022-01-22 22:17:44
【问题描述】:

Windows 系统连接/断开互联网时需要通知我。

我在 C# 中看到过answers,但我需要在 C++ 中执行此操作,并且不使用 WMI。

C++ 中有一些answers,但它只在某个时间点检查互联网连接。但这需要在发生时进行检测。每隔几分钟或几秒钟重复一次这不是最好的主意。需要将事件传达给我的应用程序。 此外,ping 知名主机可能很危险,因为该主机有时可能无法访问,这会导致错误的结论。

这样的活动有可能吗?如果是,该怎么做?

【问题讨论】:

标签: c++ windows winapi event-handling internet-connection


【解决方案1】:

只要连接发生变化,您就可以使用INetworkListManager 请求INetworkConnectionEvents。要将这些放在一起,您必须执行以下操作:

  • 实现INetworkConnectionEvents 类型的事件接收器。
  • 实例化一个INetworkListManager 对象。
  • 连接事件接收器。

如果您不了解连接点,最后一步可能会造成混淆。 Raymond Chen 已就该主题发表了一篇颇具教育意义的博文,如果您需要赶上进度:An introduction to COM connection points

以下大致概述了如何实现这一点。它使用的是微软的_com_ptr_t,所以前面有相当多的样板代码:

#if defined(_DEBUG)
#    pragma comment(lib, "comsuppwd.lib")
#else
#    pragma comment(lib, "comsuppw.lib")
#endif

#include <comdef.h>
#include <comip.h>
#include <netlistmgr.h>

_COM_SMARTPTR_TYPEDEF(INetworkListManager, __uuidof(INetworkListManager));
_COM_SMARTPTR_TYPEDEF(IConnectionPointContainer, __uuidof(IConnectionPointContainer));
_COM_SMARTPTR_TYPEDEF(IConnectionPoint, __uuidof(IConnectionPoint));
_COM_SMARTPTR_TYPEDEF(IUnknown, __uuidof(IUnknown));

这确保链接到适当的库,拉入所需的头文件,并声明一些基于_com_ptr_t 的智能指针类型。接下来是INetworkConnectionEvents 实现:

struct EventSink : INetworkListManagerEvents
{
    HRESULT QueryInterface(REFIID riid, LPVOID* ppvObj)
    {
        if (!ppvObj)
        {
            return E_POINTER;
        }
        *ppvObj = nullptr;
        if (riid == IID_IUnknown || riid == IID_INetworkListManagerEvents)
        {
            AddRef();
            *ppvObj = reinterpret_cast<void*>(this);
            return S_OK;
        }
        return E_NOINTERFACE;
    }

    ULONG AddRef() { return 1; }
    ULONG Release() { return 1; }

    HRESULT ConnectivityChanged(NLM_CONNECTIVITY newConnectivity)
    {
        if ((newConnectivity & (NLM_CONNECTIVITY_IPV4_INTERNET | NLM_CONNECTIVITY_IPV6_INTERNET)) != 0)
        {
            printf("Internet connection available\n");
        }
        else
        {
            printf("Internet connection not available\n");
        }
        return S_OK;
    }
    HRESULT NetworkConnectionPropertyChanged(GUID connectionId, NLM_CONNECTION_PROPERTY_CHANGE) { return S_OK; }
};

这实现了IUnknown 接口以及两个INetworkConnectionEvents 成员。 IUnknown 的实现对于我们的用例来说还不够;生产质量的实现需要通过AddRefRelease 提供正确的引用计数。

接下来的代码会实例化一个INetworkListManager 对象并将事件接收器连接起来以接收通知:

int main()
{
    // Initialize COM
    auto hr { ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED) };

    // Instantiate INetworkListManager object
    INetworkListManagerPtr spManager { nullptr };
    if SUCCEEDED (hr)
    {
        hr = spManager.CreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_ALL);
    }

    // Query for connection point container
    IConnectionPointContainerPtr spConnectionPoints { nullptr };
    if SUCCEEDED (hr)
    {
        hr = spManager.QueryInterface(IID_PPV_ARGS(&spConnectionPoints));
    }

    // Find connection point for the interesting event
    IConnectionPointPtr spConnectionPoint { __nullptr };
    if SUCCEEDED (hr)
    {
        hr = spConnectionPoints->FindConnectionPoint(IID_INetworkListManagerEvents, &spConnectionPoint);
    }

    // Construct event sink
    EventSink sink {};
    IUnknownPtr spSink { nullptr };
    if (SUCCEEDED(hr))
    {
        hr = sink.QueryInterface(IID_IUnknown, reinterpret_cast<void**>(&spSink));
    }

    // And wire it up to the connection point
    DWORD cookie { 0 };
    if SUCCEEDED (hr)
    {
        hr = spConnectionPoint->Advise(spSink, &cookie);
    }

    // At this point everything is set up to receive notifications
    MSG msg {};
    while (::GetMessageW(&msg, nullptr, 0, 0) > 0)
    {
        ::DispatchMessageW(&msg);
    }

    // Cleanup
    if (SUCCEEDED(hr))
    {
        hr = spConnectionPoint->Unadvise(cookie);
    }

    // Don't uninitialize COM since we have smart pointers that
    // get cleaned up only after leaving this scope.
}

【讨论】:

    猜你喜欢
    • 2014-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-26
    • 1970-01-01
    相关资源
    最近更新 更多