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.asp

    wenn 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 tun

    static 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


Anmelden zum Antworten