1use std::ffi;
4use std::os::windows::ffi::OsStrExt;
5use core::ptr;
6
7use crate::sys::SetLastErrorEx;
8
9use crate::sys::*;
10use crate::utils::{self, Result};
11
12pub fn is_visible(window: HWND) -> bool {
28 return unsafe {IsWindowVisible(window) != 0};
29}
30
31pub fn get_class(window: HWND) -> Result<String> {
42 const BUF_SIZE: usize = 512;
43 let mut buff: [u16; BUF_SIZE] = [0; BUF_SIZE];
44
45 let writ_chars = unsafe { RealGetWindowClassW(window,
46 buff.as_mut_ptr(),
47 BUF_SIZE as u32) };
48
49 if writ_chars == 0 {
50 return Err(utils::get_last_error());
51 }
52
53 Ok(String::from_utf16_lossy(&buff[0..writ_chars as usize]))
54}
55
56pub fn get_text(window: HWND) -> Result<String> {
67 const BUF_SIZE: usize = 512;
68 let mut buff: [u16; BUF_SIZE] = [0; BUF_SIZE];
69
70 let writ_chars = unsafe { GetWindowTextW(window,
71 buff.as_mut_ptr(),
72 BUF_SIZE as i32) };
73
74 if writ_chars == 0 {
75 return Err(utils::get_last_error());
76 }
77
78 Ok(String::from_utf16_lossy(&buff[0..writ_chars as usize]))
79}
80
81unsafe extern "system" fn callback_enum_windows<T: FnMut(HWND)>(window: HWND, param: LPARAM) -> i32 {
82 let func = &mut *(param as *mut T);
83
84 func(window);
85
86 1
87}
88
89unsafe extern "system" fn callback_enum_windows_until<T: FnMut(HWND) -> i32>(window: HWND, param: LPARAM) -> i32 {
90 let func = &mut *(param as *mut T);
91
92 func(window)
93}
94
95pub fn enum_by<T: FnMut(HWND)>(parent: Option<HWND>, mut cmp_func: T) -> Result<()> {
107 let lparam = &mut cmp_func as *mut _ as LPARAM;
108
109 let result: i32;
110
111 if let Some(parent_window) = parent {
112 result = unsafe { EnumChildWindows(parent_window, Some(callback_enum_windows::<T>), lparam) };
113 }
114 else {
115 result = unsafe { EnumWindows(Some(callback_enum_windows::<T>), lparam) };
116 }
117
118 if result == 0 {
119 return Err(utils::get_last_error());
120 }
121
122 Ok(())
123}
124
125pub fn enum_by_until<T: FnMut(HWND) -> i32>(parent: Option<HWND>, mut cmp_func: T) -> Result<()> {
146 let lparam = &mut cmp_func as *mut _ as LPARAM;
147
148 let result: i32;
149
150 unsafe { SetLastErrorEx(0, 0) };
152 if let Some(parent_window) = parent {
153 result = unsafe { EnumChildWindows(parent_window, Some(callback_enum_windows_until::<T>), lparam) };
154 }
155 else {
156 result = unsafe { EnumWindows(Some(callback_enum_windows_until::<T>), lparam) };
157 }
158
159 if result == 0 {
162 let error = utils::get_last_error();
163
164 if error.raw_code() != 0 {
165 return Err(utils::get_last_error());
166 }
167 }
168
169 Ok(())
170}
171
172pub fn get_by_pid(pid: u32) -> Result<Option<HWND>> {
183 let mut found_window: Option<HWND> = None;
184
185 let res = enum_by_until(None,
186 |handle: HWND| {
187 let (process_pid, _) = get_thread_process_id(handle);
188 if process_pid == pid {
189 found_window = Some(handle);
190 return 0;
191 }
192 1
193 });
194
195 if let Err(error) = res {
196 Err(error)
197 }
198 else {
199 Ok(found_window)
200 }
201
202}
203
204pub fn get_by_class(class_name: &str, parent: Option<HWND>) -> Result<Vec<HWND>> {
216 let mut found_windows: Vec<HWND> = vec![];
217
218 let res = enum_by(parent,
219 |handle: HWND| {
220 if let Ok(window_class) = get_class(handle) {
221 if window_class == class_name {
222 found_windows.push(handle);
223 }
224 }
225 });
226
227 if let Err(error) = res {
228 Err(error)
229 }
230 else {
231 Ok(found_windows)
232 }
233}
234
235pub fn get_by_title(name: &str, parent: Option<HWND>) -> Result<Vec<HWND>> {
247 let mut found_windows: Vec<HWND> = vec![];
248
249 let res = enum_by(parent,
250 |handle: HWND| {
251 if let Ok(window_title) = get_text(handle) {
252 if window_title == name {
253 found_windows.push(handle);
254 }
255 }
256 });
257
258 if let Err(error) = res {
259 Err(error)
260 }
261 else {
262 Ok(found_windows)
263 }
264}
265
266pub fn get_thread_process_id(window: HWND) -> (u32, u32) {
277 let mut process_pid: u32 = 0;
278 let thread_pid = unsafe {GetWindowThreadProcessId(window, &mut process_pid)};
279
280 (process_pid, thread_pid)
281}
282
283pub fn find<T: AsRef<ffi::OsStr>>(class_name: T, window_name: Option<T>) -> Result<HWND> {
295 let result: HWND;
296 let mut class_name: Vec<u16> = class_name.as_ref().encode_wide().collect();
297 class_name.push(0);
298 let class_name = class_name.as_ptr();
299
300 if let Some(window_name) = window_name {
301 let mut window_name: Vec<u16> = window_name.as_ref().encode_wide().collect();
302 window_name.push(0);
303 let window_name = window_name.as_ptr();
304
305 result = unsafe {FindWindowW(class_name, window_name)};
306 }
307 else {
308 result = unsafe {FindWindowW(class_name, ptr::null())};
309 }
310
311 if result.is_null() {
312 return Err(utils::get_last_error());
313 }
314
315 Ok(result)
316}
317
318pub fn find_child<T: AsRef<ffi::OsStr>>(class_name: T,
332 window_name: Option<T>,
333 parent: Option<HWND>,
334 child_after: Option<HWND>) -> Result<HWND> {
335 let result: HWND;
336 let mut class_name: Vec<u16> = class_name.as_ref().encode_wide().collect();
337 class_name.push(0);
338 let class_name = class_name.as_ptr();
339
340 let parent = parent.unwrap_or(0x0 as HWND);
341 let child_after = child_after.unwrap_or(0x0 as HWND);
342
343 if let Some(window_name) = window_name {
344 let mut window_name: Vec<u16> = window_name.as_ref().encode_wide().collect();
345 window_name.push(0);
346 let window_name = window_name.as_ptr();
347
348 result = unsafe {FindWindowExW(parent, child_after, class_name, window_name)};
349 }
350 else {
351 result = unsafe {FindWindowExW(parent, child_after, class_name, ptr::null())};
352 }
353
354 if result.is_null() {
355 return Err(utils::get_last_error());
356 }
357
358 Ok(result)
359}
360
361pub fn send_message(window: HWND,
381 msg_type: UINT,
382 w_param: WPARAM,
383 l_param: LPARAM,
384 timeout: Option<UINT>) -> Result<LRESULT> {
385 if let Some(timeout) = timeout {
386 unsafe {
387 let mut result: ULONG_PTR = 0;
388 let result_ptr = &mut result as PDWORD_PTR;
389 if SendMessageTimeoutW(window, msg_type, w_param, l_param, SMTO_BLOCK, timeout, result_ptr) == 0 {
390 return Err(utils::get_last_error());
391 }
392 Ok(result as LRESULT)
393 }
394 }
395 else {
396 unsafe {
397 Ok(SendMessageW(window, msg_type, w_param, l_param))
398 }
399 }
400}
401
402const BM_CLICK: c_uint = 0x00F5;
404
405pub fn send_push_button(window: HWND, timeout: Option<UINT>) -> Result<LRESULT> {
412 send_message(window, BM_CLICK, 0, 0, timeout)
413}
414
415pub fn send_set_text<T: AsRef<ffi::OsStr>>(window: HWND, text: T) -> bool {
427 let mut text: Vec<u16> = text.as_ref().encode_wide().collect();
428 text.push(0);
429 let text = text.as_ptr() as LPARAM;
430
431 let result = send_message(window, WM_SETTEXT, 0, text, None);
432 result.is_ok() && result.unwrap() != 0
433}
434
435pub fn send_get_text(window: HWND) -> Option<String> {
446 let buf_len = send_message(window, WM_GETTEXTLENGTH, 0, 0, None).unwrap();
448
449 if buf_len == 0 {
450 return None
451 }
452
453 let buf_len = buf_len + 1;
454
455 let text: Vec<u16> = vec![0; buf_len as usize];
456 let text_ptr = text.as_ptr() as LPARAM;
457 let buf_len = send_message(window, WM_GETTEXT, buf_len as WPARAM, text_ptr, None).unwrap() as usize;
459
460 Some(String::from_utf16_lossy(&text[..buf_len]))
461}
462
463pub fn send_sys_command(window: HWND, cmd_type: WPARAM, l_param: LPARAM) -> bool {
478 let result = send_message(window, WM_SYSCOMMAND, cmd_type, l_param, None);
479 result.is_ok() && result.unwrap() == 0
481}
482
483#[inline]
484pub fn get_active() -> HWND {
486 unsafe {
487 GetActiveWindow()
488 }
489}
490
491#[inline]
492pub fn get_console() -> HWND {
494 unsafe {
495 GetConsoleWindow()
496 }
497}
498
499pub struct Builder {
504 ex_style: DWORD,
505 class_name: Option<Vec<u16>>,
506 window_name: Option<Vec<u16>>,
507 style: DWORD,
508 position: (c_int, c_int),
509 width: c_int,
510 height: c_int,
511 parent: HWND,
512 menu: HMENU,
513 inst: HINSTANCE,
514 param: Option<CREATESTRUCTW>
515}
516
517impl Builder {
518 pub fn new() -> Builder {
520 Builder {
521 ex_style: 0,
522 class_name: None,
523 window_name: None,
524 style: 0,
525 position: (CW_USEDEFAULT, CW_USEDEFAULT),
526 width: CW_USEDEFAULT,
527 height: CW_USEDEFAULT,
528 parent: ptr::null_mut(),
529 menu: ptr::null_mut(),
530 inst: ptr::null_mut(),
531 param: None
532 }
533 }
534
535 pub fn style(&mut self, value: DWORD) -> &mut Builder {
539 self.style = value;
540 self
541 }
542
543 pub fn ex_style(&mut self, value: DWORD) -> &mut Builder {
547 self.ex_style = value;
548 self
549 }
550
551 pub fn class_name<T: AsRef<ffi::OsStr>>(&mut self, value: T) -> &mut Builder {
553 let mut class_name: Vec<u16> = value.as_ref().encode_wide().collect();
554 class_name.push(0);
555 self.class_name = Some(class_name);
556 self
557 }
558
559 pub fn window_name<T: AsRef<ffi::OsStr>>(&mut self, value: T) -> &mut Builder {
561 let mut window_name: Vec<u16> = value.as_ref().encode_wide().collect();
562 window_name.push(0);
563 self.window_name = Some(window_name);
564 self
565 }
566
567 pub fn position(&mut self, x: c_int, y: c_int) -> &mut Builder {
569 self.position.0 = x;
570 self.position.1 = y;
571 self
572 }
573
574 pub fn size(&mut self, width: c_int, height: c_int) -> &mut Builder {
576 self.width = width;
577 self.height = height;
578 self
579 }
580
581 pub fn parent(&mut self, value: HWND) -> &mut Builder {
583 self.parent = value;
584 self
585 }
586
587 pub fn parent_message(&mut self) -> &mut Builder {
589 self.parent = HWND_MESSAGE;
590 self
591 }
592
593 pub fn instance(&mut self, value: HINSTANCE) -> &mut Builder {
595 self.inst = value;
596 self
597 }
598
599 pub fn param(&mut self, value: &CREATESTRUCTW) -> &mut Builder {
601 self.param = Some(*value);
602 self
603 }
604
605 pub fn create(&mut self) -> Result<HWND> {
607 let param = self.param.as_mut()
608 .map(|create_struct| create_struct as *mut CREATESTRUCTW as *mut c_void)
609 .unwrap_or(ptr::null_mut());
610
611 let result = unsafe { CreateWindowExW(self.ex_style,
612 self.class_name.as_mut().map(|val| val.as_ptr()).unwrap_or(ptr::null()),
613 self.window_name.as_mut().map(|val| val.as_ptr()).unwrap_or(ptr::null()),
614 self.style,
615 self.position.0, self.position.1,
616 self.width, self.height,
617 self.parent,
618 self.menu,
619 self.inst,
620 param) };
621
622 if result.is_null() {
623 Err(utils::get_last_error())
624 }
625 else {
626 Ok(result)
627 }
628 }
629}
630
631pub fn show(window: HWND, cmd: c_int) -> bool {
638 unsafe {
639 ShowWindow(window, cmd) != 0
640 }
641}
642
643#[inline]
647pub fn destroy(window: HWND) -> bool {
648 unsafe {
649 DestroyWindow(window) != 0
650 }
651}