Skip to content

Commit

Permalink
fix: 修复 windows 获取 app_name 报错 panic (#109)
Browse files Browse the repository at this point in the history
  • Loading branch information
nashaofu authored Mar 17, 2024
1 parent 1ad6fe4 commit b1183f0
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 27 deletions.
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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"
Expand All @@ -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",
Expand Down
26 changes: 17 additions & 9 deletions src/windows/boxed.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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)
}
}
};
Expand Down Expand Up @@ -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)
}
};
}
Expand All @@ -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));
};
}
}
Expand All @@ -126,8 +125,17 @@ impl BoxProcessHandle {
b_inherit_handle: bool,
dw_process_id: u32,
) -> XCapResult<Self> {
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))
}
}
}
50 changes: 36 additions & 14 deletions src/windows/impl_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ 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},
},
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,
Expand All @@ -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,
Expand Down Expand Up @@ -173,20 +176,47 @@ struct LangCodePage {
pub w_code_page: u16,
}

fn get_module_basename(box_process_handle: BoxProcessHandle) -> XCapResult<String> {
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<String> {
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];

Expand Down Expand Up @@ -253,15 +283,7 @@ fn get_app_name(hwnd: HWND) -> XCapResult<String> {
}
}

// 默认使用 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)
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/windows/utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use sysinfo::System;
use windows::Win32::{
Foundation::{HWND, RECT},
Foundation::{GetLastError, HWND, RECT},
UI::WindowsAndMessaging::GetWindowRect,
};

Expand Down Expand Up @@ -32,3 +32,10 @@ pub(super) fn get_window_rect(hwnd: HWND) -> XCapResult<RECT> {
Ok(rect)
}
}

pub(super) fn log_last_error<T: ToString>(label: T) {
unsafe {
let err = GetLastError();
log::error!("{} error: {:?}", label.to_string(), err);
}
}

0 comments on commit b1183f0

Please sign in to comment.