2011-09-07 16 views
5

Come si impone a Excel (2007) VBA di rilasciare riferimenti a un oggetto server COM?Come rilasciare l'oggetto server COM in elaborazione da Excel VBA

Ho scritto un server COM in esecuzione (Single instance DLL) in Visual Foxpro 9 SP2, che viene istanziato dal codice VBA di Excel 2007 sul mio computer di sviluppo. Sembra che Excel abbia un riferimento all'oggetto COM/dll anche se l'ho impostato = Nothing. Questo mi impedisce di ricostruire la DLL a causa di un messaggio "File Access is denito TestCOM.dll" finché non esco da Excel, il che è un dolore ogni volta che voglio apportare una modifica e testarlo.

Ho bollito il codice fino a una semplice configurazione di prova: Il progetto VFP9 (TESTCOM) ha un solo file prg con il seguente contenuto

DEFINE CLASS TestClass As Session OLEPUBLIC 

ENDDEFINE 

il codice VBA è la seguente:

Sub Test() 

    Set objTest = CreateObject("TestCOM.TestClass") 
    Set objTest = Nothing 

End Sub 

Ho provato a rimuovere il riferimento alla libreria del server COM nel progetto VBA ma questo non fa alcuna differenza. Ho provato con e senza DIMing le variabili oggetto e non fa differenza. Ho provato a creare un nuovo progetto DLL VFP ma il problema persiste.

Se io costruisco l'applicazione/dll VFP come INPROCESS/DLL ed eseguire il codice VBA ottengo questo problema, ma se io costruisco come un OUTOFPROCESS/EXE ed eseguire il codice VBA non ottengo questo problema.

Ho trovato un problema molto simile in COM Object Cleanup tranne che il mio server COM è scritto in Visual Foxpro 9 SP2 mentre quello relativo a C# e l'OP non ha spiegato in dettaglio come hanno risolto il problema quindi non so come aggirarlo; se è possibile.

+0

Per tutti gli altri la lettura di questa discussione in seguito mi sono reso conto che se il progetto è costruito come un fuori di processo (EXE) COM server allora si può ricostruire solo il progetto senza uscire da Excel se non si dispone di un riferimento alla libreria dei tipi in VBA/Excel. – Caltor

risposta

6

La procedura utilizzata per creare un'istanza della classe COM dal codice nella DLL è che Excel chiama il livello della libreria COM per trovare l'implementazione utilizzando ProgID o ClassID. Quando si dispone di un server inproc significa che trova un percorso per la DLL e utilizza LoadLibrary per caricarlo nel processo client e quindi crea la classe factory e chiama i metodi nella DLL. Il risultato finale è che Excel chiama LoadLibrary sulla DLL e blocca il file fino a quando Excel chiama FreeLibrary sull'handle.

Utilizzando le interfacce COM non si ha il controllo di questo. Si chiama CoCreateInstance() (o da VBA si crea l'oggetto con New o CreateObject che chiama questa API Win32 sotto). L'implementazione di questo gestisce la LoadLibrary e tutto il resto fino a quando non viene consegnato un puntatore a interfaccia con cui lavorare. Alcune applicazioni chiamano periodicamente CoFreeUnusedLibraries() per tentare di rilasciare DLL COM caricate che non sono attualmente in uso. L'implementazione factory class predefinita mantiene un contatore di oggetti creati che possono essere utilizzati per determinare se una DLL è in uso o meno - ma questo non è sempre affidabile in quanto i writer della classe COM potrebbero non rispettare le regole. Uscire da Excel rilascia ovviamente il blocco sul file.

Quando si crea la classe COM come server out-of-process, esso vive in un file eseguibile o DLL separato la cui durata è gestita in modo diverso. Excel non contiene più un blocco sulla DLL e il rilascio dell'istanza COM potrebbe consentire l'uscita del processo di hosting.

È possibile convertire una DLL da utilizzare come localserver (out-of-process) organizzando per farla ospitare da DllHost. Se si utilizza l'utilità OleView e si trova ProgId delle classi, è possibile abilitare l'hosting in un processo surrogato (dllhost). È passato un po 'di tempo da quando l'ho fatto, ma ci dovrebbero essere informazioni sul web sull'utilizzo dell'host surrogato. Ovviamente l'hosting di un oggetto COM out-of-process rende tutto più lento e introduce il potenziale per vari problemi di marshalling.Purché si mantengano interfacce compatibili con l'oleautomazione, dovrebbe andare bene.

+0

Grazie per la tua eccellente risposta tecnica dettagliata. Quindi in breve si sta sostanzialmente dicendo che con le interfacce COM sono alla mercé del client, in questo caso Excel, e non c'è modo che io imponga un rilascio della DLL? Avrei dovuto ricordare nella mia domanda che questo problema non si verifica quando il server COM viene chiamato da un'altra copia di VFP, quindi l'errore sembra essere con il client piuttosto che con il server. Penso che come soluzione temporanea costruirò questo progetto come un server Out of Process (EXE) durante lo sviluppo e poi lo passerò a In Process (DLL) per il test finale e il rilascio. – Caltor

+2

È richiesto un ingrediente in più. Il server COM deve restituire S_OK dal suo punto di accesso DllCanUnloadNow(). Non semplice da testare in un ambiente VBA + Foxpro. –

1

Aggiunta di una risposta più breve ....

Rilasciando il DLL è problema spinoso e uno familiare agli sviluppatori di processo in COM componenti per l'uso in Excel.

ci sono due condizioni che devono essere soddisfatte

1) Non utilizzare uno dei primi riferimenti alla libreria vincolanti (Strumenti-> Riferimento), utilizzare l'associazione tardiva, invece. Il riferimento agli strumenti di rilegatura precoce terrà un lucchetto.

2) Chiama CoFreeUnusedLibraries per scaricare i server COM che non hanno più clienti.

Dal codice di esempio si è già in ritardo, ma si prega di controllare i riferimenti. Mentre il punto 2) è indicato in payyhoyts answer non viene fornito alcun codice.

Ecco una copia e la dichiarazione pasteable

Private Declare Sub CoFreeUnusedLibraries Lib "ole32.dll"()