[fix] restore shared capture on Windows secure desktop

This commit is contained in:
dijunkun
2026-09-16 15:31:27 +08:00
parent c4aca303c8
commit ad62e60b9a
2 changed files with 34 additions and 10 deletions
@@ -1138,6 +1138,18 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() {
max_status_ms = 0;
};
std::vector<uint8_t> secure_frame;
ULONGLONG last_shared_error_tick = 0;
auto report_shared_error = [&](const char* operation,
const std::string& error) {
const ULONGLONG now = GetTickCount64();
if (last_shared_error_tick == 0 || now - last_shared_error_tick >= 5000) {
LOG_WARN(
"Windows capturer secure shared capture {} failed; using pipe "
"fallback, stage='{}', session_id={}, error={}",
operation, status.interactive_stage, status.active_session_id, error);
last_shared_error_tick = now;
}
};
while (running_.load(std::memory_order_relaxed)) {
// Privacy covers belong to the ordinary desktop. Drop privacy on a
@@ -1285,6 +1297,7 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() {
status.interactive_stage, status.interactive_desktop, show_cursor,
shared_fps, &error_message);
if (!shared_ready) {
report_shared_error("start", error_message);
frame_schedule.OnStartFailure(GetTickCount64());
} else if (!was_started) {
frame_schedule.Reset(GetTickCount64());
@@ -1304,6 +1317,7 @@ void ScreenCapturerWin::SecureDesktopCaptureLoop() {
IsPendingSecureDesktopFrame(error_message);
if (frame_pending) ++shared_waits;
if (shared_ready && !frame_delivered && !frame_pending) {
report_shared_error("read", error_message);
StopSecureDesktopSharedCapture(secure_shared_session_id_);
frame_schedule.OnStartFailure(GetTickCount64());
}
@@ -98,18 +98,18 @@ struct SecureSharedCaptureState {
uint32_t sequence = 0;
};
struct PipeSecurityAttributes {
PipeSecurityAttributes() = default;
~PipeSecurityAttributes() {
struct IpcSecurityAttributes {
IpcSecurityAttributes() = default;
~IpcSecurityAttributes() {
if (security_descriptor_ != nullptr) {
LocalFree(security_descriptor_);
}
}
bool Initialize() {
constexpr wchar_t kPipeSddl[] = L"D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGW;;;AU)";
bool Initialize(const wchar_t* sddl =
L"D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGW;;;AU)") {
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
kPipeSddl, SDDL_REVISION_1, &security_descriptor_, nullptr)) {
sddl, SDDL_REVISION_1, &security_descriptor_, nullptr)) {
return false;
}
@@ -453,7 +453,7 @@ std::string BuildHelperStatusResponse(HelperState* helper_state) {
void HelperIpcServerLoop(HANDLE stop_event, DWORD session_id,
HelperState* helper_state) {
PipeSecurityAttributes security_attributes;
IpcSecurityAttributes security_attributes;
SECURITY_ATTRIBUTES* pipe_attributes = nullptr;
if (security_attributes.Initialize()) {
pipe_attributes = security_attributes.get();
@@ -1471,12 +1471,21 @@ std::vector<uint8_t> StartSecureDesktopSharedCapture(
return BuildTextResponseBytes(BuildErrorJson("invalid_capture_size"));
}
PipeSecurityAttributes security_attributes;
IpcSecurityAttributes security_attributes;
SECURITY_ATTRIBUTES* attributes = nullptr;
if (security_attributes.Initialize()) {
attributes = security_attributes.get();
}
// Event GENERIC_READ/GENERIC_WRITE omit SYNCHRONIZE. The GUI only needs
// to wait for frames; the SYSTEM helper retains permission to signal them.
IpcSecurityAttributes event_security_attributes;
if (!event_security_attributes.Initialize(
L"D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;0x00100000;;;AU)")) {
return BuildTextResponseBytes(
BuildErrorJson("create_frame_event_security_failed", GetLastError()));
}
const std::wstring mapping_name =
crossdesk::GetCrossDeskSecureDesktopFrameMappingName(
capture_state->session_id);
@@ -1503,7 +1512,8 @@ std::vector<uint8_t> StartSecureDesktopSharedCapture(
}
HANDLE frame_ready_event =
CreateEventW(attributes, FALSE, FALSE, event_name.c_str());
CreateEventW(event_security_attributes.get(), FALSE, FALSE,
event_name.c_str());
if (frame_ready_event == nullptr) {
const DWORD error = GetLastError();
UnmapViewOfFile(frame_view);
@@ -1665,7 +1675,7 @@ void SecureInputHelperIpcServerLoop(HANDLE stop_event, DWORD session_id) {
auto capture_state = std::make_shared<SecureSharedCaptureState>();
capture_state->session_id = session_id;
PipeSecurityAttributes security_attributes;
IpcSecurityAttributes security_attributes;
SECURITY_ATTRIBUTES* pipe_attributes = nullptr;
if (security_attributes.Initialize()) {
pipe_attributes = security_attributes.get();