0

TeraTerm のような UART 端末プログラムに取り組んでいます。他の端末プログラムにはない機能が必要なので、独自の端末プログラムを作成しています。

私の端末プログラムは、選択した COM ポートからの出力をそれぞれ表示する複数の端末ウィンドウを開くことができます。各ターミナル ウィンドウは、独自のスレッドで実行されます。

ComboBox の項目を現在の PC の利用可能な COM ポートで更新したいので、端末ウィンドウ フォームの WndProc 関数をオーバーライドしてデバイス変更イベントをキャッチしました。これは、ユーザーが USB COM ポート デバイスを接続している場合に、COM ポートのリストを最新の状態に保つために行われます。

私の WndProc は次のようになります。

    protected override void WndProc(ref Message m)
    {
        switch(m.Msg)
        {
            case WM_DEVICECHANGE:
                GetAvailableCOMPorts();
                COMPortsComboBox.Invoke(UpdateCOMPortsComboBoxDelegate);
                break;
        }

        base.WndProc(ref m);
    }

UpdateCOMPortsComboBoxDelegate は、デバイスの変更が発生したときに ComboBox 内の項目を更新する関数です。デバイスが COM デバイスでなくてもかまいません。簡単にするためにチェックはしません。

デリゲートが指す UpdateCOMPortsComboBox 関数は次のようになります。

    private void UpdateCOMPortsComboBox()
    {
        bool State                  = COMPortsComboBox.Enabled;
        COMPortsComboBox.Enabled    = false;           
        COMPortsComboBox.Items.Clear();
        COMPortsComboBox.Enabled    = State;

        // Then add the new list of COM ports
        for(int i = 0; i < AvailableSerialPorts.Length; i++)
        {
            COMPortsComboBox.Items.Add(AvailableSerialPorts[i]);
        }
    }

私の問題は、コントロール メッセージ ループを実行しているスレッドで呼び出されることを確認するために Invoke を使用したにもかかわらず、Clear() メソッド呼び出しで RaceOnRCW を取得することがあるということです。

何が起こっている?

これを防ぐにはどうすればよいですか?

または、コントロールが別のスレッドで使用されているかどうかを確認するにはどうすればよいでしょうか? そして、おそらく他のスレッドが終了するのを待ちます。

デバイス変更イベントが発生したときに ComboBox アイテムを新しいリストで更新するより良い方法はありますか?

これが発生すると、コール スタックは次のようになります。

    mscorlib.dll!System.__ComObject.ReleaseSelf() + 0x5 bytes   
    mscorlib.dll!System.Runtime.InteropServices.Marshal.ReleaseComObject(object o) + 0x9a bytes 
    System.Windows.Forms.dll!System.Windows.Forms.StringSource.ReleaseAutoComplete() + 0x11 bytes   
    System.Windows.Forms.dll!System.Windows.Forms.ComboBox.OnHandleDestroyed(System.EventArgs e) + 0x85 bytes   
    System.Windows.Forms.dll!System.Windows.Forms.Control.WmDestroy(ref System.Windows.Forms.Message m) + 0x46 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) + 0x44d bytes 
    System.Windows.Forms.dll!System.Windows.Forms.ComboBox.WndProc(ref System.Windows.Forms.Message m) + 0x882 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) + 0x13 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x31 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x64 bytes 
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    System.Windows.Forms.dll!System.Windows.Forms.UnsafeNativeMethods.DestroyWindow(System.Runtime.InteropServices.HandleRef hWnd) + 0x10 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DestroyHandle() + 0x89 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.Control.DestroyHandle() + 0x157 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.Control.RecreateHandleCore() + 0x16a bytes    
    System.Windows.Forms.dll!System.Windows.Forms.ComboBox.RecreateHandleCore() + 0x1a bytes    
    System.Windows.Forms.dll!System.Windows.Forms.ComboBox.SetAutoComplete(bool reset, bool recreate) + 0x105 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.ComboBox.ObjectCollection.ClearInternal() + 0xa1 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.ComboBox.ObjectCollection.Clear() + 0x17 bytes    
