QNI: NetworkListManager: Extract the Events class
Moving the class out makes it easier to navigate the code Change-Id: I8de67641512a7dbbf6446cdca9d8dea79a63c217 Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
This commit is contained in:
parent
5d941c7660
commit
1834fcad33
@ -3,7 +3,9 @@ qt_internal_add_plugin(QNLMNIPlugin
|
||||
CLASS_NAME QNetworkListManagerNetworkInformationBackendFactory
|
||||
PLUGIN_TYPE networkinformation
|
||||
DEFAULT_IF WIN32 AND QT_FEATURE_networklistmanager
|
||||
SOURCES qnetworklistmanagernetworkinformationbackend.cpp
|
||||
SOURCES
|
||||
qnetworklistmanagernetworkinformationbackend.cpp
|
||||
qnetworklistmanagerevents.h qnetworklistmanagerevents.cpp
|
||||
LIBRARIES
|
||||
Qt::NetworkPrivate
|
||||
)
|
||||
|
@ -0,0 +1,178 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qnetworklistmanagerevents.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace {
|
||||
template<typename T>
|
||||
bool QueryInterfaceImpl(IUnknown *from, REFIID riid, void **ppvObject)
|
||||
{
|
||||
if (riid == __uuidof(T)) {
|
||||
*ppvObject = static_cast<T *>(from);
|
||||
from->AddRef();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QNetworkListManagerEvents::QNetworkListManagerEvents() : QObject(nullptr)
|
||||
{
|
||||
auto hr = CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_INetworkListManager, &networkListManager);
|
||||
if (FAILED(hr)) {
|
||||
qCWarning(lcNetInfoNLM) << "Could not get a NetworkListManager instance:"
|
||||
<< errorStringFromHResult(hr);
|
||||
return;
|
||||
}
|
||||
|
||||
ComPtr<IConnectionPointContainer> connectionPointContainer;
|
||||
hr = networkListManager.As(&connectionPointContainer);
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = connectionPointContainer->FindConnectionPoint(IID_INetworkListManagerEvents,
|
||||
&connectionPoint);
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
qCWarning(lcNetInfoNLM) << "Failed to get connection point for network list manager events:"
|
||||
<< errorStringFromHResult(hr);
|
||||
}
|
||||
}
|
||||
|
||||
QNetworkListManagerEvents::~QNetworkListManagerEvents()
|
||||
{
|
||||
Q_ASSERT(ref == 0);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QNetworkListManagerEvents::QueryInterface(REFIID riid, void **ppvObject)
|
||||
{
|
||||
if (!ppvObject)
|
||||
return E_INVALIDARG;
|
||||
|
||||
return QueryInterfaceImpl<IUnknown>(this, riid, ppvObject)
|
||||
|| QueryInterfaceImpl<INetworkListManagerEvents>(this, riid, ppvObject)
|
||||
? S_OK
|
||||
: E_NOINTERFACE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
QNetworkListManagerEvents::ConnectivityChanged(NLM_CONNECTIVITY newConnectivity)
|
||||
{
|
||||
// This function is run on a different thread than 'monitor' is created on, so we need to run
|
||||
// it on that thread
|
||||
emit connectivityChanged(newConnectivity);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool QNetworkListManagerEvents::start()
|
||||
{
|
||||
if (!connectionPoint) {
|
||||
qCWarning(lcNetInfoNLM, "Initialization failed, can't start!");
|
||||
return false;
|
||||
}
|
||||
auto hr = connectionPoint->Advise(this, &cookie);
|
||||
if (FAILED(hr)) {
|
||||
qCWarning(lcNetInfoNLM) << "Failed to subscribe to network connectivity events:"
|
||||
<< errorStringFromHResult(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update connectivity since it might have changed since this class was constructed
|
||||
NLM_CONNECTIVITY connectivity;
|
||||
hr = networkListManager->GetConnectivity(&connectivity);
|
||||
if (FAILED(hr))
|
||||
qCWarning(lcNetInfoNLM) << "Could not get connectivity:" << errorStringFromHResult(hr);
|
||||
else
|
||||
emit connectivityChanged(connectivity);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QNetworkListManagerEvents::stop()
|
||||
{
|
||||
Q_ASSERT(connectionPoint);
|
||||
auto hr = connectionPoint->Unadvise(cookie);
|
||||
if (FAILED(hr)) {
|
||||
qCWarning(lcNetInfoNLM) << "Failed to unsubscribe from network connectivity events:"
|
||||
<< errorStringFromHResult(hr);
|
||||
return false;
|
||||
}
|
||||
cookie = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QNetworkListManagerEvents::checkBehindCaptivePortal()
|
||||
{
|
||||
if (!networkListManager)
|
||||
return false;
|
||||
ComPtr<IEnumNetworks> networks;
|
||||
HRESULT hr =
|
||||
networkListManager->GetNetworks(NLM_ENUM_NETWORK_CONNECTED, networks.GetAddressOf());
|
||||
if (FAILED(hr) || networks == nullptr)
|
||||
return false;
|
||||
|
||||
// @note: This checks all connected networks, but that might not be necessary
|
||||
ComPtr<INetwork> network;
|
||||
hr = networks->Next(1, network.GetAddressOf(), nullptr);
|
||||
while (SUCCEEDED(hr) && network != nullptr) {
|
||||
ComPtr<IPropertyBag> propertyBag;
|
||||
hr = network.As(&propertyBag);
|
||||
if (SUCCEEDED(hr) && propertyBag != nullptr) {
|
||||
VARIANT variant;
|
||||
VariantInit(&variant);
|
||||
const auto scopedVariantClear = qScopeGuard([&variant]() { VariantClear(&variant); });
|
||||
|
||||
const wchar_t *versions[] = { NA_InternetConnectivityV6, NA_InternetConnectivityV4 };
|
||||
for (const auto version : versions) {
|
||||
hr = propertyBag->Read(version, &variant, nullptr);
|
||||
if (SUCCEEDED(hr)
|
||||
&& (V_UINT(&variant) & NLM_INTERNET_CONNECTIVITY_WEBHIJACK)
|
||||
== NLM_INTERNET_CONNECTIVITY_WEBHIJACK) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr = networks->Next(1, network.GetAddressOf(), nullptr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
@ -0,0 +1,100 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtNetwork/private/qtnetworkglobal_p.h>
|
||||
|
||||
#include <QtCore/qstring.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
#include <objbase.h>
|
||||
#include <netlistmgr.h>
|
||||
#include <wrl/client.h>
|
||||
#include <wrl/wrappers/corewrappers.h>
|
||||
#include <comdef.h>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcNetInfoNLM)
|
||||
|
||||
inline QString errorStringFromHResult(HRESULT hr)
|
||||
{
|
||||
_com_error error(hr);
|
||||
return QString::fromWCharArray(error.ErrorMessage());
|
||||
}
|
||||
|
||||
class QNetworkListManagerEvents : public QObject, public INetworkListManagerEvents
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QNetworkListManagerEvents();
|
||||
virtual ~QNetworkListManagerEvents();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef() override { return ++ref; }
|
||||
ULONG STDMETHODCALLTYPE Release() override
|
||||
{
|
||||
if (--ref == 0) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ConnectivityChanged(NLM_CONNECTIVITY newConnectivity) override;
|
||||
|
||||
[[nodiscard]] bool start();
|
||||
bool stop();
|
||||
|
||||
[[nodiscard]] bool checkBehindCaptivePortal();
|
||||
|
||||
signals:
|
||||
void connectivityChanged(NLM_CONNECTIVITY);
|
||||
|
||||
private:
|
||||
ComPtr<INetworkListManager> networkListManager = nullptr;
|
||||
ComPtr<IConnectionPoint> connectionPoint = nullptr;
|
||||
|
||||
QAtomicInteger<ULONG> ref = 0;
|
||||
DWORD cookie = 0;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
@ -39,42 +39,20 @@
|
||||
|
||||
#include <QtNetwork/private/qnetworkinformation_p.h>
|
||||
|
||||
#include "qnetworklistmanagerevents.h"
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/private/qobject_p.h>
|
||||
#include <QtCore/qscopeguard.h>
|
||||
|
||||
#include <objbase.h>
|
||||
#include <netlistmgr.h>
|
||||
#include <wrl/client.h>
|
||||
#include <wrl/wrappers/corewrappers.h>
|
||||
#include <comdef.h>
|
||||
#include <iphlpapi.h>
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcNetInfoNLM)
|
||||
|
||||
// Declared in qnetworklistmanagerevents.h
|
||||
Q_LOGGING_CATEGORY(lcNetInfoNLM, "qt.network.info.netlistmanager");
|
||||
|
||||
static const QString backendName = QStringLiteral("networklistmanager");
|
||||
|
||||
namespace {
|
||||
QString errorStringFromHResult(HRESULT hr)
|
||||
{
|
||||
_com_error error(hr);
|
||||
return QString::fromWCharArray(error.ErrorMessage());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool QueryInterfaceImpl(IUnknown *from, REFIID riid, void **ppvObject)
|
||||
{
|
||||
if (riid == __uuidof(T)) {
|
||||
*ppvObject = static_cast<T *>(from);
|
||||
from->AddRef();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool testCONNECTIVITY(NLM_CONNECTIVITY connectivity, NLM_CONNECTIVITY flag)
|
||||
{
|
||||
return (connectivity & flag) == flag;
|
||||
@ -105,7 +83,6 @@ QNetworkInformation::Reachability reachabilityFromNLM_CONNECTIVITY(NLM_CONNECTIV
|
||||
}
|
||||
}
|
||||
|
||||
class QNetworkListManagerEvents;
|
||||
class QNetworkListManagerNetworkInformationBackend : public QNetworkInformationBackend
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -172,164 +149,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class QNetworkListManagerEvents : public QObject, public INetworkListManagerEvents
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QNetworkListManagerEvents();
|
||||
virtual ~QNetworkListManagerEvents();
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
|
||||
|
||||
ULONG STDMETHODCALLTYPE AddRef() override { return ++ref; }
|
||||
ULONG STDMETHODCALLTYPE Release() override
|
||||
{
|
||||
if (--ref == 0) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE ConnectivityChanged(NLM_CONNECTIVITY newConnectivity) override;
|
||||
|
||||
[[nodiscard]] bool start();
|
||||
bool stop();
|
||||
|
||||
[[nodiscard]] bool checkBehindCaptivePortal();
|
||||
|
||||
signals:
|
||||
void connectivityChanged(NLM_CONNECTIVITY);
|
||||
|
||||
private:
|
||||
ComPtr<INetworkListManager> networkListManager = nullptr;
|
||||
ComPtr<IConnectionPoint> connectionPoint = nullptr;
|
||||
|
||||
QAtomicInteger<ULONG> ref = 0;
|
||||
DWORD cookie = 0;
|
||||
};
|
||||
|
||||
QNetworkListManagerEvents::QNetworkListManagerEvents() : QObject(nullptr)
|
||||
{
|
||||
auto hr = CoCreateInstance(CLSID_NetworkListManager, nullptr, CLSCTX_INPROC_SERVER,
|
||||
IID_INetworkListManager, &networkListManager);
|
||||
if (FAILED(hr)) {
|
||||
qCWarning(lcNetInfoNLM) << "Could not get a NetworkListManager instance:"
|
||||
<< errorStringFromHResult(hr);
|
||||
return;
|
||||
}
|
||||
|
||||
ComPtr<IConnectionPointContainer> connectionPointContainer;
|
||||
hr = networkListManager.As(&connectionPointContainer);
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = connectionPointContainer->FindConnectionPoint(IID_INetworkListManagerEvents,
|
||||
&connectionPoint);
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
qCWarning(lcNetInfoNLM) << "Failed to get connection point for network list manager events:"
|
||||
<< errorStringFromHResult(hr);
|
||||
}
|
||||
}
|
||||
|
||||
QNetworkListManagerEvents::~QNetworkListManagerEvents()
|
||||
{
|
||||
Q_ASSERT(ref == 0);
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE QNetworkListManagerEvents::QueryInterface(REFIID riid, void **ppvObject)
|
||||
{
|
||||
if (!ppvObject)
|
||||
return E_INVALIDARG;
|
||||
|
||||
return QueryInterfaceImpl<IUnknown>(this, riid, ppvObject)
|
||||
|| QueryInterfaceImpl<INetworkListManagerEvents>(this, riid, ppvObject)
|
||||
? S_OK
|
||||
: E_NOINTERFACE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
QNetworkListManagerEvents::ConnectivityChanged(NLM_CONNECTIVITY newConnectivity)
|
||||
{
|
||||
// This function is run on a different thread than 'monitor' is created on, so we need to run
|
||||
// it on that thread
|
||||
emit connectivityChanged(newConnectivity);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
bool QNetworkListManagerEvents::start()
|
||||
{
|
||||
if (!connectionPoint) {
|
||||
qCWarning(lcNetInfoNLM, "Initialization failed, can't start!");
|
||||
return false;
|
||||
}
|
||||
auto hr = connectionPoint->Advise(this, &cookie);
|
||||
if (FAILED(hr)) {
|
||||
qCWarning(lcNetInfoNLM) << "Failed to subscribe to network connectivity events:"
|
||||
<< errorStringFromHResult(hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update connectivity since it might have changed since this class was constructed
|
||||
NLM_CONNECTIVITY connectivity;
|
||||
hr = networkListManager->GetConnectivity(&connectivity);
|
||||
if (FAILED(hr))
|
||||
qCWarning(lcNetInfoNLM) << "Could not get connectivity:" << errorStringFromHResult(hr);
|
||||
else
|
||||
emit connectivityChanged(connectivity);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QNetworkListManagerEvents::stop()
|
||||
{
|
||||
Q_ASSERT(connectionPoint);
|
||||
auto hr = connectionPoint->Unadvise(cookie);
|
||||
if (FAILED(hr)) {
|
||||
qCWarning(lcNetInfoNLM) << "Failed to unsubscribe from network connectivity events:"
|
||||
<< errorStringFromHResult(hr);
|
||||
return false;
|
||||
}
|
||||
cookie = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QNetworkListManagerEvents::checkBehindCaptivePortal()
|
||||
{
|
||||
if (!networkListManager)
|
||||
return false;
|
||||
ComPtr<IEnumNetworks> networks;
|
||||
HRESULT hr =
|
||||
networkListManager->GetNetworks(NLM_ENUM_NETWORK_CONNECTED, networks.GetAddressOf());
|
||||
if (FAILED(hr) || networks == nullptr)
|
||||
return false;
|
||||
|
||||
// @note: This checks all connected networks, but that might not be necessary
|
||||
ComPtr<INetwork> network;
|
||||
hr = networks->Next(1, network.GetAddressOf(), nullptr);
|
||||
while (SUCCEEDED(hr) && network != nullptr) {
|
||||
ComPtr<IPropertyBag> propertyBag;
|
||||
hr = network.As(&propertyBag);
|
||||
if (SUCCEEDED(hr) && propertyBag != nullptr) {
|
||||
VARIANT variant;
|
||||
VariantInit(&variant);
|
||||
const auto scopedVariantClear = qScopeGuard([&variant]() { VariantClear(&variant); });
|
||||
|
||||
const wchar_t *versions[] = { NA_InternetConnectivityV6, NA_InternetConnectivityV4 };
|
||||
for (const auto version : versions) {
|
||||
hr = propertyBag->Read(version, &variant, nullptr);
|
||||
if (SUCCEEDED(hr)
|
||||
&& (V_UINT(&variant) & NLM_INTERNET_CONNECTIVITY_WEBHIJACK)
|
||||
== NLM_INTERNET_CONNECTIVITY_WEBHIJACK) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr = networks->Next(1, network.GetAddressOf(), nullptr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QNetworkListManagerNetworkInformationBackend::QNetworkListManagerNetworkInformationBackend()
|
||||
{
|
||||
auto hr = CoInitialize(nullptr);
|
||||
|
Loading…
Reference in New Issue
Block a user