[C++/WinApi] Anzeigefehler auf fremden PC

posi90

Erfahrenes Mitglied
Hallo,

An was kann es liegen, dass auf einem fremden PC (von einem Freund) die Release-Version meines Programms Anzeigefehler verursacht?

So sieht der Fehler aus:

021110231906_IMG_02112010_231536.png


021110231806_IMG_02112010_231450.png


Und so sollte es aussehn:

021110233349_orig.png


An der Rechenleistung liegt es nicht weil es auf meinem Netbook einwandfrei funktioniert.

Bitte um Vorschläge.


mfg. Poseidon
 
Solche Fehler liegen entweder an den verwendeten API Funktionen oder an Bugs in installierten Grafikprogrammen, ich kann von beidem ein Lied singen.

Hintergründe wie in deinem ersten Screenshot verwenden oft StretchBlt() um das Bild auf Vollbildgrösse zu bringen, wobei StretchBlt() recht viel Power braucht, sprich immer dann wenn ein Fenster, was seinerseits diverse BitBlt(), StretchBlt(), usw. enthält, über einen Hintergrund gezogen wird der auch wieder StretchBlt() enthält, kommt der Rechner mit dem neu zeichnen der Fenster nicht nach.

Programme wie GIMP, PhotoImpact, usw. vertragen sich nicht besonders miteinander, hat man mehrere solche Programme installiert kommt es im normalen Windows-Betrieb zu den unsinnigsten Anzeigefehlern, selbst dann wenn keins dieser Grafikprogramme geöffnet ist.

Dieser Effekt wird um ein vielfaches heftiger, wenn dein Programm ein 32bit Programm ist, was auf 64bit Windows laufen soll, oder wenn man 32bit Grafikprogramme auf 64bit Windows installiert und er wird nochmal heftiger, wenn man im Programm heftig overhead hat, wie z.B. mit .NET.
 
Hm...

Also, ich hab 2 PCs, einmal Win7 x64 und einmal Win7 x86. Egal wo ich kompeliere, das Programm läuft auf beiden einwandfrei. Ein Freund von mir hat WinXp x64 glaub ich, und da funktioniert keines der Programme (weder das x86 kompelierte noch das x64 kompelierte).

So hab ich das Fenster erzeugt:
Code:
WNDCLASSEX wc;	
wc.cbSize        = sizeof(WNDCLASSEX);
wc.style         = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc   = WndProc;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = 0;
wc.hInstance     = g_hInstance;

wc.hIcon         = NULL;
wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName  = 0;
wc.lpszClassName = (LPCWSTR)g_szAppName;
wc.hIconSm       = (HICON) LoadImage(s->g_hInstance, MAKEINTRESOURCE(ID_EXE_ICON), IMAGE_ICON, 32, 32, LR_DEFAULTSIZE);
	...
posx=GetSystemMetrics(SM_CXSCREEN) / 2 - bmp.bmWidth / 2;
posy=GetSystemMetrics(SM_CYSCREEN) / 2 - bmp.bmHeight / 2;
hwnd = CreateWindowEx(WS_EX_TRANSPARENT, (LPCWSTR)g_szAppName, (LPCWSTR)g_szTitle, WS_POPUP, posx, posy, bmp.bmWidth, bmp.bmHeight, NULL, NULL, g_hInstance, NULL);
Peekmessageschleife

Danach in der WM_PAINT message den Hintergrund gezeichnet:

Code:
GetObject(LoadBitmap (g_hInstance, MAKEINTRESOURCE (ID_BITMAP_MAIN_BG)), sizeof(BITMAP), (LPSTR)&bm);

HDC hdc = BeginPaint(hwnd, &ps);

HDC hdcMem = CreateCompatibleDC(hdc);
SelectObject(hdcMem, LoadBitmap( g_hInstance,MAKEINTRESOURCE(ID_BITMAP_MAIN_BG)));    
BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);
DeleteDC(hdcMem);
EndPaint(hwnd, &ps);

Verschiebbar hab ich es so gemacht:
Code:
case WM_LBUTTONDOWN:
            SendMessage(hwnd, WM_NCLBUTTONDOWN, HTCAPTION,NULL);
            break;

Wo kann ich hier mit der Problemlösung ansetzen, damit es ab Windows Xp unter beiden Architekturen ausführbar ist?

mfg. Poseidon
 
Lass mal CS_HREDRAW | CS_VREDRAW weg, das ist auch so ein Powerfresser ohne viel Sinn, vor allem wo du eh schon DoubleBuffering im WM_PAINT verwendest.
Dann machst du noch dazu:
Code:
case WM_ERASEBKGND:
{
return 1;
}
break;
 
Unter XP sind leider immer noch Anzeigefehler. Kann dies vielleicht an Kompilereinstellungen liegen? Im Notfall muss ich mir irgendwie XP besorgen und von Neuem beginnen.
 
Am Compiler liegt es sicher nicht.

WS_EX_TRANSPARENT wäre noch so ein Kandidat, der solche Fehler verursacht.

Ausserdem ist da noch ein Problem, was ich selber auch noch nicht gelöst habe, bzw. wo ich nicht mal weiss, wann oder unter welchen Umständen der Fehler auftritt.
Streifen die beim Verschieben zurückbleiben, an Stellen wo das Fenster vorher war, jetzt aber nicht mehr ist, liegen daran, dass der Desktop nicht neu gezeichnet wird.
Als Notlösung geht da

InvalidateRect(HWND_DESKTOP,0,0);

aber das flackert heftig, logisch, weil es den ganzen Desktop neu zeichnet.
Weniger flackert es, wenn du unter case WM_WINDOWPOSCHANGING: und case WM_WINDOWPOSCHANGED: die Position abfängst, und das neu zeichnen vom Desktop auf dieses rect beschränkst, aber eine wirkliche Lösung ist das auch nicht.

Da muss dir/uns jemand anders sagen, wie das geht.
 
Hallo posi90,

für diese Darstellungsfehler fallen mir zwei mögliche Ursachen ein:
  1. Die Paint-Routine benötigt zu zuviel Rechenzeit,
  2. Dein Programm führt im Hauptthread rechenintensive Aktionen aus, die die GUI ausbremsen.

Da dein Hintergrundbild wohl unverändert bleibt, würde ich "LoadBitmap" nur ein einziges Mal außerhalb der Paint-Routine ausführen und das Bitmap in einer globalen Variablen speichern. Du rufst "LoadBitmap" sogar zweimal auf - das kostet Performance.
Außerdem sollte ein mit SelectObject verwendetes Objekt auch wieder freigegeben werden. Sonst fährt man sich den GDI-Speicher zu, was irgendwann auch zu Darstellungsfehlern führt.

Gruß
MCoder
 
MCoder hat natürlich recht, das sind so Feinheiten die man sowieso machen kann/sollte.
Allerdings habe ich das bei mir schon alles, sämtliche Grafiken in einem Canvas Buffer, keine CPU hungrigen Funktionen, und der Fehler tritt (ohne InvalidateDesktop) trotzdem noch auf, insbesondere bei älteren PC´s mit SingleCore CPU.
 
Danke für die vielen Antworten =)

Habe nun auf ein von VC++ gefertigte Vorlage aufgebaut, zwischen durch auf einer virtuellen XP-Maschine getestet ob Anzeigefehler auftregen, und so mein Programm zum Laufen gebracht. Weiters habe ich Funktionen wie "LoadBitmap" nur bei der Initialisierung verwendet.

Hab all eure Räte mit eingebaut, also, weg mit WS_EX_TRANSPARENT, weg mit CS_HREDRAW | CS_VREDRAW, WM_ERASEBKGND mit return 1.

Habe noch eine Frage an Thomasio, und zwar möchte ich gerne wissen was ein Canvas Buffer ist.

Danke!
 
Zurück