DLL-Methoden hinzufügen (.NET 2 FORTRAN): Difference between revisions

From BlueM
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
</fortran>
</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:
                 ...
                 ...
         }
         }
</csharp>
</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 </csharp>
<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 </csharp>
<source lang="csharp"> uint length </source>


==== Aufruf der DLL-Methode ====
==== Aufruf der DLL-Methode ====
<csharp>IntPtr pProc = DllImportDynamic.GetProcAddress(myDll, "OPENMI_mp_GETMODELDESCRIPTION");</csharp>
<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));</csharp>
<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);</csharp>
<source lang="csharp">cpv(description, (uint)description.Length);</source>


[[Category:Fortran]]
[[Category:Fortran]]

Latest revision as of 09: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.

  1. Hinzufügen des Delegats in DLLMethoden
  2. Hinzufügen der Schnittstellenmethode
  3. 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 und double oder wie bei GetModelDescriptionDelegate 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);