diff --git a/Cargo.lock b/Cargo.lock index 940825d..619e700 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -548,7 +548,7 @@ dependencies = [ [[package]] name = "windows-capture" -version = "1.0.45" +version = "1.0.47" dependencies = [ "image", "log", @@ -560,9 +560,10 @@ dependencies = [ [[package]] name = "windows-capture-python" -version = "1.0.45" +version = "1.0.47" dependencies = [ "pyo3", + "thiserror", "windows-capture", ] diff --git a/Cargo.toml b/Cargo.toml index d0f8218..ac067c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windows-capture" -version = "1.0.45" +version = "1.0.47" authors = ["NiiightmareXD"] edition = "2021" description = "Fastest Windows Screen Capture Library For Rust 🔥" diff --git a/README.md b/README.md index 886a283..79ad04b 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Add this library to your `Cargo.toml`: ```toml [dependencies] -windows-capture = "1.0.45" +windows-capture = "1.0.47" ``` or run this command diff --git a/src/capture.rs b/src/capture.rs index dc8c85c..8c82460 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -3,8 +3,7 @@ use std::{ os::windows::prelude::AsRawHandle, sync::{ atomic::{self, AtomicBool}, - mpsc::{self, SendError}, - Arc, + mpsc, Arc, }, thread::{self, JoinHandle}, }; @@ -171,10 +170,10 @@ pub enum WindowsCaptureError { FailedToSetDispatcherQueueCompletedHandler, #[error("Graphics Capture Error")] GraphicsCaptureError(graphics_capture_api::Error), - #[error("Handler Error")] - HandlerError(E), - #[error(transparent)] - FailedToThreadID(SendError), + #[error("New Handler Error")] + NewHandlerError(E), + #[error("Frame Handler Error")] + FrameHandlerError(E), } /// Event Handler Trait @@ -218,7 +217,7 @@ pub trait WindowsCaptureHandler: Sized { info!("Starting Capture Thread"); let result = Arc::new(Mutex::new(None)); let callback = Arc::new(Mutex::new( - Self::new(settings.flags).map_err(WindowsCaptureError::HandlerError)?, + Self::new(settings.flags).map_err(WindowsCaptureError::NewHandlerError)?, )); let mut capture = GraphicsCaptureApi::new( settings.item, @@ -279,7 +278,7 @@ pub trait WindowsCaptureHandler: Sized { // Check Handler Result trace!("Checking Handler Result"); if let Some(e) = result.lock().take() { - return Err(WindowsCaptureError::HandlerError(e)); + return Err(WindowsCaptureError::FrameHandlerError(e)); } Ok(()) @@ -326,7 +325,7 @@ pub trait WindowsCaptureHandler: Sized { info!("Starting Capture Thread"); let result = Arc::new(Mutex::new(None)); let callback = Arc::new(Mutex::new( - Self::new(settings.flags).map_err(WindowsCaptureError::HandlerError)?, + Self::new(settings.flags).map_err(WindowsCaptureError::NewHandlerError)?, )); let mut capture = GraphicsCaptureApi::new( settings.item, @@ -397,7 +396,7 @@ pub trait WindowsCaptureHandler: Sized { // Check Handler Result trace!("Checking Handler Result"); if let Some(e) = result.lock().take() { - return Err(WindowsCaptureError::HandlerError(e)); + return Err(WindowsCaptureError::FrameHandlerError(e)); } Ok(()) diff --git a/src/lib.rs b/src/lib.rs index f1efab6..d6887ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,7 @@ //! //! ```toml //! [dependencies] -//! windows-capture = "1.0.45" +//! windows-capture = "1.0.47" //! ``` //! or run this command //! @@ -33,26 +33,28 @@ //! ## Usage //! //! ```no_run -//! use std::error::Error; -//! //! use windows_capture::{ //! capture::WindowsCaptureHandler, //! frame::Frame, //! graphics_capture_api::InternalCaptureControl, -//! settings::{ColorFormat, WindowsCaptureSettings}, +//! settings::{ColorFormat, Settings}, //! window::Window, //! }; //! -//! // Struct To Implement Methods For +//! // Struct To Implement The Trait For //! struct Capture; //! //! impl WindowsCaptureHandler for Capture { -//! type Flags = String; // To Get The Message From The Settings +//! // To Get The Message From The Settings +//! type Flags = String; +//! +//! // To Redirect To CaptureControl Or Start Method +//! type Error = Box; //! //! // Function That Will Be Called To Create The Struct The Flags Can Be Passed -//! // From Settings -//! fn new(message: Self::Flags) -> Result> { -//! println!("Got The Message: {message}"); +//! // From `WindowsCaptureSettings` +//! fn new(message: Self::Flags) -> Result { +//! println!("Got The Flag: {message}"); //! //! Ok(Self {}) //! } @@ -62,10 +64,10 @@ //! &mut self, //! frame: &mut Frame, //! capture_control: InternalCaptureControl, -//! ) -> Result<(), Box> { +//! ) -> Result<(), Self::Error> { //! println!("New Frame Arrived"); //! -//! // Save The Frame As An Image To Specified Path +//! // Save The Frame As An Image To The Specified Path //! frame.save_as_image("image.png")?; //! //! // Gracefully Stop The Capture Thread @@ -76,7 +78,7 @@ //! //! // Called When The Capture Item Closes Usually When The Window Closes, Capture //! // Session Will End After This Function Ends -//! fn on_closed(&mut self) -> Result<(), Box> { +//! fn on_closed(&mut self) -> Result<(), Self::Error> { //! println!("Capture Session Closed"); //! //! Ok(()) @@ -84,9 +86,9 @@ //! } //! //! // Checkout Docs For Other Capture Items -//! let foreground_window = Window::foreground().unwrap(); +//! let foreground_window = Window::foreground().expect("No Active Window Found"); //! -//! let settings = WindowsCaptureSettings::new( +//! let settings = Settings::new( //! // Item To Captue //! foreground_window, //! // Capture Cursor @@ -100,7 +102,7 @@ //! ) //! .unwrap(); //! -//! // Every Error From on_closed and on_frame_arrived Will End Up Here +//! // Every Error From `new`, `on_frame_arrived` and `on_closed` Will End Up Here //! Capture::start(settings).unwrap(); //! ``` #![warn(clippy::pedantic)] diff --git a/windows-capture-python/Cargo.toml b/windows-capture-python/Cargo.toml index ddbd1ca..b029b3f 100644 --- a/windows-capture-python/Cargo.toml +++ b/windows-capture-python/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windows-capture-python" -version = "1.0.45" +version = "1.0.47" authors = ["NiiightmareXD"] edition = "2021" description = "Fastest Windows Screen Capture Library For Python 🔥" @@ -25,4 +25,5 @@ pyo3 = { version = "0.20.0", features = [ "extension-module", "auto-initialize", ] } +thiserror = "1.0.50" windows-capture = { path = ".." } diff --git a/windows-capture-python/pyproject.toml b/windows-capture-python/pyproject.toml index 6d26d5a..665b8cd 100644 --- a/windows-capture-python/pyproject.toml +++ b/windows-capture-python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "windows-capture" -version = "1.0.45" +version = "1.0.47" description = "Fastest Windows Screen Capture Library For Python 🔥" readme = "README.md" requires-python = ">=3.9" diff --git a/windows-capture-python/src/lib.rs b/windows-capture-python/src/lib.rs index 15fbe95..1b69a46 100644 --- a/windows-capture-python/src/lib.rs +++ b/windows-capture-python/src/lib.rs @@ -5,11 +5,11 @@ #![allow(clippy::missing_panics_doc)] #![allow(clippy::redundant_pub_crate)] -use std::{error::Error, sync::Arc}; +use std::sync::Arc; use ::windows_capture::{ - capture::{CaptureControl, WindowsCaptureHandler}, - frame::Frame, + capture::{CaptureControl, CaptureControlError, WindowsCaptureError, WindowsCaptureHandler}, + frame::{self, Frame}, graphics_capture_api::InternalCaptureControl, monitor::Monitor, settings::{ColorFormat, Settings}, @@ -20,8 +20,8 @@ use pyo3::{exceptions::PyException, prelude::*, types::PyList}; /// Fastest Windows Screen Capture Library For Python 🔥. #[pymodule] fn windows_capture(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; m.add_class::()?; + m.add_class::()?; Ok(()) } @@ -29,12 +29,12 @@ fn windows_capture(_py: Python, m: &PyModule) -> PyResult<()> { #[pyclass] pub struct NativeCaptureControl { capture_control: - Option>>, + Option>, } impl NativeCaptureControl { const fn new( - capture_control: CaptureControl>, + capture_control: CaptureControl, ) -> Self { Self { capture_control: Some(capture_control), @@ -59,8 +59,19 @@ impl NativeCaptureControl { match capture_control.wait() { Ok(()) => (), Err(e) => { + if let CaptureControlError::WindowsCaptureError( + WindowsCaptureError::FrameHandlerError( + InnerNativeWindowsCaptureError::PythonError(ref e), + ), + ) = e + { + return Err(PyException::new_err(format!( + "Failed To Join The Capture Thread -> {e}", + ))); + } + return Err(PyException::new_err(format!( - "Failed To Join The Capture Thread -> {e}" + "Failed To Join The Capture Thread -> {e}", ))); } }; @@ -80,8 +91,19 @@ impl NativeCaptureControl { match capture_control.stop() { Ok(()) => (), Err(e) => { + if let CaptureControlError::WindowsCaptureError( + WindowsCaptureError::FrameHandlerError( + InnerNativeWindowsCaptureError::PythonError(ref e), + ), + ) = e + { + return Err(PyException::new_err(format!( + "Failed To Stop The Capture Thread -> {e}", + ))); + } + return Err(PyException::new_err(format!( - "Failed To Stop The Capture Thread -> {e}" + "Failed To Stop The Capture Thread -> {e}", ))); } }; @@ -197,8 +219,17 @@ impl NativeWindowsCapture { match InnerNativeWindowsCapture::start(settings) { Ok(()) => (), Err(e) => { + if let WindowsCaptureError::FrameHandlerError( + InnerNativeWindowsCaptureError::PythonError(ref e), + ) = e + { + return Err(PyException::new_err(format!( + "Capture Session Threw An Exception -> {e}", + ))); + } + return Err(PyException::new_err(format!( - "Capture Session Threw An Exception -> {e}" + "Capture Session Threw An Exception -> {e}", ))); } } @@ -267,8 +298,17 @@ impl NativeWindowsCapture { let capture_control = match InnerNativeWindowsCapture::start_free_threaded(settings) { Ok(capture_control) => capture_control, Err(e) => { + if let WindowsCaptureError::FrameHandlerError( + InnerNativeWindowsCaptureError::PythonError(ref e), + ) = e + { + return Err(PyException::new_err(format!( + "Capture Session Threw An Exception -> {e}", + ))); + } + return Err(PyException::new_err(format!( - "Failed To Start Capture Session On A Dedicated Thread -> {e}" + "Capture Session Threw An Exception -> {e}", ))); } }; @@ -284,9 +324,17 @@ struct InnerNativeWindowsCapture { on_closed: Arc, } +#[derive(thiserror::Error, Debug)] +pub enum InnerNativeWindowsCaptureError { + #[error("Python Callback Error")] + PythonError(pyo3::PyErr), + #[error("Frame Process Error")] + FrameProcessError(frame::Error), +} + impl WindowsCaptureHandler for InnerNativeWindowsCapture { type Flags = (Arc, Arc); - type Error = Box; + type Error = InnerNativeWindowsCaptureError; fn new((on_frame_arrived_callback, on_closed): Self::Flags) -> Result { Ok(Self { @@ -302,25 +350,33 @@ impl WindowsCaptureHandler for InnerNativeWindowsCapture { ) -> Result<(), Self::Error> { let width = frame.width(); let height = frame.height(); - let mut buffer = frame.buffer()?; + let mut buffer = frame + .buffer() + .map_err(InnerNativeWindowsCaptureError::FrameProcessError)?; let buffer = buffer.as_raw_buffer(); - Python::with_gil(|py| -> PyResult<()> { - py.check_signals()?; + Python::with_gil(|py| -> Result<(), Self::Error> { + py.check_signals() + .map_err(InnerNativeWindowsCaptureError::PythonError)?; let stop_list = PyList::new(py, [false]); - self.on_frame_arrived_callback.call1( - py, - ( - buffer.as_ptr() as isize, - buffer.len(), - width, - height, - stop_list, - ), - )?; - - if stop_list[0].is_true()? { + self.on_frame_arrived_callback + .call1( + py, + ( + buffer.as_ptr() as isize, + buffer.len(), + width, + height, + stop_list, + ), + ) + .map_err(InnerNativeWindowsCaptureError::PythonError)?; + + if stop_list[0] + .is_true() + .map_err(InnerNativeWindowsCaptureError::PythonError)? + { capture_control.stop(); } @@ -330,8 +386,9 @@ impl WindowsCaptureHandler for InnerNativeWindowsCapture { Ok(()) } - fn on_closed(&mut self) -> Result<(), Box<(dyn Error + Send + Sync)>> { - Python::with_gil(|py| self.on_closed.call0(py))?; + fn on_closed(&mut self) -> Result<(), Self::Error> { + Python::with_gil(|py| self.on_closed.call0(py)) + .map_err(InnerNativeWindowsCaptureError::PythonError)?; Ok(()) }