Avatar billede tax Nybegynder
14. januar 2002 - 17:07 Der er 16 kommentarer og
1 løsning

GDI går ned.

Jeg arbejder på en simulator som optegner med windows GDI.

Jeg oplever at den går ned for næsen af mig, og min optegning med windows \"penne\" går i stå.

Jeg tegner i et bitmap i hukommelsen og \"blitter\" dette ned til mit clientarea. med jævne mellemrum.

Det er optegningen i bitmappet der går ned.

Jeg gør således:


//hdcB = hdc for den bitmap jeg tegner i.

LOGBRUSH lb;
lb.lbStyle = BS_SOLID;
lb.lbColor = reagents[contents->getVal(tempindex)].Color;
lb.lbHatch = 0;   

DeleteObject(SelectObject(WsObject::hdcB, ExtCreatePen(PS_ENDCAP_ROUND |PS_SOLID | PS_GEOMETRIC  , 1, &lb, 0, NULL)));

MoveToEx(WsObject::hdcB, pos1.x, pos1.y, NULL);
LineTo(WsObject::hdcB, pos2.x, pos2.y);
EndPath(WsObject::hdcB);
StrokePath(WsObject::hdcB);                                   

DeleteObject(SelectObject(WsObject::hdcB,GetStockObject(BLACK_BRUSH)));


Det hele fungerer fint i ca 2-3 minutter, og så stopper optegningen bare. Resten af proggy går ikke ned.
Avatar billede tax Nybegynder
14. januar 2002 - 17:12 #1
Jeg optegner også med setpixel, og denne optegningsfunktionalitet i bitmappet går heller ikke ned.
Avatar billede jpk Nybegynder
15. januar 2002 - 08:34 #2
Er det en indtastningsfejl at du kalder DeleteObject i linien:
DeleteObject(SelectObject(WsObject::hdcB, ExtCreatePen(PS_ENDCAP_ROUND |PS_SOLID | PS_GEOMETRIC  , 1, &lb, 0, NULL)));?

Bruger du ikke MFC længere?
Avatar billede tax Nybegynder
15. januar 2002 - 10:07 #3
JPK: Hvad mener du?
Avatar billede jpk Nybegynder
15. januar 2002 - 10:13 #4
Jeg tænkte bare på om det var et andet objekt du selv har oprettet og som du senere \"selecter\" igen.
I så fald skal det jo ikke slettes...

Avatar billede tax Nybegynder
15. januar 2002 - 10:42 #5
Jeg kører et sæt klasser hvor deres optegningsrutiner ligger i selve klasserne. de har så en moderklasse, som indeholder et bitmap. Optegningen foregår så ved at jeg ved moderklassens initalisering opretter og selecter et bitmap i min device context.

Hvergang jeg tegner sletter jeg den gamle pen.
Avatar billede jpk Nybegynder
15. januar 2002 - 10:46 #6
Symptomerne tyder på at du har noget device memory  du ikke får frigivet.
Har du prøvet at debugge og så afslutte programmet efter lidt tid, måske du så kan se noget memory cleanup i outputtet?

Avatar billede tax Nybegynder
15. januar 2002 - 12:37 #7
Jeg har et helt rent output.

The thread 0x1E74 has exited with code 0 (0x0).
model thread ended.
The thread 0x1E00 has exited with code 0 (0x0).
comCon thread ended.
The thread 0x1ECC has exited with code 0 (0x0).
Receive error: -1 - going offline
comRecv thread ended.
The thread 0x13B0 has exited with code 0 (0x0).
comMonitor thread ended.
The thread 0x1EE4 has exited with code 0 (0x0).
The thread 0x1EDC has exited with code 0 (0x0).
The thread 0x1E90 has exited with code 0 (0x0).
The program \'E:\\AU\\AUHWSIM\\Debug\\AUHWSIM.exe\' has exited with code 0 (0x0).

