From 5a15b1ab2629390ec15100c45704ef1bc46b52c1 Mon Sep 17 00:00:00 2001 From: Marcus Birkin Date: Sat, 25 May 2024 19:24:14 +0100 Subject: [PATCH] Gracefully handle missing Libpcap on Windows Issue a message to the user if WinPcap/Npcap is not found. Delay load Libpcap on Windows, so that if WinPcap/Npcap is not installed, the main application will still open. --- CMakeLists.txt | 11 +++------ src/pcap/pcapplayback.cpp | 52 +++++++++++++++++++++++++++++++++++++++ src/pcap/pcapplayback.h | 3 +++ src/ui/aboutdialog.cpp | 17 +++++++------ 4 files changed, 68 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 949e329a..10f261a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,14 +234,9 @@ target_link_libraries(sACNView PRIVATE ${SACNVIEW_QT_LIBRARIES}) # Link PCap/WinPCap libraries target_link_libraries(sACNView PRIVATE ${PCAP_LIBS}) - -if(WIN32) - # Copy WinPCap DLLs - foreach(DLLFILE IN LISTS PCAP_LIBS) - add_custom_command (TARGET sACNView POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - $ $) - endforeach() +if(MSVC) + target_link_libraries(sACNView PRIVATE delayimp) + target_link_options(sACNView PRIVATE "/DELAYLOAD:wpcap.dll") endif() # Blake2 diff --git a/src/pcap/pcapplayback.cpp b/src/pcap/pcapplayback.cpp index 9de16cb7..f2dd1e32 100644 --- a/src/pcap/pcapplayback.cpp +++ b/src/pcap/pcapplayback.cpp @@ -8,6 +8,11 @@ #include #include +#ifdef Q_OS_WIN +#include +#include +#endif + PcapPlayback::PcapPlayback(QWidget *parent) : QWidget(parent), ui(new Ui::PcapPlayback), @@ -22,6 +27,41 @@ PcapPlayback::~PcapPlayback() delete ui; } +bool PcapPlayback::foundLibPcap() +{ +#ifdef Q_OS_WIN + const auto checkDelayException = [](int exception_value) { + if (exception_value == VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND) + || exception_value == VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND)) { + return EXCEPTION_EXECUTE_HANDLER; + } + return EXCEPTION_CONTINUE_SEARCH; + }; + + __try { + HRESULT hr = __HrLoadAllImportsForDll("wpcap.dll"); + if (FAILED(hr)) { + return false; + } + } __except (checkDelayException(GetExceptionCode())) { + return false; + } +#endif + return true; +} + +std::string PcapPlayback::getLibPcapVersion() +{ + if (foundLibPcap()) { + const char *version = pcap_lib_version(); + return std::string(version); + } + else + { + return {}; + } +} + void PcapPlayback::openThread() { if (sender) { @@ -59,6 +99,18 @@ void PcapPlayback::playbackThreadClosed() void PcapPlayback::on_btnOpen_clicked() { + if (!foundLibPcap()) { + QMessageBox::critical( + this, + tr("Pcap not found"), +#ifdef Q_OS_WIN + tr("Pcap not found, please install Wireshark")); +#else + tr("Libpcap not found, please install")); +#endif + return; + } + /* Select file to open */ QString fileName = QFileDialog::getOpenFileName(this, tr("Open Capture"), diff --git a/src/pcap/pcapplayback.h b/src/pcap/pcapplayback.h index ec0fa10a..0fa3758a 100644 --- a/src/pcap/pcapplayback.h +++ b/src/pcap/pcapplayback.h @@ -16,6 +16,9 @@ class PcapPlayback : public QWidget explicit PcapPlayback(QWidget *parent = 0); ~PcapPlayback(); + static bool foundLibPcap(); + static std::string getLibPcapVersion(); + private slots: void on_btnOpen_clicked(); void on_btnStartPause_clicked(); diff --git a/src/ui/aboutdialog.cpp b/src/ui/aboutdialog.cpp index 4fdd69a7..1f3df257 100644 --- a/src/ui/aboutdialog.cpp +++ b/src/ui/aboutdialog.cpp @@ -16,7 +16,7 @@ #include "aboutdialog.h" #include "ui_aboutdialog.h" #include "consts.h" -#include +#include "pcap/pcapplayback.h" #include "translations/translations.h" #include @@ -73,12 +73,15 @@ aboutDialog::aboutDialog(QWidget* parent) : } { - const char* libpcap = pcap_lib_version(); - ui->lblLibs->setText( - tr("

This application uses libpcap
" - "%1
" - "Licensed under the The 3-Clause BSD License

") - .arg(QString::fromUtf8(libpcap))); + ui->lblLibs->clear(); + if (PcapPlayback::foundLibPcap()) + { + ui->lblLibs->setText( + tr("

This application uses libpcap
" + "%1
" + "Licensed under the The 3-Clause BSD License

") + .arg(QString::fromStdString(PcapPlayback::getLibPcapVersion()))); + } ui->lblLibs->setText(ui->lblLibs->text() + tr("

This application uses BLAKE2
" "Licensed under the Creative Commons Zero v1.0 Universal

"));