Domanda

Ricevo System.IO.FileNotFoundException: impossibile trovare il modulo specificato quando si esegue il codice C # che chiama un assembly C ++ / CLI che a sua volta chiama un DLL C pura. Succede non appena viene istanziato un oggetto che chiama le funzioni C DLL pure.

BackingStore è puro C. CPPDemoViewModel è C ++ / CLI che chiama BackingStore ha un riferimento a BackingStore.

Ho provato il caso più semplice possibile: aggiungere un nuovo progetto di unit test C # che tenta solo di creare un oggetto definito in CPPDemoViewModel. Ho aggiunto un riferimento dal progetto C # a CPPDemoViewModel.

Un progetto di test C ++ / CLI funziona bene con solo il riferimento aggiunto a CPPDemoViewModel, quindi si tratta di passare da una lingua all'altra.

Sto usando Visual Studio 2008 SP1 con .Net 3.5 SP1. Sto costruendo su Vista x64 ma sono stato attento ad assicurarmi che il mio obiettivo di piattaforma sia impostato su x86.

Mi sembra che manchi qualcosa di stupido ed ovvio, ma sarebbe ancora più stupido da parte mia perdere tempo a cercare di risolverlo in privato, quindi sono qui imbarazzante!

Questo è un test per un progetto che porta un'enorme quantità di codice C legacy che sto conservando in una DLL con un ViewModel implementato in C ++ / CLI.

modifica Dopo aver controllato le directory, posso confermare che BackingStore.dll non è stato copiato.

Ho le cartelle di progetto uniche standard create con una tipica soluzione multi-progetto.

WPFViewModelInCPP
  BackingStore
  CPPViewModel
  CPPViewModelTestInCS
    bin
      Debug
  Debug

Il debug di livello superiore sembra essere una cartella comune utilizzata dai progetti C e C ++ / CLI, con mia sorpresa.

WPFViewModelInCPP \ Debug contiene BackingStore.dll, CPPDemoViewModel.dll, CPPViewModelTest.dll e i relativi file .ilk e .pdb associati

WPFViewModelInCPP \ CPPViewModelTestInCS \ bin \ Debug contiene i file CPPDemoViewModel e CPPViewModelTestInCS .dll e .pdb ma non BackingStore. Tuttavia, la copia manuale di BackingStore in quella directory non ha corretto l'errore.

CPPDemoViewModel ha impostato la proprietà Copia locale che presumo sia responsabile della copia della sua DLL quando si fa riferimento. Non riesco ad aggiungere un riferimento da un progetto C # a una DLL C pura - dice solo Impossibile aggiungere un riferimento al Backing Store.

Non sono sicuro di avere solo un problema o due.

Posso usare un passaggio di compilazione di copia vecchio stile per copiare BackingStore.dll in qualsiasi directory del progetto C #, anche se speravo che il nuovo modello .net non lo richiedesse.

DependencyWalker mi sta dicendo che il file mancante è GPSVC.dll che è stato suggerito indica problemi di impostazione della sicurezza. Sospetto che si tratti di un'aringa rossa.

edit2 Con una copia manuale di BackingStore.dll adiacente all'eseguibile, la GUI ora funziona correttamente. Il progetto di test C # presenta ancora problemi che sospetto siano dovuti all'ambiente di runtime di un progetto di test, ma per ora posso vivere senza quello.

È stato utile?

Soluzione 2

La risposta per la GUI, oltre alla modifica delle impostazioni di output, è stata l'aggiunta di una fase di pre-compilazione

copy $(ProjectDir)..\Debug\BackingStore.* $(TargetDir)

La risposta per i progetti di test è stata l'aggiunta della DLL mancante alla scheda Deployment di testrunconfig. Puoi farlo modificando direttamente LocalTestRun.testrunconfig predefinito (appare in Soluzione in Elementi soluzione) oppure fai clic con il pulsante destro del mouse sulla soluzione e aggiungi una nuova configurazione di esecuzione test, che verrà quindi visualizzata nel Test principale menu.

Grazie per le risposte su questa domanda SO sulle configurazioni di test per avermi portato alla risposta.

Altri suggerimenti

Le DLL C e C ++ si trovano nella stessa directory dell'assembly C # in esecuzione?

