没有表单的ActiveX控件

我们需要使用第三方ActiveX控件。

唯一的问题是,我们软件中的图层是业务层,无法访问窗口或表单。 它还运行在不是STA的单独线程上(并且应该可以在任何线程中工作)。

我们使用此解决方法使其工作,而不是将UI与业务逻辑分开。

Thread thread = new Thread((ThreadStart) delegate { _myActiveX = new MyActiveXType(); _myActiveX.CreateControl(); //more initialize work Application.Run(); }); thread.SetApartmentState(ApartmentState.STA); thread.IsBackground = true; thread.Start(); 

然后,只要我们需要引用控件,我们就会调用_myActiveX.BeginInvoke()Invoke()

在处理这个类(退出我们的应用程序)时,我们处理控件并中止线程。

我的问题是,这有什么问题吗? 有没有更好的方法来处理这个?

是否有更好的内置方法可以在未知的multithreading环境中使用ActiveX控件? 我们试图以包装控件的方式编写我们的类,但是可以在任何线程中工作。

更新:作为一个答案建议,我们真的宁愿使用标准的COM对象,而根本不使用控件。 我们的问题是我们会在我们调用COM对象的第一个方法或属性上得到错误“(来自HRESULT的exception:0x8000FFFF(E_UNEXPECTED)”。这是一个非常一般的错误,我们在使用ActiveX时没有得到这个错误, 有任何想法吗?

更新:我们的ocx是“CX25.ocx”,使用tlbimp.exe我们得到CX25Lib.dll。 使用aximp.exe,我们得到AxCX25Lib.dll和CX25Lib.dll。 在任何一种情况下CX25Lib.dll都不起作用。 AxCX25Lib.dll可以使用。

我认为这是解决这个问题的正确方法。

过去几周我们一直在测试环境中使用我的代码而没有任何问题。

如果有人必须使用没有表单的ActiveX,我认为这是一种方法。

只需确保在ActiveX对象的构造函数之后直接调用_yourActiveXControl.CreateControl()。 这简化了我们最初的许多问题。

如果从业务层调用ActiveX控件,这意味着它必须能够在没有UI的情况下使用,例如只需调用其公共方法即可。 为什么不直接为ActiveX控件类创建一个interop RCW并直接调用它的方法?

我的解决方案是创建一个托管activex控件的隐藏winform

我知道这是一个老post,但我建议在现代时代使用TPL。

由于围绕exception处理,取消,延续和返回结果的function,最好使用任务并行库而不是旧的线程API。

这是一个例子:

 using (var sta = new StaTaskScheduler(1)) { var taskResult = await Task.Factory.StartNew(() => { var results = new List(); using (var ax = new MyActiveXType()) { // important to call this just after constructing ActiveX type ax.CreateControl(); ax.SomeIterativeEvent += (s, e) => results.Add(e.SomeThing); // if applicable, you can tear down the message pump ax.SomeFinalEvent += (s, e) => Application.ExitThread(); //more initialize work // start message pump Application.Run(); return results; } }, CancellationToken.None, TaskCreationOptions.None, sta); return taskResult; } 

一些要点:

  1. StaTaskScheduler是在ParallelExtensionsExtras nuget包中找到的类型。 您需要这个来安排在单线程公寓中执行的任务。

  2. 我将1传递给StaTaskScheduler的构造函数,以便它只为我创建一个单独的线程。

  3. 调用Application.ExitThread()来停止消息泵,这反过来允许执行由Application.Run()传递,以便可以将一些结果返回给调用者。