Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CreateDIBSection is whipping me... All I want is a pointer to display memory

783 views
Skip to first unread message

Decl...@my-dejanews.com

unread,
Nov 17, 1998, 3:00:00 AM11/17/98
to
Scenario:
Need quick & dirty, high compression, >free<, command line driven
screengrabber

Solution:
Ind. JPEG Group's free (both senses) JPEG library
Quick Win32-based screen scan to feed the library.

Status:
Library: 2 hours to find, evaluate, and adapt.
Windows (tm) screen handling: Oh, say, 12 hours? So far.

Now, while GetPixel does work, it's an order of magnitude too slow.

I'm aware of CreateDIBSection, but can't make heads nor tails of the
incantations needed to derive a simple pointer to memory.

I've tried so many variations on getting, creating, blessing, inverting,
compatiblizing, moving, Blt-ing, stretching DCs, DIB, Bitmaps yada yada yada.
that I figure it's best to just present an objective rather than the mess I've
got.

If someone can give me a way to get a simple, itsy bitsy little pointer to the
display memory or it's equivalent, I can take it from there.

I need to support NT4, SP0. Win95a would be nice. Elegance strictly optional
at this point.

Thanks,
-Greg

P.S. Anyone want to suggest some resources for to bring a hardcore technical
programmer quickly up to speed on the Win32 architecture? (5+ years
professional C/++, *ix, G90 coding experience with some hobbyist Win 3.1 code)
If you teach me to fish, I won't have to pester you in the future, right?

Along that vein, all the example code I can find sort of implies a familiarity
with a highly non-intuitive master plan, with various calls to create, select,
realize, etc. objects that wouldn't seem to need to exist at all.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

Chris Becke

unread,
Nov 17, 1998, 3:00:00 AM11/17/98
to
Decl...@my-dejanews.com wrote:

>Scenario:
> Need quick & dirty, high compression, >free<, command line driven
>screengrabber
>
>Solution:
> Ind. JPEG Group's free (both senses) JPEG library
> Quick Win32-based screen scan to feed the library.
>
>Status:
> Library: 2 hours to find, evaluate, and adapt.
> Windows (tm) screen handling: Oh, say, 12 hours? So far.
>
>Now, while GetPixel does work, it's an order of magnitude too slow.

erm,

HDC hdcScreen = GetDC(NULL);

// Now you have a DC that represents the screen.

