Thread: Windows GetDIBits Call Not Working - I'm desperate - please help - I'm begging!

  1. #1
    Code Monkey Davros's Avatar
    Join Date
    Jun 2002
    Posts
    812

    Windows GetDIBits Call Not Working - I'm desperate - please help - I'm begging!

    Hi there,

    I have a nightmare with the GetDIBits call. It is working 95% of the time, but occasionally fails inexplicably. I say inexplicably, because it returns zero (fail result) but the Windows GetLastError() call says there was no error afterwards.

    Can anyone help? I have put some of my code below, where 'src' is the HBITMAP. Is possible that HBITMAP could be being used by another area of windows at the time? If so, how can I release it?

    Thanks



    Code:
      HDC hdc = 0;
      BITMAPINFO bmi;
      memset(&bmi, 0, sizeof(BITMAPINFO));
      bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    
      // Make temporary compatible device
      hdc = CreateCompatibleDC(0);
    
      // Get dimensions first
      GetDIBits(hdc, (HBITMAP)src, 0, 0, 0, &bmi, DIB_RGB_COLORS);
    
      // We always want positive height (bottom up bmp)
      bmi.bmiHeader.biHeight = abs(bmi.bmiHeader.biHeight);
    
      bmi.bmiHeader.biBitCount = 24;
      bmi.bmiHeader.biCompression = BI_RGB;
      
      // Create memory
      data = new char[bmi.bmiHeader.biSizeImage];
    
       if (GetDIBits(hdc, (HBITMAP)src, 0, bmi.bmiHeader.biHeight, data,
           &bmi, DIB_RGB_COLORS) == 0)
       {
    FAILS HERE
    with GetLastError == 0 (OK?)
       }
    OS: Windows XP
    Compilers: MinGW (Code::Blocks), BCB 5

    BigAngryDog.com

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Read the manual page disclaimer
    biSizeImage
    Specifies the size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps.

    Windows 98/Me, Windows 2000/XP: If biCompression is BI_JPEG or BI_PNG, biSizeImage indicates the size of the JPEG or PNG image buffer, respectively.
    In both these cases, you're not counting pixels

    Since you're passing "RGB" to GetDIBits, perhaps it's actually 0
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    [edit]We both quoted the manual in our answers, possibly there is a message in that somewhere.[/edit]

    Code:
      bmi.bmiHeader.biBitCount = 24;
    It is your responsibility to calculate the size of the bitmap bits as the native bitmap format may not be 24bpp and also:
    Quote Originally Posted by MSDN BITMAPINFOHEADER
    biSizeImage
    Specifies the size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps.
    The code to calculate the required size, taking into account DWORD alignment, is:
    Code:
        bmi.bmiHeader.biSizeImage = ((bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount + 31) & ~31) / 8
                                      * abs(bmi.bmiHeader.biHeight);
    Quote Originally Posted by Davros
    I say inexplicably, because it returns zero (fail result) but the Windows GetLastError() call says there was no error afterwards.
    Unfortunately, the bitmap functions seem not to call SetLastError() on many failure paths.

    Quote Originally Posted by Davros
    Is possible that HBITMAP could be being used by another area of windows at the time? If so, how can I release it?
    You'd have to tell us that. It is true that the bitmap can't be selected into any DC when you call GetDiBits().
    Last edited by anonytmouse; 08-18-2004 at 07:00 AM.

  4. #4
    Code Monkey Davros's Avatar
    Join Date
    Jun 2002
    Posts
    812
    Thanks for the replies

    >In both these cases, you're not counting pixels

    The code I put up was simplified, because I didn't expect people to read through reems of the stuff & made the mistake in the simplification. I've pasted my more complete code below.

    >Unfortunately, the bitmap functions seem not to call SetLastError()

    That's helpful. Thanks. It saves me wasting time trying to figure out why there is no error.


    >You'd have to tell us that. It is true that the bitmap can't be selected into any DC when you call GetDiBits().

    I'm not sure because the HBITMAP I am using is coming from a third-party control (TBitmap if that helps). But I think that is where the problem is. Is there any way I could unselect a HBITMAP from a device context?

    I have in fact read the manual, but still gotta admit I'm not 100% sure about device contexts. For example, I am calling CreateCompatibleDC(0) to a device of the screen. Is this what I should be doing?

    Code:
    int Gfx::create(Gfx& dst, void* src, int cnt, int y)
    {
      // Creates gfx data and fills it with contents of bitmap from
      // platform specific bitmap object src. At the moment, this method
      // only works under windows. Does nothing under any other platform.
    
      // Under windows, src is a HBITMAP & hdSrc is a HDC.
      // Gfx memory data which must be destroyed when finished by calling
      // destroy(). cnt is number of rows to retrieve. If this is <= 0,
      // full bmp height is retrieved. y is row to scan from which defaults
      // to zero if omitted. hdSrc maybe null, in which case screen is used.
      // If this method fails, rslt.data is NULL(0) & returns
      // platform specific error code. Error is -1 if operation
      // is not supported on platform.
      int err;
      if (y < 0) y = 0;
    
      // Ensure existing is destroyed.
      destroy(dst);
    
    #ifdef AIDAWIN
      // WINDOWS IMPLEMENTATION
      // hndl must not be 'selected into a device'
      err = 0;
      HDC hdc = 0;
      BITMAPINFO bmi;
      memset(&bmi, 0, sizeof(BITMAPINFO));
      bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    
      try
      {
        // Make temporary compatible device
        hdc = CreateCompatibleDC(0);
    
        // Get dimensions first
        GetDIBits(hdc, (HBITMAP)src, 0, 0, 0, &bmi, DIB_RGB_COLORS);
    
        // We always want positive height (bottom up bmp)
        bmi.bmiHeader.biHeight = abs(bmi.bmiHeader.biHeight);
    
        // Work out full size count if needed
        if (cnt <= 0) cnt = bmi.bmiHeader.biHeight - y;
    
        // Fill data
        dst.pDim.x = bmi.bmiHeader.biWidth;
        dst.pDim.y = cnt;
    
        // Check we can handle range
        err = ERROR_INVALID_PARAMETER;
    
        if (y + cnt <= bmi.bmiHeader.biHeight && cnt > 0)
        {
          // Set pixel format to be retrieved
          bmi.bmiHeader.biBitCount = 24;
          bmi.bmiHeader.biCompression = BI_RGB;
          unsigned int sz = dst.rowsz() * dst.pDim.y;
    
          if (sz > 0)
          {
            // Create memory array
            dst.pData = new char[sz];
    
            err = 0;
            if (GetDIBits(hdc, (HBITMAP)src, (WORD)y, (WORD)cnt, dst.pData,
              &bmi, DIB_RGB_COLORS) == 0)
            {
              // Error - destroy memory and
              // error code will be set below
              destroy(dst);
    ShowMessage("Y " + IntToStr(y));
    ShowMessage("CNT : " +IntToStr(cnt));
    
            throw Exception("Error " + IntToStr(GetLastError()));
            }
          }
        }
    
        // If no data - set error code
        if (dst.pData == 0)
        {
          dst.pDim = Axy();
          if (err == 0) err = GetLastError();
        }
    
        // Free temporary device context
        DeleteDC(hdc);
      }
      catch(...)
      {
        // Clean-up
        destroy(dst);
        DeleteDC(hdc);
        throw;
      }
    #else
      // NOT SUPPORTED
      err = -1;
    #endif
    
      return err;
    }
    //---------------------------------------------------------------------------
    OS: Windows XP
    Compilers: MinGW (Code::Blocks), BCB 5

    BigAngryDog.com

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. dual boot Win XP, win 2000
    By Micko in forum Tech Board
    Replies: 6
    Last Post: 05-30-2005, 02:55 PM
  2. GetDiskFreeSpaceEx not working on windows XP
    By OOPboredom in forum C++ Programming
    Replies: 1
    Last Post: 05-14-2004, 10:58 PM
  3. Function call not working
    By Drew in forum C++ Programming
    Replies: 3
    Last Post: 09-18-2003, 07:36 PM
  4. IE 6 status bar
    By DavidP in forum Tech Board
    Replies: 15
    Last Post: 10-23-2002, 05:31 PM
  5. Newbie working on a lift simulation
    By dethray79 in forum C++ Programming
    Replies: 1
    Last Post: 10-07-2001, 08:28 AM