DLL-Methoden hinzufügen: Difference between revisions

From BlueM
Jump to navigation Jump to search
m (Formatierung)
Line 1: Line 1:
== Anleitung für die Hinzufügen neuer Methoden in eine Modell-DLL (am Beispiel von BlueM) ==
<div style="float:left; margin-right:10px">__TOC__</div>
<big> Anleitung für das Hinzufügen neuer Methoden in eine Modell-DLL (am Beispiel von [[BlueM]]) </big><br clear="all"/>


=== Hinzufügen der neuen Methode in der BlueM Fortran-DLL ===
== Hinzufügen der neuen Methode in der BlueM Fortran-DLL ==


<fortran>
<fortran>
Line 14: Line 15:




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




=== Erweiterung des DLL-Wrappers (C#) ===
== Erweiterung des [[BlueM.DLLAdapter|DLL-Wrappers]] (C#) ==
Die Methoden der DLL werden aus der Klasse <code>DLLMethoden</code> aufgerufen.
Die Methoden der DLL werden aus der Klasse <code>DLLMethoden</code> aufgerufen.


Line 43: Line 44:
</csharp>
</csharp>


===== Delegate =====
==== 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]]).
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]]).


===== 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. <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 "MarshalAs". Ü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>
<csharp> [MarshalAs(UnmanagedType.LPStr)] StringBuilder description </csharp>
Line 52: Line 53:
<csharp> uint length </csharp>
<csharp> uint length </csharp>


===== Aufruf der DLL-Methode =====
==== Aufruf der DLL-Methode ====
<csharp>IntPtr pProc = DllImportDynamic.GetProcAddress(myDll, "OPENMI_mp_GETMODELDESCRIPTION");</csharp>
<csharp>IntPtr pProc = DllImportDynamic.GetProcAddress(myDll, "OPENMI_mp_GETMODELDESCRIPTION");</csharp>
Holt sich die Einsprungadresse der DLL_Methode.
Holt sich die Einsprungadresse der DLL_Methode.

Revision as of 02:28, 2 November 2007

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

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

<fortran>

       logical function GetModelDescription(Description)
       !DEC$ ATTRIBUTES DLLEXPORT :: GETMODELDESCRIPTION
       character(*) Description
           ...
       end function

</fortran>

  • 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 UnitTest


<csharp>

       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);
               }        
               ...
       }

</csharp>

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):

<csharp> [MarshalAs(UnmanagedType.LPStr)] StringBuilder description </csharp>

  • 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>

Aufruf der DLL-Methode

<csharp>IntPtr pProc = DllImportDynamic.GetProcAddress(myDll, "OPENMI_mp_GETMODELDESCRIPTION");</csharp> Holt sich die Einsprungadresse der DLL_Methode. <csharp>GetModelDescriptionDelegate cpv = (GetModelDescriptionDelegate)Marshal.GetDelegateForFunctionPointer(pProc, typeof(GetModelDescriptionDelegate));</csharp> 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>