when do:

operator HBITMAP()
    {
        HBITMAP hbitmap=CreateBitmap(imageweight,imageheight,1,32,NULL);//create the bitmap with icon size
        SelectObject(hdcimage, hbitmap);//add the bitmap to memory DC
        MessageBox(NULL,to_string(GetLastError()).c_str(),"error",MB_OK);
        return hbitmap;
    }

the hdcimage is copyied to hbitmap, right?

Edited 1 Year Ago by pritaeas: Changed title. Next time please use the flag icon next to your post. Every moderator can see you request then and help you, I am not always online.

Have you tested your code? The way I do it is:

HBITMAP hBmp = reinterpret_cast<HBITMAP>(GetCurrentObject(DC, OBJ_BITMAP));

This is a MS API question, and not relevant generally to C++. We would need to know in detail what the SelectObject() function is doing, and that is not in the pervue of C++. It is specific to the MS API's. Read their documentation for more information would be an appropriate answer I think.

triumphost the image isn't showed on menu :(

//on image class
operator HBITMAP()
    {
        HBITMAP hbitmap=reinterpret_cast<HBITMAP>(GetCurrentObject(hdcimage, OBJ_BITMAP));
        return hbitmap;
    }




//on menu class
void bitmap(image imgImage)
    {
        //HBITMAP bitimage = (HBITMAP)LoadImage( NULL, filename.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
        HMENU hMenu = NULL;
        if(primeiromenu)
            hMenu = mnuBar;
        else
            hMenu = MenuHandle;
        SetMenuItemBitmaps(hMenu,menuposition,MF_BYPOSITION ,(HBITMAP)imgImage ,(HBITMAP)imgImage);
    }

finally works fine:

