托管調試助手 "DisconnectedContext":“上下文 0xf20540 已斷開連接... 請確保在應用程序全部完成 RuntimeCallableWrapper (表示其內部的 COM 組件)之前,所有 COM 上下文/單元/線程都保持活動狀態並可用於上下文轉換


      最近做一個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
View Code
        /// <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(500);
                }
                else
                {
                   //這里編寫業務邏輯代碼。。。。。

         isReload = false; } } }

      注:使用 While True +  Thread.Sleep + 執行標識(isReload)  實現。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM