You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 20:33:13