C # zu C ++ / CLI zu C DLL System.IO.FileNotFoundException

7

Ich erhalte System.IO.FileNotFoundException: The specified module could not be found bei der Ausführung von C # -Code, der eine C ++ / CLI-Assembly aufruft, die wiederum eine reine C-DLL aufruft. Es passiert, sobald ein Objekt instanziiert wird, das die reinen C DLL-Funktionen aufruft.

BackingStore ist reines C. CPPDemoViewModel ist C ++ / CLI, das BackingStore aufruft, hat einen Verweis auf BackingStore.

Ich habe den einfachsten Fall ausprobiert - fügen Sie ein neues C # -Einheitstestprojekt hinzu, das gerade versucht, ein in CPPDemoViewModel definiertes Objekt zu erstellen. Ich habe eine Referenz aus dem C # -Projekt zu CPPDemoViewModel hinzugefügt.

Ein C ++ / CLI-Testprojekt funktioniert nur mit dem hinzugefügten ref zu CPPDemoViewModel, also geht es darum, zwischen den Sprachen zu wechseln.

Ich verwende Visual Studio 2008 SP1 mit .Net 3.5 SP1. Ich baue auf Vista x64 auf, habe aber darauf geachtet, dass mein Platform-Ziel auf x86 gesetzt ist.

Das fühlt sich an wie etwas Dummes und Offensichtliches, das ich vermisse, aber es wäre noch dümmer von mir, Zeit damit zu verschwenden, es privat zu lösen, also bin ich hier draußen und peinlich!

Dies ist ein Test für ein Projekt, bei dem eine große Menge von altem C-Code portiert wird, den ich in einer DLL mit einem in C ++ / CLI implementierten ViewModel aufbewahre.

Bearbeiten Nach dem Überprüfen der Verzeichnisse kann ich bestätigen, dass die BackingStore.dll nicht kopiert wurde.

Ich habe die standardmäßigen eindeutigen Projektordner, die mit einer typischen Multiprojektlösung erstellt wurden.

%Vor%

Der Debuggen auf höherer Ebene scheint zu meiner Überraschung ein allgemeiner Ordner zu sein, der von C- und C ++ / CLI-Projekten verwendet wird.

WPFViewModelInCPP \ Debug enthält BackingStore.dll, CPPDemoViewModel.dll, CPPViewModelTest.dll und die zugehörigen .ILK- und .PDB-Dateien

WPFViewModelInCPP \ CPPViewModelTestInCS \ bin \ Debug enthält die Dateien CPPDemoViewModel und CPPViewModelTestInCS .dll und .pdb aber nicht BackingStore. Das manuelle Kopieren von BackingStore in dieses Verzeichnis hat den Fehler jedoch nicht behoben.

CPPDemoViewModel hat die Eigenschaft Copy Local gesetzt, von der ich annahm, dass sie für das Kopieren ihrer DLL verantwortlich ist, wenn if darauf verwiesen wird. Ich kann keine Referenz von einem C # -Projekt zu einer reinen C-DLL hinzufügen - es wird nur angegeben. Ein Verweis auf den Sicherungsspeicher konnte nicht hinzugefügt werden.

Ich bin mir nicht sicher, ob ich nur ein oder zwei Probleme habe.

Ich kann einen altmodischen Kopier-Build-Schritt verwenden, um die BackingStore.dll in die Verzeichnisse eines bestimmten C # -Projekts zu kopieren, obwohl ich gehofft hatte, dass das neue .net-Modell dies nicht benötigt.

DependencyWalker teilt mir mit, dass die fehlende Datei GPSVC.dll ist. wurde vorgeschlagen zeigt Sicherheitseinstellungen an Probleme. Ich vermute, das ist ein Ablenkungsmanöver.

edit2 Mit einer manuellen Kopie der BackingStore.dll neben der ausführbaren Datei funktioniert die GUI nun einwandfrei. Das C # -Testprojekt hat immer noch Probleme, von denen ich vermute, dass sie auf die Laufzeitumgebung eines Testprojekts zurückzuführen sind, aber ich kann vorerst davon leben.

    
Andy Dent 15.03.2009, 04:39
quelle

6 Antworten

4

Die Antwort für die GUI war neben der Änderung der Ausgabeeinstellungen die Hinzufügung eines Pre-Build-Schritts

%Vor%

Die Antwort für die Testprojekte war das Hinzufügen der fehlenden DLL zur Registerkarte "Bereitstellung" von testrunconfig. Sie können dies entweder tun, indem Sie direkt den Standard LocalTestRun.testrunconfig bearbeiten (wird in Solution unter Solution Items angezeigt) oder klicken Sie mit der rechten Maustaste auf die Lösung und fügen Sie eine neue Testlaufkonfiguration hinzu, die dann unter dem Haupttest angezeigt wird Menü.

Danke für die Antworten auf diese SO-Frage zu Testkonfigurationen um mich zu der Antwort zu führen.

    
Andy Dent 17.03.2009, 07:46
quelle
11

Sind die C- und C ++ - DLLs im selben Verzeichnis wie die C # -Assembly, die ausgeführt wird?

Sie müssen möglicherweise Ihre Projektausgabeeinstellungen ändern, damit die C # -Assembly und die anderen DLLs alle in demselben Ordner landen.

