最近做一个winForm的小工具,用到了 ManagementObjectSearcher/ManagementClass 和 WndProc ,涉及到对 移动设备的检测。
窗体加载时会执行一个 Reload()方法(通过 ManagementObjectSearcher/ManagementClass 重新获取移动设备盘符),但是当把设备 拔出或插入时,由 WndProc 去执行 Reload() 方法,老是报 :
托管调试助手 "DisconnectedContext":“上下文 0xf20540 已断开连接。将不会使用代理来处理 COM 组件上的请求。这可能会导致损坏或数据丢失。要避免此问题,请确保在应用程序全部完成 RuntimeCallableWrapper (表示其内部的 COM 组件)之前,所有上下文/单元都保持活动状态。
怎么来解决这个问题?我也不知道,网上找了很久,没由合适的的解决办法。只有自己分析,去尝试解决了。。
通过调试,发现 Reload() 在三处有调用,窗体加载,设备插入,设备拔出。窗体加载时,Reload() 没有报错,正常加载,而当设备插入或拔出后,执行Reload() 就会报异常。
由此可见,可能好像是 不是一个线程 去执行 的 Reload() 导致,窗体加载时是UI线程 主线程 执行,而 插拔 执行的 WndProc 是另外的线程去执行。
在此,为了保证 Reload() 的 3处地方 执行都是一个线程去执行,怎么实现呢?看代码:
#region 检测可移动设备 public const int WM_DEVICECHANGE = 0x219;
public const int DBT_DEVICEARRIVAL = 0x8000;
public const int DBT_CONFIGCHANGECANCELED = 0x0019;
public const int DBT_CONFIGCHANGED = 0x0018;
public const int DBT_CUSTOMEVENT = 0x8006;
public const int DBT_DEVICEQUERYREMOVE = 0x8001;
public const int DBT_DEVICEQUERYREMOVEFAILED = 0x8002;
public const int DBT_DEVICEREMOVECOMPLETE = 0x8004;
public const int DBT_DEVICEREMOVEPENDING = 0x8003;
public const int DBT_DEVICETYPESPECIFIC = 0x8005;
public const int DBT_DEVNODES_CHANGED = 0x0007;
public const int DBT_QUERYCHANGECONFIG = 0x0017;
public const int DBT_USERDEFINED = 0xFFFF; /// <summary>
/// 检测可移动设备
/// </summary>
protected override void WndProc(ref Message m)
{
try
{
if (m.Msg == WM_DEVICECHANGE)
{
switch (m.WParam.ToInt32())
{
case WM_DEVICECHANGE:
break;
case DBT_DEVICEARRIVAL://可移动设备 插入
isReload = true;
break;
case DBT_CONFIGCHANGECANCELED:
break;
case DBT_CONFIGCHANGED:
break;
case DBT_CUSTOMEVENT:
break;
case DBT_DEVICEQUERYREMOVE:
break;
case DBT_DEVICEQUERYREMOVEFAILED:
break;
case DBT_DEVICEREMOVECOMPLETE: //可移动设备 卸载
isReload = true;
break;
case DBT_DEVICEREMOVEPENDING:
break;
case DBT_DEVICETYPESPECIFIC:
break;
case DBT_DEVNODES_CHANGED:
break;
case DBT_QUERYCHANGECONFIG:
break;
case DBT_USERDEFINED:
break;
default:
break;
}
}
}
catch (Exception ex)
{
MessageBox.Show((ex.InnerException ?? ex).ToString(), "检测可移动设备时出错", MessageBoxButtons.OK, MessageBoxIcon.Warning);
} base.WndProc(ref m);
} #endregion
/// <summary>
/// 因为 Form_Load 与 WndProc 两个不同线程 去调用 ManagementClass 会报异常,故这里 开启一个线程去后台维护更新下拉框。
/// </summary>
public Thread thread = null;
/// <summary>
/// 是否重新加载 下拉框
/// </summary>
public bool isReload = false;
private void MainForm_Load(object sender, EventArgs e)
{
thread = new Thread(Reload);
thread.IsBackground = true;
isReload = true;
thread.Start();
}
/// <summary>
/// 重新加载 移动硬盘盘符
/// </summary>
private void Reload()
{
while (true)
{
if (!isReload)
{
Thread.Sleep();
}
else
{
//这里编写业务逻辑代码。。。。。
isReload = false;
}
}
}
注:使用 While True + Thread.Sleep + 执行标识(isReload) 实现。