set_user_tasks/
lib.rs

1use windows::{
2    core::{PCWSTR},
3    Win32::{
4        System::{
5            Com::{CoCreateInstance, CLSCTX_INPROC_SERVER}
6        },
7        UI::{
8            Shell::{ICustomDestinationList, IShellLinkW, Common::{IObjectCollection, IObjectArray}, DestinationList, EnumerableObjectCollection, ShellLink, PropertiesSystem::{IPropertyStore, InitPropVariantFromStringVector}}
9        },
10    }
11};
12use windows::core::ComInterface;
13use windows::Win32::Storage::EnhancedStorage::PKEY_Title;
14
15
16/// Construct a `windows-rs`'s [`PWSTR`] from a [`&str`].
17///
18/// See: https://github.com/microsoft/windows-rs/issues/973#issue-942298423
19#[inline]
20fn string_to_pwstr(str: &str) -> PCWSTR {
21    let mut encoded = str.encode_utf16().chain([0u16]).collect::<Vec<u16>>();
22    PCWSTR(encoded.as_mut_ptr())
23}
24
25pub struct UserTask<'a> {
26    pub title: &'a str,
27    pub description: &'a str,
28    pub arguments: &'a str,
29    pub icon_path: &'a str,
30    pub icon_index: i32,
31    pub program: &'a str,
32}
33
34pub fn set_tasks(tasks: Vec<UserTask>) -> Result<(), windows::core::Error> {
35    let cdl: ICustomDestinationList = unsafe {
36        CoCreateInstance(&DestinationList, None, CLSCTX_INPROC_SERVER)?
37    };
38
39    let collection: IObjectCollection = unsafe {
40        CoCreateInstance(&EnumerableObjectCollection, None, CLSCTX_INPROC_SERVER)?
41    };
42
43    unsafe {
44        for task in tasks {
45            let shell_link: IShellLinkW = CoCreateInstance(&ShellLink, None, CLSCTX_INPROC_SERVER)?;
46
47            shell_link.SetDescription(string_to_pwstr(task.description))?;
48            shell_link.SetArguments(string_to_pwstr(task.arguments))?;
49            shell_link.SetIconLocation(string_to_pwstr(task.icon_path), task.icon_index)?;
50            shell_link.SetPath(string_to_pwstr(task.program)  )?;
51
52            let prop_store: IPropertyStore = shell_link.cast()?;
53            let pkey = PKEY_Title;
54
55            let mut title: Vec<u16> = task.title.encode_utf16().collect();
56            title.push(0x00);
57            let pv = InitPropVariantFromStringVector(Some(&[windows::core::PCWSTR(title.as_mut_ptr())]))?;
58
59            prop_store.SetValue(&pkey, &pv)?;
60            prop_store.Commit()?;
61
62            collection.AddObject(&shell_link)?;
63        }
64
65        let mut slots_visible: u32 = 0;
66        let _removed: IObjectArray = cdl.BeginList(&mut slots_visible as *mut u32)?;
67
68        cdl.AddUserTasks(&collection)?;
69        cdl.CommitList()?;
70    }
71
72    Ok(())
73}