@@ -7,17 +7,18 @@ use tauri::{command, AppHandle, Runtime};
77
88#[ cfg( target_os = "windows" ) ]
99use 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 {
5657pub ( 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) ->
10299pub ( 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