3

我正在使用 COM shim 向导开发 Word 共享加载项。 http://blogs.msdn.com/b/mshneer/archive/2010/03/19/com-shim-wizards-for-vs-2010.aspx

一切正常,直到我尝试使用一些线程。它在某些机器上失败,主线程中创建的 COM 对象的 TYPE_E_LIBNOTREGISTERED 异常。

我有一个来自某个 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._Document”。此操作失败,因为 IID 为“{0002096B-0000-0000-C000-000000000046}”的接口的 COM 组件上的 QueryInterface 调用因以下错误而失败:库未注册。(来自 HRESULT 的异常:0x8002801D (TYPE_E_LIBNOTREGISTERED))。

我们能够重现它的唯一方法是安装 Office 2013,然后将其删除并安装 Office 2007。我检查了注册表,但没有发现此 guid 的任何注册问题。我尝试了 MS 的工具,它应该可以清除 Office 2013 的残留物, http://support.microsoft.com/kb/2739501 , 但它没有帮助。

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

我尝试使用 CoMarshalInterThreadInterfaceInStream,如此处所建议的, 无法从其他 STA 线程调用从 STAThread 创建的 COM 对象, 但即使在我的开发机器上也无法使其工作。这是代码: [DllImport("ole32.dll")] static extern int CoMarshalInterThreadInterfaceInStream([In] ref Guid riid, [MarshalAs(UnmanagedType.IUnknown)] object pUnk, out IStream ppStm);

    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
     }

当我尝试从 IStream 获取对象时,CoGetInterfaceAndReleaseStream 给了我 E_NOINTERFACE。任何人都可以向我发送 C# 工作示例的链接吗?我用谷歌搜索,但只找到了一些 C++ 的例子。

似乎 Office COM 注册被破坏,以至于它适用于同一个线程(加载项与 office 在同一个线程中运行),但未能编组到另一个 STA 线程......

4

1 回答 1

-1

就在最近,我们看到了同样的案例:在线程中调用 Word 对象模型时使用 TYPE_E_LIBNOTREGISTERED。您只能在主线程中使用任何 Office 对象模型。请在http://www.add-in-express.com/creating-addins-blog/2010/11/04/threads-managed-office-extensions/找到一些信息和更多链接。

于 2012-12-05T14:38:27.860 回答