/* * Copyright (C) 2019-2020 by Savoir-faire Linux * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "connectivitymonitor.h" #ifdef Q_OS_WIN #include <QDebug> #include <atlbase.h> #include <netlistmgr.h> class NetworkEventHandler : public INetworkListManagerEvents { public: NetworkEventHandler() : m_lRefCnt(1) {}; virtual ~NetworkEventHandler() {}; HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) { HRESULT hr = S_OK; if (IsEqualIID(riid, IID_IUnknown)) { *ppvObject = (IUnknown*) this; } else if (IsEqualIID(riid, IID_INetworkListManagerEvents)) { *ppvObject = (INetworkListManagerEvents*) this; } else { hr = E_NOINTERFACE; } return hr; }; ULONG STDMETHODCALLTYPE AddRef() { return (ULONG) InterlockedIncrement(&m_lRefCnt); }; ULONG STDMETHODCALLTYPE Release() { LONG res = InterlockedDecrement(&m_lRefCnt); if (res == 0) { delete this; } return (ULONG) res; }; virtual HRESULT STDMETHODCALLTYPE ConnectivityChanged(NLM_CONNECTIVITY newConnectivity) { qDebug() << "connectivity changed: " << newConnectivity; if (connectivityChangedCb_) { connectivityChangedCb_(); } return S_OK; }; void setOnConnectivityChangedCallBack(std::function<void()>&& cb) { connectivityChangedCb_ = cb; }; private: LONG m_lRefCnt; std::function<void()> connectivityChangedCb_; }; ConnectivityMonitor::ConnectivityMonitor(QObject* parent) : QObject(parent) { CoInitialize(NULL); IUnknown* pUnknown = NULL; HRESULT hr = CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL, IID_IUnknown, (void**) &pUnknown); if (FAILED(hr)) { return; } pNetworkListManager_ = NULL; hr = pUnknown->QueryInterface(IID_INetworkListManager, (void**) &pNetworkListManager_); if (FAILED(hr)) { destroy(); pUnknown->Release(); return; } pCPContainer_ = NULL; hr = pNetworkListManager_->QueryInterface(IID_IConnectionPointContainer, (void**) &pCPContainer_); if (FAILED(hr)) { destroy(); pUnknown->Release(); return; } pConnectPoint_ = NULL; hr = pCPContainer_->FindConnectionPoint(IID_INetworkListManagerEvents, &pConnectPoint_); if (SUCCEEDED(hr)) { cookie_ = NULL; netEventHandler_ = new NetworkEventHandler; netEventHandler_->setOnConnectivityChangedCallBack([this] { emit connectivityChanged(); }); hr = pConnectPoint_->Advise((IUnknown*) netEventHandler_, &cookie_); } else { destroy(); } pUnknown->Release(); } bool ConnectivityMonitor::isOnline() { if (!pNetworkListManager_) { return false; } VARIANT_BOOL IsConnect = VARIANT_FALSE; HRESULT hr = pNetworkListManager_->get_IsConnectedToInternet(&IsConnect); if (SUCCEEDED(hr)) { return IsConnect == VARIANT_TRUE; } return false; } void ConnectivityMonitor::destroy() { if (pConnectPoint_) { pConnectPoint_->Unadvise(cookie_); pConnectPoint_->Release(); } if (pCPContainer_) { pCPContainer_->Release(); } if (pNetworkListManager_) { pNetworkListManager_->Release(); pNetworkListManager_ = NULL; } } ConnectivityMonitor::~ConnectivityMonitor() { destroy(); CoUninitialize(); } #endif // Q_OS_WIN