diff --git a/Cargo.toml b/Cargo.toml index fa243f7..d58cbe6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xcap" -version = "0.0.4" +version = "0.0.5" edition = "2021" description = "XCap is a cross-platform screen capture library written in Rust. It supports Linux (X11, Wayland), MacOS, and Windows. XCap supports screenshot and video recording (to be implemented)." license = "Apache-2.0" @@ -12,7 +12,7 @@ keywords = ["screen", "monitor", "window", "capture", "image"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -image = "0.24" +image = "0.25" log = "0.4" sysinfo = "0.30.5" thiserror = "1.0" @@ -22,7 +22,7 @@ core-foundation = "0.9" core-graphics = "0.23" [target.'cfg(target_os = "windows")'.dependencies] -windows = { version = "0.52", features = [ +windows = { version = "0.54", features = [ "Win32_Foundation", "Win32_Graphics_Gdi", "Win32_Graphics_Dwm", diff --git a/src/windows/boxed.rs b/src/windows/boxed.rs index 07df664..843dd50 100644 --- a/src/windows/boxed.rs +++ b/src/windows/boxed.rs @@ -1,15 +1,14 @@ -use log::error; use std::{ops::Deref, ptr}; use windows::{ core::PCWSTR, Win32::{ - Foundation::{CloseHandle, HANDLE, HWND}, + Foundation::{CloseHandle, GetLastError, HANDLE, HWND}, Graphics::Gdi::{CreateDCW, DeleteDC, DeleteObject, GetWindowDC, ReleaseDC, HBITMAP, HDC}, System::Threading::{OpenProcess, PROCESS_ACCESS_RIGHTS}, }, }; -use crate::XCapResult; +use crate::{XCapError, XCapResult}; #[derive(Debug)] pub(super) struct BoxHDC { @@ -31,11 +30,11 @@ impl Drop for BoxHDC { unsafe { if let Some(hwnd) = self.hwnd { if ReleaseDC(hwnd, self.hdc) != 1 { - error!("ReleaseDC {:?} failed", self) + log::error!("ReleaseDC {:?} failed", self) } } else { if !DeleteDC(self.hdc).as_bool() { - error!("DeleteDC {:?} failed", self) + log::error!("DeleteDC {:?} failed", self) } } }; @@ -90,7 +89,7 @@ impl Drop for BoxHBITMAP { // https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/nf-wingdi-createcompatiblebitmap unsafe { if !DeleteObject(self.0).as_bool() { - error!("DeleteObject {:?} failed", self) + log::error!("DeleteObject {:?} failed", self) } }; } @@ -115,7 +114,7 @@ impl Deref for BoxProcessHandle { impl Drop for BoxProcessHandle { fn drop(&mut self) { unsafe { - CloseHandle(self.0).unwrap_or_else(|_| error!("CloseHandle {:?} failed", self)); + CloseHandle(self.0).unwrap_or_else(|_| log::error!("CloseHandle {:?} failed", self)); }; } } @@ -126,8 +125,17 @@ impl BoxProcessHandle { b_inherit_handle: bool, dw_process_id: u32, ) -> XCapResult { - let h_process = unsafe { OpenProcess(dw_desired_access, b_inherit_handle, dw_process_id)? }; + unsafe { + let h_process = OpenProcess(dw_desired_access, b_inherit_handle, dw_process_id)?; + + if h_process.is_invalid() { + return Err(XCapError::new(format!( + "OpenProcess error {:?}", + GetLastError() + ))); + } - Ok(BoxProcessHandle(h_process)) + Ok(BoxProcessHandle(h_process)) + } } } diff --git a/src/windows/impl_window.rs b/src/windows/impl_window.rs index 4be6e50..a40bab0 100644 --- a/src/windows/impl_window.rs +++ b/src/windows/impl_window.rs @@ -4,7 +4,7 @@ use std::{cmp::Ordering, ffi::c_void, mem, ptr}; use windows::{ core::{HSTRING, PCWSTR}, Win32::{ - Foundation::{BOOL, HMODULE, HWND, LPARAM, MAX_PATH, TRUE}, + Foundation::{BOOL, HWND, LPARAM, MAX_PATH, TRUE}, Graphics::{ Dwm::{DwmGetWindowAttribute, DWMWA_CLOAKED}, Gdi::{IsRectEmpty, MonitorFromWindow, MONITOR_DEFAULTTONEAREST}, @@ -12,7 +12,7 @@ use windows::{ Storage::FileSystem::{GetFileVersionInfoSizeW, GetFileVersionInfoW, VerQueryValueW}, System::{ ProcessStatus::{GetModuleBaseNameW, GetModuleFileNameExW}, - Threading::{GetCurrentProcessId, PROCESS_QUERY_LIMITED_INFORMATION}, + Threading::{GetCurrentProcessId, PROCESS_ALL_ACCESS}, }, UI::WindowsAndMessaging::{ EnumWindows, GetClassNameW, GetWindowInfo, GetWindowLongPtrW, GetWindowTextLengthW, @@ -22,7 +22,10 @@ use windows::{ }, }; -use crate::{error::XCapResult, platform::boxed::BoxProcessHandle}; +use crate::{ + error::XCapResult, + platform::{boxed::BoxProcessHandle, utils::log_last_error}, +}; use super::{ capture::capture_window, @@ -173,20 +176,47 @@ struct LangCodePage { pub w_code_page: u16, } +fn get_module_basename(box_process_handle: BoxProcessHandle) -> XCapResult { + unsafe { + // 默认使用 module_basename + let mut module_base_name_w = [0; MAX_PATH as usize]; + let result = GetModuleBaseNameW(*box_process_handle, None, &mut module_base_name_w); + + if result == 0 { + log_last_error("GetModuleBaseNameW"); + + GetModuleFileNameExW(*box_process_handle, None, &mut module_base_name_w); + } + + wide_string_to_string(&module_base_name_w) + } +} + fn get_app_name(hwnd: HWND) -> XCapResult { unsafe { let mut lp_dw_process_id = 0; GetWindowThreadProcessId(hwnd, Some(&mut lp_dw_process_id)); let box_process_handle = - BoxProcessHandle::open(PROCESS_QUERY_LIMITED_INFORMATION, false, lp_dw_process_id)?; + match BoxProcessHandle::open(PROCESS_ALL_ACCESS, false, lp_dw_process_id) { + Ok(box_handle) => box_handle, + Err(err) => { + log::error!("{}", err); + return Ok(String::new()); + } + }; let mut filename = [0; MAX_PATH as usize]; - GetModuleFileNameExW(*box_process_handle, HMODULE::default(), &mut filename); + GetModuleFileNameExW(*box_process_handle, None, &mut filename); let pcw_filename = PCWSTR::from_raw(filename.as_ptr()); let file_version_info_size_w = GetFileVersionInfoSizeW(pcw_filename, None); + if file_version_info_size_w == 0 { + log_last_error("GetFileVersionInfoSizeW"); + + return get_module_basename(box_process_handle); + } let mut file_version_info = vec![0u16; file_version_info_size_w as usize]; @@ -253,15 +283,7 @@ fn get_app_name(hwnd: HWND) -> XCapResult { } } - // 默认使用 module_basename - let mut module_base_name_w = [0; MAX_PATH as usize]; - GetModuleBaseNameW( - *box_process_handle, - HMODULE::default(), - &mut module_base_name_w, - ); - - wide_string_to_string(&module_base_name_w) + get_module_basename(box_process_handle) } } diff --git a/src/windows/utils.rs b/src/windows/utils.rs index 3987f8a..b13fa7e 100644 --- a/src/windows/utils.rs +++ b/src/windows/utils.rs @@ -1,6 +1,6 @@ use sysinfo::System; use windows::Win32::{ - Foundation::{HWND, RECT}, + Foundation::{GetLastError, HWND, RECT}, UI::WindowsAndMessaging::GetWindowRect, }; @@ -32,3 +32,10 @@ pub(super) fn get_window_rect(hwnd: HWND) -> XCapResult { Ok(rect) } } + +pub(super) fn log_last_error(label: T) { + unsafe { + let err = GetLastError(); + log::error!("{} error: {:?}", label.to_string(), err); + } +}