【问题标题】:The application called an interface that was marshalled for a different thread应用程序调用了为不同线程编组的接口
【发布时间】:2012-08-31 07:40:48
【问题描述】:

我正在使用 WMI 来查询设备。我需要在插入或移除新设备时更新 UI(以使设备列表保持最新)。

private void LoadDevices()
{
    using (ManagementClass devices = new ManagementClass("Win32_Diskdrive"))
    {
        foreach (ManagementObject mgmtObject in devices.GetInstances())
        {
            foreach (ManagementObject partitionObject in mgmtObject.GetRelated("Win32_DiskPartition"))
            {
                foreach (ManagementBaseObject diskObject in partitionObject.GetRelated("Win32_LogicalDisk"))
                {
                    trvDevices.Nodes.Add( ... );
                }
            }
        }
    }
}

protected override void WndProc(ref Message m)
{
    const int WM_DEVICECHANGE = 0x0219;
    const int DBT_DEVICEARRIVAL = 0x8000;
    const int DBT_DEVICEREMOVECOMPLETE = 0x8004;
    switch (m.Msg)
    {
        // Handle device change events sent to the window
        case WM_DEVICECHANGE:
            // Check whether this is device insertion or removal event
            if (
                (int)m.WParam == DBT_DEVICEARRIVAL ||
                (int)m.WParam == DBT_DEVICEREMOVECOMPLETE)
        {
            LoadDevices();
        }

        break;
    }

    // Call base window message handler
    base.WndProc(ref m);
}

此代码抛出异常并显示以下文本

The application called an interface that was marshalled for a different thread.

我放了

MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());

在 LoadDevices 方法的开头,我看到它总是从同一个线程 (1) 调用。你能解释一下这里发生了什么以及如何摆脱这个错误吗?

【问题讨论】:

    标签: c# .net com wmi


    【解决方案1】:

    最后我用新线程解决了它。 我拆分了这个方法,所以现在我有GetDiskDevices()LoadDevices(List<Device>) 方法,我有InvokeLoadDevices() 方法。

    private void InvokeLoadDevices()
    {
        // Get list of physical and logical devices
        List<PhysicalDevice> devices = GetDiskDevices();
    
        // Check if calling this method is not thread safe and calling Invoke is required
        if (trvDevices.InvokeRequired)
        {
            trvDevices.Invoke((MethodInvoker)(() => LoadDevices(devices)));
        }
        else
        {
            LoadDevices(devices);
        }
    }
    

    当我收到 DBT_DEVICEARRIVAL 或 DBT_DEVICEREMOVECOMPLETE 消息时,我会调用

    ThreadPool.QueueUserWorkItem(s => InvokeLoadDevices());
    

    谢谢。

    【讨论】:

      【解决方案2】:

      对于 w10 上的 UWP,您可以使用:

      public async SomeMethod()
      {
          await CoreWindow.GetForCurrentThread().Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
              {
                   //   Your code here...
              });
      }
      

      【讨论】:

        猜你喜欢
        • 2018-05-21
        • 1970-01-01
        • 1970-01-01
        • 2011-04-05
        • 2023-03-20
        • 1970-01-01
        • 1970-01-01
        • 2013-10-20
        相关资源
        最近更新 更多