@@ -20,18 +20,38 @@ use windows_sys::Win32::{
20
20
} ,
21
21
UI :: WindowsAndMessaging :: {
22
22
self as w32wm, CreateWindowExW , DefWindowProcW , DestroyWindow , FindWindowW ,
23
- RegisterClassExW , SendMessageW , GWL_STYLE , GWL_USERDATA , WINDOW_LONG_PTR_INDEX ,
24
- WM_COPYDATA , WM_DESTROY , WNDCLASSEXW , WS_EX_LAYERED , WS_EX_NOACTIVATE , WS_EX_TOOLWINDOW ,
25
- WS_EX_TRANSPARENT , WS_OVERLAPPED , WS_POPUP , WS_VISIBLE ,
23
+ RegisterClassExW , SendMessageW , CREATESTRUCTW , GWLP_USERDATA , GWL_STYLE ,
24
+ WINDOW_LONG_PTR_INDEX , WM_COPYDATA , WM_CREATE , WM_DESTROY , WNDCLASSEXW , WS_EX_LAYERED ,
25
+ WS_EX_NOACTIVATE , WS_EX_TOOLWINDOW , WS_EX_TRANSPARENT , WS_OVERLAPPED , WS_POPUP , WS_VISIBLE ,
26
26
} ,
27
27
} ;
28
28
29
+ const WMCOPYDATA_SINGLE_INSTANCE_DATA : usize = 1542 ;
30
+
29
31
struct MutexHandle ( isize ) ;
32
+
30
33
struct TargetWindowHandle ( isize ) ;
31
34
32
- const WMCOPYDATA_SINGLE_INSTANCE_DATA : usize = 1542 ;
35
+ struct UserData < R : Runtime > {
36
+ app : AppHandle < R > ,
37
+ callback : Box < SingleInstanceCallback < R > > ,
38
+ }
39
+
40
+ impl < R : Runtime > UserData < R > {
41
+ unsafe fn from_hwnd_raw ( hwnd : HWND ) -> * mut Self {
42
+ GetWindowLongPtrW ( hwnd, GWLP_USERDATA ) as * mut Self
43
+ }
33
44
34
- pub fn init < R : Runtime > ( f : Box < SingleInstanceCallback < R > > ) -> TauriPlugin < R > {
45
+ unsafe fn from_hwnd < ' a > ( hwnd : HWND ) -> & ' a mut Self {
46
+ & mut * Self :: from_hwnd_raw ( hwnd)
47
+ }
48
+
49
+ fn run_callback ( & mut self , args : Vec < String > , cwd : String ) {
50
+ ( self . callback ) ( & self . app , args, cwd)
51
+ }
52
+ }
53
+
54
+ pub fn init < R : Runtime > ( callback : Box < SingleInstanceCallback < R > > ) -> TauriPlugin < R > {
35
55
plugin:: Builder :: new ( "single-instance" )
36
56
. setup ( |app, _api| {
37
57
#[ allow( unused_mut) ]
@@ -54,37 +74,35 @@ pub fn init<R: Runtime>(f: Box<SingleInstanceCallback<R>>) -> TauriPlugin<R> {
54
74
let hwnd = FindWindowW ( class_name. as_ptr ( ) , window_name. as_ptr ( ) ) ;
55
75
56
76
if !hwnd. is_null ( ) {
57
- let data = format ! (
58
- "{}|{}\0 " ,
59
- std:: env:: current_dir( )
60
- . unwrap_or_default( )
61
- . to_str( )
62
- . unwrap_or_default( ) ,
63
- std:: env:: args( ) . collect:: <Vec <String >>( ) . join( "|" )
64
- ) ;
77
+ let cwd = std:: env:: current_dir ( ) . unwrap_or_default ( ) ;
78
+ let cwd = cwd. to_str ( ) . unwrap_or_default ( ) ;
79
+
80
+ let args = std:: env:: args ( ) . collect :: < Vec < String > > ( ) . join ( "|" ) ;
81
+
82
+ let data = format ! ( "{cwd}|{args}\0 " , ) ;
83
+
65
84
let bytes = data. as_bytes ( ) ;
66
85
let cds = COPYDATASTRUCT {
67
86
dwData : WMCOPYDATA_SINGLE_INSTANCE_DATA ,
68
87
cbData : bytes. len ( ) as _ ,
69
88
lpData : bytes. as_ptr ( ) as _ ,
70
89
} ;
90
+
71
91
SendMessageW ( hwnd, WM_COPYDATA , 0 , & cds as * const _ as _ ) ;
92
+
72
93
app. cleanup_before_exit ( ) ;
73
94
std:: process:: exit ( 0 ) ;
74
95
}
75
96
}
76
97
} else {
77
98
app. manage ( MutexHandle ( hmutex as _ ) ) ;
78
99
79
- let hwnd = create_event_target_window :: < R > ( & class_name, & window_name) ;
80
- unsafe {
81
- SetWindowLongPtrW (
82
- hwnd,
83
- GWL_USERDATA ,
84
- Box :: into_raw ( Box :: new ( ( app. clone ( ) , f) ) ) as _ ,
85
- )
100
+ let userdata = UserData {
101
+ app : app. clone ( ) ,
102
+ callback,
86
103
} ;
87
-
104
+ let userdata = Box :: into_raw ( Box :: new ( userdata) ) ;
105
+ let hwnd = create_event_target_window :: < R > ( & class_name, & window_name, userdata) ;
88
106
app. manage ( TargetWindowHandle ( hwnd as _ ) ) ;
89
107
}
90
108
@@ -116,37 +134,43 @@ unsafe extern "system" fn single_instance_window_proc<R: Runtime>(
116
134
wparam : WPARAM ,
117
135
lparam : LPARAM ,
118
136
) -> LRESULT {
119
- let data_ptr = GetWindowLongPtrW ( hwnd, GWL_USERDATA )
120
- as * mut ( AppHandle < R > , Box < SingleInstanceCallback < R > > ) ;
121
-
122
- if data_ptr. is_null ( ) {
123
- return DefWindowProcW ( hwnd, msg, wparam, lparam) ;
124
- }
125
-
126
- let ( app_handle, callback) = & mut * data_ptr;
127
-
128
137
match msg {
138
+ WM_CREATE => {
139
+ let create_struct = & * ( lparam as * const CREATESTRUCTW ) ;
140
+ let userdata = create_struct. lpCreateParams as * const UserData < R > ;
141
+ SetWindowLongPtrW ( hwnd, GWLP_USERDATA , userdata as _ ) ;
142
+ 0
143
+ }
144
+
129
145
WM_COPYDATA => {
130
146
let cds_ptr = lparam as * const COPYDATASTRUCT ;
131
147
if ( * cds_ptr) . dwData == WMCOPYDATA_SINGLE_INSTANCE_DATA {
148
+ let userdata = UserData :: < R > :: from_hwnd ( hwnd) ;
149
+
132
150
let data = CStr :: from_ptr ( ( * cds_ptr) . lpData as _ ) . to_string_lossy ( ) ;
133
151
let mut s = data. split ( '|' ) ;
134
152
let cwd = s. next ( ) . unwrap ( ) ;
135
153
let args = s. map ( |s| s. to_string ( ) ) . collect ( ) ;
136
- callback ( app_handle, args, cwd. to_string ( ) ) ;
154
+
155
+ userdata. run_callback ( args, cwd. to_string ( ) ) ;
137
156
}
138
157
1
139
158
}
140
159
141
160
WM_DESTROY => {
142
- let _ = Box :: from_raw ( data_ptr) ;
161
+ let userdata = UserData :: < R > :: from_hwnd_raw ( hwnd) ;
162
+ drop ( Box :: from_raw ( userdata) ) ;
143
163
0
144
164
}
145
165
_ => DefWindowProcW ( hwnd, msg, wparam, lparam) ,
146
166
}
147
167
}
148
168
149
- fn create_event_target_window < R : Runtime > ( class_name : & [ u16 ] , window_name : & [ u16 ] ) -> HWND {
169
+ fn create_event_target_window < R : Runtime > (
170
+ class_name : & [ u16 ] ,
171
+ window_name : & [ u16 ] ,
172
+ userdata : * const UserData < R > ,
173
+ ) -> HWND {
150
174
unsafe {
151
175
let class = WNDCLASSEXW {
152
176
cbSize : std:: mem:: size_of :: < WNDCLASSEXW > ( ) as u32 ,
@@ -187,7 +211,7 @@ fn create_event_target_window<R: Runtime>(class_name: &[u16], window_name: &[u16
187
211
std:: ptr:: null_mut ( ) ,
188
212
std:: ptr:: null_mut ( ) ,
189
213
GetModuleHandleW ( std:: ptr:: null ( ) ) ,
190
- std :: ptr :: null ( ) ,
214
+ userdata as _ ,
191
215
) ;
192
216
SetWindowLongPtrW (
193
217
hwnd,
0 commit comments