在.NET中调用一个COM对象
在.NET中调用一个COM对象是一件很简单的事。你设置了将会涉及的对象,VS.NET则为你创建了一个 interop对象,你可以用它来为你要调用的COM对象命名。就如同在一个当地的.NET中创建任何其它对象一样。当该COM对象的线程模式与.NET 应用程序的线程模式相匹配时,运行会很顺利。然而,假如情况不是这样的(即不相匹配时),当你例示该对象时,你就会看见一个出错提示。
解决这一问题的方法就是,调用与COM对象自身有着相同的线程模式的COM对象。在像Web服务这样的情况下,你无法控制主线的线程模式,这样,你就不得不用System.Threading来产生一个新的线程。在你所创建的新线程中,你有控制线程模式的选择权,因此你可以使它与该COM对象相匹配。
要想创建一个线程,你首先一定要创建一个ThreadStart代理。如果你对代理不是很熟悉的话,你只要知道他会行使指示器的功能即可。你可以赋一个函数名给一个代理,然后让该代理来执行操作,而不需要使用一个实际的函数名。正如其名字所指出的,ThreadStart 是某条线程的起点。由你告知.NET该从哪里开始执行其编码。
ThreadStart代理行使的是这样一种功能,它不接受任何参数,也不会返回任何参数。为了充分利用这一功能,你可能会想在一个对象(技术上它是一个方法)中封装该功能。通过这种方法,一开始你可以初始化创建一个对象,将该线程需要用到的数据填入该对象中,然后你就可以创建方法,在方法里可以使用刚才创建的对象里封装的ThreadStart进程里要用到的数据。
完成之后展开这些线程
在我将功能代码的清单完全展示给你之前,你先应该了解两件事,都是关于线程的。第一,线程在任何时候都可能结束。它们是独立运行的。尽管如此,在大多数调用COM对象的情形下,你最后都需要花一些时间来等该COM对象完成它的工作,当然是在开始运行之前。在一个 Thread对象中,那就是调用Join()这一方法的目的,这一方法会中止当前的线程(在我们的事例中指的是主线程),直到所涉及到的线程结束为止。这是一种很简单的方法,可以使一个线程与另一个线程的操作同步。
关于线程的第二个重点是,它们存在于它们自己的异常空间中。一个线程抛出的异常不会被送回那条分解出它们的母线程。如此一来,你需要包装一个try/catch块,并将那些异常存储在被调用的包装函数里的一个对象里。接下来,该调用线程就会检查,看该线是否已经完成(Thread.IsAlive == false)然后检查在内部异常中是否有一个除NULL以外的值。如果有一个值,就等于告诉你,你的线产生了一个异常。如果没有,就没什么问题了。
看看它的实践
我创建了一个简单的控制台应用程序,它所执行的步骤与你在一个Web服务中所执行的完全一样,这样我就不需要说明这样一种Web服务,这一服务需要使用自动的Web界面或者使用一个专门的工具来调用它。
图表A(Class1.cs)向你展示了一个简单的控制台应用程序类,它创建了一个shell类的实例的60个线程,接着给这些类的每一个返回类的ThreadStart代理创建一个线程。它为那些被建在STA,或单线程套间中的线程设置了线程模式。这样一来,甚至一个Web服务都可以调用STA COM对象。一旦所有的线程都建好了,它就会在线程组中一再重复并加入到每一条线中,以确保它可以适时结束。
图表B(ShellClass.cs)是这样一个类,每一个线程实例都在它里面居留。所有被抛出的异常(这些为控制台应用程序所忽视了)都被它收容了。它还包括一些基本的轨迹描述,以及我们的 COM对象的创建。在这一情形下,如果该对象是一个Delphi对象,它唯一的目的是揭示休眠的方法;然而,任何一个STA COM对象都可以做到这一点。
绑好
让一个STA COM对象在一个MTA体系中运行并不是一件很简单的事;不过,如果你愿意不使用多线程,则它又能安全运行。
