Элемент управления ActiveX без формы - PullRequest
18 голосов
/ 07 октября 2009

Мы обязаны использовать сторонний элемент управления 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 из неизвестной многопоточной среды? Мы пытаемся написать наш класс таким образом, чтобы обернуть элемент управления, но он будет работать из любого потока.

ОБНОВЛЕНИЕ: Как подсказал ответ, мы действительно предпочли бы использовать стандартный объект COM и вообще не использовать элемент управления. Наша проблема с этим заключалась в том, что мы получили бы ошибку «(Исключение из HRESULT: 0x8000FFFF (E_UNEXPECTED)» при первом методе или свойстве, которое мы вызываем для объекта COM. Это довольно общая ошибка, которую мы не получаем при использовании ActiveX есть идеи?

ОБНОВЛЕНИЕ: Наш ocx - "CX25.ocx", с помощью tlbimp.exe мы получаем CX25Lib.dll. Используя aximp.exe, мы получаем AxCX25Lib.dll и CX25Lib.dll. CX25Lib.dll не работает ни в одном случае. AxCX25Lib.dll работает.

Ответы [ 5 ]

16 голосов
/ 14 октября 2009

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

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

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

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

1 голос
/ 08 июля 2014

Я знаю, что это старый пост, но я бы порекомендовал использовать 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;
}

Некоторые баллы:

  1. StaTaskScheduler - это тип, найденный в пакете ParallelExtensionsExtras nuget . Это необходимо для планирования задач, выполняемых в однопоточной квартире.

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

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

1 голос
/ 01 декабря 2009

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

1 голос
/ 07 октября 2009

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

0 голосов
/ 20 июня 2019

Метод 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 в C # по этой ссылке . Это может помочь кому-то, пытающемуся запустить ActiveX без UI.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...