Skip to content

Commit

Permalink
improve the state of things on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfv committed Sep 29, 2024
1 parent bed8a1a commit c4b172f
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 11 deletions.
8 changes: 7 additions & 1 deletion crates/rattler_menuinst/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,14 @@ shell-words = "1.1.0"
known-folders = "1.2.0"

[target.'cfg(target_os = "windows")'.dependencies]
winapi = "0.3.9"
winreg = "0.52.0"
windows = { version = "0.58", features = [
"Win32_System_Com",
"Win32_UI_Shell",
"Win32_UI_Shell_PropertiesSystem",
"Win32_Foundation",
"Win32_System_Com_StructuredStorage",
] }

[dev-dependencies]
insta = { workspace = true }
67 changes: 57 additions & 10 deletions crates/rattler_menuinst/src/windows.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
use std::path::PathBuf;
use std::path::{Path, PathBuf};

Check warning on line 2 in crates/rattler_menuinst/src/windows.rs

View workflow job for this annotation

GitHub Actions / Format, Lint and Test the Python bindings

Diff in /home/runner/work/rattler/rattler/crates/rattler_menuinst/src/windows.rs

Check warning on line 2 in crates/rattler_menuinst/src/windows.rs

View workflow job for this annotation

GitHub Actions / Format and Lint

Diff in /home/runner/work/rattler/rattler/crates/rattler_menuinst/src/windows.rs
use crate::{schema, MenuInstError, MenuMode};
use fs_err as fs;
mod knownfolders;
mod registry;
mod create_shortcut;

struct Directories {
start_menu_location: PathBuf,
quick_launch_location: PathBuf,
desktop_location: PathBuf,
quick_launch_location: Option<PathBuf>,
desktop_location: Option<PathBuf>,
}

