MSXM2.DOMDocument实例创建会中断执行流程

时间:2018-04-02 05:28:04

标签: c# .net multithreading com activex

当从.NET COM组件创建MSXML2.DOMDocument()实例时,它允许中断当前方法执行流并让其他请求在同一个线程上执行,并且当它们完成时,它将恢复初始方法被打断了。 但是在创建MSXML2.FreeThreadedDOMDocument()实例时没有看到相同的观察结果。在这种情况下,方法执行流程不会中断。

我知道MSXML2.DOMDocument不是线程安全的,MSXML2.FreeThreadedDOMDocumen是。但MSXML2.DOMDocument()的上述行为似乎很奇怪。我错过了什么

您可以使用以下link中的示例应用程序来重现。

  

MFCApplication - > ATL COM EXE - > .NET COM组件。

     
      
  • .NET COM组件(dll):      
        
    • 开始()=>创建" MSXML2.DOMDocument"文件不确定,直到" _stop"国旗已经设定。
    •   
  •   
  • 停止()=>设置标志" _stop"真实。
  •   
  • ATL COM EXE:
  •   
  • CreateCSCOMComponent()=>在COINIT_APARTMENTTHREADED上创建.NET COM组件实例
  •   
  • Start()=>在.NET COM组件上调用Start()。
  •   
  • 停止()=>在.NET COM组件上调用Stop()。

  •   
  • MFCApplication:* Button"启动ATLCOMEXE" :在COINIT_MULTITHREADED中创建一个ATLCOMObject实例的实例,该实例启动   ATLCOMEXE。 * ATLCOMObject-> Start()=>所调用   "&ATLCOMObject- GT;启动()"在一个单独的线程上。 *   ATLCOMObject-> Stop()=>调用" ATLCOMObject->停止()"在一个单独的   线程。

  •   
     

重现的步骤

     

1)打开MFCApplication。

     

2)运行debugviewer查看   痕迹

     

3)点击"启动ATLCOMEXE"

     

4)点击" ATLCOMObject->开始()"

     

5)在debugview中连续观察.NET COM对象的日志   创建" MSXML2.DOMDocument()"的实例在同一个thead。

     

6)   单击" ATLCOMObject->停止()"(一次或多次)。

     

7)观察   登录debugview,.NET COM对象会中断执行流程   "开始"并执行"停止()"在同一个线程中,"开始"是   执行。

上述行为对我来说似乎很奇怪。

现在,如果我们替换.NET COM组件的Start()方法中的代码,创建MSXML2.FreeThreadedDOMDocument()而不是MSXML2.DOMDocument()并再次运行上述步骤,我们就不会看到观察7),这至少是我对COM的一点知识所预期的。

所以我想知道在创建MSXML2.DOMDocument时导致方法执行流中断的原因是什么?

1 个答案:

答案 0 :(得分:0)

你的EXE服务器在stdafx.h中定义了这个(可能是由VS向导添加的):

#define _ATL_APARTMENT_THREADED
  • 所以这意味着exe服务器将使用CoInitialize(NULL)初始化COM,这意味着将创建.NET对象的线程将是STA。
  • .NET对象默认标记为"两者都是",因此它们基本上可以存在于STA或MTA中。所以你的.NET对象将是STA。
  • DomDocument需要一个STA。
  • 自由线程的DomDocument需要一个MTA。 (它不是"两个')。

根据经验,STA线程意味着在此线程中创建的对象的COM消息(=方法调用)由在此线程中运行的COM创建的消息循环泵送。 如果你在该线程中运行自己的循环并且从不让COM消息循环运行,那么任何方法调用都不会到达此STA中的对象。

STA是功能(默认情况下通常默认启用,没有人注意到),这将确保标记为此类的对象不会被随机线程调用并崩溃。

在循环中,当您创建STA实例时,您隐含地让COM循环运行,因此方法调用(Stop)可以完成它。 当您创建FT DomDocument实例时,COM循环根本不运行,并且没有方法调用通过。

您必须了解COM线程如何在您的案例中做出最佳决策。

使用您的示例,您只需更改您的exe代码并发表评论_ATL_APARTMENT_THREADED(the default is _ATL_FREE_THREADED) 在这种情况下,一切都将在MTA中运行(好吧,如果你仍然使用非FT DomDocument,它将在STA上运行。)

注意:必须由线程所有者调用CoInitialize(Ex)。一旦被呼叫,再次呼叫它是没用的。你的代码周围有一些无用的CoInitializeEx。