Ich habe oft den Dependency Walker in solchen Fällen verwendet; Es ist eine Plausibilitätsprüfung, die zeigt, dass alle Abhängigkeiten tatsächlich gefunden werden können.

Sobald Ihre App ausgeführt wird, können Sie auch Process Monitor auf der Seite ausprobieren Code, den Sie ausführen, um zu sehen, auf welche DLLs verwiesen wird und wo sie sich befinden.

    
Daniel LeCheminant 15.03.2009 04:42
quelle
4

Der Grund dafür ist, dass Sie entweder DLLMAIN aus verwaltetem Code laden, bevor der CRT eine Gelegenheit zur Initialisierung hat. Sie haben möglicherweise keinen verwalteten Code, der DIREKT oder INDErTLICH aufgrund eines Effekts von DllMain-Benachrichtigungen ausgeführt wird. (Siehe: Experten-C ++ / CLI: .Net für Visual C ++ - Programmierer, Kapitel 11 ++).

Oder Sie haben keinen nativen Einstiegspunkt definiert, obwohl Sie mit MSVCRT verbunden sind. Die CLR wird automatisch mit / clr für Sie initialisiert, dieses Detail verursacht viel Verwirrung und muss berücksichtigt werden. Eine DLL im gemischten Modus lädt die CLR durch das Hot-Patching aller verwalteten Zugriffspunkt-VTables in Ihren Klassen.

Eine Reihe von Klasseninitialisierungsproblemen umgeben dieses Thema, Loader Lock und Delay Loading CLR sind manchmal etwas trickreich. Versuchen Sie, global static zu deklarieren und #pragma managed / unmanaged nicht zu verwenden, isolieren Sie Ihren Code mit / clr per-file.

Wenn Sie Ihren Code nicht vom verwalteten Code isolieren können und Probleme haben (nachdem Sie einige dieser Schritte ausgeführt haben), können Sie auch auf das Hosting der CLR selbst schauen und vielleicht die Erstellung eines Domain-Managers das würde sicherstellen, dass Runtime-Ereignisse und Bootstrapping vollständig "in der Schleife" ausgeführt werden.

Genau aus diesem Grund hat es nichts mit Ihrem Suchpfad oder der Initialisierung zu tun. Leider hilft der Fusion-Protokoll-Viewer nicht so viel (das ist der übliche Ort, um nach Problemen mit .NET-CLR-Assembly-Bindungen und nicht nach Abhängigkeiten zu suchen).

Das statische Verbinden hat auch nichts damit zu tun. Sie können NICHT eine C ++ / CLI-Anwendung statisch verknüpfen, bei der es sich um einen gemischten Modus handelt.

  1. Platzieren Sie Ihre DLLMAIN-Funktion selbst in eine Datei.
  2. Stellen Sie sicher, dass diese Datei NICHT in den Erstellungsoptionen ( Datei Erstellungsoptionen)
  3. / CLR festgelegt ist
  4. Stellen Sie sicher, dass Ihre Verbindung mit / MD oder / MDd und alle Ihre Abhängigkeiten, die Sie LINK verwenden, genau die gleiche CRT verwenden.
  5. Werten Sie die Einstellungen Ihres Linkers für / DEFAULTLIB und / INCLUDE aus, um mögliche Referenzprobleme zu identifizieren. Sie können im Code einen Prototyp deklarieren und / / INCLUDE verwenden, um die Auflösung der Standardbibliotheksverbindung zu überschreiben.

Viel Glück, überprüfen Sie auch dieses Buch, es ist sehr gut.

    
RandomNickName42 19.05.2009 05:33
quelle
1

Das ist ein interessantes Dilemma. Ich habe nie von einem Problem gehört, das native .DLLs von C ++ / CLI nach einem Anruf von C # vorher lädt. Ich kann nur annehmen, dass das Problem als ist @Daniel L vorgeschlagen, und dass Ihre .DLL ist einfach nicht in einem Pfad der Assembly Loader finden kann.

Wenn Daniels Vorschlag nicht funktioniert, schlage ich vor, dass Sie versuchen, den nativen C-Code statisch mit dem C ++ / CLI-Programm zu verknüpfen, wenn Sie können. Das würde das Problem sicherlich lösen, da die .DLL dann vollständig in C ++ / CLI .DLL absorbiert würde.

    
Randolpho 15.03.2009 05:03
quelle
1

Stellen Sie sicher, dass das Zielsystem über die richtige MS Visual C-Laufzeit verfügt und dass Sie die C-DLL nicht versehentlich mit einer Debug-Laufzeit erstellen.

    
leppie 15.03.2009 06:10
quelle
0

Hatte das gleiche Problem auf 64-Bit-Vista zu wechseln. Unsere Anwendung rief Win32-DLLs auf, die den Zielbuild für die Anwendung verwirrten. Um es zu lösen, haben wir folgendes gemacht:

  1. Gehe zu den Projekteigenschaften;
  2. Wählen Sie die Registerkarte Erstellen;
  3. Ändern Sie die Option "Platform target:" auf x86;
  4. Erstellen Sie die Anwendung neu.

Wenn ich die Anwendung erneut ausgeführt habe, funktionierte es.

    
Matt H 14.07.2009 15:47
quelle