2009-10-07 32 views
17

Wymagane jest użycie formantu ActiveX innej firmy.Formant ActiveX bez formularza

Jedynym problemem jest to, że warstwa w naszym oprogramowaniu jest warstwą biznesową i nie ma dostępu do okna lub formularza. Działa również na osobnych wątkach (i powinno działać z dowolnego wątku), które nie są STA.

Zamiast łamiąc nasze oddzielenie interfejsu użytkownika od logiki biznesowej, użyliśmy tego obejścia, aby to działało:

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

Następnie w każdej chwili musimy odwoływać się do kontroli, nazywamy _myActiveX.BeginInvoke() lub Invoke().

Utylizując tę ​​klasę (opuszczając naszą aplikację), pozbieramy kontrolę i przerywamy wątek.

Moje pytanie brzmi, czy są jakieś problemy z tym związane? Czy jest lepszy sposób to obsłużyć?

Czy jest lepiej przygotowany do pracy z formantem ActiveX z nieznanego środowiska wielowątkowego? Staramy się napisać naszą klasę w sposób, który owija kontrolę, ale działa z dowolnego wątku.

AKTUALIZACJA: Zgodnie z sugestią sugerujemy raczej użycie standardowego obiektu COM i nieużywanie kontrolki. Nasz problem polegał na tym, że uzyskalibyśmy błąd "(Wyjątek od HRESULT: 0x8000FFFF (E_UNEXPECTED)" przy pierwszej metodzie lub właściwości, którą wywołujemy w obiekcie COM.) Jest to generyczny błąd, którego nie otrzymujemy podczas korzystania z ActiveX , wszelkie pomysły?

AKTUALIZACJA: Nasze ocx to "CX25.ocx", przy użyciu narzędzia tlbimp.exe otrzymujemy plik CX25Lib.dll.Za pomocą narzędzia aximp.exe otrzymujemy pliki AxCX25Lib.dll i CX25Lib.dll. CX25Lib.dll nie działa w obu przypadkach działa AxCX25Lib.dll

+0

Powyższy kod, o którym wspomnę, działa. Czy ktoś musiał używać formantu ActiveX bez formularza? A może ktoś miał problemy z używaniem standardowego obiektu COM, ale zauważył, że ActiveX działa? – jonathanpeppers

+0

Czy znalazłeś rozwiązanie tego problemu? Podejrzewam, że poprawne podejście zależy od tego, czy nie oczekujesz wywołań zwrotnych/zdarzeń z kontrolki, ponieważ zależałoby by to od pompy komunikatów Windows do obsługi. – Tormod

+1

Tak, powyższy kod działa. Używamy go od ponad roku teraz bez problemu. Używamy go również z wieloma bibliotekami COM. Zakończyliśmy zawijanie go w klasie i zaimplementowaliśmy Invoke/BeginInvoke do interakcji z kontrolką, która jest wymagana. – jonathanpeppers

Odpowiedz

16

Zakładam, że to jest właściwy sposób, aby o tym porozmawiać.

Użyliśmy mojego kodu powyżej w środowiskach testowych przez ostatnie kilka tygodni bez żadnych problemów.

Jeśli ktoś musi używać ActiveX bez formularza, zakładam, że jest to jeden sposób, aby to zrobić.

Po prostu upewnij się, że wywołasz _yourActiveXControl.CreateControl() bezpośrednio za konstruktorem obiektu ActiveX. Uprościło to wiele problemów, które mieliśmy pierwotnie.

+0

Dzięki za zamieszczenie tej informacji , wygląda na to, że byłoby to przydatne dla niektórych osób.Jednak tylko punkt danych, sam mam kontrolkę ActiveX, na którą to nie działa. Musiałem umieścić przedmiot na formularzu, który uruchamiam w oddzielnym wątku (ale nigdy nie musiałem pokazywać formularza przynajmniej). – user12861

+1

Dzięki - informację o tym innym osobom, jeśli uruchamiasz formularz z innego formularza/okna, musisz to zrobić, aby aktywna kontrola x działała poprawnie. Aktywny klient X RDP nie wyświetliłby okna przekierowującego napędy itp. W moim przypadku, dlatego po prostu zamknąłby formularz. Umieszczenie 'CreateControl()' po 'BeginInit()' na kontrole rozwiązało to. Nie musisz tego robić, jeśli masz główny formularz z tym osadzonym. – uNople

1

Jeśli wywołujesz kontrolkę ActiveX z warstwy biznesowej, oznacza to, że musi ona być dostępna bez interfejsu użytkownika, np. po prostu przez wywołanie jej publicznych metod. utworzyć RCW interop dla klasy kontrolki ActiveX i wywołać jej metody bezpośrednio?

+0

Czy mówisz o uruchomieniu tlbimp na sterowaniu .ocx? Próbowaliśmy tego i nie zadziałało. Otrzymalibyśmy "Katastrofalną awarię (wyjątek od HRESULT: 0x8000FFFF (E_UNEXPECTED))" za każdym razem, gdy wypróbowaliśmy go ze standardowego obiektu COM. Kontrolka ActiveX działa z jakiegoś powodu. – jonathanpeppers

+0

Czy wypróbowałeś 'aximp.exe' zamiast' tlbimp.exe'? Tworzy dwa zespoły: normalny RCW i jeden serwer proxy WinForm. Możesz być w stanie samodzielnie użyć zestawu RCW w kodzie. Zastrzeżenie - nie próbowałem tego, po prostu zgaduję na podstawie mojego doświadczenia 'tlbimp.exe'. –

+0

Zobacz moją edycję powyżej. – jonathanpeppers

1

Moje rozwiązanie jest stworzenie ukrytego WinForm że gościć w ActiveX Control

+0

Moje rozwiązanie wydaje się o wiele lżejsze. Co zyskujesz, korzystając z formularza poza ekranem? – jonathanpeppers

+0

Mam program innej firmy, który eksponuje kontrolkę ActiveX, nie ma łatwego sposobu kontrolowania programu, włączam kontrolę ActiveX. właściwie, wypróbowałem twoje rozwiązanie, wygląda na to, że działa. więc wezmę twoje rozwiązanie. – Benny

+0

To było jedyne rozwiązanie dla kontrolki, której używałem, więc dziękuję za opublikowanie tego. – user12861

1

Wiem, że to stary post, ale polecam korzystania z TPL w naszej epoce nowożytnej.

Lepiej używać biblioteki równoległej do zadań zamiast starego interfejsu API dla wątków ze względu na funkcje dotyczące obsługi wyjątków, anulowania, kontynuacji i zwracania wyników.

Oto przykład:

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

Niektóre punkty:

  1. StaTaskScheduler jest rodzajem znaleźć w ParallelExtensionsExtras nuget package. Będziesz potrzebował tego, aby zaplanować zadania do wykonania w mieszkaniu z pojedynczym wątkiem.

  2. Przechodzę 1 do konstruktora StaTaskScheduler, tak, że tworzy on dla mnie tylko jeden wątek.

  3. Application.ExitThread() jest wywoływana w celu zatrzymania pompy komunikatów, co z kolei umożliwia wykonanie przejścia przez Application.Run(), aby niektóre wyniki mogły zostać zwrócone do osoby dzwoniącej.

Powiązane problemy