1#![cfg(windows)]
2#![warn(missing_docs)]
8#![cfg_attr(feature = "cargo-clippy", allow(clippy::not_unsafe_ptr_arg_deref))]
9#![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
10#![cfg_attr(feature = "cargo-clippy", allow(clippy::derivable_impls))]
11
12pub mod sys;
13
14use std::ffi;
15use core::{ptr, mem, convert};
16
17#[path="raw/mod.rs"]
18mod inner_raw;
19pub mod utils;
20pub mod ui;
21
22pub use utils::{ErrorCode, Result};
23
24pub mod raw {
25 pub use super::inner_raw::process;
27 pub use super::inner_raw::window;
28 pub use super::inner_raw::message;
29 pub use super::inner_raw::file;
30 pub use super::inner_raw::memory;
31 pub use super::inner_raw::module;
32 pub use super::inner_raw::timer;
33}
34
35use sys::{
36 HANDLE,
37 HWND,
38 UINT,
39 WPARAM,
40 LPARAM,
41 LRESULT,
42 MSG,
43 c_uint,
44 c_ulong,
45 c_void,
46 c_uchar,
47 SW_SHOW,
48 SW_HIDE
49};
50
51pub struct Process {
53 pid: u32,
54 inner: HANDLE,
55}
56
57impl Process {
58 pub fn open(pid: u32, access_rights: u32) -> utils::Result<Process> {
74 match raw::process::open(pid, access_rights) {
75 Ok(handle) => Ok(Process {
76 pid: pid,
77 inner: handle,
78 }),
79 Err(error) => Err(error),
80 }
81 }
82
83 pub fn from_raw(handle: HANDLE) -> Self {
85 Process {
86 pid: raw::process::get_id(handle),
87 inner: handle
88 }
89 }
90
91 #[inline]
92 pub fn inner(&self) -> HANDLE {
94 self.inner
95 }
96
97 #[inline]
98 pub fn into_inner(self) -> HANDLE {
102 let result = self.inner;
103 mem::forget(self);
104 result
105 }
106
107 #[inline]
108 pub fn exe_path(&self) -> Result<String> {
119 raw::process::get_exe_path(self.inner)
120 }
121
122 #[inline]
123 pub fn window(&self) -> Result<Option<HWND>> {
129 raw::window::get_by_pid(self.pid)
130 }
131
132 #[inline]
133 pub fn read_memory(&self, base_addr: usize, storage: &mut [u8]) -> Result<()> {
140 raw::process::read_memory(self.inner, base_addr, storage)
141 }
142
143 #[inline]
144 pub fn write_memory(&self, base_addr: usize, data: &[u8]) -> Result<()> {
156 raw::process::write_memory(self.inner, base_addr, data)
157 }
158
159 pub fn close(&mut self) {
167 if !self.inner.is_null() {
168 raw::process::close(self.inner).expect("Unable to close process");
169 self.inner = ptr::null_mut();
170 }
171 }
172
173 pub fn terminate(self, exit_code: c_uint) -> Result<()> {
177 raw::process::terminate(self.inner, exit_code).map(|_| {
178 let _ = self.into_inner();
179 })
180 }
181}
182
183impl Drop for Process {
184 fn drop(&mut self) {
185 self.close()
186 }
187}
188
189pub struct Msg {
194 inner: MSG
195}
196
197impl Msg {
198 pub fn new(message: MSG) -> Msg {
200 Msg {
201 inner: message
202 }
203 }
204
205 #[inline]
206 pub fn id(&self) -> UINT {
208 self.inner.message
209 }
210
211 #[inline]
212 pub fn as_ptr(&self) -> *const MSG {
214 &self.inner as *const MSG
215 }
216
217 #[inline]
218 pub fn as_mut_ptr(&mut self) -> *mut MSG {
220 &mut self.inner as *mut MSG
221 }
222
223 #[inline]
224 pub fn inner(&self) -> MSG {
228 self.inner
229 }
230
231 #[inline]
232 pub fn into_inner(self) -> MSG {
236 let result = self.inner;
237 mem::forget(self);
238 result
239 }
240
241 #[inline]
242 pub fn dispatch(self) {
245 drop(self);
246 }
247}
248
249impl Drop for Msg {
250 fn drop(&mut self) {
251 raw::message::translate(self.as_mut_ptr());
252 raw::message::dispatch(self.as_mut_ptr());
253 }
254}
255
256pub struct Messages {
265 window: Option<HWND>,
266 range: (Option<UINT>, Option<UINT>),
267 is_block: bool
268}
269
270impl Messages {
271 pub fn new() -> Messages {
273 Messages {
274 window: None,
275 range: (None, None),
276 is_block: true
277 }
278 }
279
280 pub fn window(&mut self, window: Option<HWND>) -> &mut Messages {
282 self.window = window;
283 self
284 }
285
286 pub fn low(&mut self, low: Option<UINT>) -> &mut Messages {
288 self.range.0 = low;
289 self
290 }
291
292 pub fn high(&mut self, high: Option<UINT>) -> &mut Messages {
294 self.range.1 = high;
295 self
296 }
297
298 pub fn blocking(&mut self) -> &mut Messages {
300 self.is_block = true;
301 self
302 }
303
304 pub fn non_blocking(&mut self) -> &mut Messages {
310 self.is_block = false;
311 self
312 }
313}
314
315impl Iterator for Messages {
316 type Item = Result<Msg>;
317
318 fn next(&mut self) -> Option<Self::Item> {
322 if self.is_block {
323 Some(raw::message::get(self.window, self.range.0, self.range.1).map(|msg| Msg::new(msg)))
324 }
325 else {
326 match raw::message::peek(self.window, self.range.0, self.range.1, Some(0x0001)) {
327 Ok(Some(msg)) => Some(Ok(Msg::new(msg))),
328 Ok(None) => None,
329 Err(error) => Some(Err(error))
330 }
331 }
332 }
333}
334
335pub struct Window {
343 inner: HWND
344}
345
346impl Window {
347 #[inline]
348 pub fn from_hwnd(window: HWND) -> Self {
350 Window { inner: window }
351 }
352
353 #[inline]
354 pub fn from_builder(builder: &mut raw::window::Builder) -> Result<Self> {
356 builder.create().map(|win| Window::from_hwnd(win))
357 }
358
359 #[inline]
360 pub fn inner(&self) -> HWND {
364 self.inner
365 }
366
367 #[inline]
368 pub fn into_inner(self) -> HWND {
370 let result = self.inner;
371 mem::forget(self);
372 result
373 }
374
375 #[inline]
376 pub fn show(&self) -> bool {
380 !raw::window::show(self.inner, SW_SHOW)
381 }
382
383 #[inline]
384 pub fn hide(&self) -> bool {
388 raw::window::show(self.inner, SW_HIDE)
389 }
390
391 #[inline]
392 pub fn is_visible(&self) -> bool {
394 raw::window::is_visible(self.inner)
395 }
396
397 #[inline]
398 pub fn class(&self) -> Result<String> {
400 raw::window::get_class(self.inner)
401 }
402
403 #[inline]
404 pub fn title(&self) -> Result<String> {
406 raw::window::get_text(self.inner)
407 }
408
409 #[inline]
410 pub fn thread_pid(&self) -> (u32, u32) {
412 raw::window::get_thread_process_id(self.inner)
413 }
414
415 #[inline]
416 pub fn send_message(&self, msg_type: UINT, w_param: WPARAM, l_param: LPARAM, timeout: Option<UINT>) -> Result<LRESULT> {
420 raw::window::send_message(self.inner, msg_type, w_param, l_param, timeout)
421 }
422
423 #[inline]
424 pub fn send_push_button(&self, timeout: Option<UINT>) -> Result<LRESULT> {
428 raw::window::send_push_button(self.inner, timeout)
429 }
430
431 #[inline]
432 pub fn send_set_text<T: AsRef<ffi::OsStr>>(&self, text: T) -> bool {
436 raw::window::send_set_text(self.inner, text)
437 }
438
439 #[inline]
440 pub fn send_get_text(&self) -> Option<String> {
444 raw::window::send_get_text(self.inner)
445 }
446
447 #[inline]
448 pub fn send_sys_command(&self, cmd_type: WPARAM, l_param: LPARAM) -> bool {
452 raw::window::send_sys_command(self.inner, cmd_type, l_param)
453 }
454
455 #[inline]
456 pub fn destroy(self) {
458 drop(self);
459 }
460}
461
462impl convert::From<HWND> for Window {
463 fn from(window: HWND) -> Window {
464 Window { inner: window }
465 }
466}
467
468impl convert::Into<HWND> for Window {
469 fn into(self) -> HWND {
470 self.into_inner()
471 }
472}
473
474impl Drop for Window {
475 fn drop(&mut self) {
476 raw::window::destroy(self.inner);
477 }
478}
479
480enum TimerCallbackType {
481 None,
482 Raw(raw::timer::CallbackType, *mut c_void),
483}
484
485enum TimeoutType {
486 None,
487 Single(c_ulong),
488 Interval(c_ulong),
489 Both(c_ulong, c_ulong)
490}
491
492impl TimeoutType {
493 fn into_raw(self) -> (c_ulong, c_ulong) {
494 match self {
495 TimeoutType::None => (0, 0),
496 TimeoutType::Single(delay) => (delay, 0),
497 TimeoutType::Interval(interval) => (0, interval),
498 TimeoutType::Both(delay, interval) => (delay, interval),
499 }
500 }
501}
502
503unsafe extern "system" fn timer_rust_callback(param: *mut c_void, _: c_uchar) {
504 if !param.is_null() {
505 let cb: fn() -> () = mem::transmute(param);
506 cb();
507 }
508}
509
510pub struct TimerBuilder<'a> {
525 queue: Option<&'a raw::timer::TimerQueue>,
526 callback: TimerCallbackType,
527 timeout: TimeoutType,
528 flags: raw::timer::TimerFlags
529}
530
531impl<'a> TimerBuilder<'a> {
532 pub fn new() -> Self {
534 Self {
535 queue: None,
536 callback: TimerCallbackType::None,
537 timeout: TimeoutType::None,
538 flags: raw::timer::DEFAULT_TIMER_FLAGS
539 }
540 }
541
542 pub fn raw_callback(mut self, cb: raw::timer::CallbackType, param: Option<*mut c_void>) -> Self {
544 self.callback = TimerCallbackType::Raw(cb, param.unwrap_or(ptr::null_mut()));
545 self
546 }
547
548 pub fn rust_callback(mut self, cb: fn() -> ()) -> Self {
550 self.callback = TimerCallbackType::Raw(Some(timer_rust_callback), cb as _ );
551 self
552 }
553
554 pub fn queue(mut self, queue: &'a raw::timer::TimerQueue) -> Self {
558 self.queue = Some(queue);
559 self
560 }
561
562 pub fn single(mut self, delay: c_ulong) -> Self {
564 self.timeout = match self.timeout {
565 TimeoutType::Interval(interval) => TimeoutType::Both(delay, interval),
566 _ => TimeoutType::Single(delay)
567 };
568 self
569 }
570
571 pub fn interval(mut self, interval: c_ulong) -> Self {
573 self.timeout = match self.timeout {
574 TimeoutType::Single(delay) => TimeoutType::Both(delay, interval),
575 _ => TimeoutType::Interval(interval)
576 };
577 self
578 }
579
580 pub fn flags(mut self, flags: raw::timer::TimerFlags) -> Self {
584 self.flags = flags;
585 self
586 }
587
588 pub fn build(self) -> Result<raw::timer::QueueTimer> {
590 static DEFAULT: raw::timer::TimerQueue = raw::timer::DEFAULT_TIMER_QUEUE;
591
592 let queue = self.queue.unwrap_or(&DEFAULT);
593 let (delay, period) = self.timeout.into_raw();
594 let (cb, param) = match self.callback {
595 TimerCallbackType::None => (None, ptr::null_mut()),
596 TimerCallbackType::Raw(cb, param) => (cb, param),
597 };
598
599 queue.timer(cb, param, delay, period, self.flags)
600 }
601}