class image
{
private:
    ULONG_PTR m_gdiplusToken;
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    HDC hdcimage=CreateCompatibleDC(NULL);
    HBITMAP btBimap;
    Gdiplus::Graphics *graphic;
    Image *img;
    int imageheight=0;
    int imageweight=0;
    int framecount=0;
    int intSelectFrame=0;
    int framedelay=0;
    string strfilename="";
    Gdiplus::Color clrBackColor=Gdiplus::Color::Transparent;
    HDC hdcwindow;
    bool blnTransparent=true;


public:
    image()
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
        btBimap=CreateCompatibleBitmap(hdcimage,1,1);
        SelectObject(hdcimage, btBimap);
    }

    image(HDC hdcWindow)
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
        hdcwindow=hdcWindow;
    }

    image(int width, int height)
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
        hdcimage = CreateCompatibleDC(NULL);
        btBimap=CreateCompatibleBitmap(hdcimage,width,height);
        SelectObject(hdcimage, btBimap);
        framecount=1;
    }

    image(  const string & filename)
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

        if(toupper(filename[filename.size()-3])=='C' && toupper(filename[filename.size()-2])=='U' && toupper(filename[filename.size()-1])=='R')
        {
            //create the transparent icon handle
            HCURSOR hicon =  (HCURSOR)LoadImage(NULL, filename.c_str(), IMAGE_CURSOR, imageweight, imageheight, LR_LOADFROMFILE|LR_SHARED|LR_DEFAULTSIZE|LR_LOADTRANSPARENT);

            ICONINFO ii;
            BOOL fResult = GetIconInfo(hicon, &ii);
            if (fResult)
            {
                BITMAP bm;
                fResult = GetObject(ii.hbmMask, sizeof(bm), &bm) == sizeof(bm);
                if (fResult)
                {
                    imageweight= bm.bmWidth;
                    imageheight= ii.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
                }
                if (ii.hbmMask)  DeleteObject(ii.hbmMask);
                if (ii.hbmColor) DeleteObject(ii.hbmColor);
            }

            btBimap=CreateBitmap(imageweight,imageheight,1,32,NULL);//create the bitmap with icon size
            SelectObject(hdcimage, btBimap);//add the bitmap to memory DC
            DrawIconEx(hdcimage,0,0,hicon,imageweight,imageheight,0,0,DI_NORMAL);//draw the icon to DC with right size
            //seems the DrawIcon(), always, draw it with 32X32 size
            framecount=1;
        }
        else
        {
            Gdiplus::Image img2(towstring(filename).c_str());

            btBimap=CreateBitmap(img2.GetWidth(),img2.GetHeight(),1,32,NULL);
            SelectObject(hdcimage, btBimap);
            Gdiplus::Graphics graphics(hdcimage);
            graphics.DrawImage(&img2, 0, 0, img2.GetWidth(), img2.GetHeight());
            imageweight=img2.GetWidth();
            imageheight=img2.GetHeight();
            UINT count = 0;
            count = img2.GetFrameDimensionsCount();
            GUID* pDimensionIDs = (GUID*)malloc(sizeof(GUID)*count);
            img2.GetFrameDimensionsList(pDimensionIDs, count);

            framecount=img2.GetFrameCount(&pDimensionIDs[0]);
            framedelay =img2.GetPropertyItemSize(PropertyTagFrameDelay);
            img=new Image(towstring(filename).c_str());
        }
    }
    image (const image &cSource)
    {
        framecount=cSource.framecount;
        framedelay=cSource.framedelay;
        clrBackColor=cSource.clrBackColor;
        img=cSource.img->Clone();
        imageweight=cSource.imageweight;
        imageheight=cSource.imageheight;
        btBimap=CreateBitmap(imageweight,imageweight,1,32,NULL);
        SelectObject(hdcimage, btBimap);
        BitBlt(hdcimage,0,0,imageweight,imageheight,cSource.hdcimage,0,0,SRCCOPY);
    }
    image& operator= (const image &cSource)
    {
        framecount=cSource.framecount;
        framedelay=cSource.framedelay;
        intSelectFrame=cSource.intSelectFrame;
        clrBackColor=cSource.clrBackColor;
        imageweight=cSource.imageweight;
        imageheight=cSource.imageheight;
        btBimap=CreateBitmap(imageweight,imageweight,1,32,NULL);
        SelectObject(hdcimage, btBimap);
        BitBlt(hdcimage,0,0,imageweight,imageheight,cSource.hdcimage,0,0,SRCCOPY);
        return *this;
    }

    property <int> SelectFrame
    {
        Get(int)
        {
            return intSelectFrame;
        },
        Set(int selectframe)
        {
            intSelectFrame=selectframe;
            UINT count = 0;
            count = img->GetFrameDimensionsCount();
            GUID* pDimensionIDs = (GUID*)malloc(sizeof(GUID)*count);
            img->GetFrameDimensionsList(pDimensionIDs, count);
            img->SelectActiveFrame(&pDimensionIDs[0],intSelectFrame);
            graphic=new Graphics(hdcimage);
            graphic->Clear(clrBackColor);
            graphic->DrawImage(img, 0, 0, img->GetWidth(), img->GetHeight());
        }
    };

    property<int> FramesCount
    {
        Get(int)
        {
            return framecount;
        }
    };

    property<Gdiplus::Color> Backcolor
    {
        Get(Gdiplus::Color)
        {
            return clrBackColor;
        },
        Set(Gdiplus::Color bkcolor)
        {
            clrBackColor = bkcolor;
            SetDCBrushColor(hdcimage,clrBackColor.ToCOLORREF());
        }
    };

    void draw(HDC control)
    {


        //if (clrBackColor.GetValue() == Gdiplus::Color::Transparent)
        if (clrBackColor.GetValue()== Gdiplus::Color::Transparent)
        {
            TransparentBlt(control, 0, 0,width(),height(),hdcimage, 0, 0,width(), height(), GetPixel(hdcimage,width()-1,height()-1));
        }
        else
        {
            BitBlt(control,0,0,width(),height(),hdcimage,0,0,SRCCOPY);
        }

        //InvalidateRect(WindowFromDC(control),NULL,false);
    }

    operator HBITMAP()
    {
        return btBimap;
    }

    int height()
    {
        return imageheight;
    }
    int width()
    {
        return imageweight;
    }

    operator HDC()
    {
        return hdcimage;
    }

    ~image()
    {
        delete img;
        Gdiplus::GdiplusShutdown(m_gdiplusToken);
        //SelectObject(hdcimage, hbmOld);
        DeleteDC(hdcimage);
    }
};
//i created a HBITMAP global on my image class
operator HBITMAP()
    {
        return btBimap;
    }

but when i click on menu item, i have a memory leak. why?

That's a LOT of code just for one simple task: getting an hbitmap from an hdc..

Your code leaks because.. You need lessons in memory management.. Or at least, guidance. You really really need to take care of your code more carefully.

----------------------------------------------------

a. In your constructors, you are doing:

btBimap = CreateBitmap(w, h, 1, 32, NULL);

But in your destructor, you have NEVER deleted it with DeleteObject(btBtmap).

---------------------------------------------------

b. You never re-select the OldBitmap back into the DC at all! In the constructor you are doing:

SelectObject(hdcimage, btBimap); which needs to be: HGDIOBJ obj = SelectObject(hdcimage, btBimap);

then in the destructor you need to do: SelectObject(hdcimage, obj) and THEN you can delete the btBitmap. Either that or select it right back in after you finish using it.. That way you don't need to do it in the destructor.. Not sure why you need to keep it selected in the first place.

