2009-10-07 10 views
17

Wir sind verpflichtet, ein ActiveX-Steuerelement von Drittanbietern zu verwenden.ActiveX-Steuerelement ohne Formular

Das einzige Problem ist, die Schicht in unserer Software ist eine Business-Schicht und hat keinen Zugriff auf ein Fenster oder ein Formular. Es läuft auch auf separaten Threads (und sollte von jedem Thread funktionieren), die nicht STA sind.

Anstatt unsere Trennung von UI von Business-Logik zu brechen, haben wir diese Abhilfe, damit es funktioniert:

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

Dann haben wir die Kontrolle verweisen müssen zu jeder Zeit, rufen wir _myActiveX.BeginInvoke() oder Invoke().

Bei der Entsorgung dieser Klasse (Beenden unserer App), entsorgen wir die Steuerung und brechen den Thread ab.

Meine Frage ist, gibt es irgendwelche Probleme damit? Gibt es einen besseren Weg, damit umzugehen?

Gibt es eine bessere integrierte Möglichkeit, mit einem ActiveX-Steuerelement aus einer unbekannten Multithread-Umgebung zu arbeiten? Wir versuchen, unsere Klasse so zu schreiben, dass sie das Steuerelement umschließt, aber von jedem Thread funktioniert.

UPDATE: Als Antwort vorgeschlagen, würden wir lieber das Standard-COM-Objekt verwenden und überhaupt kein Steuerelement verwenden. Unser Problem dabei war, dass wir den Fehler "(Ausnahme von HRESULT: 0x8000FFFF (E_UNEXPECTED)") bei der ersten Methode oder Eigenschaft, die wir beim COM-Objekt aufrufen, erhalten. Dies ist ein ziemlich allgemeiner Fehler, den wir bei Verwendung von ActiveX nicht erhalten , irgendwelche Ideen

UPDATE:. Unser ocx ist "CX25.ocx", tlbimp.exe verwenden wir CX25Lib.dll bekommen Aximp.exe verwenden, erhalten wir AxCX25Lib.dll und CX25Lib.dll CX25Lib.dll funktioniert nicht. In beiden Fällen funktioniert AxCX25Lib.dll

+0

Der obige Code, den ich erwähne, funktioniert. Hat jemand ein ActiveX-Steuerelement ohne ein Formular verwenden müssen? Oder hatte jemand Probleme mit dem Standard-COM-Objekt, aber bemerkte, dass ActiveX funktioniert? – jonathanpeppers

+0

Haben Sie eine Lösung dafür gefunden? Ich würde vermuten, dass der richtige Ansatz davon abhängt, ob Sie Callbacks/Ereignisse von der Steuerung erwarten oder nicht, da es von einer Windows-Nachrichtenpumpe abhängen würde, mit ihnen umzugehen. – Tormod

+1

Ja, der obige Code funktioniert. Wir verwenden es seit über einem Jahr ohne Probleme. Wir verwenden es auch mit mehreren COM-Bibliotheken. Wir haben es am Ende in eine Klasse eingepackt und Invoke/BeginInvoke implementiert, um mit dem Steuerelement, das benötigt wird, zu interagieren. – jonathanpeppers

Antwort

16

Ich gehe davon aus, dass dies der richtige Weg ist.

Wir haben meinen Code oben in Testumgebungen in den letzten paar Wochen ohne Probleme verwendet.

Wenn jemand ein ActiveX ohne ein Formular verwenden muss, nehme ich an, dass dies eine Möglichkeit ist.

Stellen Sie sicher, dass Sie _yourActiveXControl.CreateControl() direkt nach dem Konstruktor Ihres ActiveX-Objekts aufrufen. Dies vereinfachte viele Probleme, die wir ursprünglich hatten.

+0

