mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-22 12:33:05 +08:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
621f2ff205 | ||
|
|
5ac6e153c8 | ||
|
|
dd5c572852 |
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity version="1.0.0.0" name="CrossDesk.SessionHelper" type="win32" />
|
||||
<description>CrossDesk Session Helper</description>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
</assembly>
|
||||
@@ -4,13 +4,10 @@ IDI_ICON1 ICON "crossdesk.ico"
|
||||
#define CREATEPROCESS_MANIFEST_RESOURCE_ID 1
|
||||
#define RT_MANIFEST 24
|
||||
|
||||
#ifdef CROSSDESK_PORTABLE
|
||||
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "crossdesk_portable.manifest"
|
||||
#elif defined(CROSSDESK_DEBUG)
|
||||
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "crossdesk_debug.manifest"
|
||||
#else
|
||||
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "crossdesk.manifest"
|
||||
#endif
|
||||
// The service supplies either the user's token (desktop observer) or a SYSTEM
|
||||
// token (secure capture/input). Requiring elevation here prevents the observer
|
||||
// from starting with CreateProcessAsUserW in installed release builds (740).
|
||||
CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "crossdesk_session_helper.manifest"
|
||||
|
||||
#define CROSSDESK_FILE_DESCRIPTION "CrossDesk Session Helper"
|
||||
#define CROSSDESK_ORIGINAL_FILENAME "crossdesk_session_helper.exe"
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "platform/windows/gui/slint_backend.h"
|
||||
#include "service_host.h"
|
||||
#include "service_lifetime.h"
|
||||
#include "shutdown_order.h"
|
||||
#include "unattended_config.h"
|
||||
#endif
|
||||
|
||||
@@ -406,6 +407,16 @@ static int RunApplication(
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef _WIN32
|
||||
// Apply in every process, including the daemon and --child. Windows does
|
||||
// not inherit shutdown priority from a parent process.
|
||||
const DWORD shutdown_error = crossdesk::ConfigureWindowsShutdownOrder(
|
||||
crossdesk::WindowsShutdownRole::host);
|
||||
if (shutdown_error != ERROR_SUCCESS) {
|
||||
std::cerr << "Could not configure Windows host shutdown order, error="
|
||||
<< shutdown_error << '\n';
|
||||
}
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
// Run before GUI, configuration, logging or display initialization.
|
||||
if (argc == 2 &&
|
||||
|
||||
@@ -426,9 +426,8 @@ ConfigCenter::VIDEO_ENCODE_FORMAT ConfigCenter::GetVideoEncodeFormat() const {
|
||||
}
|
||||
|
||||
bool ConfigCenter::IsHardwareVideoCodecAvailable() {
|
||||
#if (((defined(_WIN32) || defined(__linux__)) && !defined(__aarch64__) && \
|
||||
!defined(__arm__) && USE_CUDA) || \
|
||||
defined(__APPLE__))
|
||||
#if defined(_WIN32) || defined(__APPLE__) || \
|
||||
(defined(__linux__) && !defined(__aarch64__) && !defined(__arm__) && USE_CUDA)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include "platform/windows/gui/slint_backend.h"
|
||||
#include "platform/windows/gui/shutdown_session_guard.h"
|
||||
#include "platform/windows/gui/tray/win_tray.h"
|
||||
#include "platform/windows/gui/window_icons.h"
|
||||
#elif defined(__APPLE__)
|
||||
@@ -923,6 +924,10 @@ void DragWindow(WindowHandle& component, int phase, float mouse_x,
|
||||
} // namespace
|
||||
|
||||
struct GuiApplication::SlintUi {
|
||||
#if _WIN32
|
||||
std::unique_ptr<ShutdownSessionGuard> shutdown_guard;
|
||||
std::wstring_view shutdown_reason;
|
||||
#endif
|
||||
gallery::Workspace gallery;
|
||||
std::filesystem::path gallery_path;
|
||||
std::vector<std::string> gallery_ids;
|
||||
@@ -1284,6 +1289,10 @@ void GuiApplication::InitializeUi() {
|
||||
slint::set_xdg_app_id("crossdesk");
|
||||
#endif
|
||||
ui_ = std::make_unique<SlintUi>();
|
||||
#if _WIN32
|
||||
ui_->shutdown_guard =
|
||||
std::make_unique<ShutdownSessionGuard>(windows_rdp_handoff_connected_);
|
||||
#endif
|
||||
ui_->sponsorship_prompt_pending =
|
||||
config_center_->GetSponsorshipPromptDismissedVersion() != CROSSDESK_VERSION;
|
||||
ui_->video_presenter =
|
||||
@@ -2258,6 +2267,11 @@ void GuiApplication::Tick() {
|
||||
slint::quit_event_loop();
|
||||
return;
|
||||
}
|
||||
#if _WIN32
|
||||
if (ui_->shutdown_guard) {
|
||||
ui_->shutdown_guard->Update(ui_->shutdown_reason);
|
||||
}
|
||||
#endif
|
||||
PollUpdateCheck();
|
||||
HandleSessionCleanup();
|
||||
HandlePasswordChangeResult();
|
||||
@@ -2815,6 +2829,15 @@ void GuiApplication::UpdateLocalization() {
|
||||
if (!ui_ || ui_->localized_language == language) {
|
||||
return;
|
||||
}
|
||||
#if _WIN32
|
||||
// All views refer to static literals; selecting the text needs no allocation
|
||||
// and only runs when the language changes. Tick still checks connection state.
|
||||
ui_->shutdown_reason = language == 0
|
||||
? L"远程控制连接中,保留连接以确认或取消关机。"
|
||||
: language == 2
|
||||
? L"Удалённый сеанс активен. Соединение сохранено для подтверждения или отмены выключения."
|
||||
: L"Remote session active. Keeping the connection available to confirm or cancel shutdown.";
|
||||
#endif
|
||||
ui_localization::ApplyMainWindowStrings(ui_->main, language);
|
||||
ui_localization::ApplyStreamWindowStrings(ui_->main, language);
|
||||
ui_localization::ApplyMainWindowStrings(ui_->wall, language);
|
||||
@@ -6191,6 +6214,9 @@ void GuiApplication::Cleanup() {
|
||||
return;
|
||||
}
|
||||
ui_->file_dialog_lifetime.reset();
|
||||
#if _WIN32
|
||||
ui_->shutdown_guard.reset();
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
CancelNativeFileDialog();
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
#include "shutdown_session_guard.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "rd_log.h"
|
||||
|
||||
namespace crossdesk {
|
||||
namespace {
|
||||
constexpr wchar_t kShutdownWindowClass[] = L"CrossDesk.ShutdownSessionGuard";
|
||||
}
|
||||
|
||||
ShutdownSessionGuard::ShutdownSessionGuard(
|
||||
std::shared_ptr<std::atomic<bool>> connected)
|
||||
: connected_(std::move(connected)) {}
|
||||
|
||||
ShutdownSessionGuard::~ShutdownSessionGuard() {
|
||||
ClearReason();
|
||||
if (window_) DestroyWindow(window_);
|
||||
}
|
||||
|
||||
bool ShutdownSessionGuard::ReportError(const char* operation) {
|
||||
const DWORD error = GetLastError();
|
||||
const ULONGLONG now = GetTickCount64();
|
||||
if (last_error_tick_ == 0 || now - last_error_tick_ >= 5000) {
|
||||
LOG_WARN("Windows shutdown session guard {} failed, error={}", operation, error);
|
||||
last_error_tick_ = now;
|
||||
}
|
||||
SetLastError(error);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShutdownSessionGuard::Start() {
|
||||
if (window_) return true;
|
||||
WNDCLASSW klass{};
|
||||
klass.lpfnWndProc = WindowProc;
|
||||
klass.hInstance = GetModuleHandleW(nullptr);
|
||||
klass.lpszClassName = kShutdownWindowClass;
|
||||
if (!RegisterClassW(&klass) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
|
||||
return ReportError("register window");
|
||||
// A top-level window receives session-end broadcasts even when the Slint
|
||||
// windows are hidden in the tray. HWND_MESSAGE does not receive them.
|
||||
window_ = CreateWindowExW(WS_EX_TOOLWINDOW, kShutdownWindowClass, L"CrossDesk",
|
||||
WS_OVERLAPPED, 0, 0, 0, 0, nullptr, nullptr, klass.hInstance, this);
|
||||
if (!window_) return ReportError("create window");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShutdownSessionGuard::ClearReason() {
|
||||
if (!reason_registered_) return true;
|
||||
if (window_ && !ShutdownBlockReasonDestroy(window_))
|
||||
return ReportError("clear reason");
|
||||
reason_registered_ = false;
|
||||
LOG_INFO("Windows shutdown session guard released");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShutdownSessionGuard::SyncReason() {
|
||||
if (shutdown_allowed_ || !connected_ ||
|
||||
!connected_->load(std::memory_order_relaxed)) {
|
||||
return ClearReason();
|
||||
}
|
||||
if (reason_registered_) return true;
|
||||
if (!ShutdownBlockReasonCreate(window_, reason_.c_str()))
|
||||
return ReportError("register reason");
|
||||
reason_registered_ = true;
|
||||
LOG_INFO("Windows shutdown session guard armed for connected controller");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShutdownSessionGuard::Update(std::wstring_view reason) {
|
||||
if (!Start()) return false;
|
||||
if (std::wstring_view(reason_) != reason) {
|
||||
// Keep the old registration and text on failure so the next tick retries
|
||||
// removal before registering the newly selected language.
|
||||
if (!ClearReason()) return false;
|
||||
reason_.assign(reason);
|
||||
}
|
||||
return SyncReason();
|
||||
}
|
||||
|
||||
LRESULT CALLBACK ShutdownSessionGuard::WindowProc(
|
||||
HWND window, UINT message, WPARAM wparam, LPARAM lparam) {
|
||||
if (message == WM_NCCREATE) {
|
||||
const auto* create = reinterpret_cast<CREATESTRUCTW*>(lparam);
|
||||
auto* guard = static_cast<ShutdownSessionGuard*>(create->lpCreateParams);
|
||||
guard->window_ = window;
|
||||
SetWindowLongPtrW(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(guard));
|
||||
}
|
||||
auto* guard = reinterpret_cast<ShutdownSessionGuard*>(
|
||||
GetWindowLongPtrW(window, GWLP_USERDATA));
|
||||
if (guard && message == WM_QUERYENDSESSION) {
|
||||
const auto flags = static_cast<DWORD>(lparam);
|
||||
// "Shut down anyway", logoff and Restart Manager must remain available.
|
||||
if ((flags & (ENDSESSION_CRITICAL | ENDSESSION_LOGOFF | ENDSESSION_CLOSEAPP)) != 0)
|
||||
guard->shutdown_allowed_ = true;
|
||||
guard->SyncReason();
|
||||
const bool retain = !guard->shutdown_allowed_ && guard->reason_registered_ &&
|
||||
guard->connected_ && guard->connected_->load(std::memory_order_relaxed);
|
||||
LOG_INFO("Windows shutdown query: flags=0x{:x}, retain_remote_session={}", flags, retain);
|
||||
return retain ? FALSE : TRUE;
|
||||
}
|
||||
if (guard && message == WM_ENDSESSION) {
|
||||
LOG_INFO("Windows session end: confirmed={}, flags=0x{:x}",
|
||||
wparam != FALSE, static_cast<DWORD>(lparam));
|
||||
guard->shutdown_allowed_ = wparam != FALSE;
|
||||
guard->SyncReason();
|
||||
// A cancelled shutdown must leave transport, capture and input running.
|
||||
return 0;
|
||||
}
|
||||
if (guard && message == WM_NCDESTROY) {
|
||||
guard->ClearReason();
|
||||
// Destruction removes the native registration even if explicit removal
|
||||
// failed. A later window must not inherit the destroyed window's state.
|
||||
guard->reason_registered_ = false;
|
||||
guard->window_ = nullptr;
|
||||
SetWindowLongPtrW(window, GWLP_USERDATA, 0);
|
||||
}
|
||||
return DefWindowProcW(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
} // namespace crossdesk
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2026-10-22
|
||||
* Copyright (c) 2026 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SHUTDOWN_SESSION_GUARD_H_
|
||||
#define _SHUTDOWN_SESSION_GUARD_H_
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace crossdesk {
|
||||
|
||||
// Owned and pumped by the UI thread. The transport may revoke the shared
|
||||
// connection flag from another thread, including between UI ticks.
|
||||
class ShutdownSessionGuard {
|
||||
public:
|
||||
explicit ShutdownSessionGuard(std::shared_ptr<std::atomic<bool>> connected);
|
||||
~ShutdownSessionGuard();
|
||||
ShutdownSessionGuard(const ShutdownSessionGuard&) = delete;
|
||||
ShutdownSessionGuard& operator=(const ShutdownSessionGuard&) = delete;
|
||||
|
||||
bool Update(std::wstring_view reason);
|
||||
|
||||
private:
|
||||
bool Start();
|
||||
bool SyncReason();
|
||||
bool ClearReason();
|
||||
bool ReportError(const char* operation);
|
||||
static LRESULT CALLBACK WindowProc(HWND window, UINT message,
|
||||
WPARAM wparam, LPARAM lparam);
|
||||
|
||||
std::shared_ptr<std::atomic<bool>> connected_;
|
||||
HWND window_ = nullptr;
|
||||
std::wstring reason_;
|
||||
bool reason_registered_ = false;
|
||||
bool shutdown_allowed_ = false;
|
||||
ULONGLONG last_error_tick_ = 0;
|
||||
};
|
||||
|
||||
} // namespace crossdesk
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2026-09-07
|
||||
* @Date: 2026-10-22
|
||||
* Copyright (c) 2026 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
@@ -19,6 +19,15 @@ inline bool IsDesktopTransitionInputError(DWORD error) {
|
||||
error == ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION;
|
||||
}
|
||||
|
||||
// Only call with an observation from the interactive session, never Session 0.
|
||||
// Process presence (including LogonUI) cannot prove that Default is accessible:
|
||||
// shutdown blocking UI may be active while WTS still reports an unlocked user.
|
||||
inline bool IsSecureInputDesktop(bool available, const std::string& name,
|
||||
DWORD error) {
|
||||
if (!available) return error == ERROR_ACCESS_DENIED;
|
||||
return !name.empty() && _stricmp(name.c_str(), "Default") != 0;
|
||||
}
|
||||
|
||||
inline std::wstring GetDesktopNameW(HDESK desktop) {
|
||||
DWORD bytes_needed = 0;
|
||||
if (desktop == nullptr) {
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "secure_desktop_frame_pacer.h"
|
||||
#include "secure_desktop_nv12_cache.h"
|
||||
#include "service_lifetime.h"
|
||||
#include "shutdown_order.h"
|
||||
#include "shared_capture_lifecycle.h"
|
||||
#include "shared_capture_configuration.h"
|
||||
#include "usbmmidd_policy.h"
|
||||
@@ -398,13 +399,8 @@ void UpdateHelperState(HelperState* helper_state) {
|
||||
// Process enumeration can straddle an unlock. Observe the input desktop
|
||||
// afterwards, and expose the sample's start time for service-side rejection.
|
||||
InputDesktopInfo desktop_info = GetInputDesktopInfo();
|
||||
const bool input_desktop_is_winlogon =
|
||||
_stricmp(desktop_info.name.c_str(), "Winlogon") == 0;
|
||||
const bool inaccessible_secure_input_desktop =
|
||||
!desktop_info.available &&
|
||||
desktop_info.error_code == ERROR_ACCESS_DENIED && !logon_ui_visible;
|
||||
const bool secure_desktop_active = input_desktop_is_winlogon ||
|
||||
inaccessible_secure_input_desktop;
|
||||
const bool secure_desktop_active = crossdesk::IsSecureInputDesktop(
|
||||
desktop_info.available, desktop_info.name, desktop_info.error_code);
|
||||
bool session_locked = false;
|
||||
if (!QuerySessionLockState(helper_state->session_id, &session_locked)) {
|
||||
session_locked =
|
||||
@@ -2043,9 +2039,15 @@ void PrintUsage() {
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
const DWORD shutdown_error = crossdesk::ConfigureWindowsShutdownOrder(
|
||||
crossdesk::WindowsShutdownRole::helper);
|
||||
EnablePerMonitorDpiAwareness();
|
||||
|
||||
InitializeHelperLogger();
|
||||
if (shutdown_error != ERROR_SUCCESS) {
|
||||
LOG_WARN("Could not configure Windows helper shutdown order, error={}",
|
||||
shutdown_error);
|
||||
}
|
||||
|
||||
bool run_helper = false;
|
||||
bool run_secure_input_helper = false;
|
||||
@@ -2158,6 +2160,8 @@ int main(int argc, char* argv[]) {
|
||||
bool last_consent_ui = false;
|
||||
bool last_secure_desktop = false;
|
||||
bool last_session_locked = false;
|
||||
bool last_input_desktop_available = false;
|
||||
DWORD last_input_desktop_error = ERROR_SUCCESS;
|
||||
std::string last_stage;
|
||||
while (true) {
|
||||
UpdateHelperState(&helper_state);
|
||||
@@ -2165,6 +2169,7 @@ int main(int argc, char* argv[]) {
|
||||
std::string desktop_name;
|
||||
bool session_locked = false;
|
||||
bool input_desktop_available = false;
|
||||
DWORD input_desktop_error = ERROR_SUCCESS;
|
||||
bool lock_app_visible = false;
|
||||
bool logon_ui_running = false;
|
||||
bool consent_ui_visible = false;
|
||||
@@ -2174,6 +2179,7 @@ int main(int argc, char* argv[]) {
|
||||
desktop_name = helper_state.input_desktop_name;
|
||||
session_locked = helper_state.session_locked;
|
||||
input_desktop_available = helper_state.input_desktop_available;
|
||||
input_desktop_error = helper_state.input_desktop_error_code;
|
||||
lock_app_visible = helper_state.lock_app_visible;
|
||||
logon_ui_running = helper_state.logon_ui_visible;
|
||||
consent_ui_visible = helper_state.consent_ui_visible;
|
||||
@@ -2188,6 +2194,8 @@ int main(int argc, char* argv[]) {
|
||||
lock_app_visible, credential_ui_visible, secure_desktop_active);
|
||||
|
||||
if (desktop_name != last_desktop_name ||
|
||||
input_desktop_available != last_input_desktop_available ||
|
||||
input_desktop_error != last_input_desktop_error ||
|
||||
session_locked != last_session_locked ||
|
||||
lock_app_visible != last_lock_app ||
|
||||
logon_ui_running != last_logon_ui ||
|
||||
@@ -2195,11 +2203,15 @@ int main(int argc, char* argv[]) {
|
||||
secure_desktop_active != last_secure_desktop || stage != last_stage) {
|
||||
LOG_INFO(
|
||||
"Session helper state: session_id={}, input_desktop='{}', "
|
||||
"input_desktop_available={}, input_desktop_error={}, "
|
||||
"session_locked={}, lock_app_visible={}, logon_ui_running={}, "
|
||||
"consent_ui_visible={}, secure_desktop_active={}, stage={}",
|
||||
current_session_id, desktop_name, session_locked, lock_app_visible,
|
||||
current_session_id, desktop_name, input_desktop_available,
|
||||
input_desktop_error, session_locked, lock_app_visible,
|
||||
logon_ui_running, consent_ui_visible, secure_desktop_active, stage);
|
||||
last_desktop_name = desktop_name;
|
||||
last_input_desktop_available = input_desktop_available;
|
||||
last_input_desktop_error = input_desktop_error;
|
||||
last_session_locked = session_locked;
|
||||
last_lock_app = lock_app_visible;
|
||||
last_logon_ui = logon_ui_running;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* @Author: DI JUNKUN
|
||||
* @Date: 2026-10-22
|
||||
* Copyright (c) 2026 by DI JUNKUN, All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SHUTDOWN_ORDER_H_
|
||||
#define _SHUTDOWN_ORDER_H_
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
namespace crossdesk {
|
||||
|
||||
enum class WindowsShutdownRole { host, helper };
|
||||
|
||||
// Windows shuts processes down from high to low (the default is 0x280).
|
||||
// Keep the remote host alive while ordinary applications ask the user to
|
||||
// resolve a blocked shutdown. The helpers must outlive the host. Stay inside
|
||||
// the application range; 0x000-0x0ff is reserved for the operating system.
|
||||
inline constexpr DWORD WindowsShutdownLevel(WindowsShutdownRole role) {
|
||||
return role == WindowsShutdownRole::host ? 0x101 : 0x100;
|
||||
}
|
||||
|
||||
inline DWORD ConfigureWindowsShutdownOrder(WindowsShutdownRole role) {
|
||||
// Change only the order. The GUI's session guard separately defers shutdown
|
||||
// while a controller is connected; a confirmed shutdown still ends CrossDesk.
|
||||
if (SetProcessShutdownParameters(WindowsShutdownLevel(role), 0))
|
||||
return ERROR_SUCCESS;
|
||||
const DWORD error = GetLastError();
|
||||
return error != ERROR_SUCCESS ? error : ERROR_GEN_FAILURE;
|
||||
}
|
||||
|
||||
} // namespace crossdesk
|
||||
|
||||
#endif
|
||||
@@ -20,10 +20,6 @@ function setup_targets()
|
||||
end
|
||||
table.insert(windows_resource_defines,
|
||||
"CROSSDESK_VERSION_NUMERIC=" .. table.concat(version_parts, ","))
|
||||
local windows_helper_resource_defines = table.join(windows_resource_defines)
|
||||
if is_config("CROSSDESK_PORTABLE", true) then
|
||||
table.insert(windows_helper_resource_defines, "CROSSDESK_PORTABLE=1")
|
||||
end
|
||||
|
||||
local function copy_slint_runtime(target)
|
||||
if not target:is_plat("windows") then
|
||||
@@ -607,6 +603,7 @@ function setup_targets()
|
||||
add_files("apps/desktop/src/platform/windows/gui/tray/win_tray.cpp",
|
||||
"apps/desktop/src/platform/windows/gui/slint_backend.cpp",
|
||||
"apps/desktop/src/platform/windows/gui/window_icons.cpp",
|
||||
"apps/desktop/src/platform/windows/gui/shutdown_session_guard.cpp",
|
||||
"apps/desktop/src/platform/windows/gui/slint_renderer_probe.cpp",
|
||||
"apps/desktop/src/platform/common/gui/opengl_video_renderer.cpp",
|
||||
"apps/desktop/src/platform/common/gui/cuda_driver.cpp",
|
||||
@@ -681,7 +678,7 @@ function setup_targets()
|
||||
add_files("apps/desktop/src/platform/windows/service/session_helper_main.cpp")
|
||||
add_files("apps/desktop/src/platform/windows/virtual_display/usbmmidd_virtual_display.cpp")
|
||||
add_files("apps/desktop/resources/windows/crossdesk_session_helper.rc",
|
||||
{defines = windows_helper_resource_defines})
|
||||
{defines = windows_resource_defines})
|
||||
add_includedirs("apps/desktop/src/common",
|
||||
"apps/desktop/src/platform/windows/service",
|
||||
"apps/desktop/src/platform/windows/screen_capturer",
|
||||
|
||||
Vendored
+1
-1
Submodule deps/submodules/minirtc updated: 2e15671370...978a2410d9
Reference in New Issue
Block a user