Avatar of flynny
flynnyFlag for United Kingdom of Great Britain and Northern Ireland asked on

help using CArrayBITMAP

hi,

i'm trying to use the following links class to create and array of bitmaps loaded into memory.

however it doesn't seem to be adding it to the class. can anyone see what i'm doing wrong?

http://www.codeguru.com/cpp/g-m/bitmap/article.php/c4937/

heres my code for using it

            HBITMAP hBmp = (HBITMAP)::LoadImage(NULL,bmp,
                                 IMAGE_BITMAP,0,0,
                                 LR_LOADFROMFILE|LR_CREATEDIBSECTION);

            if(hBmp)
            {
                  CBitmap cBmp;
                  cBmp.FromHandle(hBmp);

                  int bmpPosition = array.Add(&cBmp);

                  if(bmpPosition != -1)
                  {
                  }
                  else
                  {
//is always -1 for some reason
                  }
            }

just to add i know the bitmap i pass does exist.

matt.
C++

Avatar of undefined
Last Comment
evilrix

8/22/2022 - Mon
evilrix

Hmmm... this isn't an aswer to your problem but do you realize you are adding the address of a stack based object into the array. Once the if(hBmp){} code block exits cBmp is destroyed.
evilrix

Personally, I'd just use the STL std::vector container :)
evilrix

Example using std::vector

#include <vector>

typedef vector<CBitmap *> BitmapVector;
BitmapVector array;

HBITMAP hBmp = (HBITMAP)::LoadImage(NULL,bmp,
                                 IMAGE_BITMAP,0,0,
                                 LR_LOADFROMFILE|LR_CREATEDIBSECTION);

            if(hBmp)
            {
                  CBitmap pBmp = new CBitmap; // Don't forget to delete me
                  pBmp->FromHandle(hBmp);

                  int bmpPosition = array.push_back(pBmp);

                  if(bmpPosition != -1)
                  {
                  }
                  else
                  {
//is always -1 for some reason
                  }
            }



NB. newing to raw pointers isn't really safe -- exceptions can cause memory leaks. Consider using an RAII wrapper such as boost::shared_ptr. Don't forget to delete the heap allocated bitmap classes when you've done with them (not necessary if you use an RAII wrapper!).
I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
evilrix

oops... nearly -- copy/paste error ignore previous code example, I'll try again :)

#include <vector>

typedef vector<CBitmap *> BitmapVector;
BitmapVector array;

HBITMAP hBmp = (HBITMAP)::LoadImage(NULL,bmp,
                                 IMAGE_BITMAP,0,0,
                                 LR_LOADFROMFILE|LR_CREATEDIBSECTION);

            if(hBmp)
            {
                  CBitmap pBmp = new CBitmap; // Don't forget to delete me
                  pBmp->FromHandle(hBmp);

                  array.push_back(pBmp);
}
            }

evilrix

Arrrggg.... I really should have tried compiling this first :)

This...

     CBitmap pBmp = new CBitmap; // Don't forget to delete me


Should be...

     CBitmap * pBmp = new CBitmap; // Don't forget to delete me

Sorry -- It's tricky to try compiling code snippets.
evilrix

I wish there was a post undo :)
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
ASKER
flynny

hi thanks for the reply evilrix

ok, also i would like to store some information with each bitmap if i say created a structure with the CBitmap and a char (which is what i need really) would be a good idea.

Also will storing the CBitmap have any impact on the memory and performance of the app?

many thanks,

matt.
evilrix

struct bmMeta
{
    CBitmap m_bitmap;
    char c;
};

typedef std::vector<bmMeta> array;


Regarding memory -- no idea, it depends how big the objects being allocated are and how many there are.
ASKER
flynny

hi

thanks for the help. i created the following

struct BitmapArray
{
    HBITMAP m_bitmap;
    char c;
}data[64];

ok my methods are in a dll and use a callback function and so i have a globals.h file which uses the data_seg .shared so the vars are availale across multiple processes. (this is where i put the above structure)

i hold all my bmp checking in seperate cpp and h files. for one method i want to pass across a path and the BitmapArray for population like so
(from the bmp.h file)
BitmapArray LoadTrainingData(LPTSTR path, BitmapArray* array[]);
this will populate with bmps from path and return the array

