WINAPI Klasse, Vererbung Problem



  • Ich glaube Du kannst in WM_CREATE noch keine Child-Windows erzeugen.
    WM_CREATE wird gesendet, während Du das CreateWindow() des Elternfensters aufrufst. Erst dessen Return Wert liefert Dir den hWnd des Elternfensters zurück, der für das CreateWindow() der Kind Fenster gebraucht wird.



  • ne das ist für ein Fenster
    in der Hauptklasse will ich halt die ganzen Funktionen haben und in der Kindklasse will ich die definieren.
    Nur das Problem ist die WndProc will halt nicht so wie ich will.
    Bei einer normalen Funktionen würdes funktionieren nur nicht bei dieser WndProc 😕



  • Ich mein das hier:

    hEditName = CreateWindow(...

    Da geht es schon um Kindfenster. Ich gebe zu, mein Argument war nicht so gut, weil WindowsProc ja den hWnd liefert. Allerdings hab ich selbst immer Schwierigkeiten gehabt, wenn ich versucht habe, Kindfenster zu diesem Zeitpunkt zu erzeugen.

    Aber wenn Dein WndProc ohnehin noch nicht läuft, musst Du das natürlich zuerst richten.
    - die Argumente von ".." hast Du berücksichtigt?
    - Ich weiss nicht genau was "CALLBACK" alles macht, aber hast Du nicht den falschen W.-Prozess mit CALLBACK deklariert? Das WndProc wird doch "von Dir selber" aufgerufen und ist kein CALLBACK. (Ist WINAPI synonym mit CALLBACK?)

    Bei mir sehen die Deklarationen jedenfalls etwa so aus:

    virtual LONG WindowProc( HWND, UINT, WPARAM, LPARAM );
    static LONG CALLBACK RegisteredProc(HWND, UINT, WPARAM, LPARAM);
    // der WindowProc müsste nicht unbedingt virtual sein, wenn Du das nicht
    // willst.

    Und der Code etwa so:

    const LONG MSG_NOT_HANDLED = -1;
    
      LONG CALLBACK VWindow::RegisteredProc(HWND hWnd, UINT msg, WPARAM wP, LPARAM lP)
    { 
      VWindow* pWindow = 0;
      if ( msg == WM_NCCREATE)  //oder WM_CREATE 
      {  //ASSERT(lP);  
         pWindow = (VWindow*)((CREATESTRUCT*)lP)->lpCreateParams;
         pWindow->_hWnd = hWnd;
         SetWindowLong(hWnd,GWL_USERDATA, (LONG)pWindow);
      }
      else
      {  pWindow = (VWindow*)GetWindowLong(hWnd, GWL_USERDATA);
         if(!pWindow)
         { return DefWindowProc(hWnd, msg, wP, lP);
      }  }
    
      // hier habe ich jetzt zusätzlichen Code eingefügt, so dass nichtbehandelte 
      // Messages an DefWindowProc weitergeleitet werden.
    
      LONG result = MSG_NOT_HANDLED;
    
      .... // andere Messages
    
      result = pWindow->WindowProc(....);
    
      if(result == MSG_NOT_HANDLED)
        result = DefWindowProc(hWnd, msg, wP, lP); 
      return result;
    }
    


  • [C++ Fehler] frmClass.cpp(38): E2268 Aufruf der undefinierten Funktion 'ASSERT'

    wo krieg ich die Funktiondefinition her?



  • nimm die zeile raus. ist unwichtig im moment.



  • jetzt bricht er schon hier ab

    pWindow->_hWnd = hWnd;

    ---------------------------
    Benachrichtigung über Debugger-Exception
    ---------------------------
    Im Projekt p_daldria.exe ist eine Exception der Klasse EAccessViolation aufgetreten. Meldung: 'Zugriffsverletzung bei Adresse 00401185. Schreiben von Adresse 00000004'. Prozeß wurde angehalten. Mit Einzelne Anweisung oder Start fortsetzen.
    ---------------------------
    OK Hilfe
    ---------------------------



  • hast du auch CreateWindowEx(............., this) gemacht?



  • ".....[?]" scheint immer ne gute Antwort zu wissen. Geht Dein Code jetzt?

    Ich wollte noch folgendes hinzufügen: Du wirst nur für einen kleinen Teil der eingehenden Messages eigenen Code schreiben. Diejenigen Messages, die Du nicht selber behandelst, musst Du daher an "das System" weiterleiten (z.B. damit die Grösse des Fensters verändert werden kann, ohne dass Du Dich selber darum kümmerst). Deshalb habe ich meinem letzten Beitrag editiert und noch etwas Code eingefügt, damit die unbehandelten Messages an DefWindowProc() weitergeleitet werden können.

    Ich muss meine Behauptung etwas abschwächen: Ich weiss eigentlich nicht welche Defaultverarbeitung in ::DefaultWindowProc() stattfindet, und welche erst hinter dem "return result;" kommt. Aber Du kannst ja mal einfach sehen und testen, ob und wozu Du das ::DefaultWindowProc() brauchst. Meine Klasse wurde geschrieben um selbstdefinierte Windows aber auch API-Steuerelemente zu verwalten, und ich kann jetzt nicht mehr so einfach testen wozu ich was brauche.

    NB _hWnd: bin kürzlich gerügt worden, weil ich Unterstriche vor den Namen von Klassen-Variablen benutze; ich werd das wohl weiterhin so machen, weil ich ohnehin schon verdorben bin, aber ich möchte nicht schuld sein, wenn Du Dir einen schlechten Stil angewöhnst. Also: m_hWnd ist sexy, _hWnd ist doof.



  • ich hab alle ChildWindows bei meiner Create Funktion rausgenommen von daher glaub ich nicht das es an CreateWindow(..) liegt.

    Hab mal die Dateien online gestellt vielleicht könnt ihr euch die ja mal anschauen

    http://www.Spyke-Online.de/frmClass.cpp <--- Eltern Klasse
    http://www.Spyke-Online.de/frmStarter.cpp <--- Kind Klasse



  • achja pWindow hat den Wert NULL (bei mir im Quelltext wnd)



  • kann denn keiner helfen 😢



  • Wenn ich das richtig sehe, willst du in deiner statische Fensterprozedur einen Zeiger auf die entsprechend Instanz kriegen und verwendest die User Data?

    Weiß nicht, ob es daran liegen könnte. Nur verwende doch mal statt SetWindowLong() SetProp() und um die Instanz dann zu holen GetProp(), das ging bei mir immer perfekt, vielleicht liegt es ja daran.

    Hoffe ich lag nicht total daneben,

    Grüße

    JensE



  • Habe nicht Deinen ganzen Code gelesen, geschweige denn verdaut -
    aber es scheint Du hast das hier

    "hast du auch CreateWindowEx(............., this) gemacht?"

    noch nicht umgesetzt.

    Es geht hier nicht um die ChildWindows. Sondern um die Erstellung des Hauptfensters.

    wnd = (FRM_CLASS*)((CREATESTRUCT*)lParam)->lpCreateParams;

    Hier kannst Du den Pointer auf Dein Frame nur auslesen, wenn Du diesen Pointer vorher in CreateWindow(Ex) als "Creation Parameter", übergeben hast.

    Von allein weiss die API nichts über Deine C++ Klasse.



  • könntest du mir vielleicht komplett Anweisung für CreateWindowEx geben

    und an SetWindowLong kanns nicht liegen da er nicht bis hinkommt, er bricht vorher schon ab



  • Ich glaube die Parameter in CreateWindowEx() solltest Du schon selber einsetzen. Ich kenne Dein Programm ja auch nicht so gut. Für den letzten Parameter (LPVOID lpParam // pointer to window-creation data) jedenfalls musst Du
    this
    eintragen (zumindest solange der Aufruf innerhalb einer Klassenfunktion erfolgt).

    Deine CreateWindowEx() sieht sonst ja auch nicht schlecht aus, so weit ich sehen kann.

    In meiner eigenen Window Klasse habe ich das CreateWindowEx in einer eigenen Funktion Create(). Du scheinst die ganze Fenster-Erstellung in den Konstruktor der FRM_CLASS unterbringen zu wollen. Ich weiss im Augenblick keinen Grund warum das nicht gehen soll, aber dass Du auch noch den Messageloop im Constructor hast, wird auf die Dauer wohl zu Problemen führen. Der Constructor der abgeleiteten Klasse wird dann erst aufgerufen, wenn das Programm praktisch schon zu Ende ist.

    NB:
    Bist Du sicher, dass Du hInstance initialisiert hast? Kann nichts finden.



  • Das Problem ist die "Windows Procedure"-Funktion:

    int WINAPI FRM_CLASS::WindowsProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)   
    {   
            if ( uMsg == WM_CREATE )   
                    SetWindowLong( hWnd, GWL_USERDATA, lParam); 
    
              FRM_CLASS *wnd = (FRM_CLASS*)GetWindowLong(hWnd, GWL_USERDATA); 
    
              return wnd->WndProc(hWnd, uMsg, wParam, lParam); 
    
    }
    

    Wenn du der CreateWindowEx-Funktion den this-Zeiger als lParam übergibst, erwartest du, dass die Funktion zu allererst eine WM_CREATE Nachricht an die WindowsProc-Funktion sendet. Es ist aber so, dass CreateWindowEx noch andere Nachrichten an die Procedure-Funktion sendet bevor es die WM_CREATE Nachricht versendet. Daher erhält der Zeiger "wnd" einige male den Wert NULL, weil SetWindowLong erst aufgerufen wird wenn die WM_CREATE Nachricht erhalten wird, und das passiert erst ein wenig später.

    Lösung: Du nimmst eine Dummy-Procedure-Funktion her, die einfach nur DefWindowProc aufruft. Du gibst diese bereits im WNDCLASS struct an:

    wc.lpfnWndProc = WndProc_DUMMY; // wird später ersetzt

    Wenn die CreateWindowEx-Funktion zurückkehrt machst du folgendes:

    CreateWindowEx(...); // hier brauchst du kein "this" angeben
    SetWindowLong(hwnd, GWL_USERDATA, (LONG)this); //"this"-pointer speichern
    SetWindowLong(hwnd, GWL_WNDPROC, (LONG)FRM_CLASS::WindowsProc); //richtige procedure-funktion einstellen

    Und so sollten die Funktionen aussehen:

    LRESULT WndProc_DUMMY(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
    {
      return DefWindowProc(hWnd, 0, uMsg, wParam, lParam);
    }
    
    LRESULT WINAPI FRM_CLASS::WindowsProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)   
    {   
      static FRM_CLASS *wnd = NULL; 
      wnd = (FRM_CLASS*)GetWindowLong(hWnd, GWL_USERDATA); 
      return wnd->WndProc(hWnd, uMsg, wParam, lParam);   
    }
    

Anmelden zum Antworten