如何处理从控制台应用程序COM事件? [英] How to handle COM events from a console application?

查看:127
本文介绍了如何处理从控制台应用程序COM事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是从产生周期性事件第三方库的COM对象。当我使用该库从WinForms应用程序,具有对象作为类的成员,并在主窗体线程建立它,一切正常。但是,如果我从另一个线程创建对象,我没有收到任何事件。



我的猜测是,我需要有某种事件循环在同一线程用于创建对象。



我需要使用这个对象从一个控制台应用程序。我想我可以使用Application.DoEvents,但我宁愿不包括在一个控制台应用程序中的WinForms命名空间。



我该如何解决这个问题呢?



更新3(2011-06-15):厂商已经回答了最后。总之,他们说有一个由Application.Run创建的消息泵和的Thread.join创建的之间存在一些差异,但他们不知道这有什么区别。



我同意他们的看法; ,揭示出这个问题的任何光线将是非常赞赏



更新:



从理查德注释MDM答案:



如果有其它部件是单线程的,并从MTA实例则Windows将创建工作线程+窗口+消息泵和做必要的编组



试图按照他的建议,我做了以下内容:



更新2:



我改变了下面的若昂·安杰洛答案代码

 使用系统; 

命名空间ConsoleApplication2
{
类节目
{
[STAThread]
静态无效的主要(字串[] args)
{
MyComObjectWrapper包装=新MyComObjectWrapper();
}
}

类MyComObjectWrapper
{
MyComObject m_Object;
的AutoResetEvent m_Event;

公共MyComObjectWrapper()
{
m_Event =新System.Threading.AutoResetEvent(假);

System.Threading.Thread T =新System.Threading.Thread(()=>的CreateObject());
t.SetApartmentState(System.Threading.ApartmentState.STA);
t.Start();

等待();
}

无效ObjectEvt(/*...*/)
{
// ...
}

无效等待()
{
m_Event.WaitOne();
}

无效的CreateObject()
{
m_Object =新MyComObject();
m_Object.OnEvent + = ObjectEvt;

System.Threading.Thread.CurrentThread.Join();
}
}
}



我也试过以下而不是:

 公共MyComObjectWrapper()
{
的CreateObject();
}


解决方案

在其他的答案已经说过STA COM组件需要一个消息循环,以便运行呼叫其他线程发生正确封送到拥有该组件的STA线程。



在Windows窗体你得到的消息循环免费,但在控制台应用程序必须通过调用 Thread.CurrentThread.Join <明确地去做/ code>拥有的COM组件,这可能是也为应用程序的主线程的线程上。该线程必须STA。



从的 的Thread.join 你可以看到,这是你想要什么:



< BLOCKQUOTE>

阻塞调用线程,直到某个线程终止,同时继续执行标准的COM和SendMessage消息泵。




如果你不想做任何事情在主控制台线程否则你只是等待下去,否则,你可以做其他的东西,同时定期调用 Thread.CurrentThread.Join 泵。邮件



边注:这里假设你正在处理一个STA COM组件






一个简单的例子:

 类节目
{
[ STAThread]
静态无效的主要(字串[] args)
{
变种myComObj =新MyComObject();

myComObj.OnEvent + = ObjectEvt;

Thread.CurrentThread.Join(); //将永远等待
}

静态无效ObjectEvt(对象发件人,EventArgs五){}
}

在这个例子中,控制台应用程序将是一个永无止境的循环,它应该做的而已,然后从COM组件的事件。如果这不工作,你应该尝试从COM组件供应商的支持。


I'm using a COM object from a third party library that generates periodic events. When I use the library from a Winforms app, having the object as a class member and creating it in the main form thread, everything works. However, if I create the object from another thread, I don't receive any event.

My guess is that I need to have some kind of event loop in the same thread used to create the object.

I need to use this object from a console application. I guess I could use Application.DoEvents, but I'd rather not include the Winforms namespace in a console App.

How can I solve this problem?

Update 3 (2011-06-15): The vendor has answered at last. In short, they say there is some difference between the message pump created by Application.Run and the one created by Thread.Join, but they don't know what that difference is.

I agree with them; any light shed on this matter would be very appreciated.

Update:

From Richard comment to mdm answer:

if there other component is single threaded and instantiated from an MTA then Windows will create the worker thread + window + message pump and do the necessary marshalling.

Trying to follow his advice, I'm doing the following:

Update 2:

I'm changed the code following João Angelo answer.

using System;

namespace ConsoleApplication2
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            MyComObjectWrapper wrapper = new MyComObjectWrapper();
        }
    }

    class MyComObjectWrapper
    {
        MyComObject m_Object;
        AutoResetEvent m_Event;

        public MyComObjectWrapper()
        {
            m_Event = new System.Threading.AutoResetEvent(false);

            System.Threading.Thread t = new System.Threading.Thread(() => CreateObject());
            t.SetApartmentState (System.Threading.ApartmentState.STA);
            t.Start();

            Wait();
        }

        void ObjectEvt(/*...*/)
        {
            // ...
        }

        void Wait()
        {
            m_Event.WaitOne();
        }

        void CreateObject()
        {
            m_Object = new MyComObject();
            m_Object.OnEvent += ObjectEvt;

            System.Threading.Thread.CurrentThread.Join();
        }    
    }
}

I have also tried the following instead:

        public MyComObjectWrapper()
        {
            CreateObject();
        }

解决方案

As already stated in other answers STA COM components require a message loop to be run in order for calls happening in other threads be correctly marshaled to the STA thread that owns the component.

In Windows Forms you get the message loop for free, but in a console application you must do it explicitly by calling Thread.CurrentThread.Join on the thread that owns the COM component and that is probably also the main thread for the application. This thread must be STA.

From the MSDN entry of Thread.Join you can see that this is what you want:

Blocks the calling thread until a thread terminates, while continuing to perform standard COM and SendMessage pumping.

If you don't want to do anything else in the main console thread you just wait indefinitely, otherwise you can do other stuff while periodically calling Thread.CurrentThread.Join to pump messages.

Side-note: This assumes you're dealing with a STA COM component.


A simplified example:

class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        var myComObj = new MyComObject();

        myComObj.OnEvent += ObjectEvt;

        Thread.CurrentThread.Join(); // Waits forever
    }

    static void ObjectEvt(object sender, EventArgs e) { }
}

In this example the console application will be in a never ending loop that should do nothing more then respond to events from the COM component. If this does not work you should try to get support from the COM component vendor.

这篇关于如何处理从控制台应用程序COM事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