none
GetDIBits

    Question

  • I believe the paragraph

    "If lpvBits is NULL and the bit count member of BITMAPINFO is initialized to zero, GetDIBits fills in a BITMAPINFOHEADER structure or BITMAPCOREHEADER without the color table. This technique can be used to query bitmap attributes." in GetDIBits


    should be stated like this :

    "If the bit count member of BITMAPINFO is initialized to zero, GetDIBits fills in a BITMAPINFOHEADER structure or BITMAPCOREHEADER without the color table. This technique can be used to query bitmap attributes."

    Or, is it the case that the function does not fill in a color table when lpvBits != NULL ? If that case, why is it so ?
    Monday, December 22, 2008 12:35 PM

All replies

  •  

    I decided to do some testing with the following code

    //  Load bitmap 
             
    hBitmap = LoadBitmap(ghInstance, MAKEINTRESOURCE(1)); 
    GetObject(hBitmap, sizeof(bm), &bm); 
             
    //  Get DC and Process Heap 
             
    hDC = GetDC(hWnd); 
    hHeap = GetProcessHeap(); 
             
    //  Allocate BITMAPINFOHEADER  
             
    lpbmi = (BITMAPINFO*)HeapAlloc(hHeap, 0, sizeof(BITMAPINFOHEADER)); 
             
    //  Initialize biSize and ciBitCount fields of BITMAPINFOHEADER  
             
    lpbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
    lpbmi->bmiHeader.biBitCount = 0
             
    //  Fill the BITMAPINFOHEADER struct 
             
    i = GetDIBits(hDC, hBitmap, 0, bm.bmHeight, NULL, lpbmi, DIB_RGB_COLORS); 
             
    //  Allocate bitmap bytes 
             
    lpvBits = (LPSTR)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, lpbmi->bmiHeader.biSizeImage); 
             
    //  Fill buffer lpvBits with DIB's array 
             
    j = GetDIBits(hDC, hBitmap, 0, bm.bmHeight, lpvBits, lpbmi, DIB_RGB_COLORS); 
    dw = GetLastError(); 
             
    //  Free buffers and DC 
             
    HeapFree(hHeap, 0, lpbmi); 
    HeapFree(hHeap, 0, lpvBits); 
    ReleaseDC(hWnd, hDC); 


    The program runs fine, i.e., the 2nd call to function GetDIBits() returns 96, which is the number of scan lines copied from the bitmap.

    Something wird happens when I replace lpbmi->bmiHeader.biSizeImage (36864) by an integer :

    29000 or greater - GetDIBits() still returns 96.
    28000 or lower - GetDIBits() returns 0 and GetLastError() returns 0.

    I don't see how GetDIBits() can change its behaviour, with the size of lpvBits buffer, without knowing it !!!

    Monday, December 22, 2008 5:16 PM

  • After a while I noticed that the first call to GetDIBits() returned with the biCompression = BI_BITFIELDS, which led me to conclude that the GetDIBits() function will always insert a color table consisting of 3 DWORD's masks in the BITMAPINFO structure, for a 32 bpp device like mine, and perhaps also for a 16 bpp device !!

    As a matter of fact, those 3 DWORDS are already being used by the GetDIBits(), beyond the sizeof(BITMAPINFOHEADER) = 40 bytes allocated for lpbmi. I also presume that since the memory fault didn't occur within my code, it was not catched by the debugger !!

    To avoid these pitfalls, I adjusted the program by allocating more 3 * sizeof(DWORD) bytes to the buffer in lpbmi.


    //  Load bitmap 
             
    hBitmap = LoadBitmap(ghInstance, MAKEINTRESOURCE(1)); 
    GetObject(hBitmap, sizeof(bm), &bm); 
            
    //  Get DC and Process Heap 
             
    hDC = GetDC(hWnd); 
    hHeap = GetProcessHeap(); 
             
    //  Allocate BITMAPINFOHEADER 
             
    //  *** Attention ***       GetDIBits() will always insert a color table with 3 DWORD masks for a 
    //                          device (hDC) with 16, ou 32 bpp. 
    // 
    //                          Since this computer has a 32 bpp device, these masks will be included 
    //                          automatically, in the structure BITMAPINFO, obtained in the first call 
    //                          to the function GetDIBits(). 
    // 
    //                          That's why we're adding the 3 * sizeof(DWORD) bytes to the size of the 
    //                          BITMAPINFOHEADER struct below.                           
             
    lpbmi = (BITMAPINFO*)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 
                                           3 * sizeof(DWORD)); 
             
    //  Initialize biSize and ciBitCount fields of BITMAPINFOHEADER  
             
    lpbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 
    lpbmi->bmiHeader.biBitCount = 0;                        //  If biBitCount != 0, GetDIBits() returns 0, i.e., the 
                                                            //  function fails. 
             
    //  Fill the BITMAPINFOHEADER struct 
             
    i = GetDIBits(hDC, hBitmap, 0, bm.bmHeight, NULL, lpbmi, DIB_RGB_COLORS); 
             
    //  We'll leave the biCompression member with BI_BITFIELDS(3), since we have already allocated the 
    //  space for the 3 DWORD's bytes. 
             
    //  Allocate bitmap bytes 
             
    //  *** Attention ***   But again, if I replace lpbmi->bmiHeader.biSizeImage by 28000 the function 
    //                      fails. If I replace it by 29000, the function returns 96 !!! 
    // 
    //                      How can that be, if it doesn't know lpbmi size ???  
             
    lpvBits = (LPSTR)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, lpbmi->bmiHeader.biSizeImage); 
             
    //  Fill buffer lpvBits with DIB's array 
             
    j = GetDIBits(hDC, hBitmap, 0, bm.bmHeight, lpvBits, lpbmi, DIB_RGB_COLORS); 
    dw = GetLastError(); 
             
    //  Free buffers and DC 
             
    HeapFree(hHeap, 0, lpbmi); 
    HeapFree(hHeap, 0, lpvBits); 
    ReleaseDC(hWnd, hDC); 


    However, my original concerns remain. How the 2nd call to GetDIBits() change its behaviour with the size of the lpvBits buffer ???

    Monday, December 22, 2008 9:48 PM
  • Would there be a problem if I post this discussion in another forum, like Discussions in Win32 Graphics Display Interface Programming ?

    Thanks.
    Wednesday, December 24, 2008 12:40 AM
  • Please do. Multiposting is generally discouraged, but if you've gone a while with no response (a few days in this case), it's probably for the best to find a more pertinent forum.
    Wednesday, December 24, 2008 12:46 AM
  • After some research and some difficulty (my debugger Step into function is not working) I found out that the function GetDIBits() in its assembly calls the sysenter command. From what I've read, this command transfers the execution from user to kernell mode.

    I was wondering if in Kernell mode, the code, once in a while, could verify the validity of the  address it's copying the DIB image bytes ?

    If that is possible, then we might have an answer for the enigma !
    Wednesday, December 24, 2008 1:38 AM
  • Just to better understand what's going on, I tested the program with 2 alternatives :

    1) Passing the address lpvBits to GetDIBits() where just 1 (nominal) byte was allocated by HeapAlloc().

    2) Passing the address of a BYTE internal variable in the stack.


    I'll try to summarize my findings regarding those alternatives :

    a) Both come to execute the following instructions in gdi32.dll :

    77F1A035 test byte ptr [ebp + 18h], 3
    77F1A039 jne 77F3318E

    b) Alternative (1) falls through with the next instruction, until it gets to execute sysenter in ntdll.dll .

    c) Alternative (2) jumps to the instruction at the address 77F3318E and eventually will also execute sysenter in ntdll.dll .

    d) After that, the debugger catches an unhandled exception, but only for alternative (2), and no bitmap byte is copied into lpvBits in alternative (1).

    I'm just baffled by all this. Could anyone give me a hint, on what's going on here !!!!


    Wednesday, December 24, 2008 1:19 PM