Dynamische Speicherverwaltung



  • Hallo.

    Ich schreibe gerade ein Programm, wo ich ein bisschen mit den Sortieralgorithmen herumexperimentieren will.

    Darum will ich mir auf dem Bildschirm 500 Pixel zeichnen lassen mit dem Index als x-Koordinate und einer Zufallszahl als y-Koordinate und will diese Dann sortieren und jeden Schritt neu zeichnen lassen.

    Ich bin jetzt soweit, dass ich die Zufallszahlen erzeugt habe und das Anfangsbild zeichnen kann, aber sobald das geschehen ist kommt eine Fehlermeldung:

    Die Anweisung in "0x004012fc" verweist auf Speicher in "0x00000004". Der Vorgang "read" konnte nicht auf dem SPeicher durchgeführt werden.
    Klicken Sie auf "OK" um das Programm zu beenden.
    Klicken sie auf "Abbrechen", um das Programm zu debuggen.

    Wenn ich auf abbrechen klicke, kommt die Fehlermeldung nochmal, nur ohne Abbrechen-Button.

    Ich schicke einfach mal meinen Code und ich bin mir ziemlich sicher, dass das an der Speicherverwaltung liegt, da bin ich mir immer etwas unsicher wenn ich damit arbeite:

    # include <windows.h>
    
    # define MAX_PIXELS 500
    
    TCHAR szAppName[]=TEXT("mSort");
    
    LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
    int *CreateRandomPixels(int);
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
    				   PSTR lpCmdLine, int iCmdShow)
    {
    	HWND hwnd;
    	WNDCLASS wndclass;
    	MSG msg;
    
    	wndclass.style = CS_VREDRAW | CS_HREDRAW;
    	wndclass.lpfnWndProc = WindowProc;
    	wndclass.cbClsExtra = 0;
    	wndclass.cbWndExtra = 0;
    	wndclass.hInstance = hInstance;
    	wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    	wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
    	wndclass.lpszMenuName = NULL;
    	wndclass.lpszClassName = szAppName;
    
    	if(!RegisterClass(&wndclass))
    	{
    		MessageBox(NULL, 
    			TEXT("Fehler: Programm arbeitet mit Unicode und setzt Windows NT vorraus"),
    			szAppName, MB_ICONERROR);
    		return 0;
    	};
    
    	hwnd = CreateWindow (szAppName,
    						 szAppName,
    						 WS_OVERLAPPEDWINDOW,
    						 100,
    						 100,
    						 700,
    						 640,
    						 NULL,
    						 NULL,
    						 hInstance,
    						 NULL);
    
    	ShowWindow(hwnd, iCmdShow);
    	UpdateWindow(hwnd);
    
    	while(GetMessage(&msg, NULL, 0, 0))
    	{
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	};
    
    	return msg.wParam;
    };
    
    LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	HWND hButtonGo;
    	HDC hdc;
    	int i;
    	static int *pixels;
    
    	switch(message)
    	{
    	case WM_PAINT:
    		pixels = CreateRandomPixels(MAX_PIXELS);
    		hdc = GetDC(hwnd);
    		for(i=0;i<MAX_PIXELS;i++)
    		{
    			SetPixel(hdc, i+20, pixels[i]+20, 0);
    		}
    		ReleaseDC(hwnd, hdc);
    	case WM_CREATE:
    		hButtonGo = CreateWindow (TEXT("button"),
    								  TEXT("Sort"),
    								  WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
    								  640, 20, 80, 20,
    								  hwnd,
    								  (HMENU) 1,
    								  ((LPCREATESTRUCT)lParam)->hInstance,
    								  NULL);
    		return 0;
    
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		delete[] pixels;
    		return 0;
    	};
    	return DefWindowProc(hwnd, message, wParam, lParam);
    };
    
    int *CreateRandomPixels(int max)
    {
    	int i;
    	int *randpixels = new int[max];
    
    	for(i=0;i<max;i++)
    	{
    		randpixels[i] = rand()%MAX_PIXELS;
    	};
    	return randpixels;
    };
    

    Ach ja: Die Pixel werden wunderbar gezeichnet, erst dann kommt die Fehlermeldung.

    Bitte helft mir.

    Danke schonmal
    Gruß
    Max



  • Sorry ich hab was vergessen.

    In dem Fall WM_PAINT musste doch noch return 0 hin.

    Jetzt ist der Fehler nicht mehr da, aber dafür wird diese WM_PAINT -Nachricht immer wieder aufgerufen, das soll doch aber nur einmal sein.

    Ich dachte eigentlich immer WM_PAINT kommt nur beim Erstellen des Fensters (mit UpdateWindow) und wenn man z.B. größe des Fensters ändert oder das Fenster verschiebt.

    Hat da jemand eine Lösungsmöglichkeit?



  • BeginPaint und EndPaint?



  • Jo.
    Damit gehts.

    Vielen Dank.

    Wer das hier soweit schon gelesen hat, kann mir vielleicht trotzdem sagen, warum das mit GetDC und ReleaseDC nicht geklappt hat und was da genau der Unterschied ist.

    Gruß
    Max



  • WM_PAINT wird solange immer wieder gesendet bis der neu zu zeichnende Fensterbereich wieder für gültig erklärt wurde.
    Das passiert entweder bei Verwendung von BeginPaint() und EndPaint() oder durch Aufruf von ValidateRect()
    Nimm BeginPaint() und EndPaint() !



  • Ich hab zu dem selben Programm gleich nochmal ne Frage.
    Nach jedem Sortierschritt soll jetzt dieses Feld pixels neu gezeichnet werden. Wenn ich auf meinen Button klicke geht aber leider nix los.

    Wie kann ich WM_Paint nochmal aufrufen?
    SendMessage und UpdateWindow funktionieren irgendwie nicht:

    LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	HWND hButtonGo;
    	HDC hdc;
    	PAINTSTRUCT ps;
    	int i, j, tmp, smallest;
    	static int *pixels;
    
    	switch(message)
    	{
    
    	case WM_CREATE:
    		pixels = CreateRandomPixels(MAX_PIXELS);
    		hButtonGo = CreateWindow (TEXT("button"),
    								  TEXT("Sort"),
    								  WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
    								  540, 20, 120, 30,
    								  hwnd,
    								  (HMENU) 1,
    								  ((LPCREATESTRUCT)lParam)->hInstance,
    								  NULL);
    		return 0;
    
    	case WM_PAINT:
    		hdc = BeginPaint(hwnd, &ps);
    		for(i=0;i<MAX_PIXELS;i++)
    		{
    			SetPixel(hdc, i+20, pixels[i]+20, 0);
    		}
    		EndPaint(hwnd, &ps);
    		return 0;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		delete[] pixels;
    		return 0;
    	case WM_COMMAND:
    		if(HIWORD(wParam)==BN_CLICKED)
    		{
    			if(LOWORD(wParam)==1)
    			{
    
    				for(i=0;i<(MAX_PIXELS-1); i++)
    				{
    					smallest=i;
    					for(j=i+1;j<MAX_PIXELS; j++)
    					{
    						if(pixels[j]>pixels[smallest]) smallest=j;
    					};
    					tmp=pixels[i];
    					pixels[i]=pixels[smallest];
    					pixels[smallest]=tmp;
    					SendMessage(NULL, WM_PAINT, wParam, lParam);
    					//UpdateWindow(hwnd);
    				};
    			};
    		};
    	};
    	return DefWindowProc(hwnd, message, wParam, lParam);
    };
    

    Jemand eine Idee?

    Gruß
    Max



  • InvalidateRect() mit UpdateWindow() direkt dahinter 😉



  • Wunderbar.
    Jetzt klappt alles.
    Ich denke jetzt kann ich euch erstmal für eine gewisse Zeit in Ruhe lassen.

    Vielen Dank
    MFG
    Max



  • Wenn Du "CreateRandomPixels" aber regelmäßig unter WM_PAINT aufrufst (ein paar Posts davor ist das so), erzeugst Du massig Speicherleaks!
    Dann schreib das:

    case WM_DESTROY:
            PostQuitMessage(0);
            delete[] pixels;
            return 0;
    

    besser so:

    case WM_DESTROY:
            delete[] pixels;
            PostQuitMessage(0);
            return 0;
    

    (Erst Clean-Up, dann beenden 😉 !)

    PS-1: Dein "hButtonGo" lebt nicht sehr lange 🤡 .
    PS-2: Was issen dat 🙄 :

    SendMessage(NULL, WM_PAINT, wParam, lParam);
    


  • Genaugenommen ist es egal ob PostQuitMessage nun vor dem delete steht oder dahinter, die Message lander ja erstmal in der Queue, und wird erst später verwurstet.
    Aber es liest sich natürlich "sauberer" wenn erst delete und dann PostQuitMessage dasteht.


Anmelden zum Antworten