Danke für das Posten dieser Information Es sieht so aus, als ob es für einige Leute wirklich nützlich wäre.Nur ein Datenpunkt, ich habe selbst ein ActiveX-Steuerelement, dass dies nicht funktioniert hat. Ich musste das Ding auf ein Formular setzen, das ich im separaten Thread lief (musste aber nie das Formular zeigen). – user12861

+1

Danke - ein Hinweis für andere Leute, wenn Sie ein Formular aus einem anderen Formular/Fenster starten, müssen Sie dies tun, damit das aktive x-Steuerelement ordnungsgemäß funktioniert. Der aktive X RDP-Client würde in meinem Fall die Box zum Umleiten von Laufwerken usw. nicht öffnen und würde das Formular einfach schließen. Putting 'CreateControl()' nach 'BeginInit()' auf dem Steuerelement löste dies. Sie müssen dies nicht tun, wenn Sie das Hauptformular mit diesem eingebettet haben. – uNople

1

Wenn Sie das ActiveX-Steuerelement von einer Business-Schicht aufrufen, bedeutet dies, dass es ohne UI verwendet werden kann, zB nur durch Aufruf seiner öffentlichen Methoden Erstellen Sie eine Interop-RCW für die ActiveX-Steuerelementklasse und rufen Sie ihre Methoden direkt auf

+0

Sprechen Sie davon, tlbimp auf dem OCX-Steuerelement auszuführen? Wir haben das versucht und es würde nicht funktionieren. Wir würden "Catastrophic failure (Ausnahme von HRESULT: 0x8000FFFF (E_UNEXPECTED))" jedes Mal bekommen, wenn wir es von einem Standard-COM-Objekt aus versuchten. Das ActiveX-Steuerelement funktioniert aus irgendeinem Grund. – jonathanpeppers

+0

Haben Sie 'aximp.exe' anstelle von' tlbimp.exe' ausprobiert? Es erstellt zwei Assemblys: ein normales RCW und ein WinForms-Proxy. Möglicherweise können Sie die RCW-Assembly eigenständig im Code verwenden. Disclaimer - Ich habe das nicht versucht, nur aufgrund meiner 'tlbimp.exe' Erfahrung. –

+0

Siehe meine Bearbeitung oben. – jonathanpeppers

1

Meine Lösung ist eine versteckte winform zu schaffen, die den ActiveX-Steuerelement hosten

+0

Meine Lösung scheint viel leichter. Was gewinnen Sie mit einem Off-Screen-Formular? – jonathanpeppers

+0

Ich habe ein Programm von Drittanbietern, die ein ActiveX-Steuerelement verfügbar machen, keine einfache Möglichkeit, das Programm zu steuern, ich wende mich an ActiveX-Steuerelement. eigentlich habe ich deine lösung ausprobiert, es scheint auch so zu sein. also werde ich deine lösung nehmen. – Benny

+0

Dies war die einzige Lösung für eine Steuerung, die ich verwendete, also danke für die Veröffentlichung. – user12861

1

Ich weiß, dass dies eine alte Post, aber ich würde empfehlen, die TPL in unserer modernen Zeit mit.

Es ist besser, die parallele Taskbibliothek anstelle der alten Threading-API zu verwenden, da die Funktionen zum Behandeln, Abbrechen, Fortsetzen und Zurückgeben von Exceptions behandelt werden.

Hier ist ein Beispiel:

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

Einige Punkte:

  1. StaTaskScheduler ist eine Art in der ParallelExtensionsExtras nuget package gefunden. Sie benötigen dies, um Aufgaben zu planen, die in einem Apartment mit einem Threaded Apartment ausgeführt werden sollen.

  2. Ich gebe 1 an den Konstruktor StaTaskScheduler, so dass es immer nur einen einzigen Thread für mich erstellt.

  3. Application.ExitThread() wird aufgerufen, um die Nachrichtenpumpe zu stoppen, was wiederum die Ausführung von Application.Run() ermöglicht, so dass einige Ergebnisse an den Aufrufer zurückgegeben werden können.