Need help from a Guru

Need help from a Guru

Post by Mike D Sutto » Mon, 30 Jun 2003 08:01:27



Quote:> I need a guru to help me understand why an image im creating in memory
> (loaded from a custom image format into bitmapinfo structures) is
displaying
> with incorrect colors.   Please dont just post a chunk of code with other
> ways to display an image.   I need help learning and understanding WHY
what
> im doing is wrong.  I've been trying for a week now, probably 100 times
> (seriously) various incantations to get this to work.  Obviously Im not
> understanding something, so that is why I don't just want another piece of
> code to compare to.

> Background:
> I am trying to display a custom image file format. My code can correctly
> convert the custom format to a bitmap file. I don't wish to create a file
> though (was merely for testing), but instead wish to display the image
from
> memory into a Picturebox, or any other control.

> The custom format is :
> A palette file made up of sets of 3 bytes each, RGB order, 256 colors in
> all.  I am loading this into BITMAPINFO bmiColors().
> The raw image byte data, where each byte contains the index of a palette
> entry.  The data is in top to bottom format, so in loading I am reversing
it
> to the bitmap standard of bottom to top, into a byte array.

> Problem:
> I can't get the image to display with the correct colors (for example what
> should be the white background gets displayed as a mint green)

> I've included two different versions of DisplayBitmapinfo, they both yeild
> the same result. I can break inside either function, and check my
> structures, all have the correct data. Screenshot attached.

> If you see a problem with this code, please... help me figure it out.

<snip>

First up, you've got a possible resource leak in both methods with this kind
of structure:

'***
hMemDC = CreateCompatibleDC(pb.hDC)
hBitmap = CreateCompatibleBitmap(pb.hDC, width, height)
hOldBitmap = SelectObject(hMemDC, hBitmap)
SetDIBits hMemDC, hBitmap, 0, height, bBits(0), lpbi, DIB_RGB_COLORS
If hMemDC <> 0 And hBitmap <> 0 Then
    BitBlt pb.hDC, 0, 0, width, height, hMemDC, 0, 0, SRCCOPY
    RC = SelectObject(hMemDC, hOldBitmap)
    RC = DeleteObject(hBitmap)
    RC = DeleteDC(hMemDC)
End If
'***

The problem here is that only if _everything_ succeeds will _anything_ be
destroyed or de-selected - You could easily have the DC and Bitmap be
created properly then the selection fails for instance - In this case both
the DC and Bitmap would be left in memory.  Instead, use something like
this:

*** (Pseudo)
DC = CreateDC(...)

If (DC) Then
    BMP = CreateBMP(...)

    If (BMP) Then
        Old = Select(DC, BMP)

        If (Old) Then
            ' Good to go
            Select(DC, Old)
        End If

        Delete(BMP)
    End If

    Delete(DC)
End If
***

You're also not checking the return of SetDIBits() which could be failing.
Unfortunately you've not given us enough information about what could be
going wrong (I suspect it's in your declarations or how you're setting up
the palette and/or bitmap data arrays - neither of which we can see..)
I'd suggest generating a DIBSection rather than a DDB though since this will
be make the resulting image independent of that users hardware which could
be causing a role in the colour degradation you're experiencing.  Also, make
sure that your palette array has been declared and passed properly and
you're not trying to pass in the array header rather than a pointer to the
first entry (A reasonably common mistake.)
If you still get no luck, then post some more code, specifically the
declares you're using and the way you're creating (And filling?) the data
and palette arrays.
If you _do_ decide you want an example of how to create and assign a bitmap
with palette then here's an example:
http://groups.google.co.uk/groups?selm=ukzbpIGdCHA.392%40tkmsftngp09
Here's another, it's in C++ but the steps are similar:
http://groups.google.co.uk/groups?selm=ukzbpIGdCHA.392%40tkmsftngp09
Hope this helps,

    Mike

 - Microsoft Visual Basic MVP -

WWW: Http://www.mvps.org/EDais/

 
 
 

Need help from a Guru

Post by <u.. » Mon, 30 Jun 2003 23:46:26


Quote:> First up, you've got a possible resource leak in both methods with this
kind
> of structure:

Thanks.

Quote:> You're also not checking the return of SetDIBits() which could be failing.

