Laden...

[gelöst] Probleme mit Pfaden...

Erstellt von typhos vor 17 Jahren Letzter Beitrag vor 17 Jahren 2.511 Views
T
typhos Themenstarter:in
243 Beiträge seit 2006
vor 17 Jahren
[gelöst] Probleme mit Pfaden...

Hallo,
ich bin gerade dabei, mein erstes AddIn zu entwickeln. Theoretisch funktioniert das auch ganz gut.
Aber zu meinem Problem:
Ich habe in VS 2005 ein AddIn-Projekt erstellt. Dieses benutzt zwei andere Assemblies, die ich ganz normal per Referenz hinzugefügt habe.
Mein erstes Problem habe ich mit der Konfigurationsdatei, die ich für das AddIn benötige. Da das AddIn ja "nur" eine DLL ist und Office (in meinem Fall Word) die eigentliche anwendung, funktioniert die app.config nicht - ich muss sie als WINWORD.EXE.config in das Office-Verzeichnis kopieren, damit sie gefunden wird. Das fidne ich allerdings sehr bescheiden, da ich das AddIn ja nicht direkt ins Office-Verzeichnis installieren möchte.
Das zweite Problem ist die referenzierte Assembly. Diese wird nämlich auch nicht gefunden, da das AddIn selbst nicht im Office-Verzeichnis liegt.

Muss ich die Assemblies irgendwie anders referenzieren oder hinzufügen, damit sie im AddIn-Verzeichnis gefunden werden. Ebenso soll die config-Datei im AddIn-Verzeichnis verbleiben. Hat jemand eine Idee, was ich dazu tun muss? Muss ich irgendwelche Pfade oder dergleichen setzen?
Oder befinde ich mich total auf dem Holzweg??

Danke für jeden Tipp bzw. jede Idee!

T
typhos Themenstarter:in
243 Beiträge seit 2006
vor 17 Jahren

Nochmal zur Verdeutlichung: Wenn ich alle DLLs in das Office-Verzeichnis lege, funktioniert alles einwandfrei. Nur möchte ich die DLLs sowie die config im Installationsverzeichnis des AddIns belassen...

3.728 Beiträge seit 2005
vor 17 Jahren
Registry & GAC

Office-Add-Ins leben in der Office Welt. Office ist COM und bei COM müssen DLLs in der Registry registriert sein, damit die Office-Anwendung weiss, aus welchem Pfad die DLL zu laden ist. Um das zu erreichen musst Du die Plug-In-Assembly und alle von ihr verwendeten Assemblies im GAC eintragen (gacutil -i Assembly.dll). Die Assemblies müssen dazu alle einen Starken Namen haben (Also mit einer snk-Datei signiert sein). Außerdem sollte die automatische Versionierung nicht verwendet werden (Das spart Nerven).

Was die app.config-Datei angeht, kann ich Dir nur wärmstens empfehlen, Deine Konfiguration in der Registry abzulegen. Das ist ganz einfach (Microsoft.Win32.Regsitry). Auch wenn es überall heißt, dass Registry schlecht wäre (Einen wirklichen Nachteil einer Registry basierten Konfiguration konnte mir bis jetzt noch niemand nennen). Wenn Du ein Office-Add-In schreibst, machst Du solche Sachen am besten wie in der Office-Welt üblich: Also ab in die Registry mit dem Konfigurationskram.

Mit GAC und Registry dürften sich Deine Probleme in Luft auflösen.

T
typhos Themenstarter:in
243 Beiträge seit 2006
vor 17 Jahren

Danke für die ausführliche Antwort. Ich werde das gleich ausprobieren! 👍

T
typhos Themenstarter:in
243 Beiträge seit 2006
vor 17 Jahren

Hmm, ich habe es jetzt so versucht, wie Du es erklärt hast.
Allerdings bekomme ich nun folgende Fehlermeldung, wenn das AddIn in Word geladen wird:

Auf den Typ TYP kann aufgrund von Sicherheitseinschränkungen nicht zugegriffen werden.

Der Typ TYP liegt in einem zusätzlichen Assembly, was ich nun mit einem starken Namen versehen und in den GAC geladen habe - wie Du geschrieben hast. Die AddIn-Assembly habe ich natürlich auch in den GAC geladen.
Habe ich etwas vergessen oder falsch gemacht??

3.728 Beiträge seit 2005
vor 17 Jahren
Sicherheit

Entweder liegt es an den CAS-Rechten für die .NET Assemblies, oder an den Office-Sicherheitseinstellungen für Add-Ins und Makros.

Du solltest den Assemblies zum Test mal den Fullthrust-Berechtigungssatz (CAS-Richtlinie) zuweisen (Am besten über PublicKeyToken referenzieren).

T
typhos Themenstarter:in
243 Beiträge seit 2006
vor 17 Jahren

Also in Word ist "Allen installierten AddIns und Vorlagen vetrauen" aktiviert.

Wie kann ich den Assemblies denn den Fulltrust-Berechtigungssatz zuweisen?

T
typhos Themenstarter:in
243 Beiträge seit 2006
vor 17 Jahren

Was ich noch vergessen habe zu schreiben, ist Folgendes:

Die AddIn-Assembly greift (nachdem das AddIn geladen wurde) auf eine der beiden zusätzlichen DLLs zu - das funktioniert auch, egal ob ich die Assemblies in den GAC geladen habe oder nicht. Diese zusätzliche Assembly grieft aber wiederum auf die andere, zweite zusätzliche DLL zu. Und dabei bekomme ich ohne den GAC zu benutzen eine FileNotFound-Exception oder aber mit GAC eine SecurityException.

