Referenz auf String geht verloren, nachdem ich die Funktion ISpVoice->Speak() aufrufe
-
Ich bin von Visual C++ 2003 Standard auf Visual Studio 2005 Professional umgestiegen. (Soweit ich weiß tritt das Problem jetzt erst auf. Vorher hatte ich es nicht)
Ich nutze zur Sprachausgabe die Funktion ISpVoice->Speak().
Nun hab ich in VS2005 das Problem, das ich die Referenz auf den WCHAR* verliere. Würde ich die WCHAR* nämlich nach Aufruf von Speak löschen, dann funktioniert die Sprachausgabe nicht mehr richtig. Vielleicht hat es auch mit den secure Funktionen ( "..._s" ) zu tun, auf die ich vieles umgestellt habe...
Dazu das Beispiel:
void GSpeak::Speak(GString Text) // GString funktioniert genauso wie string { WCHAR *WString=new WCHAR[Text.Length()+1]; size_t count; mbstowcs_s(&count,WString,Text.Length()+1,Text.c_str(),Text.Length()); a.Stimme->Speak(WString,SPF_ASYNC,0); delete[] WString; // ist diese Zeile da kann der String nicht gesprochen werden und die Ausgabe wird abgebrochen // ist die Zeile hingegen auskommentiert haben wir doch nach fertigreden eine Speicherleiche oder }
-
Gehe ich recht in der Annahme, daß die Sprachausgabe von Speak() nur gestartet wird (das SPF_ASYNC deutet zumindest darauf hin ;))? In dem Fall muß der String so lange gültig bleiben, bis dein Rechner ihn fertig vorgelesen hat. D.h. du müsstest irgendwie erkennen, wann die Sprachausgabe fertig ist - und danach delete[] aufrufen (so lange mußt du die Adresse mindestens aufbewahren).
-
Du kannst ja testweise erstmal statt SPF_ASYNC eifnach SPF_DEFAULT verwenden.
Ich habe allerdings keine Ahnung, von der SAPI.
-
hm danke euch beiden
Ja wenn ich SPF_DEFAULT nehme dann bleibt kommt er erst dann aus der Funktion, wenn der String komplett gelesen wurde. (und ich kann ihn löschen) Gewollt ist aber so wie jetzt die Sprachausgabe nur gestartet wird.
Mich wundert nur, dass es scheinbar mal funktionierte. Und jetzt mit Umstieg auf VS 2005 nicht mehr klappt. (Meiner Meinung ist es auch vernünftig von dem übergebenen String im Objekt eine Kopie zu erstellen, statt auf die Adresse zuzugreifen [so schien es damals zu funktionieren])
Hatte gedacht, dass es an mir liegen könnte. Hab jetzt ne Liste, wo ich jeden String reinpushe, und die ich leere, wenn keine Stimme zu hören ist. (Wenn noch gesprochen wird, und wieder ein Aufruf kommt, wird es nach Ausreden angehangen, deswegen die Liste.)
Wäre dankbar für Anmerkungen für eine bessere Lösung.
-
Ich vermute eher, daß du bei der älteren Version Glück hattest und der delete[]-Aufruf dem Heap-Manager nur mitgeteilt hat, daß der entsprechende Block wieder verwendbar ist (im Klartext - die Daten sind zufälligerweise erhalten geblieben, bis das nächste Mal Speicher per new angefordert wurde).
Randfrage: Von wo aus bekommst du denn den auszugebenden String? Eventuell kannst du dir ja die ganze Speicherverwaltung ersparen, indem du den Text per Referenz übergibst - und dessen c_str() direkt weiterreichst.
PS: Ich hoffe mal, das Programm stellt ohne Fremdeingriff fest, wann es fertig ist mit Vorlesen

-
Deine Vermutung, dass die Daten "zufälligerweise erhalten geblieben" sind, ist ziemlich gut. Sorum hatte ich nicht gedacht, und das würde echt einiges erklären.
Die Klasse die ich programmiere soll beliebig gebraucht werden. Das ist nicht festgelegt. Also man soll sie Aufrufen, und den String dann sofort löschen können. (Das muss aber nicht der Normalfall sein)
Aber Referenz übergeben geht doch auch deswegen nicht weil ich (WCHAR*) brauche und nicht (char*) - oder lieg ich da falsch.
Das prüfen ob alte Strings gelöscht werden können, wird vor jedem neuen Aufruf etwas zu Sprechen gemacht. Wenn lang nicht gesprochen wird ist halt ein String im Speicher. Aber besser als da zu pollen, oder so.
-
Samuel Plentz schrieb:
Die Klasse die ich programmiere soll beliebig gebraucht werden. Das ist nicht festgelegt. Also man soll sie Aufrufen, und den String dann sofort löschen können. (Das muss aber nicht der Normalfall sein)
Gut, wenn du nicht sicher sein kannst, woher der String kommt, mußt du vom schlimmsten Fall ausgehen - und das bedeutet, daß du tatsächlich eine Kopie aufheben solltest, bis sie nicht mehr gebraucht wird.
Aber Referenz übergeben geht doch auch deswegen nicht weil ich (WCHAR*) brauche und nicht (char*) - oder lieg ich da falsch.
Stimmt, das hatte ich für einen Moment übersehen.
Das prüfen ob alte Strings gelöscht werden können, wird vor jedem neuen Aufruf etwas zu Sprechen gemacht. Wenn lang nicht gesprochen wird ist halt ein String im Speicher. Aber besser als da zu pollen, oder so.
Ich kenne die verwendete Bibliothek nicht genau, aber was genau kannst du als dritten Parameter an die Speak()-Methode übergeben? Vielleicht gibt es dort eine Möglichkeit, sich das Ende des Diktats rückmelden zu lassen.
-
Das wohl eher nicht. Es gibt aber auch SpeakCompleteEvent welcher das Ende anzeigt.
siehe hier
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/SAPI51sr/html/ISpVoice.asp
-
Das wohl eher nicht.
Wollte ich auch sagen und bezieht sich auf den dritten Parameter in der Speak()-Methode.
Zum SpeakCompleteEvent: (hab ich auch grade gefunden) Ich glaub ich werd es so wie es jetzt ist machen. Ich will die Klasse auch einfach mit folgenden 2 Zeilen nutzen können:
GSpeak s; s.Speak("Alle Programmierer sagen Hallo Welt, aber das ist doch irgendwann ausgelutscht oder? Es könnte der Verdacht entstehen, dass Programmierer unkreativ seien...")Also ohne erst irgendwie an einen Eventhandler zu denken. (Callback wäre ok gewesen, da das dann ja innerhalb der Klasse wäre, aber so.)
Aber nochmals vielen Dank für die schnellen Antworten.