Ok, I'll do that.

Quote:> I'd suggest generating a DIBSection rather than a DDB though since this
will
> be make the resulting image independent of that users hardware which could
> be causing a role in the colour degradation you're experiencing.

Very helpful info.  I'd wondered about a palette/hardware problem but didnt
know where to look.

Quote:>Also, make
> sure that your palette array has been declared and passed properly and
> you're not trying to pass in the array header rather than a pointer to the
> first entry (A reasonably common mistake.)
> If you still get no luck, then post some more code, specifically the
> declares you're using and the way you're creating (And filling?) the data
> and palette arrays.

Ok, will do.   Thanks!    I really appreciate it.

 
 
 

Need help from a Guru

Post by <u.. » Tue, 01 Jul 2003 00:04:10


Q:  I've noticed alot now that people tend to declare fixed arrays for
bmiColors.  I on the other hand was using a dynamic array.  Could this be
the source of the problem?  Does that cause a change to the actual format
the data is stored in in memory?
 
 
 

Need help from a Guru

Post by <u.. » Tue, 01 Jul 2003 00:26:55



Quote:> Q:  I've noticed alot now that people tend to declare fixed arrays for
> bmiColors.  I on the other hand was using a dynamic array.  Could this be
> the source of the problem?  Does that cause a change to the actual format
> the data is stored in in memory?

