windows: Remove SmartGlobal (#30366)

Closes #29657

Using `with_clipboard_data()` to ensure that `GlobalLock` and
`GlobalUnlock` are called correctly.

Release Notes:

- N/A
This commit is contained in:
张小白 2025-05-09 20:05:53 +08:00 committed by GitHub
parent 30f3efe697
commit 89ce49d5b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 58 additions and 74 deletions

View file

@ -5,23 +5,21 @@ use collections::{FxHashMap, FxHashSet};
use itertools::Itertools;
use util::ResultExt;
use windows::Win32::{
Foundation::HANDLE,
Foundation::{HANDLE, HGLOBAL},
System::{
DataExchange::{
CloseClipboard, CountClipboardFormats, EmptyClipboard, EnumClipboardFormats,
GetClipboardData, GetClipboardFormatNameW, IsClipboardFormatAvailable, OpenClipboard,
RegisterClipboardFormatW, SetClipboardData,
},
Memory::{GMEM_MOVEABLE, GlobalAlloc, GlobalLock, GlobalUnlock},
Memory::{GMEM_MOVEABLE, GlobalAlloc, GlobalLock, GlobalSize, GlobalUnlock},
Ole::{CF_HDROP, CF_UNICODETEXT},
},
UI::Shell::{DragQueryFileW, HDROP},
};
use windows_core::PCWSTR;
use crate::{
ClipboardEntry, ClipboardItem, ClipboardString, Image, ImageFormat, SmartGlobal, hash,
};
use crate::{ClipboardEntry, ClipboardItem, ClipboardString, Image, ImageFormat, hash};
// https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-dragqueryfilew
const DRAGDROP_GET_FILES_COUNT: u32 = 0xFFFFFFFF;
@ -268,13 +266,10 @@ where
}
fn read_string_from_clipboard() -> Option<ClipboardEntry> {
let text = {
let global = SmartGlobal::from_raw_ptr(
unsafe { GetClipboardData(CF_UNICODETEXT.0 as u32).log_err() }?.0,
);
let text = PCWSTR(global.lock() as *const u16);
String::from_utf16_lossy(unsafe { text.as_wide() })
};
let text = with_clipboard_data(CF_UNICODETEXT.0 as u32, |data_ptr| {
let pcwstr = PCWSTR(data_ptr as *const u16);
String::from_utf16_lossy(unsafe { pcwstr.as_wide() })
})?;
let Some(hash) = read_hash_from_clipboard() else {
return Some(ClipboardEntry::String(ClipboardString::new(text)));
};
@ -295,25 +290,23 @@ fn read_hash_from_clipboard() -> Option<u64> {
if unsafe { IsClipboardFormatAvailable(*CLIPBOARD_HASH_FORMAT).is_err() } {
return None;
}
let global =
SmartGlobal::from_raw_ptr(unsafe { GetClipboardData(*CLIPBOARD_HASH_FORMAT).log_err() }?.0);
let raw_ptr = global.lock() as *const u16;
let hash_bytes: [u8; 8] = unsafe {
std::slice::from_raw_parts(raw_ptr.cast::<u8>(), 8)
.to_vec()
.try_into()
.log_err()
}?;
Some(u64::from_ne_bytes(hash_bytes))
with_clipboard_data(*CLIPBOARD_HASH_FORMAT, |data_ptr| {
let hash_bytes: [u8; 8] = unsafe {
std::slice::from_raw_parts(data_ptr.cast::<u8>(), 8)
.to_vec()
.try_into()
.log_err()
}?;
Some(u64::from_ne_bytes(hash_bytes))
})?
}
fn read_metadata_from_clipboard() -> Option<String> {
unsafe { IsClipboardFormatAvailable(*CLIPBOARD_METADATA_FORMAT).log_err()? };
let global = SmartGlobal::from_raw_ptr(
unsafe { GetClipboardData(*CLIPBOARD_METADATA_FORMAT).log_err() }?.0,
);
let text = PCWSTR(global.lock() as *const u16);
Some(String::from_utf16_lossy(unsafe { text.as_wide() }))
with_clipboard_data(*CLIPBOARD_METADATA_FORMAT, |data_ptr| {
let pcwstr = PCWSTR(data_ptr as *const u16);
String::from_utf16_lossy(unsafe { pcwstr.as_wide() })
})
}
fn read_image_from_clipboard(format: u32) -> Option<ClipboardEntry> {
@ -327,29 +320,52 @@ fn format_number_to_image_format(format_number: u32) -> Option<&'static ImageFor
}
fn read_image_for_type(format_number: u32, format: ImageFormat) -> Option<ClipboardEntry> {
let global = SmartGlobal::from_raw_ptr(unsafe { GetClipboardData(format_number).log_err() }?.0);
let image_ptr = global.lock();
let iamge_size = global.size();
let bytes =
unsafe { std::slice::from_raw_parts(image_ptr as *mut u8 as _, iamge_size).to_vec() };
let id = hash(&bytes);
let (bytes, id) = with_clipboard_data_and_size(format_number, |data_ptr, size| {
let bytes = unsafe { std::slice::from_raw_parts(data_ptr as *mut u8 as _, size).to_vec() };
let id = hash(&bytes);
(bytes, id)
})?;
Some(ClipboardEntry::Image(Image { format, bytes, id }))
}
fn read_files_from_clipboard() -> Option<ClipboardEntry> {
let global =
SmartGlobal::from_raw_ptr(unsafe { GetClipboardData(CF_HDROP.0 as u32).log_err() }?.0);
let hdrop = HDROP(global.lock());
let mut filenames = String::new();
with_file_names(hdrop, |file_name| {
filenames.push_str(&file_name);
});
let text = with_clipboard_data(CF_HDROP.0 as u32, |data_ptr| {
let hdrop = HDROP(data_ptr);
let mut filenames = String::new();
with_file_names(hdrop, |file_name| {
filenames.push_str(&file_name);
});
filenames
})?;
Some(ClipboardEntry::String(ClipboardString {
text: filenames,
text,
metadata: None,
}))
}
fn with_clipboard_data<F, R>(format: u32, f: F) -> Option<R>
where
F: FnOnce(*mut std::ffi::c_void) -> R,
{
let global = HGLOBAL(unsafe { GetClipboardData(format).log_err() }?.0);
let data_ptr = unsafe { GlobalLock(global) };
let result = f(data_ptr);
unsafe { GlobalUnlock(global).log_err() };
Some(result)
}
fn with_clipboard_data_and_size<F, R>(format: u32, f: F) -> Option<R>
where
F: FnOnce(*mut std::ffi::c_void, usize) -> R,
{
let global = HGLOBAL(unsafe { GetClipboardData(format).log_err() }?.0);
let size = unsafe { GlobalSize(global) };
let data_ptr = unsafe { GlobalLock(global) };
let result = f(data_ptr, size);
unsafe { GlobalUnlock(global).log_err() };
Some(result)
}
impl From<ImageFormat> for image::ImageFormat {
fn from(value: ImageFormat) -> Self {
match value {

View file

@ -1,11 +1,6 @@
use std::ops::Deref;
use util::ResultExt;
use windows::Win32::{
Foundation::{HANDLE, HGLOBAL},
System::Memory::{GlobalLock, GlobalSize, GlobalUnlock},
UI::WindowsAndMessaging::HCURSOR,
};
use windows::Win32::{Foundation::HANDLE, UI::WindowsAndMessaging::HCURSOR};
#[derive(Debug, Clone, Copy)]
pub(crate) struct SafeHandle {
@ -50,30 +45,3 @@ impl Deref for SafeCursor {
&self.raw
}
}
#[derive(Debug, Clone)]
pub(crate) struct SmartGlobal {
raw: HGLOBAL,
}
impl SmartGlobal {
pub(crate) fn from_raw_ptr(ptr: *mut std::ffi::c_void) -> Self {
Self { raw: HGLOBAL(ptr) }
}
pub(crate) fn lock(&self) -> *mut std::ffi::c_void {
unsafe { GlobalLock(self.raw) }
}
pub(crate) fn size(&self) -> usize {
unsafe { GlobalSize(self.raw) }
}
}
impl Drop for SmartGlobal {
fn drop(&mut self) {
unsafe {
GlobalUnlock(self.raw).log_err();
}
}
}