控制台应用程序中的STAThread COM调用的C#Timer

时间:2011-08-23 05:10:48

标签: c# multithreading timer com sta

我有一个控制台应用程序需要触发一个使用COM的方法。该程序以[STAThread]开头。程序在不使用计时器进程时正确执行,但在使用计时器时显然会阻塞回控制台。

我使用过System.Threading.Timer和System.Timers.Timer,但都没有用。现在我添加了一个Thread调用使用COM的方法(Transmit())。如果我用Console.Readline清除主线程,程序将恢复COM对象被阻止的位置,但程序当然会关闭,我将失去所需的计时器功能。

在使用控制台应用程序时,我无法弄清楚如何设置SynchronizingObject来获取ISynchronizeInvoke回调。

我不是在寻找多个线程,我只需要定期调用Transmit方法,并在将结果返回控制台的同时使用COM。

class Program
{
    private static System.Timers.Timer transTimer;

    [STAThread]
    static void Main(string[] args)

       {
                transTimer = new System.Timers.Timer();
                transTimer.Enabled = true;
                transTimer.Interval = 6000;
                transTimer.Elapsed += new System.Timers.ElapsedEventHandler(transTimer_Elapsed);
                transTimer.Start();
                Console.ReadLine();
                transTimer.Dispose();
                return;
            }


    static void transTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        if (transTimer.Enabled)
        {
            transTimer.Enabled = false;
            Thread thread = new Thread(Transmit);
            thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
            thread.Start();
            thread.Join(); //Wait for the thread to end
            transTimer.Enabled = true;
        }
    }

2 个答案:

答案 0 :(得分:2)

您违反了重要的单线程公寓(STA)要求,它必须提供一个消息循环。没有一个,COM无法编组从工作线程到创建COM组件的线程的调用。这是确保组件以线程安全方式使用所必需的。问题不是你使用了计时器,问题是你使用了一个线程。可观察到的影响是呼叫死锁。

在控制台应用程序中获取消息循环很难得到。一种解决方法是不在Main()方法中创建COM组件,而是让工作线程创建它,以便不需要编组。通过循环调用Sleep()来实现句点调用。

另一种解决方法是使用[STAThread]属性。然后,COM将自动创建一个STA线程,为COM组件提供一个安全的家。这个线程也泵出了一个消息循环。现在每个电话都会被整理,如果你做了很多话就要避免。

答案 1 :(得分:0)

设置消息泵的.NET方法是Application.Run()。从单独的专用线程调用它并使用不接受表单的重载。将您的COM代码保留在主线程上的该线程和控制台代码上,并且您不应该在控制台阻塞COM逻辑时遇到任何问题。如果需要定时器与COM逻辑交互,请使用System.Windows.Forms.Timer对象,在COM线程上创建一个启动。这样来自它的回调/事件也将在COM线程上运行。