AfxGetMainWnd() aus Thread heraus aufrufen.



  • Ich möchte aus einem Thread heraus aus eine CaptionBar ('CMFCCaptionBar') in meinem MainFrame anzeigen lassen:

    ((CMeinMainFrame*) AfxGetMainWnd())->mCaptionBar...
    

    Mein Thread wird (aus 'CMeinMainFrame' aus) so aufgerufen:

    m_pThread1 = (CThread1*)AfxBeginThread(RUNTIME_CLASS(CThread1),
                                              THREAD_PRIORITY_NORMAL,
                                              0,
                                              CREATE_SUSPENDED);
       m_pThread1->m_pMainWnd   = this;
       m_pThread1->m_pActiveWnd = this;
    
       m_pThread1->ResumeThread();
    

    In der CaptionBar wird dann an einer Stelle eine Assertion ausgelöst.
    Ohne Thread - direkt aus dem MainFrame heraus - funktioniert es.

    Gruß


  • Mod

    CWnd Objekte sind threadafin. D.h. Bei einem Zugriff aus einem anderen Thread wird geprüft ob dieses CWnd Objekt in der Handle Map des aktuellen Threads ist. Ist das nicht der Fall gibt es einen ASSERT.

    Entsprechend sind CWnd Objekte nicht threadsicher. Wenn Du ein HWND Objekt übergibst wird das gehen, allerdings kann das dann dennoch zu einem (Dead)Lock führen, denn der Zugriff aus einem anderen Thread bedeutet, dass die Fensternachricht nur dann ausgeliefert wird, wenn der Thread des Fensters auch in GetMessage oder PeekMessage ausführt.



  • Gibt es eine bessere Vorgehensweise aus dem Thread die CaptionBar anzuzeigen?



  • Um Probleme zu vermeiden sollte die ganze GUI in einem Thread laufen.
    (Bzw. genauer: jedes Top-Level Window kann seinen eigenen Thread haben, das ist OK, aber nicht mehrere Threads für Fenster/Controls die im selben Top-Level Window leben. Und weil's meistens reicht/der Einfachkeit halber: überhaupt nur ein Thread für die ganze GUI.)

    D.h. umstrukturieren. Statt dass man den GUI Thread blockiert und dann einen Thread rausstartet der irgendwas in der GUI updaten soll, damit die GUI nicht "eingefrohren" wirkt, lieber die blockierende Arbeit in einen Worker-Thread auslagern und den GUI Thread weiter laufen lassen um GUI Messages abzuarbeiten. Dazu muss man dann oft viele GUI Elemente disablen während der Worker-Thread läuft, das ist halt leider einfach so. Zumindest kenne ich keine Magic-Bullet mit der man das vermeiden könnte.

    Soweit jetzt mal allgemein. Spezifischer kann ich nix sagen, da ich ja nicht weiss was du genau machen willst bzw. warum du eine Caption Bar in einem eigenen Thread anzeigen lassen willst.



  • Was bedeutet 'aus dem Thread die CaptionBar anzuzeigen'?

    Generell kannst du mit PostMessage(...) aus einem Thread heraus eine Nachricht an ein Fenster schicken:

    https://msdn.microsoft.com/en-us/library/windows/desktop/ms644944%28v=vs.85%29.aspx


  • Mod

    Warum willst Du das überhaupt. Poste aus dem Thread eine Nachricht....

    Ansonsten ist AfxGetMainWnd auch threadafine. Jeder Thread kann ein vollkommen eigenes Main Wnd haben!



  • Ich arbeite jetzt mit 'PostMessage()', das klappt sehr gut.

    Danke und Gruß.



  • Kurze Frage rein aus Interesse.

    Mit diesem PostMessage() sendest du aus dem Thread heraus eine Nachricht an das MainWnd.

    Um dann dort eine Funktion auszuführen ?

    Gruß



  • @Raggygandalf
    PostMessage steckt eine Message in die Message-Queue eines Fensters.
    Wenn der Thread der das Fenster erzeugt hat Nachrichten abarbeitet ( GetMessage/PeekMessage ), dann wird er irgendwann diese Message aufgreifen und verarbeiten.
    Wobei "verarbeiten" normalerweise heisst DispatchMessage aufzurufen.
    DispatchMessage sucht sich dann anhand des Window Handles die Window Procedure raus, und ruft diese auf.

    Und in der Window Procedure kannst du dann auf die Message reagieren wie auch immer du darauf reagieren willst.

    Wenn man MFC verwendet dann schreibt man normalerweise keine eigene Window Procedure sondern definiert eigene Message Handler in einer sog. "Message Map". Die von MFC bereitgestellte Window Procedure guckt dann halt in der Message Map nach welcher Handler für einen bestimmten Message-Typ eingetragen ist, und ruft diesen Handler dann auf. Ebenso schreibt man normalerweise den Loop der Messages abholt und verarbeitet nicht selbst, sondern verwendet den von der MFC bereitgestellten. Vom Prinzip her bleibt es aber das selbe.



  • Kann man sich dieses prozedere ähnlich wie einen Callback vorstellen?

    Man übergibt nix. Sendet aber einen Befehl um auf irgendwas zu reagieren(Funktion ausführen)?

    Schonmal vielen Dank.

    Gruß



  • Raggygandalf schrieb:

    Kann man sich dieses prozedere ähnlich wie einen Callback vorstellen?

    Man kann vieles.
    Ich weiss jetzt aber spontan nicht was das mit einem Callstack gemeinsam haben soll.

    Ich würde eher sagen du kannst es dir als Liste von Messages vorstellen (bzw. von mir aus std::deque<MSG> wenn du was konkreteres willst). Da kann man hinten Messages anhängen.
    Und vorne welche rausholen.
    Jeder darf anhängen (beliebige Threads), nur einer holt raus (der Thread dem das Fenster gehört).

    Und der Thread der rausholt macht dann pro Message halt (sinngemäss, bzw. oft auch "wörtlich") ein

    switch (m.message) // MSG::message ist das Member in dem der "Message Typ" gespeichert ist
    {
    case WM_PAINT:
        // ... Paint Message behandeln ...
        break;
    
    case WM_CLOSE:
        // ... Close Message behandeln ...
        break;
    
    case MEINE_EIGENE_MESSAGE_ID:
        // ... Eigene Message behandeln ...
        break;
    }
    


  • Ok somit habe ich MFC einen Schritt weit mehr verstanden.

    Vielen Dank 🙂



  • Raggygandalf schrieb:

    Ok somit habe ich MFC einen Schritt weit mehr verstanden.

    Er...
    Mit der MFC hat das jetzt nicht wirklich viel zu tun.
    Die Message-Queue wird von Windows selbst verwaltet.
    Die MFC bietet nur diverse Hilfskonstrukte (Klassen, Makros, Funktionen) an, mittels derer man viele Dinge einfacher machen kann.
    Also das meiste was ich hier beschrieben habe ist total MFC unabhängig.

    Speziell das oben skizzierte switch (m.message) hat man in einem typischen MFC Programm nicht. Dort würde man eher die Message Map Makros der MFC verwenden.



  • Mhh ok.

    Muss sagen MFC/Windowsprogrammierung ist doch recht komplex 🙄

    Aber ok. Ich stehe hier noch relativ am Anfang.

    Die MessageMap ansich hatte ich auch gemeint. Welche ja in MFC verwendet wird. Dachte das wäre das gleiche. Aber da habe ich mich wohl geirrt. 🙄

    Trotzdem vielen Dank



  • In deinem ZielFenster:

    CMyThread* pClientThread = (CMyThread*)AfxBeginThread(RUNTIME_CLASS(CMyThread), THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
    pClientThread->SetTarget( this );
    pClientThread->ResumeThread();
    

    In deinem thread:

    CWnd *target;
    void SetTarget(CWnd *w) { target = w; }
    

    Dann kannst du so Sachen wie

    target->PostMessage(UWM_THREADSTART, (WPARAM) test_thread, (LPARAM)m_nThreadID);
    

    und im ZielFenster:

    ON_MESSAGE(UWM_THREADSTART, OnThreadStart)
    

    machen.


Log in to reply