Er der evt. en mulighed for at detektere andre fejl, som skal slås til i debuggeren?
Avatar billede jpk Nybegynder
15. januar 2002 - 12:47 #8
Kan du ikke vise noget mere kode?

Avatar billede tax Nybegynder
15. januar 2002 - 13:32 #9
Jeg starter med at oprette en tråd der kører min simulator. Den opretter et netværk af komponenter som er realiseret igennem en familie af klasser. Moderklassen indeholder statiske 2 bitmaps. Det første bitmap (baggrunden) tegner jeg de statiske elementer op i og gemmer. Det andet bitmap (forgrunden) kopierer jeg baggrunden over i og optegner de dynamiske dele. Når dette er gjort blitter jeg billedet ud i mit clientarea.

Alle mine komponenter er nedarvet fra moderklassen og har derfor adgang til at tegne i de to bitmaps.

Modelleringstråden har adgang til clientareaet igennem et HWND, som jeg gemmer i en struct som er delt imellem hovedprogrammet og modelleringstråden.

Moderklassen:

class WsObject
{
protected:       
    char*    szName;            //Name of object
    bool    invisible;        //Flag to indicate if component should be drawn
   
    static unsigned long deltaT; //Milliseconds between each sample
   
   
    static PCOMMONDATA pdata;
    static HBITMAP hForeground;
    static HDC hdcF;   
    static HBITMAP hBackground;        //Bitmaps representing foreground and background
    static HDC hdcB;                // Device contexts for foreground and background
    WsObject();                        //constructor
   
public:

    static BYTE lsstates[LS_SIZE];

    int    TYPE;

    static bool    recalculate;

    static  vector <WsObject*> allWsObjects; //List of all objects   
   
    static long  getDeltaT();   
    static void  setDeltaT(long ms);
    static HDC      getHDC();
    static void init(HDC h, PCOMMONDATA p);
    static void backToFront();
    static PCOMMONDATA pdat;

    static void reply(int action, int id, int d0, int d1);

    void  connect(WsObject* other);   
    char* getName();
    void  setInvisible(bool v);
   

    vector <WsObject*> connections;
   
    //Command model to do something   
    static void command(int ACT, int ID, int D0, int D1);
    static void command(MsgFrame m);
    virtual void    modelCommand(MsgFrame command)=0;

    //Drawrelated
    virtual Vector getDrawPosition(WsObject* from)=0;

    //Flowcalc related
    virtual void    sendFlow(WsObject* from, double f, WsObject* initiator)=0;
    virtual double    getControlled(WsObject* from, WsObject* initiator)=0;
    virtual double    getResOut(WsObject* from)=0;
    virtual double    getCurrent(WsObject* from)=0;
   
    ~WsObject();

    //Move microliters
    virtual void    pushUL(WsObject* from, int type, int recursioncount)=0;
};

Eksempel på komponent:

class WsTube : public WsObject    //Tube class
{
private:
   
    void            cloneContent();

protected:
    ringbuf*        contents;
    int*            olddraw;
    double            flow;            //Current flow in pipe form connection 0 to 1
    int                iVolume;        //Volume of tube in uL
    double            lResistance;        //Flowresistance of tube   

public:
    WsTube();
    WsTube(char* n, int vol, long res);
    ~WsTube();

    Vector getDrawPosition(WsObject* from);       

    void    sendFlow(WsObject* from, double f, WsObject* initiator);
    double    getControlled(WsObject* from, WsObject* initiator);
    double    getResOut(WsObject* from);
    double    getCurrent(WsObject* from);
   
    virtual void    pushUL(WsObject* from, int type, int recursioncount);

    virtual void    modelCommand(MsgFrame command);

    int insert(int end, int val);

};

Når jeg starter modelleringstråden op starter jeg med at initalisere de to bitmaps i hukommelsen:

// Initializastion of NetObj.
void WsObject::init(HDC h,  PCOMMONDATA p)
{
    hdcB = CreateCompatibleDC(h);
    hdcF = CreateCompatibleDC(h);   

    pdat = p;
   
    hBackground = CreateCompatibleBitmap(hdcB, 800, 600);
    hForeground = CreateCompatibleBitmap(hdcF, 800, 600);       

    //Klargør bitmaps
   
    WsObject::hBackground = (HBITMAP)LoadImage(0, \"./backgnd.bmp\", IMAGE_BITMAP, 800,600,  LR_VGACOLOR | LR_LOADFROMFILE);
    WsObject::hForeground = (HBITMAP)LoadImage(0, \"./backgnd.bmp\", IMAGE_BITMAP, 800,600,  LR_VGACOLOR | LR_LOADFROMFILE);
   
    //Its easyer to load twice and garanty compatibility :)
    SelectObject(WsObject::hdcB, WsObject::hBackground);
    SelectObject(WsObject::hdcF, WsObject::hForeground);

    deltaT = 1; //Milliseconds
    bool recalculate = true;
}

Optegningen foregår igennem beskeder jeg sender til komponenterne igennem modelCommand():

void    WsTube::modelCommand(MsgFrame command)
{
    switch(command.ACT)
    {
    case DRAW_STATIC:
        {
        if (invisible)break;
        Vector a = connections[0]->getDrawPosition(this);
        Vector b = connections[1]->getDrawPosition(this);
   
       
        DeleteObject(SelectObject(WsObject::hdcB, CreatePen(PS_SOLID, 9, 0)));

        BeginPath(WsObject::hdcB);
        MoveToEx(WsObject::hdcB, a.x, a.y, NULL);
        LineTo(WsObject::hdcB, b.x, b.y);
        EndPath(WsObject::hdcB);
        StrokePath(WsObject::hdcB);   
       


       
        }
        break;

    case DRAW_DYNAMIC_BACK:
        {
            if (invisible)break;
            Vector a = connections[0]->getDrawPosition(this);
            Vector b = connections[1]->getDrawPosition(this);                       
            Vector c = (b-a)/(iVolume+1);

            Vector angle = c.unit().cross();           
            Vector pos;
                                                                   
            int tempindex = contents->getIndex();
           
           
           
           
            for(int x = 0; x<iVolume; x++)
            {                   
                tempindex++;
                if (tempindex > iVolume)
                    tempindex = 0;
               
                if (olddraw[x]!=contents->getVal(tempindex))
                {                                                                           
                   
           
                    DeleteObject(SelectObject(WsObject::hdcB, CreatePen(PS_SOLID, 1, reagents[contents->getVal(tempindex)].Color)));
                   
                    pos = a+c*(x+1)-angle*2;
                   
                    BeginPath(WsObject::hdcB);
                    MoveToEx(WsObject::hdcB, pos.x, pos.y, NULL);
                   
                    pos = a+c*(x+1)+angle*3;

                    LineTo(WsObject::hdcB, pos.x, pos.y);
                    EndPath(WsObject::hdcB);
                    StrokePath(WsObject::hdcB);                                   
                    olddraw[x]=contents->getVal(tempindex);

                   
                }   
               
            }       
           
           
        }
        break;
    case VERIFY_NET:
        if (connections.size()!=2)
            TRACE(\"%s connected wrong %d connections (OK=2)\\n\",szName, connections.size());       
        break;
    case RESET_FLOW:
        flow = 0;
        break;
    case DRAW_DATA:
        {
            if (invisible)break;
            Vector a, b;
           
            a = connections[1]->getDrawPosition(this);
            b = connections[0]->getDrawPosition(this);
                       
            if((a-b).len()>18)
            {
               
            Vector pos = a + ((b - a)/2);
            char tmp[100];
            int size = sprintf(tmp,\"%.1f\", flow);
            DeleteObject(SelectObject(WsObject::hdcB, GetStockObject(BLACK_BRUSH)));
            TextOut(WsObject::hdcF, pos.x , pos.y, tmp, size);
           
            }
        }
        break;
    default:
        break;
    };
}

Optegningen foregår på samme måde i alle komponenterne.

Den tråd som opretter klasserne og kører selve simulaerineg ser således ud:


void modThread(PVOID pvoid)
{
    unsigned long progress; //Milliseconds passed   

    PCOMMONDATA pdata = (PCOMMONDATA)pvoid;
    pdata->threadModelActive = true;

    TRACE(\"Modelthread startup.\\n\");

    //Communication variables
    MsgFrame buffer;


    WsObject::init(GetDC(pdata->hWnd), pdata);

    //Simplified ABL735!!!
    WsUserInlet        Inlet(\"Inlet\", Vector(100,150),-90);
    WsTube            InletTube(\"InletTube\", 150, 150);
    WsJunction        InletPhBgJunc(\"InletPhBg\", Vector(100, 300));
    WsTube            PHBGTube(\"InletTube\", 150, 150);
    WsUserPhBg        PhBg(\"PhBg\", Vector(250,300),0);
    WsTube            PHBGELMETTube(\"PHBGELMETTube\", 90, 90);
    WsUserElMet        ElMet(\"EM\", Vector(400,300),0);
    WsTube            ElMetOxi(\"InletTube\", 141, 141);
    WsUserOxi        Oximodule(\"Oximodule\",    Vector(601,300), 0);
    WsTube            OxiPump(\"OxiPump\", 21, 21);
    WsUserPump        ReagentPump(\"Reagentpump\",PU_REAGENT,Vector(700,300),90 );
    WsUserManifold    Manifold(\"Manifold\", Vector(700,350), 180);
    Inlet.connect(&InletTube);
    InletTube.connect(&InletPhBgJunc);
    InletPhBgJunc.connect(&PHBGTube);
    PHBGTube.connect(&PhBg);
    PhBg.connect(&PHBGELMETTube);
    PHBGELMETTube.connect(&ElMet);
    ElMet.connect(&ElMetOxi);
    ElMetOxi.connect(&Oximodule);
    Oximodule.connect(&OxiPump);
    OxiPump.connect(&ReagentPump);
    ReagentPump.connect(&Manifold);
   
    //Verify connections!!!
    WsObject::command(VERIFY_NET,0,0,0);

    TRACE(\"Network consist of %d individual objects.\\n\", WsObject::allWsObjects.size());

    WsObject::command(RESET_FLOW,0,0,0);

   
    WsObject::command(DRAW_STATIC,0,0,0);
    WsObject::command(DRAW_DYNAMIC_BACK,0,0,0);
    //Prepare image in WsObject
    WsObject::backToFront();
    WsObject::command(DRAW_DYNAMIC,0,0,0);
    //BitBlt(hdc, 0, 0, 800, 600, WsObject::getHDC(), 0, 0, SRCCOPY);           
   
    PAINTSTRUCT ps;
   
    BeginPaint(pdata->hWnd, &ps);       

   

    progress = timeGetTime();
    while(pdata->Keepgoing)
    {
        //Adcust simulation to realtime
        WsObject::setDeltaT((timeGetTime() - progress));
        progress = timeGetTime(); //save time
        pdata->copyOfDeltaT = WsObject::getDeltaT();

        //We dont want to calculate flow every time (Its hard work!!!)
        if (WsObject::recalculate)
        {   
            WsObject::command(RESET_FLOW,0,0,0);
            WsObject::command(CALCULATE_FLOW,0,0,0);           
            WsObject::recalculate = false;
        }       
        //Move reagents
        WsObject::command(PUSH_UL,0,0,0);
        //Check LsSensors
        WsObject::command(CHECK_COMPONENT_STATE,0,0,0);
        //Draw fluids
        WsObject::command(DRAW_DYNAMIC_BACK,0,0,0);
        //BitBlt to foreground
        WsObject::backToFront();
        //Draw dynamic elements, valves pumps, etc.
        WsObject::command(DRAW_DYNAMIC,0,0,0);
       
        //Perhaps draw flowinformation (For debug)
        //Object::command(DRAW_DATA,0,0,0);   

        if (pdata->updateClientArea ==true)
        {
            HDC hdc = GetDC(pdata->hWnd);
            //Fetch model image
            if (hdc != NULL)
                BitBlt(hdc, 0, 0, 800, 600, WsObject::getHDC(), 0, 0, SRCCOPY);           
            else
                TRACE(\"HDC-ERROR\");
            ReleaseDC(pdata->hWnd, hdc);       
        }
        //Check for messages
       
        //Must accept at many messages as possible before calculation of flow
        //The calculation is very heavy on CPU
        while(pdata->inbox.size() > 0)
        {                                   
            memcpy((char*)&buffer, &pdata->inbox.front(), sizeof(MsgFrame));
            pdata->inbox.pop_front(); //Take message out of queue
            WsObject::command(buffer);           
        }       
       
        Sleep(100);//Give OS a break       

    }                   
    pdata->threadModelActive = false;


    //EndPaint(pdata->hWnd , &ps);   
    TRACE(\"model thread ended.\\n\");
}


Det er en stor mundfuld, men jeg sætter pris på enhver hjælp. Det er den sidste bug jeg har i mit eksamensprojekt på diplomingeniøruddannelsen.

/TAX
Avatar billede jpk Nybegynder
15. januar 2002 - 13:59 #10
Tja, det kan være en pestilens at finde fejl når det omhandler resources, men jeg ville da starte med at udkommentere dele af koden, for at se hvor problemet opstår.
Altså, du kunne måle hvor lang tid der går inden problem opstår, så prøve at fjerne noget kode.

fx
/*
      if (pdata->updateClientArea ==true)
        {
            HDC hdc = GetDC(pdata->hWnd);
            //Fetch model image
            if (hdc != NULL)
                BitBlt(hdc, 0, 0, 800, 600, WsObject::getHDC(), 0, 0, SRCCOPY);           
            else
                TRACE(\"HDC-ERROR\");
            ReleaseDC(pdata->hWnd, hdc);       
        }
*/

Og så køre programmet igen.
Hvis problemet udebliver (eller først opstår efter længere tid) har du måske fundet synderen!

Avatar billede tax Nybegynder
15. januar 2002 - 14:21 #11
Jeg har opdaget at fejlen ikke altid forekommer når jeg lader, den forekommer mange gange når jeg flytter vinduer over mit vindue.
(Mit vindue er sat til at være 800*600 fast). Jeg tror at en af de ting der går galt er at jeg bitblt\'er mit billede ind i mit clientarea, når det er overlappet og derved får en fejl.

Hvilke WM_??? modtager man når vinduet minimeres, overlappes mm.??
Avatar billede tax Nybegynder
15. januar 2002 - 14:23 #12
Kan man evt checkke sin HDC om den er iorden før man blitter?
Avatar billede jpk Nybegynder
15. januar 2002 - 14:31 #13
Hvis du vil tjekke om et vindue er minimeret, kan du bruge IsIconic...

Avatar billede tax Nybegynder
16. januar 2002 - 17:33 #14
Jeg fandt fejlen endelig. Det viste sig at jeg havde en leak i min windows messagehandler for hovedvinduet. Jeg lavede en getDC uden at returnere den. Det æder ca 200kb hukommelse pr sekund. Nu er det stabilt og jeg er glad.

Avatar billede wisen Nybegynder
30. januar 2002 - 12:32 #15
Lukker du spg. så ?
Avatar billede jpk Nybegynder
03. april 2002 - 13:58 #16
Ja, du skulle nok lukke spørgsmålet...
Avatar billede tax Nybegynder
03. maj 2002 - 11:18 #17
no ans
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester