2012-11-04 9 views
8

lunga storia di quello che sto cercando di realizzare

Sto lavorando su un programma che carica dinamicamente DLL come plugin. Sto compilando il programma utilizzando Microsoft Visual C++ 2008. Tuttavia, supponiamo che qualsiasi versione di Visual C++ con cui funziona Qt debba essere supportata. La struttura della directory del programma è il seguente:C++: Manifest e DLL caricamento dinamico di directory diversa

| plugins/ 
| plugin1.dll 
| plugin2.dll 
| QtCore4.dll 
| QtGui4.dll 
| program.exe 

program.exe rileva tutti i file DLL plugin, esegue LoadLibrary() su di loro e chiama una certa funzione di firma per scoprire se in realtà è un plugin o meno. Funziona piuttosto bene su computer che dispongono di videoregistratore per MSVC90 installato. Naturalmente, per far funzionare il programma su tutti i computer, devo ridistribuirlo con i file msvc * .dll e con il file manifest appropriato. Anche le DLL Qt richiedono l'esecuzione della redist.

Ora, ho impostato cmake per copiare automaticamente su DLL di redist appropriate e manifestare in base alla versione di Visual Studio selezionata. Per semplicità continuiamo a supporre che sto lavorando con MSVC90. Quando il redist viene copiato nella directory del programma il layout è simile al seguente:

| plugins/ 
| plugin1.dll 
| plugin2.dll 
| QtCore4.dll 
| QtGui4.dll 
| msvcm90.dll 
| msvcp90.dll 
| msvcr90.dll 
| Microsoft.VC90.CRT.manifest (I'm also aware that this file is bugged in VS2008) 
| program.exe 

Per quanto riguarda il bug nel file manifesto: http://www.cmake.org/pipermail/cmake/2008-September/023822.html

Il problema

Il programma con questo layout ora funziona su computer che non hanno il redist installato, ma i plug-in non vengono caricati. Al fine di ottenere i plugin per caricare devo fare una delle seguenti:

  1. Copiare il file manifesto per plugins/ directory. Rimuovi tutti i riferimenti ai file msvc * .dll dal file manifest. Funziona ma non è bello perché dovrei supportare diverse versioni dei file manifest modificati a seconda della versione di MSVC utilizzato. Inoltre, non ho idea se questo non si interromperà con Visual Studio diverso dal 2008.
  2. Copia intera redist nella directory plugins/. Questo non richiede alcuna modifica al file manifest, ma ora program.exe tenta stupidamente di caricare i file msvc * .dll pensando che siano plugin. Naturalmente, questo fallisce con grazia, quindi non viene fatto alcun danno. L'altro svantaggio è che la dimensione del pacchetto del programma aumenta di oltre 1 MB. Entrambi questi problemi sono qualcosa con cui posso convivere, però.
  3. Compila plugin con l'interruttore/MT. Un breve test ha dimostrato che questo funziona davvero, ma non sono sicuro che non cambierà nulla in futuro se sia Qt che program.exe sono/MD.

La domanda (s)

Qual è la soluzione migliore? Qual è la soluzione corretta? Se esiste più di una soluzione corretta, qual è la migliore pratica? Sono la prima persona a provare a farlo?

Update 1 (18 nov 2012)

Mentre la domanda rimane senza risposta ho deciso di andare per il percorso che fa sì che il minimo mal di testa. Fino ad ora ho utilizzato la soluzione numero 1 e ho deciso di seguirlo. Se CMake rileva che l'utente sta utilizzando una versione MSVC diversa rispetto al 2008, verrà visualizzato un messaggio di avviso che informa che la confezione automatica non è completamente supportata.

+1

Perché non si collega in modo statico il tempo di esecuzione per l'app e per i plug-in? –

+0

Qt richiede già il videoregistratore, quindi dovrò includerlo comunque. Inoltre ci sono problemi con l'allocazione delle risorse quando la risorsa viene allocata in un'entità collegata staticamente e poi rilasciata in un'altra: non è sicura e il programma potrebbe bloccarsi. Non so come si comporterà con Qt se Qt è/MD. – ZalewaPL

+1

Penso che dovresti lasciare che gli autori dei plugin decidano come vogliono collegarsi alla libreria di runtime e non provare a forzarli a collegarsi dinamicamente a una particolare versione del tempo di esecuzione. Per quanto riguarda i problemi di allocazione che hai menzionato, se stai chiamando il plugin per allocare una risorsa, allora dovresti richiamare nel plugin per liberare la risorsa. –

risposta

0

Se il sistema operativo di destinazione ha _WIN32_WINNT> = 0x0502 che è possibile utilizzare la funzione

SetDllDirectory() 

prima di fare il caricamento dei plug-in.

Inserire il percorso nella cartella principale del programma.

L'ordine carico di sistema sostituzioni chiamata:

  1. La directory da cui l'applicazione caricata.
  2. La directory specificata dal percorso nella chiamata SetDllDirectory().

Quindi, è possibile chiamare la funzione dopo l'avvio dell'applicazione. È sicuro in tutti i casi. In bocca al lupo!

+0

Non sembra funzionare. – ZalewaPL

0

È possibile creare collegamenti fissi alle DLL VC con la funzione CreateHardLink() durante il processo di installazione. Con il metodo (1) che hai descritto, potrebbero esserci dei problemi con diverse copie delle DLL di VCRT. Hardlink o SetDllDirectory() sembra la soluzione migliore.

Non mescolare in un singolo processo il collegamento statico e dinamico a MSVCRT: SEMPRE crea problemi!

1

È possibile fornire percorsi di file completi a "LoadLibrary", in modo da poter caricare i plug-in con i relativi percorsi. Ho usato questo esatto layout di caricare più versioni della stessa libreria dalla sottodirectory della dll corrente in Visual Studio 2005.

Innanzitutto è necessario per ottenere il percorso corrente della dll corrente utilizzando:

static LPSTR strDLLPath1 = new TCHAR[_MAX_PATH+1]; 
::GetModuleFileName((HINSTANCE)&__ImageBase, strDLLPath1, _MAX_PATH); 

Anche se il tuo programma.exe sta già scoprendo questi file plugin, suppongo che tu abbia già accesso ai loro percorsi completi.

Problemi correlati