Com verlangt MTA-Thread habe aber STA



  • Ich arbeite derzeitig gerade an einem DirectSound Wrapper. Dieser funktioniert auch recht gut, jedoch leider nicht ganz. Abspielen ist in jedem Thread kein Problem doch sobald ich von z.B. einem GUI-Thread die Lautstärke über http://msdn.microsoft.com/en-us/library/ms897852.aspx setzen möchte bekomme ich eine E_NOINTERFACE Exception. Nach sehr sehr langem suchen bin ich draufgekommen, dass es daran liegt, dass diese Methode von einem MTAThread aus aufgerufen werden muss. Nun Frage ich mich ist es nicht möglich, dass ich das Com-Interface für beide Threads kompatibel mache, da es sich um eine Bibliothek handelt und diese somit beide Arten von Threads unterstützen sollte 😞

    Hier ist noch der Code des Interfaces, das betroffen ist:

    /// <summary>
        /// Line 687 Dsound.h
        /// </summary>
        [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
        Guid("279AFA85-4981-11CE-A521-0020AF0BE560")]
        public interface IDirectSoundBuffer : IUnknown
        {
            //int QueryInterface(ref Guid guid, out IntPtr comObject);
            //int AddReference();
            //int Release();
    
            //IDirectSoundBuffer methods
            void GetCaps([MarshalAs(UnmanagedType.LPStruct)] DSBufferCaps pDSBufferCaps); //TODO
            void GetCurrentPosition([Out] out UInt32 pdwCurrentPlayCursor, [Out] out UInt32 pdwCurrentWriteCursor);
            void GetFormat([Out, MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "AMEngine.Wave.WaveFormatMarshaler")] out AMEngine.Wave.WaveFormat pwfxFormat,
                            int dwSizeAllocated, [Out] out int pdwSizeWritten); //TODO implement
            [return: MarshalAs(UnmanagedType.I4) /*See http://msdn.microsoft.com/en-us/library/aa288468%28v=vs.71%29.aspx */]
            Int32 GetVolume();
            [return: MarshalAs(UnmanagedType.I4)]
            Int32 GetPan();
            [return: MarshalAs(UnmanagedType.I4)]
            Int32 GetFrequency();
            [return: MarshalAs(UnmanagedType.I4)]
            Int32 GetStatus();
            void Initialize([In, MarshalAs(UnmanagedType.Interface)] IDirectSound pDirectSound, [In] DSBufferDescription pcDSBufferDesc);
            void Lock(int dwOffset, int dwBytes,
                      [Out] out IntPtr ppvAudioPtr1, [Out] out int pdwAudioBytes1,
                      [Out] out IntPtr ppvAudioPtr2, [Out] out int pdwAudioBytes2,
                      DSBLock dwFlags /*TODO Flags enum erstellen */);
            void Play(int dwReserved1, int dwPriority, DSBPlayFlags dwFlags); //TODO Flags enum erstellen -- Done
            void SetCurrentPosition(int dwNewPosition);
            void SetFormat([In] AMEngine.Wave.WaveFormat pcfxFormat);
            void SetVolume(int lVolume);
            void SetPan(int lPan);
            void SetFrequency(int dwFrequency);
            void Stop();
            void Unlock([In] IntPtr pvAudioPtr1, int dwAudioBytes1,
                        [In] IntPtr pvAudioPtr2, int dwAudioBytes2);
            void Restore();
        }
    


  • Ich bin mir nicht sicher ob Deine Schlußfolgerung richtig ist. Daher erstmal die Grundsätzliche Frage:

    Ist Dir bewußt das Du für jeden(!) Thread der COM-Objekte benutzen soll explizit CoInitialize aufrufen mußt? (Nicht einmal pro Applikation sondern wirklich für jeden einzelnen Thread)

    Vergisst man das, dann können einzelne Sachen schiefgehen obwohl es so aussieht das man alles richtig macht.

    http://msdn.microsoft.com/en-us/library/windows/desktop/ms678543(v=vs.85).aspx



  • hmm das ist auch interessant. Bin gestern Abend drauf gekommen, dass es am daran liegt, dass das Zeug auf MTAThreads läuft aber nicht auf STAThreads. Hängt das damit zusammen?



  • verzeifelt 001 schrieb:

    hmm das ist auch interessant. Bin gestern Abend drauf gekommen, dass es am daran liegt, dass das Zeug auf MTAThreads läuft aber nicht auf STAThreads. Hängt das damit zusammen?

    Hängt es damit zusammen? Ja. Aber trotzdem ist die Aussage (wahrscheinlich) falsch. Die Methoden müssen sowohl in MTA als auch in STA gleichermassen funktionieren. Der Unterscheid zwischen MTA und STA liegt ja nur darin wer fürs die Thread-Safety verantwortlich ist.

    Bei STA passiert es Vollautomatisch indem jeder Aufruf einer Methode in den Thread hinein marshalled wird in dem das Objekt erzeugt wurde. Vorteil: Man muß sich keinen Kopf um Thread-Safety machen weil praktisch alle Methoden in einem Thread aufgerufen werden. Nachteil: Potentieller Performanceverlust durch das Marshallen.

    Bei MTA liegt es am Entwickler die Thread-safety Sicherzustellen. Vergisst man es oder macht es falsch dann kann alles Mögliche passieren inklusive natürlich das es augenscheinlich alles funktioinert und nur gelegentlich unerklärliche Abstürze produziert. Aber auch die von Dir beschrieben Probleme können dann auftreten.

    Das Einzige was nicht geht ist beide Methoden zu vermischen. Entweder alles STA oder alles MTA. Dein Problem klingt danach als würden die DirectShow-Objekte in einem MTA-Thread erzeugt und dann aus einem STA-Thread heraus Methoden auf den Objekten aufgerufen.

    Da der GUI-Thread STA sein muß würde ich im ersten Ansatz den erzeugenden Thread ebenfalls auf STA setzen mit Thread.SetApartmentState(...)



  • Da kann ich dir nicht zustimmen. Ich erzeuge die Coms in einem STA Thread. Und außerdem funktionieren nur 2-3 Member in einem STA Thread nicht.

    Und wie sorgt man den nun für die Threadsafty?

    Außerdem verwende ich kein DirectShow. Ich verwende DirectSound und zwar eben keine fertige Bibliothek sondern ich portiere die Headerdateien.



  • verzeifelt 001 schrieb:

    Außerdem verwende ich kein DirectShow. Ich verwende DirectSound und zwar eben keine fertige Bibliothek sondern ich portiere die Headerdateien.

    Vollkommen egal, es handelt sich in beiden Fällen doch um COM-Objekte und da gelten die gleichen Regeln.



  • Ok ich hab nochmal genauer darüber nachgedacht.
    Ein Teil hat tatsächlich gestimmt es gab einen MTA Thread aus dem die im Hauptthread erzeugen Interfaces überschrieben wurden. Ich habe dies nun beseitigt und alle Threads testweise auf STA umgestellt. Kein neues Resultat. Weiterhin ein Fehler.


Anmelden zum Antworten