Get bits to [u8] from HBITMAP

I've got HBITMAP with bitblt( ) method, and want to get color bits to [u8], the following code get zero bits:

       let mut bmp: Vec<u8> = vec![]; 

      let res =    GetBitmapBits(
          hbitmap,  
          std::mem::size_of::<BITMAP>() as i32, 
          bmp.as_mut_ptr() as LPVOID, 
      );
       println!("res:{}", res);

where is wrong? should I use GetBitmapBits( ) or GetObject( ) function ?

bmp is an empty Vec. GetBitmapBits can't just resize it to be non-empty. You will need to give it the right size first. By the way GetBitmapBits returns 0 when there is an error according to the docs.

1 Like

you are correct.
I initalized bmp, this gives res of '32', which seems still incorrect, and should be the size of image.

      let mut bmp: Vec<u8> = vec![0; 1920*1080]; 

      let res =    GetBitmapBits(
          hbitmap,  
          std::mem::size_of::<BITMAP>() as i32, 
          bmp.as_mut_ptr() as LPVOID, 
      );
       println!("res:{}", res);

If bmp got correct bits, it'll used to create a bitmap with this function :

pub fn with_data(_: (u32, u32), with_alpha: bool, pixmap: &[u8]) -> Result<Image>

so for now, this code panic, gives an error of exit code: 0xc0000005, STATUS_ACCESS_VIOLATION

 sciter::graphics::Image::with_data((1920, 1080), false, &bmp );

Where are you getting the hbitmap from? It might help if you posted a full example of what you've done to retrieve it.

The whole code:

        let handle = GetDesktopWindow();
        let mut HDC_screen = um::winuser::GetDC(handle); 
        let mut HDC_compatible_DC = um::wingdi::CreateCompatibleDC(HDC_screen);
        let hbitmap = um::wingdi::CreateCompatibleBitmap(HDC_screen,  1920, 1080);   
        let hold =um::wingdi::SelectObject(HDC_compatible_DC, hbitmap as shared::windef::HGDIOBJ);
        let my_bit_blt: shared::minwindef::BOOL = um::wingdi::BitBlt(
                                               HDC_compatible_DC, 
                                               0,  0, 1920, 1080, 
                                               HDC_screen,  0,  0,
                                               um::wingdi::SRCCOPY|um::wingdi::CAPTUREBLT); 

        let mut bmp: Vec<u8> = vec![0; 1920*1080]; 
      let res =    GetBitmapBits(
          hbitmap,  
          std::mem::size_of::<BITMAP>() as i32, 
          bmp.as_mut_ptr() as LPVOID, 
      );
       println!("res:{}", res);

      sciter::graphics::Image::with_data((1920, 1080), false, &bmp );

This function should be able to do what you're looking for. Note that each returned pixel has the components [b, g, r, 0_u8]; since Image::with_data expects BGRA pixels, it should work directly, although I don't have sciter available to test.

fn screenshot() -> (u32, u32, Vec<u8>) {
    use std::{mem, ptr};
    use winapi::{
        shared::minwindef,
        um::{wingdi, winuser},
    };
    unsafe {
        let width = winuser::GetSystemMetrics(winuser::SM_CXSCREEN);
        assert!(width != 0);
        let height = winuser::GetSystemMetrics(winuser::SM_CYSCREEN);
        assert!(height != 0);
        let screen = winuser::GetDC(ptr::null_mut());
        assert!(!screen.is_null());
        let dc = wingdi::CreateCompatibleDC(screen);
        assert!(!dc.is_null());
        let bitmap = wingdi::CreateCompatibleBitmap(screen, width, height);
        assert!(!bitmap.is_null());
        let result = wingdi::SelectObject(dc, bitmap.cast());
        assert!(!result.is_null());
        let result = wingdi::BitBlt(dc, 0, 0, width, height, screen, 0, 0, wingdi::SRCCOPY);
        assert!(result != 0);
        assert!(winuser::ReleaseDC(ptr::null_mut(), screen) == 1);
        let mut header = wingdi::BITMAPINFOHEADER {
            biSize: mem::size_of::<wingdi::BITMAPINFOHEADER>() as minwindef::DWORD,
            biWidth: width,
            biHeight: -height,
            biPlanes: 1,
            biBitCount: 32,
            biCompression: wingdi::BI_RGB,
            biSizeImage: 0,
            biXPelsPerMeter: 0,
            biYPelsPerMeter: 0,
            biClrUsed: 0,
            biClrImportant: 0,
        };
        let buf_size = width as usize * height as usize * 4;
        let mut buffer: Vec<u8> = Vec::with_capacity(buf_size);
        let result = wingdi::GetDIBits(
            dc,
            bitmap,
            0,
            height as minwindef::UINT,
            buffer.as_mut_ptr().cast(),
            &mut header as *mut _ as wingdi::LPBITMAPINFO,
            wingdi::DIB_RGB_COLORS,
        );
        assert!(result == height);
        buffer.set_len(buf_size);
        assert!(wingdi::DeleteObject(bitmap.cast()) != 0);
        assert!(wingdi::DeleteDC(dc) != 0);
        (width as u32, height as u32, buffer)
    }
}

Most of this program was adapted from the Capturing an Image example on Microsoft Docs.

Cool. It works. Thank you

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.