Toon posts:

[Win32] WM_PAINT - Na 20min wordt niets meer getekend

Pagina: 1
Acties:

Verwijderd

Topicstarter
Voor een project dat 3 motoren op een CANbus aanstuurt moest ik nog een visualisatie maken, ik heb alles geschreven in MS Visual Studio 6. Alles gebeurd met API calls, en er is geen ATL, WTL of MFC etc. gebruikt. Nu had ik lang geleden wel eens wat grafische dingen geprogged in C, en heb me daarop nu terug gebasseerd. Ik kan echter mijn Win32 API Programming book van Charles Petzold niet terugvinden, en kan de fout zo meteen niet vinden. Ook niet na msdn over device contexts door te lezen..

De software is volledig af en werkte perfect, tot we het een nacht door lieten draaien. Alle functionaliteit blijft, enkel wordt er niets meer geupdate op het scherm, en uiteindelijk wordt het window gewoon zwart.
Door super veel commando's naar de liften te sturen, wat veel InvalidateRect's tot gevolg heeft, treed het probleem al op na 20min.

Hier volgt de WM_PAINT msg handler en andere relevante code, ik hoop dat iemand hier me kan vertellen wat ik verkeerd doe..

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// global vars
HBITMAP         hImgBack;                               // Background Image Handle
HBITMAP         hImgLiftRed;                            // Red Lift Image Handle
HBITMAP         hImgLiftGreen;                          // Green Lift Image Handle


...
...

// Application Entry Point
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
    if (!LoadConfig())
    {
        MessageBox(NULL, _T("Error reading configuration from registry."), _T("Config Error"), MB_OK);
        return FALSE;
    }

    if (!Comm_Init())
        return FALSE;

    if (!Can_Init())
        return FALSE;

    // Init Lifts
    Lifts_Init();
    
    // Set screen resolution to 800x600
    DEVMODE dvmd;
    EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dvmd);
    devModeDefault = dvmd;                      // Save original devmode
    dvmd.dmPelsWidth = 800;
    dvmd.dmPelsHeight = 600;
    dvmd.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
    ChangeDisplaySettings(&dvmd, 0);

    // Load Bitmaps
    hImgBack = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_BACK));
    hImgLiftRed = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_LIFTRED));
    hImgLiftGreen = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP_LIFTGREEN));

