windows: Remove `SmartGlobal` (#30366)

张小白 created

Closes #29657

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

Release Notes:

- N/A

Change summary

crates/gpui/src/platform/windows/clipboard.rs | 98 ++++++++++++--------
crates/gpui/src/platform/windows/wrapper.rs   | 34 -------
2 files changed, 58 insertions(+), 74 deletions(-)

Detailed changes

crates/gpui/src/platform/windows/clipboard.rs 🔗

@@ -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 {

crates/gpui/src/platform/windows/wrapper.rs 🔗

@@ -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();
-        }
-    }
-}