Funktion aus einem Thread aufrufen will nicht klappen



  • Hi zusammen

    ich hab folgendes problem.

    Eine Funktion soll eine Textfeld Aktualisieren.
    aber diese Funktion wir aus einem Thread her aus aufgerufen.
    dann habe ich folgende fehler meldung

    c:\dokumente und einstellungen\8 directmidi2 mit midi file lesen\directmidi2dlg.cpp(826): error C2352: 'CDirectMidi2Dlg::Anzeige::CDirectMidi2Dlg::Anzeige': Unzulässiger Aufruf einer nicht statischen Memberfunktion

    in.h
    void Anzeige(int Wert);
    in.cpp
    void CDirectMidi2Dlg:: Anzeige(int Wert)
    {
    m_sMixAnzeige.Format("%d",Wert);
    UpdateData(false);
    }

    in .h
    static UINT ProcessPlayArray(LPVOID lpParam); // Entry point for the playback thread

    in.cpp
    UINT CDirectMidi2Dlg::ProcessPlayArray(LPVOID lpParam)
    {
    Anzeige(wert++);// fehler

    }

    wie kann ich aus einem thread eine Textfeld Aktualisiren?
    ich weiss net was ich machen soll.

    Für Hilfe besten danke..
    Grüße Can



  • Hi,

    Du kannst die Funktion nicht aufrufen, weil es eine Memberfunktion der Klasse ist.
    Zudem wird dir UpdateData um die Ohren fliegen, wenn du aus einem Thread heraus
    aufrufst.
    Das sind die täglichen Probleme, mit denen man bei Threads zu kämpfen hat.
    Lösung ist, Nachrichten zu senden.

    Wenn ich das richtig sehe, ist der LPVOID-Parameter in der Thread-Funktion frei.
    Das ist gut! 😉
    Den solltest du für den this-Zeiger der Klasse verwenden. Damit hast Du schon mal zugriff
    auf die Klasse.

    // da wo der Thread gestartet wird
    void CDirectMidi2Dlg::StartThread()
    {
       AfxBeginThread(ProcessPlayArray, this);
    }
    
    UINT CDirectMidi2Dlg::ProcessPlayArray(LPVOID lpParam) 
    { 
       CDirectMidi2Dlg* pThis = reinterpret_cast<CDirectMidi2Dlg*>(lpParam);
    
       // das geht leider nicht, weil UpdateData kracht!
       pThis->Anzeige(wert++);// fehler 
    }
    

    Dann gibst du der Klasse eine Member für die Variable 'wert'.

    Diese kannst Du in den Thread dann erhöhen.

    Anschließend könntest Du eine WM_COMMAND an deine Klasse senden, die dann
    das Update des Textfeldes macht. Dafür legst Du dir eine Command ID an.

    // DirectMidi2Dlg.h
    class CDirectMidi2Dlg
    {
    public:
       afx_msg OnUpdateTextField();
    
    private:
       UINT m_wert;
    };
    
    //DirectMidi2Dlg.cpp
    
    #define ID_UPDATE_TEXTFIELD // entweder hier definieren oder in der resourcen-datei
    
    // in der Message-Map
    BEGIN_MESSAGE_MAP(CDirectMidi2Dlg, CDialog)
       ON_COMMAND(ID_UPDATE_TEXTFIELD, OnUpdateTextField)
    END_MESSAGE_MAP()
    
    // da wo der Thread gestartet wird
    void CDirectMidi2Dlg::StartThread()
    {
       AfxBeginThread(ProcessPlayArray, this);
    }
    
    void 
    
    UINT CDirectMidi2Dlg::ProcessPlayArray(LPVOID lpParam) 
    { 
       CDirectMidi2Dlg* pThis = reinterpret_cast<CDirectMidi2Dlg*>(lpParam);
    
       pThis->m_wert++; // Member ändern
    
       pThis->SendMessage(WM_COMMAND, ID_UPDATE_TEXTFIELD); // Nachricht zum Update aufrufen
    } 
    
    void CDirectMidi2Dlg::OnUpdateTextField()
    {
       m_sMixAnzeige.Format("%d", m_wert); 
    
       UpdateData(false); 
    }
    

    So sollte es klappen.

    Wenn du m_wert noch an anderen Stellen verwendest, must du dich noch mit Synchronisation ausinandersetzen.

    In diesem fall jedoch nicht, da der Dialog nicht an m_wert herumfummelt und nur
    der Thread die Variable ändert und die Nachricht mit SendMessage versendet
    statt mit PostMessage.

    Gruss
    EB



  • Habe noch zwei Fehler entdeckt...

    // DirectMidi2Dlg.h
    class CDirectMidi2Dlg
    {
    public:
       afx_msg void OnUpdateTextField(); // das void fehlte
    
    private:
       UINT m_wert;
    };
    
    //DirectMidi2Dlg.cpp
    
    #define ID_UPDATE_TEXTFIELD 300 // muss natürlich einen Wert haben...
    

    jetzt aber... 😉

    Gruss
    EB



  • Ok, hier mal ein kurzer Überblick

    CDlg.h

    class CDlg::CDialog(IDD_DLG) {
    private:
      void process();
      static UINT THREAD(LPVIOD);
    
      typedef void(CDlg::*f)(void);
    
      struct t_data {
        t_data(CDlg* pDlg_, f pFunc_)
          : pDlg(pDlg_), pFunc(pFunc_) {}
    
        ~t_data() {
          pDlg = 0;
          pFunc = 0;
        }
    
        void operator() () {
          if(pDlf && pFunc) 
            (pDlg->*pFunc)();
        }
        private:
          CDlg* pDlg;
          f pFunc;
      };
    }
    

    CDlg.cpp

    void CDlg::process() {
      // mach was..
    }
    
    BOOL CDlg::OnInitDialog() {
      AfxBeginThread(THREAD, new t_data(this, process));
      return TRUE;
    }
    
    UINT CDlg::THREAD(LPVOID param) {
      t_data *data = static_cast<t_data*>(param);
      (*data)(); // hier wird eignentliche Funktion deiner Klasse aufgerufen.
      delete data;
      return 0;
    }
    

    Das ganze hat den Vorteil, dass alle Funktionen Member deiner Klasse sind.
    Du brauchst keine public-Methoden die du aus dem Thread aufrufen kannst.
    Durch die Übergabe der Klasseninstanz wird das alles auch noch ein bisschen sicherer.

    Viel Spaß.



  • 1001 Dank! EB und hehejo
    Für die tolle erklärung mit code..

    Funktioniert super!

    Grüße can


Anmelden zum Antworten