我正在开发像TeraTerm这样的UART终端程序。我正在制作自己的终端程序,因为我需要一些我在其他终端程序中找不到的功能。
我的终端程序可以打开几个终端窗口,每个窗口都显示所选COM端口的输出。每个终端窗口都在自己的线程中运行。
我已经覆盖终端窗口窗体的WndProc函数以捕获设备更改的事件,因为我想用当前PC的可用COM端口更新ComboBox的项目。这样做是为了在用户插入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]);
}
}
我的问题是我有时在Clear()方法调用中得到一个RaceOnRCW,即使我已经使用Invoke来确保在运行控件消息循环的线程上调用它。
发生了什么事?
如何防止这种情况发生?
或者我怎么能弄清楚控件是否在另一个线程上使用?然后也许等待另一个线程完成。
当设备更改事件发生时,是否有更好的方法可以使用新列表更新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();
}
答案 0 :(得分:0)
我找到了一种避免RaceOnRCW的方法。
我通过循环替换Clear调用,逐个删除每个项目。不是我喜欢的解决方案,但似乎有效。
我仍然希望听到有关如何操作的其他想法,因为我不能使用Clear功能。
int NItems = COMPortsComboBox.Items.Count;
for(int i = 0; i < NItems; i++)
{
COMPortsComboBox.Items.RemoveAt(0);
}