>   Echo.exe!Echo.Echo.UpdateCOMPortsComboBox() Line 231 + 0x1d bytes   C#
    [Native to Managed Transition]  
    mscorlib.dll!System.Delegate.DynamicInvokeImpl(object[] args) + 0x77 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbackDo(System.Windows.Forms.Control.ThreadMethodEntry tme) + 0xa7 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(object obj) + 0x90 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallback(System.Windows.Forms.Control.ThreadMethodEntry tme) + 0xa2 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbacks() + 0xda bytes   
    System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller, System.Delegate method, object[] args, bool synchronous) + 0x365 bytes   
    System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method, object[] args) + 0x50 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method) + 0x7 bytes    
    Echo.exe!Echo.Echo.WndProc(ref System.Windows.Forms.Message m) Line 247 + 0x19 bytes    C#
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) + 0x13 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x31 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x64 bytes 
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    System.Windows.Forms.dll!System.Windows.Forms.StringSource.Bind(System.Runtime.InteropServices.HandleRef edit, int options) + 0x46 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.ComboBox.SetAutoComplete(bool reset, bool recreate) + 0x2f4 bytes 
    System.Windows.Forms.dll!System.Windows.Forms.ComboBox.ObjectCollection.Add(object item) + 0x55 bytes   
    Echo.exe!Echo.Echo.UpdateCOMPortsComboBox() Line 237 + 0x34 bytes   C#
    [Native to Managed Transition]  
    mscorlib.dll!System.Delegate.DynamicInvokeImpl(object[] args) + 0x77 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbackDo(System.Windows.Forms.Control.ThreadMethodEntry tme) + 0xa7 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(object obj) + 0x90 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallback(System.Windows.Forms.Control.ThreadMethodEntry tme) + 0xa2 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.Control.InvokeMarshaledCallbacks() + 0xda bytes   
    System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller, System.Delegate method, object[] args, bool synchronous) + 0x365 bytes   
    System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method, object[] args) + 0x50 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method) + 0x7 bytes    
    Echo.exe!Echo.Echo.WndProc(ref System.Windows.Forms.Message m) Line 247 + 0x19 bytes    C#
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) + 0x13 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x31 bytes  
    System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x64 bytes 
    [Native to Managed Transition]  
    [Managed to Native Transition]  
    System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID, int reason, int pvLoopData) + 0x1b8 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context) + 0x16c bytes  
    System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) + 0x61 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Application.RunDialog(System.Windows.Forms.Form form) + 0x33 bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window owner) + 0x38f bytes    
    System.Windows.Forms.dll!System.Windows.Forms.Form.ShowDialog() + 0x7 bytes 
    Echo.exe!Echo.Program.NewEcho() Line 48 + 0xa bytes C#
    mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x63 bytes   
    mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool ignoreSyncCtx) + 0xb0 bytes    
    mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x2c bytes    
    mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes   
    [Native to Managed Transition]  

次のコードを使用して、別のスレッドで新しいターミナル ウィンドウを作成します。

    public static void CreateNewEchoThread()
    {
        //// Create a new thread
        Thread  EchoThread      = new Thread(new ThreadStart(Program.NewEcho));

        // Set thread parameters
        EchoThread.IsBackground = true;
        EchoThread.SetApartmentState(ApartmentState.STA);

        //// Start the thread
        EchoThread.Start();

        // Increment the number of open Echo forms
        Echo.NumberOfOpenWindows++;
    }

    [STAThread]
    static void NewEcho()
    {
        // Create a new Echo form window and show it as a Dialog to prevent the thread from exiting immediately.
        Echo NewEchoForm    = new Echo();
        NewEchoForm.ShowDialog();
    }
4

1 に答える 1

0

RaceOnRCW を回避する方法を見つけました。

Clear 呼び出しを、各項目を 1 つずつ削除するループに置き換えます。私が好きな解決策ではありませんが、うまくいくようです。

クリア機能が使えないのが気になるので、他の方法も教えていただきたいです。

int NItems  = COMPortsComboBox.Items.Count;
for(int i = 0; i < NItems; i++)
{
    COMPortsComboBox.Items.RemoveAt(0);
}
于 2013-01-15T09:48:49.730 に答える