0

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

我使用过 System.Threading.Timer 和 System.Timers.Timer 都没有工作。目前我添加了一个线程调用使用 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;
        }
    }
4

2 回答 2

2

您违反了一项重要的单线程单元 (STA) 要求,它必须泵送消息循环。没有它,COM 无法将来自工作线程的调用封送到创建 COM 组件的线程。这对于确保组件以线程安全的方式使用是必要的。问题不在于您使用了计时器,而在于您使用了线程。可观察到的效果是调用死锁。

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

另一种解决方法是使用 [STAThread] 属性。然后 COM 将自动创建一个 STA 线程,为 COM 组件提供一个安全的家。该线程还泵送一个消息循环。现在每个电话都将被编组,如果你打了很多电话,请避免。

于 2011-08-23T05:43:47.927 回答
0

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

于 2011-08-23T15:38:15.923 回答