From 1d3cac54ab06c09d6c76dcbcb4f88418a72cca47 Mon Sep 17 00:00:00 2001 From: dijunkun Date: Fri, 20 Mar 2026 01:36:36 +0800 Subject: [PATCH] [feat] load wgc from wgc_plugin.dll at runtime and drop direct'windowsapp' linking, refs #74 --- src/common/platform.cpp | 2 +- src/log/rd_log.cpp | 2 +- .../windows/screen_capturer_win.cpp | 109 +++++++++++++++++- .../windows/screen_capturer_win.h | 1 + src/screen_capturer/windows/wgc_plugin_api.h | 29 +++++ .../windows/wgc_plugin_entry.cpp | 13 +++ .../windows/wgc_session_impl.cpp | 11 +- submodules/minirtc | 2 +- xmake.lua | 20 +++- 9 files changed, 172 insertions(+), 17 deletions(-) create mode 100644 src/screen_capturer/windows/wgc_plugin_api.h create mode 100644 src/screen_capturer/windows/wgc_plugin_entry.cpp diff --git a/src/common/platform.cpp b/src/common/platform.cpp index 17bec97..26cd875 100644 --- a/src/common/platform.cpp +++ b/src/common/platform.cpp @@ -108,7 +108,7 @@ std::string GetHostName() { #ifdef _WIN32 WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { - std::cerr << "WSAStartup failed." << std::endl; + LOG_ERROR("WSAStartup failed"); return ""; } if (gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR) { diff --git a/src/log/rd_log.cpp b/src/log/rd_log.cpp index 4c19390..5d8a65e 100644 --- a/src/log/rd_log.cpp +++ b/src/log/rd_log.cpp @@ -62,4 +62,4 @@ std::shared_ptr get_logger() { return g_logger; } -} // namespace crossdesk \ No newline at end of file +} // namespace crossdesk diff --git a/src/screen_capturer/windows/screen_capturer_win.cpp b/src/screen_capturer/windows/screen_capturer_win.cpp index b59db06..9235bb2 100644 --- a/src/screen_capturer/windows/screen_capturer_win.cpp +++ b/src/screen_capturer/windows/screen_capturer_win.cpp @@ -1,17 +1,108 @@ #include "screen_capturer_win.h" +#include + #include +#include #include #include +#include #include #include "rd_log.h" #include "screen_capturer_dxgi.h" #include "screen_capturer_gdi.h" -#include "screen_capturer_wgc.h" +#include "wgc_plugin_api.h" namespace crossdesk { +namespace { + +class WgcPluginCapturer final : public ScreenCapturer { + public: + using CreateFn = ScreenCapturer* (*)(); + using DestroyFn = void (*)(ScreenCapturer*); + + static std::unique_ptr Create() { + std::filesystem::path plugin_path; + wchar_t module_path[MAX_PATH] = {0}; + const DWORD len = GetModuleFileNameW(nullptr, module_path, MAX_PATH); + if (len == 0 || len >= MAX_PATH) { + return nullptr; + } + plugin_path = + std::filesystem::path(module_path).parent_path() / L"wgc_plugin.dll"; + + HMODULE module = LoadLibraryW(plugin_path.c_str()); + if (!module) { + return nullptr; + } + + auto create_fn = reinterpret_cast( + GetProcAddress(module, "CrossDeskCreateWgcCapturer")); + auto destroy_fn = reinterpret_cast( + GetProcAddress(module, "CrossDeskDestroyWgcCapturer")); + if (!create_fn || !destroy_fn) { + FreeLibrary(module); + return nullptr; + } + + ScreenCapturer* impl = create_fn(); + if (!impl) { + FreeLibrary(module); + return nullptr; + } + + return std::unique_ptr( + new WgcPluginCapturer(module, impl, destroy_fn)); + } + + ~WgcPluginCapturer() override { + if (impl_) { + destroy_fn_(impl_); + impl_ = nullptr; + } + if (module_) { + FreeLibrary(module_); + module_ = nullptr; + } + } + + int Init(const int fps, cb_desktop_data cb) override { + return impl_ ? impl_->Init(fps, std::move(cb)) : -1; + } + int Destroy() override { return impl_ ? impl_->Destroy() : 0; } + int Start(bool show_cursor) override { + return impl_ ? impl_->Start(show_cursor) : -1; + } + int Stop() override { return impl_ ? impl_->Stop() : 0; } + int Pause(int monitor_index) override { + return impl_ ? impl_->Pause(monitor_index) : -1; + } + int Resume(int monitor_index) override { + return impl_ ? impl_->Resume(monitor_index) : -1; + } + std::vector GetDisplayInfoList() override { + return impl_ ? impl_->GetDisplayInfoList() : std::vector{}; + } + int SwitchTo(int monitor_index) override { + return impl_ ? impl_->SwitchTo(monitor_index) : -1; + } + int ResetToInitialMonitor() override { + return impl_ ? impl_->ResetToInitialMonitor() : -1; + } + + private: + WgcPluginCapturer(HMODULE module, ScreenCapturer* impl, DestroyFn destroy_fn) + : module_(module), impl_(impl), destroy_fn_(destroy_fn) {} + + HMODULE module_ = nullptr; + ScreenCapturer* impl_ = nullptr; + DestroyFn destroy_fn_ = nullptr; +}; + +} // namespace + ScreenCapturerWin::ScreenCapturerWin() {} ScreenCapturerWin::~ScreenCapturerWin() { Destroy(); } @@ -40,18 +131,21 @@ int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) { int ret = -1; - impl_ = std::make_unique(); - ret = impl_->Init(fps_, cb_); + impl_ = WgcPluginCapturer::Create(); + impl_is_wgc_plugin_ = (impl_ != nullptr); + ret = impl_ ? impl_->Init(fps_, cb_) : -1; if (ret == 0) { - LOG_INFO("Windows capturer: using WGC"); + LOG_INFO("Windows capturer: using WGC plugin"); BuildCanonicalFromImpl(); return 0; } - LOG_WARN("Windows capturer: WGC init failed (ret={}), try DXGI", ret); + LOG_WARN("Windows capturer: WGC plugin init failed (ret={}), try DXGI", ret); impl_.reset(); + impl_is_wgc_plugin_ = false; impl_ = std::make_unique(); + impl_is_wgc_plugin_ = false; ret = impl_->Init(fps_, cb_); if (ret == 0) { LOG_INFO("Windows capturer: using DXGI Desktop Duplication"); @@ -63,6 +157,7 @@ int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) { impl_.reset(); impl_ = std::make_unique(); + impl_is_wgc_plugin_ = false; ret = impl_->Init(fps_, cb_); if (ret == 0) { LOG_INFO("Windows capturer: using GDI BitBlt"); @@ -79,6 +174,7 @@ int ScreenCapturerWin::Destroy() { if (impl_) { impl_->Destroy(); impl_.reset(); + impl_is_wgc_plugin_ = false; } { std::lock_guard lock(alias_mutex_); @@ -102,13 +198,14 @@ int ScreenCapturerWin::Start(bool show_cursor) { int s = cand->Start(show_cursor); if (s == 0) { impl_ = std::move(cand); + impl_is_wgc_plugin_ = false; RebuildAliasesFromImpl(); return true; } return false; }; - if (dynamic_cast(impl_.get())) { + if (impl_is_wgc_plugin_) { if (try_init_start(std::make_unique())) { LOG_INFO("Windows capturer: fallback to DXGI"); return 0; diff --git a/src/screen_capturer/windows/screen_capturer_win.h b/src/screen_capturer/windows/screen_capturer_win.h index 4c9f10c..4605e93 100644 --- a/src/screen_capturer/windows/screen_capturer_win.h +++ b/src/screen_capturer/windows/screen_capturer_win.h @@ -38,6 +38,7 @@ class ScreenCapturerWin : public ScreenCapturer { private: std::unique_ptr impl_; + bool impl_is_wgc_plugin_ = false; int fps_ = 60; cb_desktop_data cb_; cb_desktop_data cb_orig_; diff --git a/src/screen_capturer/windows/wgc_plugin_api.h b/src/screen_capturer/windows/wgc_plugin_api.h new file mode 100644 index 0000000..4b6714c --- /dev/null +++ b/src/screen_capturer/windows/wgc_plugin_api.h @@ -0,0 +1,29 @@ +/* + * @Author: DI JUNKUN + * @Date: 2026-03-20 + * Copyright (c) 2026 by DI JUNKUN, All Rights Reserved. + */ + +#ifndef _WGC_PLUGIN_API_H_ +#define _WGC_PLUGIN_API_H_ + +#include "screen_capturer.h" + +namespace crossdesk { +class ScreenCapturer; +} + +#if defined(_WIN32) && defined(CROSSDESK_WGC_PLUGIN_BUILD) +#define CROSSDESK_WGC_PLUGIN_API __declspec(dllexport) +#else +#define CROSSDESK_WGC_PLUGIN_API +#endif + +extern "C" { +CROSSDESK_WGC_PLUGIN_API crossdesk::ScreenCapturer* +CrossDeskCreateWgcCapturer(); +CROSSDESK_WGC_PLUGIN_API void CrossDeskDestroyWgcCapturer( + crossdesk::ScreenCapturer* capturer); +} + +#endif \ No newline at end of file diff --git a/src/screen_capturer/windows/wgc_plugin_entry.cpp b/src/screen_capturer/windows/wgc_plugin_entry.cpp new file mode 100644 index 0000000..836922a --- /dev/null +++ b/src/screen_capturer/windows/wgc_plugin_entry.cpp @@ -0,0 +1,13 @@ +#include "screen_capturer_wgc.h" +#include "wgc_plugin_api.h" + +extern "C" { + +crossdesk::ScreenCapturer* CrossDeskCreateWgcCapturer() { + return new crossdesk::ScreenCapturerWgc(); +} + +void CrossDeskDestroyWgcCapturer(crossdesk::ScreenCapturer* capturer) { + delete capturer; +} +} diff --git a/src/screen_capturer/windows/wgc_session_impl.cpp b/src/screen_capturer/windows/wgc_session_impl.cpp index 4b5cbd2..5b68bcc 100644 --- a/src/screen_capturer/windows/wgc_session_impl.cpp +++ b/src/screen_capturer/windows/wgc_session_impl.cpp @@ -4,15 +4,14 @@ #include #include -#include #include #include "rd_log.h" -#define CHECK_INIT \ - if (!is_initialized_) { \ - std::cout << "AE_NEED_INIT" << std::endl; \ - return 4; \ +#define CHECK_INIT \ + if (!is_initialized_) { \ + LOG_ERROR("AE_NEED_INIT"); \ + return 4; \ } #define CHECK_CLOSED \ @@ -324,7 +323,7 @@ int WgcSessionImpl::Initialize() { if (is_initialized_) return 0; if (!(d3d11_direct_device_ = CreateD3D11Device())) { - std::cout << "AE_D3D_CREATE_DEVICE_FAILED" << std::endl; + LOG_ERROR("AE_D3D_CREATE_DEVICE_FAILED"); return 1; } diff --git a/submodules/minirtc b/submodules/minirtc index 03a6449..6023fed 160000 --- a/submodules/minirtc +++ b/submodules/minirtc @@ -1 +1 @@ -Subproject commit 03a6449a11a3980f3fb599b21376cc7da157ec80 +Subproject commit 6023fedf06425267ef1d90effb96f6f1fb83aa74 diff --git a/xmake.lua b/xmake.lua index bb69651..60a03b9 100644 --- a/xmake.lua +++ b/xmake.lua @@ -37,7 +37,7 @@ add_requires("tinyfiledialogs 3.15.1") if is_os("windows") then add_requires("libyuv", "miniaudio 0.11.21") - add_links("Shell32", "windowsapp", "dwmapi", "User32", "kernel32", + add_links("Shell32", "dwmapi", "User32", "kernel32", "SDL3-static", "gdi32", "winmm", "setupapi", "version", "Imm32", "iphlpapi", "d3d11", "dxgi") add_cxflags("/WX") @@ -88,7 +88,9 @@ target("screen_capturer") add_includedirs("src/screen_capturer", {public = true}) if is_os("windows") then add_packages("libyuv") - add_files("src/screen_capturer/windows/*.cpp") + add_files("src/screen_capturer/windows/screen_capturer_dxgi.cpp", + "src/screen_capturer/windows/screen_capturer_gdi.cpp", + "src/screen_capturer/windows/screen_capturer_win.cpp") add_includedirs("src/screen_capturer/windows", {public = true}) elseif is_os("macosx") then add_files("src/screen_capturer/macosx/*.cpp", @@ -199,6 +201,20 @@ target("gui") add_files("src/gui/windows/*.mm") end +if is_os("windows") then +target("wgc_plugin") + set_kind("shared") + add_packages("libyuv") + add_deps("rd_log") + add_defines("CROSSDESK_WGC_PLUGIN_BUILD=1") + add_links("windowsapp") + add_files("src/screen_capturer/windows/screen_capturer_wgc.cpp", + "src/screen_capturer/windows/wgc_session_impl.cpp", + "src/screen_capturer/windows/wgc_plugin_entry.cpp") + add_includedirs("src/common", "src/screen_capturer", + "src/screen_capturer/windows") +end + target("crossdesk") set_kind("binary") add_deps("rd_log", "common", "gui")