| File: Internal\SapiInterop\SapiProxy.cs | Web Access |
| Project: src\runtime\src\libraries\System.Speech\src\System.Speech.csproj (System.Speech) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Threading; namespace System.Speech.Internal.SapiInterop { internal abstract class SapiProxy(ISpRecognizer recognizer) : IDisposable { #region Constructors public virtual void Dispose() { GC.SuppressFinalize(this); } #endregion #region Internal Methods internal abstract object? Invoke(ObjectDelegate pfn); internal abstract void Invoke2(VoidDelegate pfn); #endregion #region Internal Properties internal ISpRecognizer Recognizer { get { return _recognizer; } } internal ISpRecognizer2 Recognizer2 => _recognizer2 ??= (ISpRecognizer2)_recognizer; internal ISpeechRecognizer SapiSpeechRecognizer => _speechRecognizer ??= (ISpeechRecognizer)_recognizer; #endregion #region Protected Fields protected ISpeechRecognizer? _speechRecognizer; protected ISpRecognizer2? _recognizer2; protected ISpRecognizer _recognizer = recognizer; #endregion #region Protected Fields internal class PassThrough : SapiProxy, IDisposable { #region Constructors internal PassThrough(ISpRecognizer recognizer) : base(recognizer) { } ~PassThrough() { Dispose(false); } public override void Dispose() { try { Dispose(true); } finally { base.Dispose(); } } #endregion #region Internal Methods internal override object? Invoke(ObjectDelegate pfn) { return pfn.Invoke(); } internal override void Invoke2(VoidDelegate pfn) { pfn.Invoke(); } #endregion #region Private Methods private void Dispose(bool disposing) { _recognizer2 = null; _speechRecognizer = null; Marshal.ReleaseComObject(_recognizer); } #endregion } internal class MTAThread : SapiProxy, IDisposable { #region Constructors internal MTAThread(SapiRecognizer.RecognizerType type) : base(null!) // Set _recognizer field instead of base constructor { _mta = new Thread(new ThreadStart(SapiMTAThread)); if (!_mta.TrySetApartmentState(ApartmentState.MTA)) { throw new InvalidOperationException(); } _mta.IsBackground = true; _mta.Start(); if (type == SapiRecognizer.RecognizerType.InProc) { Invoke2(delegate { _recognizer = (ISpRecognizer)new SpInprocRecognizer(); }); } else { Invoke2(delegate { _recognizer = (ISpRecognizer)new SpSharedRecognizer(); }); } System.Diagnostics.Debug.Assert(_recognizer is not null); } ~MTAThread() { Dispose(false); } public override void Dispose() { try { Dispose(true); } finally { base.Dispose(); } } #endregion #region Internal Methods internal override object? Invoke(ObjectDelegate pfn) { lock (this) { _doit = pfn; _process.Set(); _done.WaitOne(); if (_exception == null) { return _result; } else { ExceptionDispatchInfo.Throw(_exception); return null; } } } internal override void Invoke2(VoidDelegate pfn) { lock (this) { _doit2 = pfn; _process.Set(); _done.WaitOne(); if (_exception != null) { ExceptionDispatchInfo.Throw(_exception); } } } #endregion #region Private Methods private void Dispose(bool disposing) { lock (this) { _recognizer2 = null; _speechRecognizer = null; Invoke2(delegate { Marshal.ReleaseComObject(_recognizer); }); ((IDisposable)_process).Dispose(); ((IDisposable)_done).Dispose(); } base.Dispose(); } private void SapiMTAThread() { while (true) { try { _process.WaitOne(); _exception = null; if (_doit != null) { _result = _doit.Invoke(); _doit = null; } else { _doit2!.Invoke(); _doit2 = null; } } catch (Exception e) { _exception = e; } try { _done.Set(); } catch (ObjectDisposedException) { break; } } } #endregion #region Private Fields private Thread _mta; private AutoResetEvent _process = new(false); private AutoResetEvent _done = new(false); private ObjectDelegate? _doit; private VoidDelegate? _doit2; private object? _result; private Exception? _exception; #endregion } internal delegate object? ObjectDelegate(); internal delegate void VoidDelegate(); } #endregion }