HBITMAP hbmdib = CreateDIBSection(... // create a DIBSection in your
preferred format the same size as the screen

// Make a DC to hold the DIBSection, and put the DIBSection in it.
HDC hdcTmp = CreateCompatibleDC(hdcScreen);
HBITMAP hbmT = SelectObject(hdcTmp,hbmDib);

// Get a copy of the screen into the DIBSection...

BitBlt(hdcTmp,0,0,cx,cy,hdcScreen,0,0,SRCCOPY);

// Clean up, and pass the bits in the DIBSection to the JPEG library...

Chris.
--
Email: <pu...@qoa.yvn.arg> (ROT13 encoded to discourage spam)
Www: <http://users.lia.net/chris>
Work: <http://www.microgaming.com>


Henry Troup

unread,
Nov 17, 1998, 3:00:00 AM11/17/98
to
Decl...@my-dejanews.com wrote:
>
> Scenario:
> Need quick & dirty, high compression, >free<, command line driven
> screengrabber


Recently did something on these lines. You may not be happy with JPEG -
"gd" is a GIF-compatible free package. JPEG images will not handle
straight lines, due to the nature of the compression. You might want to
make a test image that's "zebra-stripes" to observe the effects before
doing too much work.


MS's wincap sample is a reasonable starting point. The critical code is
much as Chris Becke presented it. Actually, MS takes a different tack,
BitBlt into a "compatible" bitmap (driver-dependent) then using
GetDIBits to extract a DIB.

Watch out for DIBs - they're upside-down and packed to DWORD (mod 4 = 0)
alignment. Neglecting this gets you mirror images that slant sideways.
Microsoft has atricles on the DIB format on the
http://msdn.microsoft.com/ site.

I have the same background as you, but am a little farther along. If
you're doing this stuff for money, get the MSDN library. Even if you're
not, consider it. It's moderately priced, heaps of sample software and
documentation, 3 CDs.

As for books, Petzold's "Programming Windows 95" (Microsoft Press) is
very good, as is Ivor Hortons "Beginning Visual C++" (Wrox Press)
--
Henry Troup h...@nortel.ca Nortel Public Carrier Networks
My personal position or opinion should not be taken for
the official position or opinion of Nortel

Decl...@my-dejanews.com

unread,
Nov 18, 1998, 3:00:00 AM11/18/98
to ch...@dbn.lia.net
Chris,

Thanks for your help so far.

Here's my best stab so far at using CreateDIBSection... It's really rough &
poorly structured, but until I actually get it to function I'm loath to pretty
it up.

Outstanding issues are:
Code does not work.
The Blt to hdcMem changes the memory pointed at by pstScreen,
but the data appears invalid.
Shouldn't every 4th byte be zero?
Cleanup
Can I nuke everything but the pointer?
If so, can I expect it to persist across calls?
Assuming not, which bitmap should be static?
Screen Geometry
I'm assuming using GetDIBits to fill bmiScr is valid, no?

Again, any help you can render is greatly appreciated.

-Greg
=============================================

#ifndef DESKTOPHORZRES
#define DESKTOPHORZRES HORZRES
#endif
#ifndef DESKTOPVERTRES
#define DESKTOPVERTRES VERTRES
#endif

RGBTRIPLE *fnScreenLine(long lRow, long *plX, long *plY){
static RGBQUAD *pstScreen = NULL; // Pointer to raw data
static BITMAPINFO bmiScr; // Screen geometry
static RGBTRIPLE *pstBuf = NULL; // Converted buffer

long lIdx = 0;

HDC hdcScr, hdcMem;
HBITMAP hbmScr, hbmSection, hbmTemp;
RGBQUAD pTmp;

if (lRow > *plY){
free(pstBuf);
// DeleteObject( <<< Gotta put something here...
return NULL;
}

if (!pstScreen){
hdcScr = GetDC(NULL); // Get Screen
hdcMem = CreateCompatibleDC(hdcScr); // To put section in
hbmScr = CreateCompatibleBitmap( hdcScr // For dummy GetDIBits call
, GetDeviceCaps(hdcScr, DESKTOPHORZRES)
, GetDeviceCaps(hdcScr, DESKTOPVERTRES));


// Tell Win32 which structure this is.
bmiScr.bmiHeader.biSize= sizeof(BITMAPINFO);

// Capture screen geometry
GetDIBits(hdcMem, hbmScr, 0, 1, NULL, &bmiScr, DIB_RGB_COLORS);
DeleteObject(hbmScr); // Done with this bitmap
*plX = bmiScr.bmiHeader.biWidth; // Set for user
*plY = bmiScr.bmiHeader.biHeight;

hbmSection = CreateDIBSection( hdcScr // From screen , &bmiScr // Same
geometry , DIB_RGB_COLORS // W want raw RGBQUADs , (void **) &pstScreen
// Point to first , (HANDLE) NULL // No file mapping , (DWORD ) NULL); //
Insert empty section in memory DC? // Why does this return a bitmap?
hbmTemp = SelectObject(hdcMem, hbmSection);

// Xfer screen to hbmSection (via hdcMem?????)
BitBlt(hdcMem,0,0,*plX, *plY,hdcScr,0,0,SRCCOPY);
// DeleteObject(hbmTemp); - Can we do this here???
// DeleteDC(hdcScr);
if (pstBuf) free(pstBuf);
pstBuf = (RGBTRIPLE *) malloc(sizeof(RGBTRIPLE) * *plX);
}

pTmp = pstScreen + ((*plY - lRow) * *plX);
for (lIdx = 0; lIdx < *plX; lIdx++){
(pstBuf + lIdx)->rgbtBlue = (pTmp + lIdx)->rgbBlue;
(pstBuf + lIdx)->rgbtGreen = (pTmp + lIdx)->rgbGreen;
(pstBuf + lIdx)->rgbtRed = (pTmp + lIdx)->rgbRed;
}

return pstBuf;

GJoh...@fastlane.net

unread,
Nov 18, 1998, 3:00:00 AM11/18/98
to
<Edited for brevity>

In article <365188...@nortel.ca>,


h...@igs.net wrote:
> Decl...@my-dejanews.com wrote:
> >
> > Scenario:
> > Need quick & dirty, high compression, >free<, command line driven
> > screengrabber
>

> You may not be happy with JPEG - "gd" is a GIF-compatible free package.

Image degradation is acceptable so far... JPEG's compression advantage is the
determinant here since the volume will be quite high. (Maxing out around
1000/day, I'd guess)


>The critical code is much as Chris Becke presented it.

Would you mind taking a quick peek at the followup to Chris' post? I'd
appreciate any critique you'd care to share.

> Watch out for DIBs <Snip> Neglecting this gets you mirror images...

Yup, my first try was pea green, rotated 90 degrees counter-clockwise, and
mirrored. Makes nice modern art, though.


>... get the MSDN library. Even if you're not, consider it.

Is this distinct from the MSDN site and subscriptions? (i.e. can I hit the
web or harass the folks over in GUI design?)

Thanks,
-Greg

Mike Enright

unread,
Nov 18, 1998, 3:00:00 AM11/18/98
to
Decl...@my-dejanews.com wrote:

> static BITMAPINFO bmiScr; // Screen geometry

BITMAPINFO structs are never seen in the wild, because they only have
room for one palette entry:
// from the docs:
typedef struct tagBITMAPINFO { // bmi
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;

The best thing to do is to make your own struct that contains a header
and space for 256 colors. This struct would contain sufficient space
to describe either 256-color mode, where the palette would need space,
and it would be able to store the 3 DWORD masks for 565-format 16-bit
color.

> static RGBTRIPLE *pstBuf = NULL; // Converted buffer
>
> long lIdx = 0;
>
> HDC hdcScr, hdcMem;
> HBITMAP hbmScr, hbmSection, hbmTemp;
> RGBQUAD pTmp;
>
> if (lRow > *plY){
> free(pstBuf);
>// DeleteObject( <<< Gotta put something here...

There's nothing to clean up here, neither malloc'ed memory nor
Create'd GDI objects. The 'free' happens to be harmless if you pass it
a NULL pointer, but you have nothing to clean up at this line.


> return NULL;
> }
>
> if (!pstScreen){
> hdcScr = GetDC(NULL); // Get Screen
> hdcMem = CreateCompatibleDC(hdcScr); // To put section in
> hbmScr = CreateCompatibleBitmap( hdcScr // For dummy GetDIBits call
> , GetDeviceCaps(hdcScr, DESKTOPHORZRES)
> , GetDeviceCaps(hdcScr, DESKTOPVERTRES));

If memory were tight, you'd be risking a failure unnecessarily at this
point. I would make a 1x1 bitmap here, and use the GetDeviceCaps calls
to 'correct' the BITMAPINFO later.


>
>
> // Tell Win32 which structure this is.
> bmiScr.bmiHeader.biSize= sizeof(BITMAPINFO);
>
> // Capture screen geometry
> GetDIBits(hdcMem, hbmScr, 0, 1, NULL, &bmiScr, DIB_RGB_COLORS);

Use the screen DC (hdcScr) with this GetDIBits. And after you follow
my advice about changing to your own BITMAPINFO, the way you should
call GetDIBits is twice:

ZeroMemory(&video, sizeof(video));
video.bi.biSize = sizeof(video.bi);
video.bi.biBitCount = 0;
GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO
*)&video,DIB_RGB_COLORS);
GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO
*)&video,DIB_RGB_COLORS);

The first call fills in the alleged BITMAPINFO so that the second one
works. Mainly, there are fields that have to be right already before
the rest of the fields will be filled in correctly. But GetDIBits will
fill in those needed fields (and only those) if the BITMAPINFO is
mostly zero. Hence two calls are needed.

> DeleteObject(hbmScr); // Done with this bitmap
> *plX = bmiScr.bmiHeader.biWidth; // Set for user
> *plY = bmiScr.bmiHeader.biHeight;
>

Change the above to use GetDeviceCaps.


> hbmSection = CreateDIBSection( hdcScr // From screen
> , &bmiScr // Same geometry

> , DIB_RGB_COLORS // Wwant raw RGBQUADs

> , (void **) &pstScreen // Point to first
> , (HANDLE) NULL // No file mapping
> , (DWORD ) NULL);

>//Insert empty section in memory DC?

>// Why does this return a bitmap?
>hbmTemp = SelectObject(hdcMem, hbmSection);

The format of the above was a big mess.

CreateDIBSection returns a bitmap because that's what it makes. It
doesn't make a DC. You make a DC when you need one.

>
> // Xfer screen to hbmSection (via hdcMem?????)
> BitBlt(hdcMem,0,0,*plX, *plY,hdcScr,0,0,SRCCOPY);
>// DeleteObject(hbmTemp); - Can we do this here???

First, don't delete the dibsection until you unselect it from the DC.
Second, don't delete the dibsection until you don't need the pstScreen
memory. The bitmap handle controls the memory.
>// DeleteDC(hdcScr);

You should be able to RELEASE the screen DC here.


> if (pstBuf) free(pstBuf);
> pstBuf = (RGBTRIPLE *) malloc(sizeof(RGBTRIPLE) * *plX);
> }
>
> pTmp = pstScreen + ((*plY - lRow) * *plX);
> for (lIdx = 0; lIdx < *plX; lIdx++){
> (pstBuf + lIdx)->rgbtBlue = (pTmp + lIdx)->rgbBlue;
> (pstBuf + lIdx)->rgbtGreen = (pTmp + lIdx)->rgbGreen;
> (pstBuf + lIdx)->rgbtRed = (pTmp + lIdx)->rgbRed;
> }

Why only one scanline? I am not quite sure what your function is
supposed to do, but if you copied all the scanlines to pstBuf, then
you could delete the bitmap handle at this point.
>
> return pstBuf;
>}
>