LoadTrainingData("C:\\Data", &data);

however i get the following error? can you help please
cannot convert parameter 2 from 'struct BitmapArray (*)[64]' to 'struct BitmapArray *[]'

also the other problem is how will the bmp.cpp know what a BitmapArray structure is? as i have defined it in the globals.h (.shared) section bu can't include this here as it throws more errors?

any ideas?
Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
evilrix

Try:

BitmapArray LoadTrainingData(LPTSTR path, BitmapArray* array);
LoadTrainingData("C:\\Data", data);

The compiler will need to see a definition for BitmapArray before it can use it -- you'll have to structure your project accordoingly.
ASKER
flynny

hi,

after playing around with this i think its going to be easier for me to go back to using the CArrayBITMAP as it has a few methods that i can use at a later stage for retieving.

How can i add these to bitmaps to the array without them being destroyed once the if statement exits?
ASKER
flynny

oh by the way this is the code i'm using now i changed it slightly

ArrayBITMAP LoadTrainingData(LPTSTR path, CArrayBITMAP* array)
{
      //path contains the directory the images are storad e.g. c:\\data
      int i;
      CString bmp;
      HBITMAP hBmp;

      //load in 0-9.bmp vals 48-57
      for( i=48; i<58; i++ )
      {
            bmp.Format("%s\\%c.bmp", path,i);

            hBmp = (HBITMAP)::LoadImage(NULL,bmp,
                                 IMAGE_BITMAP,0,0,
                                 LR_LOADFROMFILE|LR_CREATEDIBSECTION);

            if(hBmp)
            {
                  BITMAP WorkBmp;
                  GetObject(hBmp, sizeof(WorkBmp), &WorkBmp);

                  int bmpPosition = array->Add(&WorkBmp);

                  if(bmpPosition != -1)
                  {
                  }
                  else
                  {

                  }
            }
            else
            {

            }
      }
return array;
}

i have made some test images 0-9.bmp and want to try adding these to the array.
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
evilrix

Heap allocate as per my original example code....


// Create
CBitmap *pBmp = new CBitmap;

// Destroy
delete pBmp;
ASKER
flynny

hi thanks.

adding the CBitmap to the array doesn't seem to be working however, if i add this way it does (although its obviously destroying it as its still saying the array is empty when i return it).

this code seems to work (i.e. inserts before they are destroyed)

             BITMAP WorkBmp;
                  GetObject(hBmp, sizeof(WorkBmp), &WorkBmp);

                  int bmpPosition = array->Add(&WorkBmp);
how can i create a new instance of BITMAP in the memory would i have to malloc?

evilrix