---------------------------------------------------

c. You are doing: HCURSOR hicon = (HCURSOR)LoadImage(NULL, path, IMAGE_CURSOR, w, h, ....);

But you NEVER delete the hicon..

----------------------------------------------------

d. You are doing: GUID* pDimensionIDs = (GUID*)malloc(sizeof(GUID)*count); TWICE but you NEVER call free(pDimensionIDs) even once.

----------------------------------------------------

e. You are doing: graphic = new Graphics(hdcimage); but you NEVER delete graphic; anywhere. In your "set" function, you never bother to check if it already exists either.. So even if you delete it in your destructor, calling set twice will cause it to leak anyway.. You need to call delete before you set it. And call delete in the destructor as well.. Otherwise, find a way to make sure you don't set it if it's already set!

Edited 1 Year Ago by triumphost

Comments
thanks for all

i did all the changes, but i continue with problems:

class image
{
private:
    ULONG_PTR m_gdiplusToken;
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    HDC hdcimage=CreateCompatibleDC(NULL);
    HGDIOBJ obj=NULL;
    HBITMAP btBitmap;
    Gdiplus::Graphics *graphic;
    Image *img;
    int imageheight=0;
    int imageweight=0;
    int framecount=0;
    int intSelectFrame=0;
    int framedelay=0;
    string strfilename="";
    Gdiplus::Color clrBackColor=Gdiplus::Color::Transparent;
    HDC hdcwindow;
    bool blnTransparent=true;


public:
    image()
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
        btBitmap=CreateCompatibleBitmap(hdcimage,1,1);
        obj = SelectObject(hdcimage, btBitmap);
    }

    image(HDC hdcWindow)
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
        hdcwindow=hdcWindow;
    }

    image(int width, int height)
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
        hdcimage = CreateCompatibleDC(NULL);
        btBitmap=CreateCompatibleBitmap(hdcimage,width,height);
        obj = SelectObject(hdcimage, btBitmap);
        framecount=1;
    }

    image(  const string & filename)
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

        if(toupper(filename[filename.size()-3])=='C' && toupper(filename[filename.size()-2])=='U' && toupper(filename[filename.size()-1])=='R')
        {
            //create the transparent icon handle
            HCURSOR hicon =  (HCURSOR)LoadImage(NULL, filename.c_str(), IMAGE_CURSOR, imageweight, imageheight, LR_LOADFROMFILE|LR_SHARED|LR_DEFAULTSIZE|LR_LOADTRANSPARENT);

            ICONINFO ii;
            BOOL fResult = GetIconInfo(hicon, &ii);
            if (fResult)
            {
                BITMAP bm;
                fResult = GetObject(ii.hbmMask, sizeof(bm), &bm) == sizeof(bm);
                if (fResult)
                {
                    imageweight= bm.bmWidth;
                    imageheight= ii.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
                }
                if (ii.hbmMask)  DeleteObject(ii.hbmMask);
                if (ii.hbmColor) DeleteObject(ii.hbmColor);
            }

            btBitmap=CreateBitmap(imageweight,imageheight,1,32,NULL);//create the bitmap with icon size
            obj = SelectObject(hdcimage, btBitmap);//add the bitmap to memory DC
            DrawIconEx(hdcimage,0,0,hicon,imageweight,imageheight,0,0,DI_NORMAL);//draw the icon to DC with right size
            //seems the DrawIcon(), always, draw it with 32X32 size
            framecount=1;
            DestroyCursor(hicon);
        }
        else
        {
            Gdiplus::Image img2(towstring(filename).c_str());

            btBitmap=CreateBitmap(img2.GetWidth(),img2.GetHeight(),1,32,NULL);
            obj = SelectObject(hdcimage, btBitmap);
            Gdiplus::Graphics graphics(hdcimage);
            graphics.DrawImage(&img2, 0, 0, img2.GetWidth(), img2.GetHeight());
            imageweight=img2.GetWidth();
            imageheight=img2.GetHeight();
            UINT count = 0;
            count = img2.GetFrameDimensionsCount();
            GUID* pDimensionIDs = (GUID*)malloc(sizeof(GUID)*count);
            img2.GetFrameDimensionsList(pDimensionIDs, count);

            framecount=img2.GetFrameCount(&pDimensionIDs[0]);
            framedelay =img2.GetPropertyItemSize(PropertyTagFrameDelay);
            img=new Image(towstring(filename).c_str());
            free(pDimensionIDs);
        }
    }
    image (const image &cSource)
    {
        framecount=cSource.framecount;
        framedelay=cSource.framedelay;
        clrBackColor=cSource.clrBackColor;
        img=cSource.img->Clone();
        imageweight=cSource.imageweight;
        imageheight=cSource.imageheight;
        if(obj==NULL)
        {
            btBitmap=CreateBitmap(imageweight,imageweight,1,32,NULL);
            obj = SelectObject(hdcimage, btBitmap);
        }
        BitBlt(hdcimage,0,0,imageweight,imageheight,cSource.hdcimage,0,0,SRCCOPY);
    }
    image& operator= (const image &cSource)
    {
        framecount=cSource.framecount;
        framedelay=cSource.framedelay;
        intSelectFrame=cSource.intSelectFrame;
        clrBackColor=cSource.clrBackColor;
        imageweight=cSource.imageweight;
        imageheight=cSource.imageheight;
        if(obj==NULL)
        {
            btBitmap=CreateBitmap(imageweight,imageweight,1,32,NULL);
            obj = SelectObject(hdcimage, btBitmap);
        }
        BitBlt(hdcimage,0,0,imageweight,imageheight,cSource.hdcimage,0,0,SRCCOPY);
        return *this;
    }

    property <int> SelectFrame
    {
        Get(int)
        {
            return intSelectFrame;
        },
        Set(int selectframe)
        {
            intSelectFrame=selectframe;
            UINT count = 0;
            count = img->GetFrameDimensionsCount();
            GUID* pDimensionIDs = (GUID*)malloc(sizeof(GUID)*count);
            img->GetFrameDimensionsList(pDimensionIDs, count);
            img->SelectActiveFrame(&pDimensionIDs[0],intSelectFrame);
            graphic=new Graphics(hdcimage);
            graphic->Clear(clrBackColor);
            graphic->DrawImage(img, 0, 0, img->GetWidth(), img->GetHeight());
            free(pDimensionIDs);
        }
    };

    property<int> FramesCount
    {
        Get(int)
        {
            return framecount;
        }
    };

    property<Gdiplus::Color> Backcolor
    {
        Get(Gdiplus::Color)
        {
            return clrBackColor;
        },
        Set(Gdiplus::Color bkcolor)
        {
            clrBackColor = bkcolor;
            SetDCBrushColor(hdcimage,clrBackColor.ToCOLORREF());
        }
    };

    void draw(HDC control)
    {


        //if (clrBackColor.GetValue() == Gdiplus::Color::Transparent)
        if (clrBackColor.GetValue()== Gdiplus::Color::Transparent)
        {
            TransparentBlt(control, 0, 0,width(),height(),hdcimage, 0, 0,width(), height(), GetPixel(hdcimage,width()-1,height()-1));
        }
        else
        {
            BitBlt(control,0,0,width(),height(),hdcimage,0,0,SRCCOPY);
        }

        //InvalidateRect(WindowFromDC(control),NULL,false);
    }

    operator HBITMAP()
    {
        return btBitmap;
    }

    int height()
    {
        return imageheight;
    }
    int width()
    {
        return imageweight;
    }

    operator HDC()
    {
        return hdcimage;
    }

    ~image()
    {
        delete img;
        Gdiplus::GdiplusShutdown(m_gdiplusToken);
        delete graphic;//memory leak too
        SelectObject(hdcimage, obj);
        DeleteObject(btBitmap);//don't show me the image
        DeleteDC(hdcimage);
    }
};

