2009-10-07 16 views
17

È necessario utilizzare un controllo ActiveX di terze parti.Controllo ActiveX senza modulo

L'unico problema è che il livello del nostro software è un livello aziendale e non ha accesso a finestre o moduli. Funziona anche su thread separati (e dovrebbe funzionare da qualsiasi thread) che non sono STA.

Invece di rompere la nostra separazione della UI da logica di business, abbiamo usato questa soluzione per farlo funzionare:

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

Poi ogni volta che abbiamo bisogno di fare riferimento al controllo, lo chiamiamo _myActiveX.BeginInvoke() o Invoke().

Allo smaltimento di questa classe (uscendo dalla nostra app), disponiamo il controllo e interrompiamo la discussione.

La mia domanda è, ci sono problemi con questo? C'è un modo migliore per gestire questo?

Esiste un modo migliore di lavorare con un controllo ActiveX all'interno di un ambiente multi-thread sconosciuto? Stiamo cercando di scrivere la nostra classe in un modo che comprenda il controllo ma funzionerà da qualsiasi thread.

AGGIORNAMENTO: Come suggerito, preferiremmo utilizzare l'oggetto COM standard e non utilizzare affatto un controllo. Il nostro problema è stato che avremmo ricevuto l'errore "(Eccezione da HRESULT: 0x8000FFFF (E_UNEXPECTED)" sul primo metodo o proprietà che chiamiamo sull'oggetto COM. Questo è un errore piuttosto generico che non si ottiene quando si utilizza ActiveX , qualsiasi idea?

AGGIORNAMENTO: Il nostro ocx è "CX25.ocx", utilizzando tlbimp.exe otteniamo CX25Lib.dll. Utilizzando aximp.exe, otteniamo AxCX25Lib.dll e CX25Lib.dll. CX25Lib.dll non funziona AxCX25Lib.dll funziona

+0

Il codice sopra menzionato funziona. Qualcuno ha dovuto utilizzare un controllo ActiveX senza un modulo? O qualcuno ha avuto problemi usando l'oggetto COM standard, ma notato che ActiveX funziona? – jonathanpeppers

+0

Hai trovato una soluzione per questo? Sospetto che l'approccio corretto dipenda dal fatto che si aspettino o meno callback/eventi dal controllo in quanto dipenderebbe da un pump dei messaggi di Windows per gestirli. – Tormod

+1

Sì, il codice sopra funziona. Lo stiamo usando da oltre un anno senza problemi. Lo usiamo anche con più librerie COM. Abbiamo finito con il wrapping in una classe e abbiamo implementato Invoke/BeginInvoke per interagire con il controllo, che è richiesto. – jonathanpeppers

risposta

16

Suppongo che questo sia il modo corretto per farlo.

Abbiamo utilizzato il mio codice sopra negli ambienti di test nelle ultime settimane senza problemi.

Se qualcuno deve utilizzare un ActiveX senza un modulo, presumo che questo sia un modo per farlo.

Assicurati di chiamare _yourActiveXControl.CreateControl() direttamente dopo il costruttore dell'oggetto ActiveX. Questo ha semplificato molti problemi che avevamo in origine.

+0

Grazie per aver postato queste informazioni , sembra che sarebbe davvero utile per alcune persone.Solo un punto dati, però, ho un controllo ActiveX che non ha funzionato. Ho dovuto mettere la cosa su un modulo che eseguo nel thread separato (ma non ho mai dovuto mostrare il modulo almeno). – user12861

+1

Grazie - una nota a questo riguardo ad altre persone, se stai iniziando un modulo da un altro modulo/finestra, devi farlo per far funzionare correttamente il controllo x attivo. Il client X RDP attivo non apriva la casella per reindirizzare le unità ecc. Nel mio caso e quindi chiudeva semplicemente il modulo. Mettendo 'CreateControl()' dopo 'BeginInit()' sul controllo risolto questo. Non hai bisogno di farlo se hai il modulo principale con questo incorporato. – uNople

1

Se si chiama il controllo ActiveX da un livello aziendale, significa che deve poter essere utilizzato senza un'interfaccia utente, ad esempio semplicemente chiamando i metodi pubblici. creare un RCW di interoperabilità per la classe di controllo ActiveX e chiamarne direttamente i metodi?

+0

Stai parlando di eseguire tlbimp sul controllo .ocx? L'abbiamo provato e non avrebbe funzionato. Otterremmo "Errore irreversibile (Eccezione da HRESULT: 0x8000FFFF (E_UNEXPECTED))" ogni volta che l'abbiamo provato da un oggetto COM standard. Il controllo ActiveX funziona per qualche motivo. – jonathanpeppers

+0

Hai provato 'aximp.exe' invece di' tlbimp.exe'? Crea due assembly: uno normale RCW e uno proxy WinForms. Potresti essere in grado di utilizzare l'assembly RCW da solo nel codice. Disclaimer - Non ho provato questo, solo indovinando basato sulla mia esperienza 'tlbimp.exe'. –

+0

Vedere la mia modifica sopra. – jonathanpeppers

1

La mia soluzione è quella di creare un WinForm nascosta che ospita il controllo ActiveX

+0

La mia soluzione sembra molto più leggera. Cosa guadagni usando un modulo fuori campo? – jonathanpeppers

+0

Ho un programma di terze parti che espone un controllo activex, non è un modo semplice per controllare il programma, mi rivolgo al controllo activex. in realtà, ho provato la tua soluzione, sembra che funzioni anche tu. quindi prenderò la tua soluzione. – Benny

+0

Questa era l'unica soluzione per un controllo che stavo usando, quindi grazie per averlo pubblicato. – user12861

1

So che questo è un vecchio post, ma mi consiglia di utilizzare il TPL nella nostra epoca moderna.

È preferibile utilizzare la libreria parallela delle attività anziché la vecchia API di threading a causa delle funzionalità relative alla gestione delle eccezioni, alla cancellazione, alla continuazione e ai risultati di ritorno.

Ecco un esempio:

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

Alcuni punti:

  1. StaTaskScheduler è un tipo trovato nel ParallelExtensionsExtras nuget package. Ne avrai bisogno per pianificare le attività da eseguire in un appartamento a thread singolo.

  2. Sto passando 1 al costruttore di StaTaskScheduler in modo che crei sempre un solo thread per me.

  3. Application.ExitThread() viene chiamato per arrestare la pompa messaggi, che a sua volta consente l'esecuzione di passare da Application.Run() in modo che un determinato risultato possa essere restituito al chiamante.

Problemi correlati