WinAPI - nagle pojawiają się błędy

0

Witam,
Piszę (dla własnej satysfakcji) program do nauki stolic w c++ i WinAPI. Wszystko działa poprawnie, jednak po dłuższym czasie klikania w przyciski lub przemieszczania okna nagle psuje się szata graficzna.

GetLastError() zwraca:
*1400 (INVALID_WINDOW_HANDLE) - przy każdej funkcji, której podaję uchwyt głównego okna
*1425 (DC_NOT_FOUND) - przy domyślnym WM_ERASEBKGND i WM_MOVE
*6 (INVALID_HANDLE) - w bloku WM_PAINT przy używaniu kontekstu okna
*87 (INVALID_PARAMETER) - występuje razem z 1400 i 1425, co jest zrozumiałe

Ponadto zauważyłem, że co jakiś czas, przy domyślnym komunikacie WM_WINDOWPOSCHANGING pojawia się inny uchwyt do okna i następne komunikaty też mają ten zmieniony uchwyt okna. Za jakiś czas ponownie uchwyt się zmienia. Czy to normalne?

Jedyne komunikaty, które obsługuję sam to: WM_ACTIVATE, WM_COMMAND, WM_CREATE, WM_CTLCOLORBTN, WM_CTLCOLORSTATIC, WM_DESTROY, WM_PAINT i WM_SETFOCUS.

Kodu nie będę wklejał, bo łącznie ma długość ok. siedmiu tysięcy linijek.
Proszę o pomoc, gdyż nie mam zielonego pojęcia, dlaczego nagle pojawiają się w/w błędy.

Kajak4Cpp

0

6 (INVALID_HANDLE) - w bloku WM_PAINT przy używaniu kontekstu okna

No to już wiesz przynajmniej gdzie szukać błędu. Podaj może treść casa od WM_PAINT. Bez podania jakiegokolwiek kodu nikt ci nie pomoże.

0

Kod sam w sobie raczej zły nie jest, bo działa przez np. 250 naciśnięć danego przycisku, a dopiero przy 251. nagle się psuje... Błędy wynikają chyba z jakiegoś błędu przy uchwycie okna, który powoduje zły kontekst, co daje w efekcie brak grafiki.

case WM_PAINT: {
	PAINTSTRUCT ps;
	HDC hdc = BeginPaint(hWnd, &ps); //błąd 1400
	if (nFlaga&FLAG_START) {
		HDC hdc2 = CreateCompatibleDC(hdc); //błąd 6
		SelectObject(hdc2, hScreen);
		BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdc2, 0, 0, SRCCOPY); //błąd 6
		DeleteDC(hdc2);
	} else if (nFlaga&FLAG_USER) {
		SetBkMode(hdc, TRANSPARENT); //błąd 6
		FillRect(hdc, &windowRect, CreateSolidBrush(RGB(100, 130, 160))); //błąd 6
		if (nFlaga==FLAG_USEROVERVIEW)
			userOverview(hdc);
	}
	EndPaint(hWnd, &ps); //błąd 1400
	return 0;
}

void userOverview(HDC hdc) {
	if ( (nFlaga&FLAG_USEROVERVIEW)==0)
		return;
	wstring tekst = L"Powtórki na dziś:\n\n";
	int nTotal=0;
	wchar_t wchLiczba[10];
	for (vector<LANGUAGE>::iterator i=appData.langs.begin(); i!=appData.langs.end();++i) {
		tekst += L"   ";
		tekst += i->name;
		tekst += L": ";
		_itow(i->revisions.size(),wchLiczba,10);
		tekst += wchLiczba;
		tekst += L"\n";
		nTotal += i->revisions.size();
	}
	tekst += L"\nOgółem: ";
	_itow(nTotal, wchLiczba, 10);
	tekst += wchLiczba;
	//odmiana słowa "powtórka"
	char lastNumber = nTotal%10;
	if (nTotal==1)
		tekst += L" powtórka";
	else if ( (nTotal<10 || nTotal>19) && (lastNumber==2 || lastNumber==3 || lastNumber==4) )
		tekst += L" powtórki";
	else
		tekst += L" powtórek";
	SetBkMode(hdc, TRANSPARENT); //błąd 6
	showText(hdc, 100, 100, tekst, userFont); //błąd 6
	//showText(HDC,int,int,wstring,HFONT) to moja wersja TextOut(), która uwzględnia znaki '\n'
}
0

Podejrzewam że masz gdzieś mazanie po pamięci więc ci ten hWnd się zamazuje.
Postaw wokół deklaracji tej zmiennej takie coś:
unsigned BLOCK_BEFORE[1000]={0};
HANDLE hWnd;
unsigned BLOCK_AFTER[1000]={0};
I zobacz czy przestali tak szybko pojawiać się te objawy.
Jeżeli tak się stanie to z całą pewnością masz mazanie po pamięci.

0

Zachowanie programu bez zmian, a według debuggera z VS 2010 Express BLOCK_BEFORE i BLOCK_AFTER ciągle zawierają same zera, więc chyba nie w tym rzecz.

0

Całe to WM_PAINT tu niepotrzebne. Utwórz kontrolkę static text i tylko zmieniaj jej tekst (SetWindowText podając hwnd kontrolki). Wszystko będzie odmalowywane i odświeżane automatycznie. Kontrolkę tworzysz za pomocą CreateWindow podając odpowiednią nazwę klasy okna i jako parenta oczywiście twoje okno, w którym kontrolka ma być umieszczona.

Najlepiej jednak będzie utworzyć aplikację typu "Dialog based" (jeśli takiej nie masz już), czyli już główne okno aplikacji jest ładowane z zasobów, a cały układ okna z kontrolkami możesz sobie wyklikać. Sposób na zmienianie tekstu oczywiście ten sam. Rysowanie tekstu w ten sposób jak to teraz robisz jest bez sensu - dodajesz sobie tylko kłopotu.

Chyba że masz tam coś bardziej skomplikowanego typu jakaś animacja, grafika czy coś tam a na to nakładany tekst. Ale wtedy też lepiej zrobić swoją kontrolkę która będzie obsługiwać odrysowywanie, przyjmować komunikaty w celu sterowania jej działaniem, zarejestrować jej klasę okna, a we właściwym programie tworzyć za pomocą CreateWindow, tak samo jak predefiniowane kontrolki typu button, static text itd. Lub jeszcze lepiej - kontrolka w C++, wtedy możesz wiele rzeczy które kontrolka ma robić opakować w klasy i sterować jej działaniem przez wywoływanie odpowiednich metod wystawianych przez kontrolkę (np wspomniana zmiana tekstu).

1

CreateSolidBrush za każdym razem? i nigdy go nie zwalniasz? Utwórz sobie gdzieś na początku działania programu WM_CREATE zwolnij przy WM_DESTRY lub WM_CLOSE.

0

@kAzek: w życiu bym nie przypuszczał, że to wszystko przez moje lenistwo i niedbałość z CreateSolidBrush(). (W blokach WM_CTLCOLORBTN i WM_CTLCOLORSTATIC też tworzyłem pióra). Po poprawieniu wszystko działa poprawnie.

Serdecznie dziękuję za pomoc.

1 użytkowników online, w tym zalogowanych: 0, gości: 1