#![cfg(windows)]
#![warn(missing_docs)]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::not_unsafe_ptr_arg_deref))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::derivable_impls))]
pub mod sys;
use std::ffi;
use core::{ptr, mem, convert};
#[path="raw/mod.rs"]
mod inner_raw;
pub mod utils;
pub mod ui;
pub use utils::{ErrorCode, Result};
pub mod raw {
pub use super::inner_raw::process;
pub use super::inner_raw::window;
pub use super::inner_raw::message;
pub use super::inner_raw::file;
pub use super::inner_raw::memory;
pub use super::inner_raw::module;
pub use super::inner_raw::timer;
}
use sys::{
HANDLE,
HWND,
UINT,
WPARAM,
LPARAM,
LRESULT,
MSG,
c_uint,
c_ulong,
c_void,
c_uchar,
SW_SHOW,
SW_HIDE
};
pub struct Process {
pid: u32,
inner: HANDLE,
}
impl Process {
pub fn open(pid: u32, access_rights: u32) -> utils::Result<Process> {
match raw::process::open(pid, access_rights) {
Ok(handle) => Ok(Process {
pid: pid,
inner: handle,
}),
Err(error) => Err(error),
}
}
pub fn from_raw(handle: HANDLE) -> Self {
Process {
pid: raw::process::get_id(handle),
inner: handle
}
}
#[inline]
pub fn inner(&self) -> HANDLE {
self.inner
}
#[inline]
pub fn into_inner(self) -> HANDLE {
let result = self.inner;
mem::forget(self);
result
}
#[inline]
pub fn exe_path(&self) -> Result<String> {
raw::process::get_exe_path(self.inner)
}
#[inline]
pub fn window(&self) -> Result<Option<HWND>> {
raw::window::get_by_pid(self.pid)
}
#[inline]
pub fn read_memory(&self, base_addr: usize, storage: &mut [u8]) -> Result<()> {
raw::process::read_memory(self.inner, base_addr, storage)
}
#[inline]
pub fn write_memory(&self, base_addr: usize, data: &[u8]) -> Result<()> {
raw::process::write_memory(self.inner, base_addr, data)
}
pub fn close(&mut self) {
if !self.inner.is_null() {
raw::process::close(self.inner).expect("Unable to close process");
self.inner = ptr::null_mut();
}
}
pub fn terminate(self, exit_code: c_uint) -> Result<()> {
raw::process::terminate(self.inner, exit_code).map(|_| {
let _ = self.into_inner();
})
}
}
impl Drop for Process {
fn drop(&mut self) {
self.close()
}
}
pub struct Msg {
inner: MSG
}
impl Msg {
pub fn new(message: MSG) -> Msg {
Msg {
inner: message
}
}
#[inline]
pub fn id(&self) -> UINT {
self.inner.message
}
#[inline]
pub fn as_ptr(&self) -> *const MSG {
&self.inner as *const MSG
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut MSG {
&mut self.inner as *mut MSG
}
#[inline]
pub fn inner(&self) -> MSG {
self.inner
}
#[inline]
pub fn into_inner(self) -> MSG {
let result = self.inner;
mem::forget(self);
result
}
#[inline]
pub fn dispatch(self) {
drop(self);
}
}
impl Drop for Msg {
fn drop(&mut self) {
raw::message::translate(self.as_mut_ptr());
raw::message::dispatch(self.as_mut_ptr());
}
}
pub struct Messages {
window: Option<HWND>,
range: (Option<UINT>, Option<UINT>),
is_block: bool
}
impl Messages {
pub fn new() -> Messages {
Messages {
window: None,
range: (None, None),
is_block: true
}
}
pub fn window(&mut self, window: Option<HWND>) -> &mut Messages {
self.window = window;
self
}
pub fn low(&mut self, low: Option<UINT>) -> &mut Messages {
self.range.0 = low;
self
}
pub fn high(&mut self, high: Option<UINT>) -> &mut Messages {
self.range.1 = high;
self
}
pub fn blocking(&mut self) -> &mut Messages {
self.is_block = true;
self
}
pub fn non_blocking(&mut self) -> &mut Messages {
self.is_block = false;
self
}
}
impl Iterator for Messages {
type Item = Result<Msg>;
fn next(&mut self) -> Option<Self::Item> {
if self.is_block {
Some(raw::message::get(self.window, self.range.0, self.range.1).map(|msg| Msg::new(msg)))
}
else {
match raw::message::peek(self.window, self.range.0, self.range.1, Some(0x0001)) {
Ok(Some(msg)) => Some(Ok(Msg::new(msg))),
Ok(None) => None,
Err(error) => Some(Err(error))
}
}
}
}
pub struct Window {
inner: HWND
}
impl Window {
#[inline]
pub fn from_hwnd(window: HWND) -> Self {
Window { inner: window }
}
#[inline]
pub fn from_builder(builder: &mut raw::window::Builder) -> Result<Self> {
builder.create().map(|win| Window::from_hwnd(win))
}
#[inline]
pub fn inner(&self) -> HWND {
self.inner
}
#[inline]
pub fn into_inner(self) -> HWND {
let result = self.inner;
mem::forget(self);
result
}
#[inline]
pub fn show(&self) -> bool {
!raw::window::show(self.inner, SW_SHOW)
}
#[inline]
pub fn hide(&self) -> bool {
raw::window::show(self.inner, SW_HIDE)
}
#[inline]
pub fn is_visible(&self) -> bool {
raw::window::is_visible(self.inner)
}
#[inline]
pub fn class(&self) -> Result<String> {
raw::window::get_class(self.inner)
}
#[inline]
pub fn title(&self) -> Result<String> {
raw::window::get_text(self.inner)
}
#[inline]
pub fn thread_pid(&self) -> (u32, u32) {
raw::window::get_thread_process_id(self.inner)
}
#[inline]
pub fn send_message(&self, msg_type: UINT, w_param: WPARAM, l_param: LPARAM, timeout: Option<UINT>) -> Result<LRESULT> {
raw::window::send_message(self.inner, msg_type, w_param, l_param, timeout)
}
#[inline]
pub fn send_push_button(&self, timeout: Option<UINT>) -> Result<LRESULT> {
raw::window::send_push_button(self.inner, timeout)
}
#[inline]
pub fn send_set_text<T: AsRef<ffi::OsStr>>(&self, text: T) -> bool {
raw::window::send_set_text(self.inner, text)
}
#[inline]
pub fn send_get_text(&self) -> Option<String> {
raw::window::send_get_text(self.inner)
}
#[inline]
pub fn send_sys_command(&self, cmd_type: WPARAM, l_param: LPARAM) -> bool {
raw::window::send_sys_command(self.inner, cmd_type, l_param)
}
#[inline]
pub fn destroy(self) {
drop(self);
}
}
impl convert::From<HWND> for Window {
fn from(window: HWND) -> Window {
Window { inner: window }
}
}
impl convert::Into<HWND> for Window {
fn into(self) -> HWND {
self.into_inner()
}
}
impl Drop for Window {
fn drop(&mut self) {
raw::window::destroy(self.inner);
}
}
enum TimerCallbackType {
None,
Raw(raw::timer::CallbackType, *mut c_void),
}
enum TimeoutType {
None,
Single(c_ulong),
Interval(c_ulong),
Both(c_ulong, c_ulong)
}
impl TimeoutType {
fn into_raw(self) -> (c_ulong, c_ulong) {
match self {
TimeoutType::None => (0, 0),
TimeoutType::Single(delay) => (delay, 0),
TimeoutType::Interval(interval) => (0, interval),
TimeoutType::Both(delay, interval) => (delay, interval),
}
}
}
unsafe extern "system" fn timer_rust_callback(param: *mut c_void, _: c_uchar) {
if !param.is_null() {
let cb: fn() -> () = mem::transmute(param);
cb();
}
}
pub struct TimerBuilder<'a> {
queue: Option<&'a raw::timer::TimerQueue>,
callback: TimerCallbackType,
timeout: TimeoutType,
flags: raw::timer::TimerFlags
}
impl<'a> TimerBuilder<'a> {
pub fn new() -> Self {
Self {
queue: None,
callback: TimerCallbackType::None,
timeout: TimeoutType::None,
flags: raw::timer::DEFAULT_TIMER_FLAGS
}
}
pub fn raw_callback(mut self, cb: raw::timer::CallbackType, param: Option<*mut c_void>) -> Self {
self.callback = TimerCallbackType::Raw(cb, param.unwrap_or(ptr::null_mut()));
self
}
pub fn rust_callback(mut self, cb: fn() -> ()) -> Self {
self.callback = TimerCallbackType::Raw(Some(timer_rust_callback), cb as _ );
self
}
pub fn queue(mut self, queue: &'a raw::timer::TimerQueue) -> Self {
self.queue = Some(queue);
self
}
pub fn single(mut self, delay: c_ulong) -> Self {
self.timeout = match self.timeout {
TimeoutType::Interval(interval) => TimeoutType::Both(delay, interval),
_ => TimeoutType::Single(delay)
};
self
}
pub fn interval(mut self, interval: c_ulong) -> Self {
self.timeout = match self.timeout {
TimeoutType::Single(delay) => TimeoutType::Both(delay, interval),
_ => TimeoutType::Interval(interval)
};
self
}
pub fn flags(mut self, flags: raw::timer::TimerFlags) -> Self {
self.flags = flags;
self
}
pub fn build(self) -> Result<raw::timer::QueueTimer> {
static DEFAULT: raw::timer::TimerQueue = raw::timer::DEFAULT_TIMER_QUEUE;
let queue = self.queue.unwrap_or(&DEFAULT);
let (delay, period) = self.timeout.into_raw();
let (cb, param) = match self.callback {
TimerCallbackType::None => (None, ptr::null_mut()),
TimerCallbackType::Raw(cb, param) => (cb, param),
};
queue.timer(cb, param, delay, period, self.flags)
}
}