i'm confused with 1 thing: if the destructor is activated when the object class is destroyed, why the:

DeleteObject(btBitmap);

can affect on showing or not showing the image?

now i did:

~image()
    {
        Gdiplus::GdiplusShutdown(m_gdiplusToken);
        //delete graphic;//memory leak too
        //delete img;
        /*if(btBitmap!=NULL ||obj!=NULL)
        {
            SelectObject(hdcimage, obj);
            //DeleteObject(btBitmap);//don't show me the image
        }*/
        DeleteDC(hdcimage);
    }

and no memory leak. unless i return HBITMAP more than once. why?
(your solution helped me very much... thanks)

Edited 1 Year Ago by cambalinho

You ARE leaking even if you think you aren't. It might be very slight but by not deleting resources you allocate, you are indeed leaking them.

No matter what, you need to free any resource you allocated. I stated already that you need to check in your setters and getters that you do not overwrite memory allocated objects before freeing them. Something which you are still doing.

Also, you are invoking undefined behaviour by not doing the above.. Finally, your HBITMAP is deleted in the destructor so you need to make sure that your class is alive and well until you no longer need any of its resources.. This includes the HBITMAP. When your class dies, so does the HBITMAP.

a. You are using hdcImage without allocating it in your constructor.. How can you use it in the constructor or anywhere else, if it's NULL.

