DLL-Methoden hinzufügen (.NET 2 FORTRAN)

From BlueM
Jump to navigation Jump to search

Anleitung für das Hinzufügen neuer Methoden in eine Modell-DLL (am Beispiel von BlueM.Sim)

Hinzufügen der neuen Methode in der BlueM.Sim Fortran-DLL

1
2
3
4
5
logical function GetModelDescription(Description)
!DEC$ ATTRIBUTES DLLEXPORT :: GETMODELDESCRIPTION
character(*) Description
    ...
end function
  • Funktionsname und DLLEXPORT-Name müssen gleich sein !
  • Übergabeparameter müssen definiert sein (und die Typen sollten so einfach wie möglich sein) !


Tip
Kontrollieren, ob der Export funktioniert hat, kann man mit dem DependencyWalker des Visual Studios
C:\Programme\Microsoft Visual Studio 8\Common7\Tools\Bin\Depends.Exe.
Dort werden alle exportierte Methoden aufgelistet.

Erweiterung des DLL-Wrappers (C#)

Die Methoden der DLL werden aus der Klasse DLLMethoden aufgerufen.

  1. Hinzufügen des Delegats in DLLMethoden
  2. Hinzufügen der Schnittstellenmethode
  3. Hinzufügen einer Testmethode (siehe UnitTest)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class DLLMethoden
{      
        ...
        delegate bool GetModelDescriptionDelegate([MarshalAs(UnmanagedType.LPStr)] StringBuilder description, uint length);
        ...
        public bool GetModelDescription(StringBuilder description, uint length)
        {
            if (myDll == IntPtr.Zero)
                InitializeMyDll(pathToDll);
            IntPtr pProc = DllImportDynamic.GetProcAddress(myDll, "OPENMI_mp_GETMODELDESCRIPTION");
            GetModelDescriptionDelegate cpv = (GetModelDescriptionDelegate)Marshal.GetDelegateForFunctionPointer(pProc, typeof(GetModelDescriptionDelegate));
            return cpv(description, (uint)description.Length);
        }       
        ...
}

Delegate

Eine Delegatmethode ist eine Art "Platzhalter". in diesem Beispiel fungiert sie als Platzhalter für die Fortran-DLL. Sie hat die selben Übergabeparameter wie in der Fortran-DLL beschrieben - Ausnahme sind Zeichenketten (Siehe Marshaling).

Marshaling

  • Um Typensicherheit zu gewährleiseten, gibt es in .NET die Attributsklasse MarshalAs. Über diese Klasse können Typen aus unmanaged Code und dem .NET Code ausgetauscht werden - z.B. r8 und double oder wie bei GetModelDescriptionDelegate eine Zeichenkette (LPStr/StringBuilder):
1
[MarshalAs(UnmanagedType.LPStr)] StringBuilder description
  • Um eine Zeichenkette mit der Fortran-DLL auszutauschen, muss zu dem inhalt immer auch die Länge des Strings angegeben werden:
1
uint length

Aufruf der DLL-Methode

1
IntPtr pProc = DllImportDynamic.GetProcAddress(myDll, "OPENMI_mp_GETMODELDESCRIPTION");

Holt sich die Einsprungadresse der DLL_Methode.

1
GetModelDescriptionDelegate cpv = (GetModelDescriptionDelegate)Marshal.GetDelegateForFunctionPointer(pProc, typeof(GetModelDescriptionDelegate));

Die Einsprungadresse und der "Platzhalter" werden miteinander verknüpft. Nun kann man einfach die Delegatmethode mit den entsprechenden Parametern aufrufen:

1
cpv(description, (uint)description.Length);