On a similar note, the Types in both AllAPI viewer, and API-Guide DONT
declare bmiColors as an array, but instead as a long (pointer Im assuming,
from what I've read at MSDN).

Private Type BITMAPINFO
        bmiHeader As BITMAPINFOHEADER
        bmiColors As RGBQUAD
End Type

yet most of the code I've encountered declares it as an array.   Does this
make any difference?  Does declaring it as an array in reality just create a
long descriptor in the position of bmiColors, the actual array data being
stored after that? (and ignored by calls which utilize the BITMAPINFO
structure?)

Sorry, I know these are probably basic vb questions, but im still quite new
to it all.

 
 
 

Need help from a Guru

Post by <u.. » Tue, 01 Jul 2003 09:19:22


Ok, I've redone the code to match the google groups example you'ld posted.

Notes:

I am uncertain what the 'best' way is to introduce the bits.  All the code
examples people offer (yours included) usually take the bits from a
picturebox object.  In my case I have the bits in an array.   I've tried
three different formats here to introduce the bits into the image, all three
yeild the same palette problem, so I'm guessing the problem lies elsewhere.

An interesting thing I discovered is that SetBitmapBits actually expects the
image Bits in Top-to-Bottom order, thus, just for display I wouldnt need to
invert the scan lines as I was doing, which will speed things a bit.  (At
the cost of code compatability, but it is interesting none the less).

So... looking elsewhere:

'Display Bitmap Version 3 ''''''''''''''''''''''''''''''''''''''''
Private Sub DisplayBitmapinfo3(pb As PictureBox, bi As BITMAPINFO, bBits()
As Byte)
   Dim DeskWnd As Long, DeskDC As Long
   Dim MyDC As Long
   Dim MyDIB As Long, OldDIB As Long
   Dim lpBits As Long

   'Persist drawing
   pb.AutoRedraw = True

   'Create DC based on desktop DC
   DeskWnd = GetDesktopWindow()
   DeskDC = GetDC(DeskWnd)
   MyDC = CreateCompatibleDC(DeskDC)
   ReleaseDC DeskWnd, DeskDC

   'Validate DC
   If (MyDC = 0) Then Exit Sub

   ' Create the DIBSection
   MyDIB = CreateDIBSection(MyDC, bi, DIB_RGB_COLORS, VarPtr(lpBits), 0, 0)
'ByVal 0&, 0, 0)

   If (MyDIB) Then ' Validate

      ' How do I transfer the bits into my picture?

      ' CopyMemory the bits to where pBits points?
      'CopyMemory ByVal lpBits, bBits(0), bi.bmiHeader.biSizeImage

      ' SetBitmapBits?
      Dim lNumBits As Long
      lNumBits = SetBitmapBits(MyDIB, bi.bmiHeader.biSizeImage, bBits(0))

      ' Or SetDIBits (see after SelectObject)

      'Select DIB
      OldDIB = SelectObject(MyDC, MyDIB)

      ' Draw original picture to the 8bit DC
      'SetDIBits MyDC, MyDIB, 0, bi.bmiHeader.biHeight, _
         bBits(0), bi, DIB_RGB_COLORS

      ' Draw the 8bit image back to the picture box
      BitBlt pb.hDC, 0, 0, bi.bmiHeader.biWidth, _
         bi.bmiHeader.biHeight, MyDC, 0, 0, vbSrcCopy

      ' Clean up DIB
      SelectObject MyDC, OldDIB
      DeleteObject MyDIB
   End If

   ' Clean up DC
   DeleteDC MyDC

   ' Redraw on screen
   pb.Refresh

End Sub

Here are my declarations etc.. (Public because they're contained in separate
module).
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''

Public Const DIB_RGB_COLORS As Long = 0
Public Const SRCCOPY As Long = &HCC0020 ' Copies the source bitmap to
destination bitmap.

Public Type BITMAPINFOHEADER '40 bytes
        biSize As Long
        biWidth As Long
        biHeight As Long
        biPlanes As Integer
        biBitCount As Integer
        biCompression As Long
        biSizeImage As Long
        biXPelsPerMeter As Long
        biYPelsPerMeter As Long
        biClrUsed As Long
        biClrImportant As Long
End Type

Public Type RGBQUAD
        rgbBlue As Byte
        rgbGreen As Byte
        rgbRed As Byte
        rgbReserved As Byte
End Type

Public Type BITMAPINFO
        bmiHeader As BITMAPINFOHEADER
        bmiColors() As RGBQUAD
End Type

Public Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, _
      ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, _
      ByVal nHeight As Long,
ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, _
      ByVal dwRop As Long) As Long
Public Declare Function CreateCompatibleBitmap Lib "gdi32" ( _
      ByVal hDC As Long, ByVal nWidth As Long, ByVal nHeight As Long) As
Long
Public Declare Function CreateCompatibleDC Lib "gdi32" ( _
      ByVal hDC As Long) As Long
Public Declare Function SelectObject Lib "gdi32" (ByVal hDC As Long, _
      ByVal hObject As Long) As Long
Public Declare Function SetDIBits Lib "gdi32" (ByVal hDC As Long, _
      ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As
Long, _
      lpBits As Any, lpbi As BITMAPINFO, ByVal wUsage As Long) As Long
Public Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long
Public Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As
Long

The relevant lines from the sub loading/converting the image:  (Ive excluded
the code
which loads the bits, but they're displaying where they should, so I'll the
code is ok.)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''''

   'Create Bitmap '''''''''''''''''''''''''''''''''''''''''
   Dim lpbi As BITMAPINFO
   lpbi = CreateDIB(width, height, 8)
   ...
   'Convert Act to Bitmap Palette '''''''''''''''''''''''''
   lpbi.bmiColors = ActToRGBQuads(rawpal)
   ...
   Dim bBits() As Byte
   ReDim bBits(lpbi.bmiHeader.biSizeImage - 1) As Byte

And the subs referenced above:
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''

Public Function CreateDIB(ByVal dwWidth As Long, _
   ByVal dwHeight As Long, ByVal wBitCount As Integer) As BITMAPINFO

   Dim bi As BITMAPINFOHEADER
   Dim dwBytesPerLine As Long ' Number of bytes per scanline

   On Error GoTo EH

   ' Convert the color format to a count of bits.
   If (wBitCount <= 1) Then
      wBitCount = 1
   ElseIf (wBitCount <= 4) Then
      wBitCount = 4
   ElseIf (wBitCount <= 8) Then
      wBitCount = 8
   ElseIf (wBitCount <= 16) Then
      wBitCount = 16
   ElseIf (wBitCount <= 24) Then
      wBitCount = 24
   Else
      wBitCount = 32
   End If

   ' initialize BITMAPINFOHEADER
   bi.biSize = LenB(bi)
   bi.biWidth = dwWidth ' fill in width from parameter
   bi.biHeight = dwHeight ' fill in height from parameter
   bi.biPlanes = 1 ' must be 1
   bi.biBitCount = wBitCount ' from parameter
   bi.biCompression = BI_RGB
   ' Not sure what the following values are used for, but
   ' the C reference code I have uses the following values
   bi.biXPelsPerMeter = 2834 ' 0
   bi.biYPelsPerMeter = 2834 ' 0
   bi.biClrUsed = 0
   bi.biClrImportant = 0

    'Following formula is from MSDN
   dwBytesPerLine = ShiftRight((((wBitCount * dwWidth) + 31) And Not 31), 3)
   bi.biSizeImage = dwBytesPerLine * dwHeight

   ' Since we don't know what the colortable and bits should contain,
   ' just leave these blank.
   CreateDIB.bmiHeader = bi

   Exit Function
EH:
Debug.Print Err.Source, Err.number, Err.Description

End Function

' The Const ACT_SIZE_BYTES = 768
' The Const COLORS_8_BIT = 256
Public Function ActToRGBQuads(vAct As Variant) As RGBQUAD()
   Dim bmiColors(0 To COLORS_8_BIT - 1) As RGBQUAD
   Dim curcolor As Long
   Dim color As Long

   On Error GoTo EH

   If VarType(vAct) <> vbArray + vbByte Then
      'Raise Incorrect Parameter Error
      Err.Raise 5
   End If

   If UBoundEx(vAct) - LBoundEx(vAct) + 1 <> ACT_SIZE_BYTES Then
      'Raise Incorrect Parameter Error
      Err.Raise 5
   End If

   For color = LBound(bmiColors) To UBound(bmiColors)
      bmiColors(color).rgbBlue = vAct(color * 3 + 3)
      bmiColors(color).rgbGreen = vAct(color * 3 + 2)
      bmiColors(color).rgbRed = vAct(color * 3 + 1)
      bmiColors(color).rgbReserved = 0
   Next

   ActToRGBQuads = bmiColors

   Exit Function
EH:
   Debug.Print Err.Source, Err.number, Err.Description
End Function

 
 
 

Need help from a Guru

Post by <u.. » Tue, 01 Jul 2003 09:42:20


doh, shoulda read it closer before I posted:

Clarifications :

Quote:> (Ive excluded the code which loads the bits, but they're displaying where
> they should, so I'll the code is ok.)

Should read
... so I'll guess the code is ok.

Quote:>    ...
>    'Convert Act to Bitmap Palette '''''''''''''''''''''''''
>    lpbi.bmiColors = ActToRGBQuads(rawpal)

Where :
rawpal(1 To 768) As Byte 'Filled R G B order

Quote:>    For color = LBound(bmiColors) To UBound(bmiColors)
>       bmiColors(color).rgbBlue = vAct(color * 3 + 3)
>       bmiColors(color).rgbGreen = vAct(color * 3 + 2)
>       bmiColors(color).rgbRed = vAct(color * 3 + 1)
>       bmiColors(color).rgbReserved = 0
>    Next

And hopefully the previous code makes sense.
Loop will start at 0... thus:
    ' First iteration :
        vAct(0*3+3 = 3) ' Third / Blue Byte
        vAct(0*3+2 = 2) ' Second  / Green Byte
        vAct(0*3+1 = 1) ' First / Red Byte
    ' Second iteration:
        vAct(1*3+3 = 6) ' Sixth / Blue Byte
        vAct(1*3+2 = 5) ' Fifth / Green Byte
        vAct(1*3+1 = 4) ' Fourth / Red Byte
etc ...

And lastly, ignore the shoddy error handling. :)  I know its lame, but I
don't normally do such until the polishing phase.  (Yes, I know, thats bad
in and of itself... give me a break, im new, and still learning.)

 
 
 

Need help from a Guru

Post by Mike D Sutto » Tue, 01 Jul 2003 17:40:42


Quote:> Ok, I've redone the code to match the google groups example you'ld posted.

> Notes:

> I am uncertain what the 'best' way is to introduce the bits.  All the code
> examples people offer (yours included) usually take the bits from a
> picturebox object.  In my case I have the bits in an array.   I've tried
> three different formats here to introduce the bits into the image, all
three
> yeild the same palette problem, so I'm guessing the problem lies

elsewhere.

Ah, it seems I posted the same link twice last time, here's a C++ version I
mentioned which doesn't use a picture box:
http://www.veryComputer.com/%237TJro4JDHA.456%40TK2MSFTNGP...

Here's a very fast way of getting the data into a DIBSection, by temporarily
pointing a byte array at the underlying data - It's a hack but it works as
long as you're careful and outperforms SetDIBits() which is what you'd have
to do to work from a byte array usually:
http://www.veryComputer.com/%40tkmsftngp08

Here's a little more information on the technique:
http://www.veryComputer.com/
(Sorry I couldn't find the original article but you're welcome to go and
hunt on www.fawcette.com)

Quote:> An interesting thing I discovered is that SetBitmapBits actually expects
the
> image Bits in Top-to-Bottom order, thus, just for display I wouldnt need
to
> invert the scan lines as I was doing, which will speed things a bit.  (At
> the cost of code compatability, but it is interesting none the less).

Yep, by default DIB's are stored bottom to top, if you particularly need the
data to be stored top down then set the biHeight memory of your
BITMAPINTOHEADER structure to the negative height.  Not everything supports
this though so you may run into some problems with this so it's best to just
play by the rules and work with reversed scanline ordering.  Since the
scanlines must be DWord aligned in a DIB buffer anyway and few formats
actually enforce this on their own, it's often the case that you have to
read and write the scanlines individually anyway, so just write them in
reverse order into the array.

<snip>

Quote:>    ' Create the DIBSection
>    MyDIB = CreateDIBSection(MyDC, bi, DIB_RGB_COLORS, VarPtr(lpBits), 0,

0)

Watch out here, you don't need to pass the memory pointer here
(VarPtr(lpBits)) - it's an output only parameter and by default the API call
is set to ByVal so it will only allow the C++ DLL to read, rather than write
the value (Otherwise it would overwrite the header of your array descriptor
and you'd most likely get a big ol' crash!)
If you want to get the data pointer back, then create a new pointer value
(As a Long) and convert the ppvBits parameter of the CreateDIBSection() call
to being ByRef so the DLL will be able to write to the value:

'***
Private Declare Function CreateDIBSection Lib "gdi32" _
    (ByVal hDC As Long, ByRef pbmi As BITMAPINFO, _
    ByVal iUsage As Long, ByRef ppvBits As Long, ByVal hSection As Long, _
    ByVal dwOffset As Long) As Long

...

Dim DataPtr As Long
Call CreateDIBSection(hDC, bmi, DIB_RGB_COLORS, DataPtr, 0, 0)

' DataPtr now holds a pointer to the DIB data
'***

Quote:>       ' How do I transfer the bits into my picture?

You can either use the SetDIBits() API call, the method described at the top
of the post (Pointing a byte array) or CopyMemory/RtlMoveMemory to the data
pointer.  Make sure your data is compatible with the DIBSection's though
(I.e. DWord aligned, bottom to top, same bit-depth and byte ordering) since
no conversion will be applied for you.

Quote:>       ' SetBitmapBits?

SetBitmapBits() is a throwback from 16-bit Windows and used primarily with
DDB's rather than DIB's.  To be quite honest I've never tried it with a DIB
but I wouldn't be surprised if it didn't work at all since DIBSections are
more of a 32-bit Windows invention.

<snip>

Quote:>    ' Not sure what the following values are used for, but
>    ' the C reference code I have uses the following values
>    bi.biXPel*eter = 2834 ' 0
>    bi.biYPel*eter = 2834 ' 0
>    bi.biClrUsed = 0
>    bi.biClrImportant = 0

The biX/YPel*eter properties are used to describe the DPI of the image,
unless you're writing this out to disk though or printing it then these have
no meaning and you don't need to set them (Very few people bother with these
anyway since they're somewhat undocumented.)
.biClrUsed and .biClrImportant are used to describe the palette use on <=
8-bit images (They're ignored at higher depths.)  The ClrUsed property
defines how many colours for the palette are actually used *I.e. the total
size of the palette, this is usually 2^BitDepth.)  The ClrImportant property
defines the number of important colour entries for low-colour machines,
these days this is seldom used since 16-colour displays are a thing of the
past and unless you're writing your palette sorted by colour count it's
largely meaningless anyway.

Quote:>     'Following formula is from MSDN
>    dwBytesPerLine = ShiftRight((((wBitCount * dwWidth) + 31) And Not 31),
3)
>    bi.biSizeImage = dwBytesPerLine * dwHeight

Yep, this is the code to DWord align a scanline.  Personally I prefer:

'***
Dim ScanLine As Long

ScanLine = (RoundUp(Width * (BitDepth / 8)) + 3) And &H7FFFFFFC
' Or: ScanLine = ((RoundUp(Width * (BitDepth / 8)) + 3) \ 4) * 4
...

Private Function RoundUp(ByVal inVal As Single) As Long
    RoundUp = Int(inVal)
    If (inVal <> RoundUp) Then RoundUp = RoundUp + Sgn(inVal)
End Function
'***

Which is a little easier to read, but either work ok.
Hope this helps,

    Mike

 - Microsoft Visual Basic MVP -

WWW: http://www.veryComputer.com/

 
 
 

Need help from a Guru

Post by <u.. » Tue, 01 Jul 2003 19:05:12


Quote:> <snip>
> >    ' Create the DIBSection
> >    MyDIB = CreateDIBSection(MyDC, bi, DIB_RGB_COLORS, VarPtr(lpBits), 0,
> 0)

> Watch out here, you don't need to pass the memory pointer here
> (VarPtr(lpBits)) - it's an output only parameter and by default the API
call
> is set to ByVal so it will only allow the C++ DLL to read, rather than
write
> the value (Otherwise it would overwrite the header of your array
descriptor
> and you'd most likely get a big ol' crash!)
> If you want to get the data pointer back, then create a new pointer value
> (As a Long) and convert the ppvBits parameter of the CreateDIBSection()
call
> to being ByRef so the DLL will be able to write to the value:

I believe this is actually the opposite of what youre saying.  If I pass a
long, it doesnt get set.  If I pass the pointer, it does get set.  I needed
the pointer for use with CopyMemory to set the bits.   Or am I
misunderstanding what youre saying?

Did you notice any problems with my declarations?   or how Im setting the
biColors array?

Also, not sure if you saw my question, but does it make a difference if
biColors is a fixed or dynamic array?  (Im using dynamic).

 
 
 

Need help from a Guru

Post by Mike D Sutto » Tue, 01 Jul 2003 19:24:45


Quote:> I believe this is actually the opposite of what youre saying.  If I pass a
> long, it doesnt get set.  If I pass the pointer, it does get set.  I
needed
> the pointer for use with CopyMemory to set the bits.   Or am I
> misunderstanding what youre saying?

By default the CreateDIBSection() API call declares this parameter ByVal
which means we only pass the value of the variable rather than the address
of it.  The parameter is out only as described in the MSDN:

<quote src="http://msdn.microsoft.com/library/en-us/gdi/bitmaps_233i.asp">
ppvBits
[out] Pointer to a variable that receives a pointer to the location of the
DIB bit values.
</quote>

If we've only passed the value of a parameter then there's no way we can get
the value of this back no matter what actual value is passed to it.  By
changing the parameter to ByRef, we instead pass a pointer to the variable,
and so when the API call writes to this pointer it will be seen by our VB
application too - Have a look at ByVal and ByRef in help for more on this.

Quote:> Did you notice any problems with my declarations?   or how Im setting the
> biColors array?

I didn't have a good look through them, but most are ok straight out of the
API viewer.

Quote:> Also, not sure if you saw my question, but does it make a difference if
> biColors is a fixed or dynamic array?  (Im using dynamic).

It depends where you're using this array.  If you're using it as part of a
BITMAPINFO structure for example then you'll run into a bunch of problems
since VB's dynamic array are prefixed with an array descriptor containing
information about the array.  If you pass a pointer to the BITMAPINFO
structure to an API call it will interpret the data as a contiguous block
and read the array header as palette entries!  If you use a fixed array
(Just declare it as a 256 byte array and use what you need of it, the API
will ignore anything that's not used) then there is no array descriptor
(Since VB knows the size of this data block ahead of time) and the API will
properly read in the palette entries.
Hope this helps,

    Mike

 - Microsoft Visual Basic MVP -

WWW: Http://www.mvps.org/EDais/

 
 
 

Need help from a Guru

Post by Eric Baum » Fri, 04 Jul 2003 00:37:15


Hello.

I've been having a resource leak problem similar to one alluded to
here and was wondering if anybody's got any ideas.

Quote:> First up, you've got a possible resource leak in both methods with this kind
> of structure:

> '***
> hMemDC = CreateCompatibleDC(pb.hDC)
> hBitmap = CreateCompatibleBitmap(pb.hDC, width, height)
> hOldBitmap = SelectObject(hMemDC, hBitmap)

My code looks something more like this.

    CRect mapRect;
    GetClientRect(mapRect);
    CDC* outerdc = GetDC();
    CDC dc;
    dc.CreateCompatibleDC(outerdc);

    CBitmap* fTempBitmap = new CBitmap();
    fTempBitmap->CreateCompatibleBitmap(outerdc, mapRect.right,
mapRect.bottom);
    CBitmap* oldBitmap = (CBitmap*)dc.SelectObject(fTempBitmap);

Before the function in which this occurs ends, I make sure to select
fTempBitmap out of the dc and oldBitmap back in with

    dc.SelectObject( oldBitmap );

Then, before the end of the function, I delete the bitmap and dc and
release the outerdc.

    fTempBitmap->DeleteObject();
    delete fTempBitmap;
    dc.DeleteDC();
    ReleaseDC( outerdc );

According to the system monitor, I am not leaking memory or anything
like that.  However, BoundsChecker is still telling me there is a
Resouce Leak being caused by CreateCompatibleBitmap.  The
documentation says that, after I am done with the compatible bitmap,
it must be selected out of the DC and deleted.  As far as I can tell,
that is being done.

I am also getting a resource leak with a similar method that uses
LoadBitmap to load a predefined resource bitmap, but I suspect that
they are related.  Basically, I'm wondering if there is something else
that must be done to release a bitmap created with
CreateCompatibleBitmap or LoadBitmap.  Any kind of help or advice
would be most appreciated.

 
 
 

Need help from a Guru

Post by Mike D Sutto » Fri, 04 Jul 2003 18:07:08


Quote:> I've been having a resource leak problem similar to one alluded to
> here and was wondering if anybody's got any ideas.
> My code looks something more like this.
<snip>
> Before the function in which this occurs ends, I make sure to select
> fTempBitmap out of the dc and oldBitmap back in with
<snip>
> Then, before the end of the function, I delete the bitmap and dc and
> release the outerdc.
<snip>
> According to the system monitor, I am not leaking memory or anything
> like that.  However, BoundsChecker is still telling me there is a
> Resouce Leak being caused by CreateCompatibleBitmap.  The
> documentation says that, after I am done with the compatible bitmap,
> it must be selected out of the DC and deleted.  As far as I can tell,
> that is being done.

> I am also getting a resource leak with a similar method that uses
> LoadBitmap to load a predefined resource bitmap, but I suspect that
> they are related.  Basically, I'm wondering if there is something else
> that must be done to release a bitmap created with
> CreateCompatibleBitmap or LoadBitmap.  Any kind of help or advice
> would be most appreciated.

First off, you'd probably be better posting this to a C++ or GDI group such
as microsoft.public.win32.programmer.gdi since this is a VB groups and we
don't use (Or have access to) the MFC GDI wrapper objects you're using.
One thing I'd suggest though is that perhaps you need to clean up these
objects, there's still a bunch in use (Despite having had their internal GDI
objects dealt with properly) at the end of the code, at least from what
you've posted.  From what I can see, oldBitmap*, dc, outerdc* and maprect
are all still active at the end of the routine, try calling delete on each
one and see if that cleans up the problem, otherwise as far as I see there's
no leak in the code you posted.
Hope this helps,

    Mike

 - Microsoft Visual Basic MVP -

WWW: Http://www.mvps.org/EDais/

 
 
 

Need help from a Guru

Post by Brad Baue » Tue, 08 Jul 2003 09:28:07


Im baaaaack!

Change of internet providers, and some hardware changes as well... so I
never got a chance to get back in here and see
what else was said.



Quote:> > I believe this is actually the opposite of what youre saying.  If I pass
a
> > long, it doesnt get set.  If I pass the pointer, it does get set.  I
> needed
> > the pointer for use with CopyMemory to set the bits.   Or am I
> > misunderstanding what youre saying?

> By default the CreateDIBSection() API call declares this parameter ByVal
> which means we only pass the value of the variable rather than the address
> of it.  The parameter is out only as described in the MSDN:

> <quote src="http://msdn.microsoft.com/library/en-us/gdi/bitmaps_233i.asp">
> ppvBits
> [out] Pointer to a variable that receives a pointer to the location of the
> DIB bit values.
> </quote>

> If we've only passed the value of a parameter then there's no way we can
get
> the value of this back no matter what actual value is passed to it.  By
> changing the parameter to ByRef, we instead pass a pointer to the
variable,
> and so when the API call writes to this pointer it will be seen by our VB
> application too - Have a look at ByVal and ByRef in help for more on this.

I guess Im confused here.  I'll have to look a bit further into what you
mean.  The way I was doing it 'was' working though.
Perhaps were accomplishing the same thing different ways.  You using ByRef,
me using VarPrt, Im not sure.

Quote:> > does it make a difference if
> > biColors is a fixed or dynamic array?  (Im using dynamic).

> It depends where you're using this array.  If you're using it as part of a
> BITMAPINFO structure for example then you'll run into a bunch of problems
> since VB's dynamic array are prefixed with an array descriptor containing
> information about the array.  If you pass a pointer to the BITMAPINFO
> structure to an API call it will interpret the data as a contiguous block
> and read the array header as palette entries!  If you use a fixed array
> (Just declare it as a 256 byte array and use what you need of it, the API
> will ignore anything that's not used) then there is no array descriptor
> (Since VB knows the size of this data block ahead of time) and the API
will
> properly read in the palette entries.
> Hope this helps,

Ok, this might be my problem then.  I believe I was using a dynamic array,
not realising there was a difference in the structures that created in
memory.

Thanks
Brad

 
 
 

Need help from a Guru

Post by Mike D Sutto » Tue, 08 Jul 2003 17:54:50


Quote:> I guess Im confused here.  I'll have to look a bit further into what you
> mean.  The way I was doing it 'was' working though.
> Perhaps were accomplishing the same thing different ways.  You using
ByRef,
> me using VarPrt, Im not sure.

The reason it was working before was that you were never actually using the
pointer to the data (You were using GetDIBits() instead which reads the data
pointer internally), if you check it's value in your code you'll see it
never gets set.  While this is fine and as you say, doesn't impede your
current code, if you do decide to move to a faster method utilising the
Bitmap data pointer then your current method wouldn't work with the API call
set up the way it is currently.

Quote:> Ok, this might be my problem then.  I believe I was using a dynamic array,
> not realising there was a difference in the structures that created in
> memory.

If you particularly need the pointer to the array structure then you can use
the VarPtrArr() function which you'll find on one of the pots previously
linked to in this thread, otherwise to pass a pointer to the array data
itself simply pass the first item of the array (The array contents is stored
contiguously so all other items follow this one.)
Hope this helps,

    Mike

 - Microsoft Visual Basic MVP -

WWW: Http://www.mvps.org/EDais/

 
 
 

1. HELP!!! Need help of ASM guru

Hello all...

        I am new to the world of assmebly and I am trying to do something and I
have
NO idea on how to do it.  Here it is, I have a unsigned char pointer with 64K
alloacted to it and a decoded graphic in it, now I want it on the screen
REALLY fast, so I figured that I would use Inline ASM and do a simple "Move
into A000h stosw loop" but quickly run into a problem, how do I use the
pointer in the ASM code, I figure that there must be a way to copy one memory
area to another in ASM...any help would be wonderful, please EMAIL...

                        TTYL,

                                Chris

||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
        Christopher McKillop
        Computer Engineering      "There can be only one!!!"
        University of Waterloo          - The Highlander


        Former AlphaQ member...:(
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

2. Simple combimer ext example...

3. Need Help from Clipboard Gurus

4. Conv3ds to .X file for Direct 3D looses mapping coordinates

5. Need help from graphics guru

6. PLEASE HELP ME!!

7. Need Help From graphics Guru!

8. Particle system hurricanes and tornadoes

9. QuarkXPRess Gurus--Novice Needs Help!

10. Dreamweaver 3 Gurus- need your help!

11. Hey HTML guru's Need Help!

12. QuarkXPRess Gurus--Novice Needs Help!

13. HELP: Graphics GURU in 3d needed!