Подтвердить что ты не робот

Элемент управления ActiveX без формы

Мы должны использовать сторонний элемент управления ActiveX.

Единственная проблема заключается в том, что слой в нашем программном обеспечении является бизнес-слоем и не имеет доступа к окну или форме. Он также работает на отдельных потоках (и должен работать из любого потока), которые не являются STA.

Вместо того, чтобы нарушать наше разделение пользовательского интерфейса от бизнес-логики, мы использовали это обходное решение, чтобы заставить его работать:

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().

При утилизации этого класса (выход из нашего приложения) мы удаляем элемент управления и прерываем поток.

Мой вопрос в том, есть ли проблемы с этим? Есть ли лучший способ справиться с этим?

Есть ли лучший встроенный способ работы с элементом управления ActiveX из неизвестной многопоточной среды? Мы пытаемся написать наш класс таким образом, чтобы обернуть элемент управления, но он будет работать из любого потока.

UPDATE: в качестве ответа мы действительно предпочли бы использовать стандартный COM-объект и вообще не использовать элемент управления. Наша проблема заключалась в том, что мы получили бы ошибку "(Исключение из HRESULT: 0x8000FFFF (E_UNEXPECTED)" при первом методе или свойстве, которое мы вызываем для COM-объекта. Это довольно общая ошибка, которую мы не получаем при использовании ActiveX, любые идеи?

UPDATE: наш ocx является "CX25.ocx", используя tlbimp.exe, мы получаем CX25Lib.dll. Используя aximp.exe, мы получаем AxCX25Lib.dll и CX25Lib.dll. CX25Lib.dll не работает ни в одном случае. Работает AxCX25Lib.dll.

4b9b3361

Ответ 1

Я предполагаю, что это правильный способ сделать это.

Мы использовали мой код выше в тестовых средах в течение последних нескольких недель без проблем.

Если кто-то должен использовать ActiveX без формы, я предполагаю, что это один из способов сделать это.

Просто убедитесь, что вы вызываете _yourActiveXControl.CreateControl() непосредственно после вашего конструктора объектов ActiveX. Это упростило многие проблемы, которые мы изначально имели.

Ответ 2

Если вы вызываете элемент управления ActiveX из бизнес-уровня, это означает, что он должен быть доступен без пользовательского интерфейса, например. просто позвонив своим публичным методам. Почему бы просто не создать interop RCW для класса управления ActiveX и вызвать его методы напрямую?

Ответ 3

Мое решение - создать скрытую winform, в которой размещается элемент управления activex

Ответ 4

Я знаю, что это старый пост, но я бы рекомендовал использовать TPL в нашу современную эпоху.

Лучше использовать параллельную библиотеку задач вместо старого API потоков из-за особенностей обработки исключений, отмены, продолжения и возврата.

Вот пример:

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

Некоторые моменты:

  • StaTaskScheduler - это тип, найденный в ParallelExtensionsExtras пакет nuget. Это вам нужно, чтобы планировать выполнение задач в однопоточной квартире.

  • Я передаю 1 конструктору StaTaskScheduler, чтобы он только создавал для меня один поток.

  • Application.ExitThread() вызывается, чтобы остановить насос сообщений, который, в свою очередь, позволяет исполнению проходить через Application.Run(), чтобы какой-то результат мог быть возвращен вызывающему.

Ответ 5

Метод CreateControl() из AxHost и требует System.Windows.Forms в качестве зависимости. Если вы хотите использовать ActiveX без UI, вы можете напрямую создать COM-объект ocx, используя собственный вызов.

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

Позже вы можете привести объект COM к необходимым интерфейсам

IOleObject iole = yourOCX as IOleObject;

IWMPCore iwmp =  yourOCX as IWMPCore;

Я создал Windows Media Player ActiveX без пользовательского интерфейса или AxHost в С# по этой ссылке. Это может помочь кому-то, пытающемуся запустить ActiveX без UI.