impl Directories {
Expand All @@ -15,11 +18,9 @@ impl Directories {
known_folders::get_known_folder_path(known_folders::KnownFolder::StartMenu)
.expect("Failed to get start menu location");
let quick_launch_location =
known_folders::get_known_folder_path(known_folders::KnownFolder::QuickLaunch)
.expect("Failed to get quick launch location");
known_folders::get_known_folder_path(known_folders::KnownFolder::QuickLaunch);
let desktop_location =
known_folders::get_known_folder_path(known_folders::KnownFolder::Desktop)
.expect("Failed to get desktop location");
known_folders::get_known_folder_path(known_folders::KnownFolder::Desktop);

Directories {
start_menu_location,
Expand All @@ -30,8 +31,54 @@ impl Directories {
}

pub struct WindowsMenu {
name: String,
mode: String,
directories: Directories,
item: schema::Windows,
mode: MenuMode,
prefix: PathBuf,
base_prefix: PathBuf,
}

impl WindowsMenu {
pub fn new(item: schema::Windows, prefix: &Path, mode: MenuMode) -> WindowsMenu {
let directories = Directories::create();

WindowsMenu {
directories,
item,
mode,
prefix: prefix.to_path_buf(),
}
}

pub fn create(&self) -> Result<PathBuf, MenuInstError> {
tracing::debug!("Creating {:?}", self.directories.start_menu_location);
fs::create_dir_all(&self.directories.start_menu_location)?;

if let Some(ref quick_launch_location) = self.directories.quick_launch_location {
fs::create_dir_all(quick_launch_location)?;
}

if let Some(ref desktop_location) = self.directories.desktop_location {
fs::create_dir_all(desktop_location)?;
}

Ok(self.directories.start_menu_location.clone())
}

pub fn remove(&self) -> Result<PathBuf, MenuInstError> {
let menu_location = &self.directories.start_menu_location;

Check warning on line 68 in crates/rattler_menuinst/src/windows.rs

View workflow job for this annotation

GitHub Actions / Format, Lint and Test the Python bindings

Diff in /home/runner/work/rattler/rattler/crates/rattler_menuinst/src/windows.rs

Check warning on line 68 in crates/rattler_menuinst/src/windows.rs

View workflow job for this annotation

GitHub Actions / Format and Lint

Diff in /home/runner/work/rattler/rattler/crates/rattler_menuinst/src/windows.rs
if menu_location.exists() {
if menu_location.read_dir()?.next().is_none() {
tracing::info!("Removing {menu_location:?}", );
fs::remove_dir_all(menu_location)?;
}
}
Ok(self.directories.start_menu_location.clone())
}
}

struct WindowsMenuItem {
item: schema::Windows,

Check warning on line 80 in crates/rattler_menuinst/src/windows.rs

View workflow job for this annotation

GitHub Actions / Format, Lint and Test the Python bindings

Diff in /home/runner/work/rattler/rattler/crates/rattler_menuinst/src/windows.rs

Check warning on line 80 in crates/rattler_menuinst/src/windows.rs

View workflow job for this annotation

GitHub Actions / Format and Lint

Diff in /home/runner/work/rattler/rattler/crates/rattler_menuinst/src/windows.rs
prefix: PathBuf,
}


68 changes: 68 additions & 0 deletions crates/rattler_menuinst/src/windows/create_shortcut.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use std::path::Path;

Check warning on line 1 in crates/rattler_menuinst/src/windows/create_shortcut.rs

View workflow job for this annotation

GitHub Actions / Format, Lint and Test the Python bindings

Diff in /home/runner/work/rattler/rattler/crates/rattler_menuinst/src/windows/create_shortcut.rs

Check warning on line 1 in crates/rattler_menuinst/src/windows/create_shortcut.rs

View workflow job for this annotation

GitHub Actions / Format and Lint

Diff in /home/runner/work/rattler/rattler/crates/rattler_menuinst/src/windows/create_shortcut.rs
use windows::{
core::*,
Win32::System::Com::*,
Win32::System::Com::StructuredStorage::*,
Win32::UI::Shell::*,
Win32::UI::Shell::PropertiesSystem::*,
};

#[derive(thiserror::Error, Debug)]
enum CreateShortcutFail {
#[error("Failed to create shortcut: {0}")]
WindowsError(#[from] windows::core::Error),

#[error("Failed to initialize COM")]
CoInitializeFail,
}

/// Create a shortcut at the specified path.
pub(crate) fn create_shortcut(
path: &Path,
description: &str,
filename: &Path,
arguments: Option<&str>,
workdir: Option<&Path>,
iconpath: Option<&Path>,
iconindex: i32,
app_id: Option<&str>,
) -> std::result::Result<(), CreateShortcutFail> {
unsafe {
if !CoInitialize(None).is_ok() {
return Err(CreateShortcutFail::CoInitializeFail);
}

let shell_link: IShellLinkW = CoCreateInstance(&ShellLink, None, CLSCTX_INPROC_SERVER)?;
let persist_file: IPersistFile = shell_link.cast()?;

shell_link.SetPath(&HSTRING::from(path))?;
shell_link.SetDescription(&HSTRING::from(description))?;

if let Some(args) = arguments {
shell_link.SetArguments(&HSTRING::from(args))?;
}

if let Some(icon) = iconpath {
shell_link.SetIconLocation(&HSTRING::from(icon), iconindex)?;
}

if let Some(dir) = workdir {
shell_link.SetWorkingDirectory(&HSTRING::from(dir))?;
}

if let Some(id) = app_id {
let property_store: IPropertyStore = shell_link.cast()?;
let mut prop_variant = PROPVARIANT::default();
// PropVariantInit(&mut prop_variant);
// SetPropStringValue(PCWSTR(PWSTR::from_raw(to_wide_string(id).as_mut_ptr())), &mut prop_variant)?;
// property_store.SetValue(&PROPERTYKEY_AppUserModel_ID, &prop_variant)?;
property_store.Commit()?;
PropVariantClear(&mut prop_variant)?;
}

persist_file.Save(&HSTRING::from(filename), true)?;

CoUninitialize();
Ok(())

Check warning on line 66 in crates/rattler_menuinst/src/windows/create_shortcut.rs

View workflow job for this annotation

GitHub Actions / Format, Lint and Test the Python bindings

Diff in /home/runner/work/rattler/rattler/crates/rattler_menuinst/src/windows/create_shortcut.rs

Check warning on line 66 in crates/rattler_menuinst/src/windows/create_shortcut.rs

View workflow job for this annotation

GitHub Actions / Format and Lint

Diff in /home/runner/work/rattler/rattler/crates/rattler_menuinst/src/windows/create_shortcut.rs
}
}

0 comments on commit c4b172f

Please sign in to comment.