How to use UpdateLayeredWindow for drawing a bitmap to screen (with alpha)

Tovernaar123 20 Reputation points
2023-05-25T19:04:29.6266667+00:00

I am trying to draw a bitmap to screen that has rgba to my layered window I tried using the UpdateLayeredWindow function but altough it does not error (it returns 1) I don't see any red square which is what I expected what I am doing wrong? (I might be missing something very obvious I have never used the winapi before.)

Here is my code its in rust with the winapi crate (the winapi functions).


use std::{
    error::Error,
    os::windows::prelude::OsStrExt,
    ptr::{null, null_mut},
};

use winapi::{
    ctypes::*,
    shared::{minwindef::*, windef::*},
    um::{libloaderapi::GetModuleHandleW, wingdi::*, winuser::*},
};

fn to_wstring(value: &str) -> Vec<u16> {
    std::ffi::OsStr::new(value)
        .encode_wide()
        .chain(std::iter::once(0))
        .collect()
}

fn main() {
    let hdl = create_main_window("my_windeow", "Exaemple window creation");
    match hdl {
        Ok(hdl) => unsafe {
            let r = ShowWindow(hdl, SW_SHOW);

            let mut rect = std::mem::MaybeUninit::<RECT>::uninit();
            if GetWindowRect(hdl, rect.as_mut_ptr()) != 0 {
                let rect = rect.assume_init();
                println!("Window position: ({}, {})", rect.left, rect.top);
                println!(
                    "Window size: {}x{}",
                    rect.right - rect.left,
                    rect.bottom - rect.top
                );
            } else {
                // Handle error
            }
            println!("{:#?} 306", r);
            draw(hdl);
            run_message_loop(hdl);
        },
        Err(e) => {
            println!("{:#?} 311", e);
        }
    }
}