Potrebbe essere necessario modificare le impostazioni di output del progetto in modo che l'assembly C # e le altre DLL finiscano tutti nella stessa cartella.

Ho usato spesso Dipendente Walker in casi come questo; è un controllo di integrità che mostra che tutte le dipendenze possono essere effettivamente trovate.

Una volta eseguita l'app, potresti anche provare Process Monitor sul codice in esecuzione, per vedere a quali DLL si fa riferimento e dove si trovano.

Il motivo per cui ciò accade è perché si sta caricando DLLMAIN dal codice gestito, prima che il CRT abbia l'opportunità di essere inizializzato. Potresti non avere alcun codice gestito, essere eseguito DIRETTAMENTE o INDERETTAMENTE da un effetto delle notifiche DllMain. (Vedi: Expert C ++ / CLI: .Net per programmatori Visual C ++, capitolo 11 ++).

Oppure non hai nessun punto di accesso nativo definito wahtsoever, eppure sei collegato a MSVCRT. Il CLR viene inizializzato automaticamente con / clr, questo dettaglio crea molta confusione e deve essere preso in considerazione. Una DLL in modalità mista in realtà ritarda il caricamento del CLR mediante l'uso di hot patching di tutti i punti di accesso gestiti gestiti nelle classi.

Una serie di problemi di inizializzazione della classe circondano questo argomento, a volte il blocco del caricatore e il caricamento ritardato del CLR sono un po 'trickey. Prova a dichiarare statico globale e non usare #pragma gestito / non gestito, isola il tuo codice con / clr per file.

Se non riesci a isolare il tuo codice dal codice gestito e stai riscontrando problemi (dopo aver seguito alcuni di questi passaggi), puoi anche cercare di ospitare tu stesso il CLR e magari passare attraverso lo sforzo di creare un gestore dominio, ciò garantirebbe il tuo "in-the-loop" pieno di eventi di runtime e bootstrap.

Questo è esattamente il motivo per cui non ha nulla da fare con il percorso di ricerca o l'inizializzazione. Sfortunatamente il visualizzatore di log di Fusion non aiuta molto (che è il solito posto dove cercare i problemi di associazione dell'assemblaggio CLR .NET non il walker delle dipendenze).

Anche il collegamento statico non ha nulla a che fare con questo. Puoi NON collegare staticamente un'applicazione C ++ / CLI in modalità mista.

  1. Posiziona la tua funzione DLLMAIN in un file da sola.
  2. Assicurati che NON abbia / CLR impostato nelle opzioni di compilazione ( file opzioni di compilazione)
  3. Assicurati che il tuo collegamento con / MD o / MDd e tutte le dipendenze con cui LINK utilizzino lo stesso CRT esatto.
  4. Valuta le impostazioni del tuo linker per / DEFAULTLIB e / INCLUDE per identificare eventuali problemi di riferimento possibili, puoi dichiarare un prototipo nel tuo codice e utilizzare / INCLUDE per sovrascrivere la risoluzione predefinita del link della libreria.

Buona fortuna, controlla anche che il libro sia molto buono.

Questo è un dilemma interessante. Non ho mai sentito parlare di un problema durante il caricamento di .DLL nativi da C ++ / CLI dopo una chiamata da C # prima. Posso solo supporre che il problema sia @Daniel L ha suggerito, e che il tuo .DLL semplicemente non è in un percorso che il caricatore di assiemi può trovare.

Se il suggerimento di Daniel non funziona, ti suggerisco di provare a collegare staticamente il codice C nativo al programma C ++ / CLI, se puoi. Ciò risolverebbe sicuramente il problema, poiché il .DLL verrebbe quindi completamente assorbito dal .DLL C ++ / CLI.

Assicurarsi che il sistema di destinazione abbia il runtime MS Visual C corretto e che non si stia costruendo accidentalmente la DLL con un runtime di debug.

Si è verificato lo stesso problema passando a Vista a 64 bit. La nostra applicazione chiamava DLL Win32 che confondeva la build di destinazione per l'applicazione. Per risolverlo abbiamo fatto quanto segue:

  1. Vai alle proprietà del progetto;
  2. Seleziona la scheda Build;
  3. Modifica l'opzione "Target piattaforma:" in x86;
  4. Ricostruisci l'applicazione.

Quando ho rieseguito l'applicazione ha funzionato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top