[feat] load wgc from wgc_plugin.dll at runtime and drop direct'windowsapp' linking, refs #74

This commit is contained in:
dijunkun
2026-03-20 01:36:36 +08:00
parent 2f26334775
commit 1d3cac54ab
9 changed files with 172 additions and 17 deletions

View File

@@ -108,7 +108,7 @@ std::string GetHostName() {
#ifdef _WIN32 #ifdef _WIN32
WSADATA wsaData; WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed." << std::endl; LOG_ERROR("WSAStartup failed");
return ""; return "";
} }
if (gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR) { if (gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR) {

View File

@@ -62,4 +62,4 @@ std::shared_ptr<spdlog::logger> get_logger() {
return g_logger; return g_logger;
} }
} // namespace crossdesk } // namespace crossdesk

View File

@@ -1,17 +1,108 @@
#include "screen_capturer_win.h" #include "screen_capturer_win.h"
#include <Windows.h>
#include <cmath> #include <cmath>
#include <filesystem>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include "rd_log.h" #include "rd_log.h"
#include "screen_capturer_dxgi.h" #include "screen_capturer_dxgi.h"
#include "screen_capturer_gdi.h" #include "screen_capturer_gdi.h"
#include "screen_capturer_wgc.h" #include "wgc_plugin_api.h"
namespace crossdesk { namespace crossdesk {
namespace {
class WgcPluginCapturer final : public ScreenCapturer {
public:
using CreateFn = ScreenCapturer* (*)();
using DestroyFn = void (*)(ScreenCapturer*);
static std::unique_ptr<ScreenCapturer> 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<CreateFn>(
GetProcAddress(module, "CrossDeskCreateWgcCapturer"));
auto destroy_fn = reinterpret_cast<DestroyFn>(
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<ScreenCapturer>(
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<DisplayInfo> GetDisplayInfoList() override {
return impl_ ? impl_->GetDisplayInfoList() : std::vector<DisplayInfo>{};
}
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() {}
ScreenCapturerWin::~ScreenCapturerWin() { Destroy(); } ScreenCapturerWin::~ScreenCapturerWin() { Destroy(); }
@@ -40,18 +131,21 @@ int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) {
int ret = -1; int ret = -1;
impl_ = std::make_unique<ScreenCapturerWgc>(); impl_ = WgcPluginCapturer::Create();
ret = impl_->Init(fps_, cb_); impl_is_wgc_plugin_ = (impl_ != nullptr);
ret = impl_ ? impl_->Init(fps_, cb_) : -1;
if (ret == 0) { if (ret == 0) {
LOG_INFO("Windows capturer: using WGC"); LOG_INFO("Windows capturer: using WGC plugin");
BuildCanonicalFromImpl(); BuildCanonicalFromImpl();
return 0; 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_.reset();
impl_is_wgc_plugin_ = false;
impl_ = std::make_unique<ScreenCapturerDxgi>(); impl_ = std::make_unique<ScreenCapturerDxgi>();
impl_is_wgc_plugin_ = false;
ret = impl_->Init(fps_, cb_); ret = impl_->Init(fps_, cb_);
if (ret == 0) { if (ret == 0) {
LOG_INFO("Windows capturer: using DXGI Desktop Duplication"); 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_.reset();
impl_ = std::make_unique<ScreenCapturerGdi>(); impl_ = std::make_unique<ScreenCapturerGdi>();
impl_is_wgc_plugin_ = false;
ret = impl_->Init(fps_, cb_); ret = impl_->Init(fps_, cb_);
if (ret == 0) { if (ret == 0) {
LOG_INFO("Windows capturer: using GDI BitBlt"); LOG_INFO("Windows capturer: using GDI BitBlt");
@@ -79,6 +174,7 @@ int ScreenCapturerWin::Destroy() {
if (impl_) { if (impl_) {
impl_->Destroy(); impl_->Destroy();
impl_.reset(); impl_.reset();
impl_is_wgc_plugin_ = false;
} }
{ {
std::lock_guard<std::mutex> lock(alias_mutex_); std::lock_guard<std::mutex> lock(alias_mutex_);
@@ -102,13 +198,14 @@ int ScreenCapturerWin::Start(bool show_cursor) {
int s = cand->Start(show_cursor); int s = cand->Start(show_cursor);
if (s == 0) { if (s == 0) {
impl_ = std::move(cand); impl_ = std::move(cand);
impl_is_wgc_plugin_ = false;
RebuildAliasesFromImpl(); RebuildAliasesFromImpl();
return true; return true;
} }
return false; return false;
}; };
if (dynamic_cast<ScreenCapturerWgc*>(impl_.get())) { if (impl_is_wgc_plugin_) {
if (try_init_start(std::make_unique<ScreenCapturerDxgi>())) { if (try_init_start(std::make_unique<ScreenCapturerDxgi>())) {
LOG_INFO("Windows capturer: fallback to DXGI"); LOG_INFO("Windows capturer: fallback to DXGI");
return 0; return 0;

View File

@@ -38,6 +38,7 @@ class ScreenCapturerWin : public ScreenCapturer {
private: private:
std::unique_ptr<ScreenCapturer> impl_; std::unique_ptr<ScreenCapturer> impl_;
bool impl_is_wgc_plugin_ = false;
int fps_ = 60; int fps_ = 60;
cb_desktop_data cb_; cb_desktop_data cb_;
cb_desktop_data cb_orig_; cb_desktop_data cb_orig_;

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -4,15 +4,14 @@
#include <atomic> #include <atomic>
#include <functional> #include <functional>
#include <iostream>
#include <memory> #include <memory>
#include "rd_log.h" #include "rd_log.h"
#define CHECK_INIT \ #define CHECK_INIT \
if (!is_initialized_) { \ if (!is_initialized_) { \
std::cout << "AE_NEED_INIT" << std::endl; \ LOG_ERROR("AE_NEED_INIT"); \
return 4; \ return 4; \
} }
#define CHECK_CLOSED \ #define CHECK_CLOSED \
@@ -324,7 +323,7 @@ int WgcSessionImpl::Initialize() {
if (is_initialized_) return 0; if (is_initialized_) return 0;
if (!(d3d11_direct_device_ = CreateD3D11Device())) { if (!(d3d11_direct_device_ = CreateD3D11Device())) {
std::cout << "AE_D3D_CREATE_DEVICE_FAILED" << std::endl; LOG_ERROR("AE_D3D_CREATE_DEVICE_FAILED");
return 1; return 1;
} }

View File

@@ -37,7 +37,7 @@ add_requires("tinyfiledialogs 3.15.1")
if is_os("windows") then if is_os("windows") then
add_requires("libyuv", "miniaudio 0.11.21") 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", "SDL3-static", "gdi32", "winmm", "setupapi", "version",
"Imm32", "iphlpapi", "d3d11", "dxgi") "Imm32", "iphlpapi", "d3d11", "dxgi")
add_cxflags("/WX") add_cxflags("/WX")
@@ -88,7 +88,9 @@ target("screen_capturer")
add_includedirs("src/screen_capturer", {public = true}) add_includedirs("src/screen_capturer", {public = true})
if is_os("windows") then if is_os("windows") then
add_packages("libyuv") 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}) add_includedirs("src/screen_capturer/windows", {public = true})
elseif is_os("macosx") then elseif is_os("macosx") then
add_files("src/screen_capturer/macosx/*.cpp", add_files("src/screen_capturer/macosx/*.cpp",
@@ -199,6 +201,20 @@ target("gui")
add_files("src/gui/windows/*.mm") add_files("src/gui/windows/*.mm")
end 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") target("crossdesk")
set_kind("binary") set_kind("binary")
add_deps("rd_log", "common", "gui") add_deps("rd_log", "common", "gui")