Programm mit modifiziertem aarot stürzt ab - vermutlich Speicherproblem.



  • Hi,

    ich versuche jetzt seit gut zwei Tagen mein Programm vom Abstürzen abzuhalten, es klappt aber leider nicht.

    In einem anderen Thread hat man mir diesen code (http://www.codeproject.com/bitmap/aarot.asp) zum rotieren von Bildern empfohlen.

    Den hab ich dann auch eingebaut und leicht modifizieren müssen. Ich will nämlich nicht ein Bild rotieren und in einer Ausgabedatei anzeigen lassen, sondern das Bild wird durchgehend anhand eingehender Gradzahlen rotiert. Damit dann immer wieder der Speicher freigegeben wird, hab ich den code ein wenig umgebaut, so dass ich die Objekte alle wieder löschen konnte.

    Jetzt funktioniert die Rotation einwandfrei, nur ist es so, dass das Programm irgendwann irgendwie irgendwo Speicher beschreibt, den es nicht beschreiben darf o.ä. Zumindest stürzt es dann ab.

    Wenn ich dann irgendetwas anderes mache, so dass der Speicher wieder anders belegt wird, funktioniert das Programm wieder, bis es eben wieder diesen Speicherfehler bekommt.

    Das Programm stellt die Position und "Blickrichtung" eines AUV auf einem Satellitenbild dar.

    Jetzt poste ich euch noch den Sourcecode.
    Zunächst die Rotationsroutinen:

    void aarot::dorotate(HBITMAP src, HBITMAP dstbmp, double rotation, aar_callback callbackfunc, int bgcolor, bool autoblend)
    {
        //Calculate some index values so that values can easily be looked up
        int indminx = ((int)rotation / 90 + 0) % 4;
        int indminy = (indminx + 1) % 4;
        int indmaxx = (indminx + 2) % 4;
        int indmaxy = (indminx + 3) % 4;
    
        //Load the source bitmaps information
        BITMAP srcbmp;
        if (GetObject(src, sizeof(srcbmp), &srcbmp) == 0)
    		return;
    
        //Calculate the sources x and y offset
        double srcxres = (double)srcbmp.bmWidth / 2.0;
        double srcyres = (double)srcbmp.bmHeight / 2.0;
    
        //Calculate the x and y offset of the rotated image (half the width and height of the rotated image)
        int mx[] = {-1, 1, 1, -1};
        int my[] = {-1, -1, 1, 1};
        double xres = mx[indmaxx] * srcxres * coss - my[indmaxx] * srcyres * sins;
        double yres = mx[indmaxy] * srcxres * sins + my[indmaxy] * srcyres * coss;
    
        //Get the width and height of the image
        int width = roundup(xres * 2);
        int height = roundup(yres * 2);
    
        //Create the source dib array and the destdib array
        RGBQUAD * srcdib = new RGBQUAD[srcbmp.bmWidth * srcbmp.bmHeight];
        aar_dblrgbquad * dbldstdib = new aar_dblrgbquad[width * height];
    	memset(dbldstdib, 0, width * height * sizeof(aar_dblrgbquad));
    
        //Load source bits into srcdib
        BITMAPINFO srcdibbmap;
        srcdibbmap.bmiHeader.biSize = sizeof(srcdibbmap.bmiHeader);
        srcdibbmap.bmiHeader.biWidth = srcbmp.bmWidth;
        srcdibbmap.bmiHeader.biHeight = -srcbmp.bmHeight;
        srcdibbmap.bmiHeader.biPlanes = 1;
        srcdibbmap.bmiHeader.biBitCount = 32;
        srcdibbmap.bmiHeader.biCompression = BI_RGB;
    
        HDC ldc = CreateCompatibleDC(0);
        GetDIBits(ldc, src, 0, srcbmp.bmHeight, srcdib, &srcdibbmap, DIB_RGB_COLORS);
        DeleteDC(ldc);
    
        aar_pnt * p = new aar_pnt[4];
        aar_pnt * poffset = new aar_pnt[4];
        aar_pnt c(0, 0);
    
        //Loop through the source's pixels
        double xtrans;
        double ytrans;
        for (int x = 0; x < srcbmp.bmWidth; x++)
        {
            for (int y = 0; y < srcbmp.bmHeight; y++)
            {
                //Construct the source pixel's rotated polygon
    
                xtrans = (double)x - srcxres;
                ytrans = (double)y - srcyres;
    
                p[0].x = xtrans * coss - ytrans * sins + xres;
                p[0].y = xtrans * sins + ytrans * coss + yres;
                p[1].x = (xtrans + 1.0) * coss - ytrans * sins + xres;
                p[1].y = (xtrans + 1.0) * sins + ytrans * coss + yres;
                p[2].x = (xtrans + 1.0) * coss - (ytrans + 1.0) * sins + xres;
                p[2].y = (xtrans + 1.0) * sins + (ytrans + 1.0) * coss + yres;
                p[3].x = xtrans * coss - (ytrans + 1.0) * sins + xres;
                p[3].y = xtrans * sins + (ytrans + 1.0) * coss + yres;
    
                //Caculate center of the polygon
                c.x = 0;
                c.y = 0;
                for (int i = 0; i < 4; i++)
                {
                    c.x += p[i].x / 4.0;
                    c.y += p[i].y / 4.0;
                }
    
                //Find the scan area on the destination's pixels
                int mindx = (int)p[indminx].x;
                int mindy = (int)p[indminy].y;
                int maxdx = roundup(p[indmaxx].x);
                int maxdy = roundup(p[indmaxy].y);
    
                int SrcIndex = x + y * srcbmp.bmWidth;
                //loop through the scan area to find where source(x, y) overlaps with the destination pixels
    
                for (int xx = mindx; xx < maxdx; xx++)
                {
                    for (int yy = mindy; yy < maxdy; yy++)
                    {
                        for (int i = 0; i < 4; i++)
                        {
                            poffset[i].x = p[i].x - xx;
                            poffset[i].y = p[i].y - yy;
                        }
    
                        //Calculate the area of the source's rotated pixel (polygon p) over the destinations pixel (xx, yy)
                        //The function actually calculates the area of poffset over the square (0,0)-(1,1)
                        double dbloverlap = pixoverlap(poffset, aar_pnt(c.x - xx, c.y - yy));
                        if (dbloverlap)
                        {
                            int DstIndex = xx + yy * width;
    
                            //Add the rgb and alpha values in proportion to the overlap area
                            dbldstdib[DstIndex].red += (double)(srcdib[SrcIndex].rgbRed) * dbloverlap;
                            dbldstdib[DstIndex].blue += (double)(srcdib[SrcIndex].rgbBlue) * dbloverlap;
                            dbldstdib[DstIndex].green += (double)(srcdib[SrcIndex].rgbGreen) * dbloverlap;
                            dbldstdib[DstIndex].alpha += dbloverlap;
                        }
                    }
                }
    
            }
            if (callbackfunc != NULL)
            {
                double percentdone = (double)(x + 1) / (double)(srcbmp.bmWidth);
                if (callbackfunc(percentdone))
                {
                    delete [] srcdib;
                    delete [] dbldstdib;
                    return;
                }
            }
        }
        delete [] p;
        delete [] poffset;
        delete [] srcdib;
    	srcdib = NULL;
    
        //Create final destination bits
        RGBQUAD * dstdib = new RGBQUAD[width * height];
    
        //load dstdib with information from dbldstdib
        RGBQUAD backcolor;
        backcolor.rgbRed = bgcolor & 0x000000FF;
        backcolor.rgbGreen = (bgcolor & 0x0000FF00) / 0x00000100;
        backcolor.rgbBlue = (bgcolor & 0x00FF0000) / 0x00010000;
        for (int i = 0; i < width * height; i++)
        {
            if (dbldstdib[i].alpha)
            {
                if (autoblend)
                {
                    dstdib[i].rgbReserved = 0;
                    dstdib[i].rgbRed = byterange(dbldstdib[i].red + (1 - dbldstdib[i].alpha) * (double)backcolor.rgbRed);
                    dstdib[i].rgbGreen = byterange(dbldstdib[i].green + (1 - dbldstdib[i].alpha) * (double)backcolor.rgbGreen);
                    dstdib[i].rgbBlue = byterange(dbldstdib[i].blue + (1 - dbldstdib[i].alpha) * (double)backcolor.rgbBlue);
                }
                else
                {
                    dstdib[i].rgbRed = byterange(dbldstdib[i].red / dbldstdib[i].alpha);
                    dstdib[i].rgbGreen = byterange(dbldstdib[i].green / dbldstdib[i].alpha);
                    dstdib[i].rgbBlue = byterange(dbldstdib[i].blue / dbldstdib[i].alpha);
                    dstdib[i].rgbReserved = byterange(255.0 * dbldstdib[i].alpha);
                }
            }
            else
            {
                //No color information
                dstdib[i].rgbRed = backcolor.rgbRed;
                dstdib[i].rgbGreen = backcolor.rgbGreen;
                dstdib[i].rgbBlue = backcolor.rgbBlue;
                dstdib[i].rgbReserved = 0;
            }
        }
    
        delete [] dbldstdib;
        dbldstdib = NULL;
    
        //Get Current Display Settings
        //DEVMODE screenmode;
        //screenmode.dmSize = sizeof(DEVMODE);
        //EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &screenmode);
    
        //Create the final bitmap object
        //HBITMAP dstbmp = CreateBitmap(width, height, 1, screenmode.dmBitsPerPel, NULL);
    
        //Write the bits into the bitmap and return it
        BITMAPINFO dstdibmap;
        dstdibmap.bmiHeader.biSize = sizeof(dstdibmap.bmiHeader);
        dstdibmap.bmiHeader.biWidth = width;
        dstdibmap.bmiHeader.biHeight = -height;
        dstdibmap.bmiHeader.biPlanes = 1;
        dstdibmap.bmiHeader.biBitCount = 32;
        dstdibmap.bmiHeader.biCompression = BI_RGB;
        SetDIBits(0, dstbmp, 0, height, dstdib, &dstdibmap, DIB_RGB_COLORS);
        //SetDIBits(0, src, 0, height, dstdib, &dstdibmap, DIB_RGB_COLORS);
    
        delete [] dstdib;
        dstdib = NULL;
    
    }
    
    void aarot::rotate(HBITMAP src, HBITMAP dstbmp, double rotation, aar_callback callbackfunc, int bgcolor, bool autoblend)
    {
    
        polyoverlap = new aar_pnt[16];
        polysorted = new aar_pnt[16];
        corners = new aar_pnt[4];
    
        double dx[] = {0.0, 1.0, 1.0, 0.0};
        double dy[] = {0.0, 0.0, 1.0, 1.0};
    
        for (int i = 0; i < 4; i++)
        {
            corners[i].x = dx[i];
            corners[i].y = dy[i];
        }
    
        //Get rotation between [0, 360)
    /*    int mult = (int)floor(rotation / 360.0);
        if (rotation >= 0)
            rotation = rotation - 360.0 * mult;
        else
            rotation = rotation - 360.0 * (mult - 1);
    */ 
        if (rotation < 0.0) rotation += 360.0;
    
        //Calculate the cos and sin values that will be used throughout the program
        coss = aar_cos(rotation);
        sins = aar_sin(rotation);    
    	dorotate(src, dstbmp, rotation, callbackfunc, bgcolor, autoblend);
    
        delete [] polyoverlap; polyoverlap = NULL;
        delete [] polysorted; polysorted = NULL;
        delete [] corners; corners = NULL;
    
        return;
    }
    

    Und jetzt der Aufruf der Funktion

    void CControlPanelDlg::PaintVehiclePointer(int x, int y) 
    {
    //repaint the vehicle pointer (else it will disappear when window is moved or covered)
    
    //repaint the xyz.bmp only if Vehicle Pointer was moved and Redraw is not 0.
    
    	int spur = 0;
    
    	if(spur !=1 && m_oldX != x || spur !=1 && m_oldY != y || spur != 1 && m_oldHeading != m_dHeadingFromAUV || spur == 1 && m_dSpeedFromAUV == 0) PaintBaggersee(); 
    
    	CString szFilename("res\\arrow_white.bmp");
    
    	HBITMAP hsrcbmp = (HBITMAP)LoadImage(NULL, szFilename, IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
    
    	int width = 10;
    	int height = 10;
    	aarot::GetSize(&width, &height, hsrcbmp, -m_dHeadingFromAUV);
    
    	//Get Current Display Settings
        DEVMODE screenmode;
        screenmode.dmSize = sizeof(DEVMODE);
        EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &screenmode);
    
    	HBITMAP dstbmp = CreateBitmap(width, height, 1, screenmode.dmBitsPerPel, NULL);
    
    	aarot::rotate(hsrcbmp, dstbmp, -m_dHeadingFromAUV, NULL, 0xFFFFFF, false);
    
    	CBitmap bmp;
    
    	bmp.Attach(dstbmp);
    	//bmp.Attach(hsrcbmp);
    
    	CClientDC dc(this);
    	CDC bmDC;
    	bmDC.CreateCompatibleDC(&dc);
    	CBitmap *pOldbmp = bmDC.SelectObject(&bmp);
    
    	BITMAP  bi;
    	bmp.GetBitmap(&bi);
    
    	dc.BitBlt(x,y,bi.bmWidth,bi.bmHeight,&bmDC,0,0,MERGEPAINT); 	
    
    	m_oldX = x;
    	m_oldY = y;
    
    	bmDC.SelectObject(pOldbmp);
    
    	DeleteObject(dstbmp);
    	bmDC.DeleteDC();
    }
    

    Und jetzt noch die Fehlermeldung. Ich kann den Screenshot grad nirgends hochladen 😕 Daher tipp ich euch die Meldung ab:

    Die Ausnahme "unknown software exception" (0x80000003) ist in der Anwendung an der Stelle 0x7c911230 aufgetreten.

    Klicken Sie auf OK, um das Programm zu beenden.
    Klicken Sie auf Abbrechen, um das Programm zu debuggen.

    Ich vermute, dass der Fehler in der rotate-Funktion liegt. Denn wenn ich anstatt
    bmp.Attach(dstbmp); <- das kommt aus der rotate-Funktion zurück

    bmp.Attach(hsrcbmp); <- die Ausgangs-BMP

    verwende, funktionierts.

    Ich weiß, dass das recht umfangreich ist. Und ich erwarte auch fast gar nicht, dass sich jemand die Mühe macht, sich da komplett einzulesen und versucht zu verstehen, wo das Problem liegt.

    Aber vielleicht hat ja doch jemand die Motivation 🙂 N Versuch kann nicht schaden. Ich wäre auf jeden Fall höchst dankbar!

    Gruß & vielen Dank

    meph



  • Klar, wenn du ein Handle weiterverarbeitest, nachdem du es gelöscht hast, kann das nur in die Hose gehen - und nach dem Aufruf "DeleteObject(dstbmp);" ist dein Handle gelöscht.

    (und afaik ruft der Dtor von CBitmap ebenfalls DeleteObject() auf, um "sein" Handle freizugeben)



  • Ok, deiner Meinung nach soll ich das also nicht löschen?!

    Wenn ich das auskommentier, stürzt das Programm genauso ab...

    Zudem, haben wir genau deswegen die Funktion umgebaut. Denn in der Ausgangsfassung war es so, dass die Rotationsfunktion immer mehr Speicher belegt hat, wodurch das Programm nach einiger Zeit ebenfalls abgestürzt ist.

    Danke zunächst!



  • Klar solltest du deinen Speicher korrekt wieder freigeben - aber bei der Arbeit mit Handle's und Pointern kann es zu schnell passieren, daß du dich da verknotest.

    (persönlicher Tip von mir: ändere das ganze Programm so, daß du mit CBitmap's arbeitest)



  • Uff, da hab ich leider Null Plan von. 😕

    Ich hab das Programm hier bisher nur ergänzt und verändert.

    Ich brauch ne C++ Schulung 😞



  • Okay, anders.

    Ich hab den Rotationscode jetzt so gelassen, wie er ursprünglich war.

    Aufgerufen wird das Ganze jetzt einfach so:

    CString szFilename("res\\arrow_white.bmp");
    
    	HBITMAP hsrcbmp = (HBITMAP)LoadImage(NULL, szFilename, IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE);
    
    	CBitmap bmp;
    
    	HBITMAP dstbmp = aarot::rotate(hsrcbmp, -m_dHeadingFromAUV, NULL, 0xFFFFFF, false);
    
    	bmp.Attach(dstbmp);
    	//bmp.Attach(hsrcbmp);
    
    	CClientDC dc(this);
    	CDC bmDC;
    	bmDC.CreateCompatibleDC(&dc);
    	CBitmap *pOldbmp = bmDC.SelectObject(&bmp);
    
    	BITMAP  bi;
    	bmp.GetBitmap(&bi);
    
    	dc.BitBlt(x,y,bi.bmWidth,bi.bmHeight,&bmDC,0,0,MERGEPAINT); 	
    
    	m_oldX = x;
    	m_oldY = y;
    
    	bmDC.SelectObject(pOldbmp);
    

    Jetzt ist es aber - wie bereits oben erwähnt - so, dass langsam immer mehr Speicher belegt wird. Der zählt in 4K Schritten hoch. Und irgendwann - manchmal erst nach ner halben Stunde - ist Feierabend und das Programm stürzt ab, was natürlich nicht sein darf. Wenn man son AUV vorführt und irgendwann bestimmte Leute nicht mehr sehen, wo das Fahrzeug ist, kommt das n bisschen schlecht.

    Hat irgendwer ne einfache Lösung für dieses Speicherproblem?

    Irgendwas, wo ich nicht das ganze Rad neu erfinden muss? Weil dafür hab ich definitiv zu wenig Ahnung von C++

    Soll ich den Code der Rotationsfunktionen nochmal posten, wie er jetzt aussieht?

    Danke & Gruß
    meph


Anmelden zum Antworten