Dlg-Pointer übergeben



  • hallo!
    wenn ich einen pointer auf ein Dialogfeld woanders hin übergebe schreit im Debug-Modus ein assert wo drunter folgender Kommentar steht:

    // Note: if either of the above asserts fire and you are
    // writing a multithreaded application, it is likely that
    // you have passed a C++ object from one thread to another
    // and have used that object in a way that was not intended.
    // (only simple inline wrapper functions should be used)
    //
    // In general, CWnd objects should be passed by HWND from
    // one thread to another.  The receiving thread can wrap
    // the HWND with a CWnd object by using CWnd::FromHandle.
    //
    // It is dangerous to pass C++ objects from one thread to
    // another, unless the objects are designed to be used in
    // such a manner.
    

    Also habe ich den betreffenden Code wie folgt umgeschrieben:

    m_pDlg = (CDialogXYZ *)CWnd::FromHandle(hwnd);
    

    -> ***CRASH***

    Also wieder umgeschrieben:

    m_pDlg = static_cast<CDialogXYZ *>(CWnd::FromHandle(hwnd));
    

    -> ***CRASH***

    ???
    Tja, und jetzt weiß ich nicht mehr weiter....

    kann mir jemand helfen?

    danke
    matthias



  • die frage ist ??

    if (hwnd && ::IsWindow(hwnd))
    {
      // alles ok
      m_pDlg = (CDialogXYZ *)CWnd::FromHandle(hwnd);
    }
    else
    {
      kein gültiges fester-handle
    }
    

    volker



  • *lol*
    Also so ausgebufft scheinst Du noch nicht zu sein.

    you have passed a C++ object from one thread to another

    Szenario:
    Du stehst in Raum1 und versuchst, ohne Hilfsmittel den Fernseher in Raum2 anzuschalten. Und dazu fällt Dir folgendes ein:
    ((Raum2)Raum1)->FernseherAn.
    Sozusagen: "Weil ich zu faul bin, in Raum2 zu gehen, definiere ich Raum1 einfach als Raum2 und schon hab ich den TV vor mir! 😃 😃



  • @vdittrich
    Falsch, denn hWnd ist gültig und IsWindow( hWnd) ist auch gültig, aber
    CWnd::FromHandle( hWnd) ist ungültig, weil man das Drumherum um das HWND, also die CWnd-Klasse aufgrund fehlender Thread-Synchronisation nicht einfach von einem Thread in einen anderen übernehmen kann.

    [ Dieser Beitrag wurde am 17.04.2003 um 14:45 Uhr von RenéG editiert. ]



  • @rene

    warum sollte ich nicht ein fester-handle von einen Thread in den anderen Thread übergeben, und mir daraus eine Klasse vom typ CWnd zurückgeben.

    kritsch wird es erst doch wenn festerhandle gar nicht vom typ dialog ist und aber funktion dafür aufrufen will.

    volker



  • Und wie macht man es dann? Wenn ich eine Variable meines CDialogXYZ von einem Thread aus ändern will, kann ich ja noch mit SendMessage arbeiten (ist aber unschön). Aber wenn ich den Wert einer Variablem auslesen will???



  • @rene wirde ich dir widersprechen wollen,

    da ich ich selber das problem hatte, das thread 2 mir eine anderen pointer zurückgab als thread 1 bei gleichen fensterhandle.

    ???

    volker



  • warum sollte ich nicht ein fester-handle von einen Thread in den anderen Thread übergeben

    Ich sagte ja auch nicht, dass es falsch ist, das Fensterhandle zu übergeben, dass steht ja selbst als Workaround im Kommentar siehe oben!



  • m_nThreadID=::GetCurrentThreadId(); der App-> nicht des thread

    PostThreadMessage(m_nThreadID, msg, (WPARAM)VDB_OPEN, 0);



  • da ich ich selber das problem hatte, das thread 2 mir eine anderen pointer zurückgab als thread 1 bei gleichen fensterhandle.

    Genau das ist der Fehler. Da CWnd::FromHandle im aktuellen Thread das Fenster nicht findet, legt es einfach ein neues an, obwohl es schon im anderen Thread existiert. Solange es sich nur um ein reines CWnd handelt, funktioniert das auch, aber sobald auf eigenen Datenspeicher zugegriffen werden soll, nicht mehr. Denn die Kopie in Thread1 ist eine andere als die in Thread2.



  • Und wie macht man es dann? Wenn ich eine Variable meines CDialogXYZ von einem Thread aus ändern will, kann ich ja noch mit SendMessage arbeiten (ist aber unschön). Aber wenn ich den Wert einer Variablem auslesen will???



  • Und wie macht man es dann? Wenn ich eine Variable meines CDialogXYZ von einem Thread aus ändern will, kann ich ja noch mit SendMessage arbeiten (ist aber unschön). Aber wenn ich den Wert einer Variablem auslesen will???

    geht ehendlich nur über PostThreadMessage als sender und

    m_nThreadID=::GetCurrentThreadId(); 
      VERIFY(m_hHook=::SetWindowsHookEx(WH_GETMESSAGE, &CRegDEx::_GetMsgProc, \
                                        NULL, m_nThreadID));
    
    LRESULT CRegDEx::GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
      LPMSG lpMsg=(LPMSG)lParam; 
      if ( nCode >= 0 && PM_REMOVE == wParam && lpMsg->hwnd==0)
      {
        switch (lpMsg->message)
        {
          case WM_THREAD_MYSQL:
            TRACE("CRegDEx::GetMsgProc State:%i\n", lpMsg->wParam);
            {
            }
            break;
        }
      }
      return CallNextHookEx(m_hHook, nCode, wParam, lParam);
    }
    
    oder über MFC
    

    als empfänger, synconisation hilft nicht

    volker



  • Wenn ich eine Variable meines

    für variablen greift syncronisation über CCriticalSection und die klasse bzw. pointer übergibst du ganz normal.

    CCriticalSection m_cs;

    {
    CSingleLock cLock(&m_cs, true); //lock
    // jetzt kannst du mit deiner klassse arbeiten

    }
    // unlock da ->} oder cLock.Unlock();



  • Stichwort Threadsynchronisation, dafür gibts mächtig viele Seiten Literatur!
    Man muss andere Threads davon ausschliessen, auf die Variablen zuzugreifen, wenn man sie gerade ändern will.

    Effizient ist hier 'ne Critical Section, da sie feststellt, von welchem Thread aus der Lock() erfolgt und somit einen weiteren Zugriff vom gleichen Thread aus nicht blockiert, während andere Synchronisationsobjekte schon blockieren würden.

    FAQ:
    F:Wie kann ich nun von mehreren Threads auf die gleiche CWnd-Klasse zugreifen?
    A:Einfach den CWnd-Zeiger übergeben.

    F:Wie muss ich Zugriffe auf die Variable synchronisieren?
    A:

    class CMyWnd : public CWnd
    {
      int m_Member;
      CCriticalSection m_cs;
    public:
      void IncMember()
      {
        CSingleLock lock( &m_cs, TRUE);
        if( lock.IsLocked())
        {
          m_Member++;
        }
        // lock.Unlock();  // wird automatisch aufgerufen
      }
    };
    

    [ Dieser Beitrag wurde am 17.04.2003 um 15:14 Uhr von RenéG editiert. ]



  • @RenéG: Wenn ich das so wie in deinem letzten Posting mache, kann ich mit

    m_pDlg = (CDialogXYZ *)CWnd::FromHandle(hwnd);
    BOOL m_pDlg->IsFinished(); // wobei IsFinished() eine CS benutzt
    

    aus jedem Thread auf eine Dialog zugreifen?



  • Nein, wie schon in Frage 1 beantwortet, Du musst den Zeiger auf das CWnd an den Thread übergeben, NICHT das HWND. Dann fällt nämlich auch die Methode CWnd::FromHandle flach!

    + Beispiel:

    CMeinDialog::BeginneThread()
    {
      AfxBeginThread( MeinThread, (LPVOID)this...); // hier wird der Zeiger auf  CMeinDialog an den Thread übergeben
    }
    
    UINT MeinThread( LPVOID pParam)
    {
      CMeinDialog* pDlg = (CMeinDialog*)pParam;
      // Zugriffe auf synchronisierte Memberfunktionen von CMeinDialog
      return 0;
    }
    

    Wenn man sich ganz ganz sicher ist, dass es keine Synchronisationsprobleme geben kann, kann man die Synchronisation auch weglassen, was die Zugriffe sehr beschleunigt.

    [ Dieser Beitrag wurde am 17.04.2003 um 15:24 Uhr von RenéG editiert. ]



  • Danke für das Beispiel. 🙂 seltsam... bei mir wurde auf CMeinDialog-Member immer nur von einem Thread aus zugegriffen und dennoch kam diese Assertion failed.



  • wo und im welchen zusammenhang ??



  • @vdittrich: schau mal in "CAsyncSocket oder ...."



  • Zur letzten Antwort von RenéG:
    SO GEHT ES EBEN NICHT! So habe ich es früher gemacht und da kommt ja genau dieses Assertion failure!

    Ich weiß jetzt warum er bei der static_cast methode auch gecrasht ist: Weil ich der SetParentDlg Funktion der betreffenden Klasse einen ungültigen hwnd gegeben habe... (habe GetSafeHwnd() fatalerweise schon im konstruktor meiner Fensterklasse aufgerufen)

    Mit dieser rauf-Cast-methode gibt er eine weile ruhe mit den asserts, aber wenn ich anschließend wieder irgend wo anders mit diesem pointer arbeite passiert wieder dasselbe.
    Und wisst ihr was: Der kann mich mal! Mittlerweile bin ich mal wieder soweit, dass ich alles einfach unter release kompilliere ... *gg*

    matthias


Anmelden zum Antworten