use std::io;
use std::os::windows::ffi::OsStrExt;
use std::ptr;
use std::ffi;
use crate::inner_raw as raw;
use self::raw::winapi::*;
use crate::utils;
pub fn is_visible(window: HWND) -> bool {
return unsafe {IsWindowVisible(window) != 0};
}
pub fn get_class(window: HWND) -> io::Result<String> {
const BUF_SIZE: usize = 512;
let mut buff: [u16; BUF_SIZE] = [0; BUF_SIZE];
let writ_chars = unsafe { RealGetWindowClassW(window,
buff.as_mut_ptr(),
BUF_SIZE as u32) };
if writ_chars == 0 {
return Err(utils::get_last_error());
}
Ok(String::from_utf16_lossy(&buff[0..writ_chars as usize]))
}
pub fn get_text(window: HWND) -> io::Result<String> {
const BUF_SIZE: usize = 512;
let mut buff: [u16; BUF_SIZE] = [0; BUF_SIZE];
let writ_chars = unsafe { GetWindowTextW(window,
buff.as_mut_ptr(),
BUF_SIZE as i32) };
if writ_chars == 0 {
return Err(utils::get_last_error());
}
Ok(String::from_utf16_lossy(&buff[0..writ_chars as usize]))
}
unsafe extern "system" fn callback_enum_windows<T: FnMut(HWND)>(window: HWND, param: LPARAM) -> i32 {
let func = &mut *(param as *mut T);
func(window);
1
}
unsafe extern "system" fn callback_enum_windows_until<T: FnMut(HWND) -> i32>(window: HWND, param: LPARAM) -> i32 {
let func = &mut *(param as *mut T);
func(window)
}
pub fn enum_by<T: FnMut(HWND)>(parent: Option<HWND>, mut cmp_func: T) -> io::Result<()> {
let lparam = &mut cmp_func as *mut _ as LPARAM;
let result: i32;
if let Some(parent_window) = parent {
result = unsafe { EnumChildWindows(parent_window, Some(callback_enum_windows::<T>), lparam) };
}
else {
result = unsafe { EnumWindows(Some(callback_enum_windows::<T>), lparam) };
}
if result == 0 {
return Err(utils::get_last_error());
}
Ok(())
}
pub fn enum_by_until<T: FnMut(HWND) -> i32>(parent: Option<HWND>, mut cmp_func: T) -> io::Result<()> {
let lparam = &mut cmp_func as *mut _ as LPARAM;
let result: i32;
if let Some(parent_window) = parent {
result = unsafe { EnumChildWindows(parent_window, Some(callback_enum_windows_until::<T>), lparam) };
}
else {
result = unsafe { EnumWindows(Some(callback_enum_windows_until::<T>), lparam) };
}
if result == 0 {
let error = utils::get_last_error();
if let Some(errno) = error.raw_os_error() {
if errno != 0 {
return Err(utils::get_last_error());
}
}
}
Ok(())
}
pub fn get_by_pid(pid: u32) -> io::Result<Option<HWND>> {
let mut found_window: Option<HWND> = None;
let res = enum_by_until(None,
|handle: HWND| {
let (process_pid, _) = get_thread_process_id(handle);
if process_pid == pid {
found_window = Some(handle);
return 0;
}
1
});
if let Err(error) = res {
Err(error)
}
else {
Ok(found_window)
}
}
pub fn get_by_class(class_name: &str, parent: Option<HWND>) -> io::Result<Vec<HWND>> {
let mut found_windows: Vec<HWND> = vec![];
let res = enum_by(parent,
|handle: HWND| {
if let Ok(window_class) = get_class(handle) {
if window_class == class_name {
found_windows.push(handle);
}
}
});
if let Err(error) = res {
Err(error)
}
else {
Ok(found_windows)
}
}
pub fn get_by_title(name: &str, parent: Option<HWND>) -> io::Result<Vec<HWND>> {
let mut found_windows: Vec<HWND> = vec![];
let res = enum_by(parent,
|handle: HWND| {
if let Ok(window_title) = get_text(handle) {
if window_title == name {
found_windows.push(handle);
}
}
});
if let Err(error) = res {
Err(error)
}
else {
Ok(found_windows)
}
}
pub fn get_thread_process_id(window: HWND) -> (u32, u32) {
let mut process_pid: u32 = 0;
let thread_pid = unsafe {GetWindowThreadProcessId(window, &mut process_pid)};
(process_pid, thread_pid)
}
pub fn find<T: AsRef<ffi::OsStr>>(class_name: T, window_name: Option<T>) -> io::Result<HWND> {
let result: HWND;
let mut class_name: Vec<u16> = class_name.as_ref().encode_wide().collect();
class_name.push(0);
let class_name = class_name.as_ptr() as *const u16;
if let Some(window_name) = window_name {
let mut window_name: Vec<u16> = window_name.as_ref().encode_wide().collect();
window_name.push(0);
let window_name = window_name.as_ptr() as *const u16;
result = unsafe {FindWindowW(class_name, window_name)};
}
else {
result = unsafe {FindWindowW(class_name, ptr::null())};
}
if result.is_null() {
return Err(utils::get_last_error());
}
Ok(result)
}
pub fn find_child<T: AsRef<ffi::OsStr>>(class_name: T,
window_name: Option<T>,
parent: Option<HWND>,
child_after: Option<HWND>) -> io::Result<HWND> {
let result: HWND;
let mut class_name: Vec<u16> = class_name.as_ref().encode_wide().collect();
class_name.push(0);
let class_name = class_name.as_ptr() as *const u16;
let parent = parent.unwrap_or(0x0 as HWND);
let child_after = child_after.unwrap_or(0x0 as HWND);
if let Some(window_name) = window_name {
let mut window_name: Vec<u16> = window_name.as_ref().encode_wide().collect();
window_name.push(0);
let window_name = window_name.as_ptr() as *const u16;
result = unsafe {FindWindowExW(parent, child_after, class_name, window_name)};
}
else {
result = unsafe {FindWindowExW(parent, child_after, class_name, ptr::null())};
}
if result.is_null() {
return Err(utils::get_last_error());
}
Ok(result)
}
pub fn send_message(window: HWND,
msg_type: UINT,
w_param: WPARAM,
l_param: LPARAM,
timeout: Option<UINT>) -> io::Result<LRESULT> {
if let Some(timeout) = timeout {
unsafe {
let mut result: ULONG_PTR = 0;
let result_ptr = &mut result as PDWORD_PTR;
if SendMessageTimeoutW(window, msg_type, w_param, l_param, SMTO_BLOCK, timeout, result_ptr) == 0 {
return Err(utils::get_last_error());
}
Ok(result as LRESULT)
}
}
else {
unsafe {
Ok(SendMessageW(window, msg_type, w_param, l_param))
}
}
}
const BM_CLICK: c_uint = 0x00F5;
pub fn send_push_button(window: HWND, timeout: Option<UINT>) -> io::Result<LRESULT> {
send_message(window, BM_CLICK, 0, 0, timeout)
}
pub fn send_set_text<T: AsRef<ffi::OsStr>>(window: HWND, text: T) -> bool {
let mut text: Vec<u16> = text.as_ref().encode_wide().collect();
text.push(0);
let text = text.as_ptr() as *const u16 as LPARAM;
let result = send_message(window, WM_SETTEXT, 0, text, None);
result.is_ok() && result.unwrap() != 0
}
pub fn send_get_text(window: HWND) -> Option<String> {
let buf_len = send_message(window, WM_GETTEXTLENGTH, 0, 0, None).unwrap();
if buf_len == 0 {
return None
}
let buf_len = buf_len + 1;
let text: Vec<u16> = vec![0; buf_len as usize];
let text_ptr = text.as_ptr() as *const u16 as LPARAM;
let buf_len = send_message(window, WM_GETTEXT, buf_len as WPARAM, text_ptr, None).unwrap() as usize;
Some(String::from_utf16_lossy(&text[..buf_len]))
}
pub fn send_sys_command(window: HWND, cmd_type: WPARAM, l_param: LPARAM) -> bool {
let result = send_message(window, WM_SYSCOMMAND, cmd_type, l_param, None);
result.is_ok() && result.unwrap() == 0
}
#[inline]
pub fn get_active() -> HWND {
unsafe {
GetActiveWindow()
}
}
#[inline]
pub fn get_console() -> HWND {
unsafe {
GetConsoleWindow()
}
}
pub struct Builder {
ex_style: DWORD,
class_name: Option<Vec<u16>>,
window_name: Option<Vec<u16>>,
style: DWORD,
position: (c_int, c_int),
width: c_int,
height: c_int,
parent: HWND,
menu: HMENU,
inst: HINSTANCE,
param: Option<CREATESTRUCTW>
}
impl Builder {
pub fn new() -> Builder {
Builder {
ex_style: 0,
class_name: None,
window_name: None,
style: 0,
position: (CW_USEDEFAULT, CW_USEDEFAULT),
width: CW_USEDEFAULT,
height: CW_USEDEFAULT,
parent: ptr::null_mut(),
menu: ptr::null_mut(),
inst: ptr::null_mut(),
param: None
}
}
pub fn style(&mut self, value: DWORD) -> &mut Builder {
self.style = value;
self
}
pub fn ex_style(&mut self, value: DWORD) -> &mut Builder {
self.ex_style = value;
self
}
pub fn class_name<T: AsRef<ffi::OsStr>>(&mut self, value: T) -> &mut Builder {
let mut class_name: Vec<u16> = value.as_ref().encode_wide().collect();
class_name.push(0);
self.class_name = Some(class_name);
self
}
pub fn window_name<T: AsRef<ffi::OsStr>>(&mut self, value: T) -> &mut Builder {
let mut window_name: Vec<u16> = value.as_ref().encode_wide().collect();
window_name.push(0);
self.window_name = Some(window_name);
self
}
pub fn position(&mut self, x: c_int, y: c_int) -> &mut Builder {
self.position.0 = x;
self.position.1 = y;
self
}
pub fn size(&mut self, width: c_int, height: c_int) -> &mut Builder {
self.width = width;
self.height = height;
self
}
pub fn parent(&mut self, value: HWND) -> &mut Builder {
self.parent = value;
self
}
pub fn parent_message(&mut self) -> &mut Builder {
self.parent = HWND_MESSAGE;
self
}
pub fn instance(&mut self, value: HINSTANCE) -> &mut Builder {
self.inst = value;
self
}
pub fn param(&mut self, value: &CREATESTRUCTW) -> &mut Builder {
self.param = Some(value.clone());
self
}
pub fn create(&mut self) -> io::Result<HWND> {
let param = self.param.as_mut()
.map(|create_struct| create_struct as *mut CREATESTRUCTW as *mut c_void)
.unwrap_or(ptr::null_mut());
let result = unsafe { CreateWindowExW(self.ex_style,
self.class_name.as_mut().map(|val| val.as_ptr()).unwrap_or(ptr::null()),
self.window_name.as_mut().map(|val| val.as_ptr()).unwrap_or(ptr::null()),
self.style,
self.position.0, self.position.1,
self.width, self.height,
self.parent,
self.menu,
self.inst,
param) };
if result.is_null() {
Err(utils::get_last_error())
}
else {
Ok(result)
}
}
}
pub fn show(window: HWND, cmd: c_int) -> bool {
unsafe {
ShowWindow(window, cmd) != 0
}
}
#[inline]
pub fn destroy(window: HWND) -> bool {
unsafe {
DestroyWindow(window) != 0
}
}