DLL-Methoden hinzufügen (.NET 2 FORTRAN): Difference between revisions
Jump to navigation
Jump to search
m (fix syntax highlighting) |
|||
Line 3: | Line 3: | ||
== Hinzufügen der neuen Methode in der BlueM.Sim Fortran-DLL == | == Hinzufügen der neuen Methode in der BlueM.Sim Fortran-DLL == | ||
<fortran> | <source lang="fortran"> | ||
logical function GetModelDescription(Description) | logical function GetModelDescription(Description) | ||
!DEC$ ATTRIBUTES DLLEXPORT :: GETMODELDESCRIPTION | !DEC$ ATTRIBUTES DLLEXPORT :: GETMODELDESCRIPTION | ||
Line 9: | Line 9: | ||
... | ... | ||
end function | end function | ||
</ | </source> | ||
* Funktionsname und DLLEXPORT-Name müssen gleich sein ! | * Funktionsname und DLLEXPORT-Name müssen gleich sein ! | ||
* Übergabeparameter müssen definiert sein (und die Typen sollten so einfach wie möglich sein) ! | * Übergabeparameter müssen definiert sein (und die Typen sollten so einfach wie möglich sein) ! | ||
Line 24: | Line 24: | ||
<csharp> | <source lang="csharp"> | ||
public class DLLMethoden | public class DLLMethoden | ||
{ | { | ||
Line 40: | Line 40: | ||
... | ... | ||
} | } | ||
</ | </source> | ||
==== Delegate ==== | ==== Delegate ==== | ||
Line 47: | Line 47: | ||
==== Marshaling ==== | ==== Marshaling ==== | ||
* Um Typensicherheit zu gewährleiseten, gibt es in .NET die Attributsklasse <code>MarshalAs</code>. Über diese Klasse können Typen aus unmanaged Code und dem .NET Code ausgetauscht werden - z.B. <code>r8</code> und <code>double</code> oder wie bei <code>GetModelDescriptionDelegate</code> eine Zeichenkette (<code>LPStr</code>/<code>StringBuilder</code>): | * Um Typensicherheit zu gewährleiseten, gibt es in .NET die Attributsklasse <code>MarshalAs</code>. Über diese Klasse können Typen aus unmanaged Code und dem .NET Code ausgetauscht werden - z.B. <code>r8</code> und <code>double</code> oder wie bei <code>GetModelDescriptionDelegate</code> eine Zeichenkette (<code>LPStr</code>/<code>StringBuilder</code>): | ||
<csharp> [MarshalAs(UnmanagedType.LPStr)] StringBuilder description </ | <source lang="csharp"> [MarshalAs(UnmanagedType.LPStr)] StringBuilder description </source> | ||
* Um eine Zeichenkette mit der Fortran-DLL auszutauschen, muss zu dem inhalt immer auch die Länge des Strings angegeben werden: | * Um eine Zeichenkette mit der Fortran-DLL auszutauschen, muss zu dem inhalt immer auch die Länge des Strings angegeben werden: | ||
<csharp> uint length </ | <source lang="csharp"> uint length </source> | ||
==== Aufruf der DLL-Methode ==== | ==== Aufruf der DLL-Methode ==== | ||
<csharp>IntPtr pProc = DllImportDynamic.GetProcAddress(myDll, "OPENMI_mp_GETMODELDESCRIPTION");</ | <source lang="csharp">IntPtr pProc = DllImportDynamic.GetProcAddress(myDll, "OPENMI_mp_GETMODELDESCRIPTION");</source> | ||
Holt sich die Einsprungadresse der DLL_Methode. | Holt sich die Einsprungadresse der DLL_Methode. | ||
<csharp>GetModelDescriptionDelegate cpv = (GetModelDescriptionDelegate)Marshal.GetDelegateForFunctionPointer(pProc, typeof(GetModelDescriptionDelegate));</ | <source lang="csharp">GetModelDescriptionDelegate cpv = (GetModelDescriptionDelegate)Marshal.GetDelegateForFunctionPointer(pProc, typeof(GetModelDescriptionDelegate));</source> | ||
Die Einsprungadresse und der "Platzhalter" werden miteinander verknüpft. Nun kann man einfach die Delegatmethode mit den entsprechenden Parametern aufrufen: | Die Einsprungadresse und der "Platzhalter" werden miteinander verknüpft. Nun kann man einfach die Delegatmethode mit den entsprechenden Parametern aufrufen: | ||
<csharp>cpv(description, (uint)description.Length);</ | <source lang="csharp">cpv(description, (uint)description.Length);</source> | ||
[[Category:Fortran]] | [[Category:Fortran]] |
Latest revision as of 08:43, 27 January 2018
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
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.
- Hinzufügen des Delegats in DLLMethoden
- Hinzufügen der Schnittstellenmethode
- Hinzufügen einer Testmethode (siehe UnitTest)
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
unddouble
oder wie beiGetModelDescriptionDelegate
eine Zeichenkette (LPStr
/StringBuilder
):
[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:
uint length
Aufruf der DLL-Methode
IntPtr pProc = DllImportDynamic.GetProcAddress(myDll, "OPENMI_mp_GETMODELDESCRIPTION");
Holt sich die Einsprungadresse der DLL_Methode.
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:
cpv(description, (uint)description.Length);