Skip to content

Commit 0fec61c

Browse files
committed
fix: windows impl.
1 parent ebcd3b9 commit 0fec61c

1 file changed

Lines changed: 45 additions & 52 deletions

File tree

plugins/recent-doc/src/commands.rs

Lines changed: 45 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ use tauri::command;
99

1010
#[cfg(target_os = "windows")]
1111
use windows::{
12-
core::{Interface, HSTRING, PWSTR},
12+
core::{HSTRING, PCWSTR},
1313
Win32::{
14-
Foundation::{GetLastError, MAX_PATH},
15-
System::Com::{
16-
CoCreateInstance, CoTaskMemFree, IPersistFile, CLSCTX_INPROC_SERVER, STGM_READ,
14+
System::Com::{CoCreateInstance, CoTaskMemFree, CLSCTX_INPROC_SERVER},
15+
UI::Shell::{
16+
ApplicationDocumentLists, GetCurrentProcessExplicitAppUserModelID,
17+
IApplicationDocumentLists, IShellItem, IShellItemArray, SHAddToRecentDocs, SHCreateItemFromParsingName,
18+
ADLT_RECENT, SHARDAPPIDINFO, SHARD_APPIDINFO, SIGDN_FILESYSPATH,
1719
},
18-
UI::Shell::{FOLDERID_Recent, SHGetKnownFolderPath, KNOWN_FOLDER_FLAG},
19-
UI::Shell::{IShellLinkW, SHAddToRecentDocs, ShellLink, SHARD_APPIDINFO, SHARD_PATHW},
2020
},
2121
};
2222

@@ -34,10 +34,24 @@ pub(crate) fn add_recent_document(_path: &str) -> Result<()> {
3434
unsafe {
3535
// Convert path to HSTRING
3636
let path_hstring = HSTRING::from(_path);
37+
let item = SHCreateItemFromParsingName(&path_hstring, None)?;
38+
39+
// get app id pointer
40+
let app_id_pwstr = GetCurrentProcessExplicitAppUserModelID()?;
41+
42+
// construct info
43+
let info = SHARDAPPIDINFO {
44+
pszAppID: PCWSTR::from_raw(app_id_pwstr.as_ptr()),
45+
psi: std::mem::ManuallyDrop::new(Some(item)),
46+
};
47+
3748
SHAddToRecentDocs(
38-
SHARD_PATHW.0 as u32,
39-
Some(path_hstring.as_ptr() as *const core::ffi::c_void),
49+
SHARD_APPIDINFO.0 as u32,
50+
Some(&info as *const _ as *const core::ffi::c_void),
4051
);
52+
53+
// Free memory
54+
CoTaskMemFree(Some(app_id_pwstr.as_ptr() as *mut _));
4155
}
4256

4357
#[cfg(target_os = "macos")]
@@ -91,25 +105,31 @@ pub(crate) fn get_recent_documents() -> Result<Vec<String>> {
91105

92106
#[cfg(target_os = "windows")]
93107
unsafe {
94-
let recent_path = SHGetKnownFolderPath(&FOLDERID_Recent, KNOWN_FOLDER_FLAG(0), None)?;
95-
if recent_path.is_null() {
96-
return Err(crate::error::Error::WindowsError(GetLastError().into()));
97-
}
98-
let recent_path_os_string = recent_path.to_hstring().to_os_string();
99-
100-
if let Ok(entries) = fs::read_dir(recent_path_os_string) {
101-
for entry in entries.flatten() {
102-
let path = entry.path();
103-
104-
if path.extension().and_then(|s: &std::ffi::OsStr| s.to_str()) == Some("lnk") {
105-
if let Ok(resolved_path) = resolve_shortcut(&path) {
106-
recent_docs.push(resolved_path);
107-
}
108-
}
108+
// Instantiate the IApplicationDocumentLists COM object
109+
// It automatically scopes to the calling process's AppUserModelID
110+
let app_docs: IApplicationDocumentLists = CoCreateInstance(
111+
&ApplicationDocumentLists as *const _,
112+
None,
113+
CLSCTX_INPROC_SERVER,
114+
)?;
115+
116+
// Retrieve the recent document list specific to this application
117+
let obj_array: IShellItemArray = app_docs.GetList(ADLT_RECENT, 0)?;
118+
let count = obj_array.GetCount()?;
119+
120+
// Iterate through the returned collection
121+
for i in 0..count {
122+
// Extract the generic ShellItem
123+
let item: IShellItem = obj_array.GetItemAt(i)?;
124+
125+
// Extract the absolute file system path
126+
let name_pwstr = item.GetDisplayName(SIGDN_FILESYSPATH)?;
127+
if !name_pwstr.as_ptr().is_null() {
128+
recent_docs.push(name_pwstr.to_string()?);
129+
// Free the memory allocated by the COM subsystem
130+
CoTaskMemFree(Some(name_pwstr.0 as *mut _));
109131
}
110132
}
111-
112-
CoTaskMemFree(Some(recent_path.0 as *mut _));
113133
}
114134

115135
#[cfg(target_os = "macos")]
@@ -135,30 +155,3 @@ pub(crate) fn get_recent_documents() -> Result<Vec<String>> {
135155

136156
Ok(recent_docs)
137157
}
138-
139-
#[cfg(target_os = "windows")]
140-
fn resolve_shortcut(lnk_path: &std::path::Path) -> Result<String> {
141-
unsafe {
142-
// Create IShellLink instance
143-
let shell_link: IShellLinkW =
144-
CoCreateInstance(&ShellLink as *const _, None, CLSCTX_INPROC_SERVER)?;
145-
146-
// Get IPersistFile interface
147-
let persist_file: IPersistFile = shell_link.cast()?;
148-
149-
// Convert path to wide string
150-
let path_wide = HSTRING::from(lnk_path);
151-
152-
// Load the shortcut file
153-
persist_file.Load(&path_wide, STGM_READ)?;
154-
155-
// Resolve the target path
156-
let mut target_path = [0u16; MAX_PATH as usize];
157-
shell_link.GetPath(&mut target_path, std::ptr::null_mut(), 0)?;
158-
159-
// Convert wide string to regular string
160-
let path_string = PWSTR::from_raw(target_path.as_mut_ptr()).to_string()?;
161-
162-
Ok(path_string)
163-
}
164-
}

0 commit comments

Comments
 (0)