//! Deaicup Software — Windows PE64 entry point. //! //! The original application runs on eframe/egui. For the Deshab UTSM PE //! compatibility layer we keep the egui UI logic but replace the eframe //! runtime with a minimal hand-written Win32 backend: //! user32 window + message pump -> egui RawInput events //! egui tessellation -> SoftRaster (pure Rust, raster.rs) //! 32bpp DIB backbuffer -> GDI BitBlt onto the window DC //! //! No CRT: the PE entry is `mainCRTStartup` (see .cargo/config.toml) and the //! process ends via ExitProcess. #![no_main] #![allow(static_mut_refs)] mod raster; #[allow(dead_code)] mod rt; mod win32; use egui::{self, Color32, Context, Event, Key, Modifiers, PointerButton, Pos2, Rect}; use raster::SoftRaster; use win32::*; /* ============================================================ * UI 逻辑(移植自原 eframe 应用 CODE/Deaicup Software/src) * ========================================================== */ #[derive(Debug, PartialEq, Clone, Copy, Default)] enum Page { #[default] Home, Tool, Game, LinuxWare, WindowsWare, Set, About, } #[derive(Default)] struct DeaicupSoftware { current_page: Page, } impl DeaicupSoftware { fn ui(&mut self, ctx: &Context) { // 原应用顶部是远程图片 https://deaicup.com/.../top.png。 // PE 环境无网络,用标题栏替代,保留 75px 高度布局。 egui::TopBottomPanel::top("top_image_panel").show(ctx, |ui| { ui.set_min_height(75.0); ui.vertical_centered(|ui| { ui.add_space(15.0); ui.label(egui::RichText::new("Deaicup Software").size(30.0).strong()); }); }); // main egui::SidePanel::left("navigation_panel") .default_width(200.0) .resizable(true) .show(ctx, |ui| { ui.heading("Menu"); ui.separator(); ui.vertical(|ui| { if ui.selectable_label(self.current_page == Page::Home, "HOME").clicked() { self.current_page = Page::Home; } if ui.selectable_label(self.current_page == Page::Tool, "TOOL").clicked() { self.current_page = Page::Tool; } if ui.selectable_label(self.current_page == Page::Game, "GAME").clicked() { self.current_page = Page::Game; } if ui .selectable_label(self.current_page == Page::LinuxWare, "LINUXWARE") .clicked() { self.current_page = Page::LinuxWare; } if ui .selectable_label(self.current_page == Page::WindowsWare, "WINDOWSWARE") .clicked() { self.current_page = Page::WindowsWare; } if ui.selectable_label(self.current_page == Page::Set, "SET").clicked() { self.current_page = Page::Set; } if ui .selectable_label(self.current_page == Page::About, "ABOUT") .clicked() { self.current_page = Page::About; } }) }); egui::CentralPanel::default().show(ctx, |ui| { ui.separator(); match self.current_page { Page::Home => ui.label("Home"), Page::Tool => ui.label("Tool"), Page::Game => ui.label("Game"), Page::LinuxWare => ui.label("LinuxWare"), Page::WindowsWare => ui.label("WindowsWare"), Page::Set => ui.label("Set"), Page::About => ui.label("About"), } }); } } /* ============================================================ * 全局输入状态(单线程:wnd_proc 只被 DispatchMessageW 同步调用) * ========================================================== */ static mut EVENTS: Vec = Vec::new(); static mut POINTER: Pos2 = Pos2::ZERO; static mut MOD_ALT: bool = false; static mut MOD_CTRL: bool = false; static mut MOD_SHIFT: bool = false; static mut QUIT: bool = false; fn current_modifiers() -> Modifiers { unsafe { Modifiers { alt: MOD_ALT, ctrl: MOD_CTRL, shift: MOD_SHIFT, mac_cmd: false, command: MOD_CTRL, } } } #[inline] fn lparam_x(l: LPARAM) -> i32 { (l as i32 & 0xFFFF) as i16 as i32 } #[inline] fn lparam_y(l: LPARAM) -> i32 { ((l as i32 >> 16) & 0xFFFF) as i16 as i32 } fn push_pointer_button(button: PointerButton, pressed: bool, l: LPARAM) -> LRESULT { unsafe { POINTER = Pos2::new(lparam_x(l) as f32, lparam_y(l) as f32); EVENTS.push(Event::PointerButton { pos: POINTER, button, pressed, modifiers: current_modifiers(), }); } 0 } fn vk_to_egui_key(vk: usize) -> Option { // 字符键不需要映射为 egui::Key —— 文本输入走 WM_CHAR -> Event::Text。 Some(match vk { VK_LEFT => Key::ArrowLeft, VK_UP => Key::ArrowUp, VK_RIGHT => Key::ArrowRight, VK_DOWN => Key::ArrowDown, VK_BACK => Key::Backspace, VK_DELETE => Key::Delete, VK_RETURN => Key::Enter, VK_TAB => Key::Tab, VK_ESCAPE => Key::Escape, VK_SPACE => Key::Space, _ => return None, }) } fn on_key(vk: usize, pressed: bool) -> LRESULT { unsafe { match vk { VK_SHIFT => MOD_SHIFT = pressed, VK_CONTROL => MOD_CTRL = pressed, VK_MENU => MOD_ALT = pressed, _ => {} } if let Some(key) = vk_to_egui_key(vk) { EVENTS.push(Event::Key { key, physical_key: None, pressed, repeat: false, modifiers: current_modifiers(), }); } } 0 } extern "system" fn wnd_proc(hwnd: HWND, msg: u32, w: WPARAM, l: LPARAM) -> LRESULT { unsafe { match msg { WM_CLOSE | WM_DESTROY => { QUIT = true; PostQuitMessage(0); 0 } WM_MOUSEMOVE => { POINTER = Pos2::new(lparam_x(l) as f32, lparam_y(l) as f32); EVENTS.push(Event::PointerMoved(POINTER)); 0 } WM_LBUTTONDOWN => push_pointer_button(PointerButton::Primary, true, l), WM_LBUTTONUP => push_pointer_button(PointerButton::Primary, false, l), WM_RBUTTONDOWN => push_pointer_button(PointerButton::Secondary, true, l), WM_RBUTTONUP => push_pointer_button(PointerButton::Secondary, false, l), WM_MBUTTONDOWN => push_pointer_button(PointerButton::Middle, true, l), WM_MBUTTONUP => push_pointer_button(PointerButton::Middle, false, l), WM_KEYDOWN => on_key(w, true), WM_KEYUP => on_key(w, false), WM_CHAR => { if let Some(c) = char::from_u32(w as u32) { if c >= ' ' && c != '\x7f' { EVENTS.push(Event::Text(c.to_string())); } } 0 } WM_ERASEBKGND => 1, // 背景由 egui 全量绘制 _ => DefWindowProcW(hwnd, msg, w, l), } } } /* ============================================================ * 计时 * ========================================================== */ fn now_secs() -> f64 { unsafe { static mut FREQ: i64 = 0; if FREQ == 0 { QueryPerformanceFrequency(&mut FREQ); if FREQ == 0 { FREQ = 1000; } } let mut c: i64 = 0; QueryPerformanceCounter(&mut c); c as f64 / FREQ as f64 } } /* ============================================================ * PE 入口 * ========================================================== */ /// ExitProcess wrapper: restore the kernel GS base before leaving. fn exit_process(code: u32) -> ! { unsafe { rt::restore_tls(); ExitProcess(code); } } #[no_mangle] pub extern "C" fn mainCRTStartup() { unsafe { // Fake TEB/TLS must precede any std facility that might touch // thread locals (parking_lot, std::io, etc.). rt::install_fake_tls(); } log("[deaicup] mainCRTStartup\n"); unsafe { let hinst = GetModuleHandleW(core::ptr::null()); let class_name = wide("DeaicupWindow"); let wc = WNDCLASSEXW { cbSize: core::mem::size_of::() as u32, style: 0, lpfnWndProc: wnd_proc, cbClsExtra: 0, cbWndExtra: 0, hInstance: hinst, hIcon: 0, hCursor: LoadCursorW(0, IDC_ARROW), hbrBackground: 0, lpszMenuName: core::ptr::null(), lpszClassName: class_name.as_ptr(), hIconSm: 0, }; RegisterClassExW(&wc); // 屏幕尺寸(shim 报 framebuffer 尺寸),窗口 800x600,超出则收缩 let sw = GetSystemMetrics(SM_CXSCREEN); let sh = GetSystemMetrics(SM_CYSCREEN); let mut ww = 800; let mut wh = 600; if sw > 0 && ww > sw { ww = sw; } if sh > 0 && wh > sh { wh = sh; } let title = wide("Deaicup Software"); let hwnd = CreateWindowExW( 0, class_name.as_ptr(), title.as_ptr(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, ww, wh, 0, 0, hinst, core::ptr::null_mut(), ); if hwnd == 0 { log("[deaicup] CreateWindowExW failed\n"); exit_process(1); } ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); // 32bpp top-down DIB 后台缓冲 let hdc = GetDC(hwnd); let memdc = CreateCompatibleDC(hdc); let mut bmi = BITMAPINFO::default(); bmi.bmiHeader.biSize = core::mem::size_of::() as u32; bmi.bmiHeader.biWidth = ww; bmi.bmiHeader.biHeight = -wh; // top-down bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; let mut bits: *mut core::ffi::c_void = core::ptr::null_mut(); let hbmp = CreateDIBSection(memdc, &bmi, DIB_RGB_COLORS, &mut bits, 0, 0); if hbmp == 0 || bits.is_null() { log("[deaicup] CreateDIBSection failed\n"); exit_process(1); } SelectObject(memdc, hbmp); log("[dc] SelectObject ok\n"); /* 二分探针:逐项验证 std 设施,定位 Context::default 崩溃点 */ { let mut v: Vec = Vec::with_capacity(16); for i in 0..64u8 { v.push(i); } log("[dc] vec ok\n"); let s = String::from("hello"); let _ = s.len(); log("[dc] string ok\n"); let mut h: std::collections::HashMap = std::collections::HashMap::new(); h.insert(1, 2); h.insert(3, 4); let _ = h.get(&1); log("[dc] hashmap ok\n"); let a = std::sync::Arc::new(42u32); let b = a.clone(); let _ = *b; log("[dc] arc ok\n"); let m = std::sync::Mutex::new(7u32); *m.lock().unwrap() = 8; log("[dc] mutex ok\n"); } let ctx = Context::default(); log("[dc] Context::default ok\n"); ctx.set_pixels_per_point(1.0); let mut app = DeaicupSoftware::default(); let mut raster = SoftRaster::new(); let mut msg = MSG::default(); let mut frame: u64 = 0; log("[dc] app+raster ok\n"); while !QUIT { // 消息泵:把 Win32 消息转成 egui 事件(由 wnd_proc 推入 EVENTS) while PeekMessageW(&mut msg, 0, 0, 0, PM_REMOVE) != 0 { if msg.message == WM_QUIT { QUIT = true; break; } TranslateMessage(&msg); DispatchMessageW(&msg); } if QUIT { break; } if frame < 3 { log("[dc] msgpump ok\n"); } let events = core::mem::take(&mut *core::ptr::addr_of_mut!(EVENTS)); let had_events = !events.is_empty(); let input = egui::RawInput { screen_rect: Some(Rect::from_min_size( Pos2::ZERO, egui::vec2(ww as f32, wh as f32), )), time: Some(now_secs()), modifiers: current_modifiers(), events, ..Default::default() }; if frame < 3 { log("[dc] rawinput ok\n"); } let full = ctx.run(input, |ctx| app.ui(&ctx)); if frame < 3 { log("[dc] ctx.run ok\n"); } let repaint_after = full .viewport_output .values() .next() .map(|v| v.repaint_delay) .unwrap_or(std::time::Duration::from_millis(16)); raster.apply_delta(&full.textures_delta); if frame < 3 { log("[dc] apply_delta ok\n"); } let prims = ctx.tessellate(full.shapes, full.pixels_per_point); if frame < 3 { log("[dc] tessellate ok\n"); } let dst = core::slice::from_raw_parts_mut(bits as *mut u32, (ww * wh) as usize); raster::clear(dst, Color32::from_rgb(0x30, 0x34, 0x3d)); raster.paint(dst, ww, wh, &prims); if frame < 3 { log("[dc] paint ok\n"); } BitBlt(hdc, 0, 0, ww, wh, memdc, 0, 0, SRCCOPY); if frame < 3 { log("[dc] bitblt ok\n"); } frame += 1; if frame > 2 && !had_events && repaint_after > std::time::Duration::from_millis(5) { let ms = repaint_after.as_millis().min(50) as u32; Sleep(if ms == 0 { 5 } else { ms }); } } log("[deaicup] quit, ExitProcess(0)\n"); exit_process(0); } }