Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从STA线程调用COM对象会导致某些计算机上未注册类型_E_libnotregisted_C#_Multithreading_Com_Add In_Office Interop - Fatal编程技术网

C# 从STA线程调用COM对象会导致某些计算机上未注册类型_E_libnotregisted

C# 从STA线程调用COM对象会导致某些计算机上未注册类型_E_libnotregisted,c#,multithreading,com,add-in,office-interop,C#,Multithreading,Com,Add In,Office Interop,我正在使用COM垫片向导开发Word共享加载项。 在我尝试使用一些线程之前,一切都很顺利。 对于在主线程中创建的COM对象,它在某些类型为_E_LIBNOTREGISTERED exception的计算机上失败 我从某个Word事件中获得了一个Word文档对象(_doc),并尝试从STA线程使用它,如下所示: Word.Document _doc; void Start() { _mainLoopThread = new Thread(MainLoop); _mainLoopT

我正在使用COM垫片向导开发Word共享加载项。

在我尝试使用一些线程之前,一切都很顺利。 对于在主线程中创建的COM对象,它在某些类型为_E_LIBNOTREGISTERED exception的计算机上失败

我从某个Word事件中获得了一个Word文档对象(_doc),并尝试从STA线程使用它,如下所示:

Word.Document _doc;
void Start()
{
    _mainLoopThread = new Thread(MainLoop);
    _mainLoopThread.SetApartmentState(ApartmentState.STA);
    _mainLoopThread.IsBackground = true;
    _mainLoopThread.Start();
}
void MainLoop()
{
    // some code...
    Word.Range r = _doc.StoryRanges[Word.WdStoryType.wdMainTextStory];
    // some code...
}
在我的开发机器、测试机器和大多数用户上,一切都很好。但是,对于某些用户,它会失败,但有一个例外: 无法将类型为“Microsoft.Office.Interop.Word.DocumentClass”的COM对象强制转换为接口类型“Microsoft.Office.Interop.Word.\u Document”。此操作失败,因为对IID为“{0002096B-0000-0000-C000-0000000000 46}”的接口的COM组件的QueryInterface调用由于以下错误而失败:库未注册。(来自HRESULT的异常:0x8002801D(类型_E_libnotregisted))

我们能够复制它的唯一方法是安装Office 2013,然后删除它并安装Office 2007。我检查了注册表,但没有发现此guid的任何注册问题。我试过微软的工具,应该可以清除Office 2013的遗留物, 但这没用

这不是注册问题,因为我可以从主线程使用相同的_doc对象而不会出现任何错误。 在COM垫片的rgs文件中,我使用STA模型 InprocServer32=s“%MODULE%” { val ThreadingModel=s“单元” } 我还在Properties Linker Advanced中将CLR模式设置为STA,但这没有帮助

我尝试使用CoMarshalInterThreadInterfaceInStream,正如这里所建议的 但即使在我的开发机器上也无法让它工作。 代码如下: [DllImport(“ole32.dll”)] 静态外部int-comarshalinterreadinterfaceinstream([In]ref-Guid-riid,[MarshalAs(UnmanagedType.IUnknown)]对象朋克,out-IStream-ppStm)

当我试图从IStream获取对象时,CogetInterface和LeaseStream给了我E_NOINTERFACE。有人能给我发一个C#工作示例的链接吗?我搜索了Google,但只找到了一些C++的例子。
Office COM注册似乎被破坏了,它在同一个线程中工作(加载项与Office在同一个线程中运行),但无法被封送到另一个STA线程…

就在最近,我们看到了非常相同的情况:在线程中调用Word对象模型时键入_E_libnotregister。必须仅在主线程中使用任何Office对象模型。请在上找到一些信息和更多链接。

COM没有主线程的概念。COM通过单元实现其线程模型。一个进程可以有任意数量的STA,最多一个MTA。对象实例仅属于单个单元。Office对象模型公开STA对象。每个对象都位于STA中,只能从创建它的STA访问。这是非常基本的COM。你发布的链接完全是模糊的,而且由于作者不了解COM,这些建议也会产生误导。谢谢你的评论。上面的讨论与COM插件有关,而不是纯COM。因为COM外接程序应该遵守其宿主应用程序指定的规则。具体来说,它应该在应用程序的主线程上使用宿主应用程序的对象模型。详情请浏览。希望这能有所帮助。你有一些倒退:COM加载项必须遵守你所谓的纯COM规则。没有区别。你在之前的评论中发布的链接阐明了纯COM规则。这些都不是特定于Office加载项的。该文档只遗漏了那些对Office插件开发不感兴趣的规则。您在回答中发布的链接谈到COM中的并发性,但没有使用术语“单元”。光是这一点就不完整了,充其量也让人有理由相信,作者的书架上没有唐·博克斯的“基本COM”。你有权随心所欲地看待事物。事实是:无论Microsoft阅读了哪些书籍,它们都明确指出,如果COM加载项在宿主应用程序主线程以外的线程上使用对象模型,则COM加载项可能无法工作。这是该页的引文:“当后台线程调用Office应用程序时,调用会自动跨STA边界封送。但是,无法保证Office应用程序能够在后台线程调用时处理调用。”“如果COM加载项在主机应用程序的主线程以外的线程上使用对象模型,则它可能无法工作。“不管在哪里,它都不是这么说的。没有所谓的主线。COM的并发模型是基于单元的。只能从创建STA对象的STA访问该对象。你说的是线程,而你应该指的是公寓。所有这些都在Don Box中进行了解释。如果你想精通COM,绝对必读。
    IStream _docForThreadStream = null;

    Guid _docInterfaceGuid;

    void InitDocForThread()
    {            
        object[] attr = _doc.GetType().GetCustomAttributes(typeof(GuidAttribute), false);
        GuidAttribute g = (GuidAttribute)attr[0];
        _docInterfaceGuid = new Guid(g.Value);

        CoMarshalInterThreadInterfaceInStream(ref _docInterfaceGuid, Marshal.GetIUnknownForObject(_doc), out _docForThreadStream);
    }

    [DllImport("ole32.dll")]
    static extern int CoGetInterfaceAndReleaseStream(IStream pStm, [In] ref Guid riid, out object ppv);

    Word.Document _docForThread = null;

    void MainLoop()
    {
            object pDoc;
            int hr = CoGetInterfaceAndReleaseStream(_docForThreadStream, ref _docInterfaceGuid, out pDoc);
            // _docForThreadStream != null, hr == E_NOINTERFACE
     }