HTH


--
Mike Enright
enri...@acm.org (Email replies cheerfully ignored, use the news group)
http://www.users.cts.com/sd/m/menright/
Cardiff-by-the-Sea, California, USA


John A. Grant

unread,
Nov 19, 1998, 3:00:00 AM11/19/98
to
Mike Enright wrote in message <3652f02c.121842798@news>...

>Decl...@my-dejanews.com wrote:
>
>> static BITMAPINFO bmiScr; // Screen geometry
>
>BITMAPINFO structs are never seen in the wild, because they only have
>room for one palette entry:
> // from the docs:
>typedef struct tagBITMAPINFO { // bmi
> BITMAPINFOHEADER bmiHeader;
> RGBQUAD bmiColors[1];
>} BITMAPINFO;
>
>The best thing to do is to make your own struct that contains a header
>and space for 256 colors. This struct would contain sufficient space
>to describe either 256-color mode, where the palette would need space,
>and it would be able to store the 3 DWORD masks for 565-format 16-bit
>color.
No, making your own struct is not a good idea. It's not wrong,
but you'll just be adding clutter to your code and make it more
difficult to maintain if you start creating your own structs derived
from Windows structs.

There is a well-defined mechanism for using all of the structs
that are declared like BITMAPINFO. The purpose of the [1]
entry is to indicate that the RGBQUAD table appears
directly after the BITMAPINFOHEADER, i.e. it is contiguous.
Use it like this:

BITMAPINFO *bmi=malloc(sizeof(BITMAPINFO)+
sizeof(RGBQUAD)*(ncolour-1));
for(i=0;i<ncolour;i++){
bmi->bmiColors[i].rgbBlue=...
bmi->bmiColors[i].rgbGreen=...
bmi->bmiColors[i].rgbRed=...
bmi->bmiColors[i].rgbReserved=0;
}
...
free(bmi);

'ncolour-1' is used for the size calculation because
sizeof(BITMAPINFO) already includes one RGBQUAD

--
John A. Grant * I speak only for myself * (remove 'z' to reply)
Airborne Geophysics, Geological Survey of Canada, Ottawa
If you followup, please do NOT e-mail me a copy: I will read it here

>

Mike Enright

unread,
Nov 19, 1998, 3:00:00 AM11/19/98
to
"John A. Grant" <zjag...@znrcanz.gcz.ca> wrote:

> BITMAPINFO *bmi=malloc(sizeof(BITMAPINFO)+
> sizeof(RGBQUAD)*(ncolour-1));
> for(i=0;i<ncolour;i++){
> bmi->bmiColors[i].rgbBlue=...
> bmi->bmiColors[i].rgbGreen=...
> bmi->bmiColors[i].rgbRed=...
> bmi->bmiColors[i].rgbReserved=0;
> }

I don't think it makes sense to correct (or advise or nudge) people in
the use of the BITMAPINFO struct given that the struct is not defined
correctly, unless the code in question will actually fail to work.
When it comes to this particular struct, no one can write programs
that are both real (use the bmiColors non-trivially) and conformant to
an ISO language standard.

Decl...@my-dejanews.com

unread,
Nov 19, 1998, 3:00:00 AM11/19/98
to
In article <36542ee1.203444379@news>,

