windows: Show error messages when zed failed to lanuch (#32537)

张小白 created

Now, if either `WindowsPlatform` or `BladeRenderer` fails to initialize,
a window will pop up to notify the user.


![image](https://github.com/user-attachments/assets/40fe7f1d-5218-4ee2-b4ec-0945fed2b743)


Release Notes:

- N/A

Change summary

crates/gpui/src/platform.rs                      |  6 +++++-
crates/gpui/src/platform/blade/blade_renderer.rs |  2 +-
crates/gpui/src/platform/windows/platform.rs     | 16 ++++++++--------
crates/gpui/src/platform/windows/util.rs         | 13 ++++++++++++-
crates/gpui/src/platform/windows/window.rs       |  9 +++++++--
5 files changed, 33 insertions(+), 13 deletions(-)

Detailed changes

crates/gpui/src/platform.rs 🔗

@@ -142,7 +142,11 @@ pub fn guess_compositor() -> &'static str {
 
 #[cfg(target_os = "windows")]
 pub(crate) fn current_platform(_headless: bool) -> Rc<dyn Platform> {
-    Rc::new(WindowsPlatform::new())
+    Rc::new(
+        WindowsPlatform::new()
+            .inspect_err(|err| show_error("Error: Zed failed to launch", err.to_string()))
+            .unwrap(),
+    )
 }
 
 pub(crate) trait Platform: 'static {

crates/gpui/src/platform/blade/blade_renderer.rs 🔗

@@ -342,7 +342,7 @@ impl BladeRenderer {
         let surface = context
             .gpu
             .create_surface_configured(window, surface_config)
-            .unwrap();
+            .map_err(|err| anyhow::anyhow!("Failed to create surface: {err:?}"))?;
 
         let command_encoder = context.gpu.create_command_encoder(gpu::CommandEncoderDesc {
             name: "main",

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

@@ -81,9 +81,9 @@ impl WindowsPlatformState {
 }
 
 impl WindowsPlatform {
-    pub(crate) fn new() -> Self {
+    pub(crate) fn new() -> Result<Self> {
         unsafe {
-            OleInitialize(None).expect("unable to initialize Windows OLE");
+            OleInitialize(None).context("unable to initialize Windows OLE")?;
         }
         let (main_sender, main_receiver) = flume::unbounded::<Runnable>();
         let main_thread_id_win32 = unsafe { GetCurrentThreadId() };
@@ -97,19 +97,19 @@ impl WindowsPlatform {
         let foreground_executor = ForegroundExecutor::new(dispatcher);
         let bitmap_factory = ManuallyDrop::new(unsafe {
             CoCreateInstance(&CLSID_WICImagingFactory, None, CLSCTX_INPROC_SERVER)
-                .expect("Error creating bitmap factory.")
+                .context("Error creating bitmap factory.")?
         });
         let text_system = Arc::new(
             DirectWriteTextSystem::new(&bitmap_factory)
-                .expect("Error creating DirectWriteTextSystem"),
+                .context("Error creating DirectWriteTextSystem")?,
         );
         let icon = load_icon().unwrap_or_default();
         let state = RefCell::new(WindowsPlatformState::new());
         let raw_window_handles = RwLock::new(SmallVec::new());
-        let gpu_context = BladeContext::new().expect("Unable to init GPU context");
-        let windows_version = WindowsVersion::new().expect("Error retrieve windows version");
+        let gpu_context = BladeContext::new().context("Unable to init GPU context")?;
+        let windows_version = WindowsVersion::new().context("Error retrieve windows version")?;
 
-        Self {
+        Ok(Self {
             state,
             raw_window_handles,
             gpu_context,
@@ -122,7 +122,7 @@ impl WindowsPlatform {
             bitmap_factory,
             validation_number,
             main_thread_id_win32,
-        }
+        })
     }
 
     fn redraw_all(&self) {

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

@@ -8,7 +8,7 @@ use windows::{
     },
     Wdk::System::SystemServices::RtlGetVersion,
     Win32::{Foundation::*, Graphics::Dwm::*, UI::WindowsAndMessaging::*},
-    core::BOOL,
+    core::{BOOL, HSTRING},
 };
 
 use crate::*;
@@ -186,3 +186,14 @@ pub(crate) fn system_appearance() -> Result<WindowAppearance> {
 fn is_color_light(color: &Color) -> bool {
     ((5 * color.G as u32) + (2 * color.R as u32) + color.B as u32) > (8 * 128)
 }
+
+pub(crate) fn show_error(title: &str, content: String) {
+    let _ = unsafe {
+        MessageBoxW(
+            None,
+            &HSTRING::from(content),
+            &HSTRING::from(title),
+            MB_ICONERROR | MB_SYSTEMMODAL,
+        )
+    };
+}

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

@@ -1258,7 +1258,7 @@ mod windows_renderer {
     use std::num::NonZeroIsize;
     use windows::Win32::{Foundation::HWND, UI::WindowsAndMessaging::GWLP_HINSTANCE};
 
-    use crate::get_window_long;
+    use crate::{get_window_long, show_error};
 
     pub(super) fn init(
         context: &BladeContext,
@@ -1270,7 +1270,12 @@ mod windows_renderer {
             size: Default::default(),
             transparent,
         };
-        BladeRenderer::new(context, &raw, config)
+        BladeRenderer::new(context, &raw, config).inspect_err(|err| {
+            show_error(
+                "Error: Zed failed to initialize BladeRenderer",
+                err.to_string(),
+            )
+        })
     }
 
     struct RawWindow {