简体   繁体   English

没有表单的ActiveX控件

[英]ActiveX control without a form

We are required to use a 3rd party ActiveX control. 我们需要使用第三方ActiveX控件。

The only issue is, the layer in our software is a business layer and has no access to a window or form. 唯一的问题是,我们软件中的图层是业务层,无法访问窗口或表单。 It also runs on separate threads (and should work from any thread) that are not STA. 它还运行在不是STA的单独线程上(并且应该在任何线程中工作)。

Rather than breaking our separation of UI from business logic, we used this workaround to make it work: 我们使用此解决方法使其工作,而不是将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();

Then anytime we need to reference the control, we call _myActiveX.BeginInvoke() or Invoke() . 然后,只要我们需要引用控件,我们就会调用_myActiveX.BeginInvoke()Invoke()

On disposing of this class (exiting our app), we dispose the control and abort the thread. 在处理这个类(退出我们的应用程序)时,我们处理控件并中止线程。

My question is, are there any problems with this? 我的问题是,这有什么问题吗? Is there a better way to handle this? 有没有更好的方法来处理这个?

Is there a better built in way to work with an ActiveX control from within an unknown multi-threaded environment? 在未知的多线程环境中有没有更好的内置方法来使用ActiveX控件? We are trying to write our class in a way that wraps the control but will work from any thread. 我们试图以包装控件的方式编写我们的类,但是可以在任何线程中工作。

UPDATE: As an answer suggested, we really would rather use the standard COM object and not use a control at all. 更新:作为一个答案建议,我们真的宁愿使用标准COM对象,而根本不使用控件。 Our issue with that was we would get the error "(Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)" upon the first method or property we call on the COM object. This is a pretty generic error that we don't get when using the ActiveX, any ideas? 我们的问题是我们会在我们调用COM对象的第一个方法或属性上得到错误“(来自HRESULT的异常:0x8000FFFF(E_UNEXPECTED)”。这是一个非常一般的错误,我们在使用ActiveX时没有得到这个错误, 有任何想法吗?

UPDATE: Our ocx is "CX25.ocx", using tlbimp.exe we get CX25Lib.dll. 更新:我们的ocx是“CX25.ocx”,使用tlbimp.exe我们得到CX25Lib.dll。 Using aximp.exe, we get AxCX25Lib.dll and CX25Lib.dll. 使用aximp.exe,我们得到AxCX25Lib.dll和CX25Lib.dll。 CX25Lib.dll does not work in either case. 在任何一种情况下CX25Lib.dll都不起作用。 AxCX25Lib.dll works. AxCX25Lib.dll可以使用。

I'm assuming this is the proper way to go about this. 我认为这是解决这个问题的正确方法。

We've been using my code above in test environments for the past few weeks with no issues. 过去几周我们一直在测试环境中使用我的代码而没有任何问题。

If anyone has to use an ActiveX without a form, I assume this is one way to do it. 如果有人必须使用没有表单的ActiveX,我认为这是一种方法。

Just make sure to call _yourActiveXControl.CreateControl() directly after your ActiveX object's constructor. 只需确保在ActiveX对象的构造函数后直接调用_yourActiveXControl.CreateControl()。 This simplified many issues we had originally. 这简化了我们最初的许多问题。

If you are calling the ActiveX control from a business layer, that means that it must be able to be used without a UI, eg just by calling its public methods. 如果从业务层调用ActiveX控件,这意味着它必须能够在没有UI的情况下使用,例如只需调用其公共方法即可。 Why not just create an interop RCW for the ActiveX control class and call its methods directly? 为什么不直接为ActiveX控件类创建一个interop RCW并直接调用它的方法?

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

I know this is an old post, but I would recommend using the TPL in our modern era. 我知道这是一个老帖子,但我建议在现代时代使用TPL。

It's better to use the task parallel library instead of the old threading API because of the features around exception handling, cancellation, continuation, and returning results. 由于异常处理,取消,延续和返回结果的特性,最好使用任务并行库而不是旧的线程API。

Here's an example: 这是一个例子:

using (var sta = new StaTaskScheduler(1))
{    
    var taskResult = await Task.Factory.StartNew(() =>
    {
        var results = new List<ResultType>();

        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;
}

Some points: 一些要点:

  1. StaTaskScheduler is a type found in the ParallelExtensionsExtras nuget package . StaTaskScheduler是在ParallelExtensionsExtras nuget包中找到的类型。 You'll need this to schedule tasks to execute in a Single Threaded Apartment. 您需要这个来安排在单线程公寓中执行的任务。

  2. I'm passing 1 to the constructor of StaTaskScheduler so that it only ever creates a single thread for me. 我将1传递给StaTaskScheduler的构造函数,以便它只为我创建一个单独的线程。

  3. Application.ExitThread() is called to stop the message pump, which in turn allows execution to pass by Application.Run() so that some result can be returned to the caller. 调用Application.ExitThread()来停止消息泵,这反过来允许执行由Application.Run()传递,以便可以将某些结果返回给调用者。

The CreateControl() method is from AxHost and requires System.Windows.Forms as a dependency. CreateControl()方法来自AxHost,需要System.Windows.Forms作为依赖项。 If you want to use ActiveX without UI you can directly create COM object of ocx using native call. 如果要在不使用UI的情况下使用ActiveX,可以使用本机调用直接创建ocx的COM对象。

   [DllImport("ole32.dll", PreserveSig = false)]
    [return: MarshalAs(UnmanagedType.Interface)]
    public static extern object CoCreateInstance([In] ref Guid clsid,[MarshalAs(UnmanagedType.Interface)] object punkOuter,int context, [In] ref Guid iid);


public object createComObject(){ 
    Guid IID_IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}");

    var gid = "{6bf52a52-394a-11d3-b153-00c04f79faa6}"; //your ocx guid
    var clsid = new Guid(gid);

    object yourOCX = CoCreateInstance(ref clsid, (object)null, 1, ref IID_IUnknown);
  return yourOCX ;
}

You can later cast the COM object to required interfaces 您可以稍后将COM对象强制转换为所需的接口

IOleObject iole = yourOCX as IOleObject;

IWMPCore iwmp =  yourOCX as IWMPCore;

I have created Windows Media Player ActiveX without UI or AxHost in C# over this link . 我通过此链接在C#中创建了没有UI或AxHost的Windows Media Player ActiveX。 It might help someone trying to run ActiveX without UI. 它可能会帮助有人尝试在没有UI的情况下运行ActiveX。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM