Problem mit HIWORD und LOWORD
-
Hallo,
ich habe ein kleines Problem gleich am Anfang.
Ich erstelle ein Fenster, und dazu sieht meine WInMain so aus:int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE dummy0, PSTR dummy1, int dummy2) { WNDCLASS wc; // Fensterklasse HWND hwnd; // Handle des Fensters MSG msg; // Message (Nachricht) // Initialisiere Fensterklasse wc.lpfnWndProc = WindowProc; // Zeiger auf WindowProc, siehe oben wc.lpszMenuName = NULL; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // Icon wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Cursor wc.hbrBackground = (HBRUSH)(CreateSolidBrush(RGB(0,128,0))); // Hintergrund wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; // Stilparameter wc.lpszClassName = "Billiard"; // Klassenname // Registriere Fensterklasse RegisterClass(&wc); // Erzeuge Fenster, merke dir den Handle hwnd = CreateWindow("Billiard", // Klassenname "Billiard 0.0.1", // Titel WS_OVERLAPPEDWINDOW, // Fenstertyp CW_USEDEFAULT, CW_USEDEFAULT, // Ursprung x,y 600, 400, // Breite, Hoehe NULL, NULL, hInstance, NULL); // Zeige Fenster ShowWindow(hwnd, SW_SHOW); // Nachrichtenschleife, Ausstieg falls GetMessage 0 liefert while ( GetMessage(&msg, NULL, 0, 0) ) { TranslateMessage(&msg); DispatchMessage(&msg); // Ruft WindowProc auf } // beende WinMain return msg.wParam; }Meine WindowProc sieht so aus:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT m, WPARAM wParam, LPARAM lParam) { // Fenster auf switch ( m ) { case WM_CREATE: SetTimer(hwnd, 0, dt, 0); hdc = GetDC(hwnd); xmax = LOWORD(lParam); ymax = HIWORD(lParam); init(hwnd); break; case WM_PAINT: ValidateRect(hwnd, 0); break; case WM_TIMER: ntimer++; InvalidateRect(hwnd, 0, 0); break; case WM_MOVE: case WM_SIZE: xmax = LOWORD(lParam); ymax = HIWORD(lParam); init(hwnd); break; case WM_DESTROY: KillTimer(hdc, 0); PostQuitMessage(0); break; case WM_KEYDOWN: case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: break; default: return DefWindowProc(hwnd, m, wParam, lParam); } return 0; }Nun habe ich das Problem das bei WM_CREATE in xmax und ymax nicht die wie von mit erwarteten 600 und 400 stehen sonder in xmax 18 und in ymax 64578 oder so.
Woran liegt das?
-
lParam
Pointer to a CREATESTRUCT structure that contains information about the window being created.Wenn du jetzt nicht siehst das dein Code falsch ist, bist du wohl auch ein C oder C++ Anfänger.
-
Das ist ja sehr schön für dich. So werden wohl programmierinteressiert wieder vertrieben.
Nur zur Info, ich habe diesen Quellcode aus einem Lernbuch für Anfänger und laut deisem Buch soll das so klappen.
Bei einem Kollegen der auch den Code verwendet hat klappt es auch.
So und nun kommst du. Du könntest mir ja wenigstens sagen, wie man es richtig macht...

-
WM_CREATE empfängt als lParam keine grössenangaben sondern einen pointer auf createstruct
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/windows/windowreference/windowmessages/wm_create.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/windows/windowreference/windowstructures/createstruct.aspwenn die angaben haben willst sollte so aussehen
case WM_CREATE: { xmax = ((LPCREATESTRUCT)lParam)->x; ymax = ((LPCREATESTRUCT)lParam)->y; // ..ps: warum rufst du zweimal init() auf?
[edit]
klammerfehler
-
Wie heißt das Buch aus dem der Code ist?
-
So das Buch heißt "Programmieren lernen mit C" Programmieren lernen für Teens mit C | ISBN: 3827318025
Wenn ich das mit dem Beispiel von Miller verwende, bekomme ich eine Zugriffsverletzung. Ich mache das übrigen mit dem Borland C++ Builder 4.
Ich möcht doch nur in einem neuen Fenster, welches grünen Hintergrund hat, eine Linie von der linken oberen Ecke zu der rechten oberen Ecke zeichnen.
Wie muss ich es machen?
So versuche ich es in der init Methode:void init(HWND hwnd) { HPEN brown_pen; brown_pen = CreatePen( PS_SOLID, 15,RGB(0, 128, 64)); SelectObject(hdc, brown_pen); MoveToEx( hdc, 0,0,NULL); LineTo( hdc, 34, 0 ); }
-
hab noch nen fehler gemacht müsste cx und cy sein.
hat aber nix mit deiner
zugriffsverletzung zu tunstatic int xmax, ymax; switch(msg) { case WM_CREATE: // timer etc // grösse und hdc und init() brauchst du hier nicht break; case WM_SIZE: xmax = LOWORD(lParam); ymax = HIWORD(lParam); break; case WM_PAINT: { HDC hdc = GetDC(hwnd); HPEN brown_pen; brown_pen = CreatePen( PS_SOLID, 15,RGB(0, 128, 64)); SelectObject(hdc, brown_pen); MoveToEx( hdc, 0,0,NULL); LineTo( hdc, xmax, ymax ); } break; // ..
-
Hmm Miller, so klappt das leider auch net...
Die Linie geht von der oberen linken Ecke nur bis zu einem drittel der Fensterhöhe runter und dann auch noch diagonal.
Aber ich hab ne andere Lösung von einem Kollegen:RECT rc; int borderwidth = 21; GetClientRect (hwnd, &rc); rect = GetWindowRect(hwnd,&myrec); xmax = rc.right - rc.left; ymax = rc.bottom - rc.top;So hab ich nun in xmax und ymax die Fenstergröße drin stehen.
Nur eine frage hab ich noch, wenn ich das Fenster jetzt verkleinere oder vergrößere, dann fängt es an zu flackern.Wie kann ich das beseitigen??
-
API Anfänger schrieb:
Hmm Miller, so klappt das leider auch net...
Die Linie geht von der oberen linken Ecke nur bis zu einem drittel der Fensterhöhe runter und dann auch noch diagonal.anscheined hast du uns etwas verheimlicht
den ich hab grad ein prog geschrieben
das genau deinen anforderungen entspricht. und mein code geht
API Anfänger schrieb:
Wie kann ich das beseitigen??
"Double Buffering" heisst das zauberwort siehe forensuche
-
Ok, mein Versuch mit DoubleBuffering klappt net so ganz.
Ich sehe nur meinen grünen Hintergrund...
Das habe ich bis jetzt:void init(HWND hwnd) { HBRUSH brown_brush, green_brush, black_brush; HPEN brown_pen,black_pen; RECT rc; int borderwidth = 21; hdc = GetDC(hwnd); hdcbuffer = CreateCompatibleDC(hdc); GetClientRect (hwnd, &rc); rect = GetWindowRect(hwnd,&myrec); xmax = rc.right - rc.left; ymax = rc.bottom - rc.top; brown_pen = CreatePen( PS_SOLID, borderwidth ,RGB(128, 64, 0)); black_pen = CreatePen( PS_SOLID, 1 ,RGB(0, 0, 0)); green_brush = CreateSolidBrush( RGB(0, 128, 0) ); //brown_brush = CreateSolidBrush( RGB(0, 128, 64) ); black_brush = CreateSolidBrush( RGB(0, 0, 0) ); SelectObject(hdcbuffer, green_brush); Rectangle(hdcbuffer, 0,0,xmax,ymax); DeleteObject(green_brush); /*Zeichnen der braunen Banden*/ SelectObject(hdcbuffer, brown_pen); MoveToEx( hdcbuffer, (int)(borderwidth/2),(int)(borderwidth/2),NULL); LineTo( hdcbuffer, xmax-((int)(borderwidth/2)), (int)(borderwidth/2) ); LineTo( hdcbuffer, xmax-((int)(borderwidth/2)), ymax-((int)(borderwidth/2)) ); LineTo( hdcbuffer, (int)(borderwidth/2), ymax-((int)(borderwidth/2)) ); LineTo( hdcbuffer, (int)(borderwidth/2), (int)(borderwidth/2) ); DeleteObject(brown_pen); /*Zeichnen der schwarzen Linie auf den Banden*/ SelectObject(hdcbuffer, black_pen); MoveToEx( hdcbuffer, (int)(borderwidth/2),(int)(borderwidth/2),NULL); LineTo( hdcbuffer, xmax-((int)(borderwidth/2)), (int)(borderwidth/2) ); LineTo( hdcbuffer, xmax-((int)(borderwidth/2)), ymax-((int)(borderwidth/2)) ); LineTo( hdcbuffer, (int)(borderwidth/2), ymax-((int)(borderwidth/2)) ); LineTo( hdcbuffer, (int)(borderwidth/2), (int)(borderwidth/2) ); DeleteObject(black_pen); /*Zeichnen der Löcher*/ SelectObject(hdcbuffer, black_brush); /*Oben links*/ Ellipse( hdcbuffer, (int)(borderwidth/5), (int)(borderwidth/5), (int)(borderwidth*1.5), (int)(borderwidth*1.5) ); /*Oben rechts*/ Ellipse( hdcbuffer, (xmax - (int)(borderwidth*1.5)), (int)(borderwidth/5), xmax -((int)(borderwidth/5)) , (int)(borderwidth*1.5) ); /*Unten rechts*/ Ellipse( hdcbuffer, (xmax - (int)(borderwidth*1.5)), (ymax - (int)(borderwidth*1.5)), xmax -((int)(borderwidth/5)) , ymax - ((int)(borderwidth/5)) ); /*Unten links*/ Ellipse( hdcbuffer, (int)(borderwidth/5), (ymax - (int)(borderwidth*1.5)), (int)(borderwidth*1.5), ymax - ((int)(borderwidth/5)) ); /*Jetzt noch die zwei Löcher in der Mitte*/ /*Obere Mitte*/ Ellipse( hdcbuffer, (int)((xmax/2)-(borderwidth/2)), (int)(borderwidth/5),(int)((xmax/2)+borderwidth), (int)(borderwidth*1.5) ); /*Untere Mitte*/ Ellipse( hdcbuffer, (int)((xmax/2)-(borderwidth/2)), (ymax - (int)(borderwidth*1.5)),(int)((xmax/2)+borderwidth), ymax - ((int)(borderwidth/5)) ); /*Von Buffer auf Vordergrund flipen*/ BitBlt(hdc, 0, 0, xmax, ymax, hdcbuffer, 0, 0, SRCCOPY); DeleteDC(hdcbuffer); } LRESULT CALLBACK WindowProc(HWND hwnd, UINT m, WPARAM wParam, LPARAM lParam) { // Fenster auf switch ( m ) { case WM_CREATE: //SetTimer(hwnd, 0, dt, 0); //init(hwnd); break; case WM_PAINT: init(hwnd); break; case WM_TIMER: break; case WM_MOVE: case WM_SIZE: //init(hwnd); break; case WM_DESTROY: KillTimer(hdc, 0); PostQuitMessage(0); break; case WM_KEYDOWN: case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: break; default: return DefWindowProc(hwnd, m, wParam, lParam); } return 0; }In dem FAQ Beitrag http://www.c-plusplus.net/forum/viewtopic.php?t=14713 ist mir eines nicht so ganz klar geworden. Die vorgehensweise ist doch folgende?: Ich führe alle zeichenoperationen auf dem Buffer durch und wenn ich dann fertig bin, tausche ich den Hintergrundbuffer mit dem Vordergrund aus, oder?
Wofür ist denn dann dieses :
HBITMAP hBM = CreateCompatibleBitmap(hDC, cxClient, cyClient); SelectObject(hDC2, hBM);gut?
Damit mache ich doch ein Bild von der aktuellen Oberfläche und zeichne sie in den Hintergrundbuffer.
Wenn ich das mit einbaue dann sehe ich zwar alles wie gewünscht, jedoch ist das flackern um so stärker...Wo liegt mein Denkfehler?
-
API Anfänger schrieb:
Wofür ist denn dann dieses :
HBITMAP hBM = CreateCompatibleBitmap(hDC, cxClient, cyClient); SelectObject(hDC2, hBM);Das ist das wichtigste(, das du einfach weggelassen hast). Es legt nämlich ein Bitmap (Größe: cxClient * cyClient) im Spiecher an und selektiert es in einen Gerätekontext (standardmassig ist hier ein monochromes 1*1 Bitmap drin), so werden alle Zeichenaktionen mittels diesem Gerätekontext in das Bitmap gezeichnet. (Das Bitmap muss wieder gelöscht werden, wenn es gemalt nicht mehr gebracuht wird!)
In WM_PAINT ruft man BeginPaint und EndPaint auf, statt GetDC und ReleaseDC 
Um das flackern ganz weg zu kriegen verarbeitest du WM_ERASEBKGND und gibst dort einfach 0 zurück, da du ja sowieso den ganzen Klientbereich in WM_PAINT übermalst.
//In WM_SIZE solltest du das Fenster nicht neu malen, sondern im sagen, das es sioch neu malen soll, das geht z.B. mit Invalidatect(hwnd, 0, false);
//ist bei dir ja noch auskommetiert