CallbackOnCollectorDelegate



  • Hallo Leute,
    in meiner Voice-over-IP App (c++/cli) empfange ich mit der Callback Funktion eines MessageOnlyWindow, das ich WSAAsyncSelect übergab, einen Buffercontent :

    case FD_READ:
    		{
    		loc_bufferrec = new char[length];				
    		error = recv_loc (SOCKET_loc, loc_bufferrec, length, 0); 
    	         if (error == SOCKET_ERROR)
    		   {	
    		    error = WSAGetLastError();
                          Settext(String::Concat("recv_ERROR:",error.ToString());
                         }
    		else memcpy(bufferout, loc_bufferrec, length);	
    		}
     break;
    

    Der Buffercontent soll natürlich über den Lautsprecher ausgegeben werden, dazu verwende ich den Callback „VoiceWaveOutProc“, den ich waveOutOpen übergeben
    habe:

    bool VoiceWaveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
    {
    if (uMsg==WOM_DONE)
    	{
    	//while(mem_locked_rec) Sleep(1);
             WaveHeaderout.lpData=bufferout;
    	MMRESULT lokresult =
              Loc_waveOutPrepareHeader(hWaveOut,&WaveHeaderout,sizeof(WAVEHDR));
    	  if(lokresult != MMSYSERR_NOERROR) Settext("Error1");//return false;
    	  lokresult =    
            Loc_waveOutWrite(hWaveOut,&WaveHeaderout,sizeof(WAVEHDR));	
            if(lokresult != MMSYSERR_NOERROR) Settext("Error2");//return false;
    	  }
    	return TRUE;
        }
    

    Vom knacken (http://programmersheaven.com/discussion/26588/how-to-suppress-gaps-between-waveoutwrite-calls) mal abgesehen funktioniert das Ganze etwa 1-2 min und wird dann durch folgenden Absturz beendet:

    CallbackOnCollectorDelegate wurde erkannt:
    Für den von der Garbage Collection gesammelten Delegaten vom Typ "WaveDotNet!WaveDotNet.VoiceWaveOutProcPTRDelegator::Invoke" wurde ein Rückruf durchgeführt. Dies kann Anwendungsabstürze, Datenbeschädigung und -verlust zur Folge haben. Beim Übergeben von Delegaten an nicht verwalteten Code müssen die Delegaten von der verwalteten Anwendung beibehalten werden, bis sichergestellt ist, dass sie nie aufgerufen werden.

    Also wie gesagt, wenn mir irgendjemand die Doku für den oben genannten Error näher erklären kann, wäre ich sehr dankbar. Neben meiner Vermutung, dass ich hier die dotnet mit Win32Code erheblich zweckentfremdet habe, nehme ich an, dass der Fehler entweder durch gleichzeitige Zugriffe auf “bufferout“ entsteht, oder der Fehler wird durch meine Settext – Funktion verursacht:

    delegate void labeltext(String^text);
    void  Settext(String^text) {
    	if (this->InvokeRequired)
            {
                labeltext^ d = 
                gcnew labeltext(this, &Form1:: Settext);
    			this->Invoke(d, gcnew array<Object^> { text});
            }
            else
            {
            this->richTextBox1->Text = text + "\r" + richTextBox1->Text ;
            }
    }
    

    Vielen Dank schon mal für Hinweise (WIN32 oder MFC will nicht nehmen und c# oder vb werde ich niemals freiwillg verwenden und dotnet- Routinen sind mir zu langsam).
    MfG



  • Oje. Dein Code macht einem ja Angst. Genau DU wärst mit C# besser bedient. Auch mit C++. Aber mit dem Gemisch aus C, C++ und C++/CLI hast du dir viel Ärger aufgehalst.

    loc_bufferrec wird nicht freigegeben ( delete[] ), ich schätze nach dem Kopieren nach bufferout wird er nicht mehr gebraucht.

    Die Fehlermeldung sagt, dass ein Delegate (.NET) an unmanaged Code übergeben wurde, welcher aufgerufen wird, obwohl schon vom GC weggeräumt. Ich gehen davon aus, dass irgendwo (meiner Meinung nach nicht im gezeigten Code) eine Delegate übergeben wird, welcher an VoiceWaveOutProc gebunden wird. Du musst dafür sorgen, dass eben dieser Delegate nicht von der GC weggeräumt wird, solange die (native) Funktion noch aktiv ist, an der du den Delegate übergeben hast.

    Zeig doch mal wo du den entsprechenden Delegate erzeugst.



  • Hallo und Danke für den Beitrag –
    tatsächlich wird der Absturz genau in dem Moment verursacht, wenn der GC::Collect durchführt und damit den Delegaten löscht. Der Zeiger auf den Callback bleibt aber im namespace gespeichert. Ich könnte auch den Delegaten speichern, aber ich verstehe nicht wozu. Ich verstehe außerdem nicht, was die Ursache für die ständigen Rückrufe auf Delegate::Invoke sein könnten, bzw. was diese Rückrufe auslöst oder geschweige denn, wozu diese überhaupt gut sein sollen. Gibt es da irgendeinen Link, wo etwas dazu steht ?



  • Ok ich konnte meine Fragen weitgehend klären-

    falls jemand eine ähnliche Frage haben sollte – hier steht was brauchbares zu Delegate:: Invoke
    http://msdn.microsoft.com/de-de/library/zyzhdc6b(v=vs.110).aspx


Anmelden zum Antworten