b. In your SelectFrame function, you are using img but you have no idea if img exists or not. Why? Because in your other constructors, img is never allocated. It's NULL or undefined. You only have one constructor that allocates img and your SelectFrame function will only be valid if that one constructor is used. All other constructors will cause your SelectFrame function to invoke undefined behaviour..

c. What I meant by freeing and allocating resources properly is an example of the following re-write of your class (which I did not test):

YourClass.h:

#ifndef AUTOGDI_H_INCLUDED
#define AUTOGDI_H_INCLUDED

#include <windows.h>
#include <gdiplus.h>

class AutoGDI
{
    private:
        ULONG_PTR m_gdiplusToken;
        Gdiplus::GdiplusStartupInput gdiplusStartupInput;

        HDC memDC;  //This will be allocated so we have to free it.
        HBITMAP hBmp;  //This will be allocated so we have to free it.
        int Width, Height;

        int FrameCount, FrameDelay;
        Gdiplus::Image* img;  //This MAY be allocated so we have to free it and check if it is allocated BEFORE using it..


    public:
        AutoGDI(HDC DC, int Width, int Height);
        AutoGDI(int Width, int Height);
        AutoGDI(const char* path);
        AutoGDI(const wchar_t* path);
        AutoGDI(const AutoGDI &other);
        ~AutoGDI();

        void SelectFrame(int Frame, DWORD ClearColour);
};

#endif // AUTOGDI_H_INCLUDED

YourClass.cpp:

#include "AutoGDI.h"

AutoGDI::~AutoGDI()
{
    DeleteDC(memDC);  //In every constructor, we create a DC.. we need to delete it!
    DeleteObject(hBmp); //In every constructor, we create an HBITMAP.. we need to delete it!

    delete img; //In ONE constructor we create an img.. Deleting a null pointer is DEFINED so it's perfectly fine not to bother checking here..
    Gdiplus::GdiplusShutdown(m_gdiplusToken);
}

AutoGDI::AutoGDI(const AutoGDI &other)
{
    Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

    img = NULL; //set Img to NULL by default.
    if (other.img) //only if img exists, may we copy it.
    {
        img = other.img->Clone();
    }

    Width = other.Width;
    Height = other.Height;
    FrameCount = other.FrameCount;
    FrameDelay = other.FrameDelay;

    HDC DC = GetDC(NULL);
    memDC = CreateCompatibleDC(DC);
    hBmp = CreateCompatibleBitmap(memDC, Width, Height);

    HGDIOBJ obj = SelectObject(memDC, hBmp);
    HGDIOBJ otherObj = SelectObject(other.memDC, other.hBmp);

    BitBlt(memDC, 0, 0, Width, Height, other.memDC, 0, 0, SRCCOPY);

    SelectObject(other.memDC, otherObj);
    SelectObject(memDC, obj);
    ReleaseDC(NULL, DC);
}

AutoGDI::AutoGDI(HDC DC, int Width, int Height)
{
    Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
    memDC = CreateCompatibleDC(DC);
    hBmp = CreateCompatibleBitmap(memDC, Width, Height);
    FrameCount = 1;
    FrameDelay = 0;
    img = NULL; //Set img to NULL by default.
}

AutoGDI::AutoGDI(int Width, int Height)
{
    Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

    HDC DC = GetDC(NULL);
    memDC = CreateCompatibleDC(DC);
    hBmp = CreateCompatibleBitmap(memDC, Width, Height);
    ReleaseDC(NULL, DC);
    FrameCount = 1;
    FrameDelay = 0;
    img = NULL;
}

AutoGDI::AutoGDI(const char* path)
{
    BITMAP bm;
    ICONINFO ii;
    HCURSOR hicon = (HCURSOR)LoadImage(NULL, path, IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE | LR_SHARED | LR_DEFAULTSIZE | LR_LOADTRANSPARENT);

    if (GetIconInfo(hicon, &ii))
    {
        if (GetObject(ii.hbmMask, sizeof(bm), &bm) == sizeof(bm))
        {
            Width = bm.bmWidth;
            Height = ii.hbmColor ? bm.bmHeight : bm.bmHeight / 2;

            HDC DC = GetDC(NULL);
            memDC = CreateCompatibleDC(DC);
            hBmp = CreateCompatibleBitmap(DC, Width, Height);
            HGDIOBJ obj = SelectObject(memDC, hBmp);
            DrawIconEx(memDC, 0, 0, hicon, Width, Height, 0, 0, DI_NORMAL);
            SelectObject(memDC, obj);
            ReleaseDC(NULL, DC);
        }

        DeleteObject(ii.hbmMask);
        DeleteObject(ii.hbmColor);
    }

    DestroyCursor(hicon);
    FrameCount = 1;
    FrameDelay = 0;
    img = NULL;
}