Hilft diese Info vielleicht weiter, um mir zu helfen =)

Ich weiß echt nicht mehr, was ich tun soll. Wie schon geschrieben: Packe ich alle drei DLLs (AddIn-Assembly und die beiden zusätzlichen) in das Office-Verzeichnis, klappt alles...

Mittlerweile habe ich auch einen neuen Berechtigungssatz mit FullTrust für die Assemblies angelegt - keine Veränderung: SecurityException beim Zugriff auf die zweite zusätzliche Assembly 🤔

369 Beiträge seit 2006
vor 17 Jahren

Zunächst sollte gesagt werden, dass Assemblies im GAC eigentlich immer Full Trust haben. Der Grund für die Security Exception ist wahrscheinlich die hinzugekommene Signierung der Assembly, denn nun darf deren Funktionalität nur noch von anderen Assemblies mit Strong Name genutzt werden (es sei denn, du verwendest das Attribut [AllowPartiallyTrustedCallers()]. Außerdem darf die Assembly selber auch bloß noch Assemblies mit starkem Namen verwenden. Bei einer GAC-Assembly muss die referenzierte Assembly überdies ebenfalls im GAC liegen.

T
typhos Themenstarter:in
243 Beiträge seit 2006
vor 17 Jahren

Danke, aber es liegen ja alle 3 Assemblies im GAC. Und ohne dass ich diese Assemblies signiere, kann ich sie doch gar nicht in den GAC packen, oder?

Geht es denn auch irgendwie ohne GAC?

3.728 Beiträge seit 2005
vor 17 Jahren
Alles in den GAC

Du musst alles in den GAC legen und alles muss einen Strong Name haben. Alle Assemblies, die aufgerufen werden (und auch die von denen aufgerufenen). Da können schon einige Assemblies zusammenkommen.

Problematisch ist das oft bei Assemblies von Fremdherstellern (Irgendwelche Frameworks, Controls, etc.), die einfach nicht signiert sind.

Du kannst Assemblies auch von Hand laden. Das geht mit Reflection. Dazu genügt es zu wissen, wo die Assembly liegt (Was wiederum in der Registry abgelegt werden kann). Also ganz ohne GAC.

T
typhos Themenstarter:in
243 Beiträge seit 2006
vor 17 Jahren

Hi,
danke für die Antworten!

Ich habe mich jetzt mal drangesetzt und versuche das Ganze mit Reflection. Dazu habe ich aber auch noch eine Frage:

Wenn ich die Assemblies manuell über Reflection nachlade, dann kann ich die Typen/Klassen darin doch aber nur mit

Activator.CreateInstance(myAssembly.GetType("..."))

ansprechen, oder?
Das ist aber auch nicht sonderlich schön, da ich in diesem Fall die beiden zusätzlich geladenen Assemblies auch wieder ändern müsste, weil dort die Typen ganz normal aufgerufen werden.
Gibt es denn eine Möglichkeit, die Assemblies manuell zu laden und sie so bekannt zu machen, dass man ganz normal auf die Typen zugreifen kann, wie es auch bei Assemblies geht, die man per Referenz/Verweis hinzugefügt hat?

btw: Ich habe die Assemblies jetzt mal per Reflection geladen und die Typen trotzdem ganz normal aufgerufen, also ganz normal Objekte erzeugt. Rufe ich nun eine Methode davon auf, kommt nicht mehr die FileNotFoundException, sondern eine InvalidCastException "Das Rückgabeargument hat einen ungültigen Typ.". Finde ich irgendwie merkwürdig...

Ich hoffe weiterhin auf eure Hilfe! Aber vielen Dank schonmal für die bisherigen Tipps/Ideen udn Hinweise!

T
typhos Themenstarter:in
243 Beiträge seit 2006
vor 17 Jahren

Noch etwas:
Ich habe mir gerade eine Liste der geladenen Assemblies in der aktuellen AppDomain angesehen. Die beiden zusätzlichen Assemblies tauchen dort auch auf!
Also scheint das Laden ja problemlos zu funktionieren.

Aber warum bekomme ich dann eine InvalidCastException? Die Methode liefert einen bool-Wert (normalerweise!), warum sollte sich das denn durch das "neue" Laden über Reflections ändern?

T
typhos Themenstarter:in
243 Beiträge seit 2006
vor 17 Jahren

Hallo!

Ich denke, ich habe es jetzt hinbekommen. Und zwar habe ich nach langem Suchen folgende Lösung gefunden:

Und zwar registriere ich den ResolveEventhandler

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

mit folgender Methode:

        Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    string[] asmName = args.Name.Split(',');

    Assembly cAsm = this.GetType().Assembly;
    string cAddInPath = System.IO.Path.GetDirectoryName(cAsm.Location);

    string asmPath = System.IO.Path.Combine(cAddInPath, asmName[0] + ".dll");
    if (!System.IO.File.Exists(asmPath)) 
        throw (new Exception("Assembly " + asmName[0] + " not found."));
    return Assembly.LoadFile(asmPath, Assembly.GetExecutingAssembly().Evidence);
}

Damit werden die Assemblies, die nicht im GAC oder im Office-Verzeichnis gefunden werden aus dem Verzeichnis der AddIn-DLL nachgeladen, sobald diese benötigt werden.