Announcement

Collapse
No announcement yet.

Unterschiedliches Verhalten von Fusion

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Unterschiedliches Verhalten von Fusion

    Hallo.

    Ich baue gerade ein "Plugin" für eine Anwendung. Alle notwendigen DLLs (die Haupt-DLL und abhängige DLLs) sind in einem gemeinsamen Unterverzeichnis der Anwendung. Die Anwendung kann aber die DLL nicht laden, da es die abhängigen DLLs nicht laden kann - laut Fusion log sucht der nur im Anwendungsroot, nicht in dem Verzeichnis, in dem die DLL liegt.

    Das seltsamste: Ein vorhandenes Plugin funktioniert - und ich finde absolut keine (relevanten) Unterschiede.

    Fusion Log der nicht funktionierenden DLL (Log Name: "WhereRefBind!Host=(LocalMAchine)!FileName=(<name> ).HTM)
    Code:
    *** Protokolleintrag für Assembly-Binder  (02.05.2018 @ 13:39:15) ***
    
    Der Vorgang wurde durchgeführt.
    Ergebnis der Bindung: hr = 0x0. Der Vorgang wurde erfolgreich beendet.
    
    Der Assemblymanager wurde geladen aus:  C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
    Als EXE-Datei ausgeführt.  C:\XXXX\SetupWizard.exe
    --- Ein detailliertes Fehlerprotokoll folgt. 
    
    === Zustandsinformationen vor Bindung ===
    LOG: Benutzer = re-PC\re
    LOG: Where-ref-Bindung. Speicherort = C:\XXXX\yyyy\yyyy.dll
    LOG: Appbase = file:///C:/XXXX/
    LOG: Ursprünglicher PrivatePath = NULL
    LOG: DynamicBase = NULL
    LOG: CacheBase = NULL
    LOG: AppName = NULL
    Aufruf von Assembly : (Unknown).
    ===
    LOG: Diese Bindung startet im LoadFrom-Load-Kontext.
    WRN: Das systemeigene Abbild wird nicht im LoadFrom-Kontext durchsucht. Das systemeigene Abbild wird nur im Standard-Load-Kontext durchsucht, z.B. Assembly.Load().
    LOG: Es wurde keine Anwendungskonfigurationsdatei gefunden.
    LOG: Die Computerkonfigurationsdatei von C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config wird verwendet.
    LOG: Download von neuem URL file:///C:/XXXX/yyyy/yyyy.dll.
    LOG: Der Assembly-Download wurde durchgeführt. Datei-Setup wird begonnen: C:\XXXX\yyyy\yyyy.dll.
    LOG: Die von der Quelle ausgeführte Setup-Phase beginnt.
    LOG: Der Assemblyname ist: yyyy, Version=2.2.2926.507, Culture=neutral, PublicKeyToken=null.
    LOG: Die Richtlinie wird für where-ref-Bindung erneut angewendet.
    LOG: Codebasis mit where-ref-Bindung stimmt mit dem überein, was im Standardkontext gefunden wurde. Ergebnis im Standardkontext behalten.
    LOG: Der Assemblyverweis nach der Richtlinie erfordert eine erneute Suche.
    LOG: Wechseln vom LoadFrom-Kontext zum Standardkontext.
    LOG: Es wurde keine Anwendungskonfigurationsdatei gefunden.
    LOG: Die Computerkonfigurationsdatei von C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config wird verwendet.
    LOG: Die Richtlinie wird derzeit nicht auf den Verweis angewendet (private, benutzerdefinierte, teilweise oder pfadbasierte Assemblybindung)
    LOG: Download von neuem URL file:///C:/XXXX/yyyy.DLL.
    LOG: Download von neuem URL file:///C:/XXXX/yyyy/yyyy.DLL.
    LOG: Der Assembly-Download wurde durchgeführt. Datei-Setup wird begonnen: C:\XXXX\yyyy\yyyy.dll.
    LOG: Die von der Quelle ausgeführte Setup-Phase beginnt.
    LOG: Die Bindung war erfolgreich. Assembly wird zurückgegeben von C:\XXXX\yyyy\yyyy.dll.
    LOG: Die Assembly wird im default-Load-Kontext geladen.
    Log Datei des Ladeversuch der abhängigen DLL: aaaa, Version=2.2.2912.425, Culture=neutral, PublicKeyToken=6fd692c2ed1a8da2.HTM
    Code:
    *** Protokolleintrag für Assembly-Binder  (02.05.2018 @ 14:34:33) ***
    
    Fehler bei diesem Vorgang.
    Ergebnis der Bindung: hr = 0x80070002. Das System kann die angegebene Datei nicht finden.
    
    Der Assemblymanager wurde geladen aus:  C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
    Als EXE-Datei ausgeführt.  C:\XXXX\SetupWizard.exe
    --- Ein detailliertes Fehlerprotokoll folgt. 
    
    === Zustandsinformationen vor Bindung ===
    LOG: Benutzer = re-PC\re
    LOG: DisplayName = aaaa, Version=2.2.2926.507, Culture=neutral, PublicKeyToken=6fd692c2ed1a8da2
     (Fully-specified)
    LOG: Appbase = file:///C:/XXXX/
    LOG: Ursprünglicher PrivatePath = NULL
    LOG: DynamicBase = NULL
    LOG: CacheBase = NULL
    LOG: AppName = NULL
    Aufruf von Assembly : yyyy, Version=2.2.2926.507, Culture=neutral, PublicKeyToken=null.
    ===
    LOG: Diese Bindung startet im default-Load-Kontext.
    LOG: Es wurde keine Anwendungskonfigurationsdatei gefunden.
    LOG: Die Computerkonfigurationsdatei von C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config wird verwendet.
    LOG: Verweis nach der Richtlinie: aaaa, Version=2.2.2926.507, Culture=neutral, PublicKeyToken=6fd692c2ed1a8da2
    LOG: Die Suche im GAC war nicht erfolgreich.
    LOG: Download von neuem URL file:///C:/XXXX/aaaa.DLL.
    LOG: Download von neuem URL file:///C:/XXXX/aaaa/aaaa.DLL.
    LOG: Download von neuem URL file:///C:/XXXX/aaaa.EXE.
    LOG: Download von neuem URL file:///C:/XXXX/aaaa/aaaa.EXE.
    LOG: Fehler bei allen Such-URLs.
    -> Korrekter Name wäre file:///C:/XXXX/yyyy/aaaa.dll.

    Zum Vergleich das Laden des funktionierenden Plugins:
    Code:
    *** Protokolleintrag für Assembly-Binder  (02.05.2018 @ 12:58:55) ***
    
    Der Vorgang wurde durchgeführt.
    Ergebnis der Bindung: hr = 0x0. Der Vorgang wurde erfolgreich beendet.
    
    Der Assemblymanager wurde geladen aus:  C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
    Als EXE-Datei ausgeführt.  C:\XXXX\SetupWizard.exe
    --- Ein detailliertes Fehlerprotokoll folgt. 
    
    === Zustandsinformationen vor Bindung ===
    LOG: Benutzer = re-PC\re
    LOG: Where-ref-Bindung. Speicherort = C:\XXXX\zzzz\zzzza.dll
    LOG: Appbase = file:///C:/XXXX/
    LOG: Ursprünglicher PrivatePath = NULL
    LOG: DynamicBase = NULL
    LOG: CacheBase = NULL
    LOG: AppName = NULL
    Aufruf von Assembly : (Unknown).
    ===
    LOG: Diese Bindung startet im LoadFrom-Load-Kontext.
    WRN: Das systemeigene Abbild wird nicht im LoadFrom-Kontext durchsucht. Das systemeigene Abbild wird nur im Standard-Load-Kontext durchsucht, z.B. Assembly.Load().
    LOG: Es wurde keine Anwendungskonfigurationsdatei gefunden.
    LOG: Die Computerkonfigurationsdatei von C:\Windows\Microsoft.NET\Framework\v2.0.50727\config\machine.config wird verwendet.
    LOG: Download von neuem URL file:///C:/XXXX/zzzz/zzzza.dll.
    LOG: Der Assembly-Download wurde durchgeführt. Datei-Setup wird begonnen: C:\XXXX\zzzz\zzzza.dll.
    LOG: Die von der Quelle ausgeführte Setup-Phase beginnt.
    LOG: Der Assemblyname ist: zzzza, Version=1.1.0.1512, Culture=neutral, PublicKeyToken=null.
    LOG: Die Richtlinie wird für where-ref-Bindung erneut angewendet.
    LOG: Die Bindung war erfolgreich. Assembly wird zurückgegeben von C:\XXXX\zzzz\zzza.dll.
    LOG: Die Assembly wird im LoadFrom-Load-Kontext geladen.
    Unterschied:
    Bis zur Zeile "LOG: Die Richtlinie wird für where-ref-Bindung erneut angewendet." gleich, danach Unterschied.
    Funktionierendes: Erfolgreich im "LoadFrom-Load Kontext". Nicht funktionierendes: "LOG: Codebasis mit where-ref-Bindung stimmt mit dem überein, was im Standardkontext gefunden wurde. Ergebnis im Standardkontext behalten." und am Ende "LOG: Die Assembly wird im default-Load-Kontext geladen."

    Ich habe auch schon versucht das ohne Signierung zu machen - gleiches Ergebnis. Noch merkwürdiger: Es gibt Versionen der Anwendung, bei denen geht es, und Versionen, bei denen geht es nicht.

    Kann mir das bitte einer erläutern was da passiert oder Links geben, wo der Mechanismus erklärt wird?

    Danke und Grüße
    Ralph Erdt
    Zuletzt editiert von Ralph Erdt (2); 09.05.2018, 09:27. Reason: Obfusciert

  • #2
    Den Grund habe ich immer noch nicht herausgefunden, aber einige interessante Erkenntnisse und ein Work-Around:

    Die Anwendung nutzt nicht CreateInstanceAndUnwrap, sondern macht zwei Schritte: Zuerst die Assembly mit Assembly.LoadFrom("xxx") laden und dann daraus die Klasse mit assembly.CreateInstance("yyy") erstellen. Beim erstellen der Klasse treten die o.g. Probleme auf. Das heißt: Die Assembly lädt der erfolgreich, und erst beim laden der Klasse lädt der die abhängigen Assemblies. Nur hier hat der nicht mehr das Verzeichnis..

    Workaround:
    Einen ResolveEvent Handler einrichten: Beim Fehlschlag des Ladens einer DLL wird dieses Event aufgerufen, und man kann "manuell" nacharbeiten:


    Code:
            public static Assembly ResolveEventHandler(object sender, ResolveEventArgs args)
            {
                try
                {
                    String filename = args.Name;
                    int pos = filename.IndexOf(','); // Wollen wir mal hoffen, dass im Pfadnamen kein Komma ist! (TODO)
                    if (pos > 0)
                    {
                        filename = filename.Substring(0, pos);
                    }
                    filename += ".dll";
                    filename = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), filename);
                    if (File.Exists(filename))
                    {
                        return Assembly.LoadFrom(filename);
                    }
                }
                catch (Exception)
                {
                    //MessageBox.Show("Exception RH: " + e);
                }
                return null;
            }
    Da es in C# keinen Modul - statischen Code gibt (der am Anfang geladen wird) habe ich das so gelöst: Jede Klasse, die extern aufgerufen wird, hat einen static Konstruktor, der mit System.Runtime.CompilerServices.RuntimeHelpers.Run ClassConstructor(typeof(LoadingWorkaround).TypeHan dle) den static Konstruktor der Workaroundklasse aufruft. Und die Workaround Klasse hat einen static Konstruktor, der das Event anhängt: AppDomain.CurrentDomain.AssemblyResolve += ResolveEventHandler;
    (So kompliziert, damit das Event nur einmal angehängt wird)

    Comment

    Working...
    X