...
...

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc, hdcMap;
    HPEN hpSolid, hpOld;
    HFONT hfnt, hfntPrev; 
    HGDIOBJ hgdi;
    PLOGFONT plf;
    RECT rt;

    switch (message) 
    {
    ...
        ...
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);

            // Fill background with black
            GetClientRect(hWnd, &rt);
            FillRect(hdc, &rt, (HBRUSH)GetStockObject(BLACK_BRUSH));

            // Draw Background Bitmap
            hdcMap = CreateCompatibleDC(hdc);
            hgdi = SelectObject(hdcMap,hImgBack);
            BitBlt(hdc, 0,0,800,600,hdcMap,0,0,SRCCOPY);
            SelectObject(hdcMap,hgdi);
            //ReleaseDC(hWnd, hdcMap);
            
            // Draw Left Lift
            //hdcMap = CreateCompatibleDC(hdc);
            hgdi = SelectObject(hdcMap,(Lift[LIFT_LEFT].Status<2)?hImgLiftRed:hImgLiftGreen);
            if (!(((Lift[LIFT_LEFT].Status==LIFT_STAT_MOVING)||(Lift[LIFT_LEFT].Status==LIFT_STAT_HOMERUN))&&(bBlink)))
                    BitBlt(hdc, Lift[LIFT_LEFT].xpos, LIFT_LEFT_YPOS,43,32, hdcMap,0,0,SRCCOPY);
            SelectObject(hdcMap,hgdi);
            //ReleaseDC(hWnd, hdcMap);

            // Draw Middle Lift
            //hdcMap = CreateCompatibleDC(hdc);
            hgdi = SelectObject(hdcMap,(Lift[LIFT_MIDDLE].Status<2)?hImgLiftRed:hImgLiftGreen);
                if (!(((Lift[LIFT_MIDDLE].Status==LIFT_STAT_MOVING)||(Lift[LIFT_MIDDLE].Status==LIFT_STAT_HOMERUN))&&(bBlink)))
                    BitBlt(hdc, Lift[LIFT_MIDDLE].xpos,LIFT_MIDDLE_YPOS,43,32, hdcMap,0,0,SRCCOPY);
            SelectObject(hdcMap,hgdi);
            //ReleaseDC(hWnd, hdcMap);

            // Draw Right Lift
            //hdcMap = CreateCompatibleDC(hdc);
            hgdi = SelectObject(hdcMap,(Lift[LIFT_RIGHT].Status<2)?hImgLiftRed:hImgLiftGreen);
                if (!(((Lift[LIFT_RIGHT].Status==LIFT_STAT_MOVING)||(Lift[LIFT_RIGHT].Status==LIFT_STAT_HOMERUN))&&(bBlink)))
                    BitBlt(hdc, Lift[LIFT_RIGHT].xpos,LIFT_RIGHT_YPOS,43,32, hdcMap,0,0,SRCCOPY);
            SelectObject(hdcMap,hgdi);
            ReleaseDC(hWnd, hdcMap);
            
            
            // Draw Left CAN Bus
            hpSolid = (HPEN)CreatePen(PS_SOLID, 1, (Lift[LIFT_LEFT].Status==LIFT_STAT_OFFLINE)?crRed:crGreen);
            hpOld = (HPEN)SelectObject(hdc, hpSolid);
            Polyline(hdc, ptLeftCanBus, 4);
            SelectObject(hdc, hpOld);
            DeleteObject((HPEN)hpSolid);

            // Draw Middle CAN Bus
            hpSolid = (HPEN)CreatePen(PS_SOLID, 1, (Lift[LIFT_MIDDLE].Status==LIFT_STAT_OFFLINE)?crRed:crGreen);
            hpOld = (HPEN)SelectObject(hdc, hpSolid);
            Polyline(hdc, ptMiddleCanBus, 2);
            SelectObject(hdc, hpOld);
            DeleteObject((HPEN)hpSolid);

            // Draw Right CAN Bus
            hpSolid = (HPEN)CreatePen(PS_SOLID, 1, (Lift[LIFT_RIGHT].Status==LIFT_STAT_OFFLINE)?crRed:crGreen);
            hpOld = (HPEN)SelectObject(hdc, hpSolid);
            Polyline(hdc, ptRightCanBus, 4);
            SelectObject(hdc, hpOld);
            DeleteObject((HPEN)hpSolid);

            // (Re-)Draw Top-Line of Control unit
            hpSolid = (HPEN)CreatePen(PS_SOLID, 1, RGB(255,255,255));
            hpOld = (HPEN)SelectObject(hdc, hpSolid);
            Polyline(hdc, ptTopController, 2);
            SelectObject(hdc, hpOld);
            DeleteObject((HPEN)hpSolid);

            // Draw -Controller- in red when UART controlpanel is offline
            if (!bMainPanelOnline)
            {
                hpSolid = (HPEN)CreatePen(PS_SOLID, 1, crRed);
                hpOld = (HPEN)SelectObject(hdc, hpSolid);
                Polyline(hdc, ptMainPanel, 5);
                SelectObject(hdc, hpOld);
                DeleteObject((HPEN)hpSolid);
            }

            // Write Texts
            // Init Font for vertical orientation
            plf = (PLOGFONT) LocalAlloc(LPTR, sizeof(LOGFONT)); 
            memcpy(plf->lfFaceName, "Arial", 6 );
            plf->lfWeight = FW_NORMAL; 
            plf->lfEscapement = 900; 
            plf->lfHeight = 9;
            hfnt = CreateFontIndirect(plf); 
            hfntPrev = (HFONT)SelectObject(hdc, hfnt);
            SetBkColor(hdc, RGB(0,0,0));

            // Write Status for Left Lift
            SetTextColor(hdc, ((Lift[LIFT_LEFT].Status<2)?crRed:crGreen));
            TextOut(hdc, rtTextLeftLift.left, rtTextLeftLift.bottom, Lift[LIFT_LEFT].szStatusMsg, strlen(Lift[LIFT_LEFT].szStatusMsg)); 

            // Write Status for Middle Lift
            SetTextColor(hdc, ((Lift[LIFT_MIDDLE].Status<2)?crRed:crGreen));
            TextOut(hdc, rtTextMiddleLift.left, rtTextMiddleLift.bottom, Lift[LIFT_MIDDLE].szStatusMsg, strlen(Lift[LIFT_MIDDLE].szStatusMsg)); 

            // Write Status for Right Lift
            SetTextColor(hdc, ((Lift[LIFT_RIGHT].Status<2)?crRed:crGreen));
            TextOut(hdc, rtTextRightLift.left, rtTextRightLift.bottom, Lift[LIFT_RIGHT].szStatusMsg, strlen(Lift[LIFT_RIGHT].szStatusMsg)); 

            // Write Remote Panels ON/OFF
            TCHAR szRemotePanelOnOff[10];
            wsprintf(szRemotePanelOnOff, (bRemotePanelEnable)?_T("ON"):_T("OFF"));
            SetTextColor(hdc, RGB(255,255,255));
            TextOut(hdc, rtTextRemoteLeft.left, rtTextRemoteLeft.bottom, _T("REMOTE"), 6); 
            TextOut(hdc, rtTextRemoteLeft.left + 9, rtTextRemoteLeft.bottom - 10, szRemotePanelOnOff, strlen(szRemotePanelOnOff)); 
            TextOut(hdc, rtTextRemoteRight.left, rtTextRemoteRight.bottom, _T("REMOTE"), 6); 
            TextOut(hdc, rtTextRemoteRight.left + 9, rtTextRemoteRight.bottom - 10, szRemotePanelOnOff, strlen(szRemotePanelOnOff));

            // Set Previous Font & Delete
            SelectObject(hdc, hfntPrev); 
            DeleteObject(hfnt); 
            LocalFree((LOCALHANDLE) plf);

            EndPaint(hWnd, &ps);
            break;