AutoGDI::AutoGDI(const wchar_t* path)
{
    img = new Gdiplus::Image(path); //read the image only ONCE..
    Width = img->GetWidth();
    Height = img->GetHeight();
    FrameCount = 1;
    FrameDelay = 0;

    HDC DC = GetDC(NULL);
    memDC = CreateCompatibleDC(DC);
    hBmp = CreateCompatibleBitmap(memDC, Width, Height);
    HGDIOBJ obj = SelectObject(memDC, hBmp);

    Gdiplus::Graphics(memDC).DrawImage(img, 0, 0, Width, Height);

    SelectObject(memDC, obj);
    ReleaseDC(NULL, DC);

    UINT count = img->GetFrameDimensionsCount();
    if (count > 0)
    {
        GUID* pDimensionIDs = (GUID*)malloc(sizeof(GUID) * count);

        img->GetFrameDimensionsList(pDimensionIDs, count);
        FrameCount = img->GetFrameCount(&pDimensionIDs[0]);
        FrameDelay = img->GetPropertyItemSize(PropertyTagFrameDelay);
        free(pDimensionIDs);
    }
}

void AutoGDI::SelectFrame(int Frame, DWORD ClearColour)
{
    if (img) //We can ONLY use this if `img != NULL!`
    {
        UINT count = img->GetFrameDimensionsCount();
        GUID* pDimensionIDs = (GUID*)malloc(sizeof(GUID) * count);

        img->GetFrameDimensionsList(pDimensionIDs, count);
        img->SelectActiveFrame(&pDimensionIDs[0], Frame);

        Gdiplus::Graphics g(memDC);
        g.Clear(ClearColour);

        g.DrawImage(img, 0, 0, Width, Height);
        free(pDimensionIDs);
    }
}

As you can see, anything we allocate, we must delete. Anything that "MAY" be allocated NEEDS to be checked before using it! If it is not allocated, you CANNOT use it at all.

In one of your constructors, I noticed that you were reading the image twice.. Why? You can just allocate the first image on the heap in the first place and store it. Why allocate on the stack first, then reallocate on the heap and store that? It makes sense to just allocate the image on the heap in one fell swoop and store that instead of reading the same image twice..

Notice that there is no need to store Graphics. Those are just cheap wrappers around the DC in your case. You can live without it. Either way, you are creating one every time you call SelectFrame. It will only be useful if you created it ONCE in one of the constructors and re-used that instance in SelectFrame. I don't see a reason to though.

SelectObject is cheap. You should not keep the object selected into the DC. As soon as you finish using it, Deselect the object.

Edited 1 Year Ago by triumphost

Comments
thank you

everytime we use the new keyword(on constructor) and if we need use it again, we must use the delete:

class image
{
private:
    ULONG_PTR m_gdiplusToken;
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    HDC hdcimage=CreateCompatibleDC(NULL);
    HGDIOBJ obj=NULL;
    HBITMAP btBitmap;
    Image *img;
    int imageheight=0;
    int imageweight=0;
    int framecount=0;
    int intSelectFrame=0;
    int framedelay=0;
    string strfilename="";
    Gdiplus::Color clrBackColor=Gdiplus::Color::Transparent;
    HDC hdcwindow;
    bool blnTransparent=true;

    HICON HICONFromHBITMAP(HBITMAP bitmap)
    {
        BITMAP bmp;
        GetObject(bitmap, sizeof(BITMAP), &bmp);
        HBITMAP hbmMask = CreateCompatibleBitmap(GetDC(NULL), bmp.bmWidth, bmp.bmHeight);

        ICONINFO ii = {0};
        ii.fIcon    = TRUE;
        ii.hbmColor = bitmap;
        ii.hbmMask  = hbmMask;

        HICON hIcon = CreateIconIndirect(&ii);
        DeleteObject(hbmMask);

        return hIcon;
    }

public:

    image()
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
        btBitmap=CreateCompatibleBitmap(hdcimage,1,1);
        obj = SelectObject(hdcimage, btBitmap);
    }

    image(HDC hdcWindow)
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
        hdcwindow=hdcWindow;
    }

    image(int width, int height)
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
        hdcimage = CreateCompatibleDC(NULL);
        btBitmap = CreateCompatibleBitmap(hdcimage,width,height);
        obj = SelectObject(hdcimage, btBitmap);
        framecount=1;
    }

    image( const string & filename)
    {
        strfilename=filename;
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
        if(toupper(filename[filename.size()-3])=='C' && toupper(filename[filename.size()-2])=='U' && toupper(filename[filename.size()-1])=='R')
        {
            //create the transparent icon handle
            HCURSOR hicon = (HCURSOR)LoadImage(NULL, filename.c_str(), IMAGE_CURSOR, imageweight, imageheight, LR_LOADFROMFILE|LR_SHARED|LR_DEFAULTSIZE|LR_LOADTRANSPARENT);
            ICONINFO ii;
            BOOL fResult = GetIconInfo(hicon, &ii);
            if (fResult)
            {
                BITMAP bm;
                fResult = GetObject(ii.hbmMask, sizeof(bm), &bm) == sizeof(bm);
                if (fResult)
                {
                    imageweight= bm.bmWidth;
                    imageheight= ii.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
                }
                if (ii.hbmMask) DeleteObject(ii.hbmMask);
                if (ii.hbmColor) DeleteObject(ii.hbmColor);
            }
            btBitmap=CreateBitmap(imageweight,imageheight,1,32,NULL);//create the bitmap with icon size
            obj = SelectObject(hdcimage, btBitmap);//add the bitmap to memory DC
            DrawIconEx(hdcimage,0,0,hicon,imageweight,imageheight,0,0,DI_NORMAL);//draw the icon to DC with right size
            //seems the DrawIcon(), always, draw it with 32X32 size
            framecount=1;
            DestroyCursor(hicon);
        }
        else
        {
            Gdiplus::Image img2(towstring(filename).c_str());
            btBitmap=CreateBitmap(img2.GetWidth(),img2.GetHeight(),1,32,NULL);
            obj = SelectObject(hdcimage, btBitmap);
            Gdiplus::Graphics graphics(hdcimage);
            graphics.DrawImage(&img2, 0, 0, img2.GetWidth(), img2.GetHeight());
            imageweight=img2.GetWidth();
            imageheight=img2.GetHeight();
            UINT count = 0;
            count = img2.GetFrameDimensionsCount();
            GUID* pDimensionIDs = (GUID*)malloc(sizeof(GUID)*count);
            img2.GetFrameDimensionsList(pDimensionIDs, count);
            framecount=img2.GetFrameCount(&pDimensionIDs[0]);
            if (framecount>1)
                framedelay =img2.GetPropertyItemSize(PropertyTagFrameDelay);
            else
                framedelay =0;
            img=new Image(towstring(filename).c_str());
            free(pDimensionIDs);
        }
    }

    image (const image &cSource)
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
        framecount=cSource.framecount;
        framedelay=cSource.framedelay;
        clrBackColor=cSource.clrBackColor;
        img=cSource.img->Clone();
        imageweight=cSource.imageweight;
        imageheight=cSource.imageheight;
        strfilename=cSource.strfilename;
        btBitmap=CreateBitmap(imageweight,imageweight,1,32,NULL);
        obj = SelectObject(hdcimage, btBitmap);
        BitBlt(hdcimage,0,0,imageweight,imageheight,cSource.hdcimage,0,0,SRCCOPY);
    }

    image& operator= (const image &cSource)
    {
        Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
        framecount=cSource.framecount;
        framedelay=cSource.framedelay;
        clrBackColor=cSource.clrBackColor;
        img=cSource.img->Clone();
        imageweight=cSource.imageweight;
        imageheight=cSource.imageheight;
        strfilename=cSource.strfilename;
        btBitmap=CreateBitmap(imageweight,imageweight,1,32,NULL);
        obj = SelectObject(hdcimage, btBitmap);
        BitBlt(hdcimage,0,0,imageweight,imageheight,cSource.hdcimage,0,0,SRCCOPY);
        return *this;
    }

    property <int> SelectFrame
    {
        Get(int)
        {
            return intSelectFrame;
        },
        Set(int selectframe)
        {
            intSelectFrame=selectframe;
            UINT count = 0;
            count = img->GetFrameDimensionsCount();
            GUID* pDimensionIDs = (GUID*)malloc(sizeof(GUID)*count);
            img->GetFrameDimensionsList(pDimensionIDs, count);
            img->SelectActiveFrame(&pDimensionIDs[0],intSelectFrame);
            Gdiplus::Graphics graphics(hdcimage);
            graphics.Clear(clrBackColor);
            graphics.DrawImage(img, 0, 0, img->GetWidth(), img->GetHeight());
            free(pDimensionIDs);
        }
    };

    property<int> FramesCount
    {
        Get(int)
        {
            return framecount;
        }
    };

    property<string> FileName
    {
        Get(string)
        {
            return strfilename;
        },
        Set(string filename)
        {
            delete img;
            DeleteObject(btBitmap);
            DeleteObject(obj);
            strfilename=filename;
            if(toupper(filename[filename.size()-3])=='C' && toupper(filename[filename.size()-2])=='U' && toupper(filename[filename.size()-1])=='R')
            {
                //create the transparent icon handle
                HCURSOR hicon = (HCURSOR)LoadImage(NULL, filename.c_str(), IMAGE_CURSOR, imageweight, imageheight, LR_LOADFROMFILE|LR_SHARED|LR_DEFAULTSIZE|LR_LOADTRANSPARENT);
                ICONINFO ii;
                BOOL fResult = GetIconInfo(hicon, &ii);
                if (fResult)
                {
                    BITMAP bm;
                    fResult = GetObject(ii.hbmMask, sizeof(bm), &bm) == sizeof(bm);
                    if (fResult)
                    {
                        imageweight= bm.bmWidth;
                        imageheight= ii.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
                    }
                    if (ii.hbmMask) DeleteObject(ii.hbmMask);
                    if (ii.hbmColor) DeleteObject(ii.hbmColor);
                }
                btBitmap=CreateBitmap(imageweight,imageheight,1,32,NULL);//create the bitmap with icon size
                obj = SelectObject(hdcimage, btBitmap);//add the bitmap to memory DC
                DrawIconEx(hdcimage,0,0,hicon,imageweight,imageheight,0,0,DI_NORMAL);//draw the icon to DC with right size
                //seems the DrawIcon(), always, draw it with 32X32 size
                framecount=1;
                DestroyCursor(hicon);
            }
            else
            {
                Gdiplus::Image img2(towstring(filename).c_str());
                btBitmap=CreateBitmap(img2.GetWidth(),img2.GetHeight(),1,32,NULL);
                obj = SelectObject(hdcimage, btBitmap);
                Gdiplus::Graphics graphics(hdcimage);
                ImageAttributes imAtt;
                imAtt.SetColorKey(
                    Color(0, 0, 0),
                    Color(100, 100, 100),
                    ColorAdjustTypeDefault);
                graphics.SetSmoothingMode(SmoothingModeAntiAlias);
                graphics.DrawImage(
                        &img2,
                        Rect(200, 300, img2.GetWidth(), img2.GetHeight()),  // dest rect
                        0, 0, img2.GetWidth(), img2.GetHeight(),          // source rect
                        UnitPixel,
                        &imAtt);
                //graphics.DrawImage(&img2, 0,0,img2.GetWidth(),img2.GetHeight());
                imageweight=img2.GetWidth();
                imageheight=img2.GetHeight();
                UINT count = 0;
                count = img2.GetFrameDimensionsCount();
                GUID* pDimensionIDs = (GUID*)malloc(sizeof(GUID)*count);
                img2.GetFrameDimensionsList(pDimensionIDs, count);
                framecount=img2.GetFrameCount(&pDimensionIDs[0]);
                framedelay =img2.GetPropertyItemSize(PropertyTagFrameDelay);
                img=new Image(towstring(filename).c_str());
                free(pDimensionIDs);
            }
        }
    };

    property<Gdiplus::Color> Backcolor
    {
        Get(Gdiplus::Color)
        {
            return clrBackColor;
        },
        Set(Gdiplus::Color bkcolor)
        {
            clrBackColor = bkcolor;
            SetDCBrushColor(hdcimage,clrBackColor.ToCOLORREF());
        }
    };

    void draw(HDC control)
    {
        //if (clrBackColor.GetValue() == Gdiplus::Color::Transparent)
        if (clrBackColor.GetValue()== Gdiplus::Color::Transparent)
        {
            TransparentBlt(control, 0, 0,width(),height(),hdcimage, 0, 0,width(), height(), GetPixel(hdcimage,width()-1,height()-1));
        }
        else
        {
            BitBlt(control,0,0,width(),height(),hdcimage,0,0,SRCCOPY);
        }
        //InvalidateRect(WindowFromDC(control),NULL,false);
    }

    operator HICON()
    {
        return HICONFromHBITMAP(btBitmap);
    }

    operator HBITMAP()
    {
        return btBitmap;
    }

    int height()
    {
        return imageheight;
    }

    int width()
    {
        return imageweight;
    }

    operator HDC()
    {
        return hdcimage;
    }

    ~image()
    {
        //delete btBitmap;
        //delete graphic; //memory leak, when i excute the aplication
        DeleteObject(obj);
        delete img;
        Gdiplus::GdiplusShutdown(m_gdiplusToken);
        //DeleteObject(btBitmap);//don't show me the image
        DeleteDC(hdcimage);
    }
};

maybe needs more work, but idon't get any memory leaks. thansk too all

Edited 1 Year Ago by cambalinho

This question has already been answered. Start a new discussion instead.