Skip to content
Merged
57 changes: 21 additions & 36 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 34 additions & 11 deletions crates/win-api-wrappers/src/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ use windows::Win32::System::ProcessStatus::K32GetMappedFileNameW;
use windows::Win32::System::RemoteDesktop::ProcessIdToSessionId;
use windows::Win32::System::Threading::{
CREATE_UNICODE_ENVIRONMENT, CreateProcessAsUserW, CreateRemoteThread, EXTENDED_STARTUPINFO_PRESENT,
GetCurrentProcess, GetCurrentProcessId, GetExitCodeProcess, GetProcessTimes, INFINITE,
GetCurrentProcess, GetCurrentProcessId, GetExitCodeProcess, GetProcessId, GetProcessTimes, INFINITE,
LPPROC_THREAD_ATTRIBUTE_LIST, LPTHREAD_START_ROUTINE, OpenProcess, OpenProcessToken, PEB, PROCESS_ACCESS_RIGHTS,
PROCESS_BASIC_INFORMATION, PROCESS_CREATION_FLAGS, PROCESS_INFORMATION, PROCESS_NAME_WIN32, PROCESS_SYNCHRONIZE,
PROCESS_TERMINATE, QueryFullProcessImageNameW, STARTUPINFOEXW, STARTUPINFOW, STARTUPINFOW_FLAGS, TerminateProcess,
WaitForSingleObject,
};
use windows::Win32::UI::Shell::{SEE_MASK_NOCLOSEPROCESS, SHELLEXECUTEINFOW, ShellExecuteExW};
use windows::Win32::UI::Shell::{
SEE_MASK_FLAG_NO_UI, SEE_MASK_NOASYNC, SEE_MASK_NOCLOSEPROCESS, SHELLEXECUTEINFOW, ShellExecuteExW,
};
use windows::Win32::UI::WindowsAndMessaging::{
EnumWindows, GetWindowThreadProcessId, PostThreadMessageW, SHOW_WINDOW_CMD,
};
Expand Down Expand Up @@ -316,6 +318,17 @@ impl Process {
Ok(exit_code)
}

pub fn process_id(&self) -> Result<u32> {
// SAFETY: The process handle is valid for this call.
let process_id = unsafe { GetProcessId(self.handle.raw()) };

if process_id == 0 {
bail!(Error::last_error());
}

Ok(process_id)
}

pub fn query_basic_information(&self) -> Result<PROCESS_BASIC_INFORMATION> {
let mut basic_info = PROCESS_BASIC_INFORMATION::default();

Expand Down Expand Up @@ -431,19 +444,25 @@ impl HandleWrapper for Process {

pub fn shell_execute(
path: &Path,
command_line: &CommandLine,
command_line: &str,
working_directory: &Path,
verb: &str,
show_cmd: SHOW_WINDOW_CMD,
) -> Result<Process> {
let path = WideString::from(path);
let command_line = WideString::from(command_line.to_command_line());
let working_directory = WideString::from(working_directory);
let command_line = WideString::from(command_line);
let working_directory = if working_directory.as_os_str().is_empty() {
WideString::default()
} else {
WideString::from(working_directory)
};
let verb = WideString::from(verb);

let mut exec_info = SHELLEXECUTEINFOW {
cbSize: u32size_of::<SHELLEXECUTEINFOW>(),
fMask: SEE_MASK_NOCLOSEPROCESS,
// UNTESTED: Launch errors must return without modal dialogs while UAC security prompts remain enabled.
// Verify both on an interactive Windows desktop when changing these flags.
fMask: SEE_MASK_NOCLOSEPROCESS | SEE_MASK_NOASYNC | SEE_MASK_FLAG_NO_UI,
lpFile: path.as_pcwstr(),
lpParameters: command_line.as_pcwstr(),
lpDirectory: working_directory.as_pcwstr(),
Expand Down Expand Up @@ -1124,12 +1143,16 @@ pub fn post_message_for_pid(pid: u32, msg: u32, wparam: WPARAM, lparam: LPARAM)
)
}?;

if windows_enum_ctx.threads.is_empty() {
return Err(windows::core::Error::from(windows::Win32::Foundation::ERROR_NOT_FOUND).into());
}

// Send message to all threads.
if !windows_enum_ctx.threads.is_empty() {
for thread in windows_enum_ctx.threads {
// SAFETY: No outstanding preconditions.
let _ = unsafe { PostThreadMessageW(thread, msg, wparam, lparam) };
}
windows_enum_ctx.threads.sort_unstable();
windows_enum_ctx.threads.dedup();
for thread in windows_enum_ctx.threads {
// SAFETY: No outstanding preconditions.
unsafe { PostThreadMessageW(thread, msg, wparam, lparam) }?;
}

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion devolutions-session/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ win-api-wrappers = { path = "../crates/win-api-wrappers", optional = true }

[dependencies.now-proto-pdu]
optional = true
version = "0.4.3"
version = "0.5.0"
features = ["std"]

[dev-dependencies]
Expand Down
9 changes: 2 additions & 7 deletions devolutions-session/src/dvc/encoding.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
//! Console encoding transcoding for IO redirection.
//!
//! When IO redirection is enabled, the child process writes its stdout/stderr using
//! the console's OEM codepage (e.g., `cmd.exe`, `powershell.exe`, `pwsh.exe`). This module
//! provides transcoding between the process's native encoding and UTF-8, which is
//! the encoding used on the wire (NowProto).
//! Transcodes OEM console streams to and from UTF-8 when requested by NOW execution flags.
//! Raw mode preserves bytes for UTF-8 applications such as `pwsh.exe` and for callers managing their own encoding.

use std::borrow::Cow;

Expand All @@ -25,9 +23,6 @@ const CP_UTF8: u32 = 65001;

impl DataEncoding {
/// Determine the OEM codepage encoding for the current system.
///
/// Console applications (`cmd.exe`, `powershell.exe` 5.x, `pwsh.exe`) use the OEM
/// codepage for piped/redirected output.
pub fn from_oem_codepage() -> Self {
// SAFETY: FFI call without outstanding preconditions.
let cp = unsafe { windows::Win32::Globalization::GetOEMCP() };
Expand Down
7 changes: 2 additions & 5 deletions devolutions-session/src/dvc/now_message_dissector.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anyhow::Context;
use now_proto_pdu::NowMessage;
use now_proto_pdu::ironrdp_core::{Decode, DecodeError, DecodeErrorKind, IntoOwned, ReadCursor, WriteBuf};
use now_proto_pdu::ironrdp_core::{Decode, DecodeErrorKind, IntoOwned, ReadCursor, WriteBuf};

/// Reconstructs Now messages from a stream of bytes.
#[derive(Default)]
Expand Down Expand Up @@ -38,10 +38,7 @@ impl NowMessageDissector {
// Remove the read bytes from the buffer
self.start_pos += pos;
}
Err(DecodeError {
kind: DecodeErrorKind::NotEnoughBytes { .. },
..
}) => {
Err(err) if matches!(err.kind(), DecodeErrorKind::NotEnoughBytes { .. }) => {
// Need more data to read the message
break;
}
Expand Down
Loading
Loading