Ondertussen draait alles al bijna 45min zonder problemen nadat ik alles van de background drawen tot en met de right can bus drawen gecomment heb ... dus het probleem zit dan wss toch ergens in deze methode van bitmaps tekenen ? :

C++:
1
2
3
4
5
6
7
// Draw Right Lift
hdcMap = CreateCompatibleDC(hdc);
hgdi = SelectObject(hdcMap,(Lift[LIFT_RIGHT].Status<2)?hImgLiftRed:hImgLiftGreen);
if (((Lift[LIFT_RIGHT].Status==LIFT_STAT_MOVING)||(Lift[LIFT_RIGHT].Status==LIFT_STAT_HOMERUN))&&(bBlink)))
    BitBlt(hdc, Lift[LIFT_RIGHT].xpos,LIFT_RIGHT_YPOS,43,32, hdcMap,0,0,SRCCOPY);
SelectObject(hdcMap,hgdi);
ReleaseDC(hWnd, hdcMap);

  • MisterData
  • Registratie: September 2001
  • Laatst online: 11-02 08:33
Vreemd, het lijkt erop alsof je ergens iets vergeet te delete'en ofzo (hoewel ik dat hier niet kan ontdekken?), waardoor je het maximum aantal GDI-handles bereikt ofzo... check voor de zekerheid eerst eens met Spy++ ofzo of de WM_PAINT message wel echt aankomt? Het zou natuurlijk kunnen dat dat niet gebeurt door een andere conditie in je programma na 20 minuten :)

Probeer anders het painten te versnellen door met een timer snel InvalidateRect te doen en kijk wat er gebeurt. Dan een paar dingen uit je paint-methode commenten en kijken of het probleem nu nog steeds (of minder snel?) optreedt :)

  • Onbekend
  • Registratie: Juni 2005
  • Laatst online: 17:02

Onbekend

...

Zou het kunnen zijn dat je programma in een lus blijft hangen en dat je dan Windows geen tijd meer geeft om acties in dat venster toe te passen?

Speel ook Balls Connect en Repeat


Verwijderd

Topicstarter
Aargh, gevonden .. Het draait ondertussen al anderhalf uur zonder problemen.

Ik had me lang geleden waarschijnlijk gefocust op deze zin uit msdn:

DeleteDC :
An application must not delete a DC whose handle was obtained by calling the GetDC function. Instead, it must call the ReleaseDC function to free the DC.
Maar ik maak een compatible dc aan, ik vraag niet DE window dc op ...

ReleaseDC:
The ReleaseDC function releases a device context (DC), freeing it for use by other applications.
Dus toen ik dat zag viel mijn eurocent ook ! ReleaseDC vervangen door DeleteDC en hij draait nog steeds zonder problemen ... dom, dom, dom !

Bedankt voor de input !

Problem solved!