@@ -9,14 +9,14 @@ use tauri::command;
99
1010#[ cfg( target_os = "windows" ) ]
1111use 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