fn run_message_loop(hwnd: HWND) -> WPARAM {
    unsafe {
        let mut msg: MSG = std::mem::uninitialized();
        loop {
            // Get message from message queue
            if GetMessageW(&mut msg, hwnd, 0, 0) > 0 {
                TranslateMessage(&msg);
                DispatchMessageW(&msg);
            } else {
                // Return on error (<0) or exit (=0) cases
                return msg.wParam;
            }
        }
    }
}
fn create_main_window(name: &str, title: &str) -> Result<HWND, Box<dyn Error>> {
    let name = to_wstring(name);
    let title = to_wstring(title);

    unsafe {
        // Get handle to the file used to create the calling process
        let hinstance = GetModuleHandleW(null_mut());

        // Create and register window class
        let wnd_class = WNDCLASSEXW {
            cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
            style:  CS_HREDRAW | CS_VREDRAW,
            lpfnWndProc: Some(window_proc),
            cbClsExtra: 0,
            cbWndExtra: 0,
            hInstance: hinstance, // Handle to the instance that contains the window procedure for the class
            hIcon: LoadIconW(null_mut(), IDI_APPLICATION),
            hCursor: LoadCursorW(null_mut(), IDC_ARROW),
            hbrBackground: CreateSolidBrush(0),
            lpszMenuName: null_mut(),
            lpszClassName: name.as_ptr(),
            hIconSm: LoadIconW(null_mut(), IDI_APPLICATION),
        };

        // Register window class
        if RegisterClassExW(&wnd_class) == 0 {
            MessageBoxW(
                null_mut(),
                to_wstring("Window Registration Failed!").as_ptr(),
                to_wstring("Error").as_ptr(),
                MB_ICONEXCLAMATION | MB_OK,
            );
            return Err("Window Registration Failed".into());
        };

        // Create a window based on registered class
        let handle: *mut HWND__ = CreateWindowExW(
            WS_EX_LAYERED | WS_EX_TRANSPARENT | WS_EX_TOPMOST | WS_EX_APPWINDOW, //| WS_EX_TOOLWINDOW,
            name.as_ptr(),
            title.as_ptr(),
            0,
            0,
            0,
            2560,
            1440,
            null_mut(),
            null_mut(),
            hinstance,
            null_mut(),
        );

        if handle.is_null() {
            MessageBoxW(
                null_mut(),
                to_wstring("Window Creation Failed!").as_ptr(),
                to_wstring("Error!").as_ptr(),
                MB_ICONEXCLAMATION | MB_OK,
            );
            return Err("Window Creation Failed!".into());
        }
        //SetWindowLongA(handle, GWL_STYLE, 0);
        //SetLayeredWindowAttributes(handle, 0, 100 as u8, LWA_ALPHA);

        Ok(handle)
    }
}
unsafe fn draw(hdl: HWND) {
    let window = GetDC(hdl);
    let hdc = CreateCompatibleDC(window);
    let header = BITMAPINFO {
        bmiHeader: BITMAPINFOHEADER {
            biSize: std::mem::size_of::<BITMAPINFOHEADER>() as u32,
            biWidth: 2560,
            biHeight: 1440,
            biPlanes: 1,
            biBitCount: 32,
            biCompression: BI_RGB,
            biSizeImage: 2560 * 1440 * 4,
            biXPelsPerMeter: 0,
            biYPelsPerMeter: 0,
            biClrUsed: 0,
            biClrImportant: 0,
        },
        bmiColors: [RGBQUAD {
            rgbBlue: 0,
            rgbGreen: 0,
            rgbRed: 0,
            rgbReserved: 0,
        }],
    };
    let mut null_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
    let pv_bits: *mut *mut std::ffi::c_void = &mut null_ptr;
    let hbitmap = CreateDIBSection(hdc, &header, DIB_RGB_COLORS, pv_bits, null_mut(), 0x0);
    let buf = *pv_bits as *mut [u32; 2560 * 1440];
    for i in 0..2560 * 1440 {
        (*buf)[i] = 0xFFFF0000;
    }
    SelectObject(hdc, hbitmap as *mut c_void);
    let blend: *mut BLENDFUNCTION = &mut BLENDFUNCTION {
        BlendOp: AC_SRC_OVER,
        BlendFlags: 0,
        SourceConstantAlpha: 255,
        AlphaFormat: AC_SRC_ALPHA,
    } as *mut BLENDFUNCTION;
    let point: *mut POINT = &mut POINT { x: 0, y: 0 } as *mut POINT;
    let x = UpdateLayeredWindow(
        hdl,
        null_mut(),
        null_mut(),
        null_mut(),
        hdc,
        point,
        0,
        blend,
        ULW_ALPHA,
    );

    //prints 1 which means no error
    println!("{:#?} 448", x);
}

pub unsafe extern "system" fn window_proc(
    hwnd: HWND,
    msg: UINT,
    wparam: WPARAM,
    lparam: LPARAM,
) -> LRESULT {
    match msg {
        WM_CLOSE => {
            DestroyWindow(hwnd);
        }
        WM_DESTROY => {
            PostQuitMessage(0);
        }
        WM_LBUTTONDOWN => {}
        WM_PAINT => {}
        WM_CREATE => {
            //draw(hwnd);
        }
        _ => return DefWindowProcW(hwnd, msg, wparam, lparam),
    }
    return 0;
}

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,511 questions
0 comments No comments
{count} votes

Accepted answer
  1. Junjie Zhu - MSFT 16,551 Reputation points Microsoft Vendor
    2023-05-26T06:58:04.0233333+00:00

    Hello @Tovernaar123 ,

    Welcome to Microsoft Q&A!

    The psize parameter is required in function UpdateLayeredWindow, you need to add the size of the bitmap.

    The following is my test using C++. After adding the size parameter, the bitmap is displayed normally.

    SIZE bitmapsize;
    bitmapsize.cx = 2560;
    bitmapsize.cy = 1440;
        
    auto x = UpdateLayeredWindow(hdl, nullptr, nullptr, &bitmapsize, hdc, &ptSrc, 0, &Blend, ULW_ALPHA);
    
    

    Thank you.

    Junjie


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful