Verweis einer managed DLL - Wird in Unterverzeichnis nicht gefunden.



  • Hallo,

    hab ne weile jetzt gesucht und keine Lösung für mein Problem gefunden, oder ich such nach den falschen Begriffen. Also nicht Böse sein, wenn's schon irgendwo nen Thread mit der Lösung gibt.

    Folgendes Problem:
    MainApp.exe lädt z.b. die myDLL.dll
    Beides managed Code - Habe den Verweis zur DLL über "Neuen Verweis" -> "Projekte" hinzugefügt. Das funktioniert auch super.

    Nachdem mein Projekt nun etliche Dateien enthält, wollte ich nun etwas aufräumen und die DLLs in ein Unterverzeichnis \libs verschieben. Also kurzerhand das Postbuild-Ereignis zum kopieren der Dateien geändert; Das Build-Ziel der DLLs auf \release\libs geändert und im MainApp die Verweise von "lokale Kopie: true" auf false gestellt.

    Und siehe da.... Nix geht. Die DLLs werden nicht gefunden. Im managed Code kann so schön die DLLs einbinden. Erzählt mir jetzt bitte nicht, dass man das Untervezeichnis nicht ändern kann?

    Wenn nicht, gibt's nen "way around"? Ich möchte das Projekt schon aufräumen.

    Gruß,
    Frank



  • Die managed DLLs werden einmal im GAC und dann AFAIK in den üblichen Suchpfaden einer DLL gesucht. Dazu zählt ein Unterverzeichnis nicht.

    Es gibt die Möglichkeiten die Assembly manuell zu laden. Assembly.Load , Assembly.LoadFile , Assembly.LoadFrom. (Wird z.B. auch für Plugins verwendet.) Schau Dir das Thema in der MSDN mal an, es gibt mehrere Arten, alle mit vor und Nachteilen behaftet.



  • Das mit GAC hatte ich mir überlegt. Fand aber, dass das mit Kanonen auf Spatzen schiessen ist. Die DLLs braucht ja nur mein Programm.

    Das Andere werd ich mir mal anschaun. Danke.

    EDIT: Dachte nur es geht einfacher....



  • Das Laden über Assembly::Load usw... war nicht sehr zufriedenstellend.

    Ich habe aber jetzt doch einen andere Möglichkeit gefunden.

    Man fügt erst mal den DLLs "Strong Names" hinzu. Man erhält so einen publicKeyToken.

    Dazu braucht man erst mal ein KeyPair:

    C:\Programme\Microsoft Visual Studio 8\SDK\v2.0\Bin\sn.exe -k myDLL.snk
    

    Das legt man in das Projektverzeichnis mit den Quelldateien der DLL.
    Unter Projekteingenschaften->Konfigurationseigenschaften->Linker->Erweitert->Schlüsseldatei wird dann myDLL.snk eigetragen. Danach bearbeitet man die AssemblyInfo.cpp der DLL.

    [assembly:AssemblyKeyFileAttribute("myDLL.snk")];
    

    Das macht man für alle DLLs. Nun kompiliert man die DLLs und macht dann für alle folgendes.

    C:\Programme\Microsoft Visual Studio 8\SDK\v2.0\Bin\sn.exe -T myDLL.dll
    

    Man erhält so den publicKeyToken der DLL. Ist hier aber nicht unbedingt nötig. (Nur um mal zu zeigen wie's geht.)

    sn.exe hab ich mir übrigens unter Extras->Externe Tools hinzugefügt.

    Nun braucht man nur noch eins - Eine app.config.

    Man legt diese unter MyApp.exe.config in das Zielverzeichnis und kompiliert alles noch mal.

    myApp.exe.config

    <configuration>
      <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
          <probing privatePath="libs"/>
        </assemblyBinding>
      </runtime>
    </configuration>
    

    libs ist hier mein Unterverzeichnis für die DLLs und natürlich austauschbar.

    Das ist für alle, die an diesem Problem scheitern. Ich finde Threads bei denen einer schreibt: "Ja super, klappt jetzt so." oder "Habs Heut selber rausgefunden." gelinde gesagt .....! Da hat Keiner was davon. Wem geholfen wird, oder es doch selber hinbekommt - Bitte immer eine kurze Wegbeschreibung. Ein Problem, dass nur einmal auftritt, gibt es fast nicht. Wer also noch Fragen hat, bitte!

    Gruß,
    Frank



  • Hallo Frank,

    vielen Dank für die Information und vor allem für die Einstellung andere an der Lösung teil haben zu lassen.

    Btw. Mit nem Strongname kannst Du die Assembly auch in die GAC packen, die Ladezeiten müssten sich durch die Vertrauensstellung verkürzen.

    @Jochen, besteht die Möglichkeit das in die FAQ aufzunehmen ? Ich finde die Information wertvoll aber schwer zu finden wenn man sie benötigt, würde mich aber freuen eine solche Information schnell in der FAQ auf zu finden.



  • Hallo!
    Ich habe ein ähnliches Problem.

    Wenn ich eine exe habe, die eine Dll verwendet, funktioniert das Ganze recht gut, wenn man im Manifest probing verwendet.

    In meinem Fall erstelle ich jedoch ein COM-Objekt, das wiederum Assemblys in Unterverzeichnissen verwenden soll.
    Zum Testen habe ich eine externe Exe (z.B. Excel) verwendet und dort mit VBA und CreateObject() ein Objekt erzeugt. Wenn ich jedoch in einer Funktion in c# auf ein anderes Assembly (in einem Unterverzeichnis) zugreifen möchte, findet er das nicht.

    Gibt es eine Möglichkeit, den Suchpfad irgendwo zu definieren? Eine DLL kann anscheinend kein Manifest erhalten (c#: Projekteinstellungen: es gibt keine Option ein Manifest auszuwählen).
    Es wäre für mich auch möglich, den Pfad ("lib") irgendwo hardcoded zu definieren.

    Hat jemand sowas schon mal gehabt?
    Joe



  • Du kannst das AppDomain.AssemblyResolve-Ereignis nutzen, um dort dann explizit die Assemblies aus dem Unterverzeichnis zu laden (dann wiederum mit Assembly.Load(File/From)).


Log in to reply