从WPF调用COM,即使使用STAThread也可以获得E_NOINTERFACE,但可以在控制台应用

时间:2018-06-02 04:52:23

标签: c# .net wpf com

我试图按照这个答案https://stackoverflow.com/a/47295752/1237135,以获取IIS Express网站列表,其中涉及引用Microsoft.Web.dll(这是一个.NET程序集,但可能是它使用COM调用)并调用此代码

using (var runtimeStatusClient = new RuntimeStatusClient())
{
  var workerProcess = runtimeStatusClient.GetWorkerProcess(19464);
  //there's more but this is all that is needed for failure
}

它确实有效,代码运行并且包含有意义的数据,但是在完成后几秒钟我得到了这个错误

System.InvalidCastException: 
'Unable to cast COM object of type 'System.__ComObject' 
to interface type 'Microsoft.Web.RuntimeStatus.IRsca2_WorkerProcess'. 
This operation failed because the QueryInterface call on the COM component
for the interface with IID '{B1341209-7F09-4ECD-AE5F-3EE40D921870}' failed 
due to the following error: No such interface supported (Exception from 
HRESULT: 0x80004002 (E_NOINTERFACE)).'

E_NOINTERFACE通常与不使用STAThread模型相关联,但我已经验证该线程是STA。

代码在Console应用环境中无错误地工作,但不能在WPF中运行。

上面的答案提到

  

我也查看过RegisteredUrlsInfo(在Microsoft.Web.dll中)   发现它使用了两个COM接口,

     

IRsca2_Core(F90F62AB-EE00-4E4F-8EA6-3805B6B25CDD)   IRsca2_WorkerProcess(B1341209-7F09-4ECD-AE5F-3EE40D921870)

我看到了另一个回答https://stackoverflow.com/a/1058978/1237135的回答

  

尝试将此添加到App.exe.manifest:

     

  IID =" {C677308A-AC0F-427D-889A-47E5DC990138}"
  proxyStubClsid32 =" {00020424-0000-0000-C000-000000000046}"
  baseInterface =" {00000000-0000-0000-C000-000000000046}" tlbid =   " {PUT-YOUR-TLB-GUID-HERE}" />在哪里可以找到TLBID   Visual Studio生成Native.Namespace.Assembly.Name.manifest,   看起来像这样:

     

但我不清楚这是否适用于此。

我也想知道它是不是它的DLL地狱但是它无法解释为什么它可以从控制台运行,是吗?

编辑:最小的复制。

创建一个WPF项目(我使用4.6.1运行时),并在我使用的MainWindow的代码隐藏中

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();


            using (var runtimeStatusClient = new Microsoft.Web.RuntimeStatus.RuntimeStatusClient())
            {
                var workerProcess = runtimeStatusClient.GetAllWorkerProcesses();

            }
        }
    }
}

唯一困难的部分是您需要查找并引用Microsoft.Web.DLL(如果您的计算机上有IIS Express,则应该在您的GAC中)。你可以在你的C:\驱动器上进行Windows搜索,它可能在某个地方,如C:\ Windows \ assembly \ GAC_MSIL \ Microsoft.Web \ 7.1.0.0__31bf3856ad364e35

这样做,你就会发现问题。

1 个答案:

答案 0 :(得分:0)

显然我做了两个致命的假设:

  1. 控制台应用使用STA。然而,这不是真的,默认情况下它们似乎是MTA。我想这些数字,因为桌面应用程序必须在Main方法中明确声明STA。

  2. 要做COM互操作,你必须使用STA。我之所以这么认为是因为使用STA是网络上E_NOINTERFACE问题的首选解决方案。但是正如我现在所理解的,一些COM可以使用MTA。它出现在Microsoft.Web.DLL中,您需要MTA。

  3. 所以我的解决方案是创建一个新线程(默认情况下将使用MTA),例如

        public MainWindow()
        {
            InitializeComponent();
    
            //Do use ThreadPool instead of this...
            Thread thread = new Thread(new ThreadStart(() => { GetWebsites(); }));
            thread.Start();
    
        }
    
        void GetWebsites()
        {