Chiamata VB6 DLL da un'applicazione C # finestre applicazione di servizio multithread?
-
22-08-2019 - |
Domanda
Sono in esecuzione un servizio di Windows multithread che hanno bisogno di chiamare un DLL VB6. Non c'è alcuna documentazione su questo VB6 dll e questo sistema legacy supporta un processo di business molto critico.
In un primo tempo (1 ° filo), questa DLL si comporta bene. Come altri thread hanno bisogno di accedere, è iniziare a fornire risultati errati.
Ho letto una ragazzi dicendo:
"Basta essere attenti di una cosa se si utilizza VB6. Il tuo threading modello è costretta a cambiare per appartamenti di supporto se si è l'esecuzione di un servizio di multithread. VB supporta solo multipla appartamenti a thread singolo, ma .NET gestisce completamente gratuito filettato normalmente. Il filo che chiama in VB6 DLL deve essere compatibile con la DLL ".
Un altro ragazzo dalla squadra mi ha dato l'idea di mettere questo ddl in un dominio di applicazione separata. Ma non sono sicuro.
Come possiamo lavorare con VB6 dll chiamato da un Windows C # applicazione di servizio multithread?
Soluzione
Quando i fili sono disponibili in, stai salvando oggetti e riutilizzarli in seguito nuove discussioni? Se è possibile, creare gli oggetti freschi per ogni thread. Abbiamo una situazione come questa, con una dll livello di dati che utilizziamo. Se si crea una connessione su un filo, non può essere utilizzato da un altro. Se si crea una nuova connessione su ogni filo, funziona benissimo.
Se è lento per creare i vostri oggetti, guardare la classe ThreadPool e l'attributo ThreadStatic. Threadpools riciclare lo stesso insieme di fili più e più volte per fare il lavoro, e ThreadStatic consente di creare un oggetto che esiste per un solo thread. ad esempio
[ThreadStatic]
public static LegacyComObject myObject;
Come arriva una richiesta, trasformarlo in un lavoro e la coda nel vostro pool di thread. Quando il processo viene avviato, controllare se l'oggetto statico viene inizializzato;
void DoWork()
{
if (myObject == null)
{
// slow intialisation process
myObject = New ...
}
// now do the work against myObject
myObject.DoGreatStuff();
}
Altri suggerimenti
Dici
Sono in esecuzione un Windows multithread servizio che hanno bisogno di chiamare un DLL VB6. Non c'è alcuna documentazione su questo VB6 dll e questo sistema legacy sostiene un business molto critica processo.
e allo stesso tempo si dice
In un primo tempo (1º filo), questa DLL si comporta bene. Come altri thread devono l'accesso, si avvia fornire sbagliato risultati.
mi piacerebbe fare molto certo che la gestione è a conoscenza del fallimento si sta vedendo, perché il codice di sostenere il processo di business critical è vecchio e non documentata, e viene utilizzato in un modo che non è mai stato destinato ad essere utilizzato, ed era mai testato per essere utilizzato. Scommetto che è anche mai stato testato per essere utilizzato da .NET prima, l'ha?
Ecco il mio consiglio, e questo è simile a qualcosa che ho effettivamente implementato:
Il VB6 DLL si aspetta di essere chiamato su un singolo filo. Non deludere esso! Quando il servizio viene avviato, avere avvio un filo del tipo appropriato (non posso dire, dal momento che ho volutamente dimenticato tutto quello che STA / MTA roba). In coda le richieste a quel filo per l'accesso al VB6 DLL. Hanno tutti tale accesso passare attraverso il singolo thread.
In questo modo, per quanto riguarda la DLL VB6 è interessato, è in esecuzione esattamente come è stato testato per funzionare.
A proposito, questo è un po 'diverso da quello che ho implementato. Ho avuto un servizio web, non è un servizio di Windows. Ho avuto un C DLL, non VB6, e non era COM. Ho appena refactoring tutti gli accessi alla cosa in una singola classe, poi mettere le dichiarazioni di blocco intorno a ciascuno dei metodi pubblici.
questo articolo sul multithreading di Visual Basic 6 DLL fornisce una certa comprensione. Dice:
Per fare un progetto DLL ActiveX multithreaded, selezionare il desiderato opzioni di filettatura nella scheda Generale della finestra di dialogo Proprietà progetto.
Questo articolo dice che ci sono tre possibili modelli tra cui scegliere:
One thread of execution
Thread pool with round-robin thread assignment
Every externally created object is on its own thread
Si considera che il default è one thread of execution
, e che una delle altre due opzioni deve essere selezionato.
Si potrebbe voler dare un'occhiata a questo: linky
E qui è un frammento che ha attirato la mia attenzione:
oggetti VB6 COM sono oggetti STA, che significa che devono funzionare su un thread STA. È stato creato due istanze dell'oggetto da due thread MTA, ma l'oggetto stesso verrà eseguito su un unico (COM (OLE) creato) STA filo, e l'accesso dai due thread MTA verranno marshalling e sincronizzati. Quindi, ciò che si dovrebbe fare è, inizializzare i thread come STA in modo che ogni oggetto viene eseguito in proprio thread STA senza marshalling e si andrà bene.
In ogni caso, VB oggetti COM stile sono sempre STA. Ora, al fine di prevenire appartamento marshalling e filo di commutazione è necessario creare casi in STA inizializzati appartamenti. Si noti inoltre che quando si imposta l'attributo [MTAThread] on Main, si inizializza in modo efficace il thread principale come MTA, quando si crea istanze di oggetti STA dal thread MTA COM crea un thread separato (non gestito) e inizializzate come STA (questo è chiamato il predefinito STA), tutte le chiamate agli oggetti STA dal thread MTA saranno marshalling (e incorrere interruttori filo), in alcuni casi chiamate IDispatch non riuscirà a causa di errori di marshalling IP. Così il consiglio è uso STA (e quindi VB6) oggetti da appartamenti compatibili solo.