Skip to content

Commit 0f3944c

Browse files
committed
fix: windows impl.
1 parent e7851b1 commit 0f3944c

1 file changed

Lines changed: 43 additions & 56 deletions

File tree

plugins/recent-doc/src/commands.rs

Lines changed: 43 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,18 @@ use tauri::{command, AppHandle, Runtime};
77

88
#[cfg(target_os = "windows")]
99
use windows::{
10-
core::{Interface, HSTRING, PCWSTR, PWSTR},
10+
core::{HSTRING, PCWSTR},
1111
// CRITICAL FIX: Changed `Interface` to `ComInterface` so `.cast()` works
1212
Win32::{
13-
Foundation::MAX_PATH,
1413
System::Com::{
15-
CoCreateInstance, CoInitializeEx, CoTaskMemFree, CoUninitialize, IPersistFile,
16-
CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED, STGM_READ,
14+
CoCreateInstance, CoInitializeEx, CoTaskMemFree, CoUninitialize, CLSCTX_INPROC_SERVER,
15+
COINIT_APARTMENTTHREADED,
1716
},
1817
UI::Shell::{
19-
FOLDERID_Recent, IShellLinkW, SHAddToRecentDocs, SHCreateItemFromParsingName,
20-
SHGetKnownFolderPath, ShellLink, KNOWN_FOLDER_FLAG, SHARDAPPIDINFO, SHARD_APPIDINFO,
18+
ApplicationDestinations, ApplicationDocumentLists, Common::IObjectArray,
19+
IApplicationDestinations, IApplicationDocumentLists, IShellItem, SHAddToRecentDocs,
20+
SHCreateItemFromParsingName, ADLT_RECENT, SHARDAPPIDINFO, SHARD_APPIDINFO,
21+
SIGDN_FILESYSPATH,
2122
},
2223
},
2324
};
@@ -56,18 +57,14 @@ impl Drop for ComGuard {
5657
pub(crate) fn add_recent_document<R: Runtime>(app: AppHandle<R>, _path: &str) -> Result<()> {
5758
#[cfg(target_os = "windows")]
5859
unsafe {
59-
// Set guard first
6060
let _com_guard = ComGuard::new();
6161

62-
// Get app id
6362
let app_id = app.config().identifier.clone();
6463
let app_id_hstring = HSTRING::from(app_id);
6564

66-
// Convert path to HSTRING
6765
let path_hstring = HSTRING::from(_path);
6866
let item = SHCreateItemFromParsingName(&path_hstring, None)?;
6967

70-
// construct info
7168
let info = SHARDAPPIDINFO {
7269
pszAppID: PCWSTR::from_raw(app_id_hstring.as_ptr()),
7370
psi: std::mem::ManuallyDrop::new(Some(item)),
@@ -102,8 +99,19 @@ pub(crate) fn add_recent_document<R: Runtime>(app: AppHandle<R>, _path: &str) ->
10299
pub(crate) fn clear_recent_documents<R: Runtime>(_app: AppHandle<R>) -> Result<()> {
103100
#[cfg(target_os = "windows")]
104101
unsafe {
105-
let _com_guard = ComGuard::new();
106-
SHAddToRecentDocs(SHARD_APPIDINFO.0 as u32, None);
102+
let _guard = ComGuard::new();
103+
104+
let app_id = _app.config().identifier.clone();
105+
let app_id_hstring = HSTRING::from(app_id);
106+
107+
if let Ok(dests) = CoCreateInstance::<_, IApplicationDestinations>(
108+
&ApplicationDestinations as *const _,
109+
None,
110+
CLSCTX_INPROC_SERVER,
111+
) {
112+
let _ = dests.SetAppID(PCWSTR::from_raw(app_id_hstring.as_ptr()));
113+
let _ = dests.RemoveAllDestinations();
114+
}
107115
}
108116

109117
#[cfg(target_os = "macos")]
@@ -130,26 +138,31 @@ pub(crate) fn get_recent_documents<R: Runtime>(_app: AppHandle<R>) -> Result<Vec
130138

131139
#[cfg(target_os = "windows")]
132140
unsafe {
133-
// Ensure COM is initialized for this worker thread
134141
let _guard = ComGuard::new();
135142

136-
// Retrieve the absolute path to "%APPDATA%\Microsoft\Windows\Recent"
137-
let recent_path_pwstr = SHGetKnownFolderPath(&FOLDERID_Recent, KNOWN_FOLDER_FLAG(0), None)?;
138-
139-
if !recent_path_pwstr.as_ptr().is_null() {
140-
let recent_path = recent_path_pwstr.to_string()?;
141-
// Free the string memory allocated by the Windows Shell
142-
CoTaskMemFree(Some(recent_path_pwstr.as_ptr() as *mut _));
143-
144-
// Iterate through the hidden directory searching for .lnk files
145-
if let Ok(entries) = std::fs::read_dir(recent_path) {
146-
for entry in entries.flatten() {
147-
let path = entry.path();
148-
149-
if path.extension().and_then(|s| s.to_str()) == Some("lnk") {
150-
// Resolve the shortcut binary to extract its actual target path
151-
if let Ok(resolved) = resolve_shortcut(&path) {
152-
recent_docs.push(resolved);
143+
let app_id = _app.config().identifier.clone();
144+
let app_id_hstring = HSTRING::from(app_id);
145+
let app_id_pcwstr = PCWSTR::from_raw(app_id_hstring.as_ptr());
146+
147+
if let Ok(doc_lists) = CoCreateInstance::<_, IApplicationDocumentLists>(
148+
&ApplicationDocumentLists,
149+
None,
150+
CLSCTX_INPROC_SERVER,
151+
) {
152+
let _ = doc_lists.SetAppID(app_id_pcwstr);
153+
if let Ok(obj_array) = doc_lists.GetList::<IObjectArray>(ADLT_RECENT, 30) {
154+
let count = obj_array.GetCount().unwrap_or(0);
155+
156+
for i in 0..count {
157+
if let Ok(shell_item) = obj_array.GetAt::<IShellItem>(i) {
158+
if let Ok(name_pwstr) = shell_item.GetDisplayName(SIGDN_FILESYSPATH) {
159+
if let Ok(path) = name_pwstr.to_string() {
160+
if !path.is_empty() {
161+
recent_docs.push(path);
162+
}
163+
}
164+
165+
CoTaskMemFree(Some(name_pwstr.as_ptr() as *const core::ffi::c_void));
153166
}
154167
}
155168
}
@@ -179,29 +192,3 @@ pub(crate) fn get_recent_documents<R: Runtime>(_app: AppHandle<R>) -> Result<Vec
179192

180193
Ok(recent_docs)
181194
}
182-
183-
/// Helper function to extract the real file system path from a Windows .lnk shortcut file.
184-
#[cfg(target_os = "windows")]
185-
fn resolve_shortcut(lnk_path: &std::path::Path) -> Result<String> {
186-
unsafe {
187-
// Instantiate the ShellLink COM Object
188-
let shell_link: IShellLinkW =
189-
CoCreateInstance(&ShellLink as *const _, None, CLSCTX_INPROC_SERVER)?;
190-
191-
// Query the IPersistFile interface to load the shortcut binary from disk
192-
// This .cast() now compiles perfectly because ComInterface is imported
193-
let persist_file: IPersistFile = shell_link.cast()?;
194-
195-
let path_hstring = HSTRING::from(lnk_path.as_os_str());
196-
persist_file.Load(&path_hstring, STGM_READ)?;
197-
198-
// Allocate a buffer to hold the resolved target path
199-
let mut target_path = [0u16; MAX_PATH as usize];
200-
shell_link.GetPath(&mut target_path, std::ptr::null_mut(), 0)?;
201-
202-
// Convert the UTF-16 C-string back to a standard Rust String
203-
let path_string = PWSTR::from_raw(target_path.as_mut_ptr()).to_string()?;
204-
205-
Ok(path_string)
206-
}
207-
}

0 commit comments

Comments
 (0)