我有一个控制台应用程序需要触发一个使用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;
}
}
答案 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线程上运行。