使用Rust调用Win32 API显示图像失败,仅显示黑色方块
免责声明
此问题与“HBITMAP created by CreateCompatibleBitmap is black and white”场景类似,但并不相同。我理解上述场景是单色模式,但我不知道如何避免生成单色位图。
目标
在屏幕左上角显示一张图像。
问题
我编写的实现代码无法正常显示图像,仅显示一个全黑的方块。我已确认图片路径正确,且尝试了多张图片。我是Win32 API新手,目前毫无头绪,若有明显疏漏敬请谅解。
代码
use image::{GenericImageView, ImageBuffer, Rgba}; use windows::{ core::*, Win32::{ Foundation::{COLORREF, HINSTANCE, HWND, LPARAM, LRESULT, WPARAM, GetLastError}, Graphics::Gdi::{BeginPaint, BitBlt, CreateCompatibleBitmap, CreateCompatibleDC, DeleteDC, DeleteObject, EndPaint, GetDC, ReleaseDC, SelectObject, SetDIBitsToDevice, UpdateWindow, BITMAPINFO, BITMAPINFOHEADER, DIB_RGB_COLORS, HBRUSH, HGDIOBJ, PAINTSTRUCT, RGBQUAD, SRCCOPY}, System::LibraryLoader::GetModuleHandleW, UI::{HiDpi::{SetProcessDpiAwareness, PROCESS_PER_MONITOR_DPI_AWARE}, WindowsAndMessaging::{CreateWindowExW, DefWindowProcW, DispatchMessageW, GetMessageW, RegisterClassExW, SetLayeredWindowAttributes, ShowWindow, TranslateMessage, CS_HREDRAW, CS_VREDRAW, HCURSOR, HMENU, LWA_ALPHA, SHOW_WINDOW_CMD, WM_PAINT, WNDCLASSEXW, WS_EX_LAYERED, WS_EX_TOPMOST, WS_POPUP}} } }; static mut BITMAP_HANDLE: Option<HGDIOBJ> = None; fn main() { unsafe { // DPI awareness setup let _ = SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); // Get instance handle let handle_instance = GetModuleHandleW(None).unwrap(); let window_class = "Glorp Class"; let window_name = "Glorp Overlay"; // Register window class let wc = WNDCLASSEXW { cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32, style: CS_HREDRAW | CS_VREDRAW, lpfnWndProc: Some(window_proc), hInstance: handle_instance.into(), hCursor: HCURSOR(std::ptr::null_mut()), hbrBackground: HBRUSH(std::ptr::null_mut()), lpszClassName: w!("Glorp Class"), ..Default::default() }; if RegisterClassExW(&wc) == 0 { panic!("Failed to register window class."); } // Load the image as a bitmap BITMAP_HANDLE = Some(load_image_as_bitmap("C:\\Users\\mdabr\\Downloads\\IMG_7592.jpg")); // Create the window let hwnd = CreateWindowExW( WS_EX_LAYERED | WS_EX_TOPMOST, &HSTRING::from(window_class), &HSTRING::from(window_name), WS_POPUP, 0, 0, 300, 300, HWND(std::ptr::null_mut()), HMENU(std::ptr::null_mut()), handle_instance, Some(std::ptr::null_mut()) ).unwrap(); // Set window transparency let transparency = 255; if SetLayeredWindowAttributes(hwnd, COLORREF(0), transparency, LWA_ALPHA).is_err() { eprintln!("Failed to set layered window attributes: {}", GetLastError().0); } // Show and update window ShowWindow(hwnd, SHOW_WINDOW_CMD(1)); UpdateWindow(hwnd); // Message loop let mut msg = std::mem::zeroed(); while GetMessageW(&mut msg, HWND(std::ptr::null_mut()), 0, 0).into() { TranslateMessage(&msg); DispatchMessageW(&msg); } // Clean up the bitmap handle if let Some(bitmap) = BITMAP_HANDLE { DeleteObject(bitmap); } } } unsafe extern "system" fn window_proc( hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM, ) -> LRESULT { match msg { WM_PAINT => { let mut ps: PAINTSTRUCT = std::mem::zeroed(); let hdc = BeginPaint(hwnd, &mut ps); if let Some(bitmap) = BITMAP_HANDLE { let hdc_mem = CreateCompatibleDC(hdc); if hdc_mem.0.is_null() { eprintln!("Failed to create compatible DC: {}", GetLastError().0); } if SelectObject(hdc_mem, bitmap).0.is_null() { eprintln!("Failed to select bitmap into DC: {}", GetLastError().0); } // Blit the bitmap to the window if BitBlt(hdc, 0, 0, 300, 300, hdc_mem, 0, 0, SRCCOPY).is_err() { eprintln!("BitBlt failed: {}", GetLastError().0); } DeleteDC(hdc_mem); } EndPaint(hwnd, &ps); return LRESULT(0); } _ => DefWindowProcW(hwnd, msg, wparam, lparam), } } fn load_image_as_bitmap(image_path: &str) -> HGDIOBJ { // Load the image let img = image::open(image_path).expect("Failed to load image"); let (width, height) = img.dimensions(); let img = img.to_rgba8(); // Convert to RGBA // Create a device context for the screen let hdc_screen = unsafe { GetDC(HWND(std::ptr::null_mut())) }; if hdc_screen.0.is_null() { panic!("Failed to get screen DC: {}", unsafe { GetLastError().0 }); } // Create a compatible device context using the screen's DC let hdc = unsafe { CreateCompatibleDC(hdc_screen) }; if hdc.0.is_null() { panic!("Failed to create compatible DC: {}", unsafe { GetLastError().0 }); } // Create a compatible bitmap using the screen's DC let hbitmap = unsafe { CreateCompatibleBitmap(hdc, width as i32, height as i32) }; if hbitmap.0.is_null() { panic!("Failed to create compatible bitmap: {}", unsafe { GetLastError().0 }); } // Set bitmap data let bmp_info_header = BITMAPINFOHEADER { biSize: std::mem::size_of::<BITMAPINFOHEADER>() as u32, biWidth: width as i32, biHeight: -(height as i32), // Negative for top-down bitmap biPlanes: 1, biBitCount: 32, biCompression: 0, ..Default::default() }; let mut bmp_info = BITMAPINFO { bmiHeader: bmp_info_header, bmiColors: [RGBQUAD::default(); 1], }; unsafe { let res = SetDIBitsToDevice( hdc, 0, 0, width as u32, height as u32, 0, 0, 0, height as u32, img.as_raw().as_ptr() as *const _, &mut bmp_info, DIB_RGB_COLORS, ); if res == 0 { eprintln!("SetDIBitsToDevice failed: {}", GetLastError().0); } } // Clean up unsafe { DeleteDC(hdc); ReleaseDC(HWND(std::ptr::null_mut()), hdc_screen); } hbitmap.into() }
内容的提问来源于stack exchange,提问作者Matthew Trip
相关产品推荐
相关产品推荐

