@@ -10,7 +10,10 @@ use windows::{
1010} ;
1111
1212use crate :: {
13- error:: ResultLogExt , modules:: system_tray:: application:: util:: Util , windows_api:: WindowsApi ,
13+ error:: { Result , ResultLogExt } ,
14+ modules:: system_tray:: application:: util:: Util ,
15+ utils:: constants:: SEELEN_COMMON ,
16+ windows_api:: WindowsApi ,
1417} ;
1518
1619// ============================================================================
@@ -37,7 +40,7 @@ pub struct TrayHookLoader {
3740impl TrayHookLoader {
3841 /// Creates a new loader, loads the DLL and installs the hook
3942 /// Events will be sent automatically through AppIpc
40- pub fn new ( ) -> crate :: Result < Self > {
43+ pub fn new ( ) -> Result < Self > {
4144 let dll_path = Self :: get_dll_path ( ) ?;
4245 let dll_handle = Self :: load_dll ( & dll_path) ?;
4346 let call_msg_proc = Self :: get_proc_address :: < GetMsgProcFn > ( dll_handle, "CallWndProc" ) ?;
@@ -65,25 +68,41 @@ impl TrayHookLoader {
6568 } )
6669 }
6770
68- /// Gets the DLL path
69- fn get_dll_path ( ) -> crate :: Result < PathBuf > {
71+ /// Gets the DLL path, copying it to SEELEN_COMMON temp directory to avoid
72+ /// permission issues with MSIX installations (WindowsApps folder is restricted)
73+ fn get_dll_path ( ) -> Result < PathBuf > {
7074 let exe_path = std:: env:: current_exe ( ) ?;
7175 let exe_dir = exe_path
7276 . parent ( )
7377 . ok_or ( "Failed to get executable directory" ) ?;
7478
7579 // The DLL should be in the same directory as the executable
76- let dll_path = exe_dir. join ( "sluhk.dll" ) ;
77-
78- if !dll_path. exists ( ) {
79- return Err ( format ! ( "DLL not found at: {}" , dll_path. display( ) ) . into ( ) ) ;
80+ let source_dll_path = exe_dir. join ( "sluhk.dll" ) ;
81+ if !source_dll_path. exists ( ) {
82+ return Err ( format ! ( "DLL not found at: {}" , source_dll_path. display( ) ) . into ( ) ) ;
8083 }
8184
82- Ok ( dll_path)
85+ // Copy to temp directory to ensure accessibility for hooks
86+ // (MSIX installations in WindowsApps have restricted permissions)
87+ let temp_dir = SEELEN_COMMON . app_temp_dir ( ) ;
88+ std:: fs:: create_dir_all ( temp_dir) ?;
89+ let target_dll_path = temp_dir. join ( "sluhk.dll" ) ;
90+
91+ // Use read & write instead of copy to avoid encryption issues on MSIX/APPX
92+ // when copying across different volumes (e.g., S: to C:)
93+ let content = std:: fs:: read ( & source_dll_path) ?;
94+ std:: fs:: write ( & target_dll_path, content) ?;
95+ log:: info!(
96+ "Tray hook DLL copied from {} to {}" ,
97+ source_dll_path. display( ) ,
98+ target_dll_path. display( )
99+ ) ;
100+
101+ Ok ( target_dll_path)
83102 }
84103
85104 /// Loads the DLL into memory
86- fn load_dll ( path : & Path ) -> crate :: Result < HMODULE > {
105+ fn load_dll ( path : & Path ) -> Result < HMODULE > {
87106 let path_wide: Vec < u16 > = path
88107 . to_string_lossy ( )
89108 . encode_utf16 ( )
@@ -97,7 +116,7 @@ impl TrayHookLoader {
97116 }
98117
99118 /// Gets the address of an exported function
100- fn get_proc_address < F > ( dll_handle : HMODULE , name : & str ) -> crate :: Result < F > {
119+ fn get_proc_address < F > ( dll_handle : HMODULE , name : & str ) -> Result < F > {
101120 let name_cstr = std:: ffi:: CString :: new ( name)
102121 . map_err ( |e| format ! ( "Invalid function name '{}': {}" , name, e) ) ?;
103122
0 commit comments