malloc and C++ do NOT mix!!!! It is not typedef and does not construct objects correctly. It has no useful place in C++ (with a few minor exceptions that I won't go into here!).

Use...

// Create
BITMAP * pBm = new BITMAP;

// Destroy
delete pBm;

Note that new will throw on error (well, it should if your complier is properly ANSI complient) so there is no need to check for NULL being returned.
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
evilrix

type -- typedef == type-safe
evilrix

malloc and C++ do NOT mix!!!! It is not [[[ type-safe ]]]
ASKER
flynny

ok, i tred this and it doesnt seem to be working in fact -1 is always been returned as before if i use the code

            BITMAP* WorkBmp = new BITMAP;
            GetObject(hBmp, sizeof(WorkBmp), WorkBmp);

            int bmpPosition = array->Add(WorkBmp);
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
evilrix

This works for me...

void CtestmfcDlg::OnBnClickedButton1()
{
      CArray<BITMAP *> a;
      BITMAP* WorkBmp = new BITMAP;
      int bmpPosition = a.Add(WorkBmp);
}

...try it!
evilrix

This too....

void CtestmfcDlg::OnBnClickedButton1()
{
      CArray<BITMAP *> a;

      for(int n = 0 ; n < 100 ; ++n)
      {
            BITMAP* WorkBmp = new BITMAP;
            int bmpPosition = a.Add(WorkBmp);
      }

      int size = a.GetSize();
      
}
ASKER
flynny

hmm it the class doesnt seem to work very well so 've (sorry to mess you around) reverted back to our original method.

ok so i have in the .shared segment a global array

      BitmapArray* bmpData[maxBitmaps];

and i call the method BitmapArray* LoadData(LPTSTR path, BitmapArray* array[]);

which i working. ok so no when the LoadDat method returns the array i've sent it, it return empty again.

this is the code i've written

BitmapArray* LoadTrainingData(LPTSTR path, BitmapArray* array[])
{
      //path contains the directory the images are storad e.g. c:\\data
      int i;
      CString bmp;
      HBITMAP hBmp;

      resetBitmapArray(array); //reset the training data array (just in case);

      //load in 0-9.bmp vals 48-57
      for( i=48; i<58; i++ )
      {
            bmp.Format("%s\\%c.bmp", path,i);
            hBmp = (HBITMAP)::LoadImage(NULL,bmp,
                                 IMAGE_BITMAP,0,0,
                                 LR_LOADFROMFILE|LR_CREATEDIBSECTION);

            if(hBmp)
            {
                  //add to the array
                  BitmapArray* tbmp = new BitmapArray;

                  tbmp->bitmap = hBmp;
                  tbmp->value = char(i);

                  if(addBitmap(*tbmp, array))
                  {
//ok
                  }
                  else
                  {

                  }
            }
            else
            {

            }
      }
return array;
}
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
ASKER
flynny

sorry where addbitmap is

BOOL addBitmap(BitmapArray bmp, BitmapArray* array[])
{
      int i;
      for(i=0; i<maxBitmaps; i++)
            if(array[i] == NULL)
            {
                  array[i] = new BitmapArray;
                  array[i]->bitmap = bmp.bitmap;
                  array[i]->value = bmp.value;
                  return true;
            }

      return false;
}

void resetBitmapArray(BitmapArray* array[])
{
      int i;
      for(i=0; i<maxBitmaps; i++)
      {
            if(array[i] != NULL)
            {
                  delete array[i]->bitmap;
                  array[i]->bitmap = NULL;
                  array[i]->value = NULL;
                  array[i] = NULL;
            }
      }
}
evilrix

Ok, obviously I can't test it but I have re-written your code to at least make sense.

I assume all elements in the array have been all NULL'ed out prior to calling LoadTrainingData? If not it will never find a slot!

If this doesn't work I feel I am unable to help you further.

BOOL addBitmap(BitmapArray * bmp, BitmapArray* array[])
{
      bool bRetval = false;

      for(int i=0; i<maxBitmaps; ++i)
      {
            if(array[i] == NULL)
            {
                  array[i] = bmp;
                  bRetval = true;
            }
      }

      return bRetval;
}

void resetBitmapArray(BitmapArray* array[])
{
      for(int i=0; i<maxBitmaps; ++i)
      {
            if(array[i] != NULL)
            {
                  delete array[i];
                  array[i] = NULL;
            }
      }
}

BitmapArray* LoadTrainingData(LPTSTR path, BitmapArray* array[])
{
      //path contains the directory the images are storad e.g. c:\\data
      CString bmp;
      HBITMAP hBmp;

      resetBitmapArray(array); //reset the training data array (just in case);

      //load in 0-9.bmp vals 48-57
      for(int i=48; i<58; i++ )
      {
            bmp.Format("%s\\%c.bmp", path,i);

            hBmp = (HBITMAP)::LoadImage(NULL,bmp,
                  IMAGE_BITMAP,0,0,
                  LR_LOADFROMFILE|LR_CREATEDIBSECTION);

            if(hBmp)
            {
                  //add to the array
                  BitmapArray* tbmp = new BitmapArray;

                  tbmp->bitmap = hBmp;
                  tbmp->value = char(i);

                  if(addBitmap(tbmp, array))
                  {
                        //ok
                  }
                  else
                  {

                  }
            }
            else
            {

            }
      }

      return (*array);
}

-Rx.
ASKER CERTIFIED SOLUTION
evilrix

Log in or sign up to see answer
Become an EE member today7-DAY FREE TRIAL
Members can start a 7-Day Free trial then enjoy unlimited access to the platform
Sign up - Free for 7 days
or
Learn why we charge membership fees
We get it - no one likes a content blocker. Take one extra minute and find out why we block content.
See how we're fighting big data
Not exactly the question you had in mind?
Sign up for an EE membership and get your own personalized solution. With an EE membership, you can ask unlimited troubleshooting, research, or opinion questions.
ask a question
itsmeandnobodyelse

Matt,

look at the last code evilrix posted. It is much better than yours, not needing any pointers and helper structs like BitmapArray.

>>>> typedef std::vector<HBITMAP> BitmapVector;
Here you have an array of handles to loaded bitmaps what is all you need. The index in the array gives you the 'name' of the bitmap file. There is no need to store it as a separate index in a struct.

>>>> HBITMAP hBmp = (HBITMAP)::LoadImage(NULL, bmpFilePath,
Here is a error. You need

     HBITMAP hBmp = (HBITMAP)::LoadImage(NULL,bmpFilePath.str().c_str(),

>>>> BitmapVector::const_iterator
If you got problems using const iterators or const HBITMAP, you can simply drop the const. It doesn't matter whether you are using a const reference or a non-const copy:


      // Access by index
      for(int i = 0 ; i < (int)bdv.size() ; ++ i)
      {
            HBITMAP bmp = bdv[i];

            DrawImage(bmp, ...);
             
      }

Regards, Alex



Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
evilrix

>> look at the last code evilrix posted. It is much better than yours...

Stop it, you're making me blush :-D
itsmeandnobodyelse

>>>> Stop it, you're making me blush
I could have added that you needed some attempts to finally posting a valid code. Do you want me to say that? No? Ok, I won't do it.  ;-)
evilrix

oi oi... that's a bit unfair!

The first lot of code examples were trying to work with the questioners code to see if I could offer him a solution that wasn't too different or confusing for him. The final version was an example of how I would do it, so he could see how simpler it could be when using the right tools! :-p

What made it harder is that I only have VS Express so I can't actually test his code -- it doesn't support MFC :(
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
ASKER
flynny

thanks for all you help guys this has been a real learning experience (and thanks for your patience rix!!)

after taking everything on board i created a new class which uses the vector to hold the bitmaps and so i can hold this in the .shared segment.  this class contains all the methods to loads the bitmaps etc. and is working great!
evilrix

Cool, I'm glad I was able to help :)

Just as an aside, you'll be served well if you learn about STL -- it's very powerul, efficient and avaliable on all versions of C++ (except very early versions!).

Regards,

-Rx.
evilrix

Um, at this point it is usually appropriate to accept the answer(s) to ensure the expert(s) who contributed are awarded the points the worked so hard for :)
Get an unlimited membership to EE for less than $4 a week.
Unlimited question asking, solutions, articles and more.
ASKER
flynny

sorry i got side tracked roning out a bug i didn't forget.

thanks for the advice rix.
evilrix

You are very welcome :)

Good luck Flynny.
evilrix

Something additional/important for you to know about std::stringstream's str() method...

The call to str() returns a std::string BY VALUE that is a copy of the contents of the internal buffer of the stringstream
The c_str() call returns a char const * pointer to the c-style string wrapped by the std::string returned by str()

These two nuggets of info have a small but rather serious implication....

Consider

char const * p = bmpFilePath.str().c_str();

At this point p is pointing to invalid memory. Why? Because the std::string that was returned by value was used as a temprary and it has now been destroyed! How do you get around this? Simple, bind the std::string returned to a reference type.

std:: string const & s = bmpFilePath.str();
char const * p = s.c_str();

At this point the temporary std::string has been bound to the reference type s and will now live for the duration of the reference type it is bound to; therefore, p is safe to use until s goes out of scope.

I hope this makes sense!

Just a note to add to that the correction Alex made to my (untested) code is perfectly safe and correct...

HBITMAP hBmp = (HBITMAP)::LoadImage(NULL,bmpFilePath.str().c_str())

...since the temporary std::string returned by str() lives for the duration of the whole expression (that line)!

-Rx.
Your help has saved me hundreds of hours of internet surfing.
fblack61