enri...@acm.org wrote:
> "John A. Grant" <zjag...@znrcanz.gcz.ca> wrote:
>
> > BITMAPINFO *bmi=malloc(sizeof(BITMAPINFO)+
>
> I don't think it makes sense to correct (or advise or nudge) people in
> the use of the BITMAPINFO struct

Which brings up an issue a few rungs down on the priority list, to wit, why
does a 24 bit image need a color palette? Unless GDI's asked to render the
DIB it be realized (I think that's the term), so unless GetDIBits() assumes
it's properly allocated and automatically fills it, is there any harm in not
allocating it?

John A. Grant

unread,
Nov 19, 1998, 3:00:00 AM11/19/98
to
Mike Enright wrote in message <36542ee1.203444379@news>...

>"John A. Grant" <zjag...@znrcanz.gcz.ca> wrote:
>
>> BITMAPINFO *bmi=malloc(sizeof(BITMAPINFO)+
>> sizeof(RGBQUAD)*(ncolour-1));
>> for(i=0;i<ncolour;i++){
>> bmi->bmiColors[i].rgbBlue=...
>> bmi->bmiColors[i].rgbGreen=...
>> bmi->bmiColors[i].rgbRed=...
>> bmi->bmiColors[i].rgbReserved=0;
>> }
>
>I don't think it makes sense to correct (or advise or nudge) people in
>the use of the BITMAPINFO struct given that the struct is not defined
>correctly, unless the code in question will actually fail to work.
>When it comes to this particular struct, no one can write programs
>that are both real (use the bmiColors non-trivially) and conformant to
>an ISO language standard.


AFAIC, the struct is 100% ANSI C. Furthermore, there is
absolutely nothing about my code above that is non-standard.
Why do you think "the struct is not defined correctly". It's
perfectly ok and it encapsulates the requirement perfectly.
The requirement is for the table of RGBQUAD entities
to be of variable length, but still be contiguous with the
BITMAPINFOHEADER struct.

How would *YOU* do it so that it meets your standards?

John A. Grant

unread,
Nov 19, 1998, 3:00:00 AM11/19/98
to
Decl...@my-dejanews.com wrote in message
<731u6s$uku$1...@nnrp1.dejanews.com>...

>In article <36542ee1.203444379@news>,
> enri...@acm.org wrote:
>> "John A. Grant" <zjag...@znrcanz.gcz.ca> wrote:
>>
>> > BITMAPINFO *bmi=malloc(sizeof(BITMAPINFO)+
>>
>> I don't think it makes sense to correct (or advise or nudge) people in
>> the use of the BITMAPINFO struct
>
>Which brings up an issue a few rungs down on the priority list, to wit, why
>does a 24 bit image need a color palette? Unless GDI's asked to render the
>DIB it be realized (I think that's the term), so unless GetDIBits() assumes
>it's properly allocated and automatically fills it, is there any harm in
not
>allocating it?
It doesn't need a palette. If the image is 24-bit, the table of
RGBQUAD entities will not be present. The bits will follow
directly after the BITMAPINFOHEADER.

Decl...@my-dejanews.com

unread,
Nov 20, 1998, 3:00:00 AM11/20/98
to
Mike,

Thanks for your time. I've only a few questions, so if you could spare me
another five minutes.

In article <3652f02c.121842798@news>,


enri...@acm.org wrote:
> Decl...@my-dejanews.com wrote:
>
> > static BITMAPINFO bmiScr; // Screen geometry

> The best thing to do is to make your own struct that contains a header


> and space for 256 colors. This struct would contain sufficient space
> to describe either 256-color mode, where the palette would need space,
> and it would be able to store the 3 DWORD masks for 565-format 16-bit
> color.

OK, now I'm really confused... At first cut, it looked like DIB_PAL_COLORS
implied palette use, while DIB_RGB_COLORS implied 24 bit RGB values.
(RGBQUADs, in fact)

How can one detect/direct the RGB format the DIB uses? More specifically how
can I get a 3 byte RGB format?

> > if (lRow > *plY){
> > free(pstBuf);
> >// DeleteObject( <<< Gotta put something here...
>

> There's nothing to clean up here <Snip>

The intent is that the static vars will hold the context across calls &
release held resources when called on an invalid row... The idea being to as
completely encapsulate Windows references as possible. (i.e. I know nothing
but that when I call foo() I get a pointer to an array of 24 bit RGB pixels.

> > // Capture screen geometry
> > GetDIBits(hdcMem, hbmScr, 0, 1, NULL, &bmiScr, DIB_RGB_COLORS);
> Use the screen DC (hdcScr) with this GetDIBits. And after you follow
> my advice about changing to your own BITMAPINFO, the way you should
> call GetDIBits is twice:

Done. Quick question: hdcMem is CreateCompatibleDC(hdcScr), no? Should they
not look exactly the same?

> The first call fills in the alleged BITMAPINFO so that the second one
> works. Mainly, there are fields that have to be right already before
> the rest of the fields will be filled in correctly. But GetDIBits will
> fill in those needed fields (and only those) if the BITMAPINFO is
> mostly zero. Hence two calls are needed.

The only thing that changes on the second call under NT4Sp3 is the color count
goes from 256 to zero.... Any idea what this means?

> > *plX = bmiScr.bmiHeader.biWidth; // Set for user
> > *plY = bmiScr.bmiHeader.biHeight;
> >
> Change the above to use GetDeviceCaps.

OK, no problem. Care to mention why GDC() might differ from the bmiScr
struct?

> First, don't delete the dibsection until you unselect it from the DC.
> Second, don't delete the dibsection until you don't need the pstScreen
> memory. The bitmap handle controls the memory.

OK, so basically I need to track a bitmap & a DC. Can you call DeleteDC() and
expect any selected bitmaps to be destroyed as well? Or do you have to
"unselect" and destroy them manually?

> Why only one scanline?

One scan line is about the lowest common denominator... You could go by
pixel, but that's tragically slow.

I always like to assume "maintenance by morons". It's usually unfortunately
close to reality. Especially if I'm doing the maintenance.

Bob Bedoll

unread,
Nov 20, 1998, 3:00:00 AM11/20/98
to
BITMAPINFO is the standard definition of DIBs, especially *.bmp files.
The DIB examples distributed with the SDK use this structure.
The reason the RGBQUAD is dimensioned as 1 is because the palette size
is variable, based on one of the fields in the bitmapinfoheader (whose
name I've forgotten).
If there is a palette, it should always start at bmiColors. (one can
also use the biSize field in BITMAPINFOHEADER to get to the palette).

If the bits/pixel is 1,4, or 8, there will be a palette.
If the bits/pixel is 0 (implying 24), 16, 24, or 32, there will not
be a palette (i.e., there will be no bimColors values).

The data bits always start following the palette (actually with
the first double word following the palette).

Mike Enright wrote:
>
> Decl...@my-dejanews.com wrote:
>
> > static BITMAPINFO bmiScr; // Screen geometry
>

> BITMAPINFO structs are never seen in the wild, because they only have
> room for one palette entry:
> // from the docs:
> typedef struct tagBITMAPINFO { // bmi
> BITMAPINFOHEADER bmiHeader;
> RGBQUAD bmiColors[1];
> } BITMAPINFO;
>

> The best thing to do is to make your own struct that contains a header
> and space for 256 colors. This struct would contain sufficient space
> to describe either 256-color mode, where the palette would need space,
> and it would be able to store the 3 DWORD masks for 565-format 16-bit
> color.
>

> > static RGBTRIPLE *pstBuf = NULL; // Converted buffer
> >
> > long lIdx = 0;
> >
> > HDC hdcScr, hdcMem;
> > HBITMAP hbmScr, hbmSection, hbmTemp;
> > RGBQUAD pTmp;
> >

> > if (lRow > *plY){
> > free(pstBuf);
> >// DeleteObject( <<< Gotta put something here...
>

> There's nothing to clean up here, neither malloc'ed memory nor
> Create'd GDI objects. The 'free' happens to be harmless if you pass it
> a NULL pointer, but you have nothing to clean up at this line.
> > return NULL;
> > }
> >
> > if (!pstScreen){
> > hdcScr = GetDC(NULL); // Get Screen
> > hdcMem = CreateCompatibleDC(hdcScr); // To put section in
> > hbmScr = CreateCompatibleBitmap( hdcScr // For dummy GetDIBits call
> > , GetDeviceCaps(hdcScr, DESKTOPHORZRES)
> > , GetDeviceCaps(hdcScr, DESKTOPVERTRES));
> If memory were tight, you'd be risking a failure unnecessarily at this
> point. I would make a 1x1 bitmap here, and use the GetDeviceCaps calls
> to 'correct' the BITMAPINFO later.
> >
> >
> > // Tell Win32 which structure this is.
> > bmiScr.bmiHeader.biSize= sizeof(BITMAPINFO);
> >

> > // Capture screen geometry
> > GetDIBits(hdcMem, hbmScr, 0, 1, NULL, &bmiScr, DIB_RGB_COLORS);
> Use the screen DC (hdcScr) with this GetDIBits. And after you follow
> my advice about changing to your own BITMAPINFO, the way you should
> call GetDIBits is twice:
>

> ZeroMemory(&video, sizeof(video));
> video.bi.biSize = sizeof(video.bi);
> video.bi.biBitCount = 0;
> GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO
> *)&video,DIB_RGB_COLORS);
> GetDIBits(hdcDisplay,hbm,0,1,NULL,(BITMAPINFO
> *)&video,DIB_RGB_COLORS);
>

> The first call fills in the alleged BITMAPINFO so that the second one
> works. Mainly, there are fields that have to be right already before
> the rest of the fields will be filled in correctly. But GetDIBits will
> fill in those needed fields (and only those) if the BITMAPINFO is
> mostly zero. Hence two calls are needed.
>

> > DeleteObject(hbmScr); // Done with this bitmap

> > *plX = bmiScr.bmiHeader.biWidth; // Set for user
> > *plY = bmiScr.bmiHeader.biHeight;
> >
> Change the above to use GetDeviceCaps.

> > hbmSection = CreateDIBSection( hdcScr // From screen
> > , &bmiScr // Same geometry
> > , DIB_RGB_COLORS // Wwant raw RGBQUADs
> > , (void **) &pstScreen // Point to first
> > , (HANDLE) NULL // No file mapping
> > , (DWORD ) NULL);
> >//Insert empty section in memory DC?
> >// Why does this return a bitmap?
> >hbmTemp = SelectObject(hdcMem, hbmSection);
> The format of the above was a big mess.
>
> CreateDIBSection returns a bitmap because that's what it makes. It
> doesn't make a DC. You make a DC when you need one.
>
> >
> > // Xfer screen to hbmSection (via hdcMem?????)
> > BitBlt(hdcMem,0,0,*plX, *plY,hdcScr,0,0,SRCCOPY);
> >// DeleteObject(hbmTemp); - Can we do this here???
>

> First, don't delete the dibsection until you unselect it from the DC.
> Second, don't delete the dibsection until you don't need the pstScreen
> memory. The bitmap handle controls the memory.

> >// DeleteDC(hdcScr);
>
> You should be able to RELEASE the screen DC here.
> > if (pstBuf) free(pstBuf);
> > pstBuf = (RGBTRIPLE *) malloc(sizeof(RGBTRIPLE) * *plX);
> > }
> >
> > pTmp = pstScreen + ((*plY - lRow) * *plX);
> > for (lIdx = 0; lIdx < *plX; lIdx++){
> > (pstBuf + lIdx)->rgbtBlue = (pTmp + lIdx)->rgbBlue;
> > (pstBuf + lIdx)->rgbtGreen = (pTmp + lIdx)->rgbGreen;
> > (pstBuf + lIdx)->rgbtRed = (pTmp + lIdx)->rgbRed;
> > }
> Why only one scanline? I am not quite sure what your function is
> supposed to do, but if you copied all the scanlines to pstBuf, then
> you could delete the bitmap handle at this point.
> >
> > return pstBuf;
> >}
> >
>
> HTH
>

Mike Enright

unread,
Nov 21, 1998, 3:00:00 AM11/21/98
to
Bob Bedoll <robert....@boeing.com> wrote:

>BITMAPINFO is the standard definition of DIBs, especially *.bmp files.
>The DIB examples distributed with the SDK use this structure.
>The reason the RGBQUAD is dimensioned as 1 is because the palette size
>is variable

The struct's definition uses an idiom that deviates from how
standard-compliant code must be written. There is no way to write a
variable-size struct. We all know how it is fudged, however, and so
however each of us deals with the fudge is fine as long as it works.

Mike Enright

unread,
Nov 21, 1998, 3:00:00 AM11/21/98
to
Decl...@my-dejanews.com wrote:

>Mike,
>
>Thanks for your time. I've only a few questions, so if you could spare me
>another five minutes.
>
>
>
>In article <3652f02c.121842798@news>,

> enri...@acm.org wrote:
>> Decl...@my-dejanews.com wrote:
>>
>> > static BITMAPINFO bmiScr; // Screen geometry
>

>> The best thing to do is to make your own struct that contains a header
>> and space for 256 colors. This struct would contain sufficient space
>> to describe either 256-color mode, where the palette would need space,
>> and it would be able to store the 3 DWORD masks for 565-format 16-bit
>> color.
>

>OK, now I'm really confused... At first cut, it looked like DIB_PAL_COLORS
>implied palette use, while DIB_RGB_COLORS implied 24 bit RGB values.
>(RGBQUADs, in fact)

DIB_PAL_COLORS is for the unusual case that, in place of specifying
the palette directly, you want to specify the palette by reference to
the palette selected into the device context. The by-reference palette
would be an array of 16-bit indices into the selected palette.

>
>How can one detect/direct the RGB format the DIB uses? More specifically how
>can I get a 3 byte RGB format?
>

The two calls to GetDIBits do the detecting. To direct the format,
just skip the GetDIBits part altogether. Just specify what you want in
the data the BITMAPINFO parameter of CreateDIBSection points at. Then
when you BitBlt the screen to your DIB section, it will be converted.
It won't always be an ideal conversion, though. A scrupulous way to
get the image of the screen in a particular format as nicely as
possible would take two DIB sections. One would make an exact copy of
the screen, and the other would be formatted the way you want. Then
you would copy from one to the other using memcpy if they happen to
match formats, or a dithering routine if the output format has fewer
colors than the screen format, or a color expansion if the output
format allows more colors than the input format.

>
>> > // Capture screen geometry
>> > GetDIBits(hdcMem, hbmScr, 0, 1, NULL, &bmiScr, DIB_RGB_COLORS);
>> Use the screen DC (hdcScr) with this GetDIBits. And after you follow
>> my advice about changing to your own BITMAPINFO, the way you should
>> call GetDIBits is twice:
>

>Done. Quick question: hdcMem is CreateCompatibleDC(hdcScr), no? Should they
>not look exactly the same?

You may be right about that. When my intention is to get the display
format, I always use an "on-screen" DC. I haven't used a compatible
memory DC.


>
>> The first call fills in the alleged BITMAPINFO so that the second one
>> works. Mainly, there are fields that have to be right already before
>> the rest of the fields will be filled in correctly. But GetDIBits will
>> fill in those needed fields (and only those) if the BITMAPINFO is
>> mostly zero. Hence two calls are needed.
>

>The only thing that changes on the second call under NT4Sp3 is the color count
>goes from 256 to zero.... Any idea what this means?

Without more information, I don't know. What is the display mode?


>
>> > *plX = bmiScr.bmiHeader.biWidth; // Set for user
>> > *plY = bmiScr.bmiHeader.biHeight;
>> >
>> Change the above to use GetDeviceCaps.
>

>OK, no problem. Care to mention why GDC() might differ from the bmiScr
>struct?

I suggested that you create a bitmap much smaller than the screen,
rather than the size of the screen, to conserve resources. So now the
dimensions from GetDIBits will not be the size you want to return.

>
>> First, don't delete the dibsection until you unselect it from the DC.
>> Second, don't delete the dibsection until you don't need the pstScreen
>> memory. The bitmap handle controls the memory.
>

>OK, so basically I need to track a bitmap & a DC. Can you call DeleteDC() and
>expect any selected bitmaps to be destroyed as well? Or do you have to
>"unselect" and destroy them manually?
>

You mainly need to track the DIB section handle and the memory
pointer. You don't need a DC for this.

DeleteDC doesn't destroy the selected objects. You need to unselect
them and delete them separately.

HTH

Mike Enright

unread,
Nov 21, 1998, 3:00:00 AM11/21/98
to
"John A. Grant" <zjag...@znrcanz.gcz.ca> wrote:


>[much snipped]


> How would *YOU* do it so that it meets your standards?

The code I corrected potentially needed room for more than one
RGBQUAD, but used a straight BITMAPINFO, which was wrong. I posted
code that corrected that problem. If my correction would fail to
execute properly, let's discuss that.

John A. Grant

unread,
Nov 21, 1998, 3:00:00 AM11/21/98
to
Mike Enright wrote in message <3656951f.295168084@news>...

>"John A. Grant" <zjag...@znrcanz.gcz.ca> wrote:
>
>>[much snipped]
>> How would *YOU* do it so that it meets your standards?
>
>The code I corrected potentially needed room for more than one
>RGBQUAD, but used a straight BITMAPINFO, which was wrong. I posted
>code that corrected that problem. If my correction would fail to
>execute properly, let's discuss that

Yes, your code will work and my code will work. I'm not
questioning that.

My followup point was that there is a 'standard' (common)
method of using those variable-length structs (as I showed)
and it does not involve the declaration of another struct.
You then stated that the struct "...is not defined correctly" and
implied that it was not "conformant to an ISO language
standard". I'd still like to know why you think the struct is
incorrect and non-standard and how you would define the
struct to conform to ISO standards.

Mike Enright

unread,
Nov 22, 1998, 3:00:00 AM11/22/98
to
"John A. Grant" <zjag...@znrcanz.gcz.ca> wrote:

> <...> I'd still like to know why you think the struct is


> incorrect and non-standard and how you would define the
> struct to conform to ISO standards.

There is no standard-compliant way to define and use such a struct.
Given any struct that follows this layout:
struct BASESTRUCT {
HEADER header;
ELEMENT elements[1];
};

the standard does not require sizeof(BASESTRUCT) to be no greater than
the sum of the sizes of the header and of the element. This affects
the "sizeof(BASESTRUCT)+(n-1)*sizeof(ELEMENT)" idiom.

Jerry Coffin

unread,
Nov 22, 1998, 3:00:00 AM11/22/98
to
In article <36584b9c.66963001@news>, enri...@acm.org says...

[ ... ]

> Given any struct that follows this layout:
> struct BASESTRUCT {
> HEADER header;
> ELEMENT elements[1];
> };
>
> the standard does not require sizeof(BASESTRUCT) to be no greater than
> the sum of the sizes of the header and of the element. This affects
> the "sizeof(BASESTRUCT)+(n-1)*sizeof(ELEMENT)" idiom.

This is NOT true. If you attempted to compute the size as `sizeof
HEADER + N*sizeof(ELEMENT)', you'd be correct that any padding in the
structure would be ignored.

However, when you use `sizeof(BASESTRUCT)', that _must_ include
whatever padding the compiler might insert between the header and the
array.

Memory for arrays is required to be contiguous, so the compiler canNOT
expect to see padding between the elements of the array.

When you allocate using `sizeof BASESTRUCT + (N-1) * sizeof(ELEMENT)'
you DO risk allocating some extra memory that you'll never use -- just
in case you might allocate an array of BASESTRUCT, the compiler is
free to insert padding at the end that wouldn't otherwise be used.
This extra size would show up in the `sizeof(BASESTRUCT)' even though
you don't really need it in this case.

The only problem left is that (in theory) a compiler could do bounds
checking on arrays. In reality, I only know of one compiler that ever
did this, and even it automatically detected this idiom and ignored
out-of-bounds accesses in cases like this (though it depended upon an
old MS extension of declaring the array with zero elements instead of
one to do the detection completely automatically).

In the real world, this is really a non-issue. It's never caused a
problem with a real compiler, and since the next revision of the
standard will completely bless an idiom like this, it seems
_extremely_ unlikely that anybody's going to write a compiler that'll
break the code even though it's technically not guaranteed to be
portable at the present time.

0 new messages