/* * @Author: DI JUNKUN * @Date: 2026-04-21 * Copyright (c) 2026 by DI JUNKUN, All Rights Reserved. */ #ifndef _SERVICE_HOST_H_ #define _SERVICE_HOST_H_ #include #include #include #include #include #include namespace crossdesk { inline constexpr wchar_t kCrossDeskServiceName[] = L"CrossDeskService"; inline constexpr wchar_t kCrossDeskServiceDisplayName[] = L"CrossDesk Service"; inline constexpr wchar_t kCrossDeskServicePipeName[] = L"\\\\.\\pipe\\CrossDeskService"; class CrossDeskServiceHost { public: CrossDeskServiceHost(); ~CrossDeskServiceHost(); int RunAsService(); int RunInConsole(); private: int RunServiceLoop(bool as_service); int InitializeRuntime(); void ShutdownRuntime(); void RequestStop(); void ClientProcessMonitorLoop(); bool LaunchUnattendedHost(DWORD session_id); void StopUnattendedHost(); void ReportServiceStatus(DWORD current_state, DWORD win32_exit_code, DWORD wait_hint); void IpcServerLoop(); void RefreshSessionState(); void EnsureSessionHelper(); void ReapSessionHelper(); void StopSessionHelper(); bool LaunchSessionHelper(DWORD session_id); void ReapSecureInputHelper(); void StopSecureInputHelper(); bool LaunchSecureInputHelper(DWORD session_id, const std::string& interactive_stage, const std::string& interactive_desktop); std::wstring GetSessionHelperPath() const; std::wstring GetSessionHelperStopEventName(DWORD session_id) const; std::wstring GetSecureInputHelperPath() const; std::wstring GetSecureInputHelperStopEventName(DWORD session_id) const; void ResetSessionHelperReportedStateLocked(const char* error, DWORD error_code); bool GetEffectiveSessionLockedLocked() const; bool IsHelperReportingLockScreenLocked() const; bool HasSecureInputUiLocked() const; void UpdateSasSecureDesktopGraceLocked(const std::string& observed_stage); bool IsSasSecureDesktopGraceActiveLocked() const; bool ShouldKeepSecureInputHelperLocked(DWORD target_session_id) const; std::string ResolveInteractiveStageLocked() const; std::string ResolveInteractiveDesktopLocked( const std::string& interactive_stage) const; void RefreshSessionHelperReportedState(); void RecordSessionEvent(DWORD event_type, DWORD session_id); std::string HandleIpcCommand(const std::string& command, DWORD client_session_id); std::string BuildStatusResponse(DWORD client_session_id); std::string SendSecureAttentionSequence(DWORD client_session_id); std::string SendSecureDesktopKeyboardInput(DWORD client_session_id, int key_code, bool is_down, uint32_t scan_code = 0, bool extended = false); std::string SendSecureDesktopMouseInput(DWORD client_session_id, int x, int y, int wheel, int flag); static void WINAPI ServiceMain(DWORD argc, LPWSTR* argv); static BOOL WINAPI ConsoleControlHandler(DWORD control_type); static DWORD WINAPI ServiceControlHandler(DWORD control, DWORD event_type, LPVOID event_data, LPVOID context); private: SERVICE_STATUS_HANDLE status_handle_ = nullptr; SERVICE_STATUS service_status_{}; HANDLE stop_event_ = nullptr; std::thread ipc_thread_; std::thread client_process_monitor_thread_; // Owned exclusively by the monitor, then drained after it joins. HANDLE unattended_process_ = nullptr; HANDLE unattended_stop_event_ = nullptr; DWORD unattended_session_ = 0xFFFFFFFF; std::atomic unattended_logoff_generation_{0}; std::mutex state_mutex_; HANDLE lifetime_mutex_ = nullptr; std::wstring lifetime_mutex_name_; DWORD active_session_id_ = 0xFFFFFFFF; DWORD process_session_id_ = 0xFFFFFFFF; DWORD input_desktop_error_code_ = 0; DWORD session_helper_process_id_ = 0; DWORD session_helper_session_id_ = 0xFFFFFFFF; DWORD session_helper_exit_code_ = 0; DWORD session_helper_last_error_code_ = 0; DWORD session_helper_status_error_code_ = 0; DWORD session_helper_report_session_id_ = 0xFFFFFFFF; DWORD session_helper_report_process_id_ = 0; DWORD session_helper_report_input_desktop_error_code_ = 0; DWORD secure_input_helper_process_id_ = 0; DWORD secure_input_helper_session_id_ = 0xFFFFFFFF; DWORD secure_input_helper_exit_code_ = 0; DWORD secure_input_helper_last_error_code_ = 0; DWORD last_session_event_type_ = 0; DWORD last_session_event_session_id_ = 0xFFFFFFFF; ULONGLONG started_at_tick_ = 0; ULONGLONG last_sas_tick_ = 0; ULONGLONG session_helper_started_at_tick_ = 0; ULONGLONG session_helper_report_state_age_ms_ = 0; ULONGLONG session_helper_report_uptime_ms_ = 0; ULONGLONG secure_input_helper_started_at_tick_ = 0; ULONGLONG sas_secure_desktop_until_tick_ = 0; bool session_locked_ = false; bool logon_ui_visible_ = false; bool consent_ui_visible_ = false; bool prelogin_ = false; bool secure_desktop_active_ = false; bool input_desktop_available_ = false; bool session_helper_running_ = false; bool session_helper_status_ok_ = false; bool session_helper_report_session_locked_ = false; bool session_helper_report_input_desktop_available_ = false; bool session_helper_report_lock_app_visible_ = false; bool session_helper_report_logon_ui_visible_ = false; bool session_helper_report_consent_ui_visible_ = false; bool session_helper_report_secure_desktop_active_ = false; bool session_helper_report_credential_ui_visible_ = false; bool session_helper_report_unlock_ui_visible_ = false; bool secure_input_helper_running_ = false; bool console_mode_ = false; bool sas_secure_desktop_seen_ = false; DWORD last_sas_error_code_ = 0; bool last_sas_success_ = false; HANDLE session_helper_process_handle_ = nullptr; HANDLE session_helper_stop_event_ = nullptr; HANDLE secure_input_helper_process_handle_ = nullptr; HANDLE secure_input_helper_stop_event_ = nullptr; std::string input_desktop_name_; std::string last_sas_error_; std::string session_helper_last_error_; std::string session_helper_status_error_; std::string session_helper_report_input_desktop_; std::string session_helper_report_interactive_stage_; std::string secure_input_helper_last_error_; std::string secure_input_helper_interactive_stage_; std::string secure_input_helper_interactive_desktop_; static CrossDeskServiceHost* instance_; }; bool IsCrossDeskServiceInstalled(); bool InstallCrossDeskService(const std::wstring& binary_path); bool UninstallCrossDeskService(); bool StartCrossDeskService(); bool StopCrossDeskService(DWORD timeout_ms = 20000); std::string QueryCrossDeskService(const std::string& command, DWORD timeout_ms = 1000); std::string SendCrossDeskSecureDesktopKeyInput(int key_code, bool is_down, uint32_t scan_code = 0, bool extended = false, DWORD timeout_ms = 1000); std::string SendCrossDeskSecureDesktopMouseInput(int x, int y, int wheel, int flag, DWORD timeout_ms = 1000); } // namespace crossdesk #endif