Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: 修复 windows 获取 app_name 报错 panic #109

Merged
merged 1 commit into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}
Loading