Skip to content
Snippets Groups Projects
  • Andreas Traczyk's avatar
    3b6bbe77
    misc: implement update system · 3b6bbe77
    Andreas Traczyk authored
    - re-introduce a genericized NetworkManager
    - isolate update logic into a qml accessible class derived from
      NetworkManager
    - fix QtWebEngineProcess missing when re-installing over existing
      version
    - provide a command line option to override the base url
      for testing local and remote updates
    - clean-up manual update-check UI
    
    Gitlab: #101
    Change-Id: I9c8d2badae59ec31cab12d38b8470edf2bcad401
    3b6bbe77
    History
    misc: implement update system
    Andreas Traczyk authored
    - re-introduce a genericized NetworkManager
    - isolate update logic into a qml accessible class derived from
      NetworkManager
    - fix QtWebEngineProcess missing when re-installing over existing
      version
    - provide a command line option to override the base url
      for testing local and remote updates
    - clean-up manual update-check UI
    
    Gitlab: #101
    Change-Id: I9c8d2badae59ec31cab12d38b8470edf2bcad401
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
connectivitymonitor.cpp 4.28 KiB
/*
 * 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