Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/devolutions-agent-shared/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub struct PackageInfoError {
pub fn get_installed_agent_version() -> Result<Option<DateVersion>, PackageInfoError> {
Ok(windows::registry::get_installed_product_version(
windows::AGENT_UPDATE_CODE,
windows::registry::ProductVersionEncoding::Agent,
)?)
}

Expand Down
4 changes: 4 additions & 0 deletions crates/devolutions-agent-shared/src/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ pub const GATEWAY_UPDATE_CODE: Uuid = uuid!("{db3903d6-c451-4393-bd80-eb9f45b902
///
/// See [`GATEWAY_UPDATE_CODE`] for more information on update codes.
pub const AGENT_UPDATE_CODE: Uuid = uuid!("{82318d3c-811f-4d5d-9a82-b7c31b076755}");
/// MSI upgrade code for the Remote Desktop Manager.
///
/// See [`GATEWAY_UPDATE_CODE`] for more information on update codes.
pub const RDM_UPDATE_CODE: Uuid = uuid!("{2707F3BF-4D7B-40C2-882F-14B0ED869EE8}");
49 changes: 47 additions & 2 deletions crates/devolutions-agent-shared/src/windows/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,17 @@ pub fn get_product_code(update_code: Uuid) -> Result<Option<Uuid>, RegistryError
Ok(Some(reversed_hex_to_uuid(&product_code)?))
}

pub enum ProductVersionEncoding {
Agent,
Rdm,
}

/// Get the installed version of a product using Windows registry. Returns `None` if the product
/// is not installed.
pub fn get_installed_product_version(update_code: Uuid) -> Result<Option<DateVersion>, RegistryError> {
pub fn get_installed_product_version(
update_code: Uuid,
version_encoding: ProductVersionEncoding,
) -> Result<Option<DateVersion>, RegistryError> {
let product_code_uuid = match get_product_code(update_code)? {
Some(uuid) => uuid,
None => return Ok(None),
Expand Down Expand Up @@ -79,10 +87,14 @@ pub fn get_installed_product_version(update_code: Uuid) -> Result<Option<DateVer
})?;

// Convert encoded MSI version number to human-readable date.
let short_year = (product_version >> 24) + 2000;
let month = (product_version >> 16) & 0xFF;
let day = product_version & 0xFFFF;

let short_year = match version_encoding {
ProductVersionEncoding::Agent => (product_version >> 24) + 2000,
ProductVersionEncoding::Rdm => (product_version >> 24) + 0x700,
Comment on lines +93 to +95
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Magic number: The constant 0x700 (1792 in decimal) for RDM version encoding is unexplained. This magic number makes the code difficult to understand and maintain. Consider adding a comment explaining what this value represents and why it's used for RDM version calculation, or define it as a named constant with documentation.

Copilot uses AI. Check for mistakes.
};
Comment on lines 90 to +96
Copy link

Copilot AI Nov 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable ordering issue: The month and day variables are extracted before short_year is calculated, but short_year logically comes first in the version sequence. Consider moving lines 90-91 after line 96 to maintain logical ordering and improve code readability.

Suggested change
let month = (product_version >> 16) & 0xFF;
let day = product_version & 0xFFFF;
let short_year = match version_encoding {
ProductVersionEncoding::Agent => (product_version >> 24) + 2000,
ProductVersionEncoding::Rdm => (product_version >> 24) + 0x700,
};
let short_year = match version_encoding {
ProductVersionEncoding::Agent => (product_version >> 24) + 2000,
ProductVersionEncoding::Rdm => (product_version >> 24) + 0x700,
};
let month = (product_version >> 16) & 0xFF;
let day = product_version & 0xFFFF;

Copilot uses AI. Check for mistakes.

Ok(Some(DateVersion {
year: short_year,
month,
Expand All @@ -91,3 +103,36 @@ pub fn get_installed_product_version(update_code: Uuid) -> Result<Option<DateVer
revision: 0,
}))
}

/// Get the installation location of a product using Windows registry. Returns `None` if the product
/// is not installed or if the InstallLocation value is not present.
pub fn get_install_location(update_code: Uuid) -> Result<Option<String>, RegistryError> {
let product_code_uuid = match get_product_code(update_code)? {
Some(uuid) => uuid,
None => return Ok(None),
}
.braced();

let key_path = format!("{REG_CURRENT_VERSION}\\Uninstall\\{product_code_uuid}");

const INSTALL_LOCATION_VALUE_NAME: &str = "InstallLocation";

// Now we know the product code of installed MSI, we could read its install location.
let product_tree = windows_registry::LOCAL_MACHINE
.open(&key_path)
.map_err(|source| RegistryError::OpenKey {
key: key_path.clone(),
source,
})?;

let install_location: String = product_tree
.get_value(INSTALL_LOCATION_VALUE_NAME)
.and_then(TryInto::try_into)
.map_err(|source| RegistryError::ReadValue {
value: INSTALL_LOCATION_VALUE_NAME.to_owned(),
key: key_path.clone(),
source,
})?;

Ok(Some(install_location))
}
7 changes: 5 additions & 2 deletions devolutions-session/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@ win-api-wrappers = { path = "../crates/win-api-wrappers", optional = true }

[dependencies.now-proto-pdu]
optional = true
version = "0.3.2"
version = "0.4.0"
features = ["std"]

[target.'cfg(windows)'.dependencies]
devolutions-agent-shared = { path = "../crates/devolutions-agent-shared" }

[target.'cfg(windows)'.build-dependencies]
embed-resource = "3.0"

Expand All @@ -60,4 +63,4 @@ features = [
"Win32_UI_Shell",
"Win32_System_Console",
"Win32_UI_Input_KeyboardAndMouse",
]
]
Loading