• MS docs CreateDIBSection shennigans ? (2bpp bitmap)

    From R.Wieser@21:1/5 to All on Wed Feb 3 08:27:46 2021
    I've been trying to use CreateDIBSection to create a 2bpp bitmap, which
    fails (4bpp works). While looking thru the docs.microsoft.com webpage regarding the function in search of /why/ it fails I stumbled over the following :

    https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-createdibsection
    - - - - - - - - - - - - - - - - - - - -
    If the function fails, the return value is NULL, and *ppvBits is NULL.

    This function can return the following value.
    Return code Description
    ERROR_INVALID_PARAMETER One or more of the input parameters is invalid.
    - - - - - - - - - - - - - - - - - - - -

    And yes, that is as close together as I've posted it.

    So, an error exits is indicated by a NULL *AND* a (possible) 0x57 value ?
    That doesn't make any sense ...

    And no, CreateDIBSection doesn't set the 'GetLastError' value (just tested
    it). :-)

    So, two questions:

    1) How can I check /what/ went wrong ?

    2) Does CreateDIBSection accept a 2 bits per color (CGA) setting ?

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to R.Wieser on Thu Feb 4 20:07:47 2021
    On Wed, 3 Feb 2021 08:27:46 +0100, R.Wieser wrote:
    I've been trying to use CreateDIBSection to create a 2bpp bitmap, which
    fails (4bpp works).

    2) Does CreateDIBSection accept a 2 bits per color (CGA) setting ?

    BMP format can store 2bpp, but it doesn't officially support 2bpp. So,
    almost all softwares will not be able to view the image. With a handcrafted 2bpp BMP, out of (Windows) Paint, Irfanview, FastStone Image Viewer, XnView, GIMP, Corel PaintShop Pro; and MSIE, Firefox, Chrome; only XnView and Chrome are able to view it.

    - - - - - - - - - - - - - - - - - - - -
    If the function fails, the return value is NULL, and *ppvBits is NULL.

    This function can return the following value.
    Return code Description
    ERROR_INVALID_PARAMETER One or more of the input parameters is invalid.
    - - - - - - - - - - - - - - - - - - - -

    And yes, that is as close together as I've posted it.

    So, an error exits is indicated by a NULL *AND* a (possible) 0x57 value ? That doesn't make any sense ...

    And no, CreateDIBSection doesn't set the 'GetLastError' value (just tested it). :-)

    So, two questions:

    1) How can I check /what/ went wrong ?

    I think you misunderstood the documentation. It specifically states:

    [quote]
    If the function succeeds, the return value is a handle to the newly created DIB, and *ppvBits points to the bitmap bit values.
    [/quote]

    So, if the return value is NULL *OR* *ppvBits is NULL, it means that the function fails. Remember that a NULL handle is basically an invalid handle value. So, "a handle" generally means a valid handle, unless stated
    otherwise. Especially considering that a NULL Bitmap handle isn't associated with any data.

    As for GetLastError, there is indeed a bug where the last error code is not updated when the function fails. At least when the given biBitCount value is unsupported. But if CreateDIBSection succeeds, the last error is not
    updated.

    FYI, in Borland's VCL framework library, it simply use the return value as
    the main indicator of success. GetLastError is only used when the return
    value is NULL. *ppvBits is not checked and is only used when the function returns non NULL.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Thu Feb 4 15:23:06 2021
    JJ,

    BMP format can store 2bpp,

    indeed.

    but it doesn't officially support 2bpp.

    Who's "it" ? the BMP guys or just MS ? :-)

    I think you misunderstood the documentation.

    I did ? I don't think so ...

    It specifically states:

    [quote]
    If the function succeeds, the return value is a handle to the newly
    created DIB, and *ppvBits points to the bitmap bit values.
    [/quote]

    That part I understood.

    The problem is it *also* states :

    [quote=me]
    This function can return the following value.
    Return code Description
    ERROR_INVALID_PARAMETER One or more of the input parameters is invalid. [/quote]

    Who/what is returning that "invalid parameter" result ?

    As for GetLastError, there is indeed a bug where the last error code is
    not updated when the function fails. At least when the given biBitCount
    value is unsupported.

    Ah. So it boils down to that the documentation forgot to mention that GetLastError is involved.

    I assumed as much, but as it didn't return an error code when it, as far as
    I could tell, should have (due to that bug you mentioned) I began to doubt
    my assumption. Hence my question.

    By the way: I found GdiSetLastError, but no complementing getter ... It
    also doesn't help that a google shows that MS doesn't know anything about
    that function (anymore).

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to R.Wieser on Fri Feb 5 15:34:16 2021
    On Thu, 4 Feb 2021 15:23:06 +0100, R.Wieser wrote:

    Who's "it" ? the BMP guys or just MS ? :-)

    Uh, those BMP guys *is* MS, because MS is the one who created BMP.

    Who/what is returning that "invalid parameter" result ?

    GetlastError, of course. HBITMAP's integer value shouldn't be treated as an error code. But due to the bug, CreateDIBSection may forgot to call SetLastError.

    Ah. So it boils down to that the documentation forgot to mention that GetLastError is involved.

    I knew it... Turns out that we're both reading different versions of the documentation. In the Windows 7 SDK (SDK v6.1), the whole "Return Values" section is this.

    [quote]
    If the function succeeds, the return value is a handle to the newly created DIB, and *ppvBits points to the bitmap bit values.

    If the function fails, the return value is NULL, and *ppvBits is NULL.

    Windows NT/2000/XP: To get extended error information, call GetLastError.
    This can be the following value.

    Value Meaning
    ERROR_INVALID_PARAMETER One or more input parameters is invalid.
    [/quote]

    SDK for Windows 8+ no longer have any offline documentation. That's when MS migrated to "community" based documentation - which is less detailed.

    Even the SDK documentations for Win95 & NT4.0 no longer describe any
    resource data format. Only Win3.x SDK does, albeit briefly.

    By the way: I found GdiSetLastError, but no complementing getter ... It also doesn't help that a google shows that MS doesn't know anything about that function (anymore).

    I've debugged CreateDIBSection. GdiSetLastError does the same thing as SetLastError, which is to set the last error field in the process' TEB structure.

    CreateDIBSection calls GdiSetLastError with ERROR_INVALID_PARAMETER and
    nothing else, but only if BITMAPINFOHEADER.biCompression is JPEG or PNG. Any other unacceptable BITMAPINFOHEADER fields won't cause it call
    GdiSetLastError at all. Instead, it simply returns NULL.

    And FYI, it only supports 1, 4, 8, 16, 24, and 32 bits; as expected. No
    support for 15 bits either, which Photoshop and/or PaintShop Pro (can't remember exactly) can actually create and use.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to All on Fri Feb 5 11:01:43 2021
    JJ,

    Who's "it" ? the BMP guys or just MS ? :-)

    Uh, those BMP guys *is* MS, because MS is the one who created BMP.

    I should have been more specific : is "it" the BMP guys who wrote the specs
    and just "allowed" the 2bpp mode to exist, but did not officially include it
    in their definition, or is "it" MS who, even though supporting 2bpp is as complicated as 4bpp, have decided not to implement - and thus support - it
    for some reason.

    "Somehow" I think its the second ...

    Ah. So it boils down to that the documentation forgot to mention that
    GetLastError is involved.

    I knew it... Turns out that we're both reading different versions of the documentation.

    Thats why I included the link to the page I found. :-)

    Windows NT/2000/XP: To get extended error information, call GetLastError. This can be the following value.

    I cannot help but wonder : What would you need to do on Vista, 7, 8 and 10 ? And why didn't they mention it ? <whistle>

    I've debugged CreateDIBSection. GdiSetLastError does the same thing
    as SetLastError, which is to set the last error field in the process' TEB structure.

    I was a bit too busy with other stuff to disassemble GDI32 and look at what GdiSetLastError actually does, but I imagined it could just have been a "hardlink" to Kernel32's SetLastError.

    And FYI, it only supports 1, 4, 8, 16, 24, and 32 bits; as expected.

    Not supporting 2bpp is unexpected to me. For the rest ? Yup, either
    values that cleanly divide 8 bits (no remainder) or multiples of it.

    I could have imagined that 8bpp would /also/ support an 2, 3, 2 color usage (similar to 16bpp, just smaller).

    No support for 15 bits either,

    Actually ... Although the 16bpp mode uses 16 bits to /store/ the pixel, by default CreateDIBSection uses just 5 bits for each of the red, green and
    blue colors - adding up to a total of just 15 bits. :-)

    That stuff makes my brain hurt - just by trying to imagine why such choices where made.

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From JJ@21:1/5 to R.Wieser on Sat Feb 6 20:38:00 2021
    On Fri, 5 Feb 2021 11:01:43 +0100, R.Wieser wrote:

    I cannot help but wonder : What would you need to do on Vista, 7, 8 and 10 ? And why didn't they mention it ? <whistle>

    While it might be due to incompetence of the one who filter the
    documentation, the filtering itself exist because MS hate their bad-for-bussiness old Windows versions.

    but I imagined it could just have been a
    "hardlink" to Kernel32's SetLastError.

    Ideally, yes. But it's like copy-pasted source code of SetLastError which
    was renamed to GdiSetLastError instead.

    Not supporting 2bpp is unexpected to me. For the rest ? Yup, either
    values that cleanly divide 8 bits (no remainder) or multiples of it.

    If I read the Windows history, Windows never did support 2-bit display.
    Windows (v1.0) development started when EGA doesn't yet exist. CGA's 2-bit 320x200 display is equal to 40x25 text display mode, whose pixel resution is way too low for Windows. So, Windows uses 1-bit 640x200 display mode instead
    - which is used when it was first presented to puclic (at 1983, before EGA
    was born). 4-bit display wasn't possible and officially supported until 1
    year later after EGA was born.

    In EGA display adapter, 640x350 was the only other 2-bit display. But EGA
    also has 4-bit 640x350. MS think that, there's no point of using 4-colors graphics when 16-colors one is already available - especially if the code
    for handling 2-bit graphic is not yet available. BMP's lack of support for 2-bit graphics is simply because there's no code for handling 2-bit image.

    1-bit image handling on the other hand, is still needed and supported,
    because it is used by fax machines and printers. But only for image
    processing. Speaking of 1-bit, it'll be interresting if we can use 1-bit 1024x768 screen. :)

    Actually ... Although the 16bpp mode uses 16 bits to /store/ the pixel, by default CreateDIBSection uses just 5 bits for each of the red, green and
    blue colors - adding up to a total of just 15 bits. :-)

    Oh, right. I forgot about that.

    But it depends on the compression type. If it's RGB, it uses R5G5B5. If it's Bitfields, it uses R5G6B5.

    15-bit Super VGA display adapter's native pixel format is R5G5B5, so BMP
    can't actually store that format, because it can only store is as RGB
    format.

    That stuff makes my brain hurt - just by trying to imagine why such choices where made.

    Likely due to new innovasions and adaptations. If we have VGA as the first display technology, we might not have 1-bit and 4-bit pixel formats.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From R.Wieser@21:1/5 to research and on Sat Feb 6 16:01:28 2021
    JJ,

    While it might be due to incompetence of the one who filter
    the documentation,

    You mean, similar to those clbuttic search-and-replace mistakes ? :-)

    the filtering itself exist because MS hate their
    bad-for-bussiness old Windows versions.

    You noticed it too. :-\

    I'm currently wondering what will happen first : that my XP becomes unsuable for access of the web (forcing me to move on to ... well, something else),
    or that all XP documentation will be eradicated (making it impossible to research and write anything new for it).

    4-bit display wasn't possible and officially supported until 1
    year later after EGA was born.

    I still cannot quite fathom why the 2bpp mode was not created alongside of
    the 4bpp one. I mean, apart from a different ammount of colors both methods look to be the same, making it pretty-much a freebee.

    Than again, I tend to write my stuff with re-usability in mind. :-)

    BMP's lack of support for 2-bit graphics is simply because
    there's no code for handling 2-bit image.

    That actually makes some sense. Thanks for the timeline & explanation.

    Actually ... Although the 16bpp mode uses 16 bits to /store/ the pixel,
    by
    default CreateDIBSection uses just 5 bits for each of the red, green and
    blue colors - adding up to a total of just 15 bits. :-)

    Oh, right. I forgot about that.

    But it depends on the compression type. If it's RGB, it uses R5G5B5.

    Which it does.

    If it's Bitfields, it uses R5G6B5.

    :-) Not quite. In that case *you* have to set the bitmasks for each of the colors.

    (pardon me for being a bit of a pedant. Somehow I get the feeling you know more about the subject than I will ever do)

    Years ago I read about how grand that that was, 'cause you could assign
    color depth for them depending on the scene: lots of lush green forrest ?
    Use a R4G8B4 scheme. Lots of blue sea ? Give B the 8 (or even more)
    bits.

    That stuff makes my brain hurt - just by trying to imagine why such
    choices
    where made.

    Likely due to new innovasions and adaptations. If we have VGA as the first display technology, we might not have 1-bit and 4-bit pixel formats.

    True.

    As you have pretty-much pointed out, I'm using 20/20 vision looking back
    into history. Choices often look simple from that vantage point. The other way around ? Not so much.

    Regards,
    Rudy Wieser

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)