如何处理来自控制台应用程序的COM事件?我正在使用来自第三方库的COM对象来生成周期性事件。当我在Winforms应用程序中使用该库时,将对象设为类成员并在主窗体线程中创建它,一切正常。但是,如果我从另一个线程创建对象,我不会收到任何事件。我的猜测是我需要在用于创建对象的同一个线程中有某种事件循环。我需要从控制台应用程序使用这个对象。我想我可以使用Application.DoEvents,但我不想在控制台应用程序中包含Winforms名称空间。我怎么解决这个问题?更新3(2011-06-15):供应商终于回答了。简而言之,他们说Application.Run创建的消息泵与Thread.Join创建的消息泵之间存在一些差异,但他们不知道差异是什么。我同意他们;任何关于此事的线索将不胜感激。更新:从Richard的评论到mdm的回答:如果其他组件是单线程的并从MTA实例化,Windows将创建工作线程+窗口+消息泵并执行必要的编组。为了听从他的建议,我正在执行以下操作:更新2:我在Jo?oAngelo的回答后更改了代码。使用系统;namespaceConsoleApplication2{classProgram{[STAThread]staticvoidMain(string[]args){MyComObjectWrapperwrapper=newMyComObjectWrapper();}}类MyComObjectWrapper{MyComObjectm_Object;AutoResetEventm_Event;.Threading.AutoResetEvent(假);System.Threading.Threadt=newSystem.Threading.Thread(()=>CreateObject());t.SetApartmentState(System.Threading.ApartmentState.STA);t.开始();等待();}voidObjectEvt(/*...*/){//...}voidWait(){m_Event.WaitOne();}voidCreateObject(){m_Object=newMyComObject();m_Object.OnEvent+=对象事件;System.Threading.Thread.CurrentThread.Join();我还尝试了以下方法:publicMyComObjectWrapper(){CreateObject();正如其他答案中所述,STACOM组件需要运行消息循环,以便将其他线程中发生的调用正确编组到拥有该组件的STA线程。在Windows窗体中,您可以免费获得消息循环,但在控制台应用程序中,您必须通过在拥有COM组件的线程上调用Thread.CurrentThread.Join来显式执行此操作,该线程也可能是应用程序的主线程。线程必须是STA。从Thread.Join的MSDN条目中,您可以看到这就是您想要的:阻止调用线程直到线程终止,同时继续执行标准COM和SendMessage提取。如果您不想在主控制台线程中执行任何其他操作,您只需无限期地等待,否则您可以在定期调用Thread.CurrentThread.Join以发送消息时执行其他操作。旁注:这假定您正在处理STACOM组件。一个简化的例子:classProgram{[STAThread]staticvoidMain(string[]args){varmyComObj=newMyComObject();myComObj.OnEvent+=ObjectEvt;Thread.CurrentThread.Join();//永远等待}staticvoidObjectEvt(objectsender,EventArgse){}}在这个例子中,控制台应用程序将处于一个永无止境的循环中,它不应该做更多的事情,然后响应COM组件中的事件。如果这不起作用,您应该尝试从您的COM组件供应商处获得支持。如果您使用的是STA,那么您将需要以某种方式进行消息循环。如果不需要消息循环,MTA可能是最简单的方法,也是控制台样式应用程序的最佳选择。需要注意的一件事是,对于MTA,创建对象的线程无关紧要;一个MTA线程创建的所有对象均等地属于所有MTA线程。(或者,在COM中,一个进程只有一个多线程单元,所有MTA线程都存在于此。)这意味着如果您采用MTA方法,则根本不需要创建单独的线程——只需从主线程创建对象.但是您还需要知道传入的事件将在“随机”线程上传递,因此您必须采取单独的步骤与主线程进行通信。使用系统;使用系统线程;类程序{静态MyComObjectm_Object;静态AutoResetEventm_Event;[MTAThread]staticvoidMain(string[]args){m_Event=newAutoResetEvent(false);m_Object=newMyComObject();+=对象事件;Console.WriteLine("主线程等待...");m_Event.WaitOne();Console.WriteLine("主线程收到事件,正在退出。");//这只在一个事件后退出;添加循环或其他逻辑以在适当时正确退出。}voidObjectEvt(/*...*/){Console.WriteLine("收到事件,正在工作...");//...请注意,这可能在任何随机COM线程上。Console.WriteLine("完成工作,发信号通知主线程...");m_Event.Set();您对以前版本的代码有几点评论:您在CreateObject和MycomObjectWrapper构造函数中都调用了Wait();看起来你应该只有一个-如果你有两个,当调用m_Event.Set()时,只有其中一个将被释放,而另一个仍在等待。此外,建议添加一些调试代码,这样您就可以看到您得到了多少。通过这种方式,您至少可以判断是否从COM获取事件,以及是否成功将事件传回主线程。如果对象在注册表中标记为中性或两者,则从MTA创建它们应该没有问题。IIRC,COM事件需要一个事件循环才能工作,它会抽取消息并调用Win32GetMessage函数。Winforms会为您做这件事,或者您可以使用Win32调用来模拟它。这个问题/答案有一个很好的例子,你可以构建。我认为以下应该有效:[STAThread]Main(...){varcomObject=newYourComObject();comObject.Event+=EventHandler;Console.WriteLine("按回车键退出。");控制台.ReadLine();}voidEventHandler(...){//处理事件}你定义线程单元模型了吗?[STAThread]staticvoidMain(string[]args){//创建将管理COM组件的线程Threadth=newThread(...);//在启动线程之前SetApartmentState(ApartmentState.STA);在线程中,只需等待事件发出终止信号即可。当线程在等待事件时,我认为它应该在线程循环中处理消息。可以试一下吗:以上是C#学习教程:HowtohandleCOMeventsfromaconsoleapplication?如果分享的内容对你有用,需要了解更多C#学习教程,希望大家多多关注——staticclassProgram{MyComObjectm_Object;[STAThread]staticvoidMain(){m_Object=newMyComObject();m_Object.OnEvent+=对象事件;System.Windows.Forms.Application.Run();}voidObjectEvt(/*...*/){//...}}本文采集自网络,不代表立场,如侵权请点击右下角联系管理员删除。如需转载请注明出处:
