Wie man .NET Dll's in Blitz einbinden und benutzen kann

Übersicht BlitzBasic DLLs und Userlibs

Neue Antwort erstellen

Jolinah

Betreff: Wie man .NET Dll's in Blitz einbinden und benutzen kann

BeitragDi, Aug 03, 2004 2:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich habe mich schon mehrmals gefragt ob es denn nicht möglich ist auch mit .NET erstellte Dll's in Blitz zu benutzen.

Als ich mit Google gesucht hab wurd ich dann zu meinem Erstaunen auch recht schnell fündig.

Man muss natürlich das .NET Framework SDK installiert haben, wie man die Dll's dann macht solltet ihr auch selber wissen.
Es gibt 2 Kommandozeilenprogramme in der SDK die man hierfür benötigt.

ildasm.exe und ilasm.exe

Mit der ersten exe kann man die DLL in IL Code disassemblieren lassen.
Mit der zweiten wieder zurück assemblieren.
Dieser Code ist sozusagen die Zwischensprache von .NET.
Egal ob man C#,VB oder C++ .Net programmiert, es werden alle Programme vor dem kompilieren immer in diese Zwischensprache kompiliert. Von dieser aus dann zu dem eigentlichen Programm.

Das kann man nun Nutzen um die .Net Dll's manuell abzuändern. Der Grund warum die normalen .Net Dll's nicht in Blitz funktionieren ist das diese sogenannten Managed Code verwenden. Damit es funktioniert muss man dafür sorgen das die Funktionen als "unmanaged" Code exportiert und aufgerufen werden.

1. So kann man die DLL disassemblieren in eine il Datei.
Der /OUT: Parameter gibt die il Datei an die generiert wird, danach folgt die DLL selbst.

Code: [AUSKLAPPEN]

ildasm.exe /OUT:DLL.il DLL.dll


Nun kann man die il Datei mit nem Text Editor bearbeiten.

Such nach der Zeile:

Code: [AUSKLAPPEN]

.corflags 0x00000001


Dieses Flag muss auf 0x00000002 geändert werden. Wenn man das nicht macht beachtet Windows die Änderungen die wir gleich machen gar nicht erst.

Unter die .corflags Zeile kommt dann folgendes:

Code: [AUSKLAPPEN]

.vtfixup [1] int32 fromunmanaged at VT_01
.data VT_01 = int32(0)


vtfixup Ist so eine Art Tabelle wo man die Adresse der Methode angibt die man exportieren will. Das [1] gibt an wie viele Felder die Tabelle hat. Zur Zeit nur 1 da wir nur 1 Funktion exportieren wollen. Der zweite Parameter legt fest ob es 32bit oder 64bit ist. Und fromunmanaged bedeutet eben das die Funktion als unmanaged aufgerufen werden soll. Das VT_01 ist eine Variable die die Adresse wo die Tabelle beginnt speichert.

Die .data Zeile erstellt diese Variable eigentlich erst, sie ist vom Typ int32 und hat den Anfangswert 0. In diese Variable wird dann automatisch vom Assembler die richtige Funktionsadresse eingetragen. Aber damit das geht muss man in der Funktion selbst noch 2 Einträge machen:


Original Code ohne Änderungen:
In meinem Beispiel die Funktion void MyBox(string name) mit C# geschrieben. Zuerst kommt noch ein Namespace und eine Klasse.

Code: [AUSKLAPPEN]

.namespace DLL
{
  .class public auto ansi beforefieldinit Class1
         extends [mscorlib]System.Object
  {
    .method public hidebysig static void
            MyBox(string text) cil managed
    {
      // Code size       8 (0x8)
      .maxstack  1
      IL_0000:  ldarg.0
      IL_0001:  call       valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string)
      IL_0006:  pop
      IL_0007:  ret
    } // end of method Class1::MyBox

    .method public hidebysig specialname rtspecialname
            instance void  .ctor() cil managed
    {
      // Code size       7 (0x7)
      .maxstack  1
      IL_0000:  ldarg.0
      IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
      IL_0006:  ret
    } // end of method Class1::.ctor

  } // end of class Class1



Jetzt zu den 2 Einträgen die noch fehlen:

Code: [AUSKLAPPEN]

...
...

    .method public hidebysig static void
            MyBox(string text) cil managed
    {
      .vtentry 1 : 1 //*** 1.Zeile ***
      .export [1] as um_MyBox //*** 2.Zeile ***

      // Code size       8 (0x8)
      .maxstack  1
      IL_0000:  ldarg.0
      IL_0001:  call       valuetype [System.Windows.Forms]System.Windows.Forms.DialogResult [System.Windows.Forms]System.Windows.Forms.MessageBox::Show(string)
      IL_0006:  pop
      IL_0007:  ret
    } // end of method Class1::MyBox

...
...


.vtentry 1 : 1

Dieser Befehl sorgt dafür das die Funktions Adresse in VT_01 geschrieben wird. Der erste Parameter (getrennt durch das ":") bedeutet in welcher .vtfixup Zeile es eingetragen wird. Der zweite in welcher Tabellen Spalte. Wir haben nur 1 .vtfixup Zeile also ist der erste Parameter 1.
Diese vtfixup Tabelle hat auch nur [1] feld, also wird es vermutlich auch 1 sein.

.export [1] as um_MyBox

Diese Zeile sorgt dafür das es Schlussendlich "unmanaged" exportiert wird. [1] ist die Feldnummer der Tabelle. Der name nach as ist der Export name der Funktion. Der kann genau gleich sein wie die Managed Funktion aber ich bevorzuge das Präfix um_ für unmanaged.


Hat man das nun alles geändert muss man nur noch aus der .il Datei wieder ne Dll machen. Dazu verwendet man nun ilasm.exe

Code: [AUSKLAPPEN]

ilasm.exe /OUT:DLL.dll DLL.il /DLL


OUT bestimmt wieder die Ausgabe Datei, hier diesmal die DLL. Der nächste Parameter ist die Source IL Datei. Und die Option /DLL darf man nicht vergessen damit auch wirklich eine DLL gemacht wird.


Nun ganz normal ins userlib Verzeichnis von BB kopieren und ne entsprechende .decls Datei schreiben:

Code: [AUSKLAPPEN]

.lib "DLL.dll"

MyBox(text$) : "um_MyBox"


Hier muss darauf geachtet werden den Namen zu benutzen den man bei der .export Zeile angegeben hat.



Wie geht man vor wenn man mehrere Funktionen exportieren will.

Entweder macht man für jede Funktion eine neue .vtfixup und .data Zeile, wobei jedesmal eine andere Variable verwendet werden muss (VT_01,VT_02,VT_03 usw.), oder man erhöht die Anzahl Tabellenfelder in der .vtfixup Zeile.

In jeder Funktion muss ausserdem die .vtentry und .export Zeile drin sein.


Also 1.Möglichkeit:

Code: [AUSKLAPPEN]

.vtfixup [1] int32 fromunmanaged at VT_01
.data VT_01 = int32(0)

.vtfixup [1] int32 fromunmanaged at VT_02
.data VT_02 = int32(0)

// In der ersten Funktion:

.vtentry 1 : 1
.export [1] as um_first

// In der zweiten Funktion:

.vtentry 2 : 1
.export [1] as um_second

// Warum 2 : 1, weil dieser eintrag dann in der zweiten .vtfixup Zeile ist in Feld 1



2. Möglichkeit:

Code: [AUSKLAPPEN]

.vtfixup [2] int32 fromunmanaged at VT_01
.data VT_01

// 1. Funktion

.vtentry 1 : 1
.export [1] as um_first

// 2. Funktion

.vtentry 1 : 2
.export [2] as um_second

// Diesmal ist alles in der ersten .vtfixup. Jedoch die 2. Funktion im 2. Feld.
// Bei Export muss dann wahrscheinlich auch das Feld 2 angegeben werden.
// Ich habe es jedoch noch nicht getestet.



Schlusswort:

In C# funktionierte bei mir alles super. In VB.Net hatte ich jedoch Probleme mit der String übergabe, obwohl ich in C# den Parameter auch als String und nicht etwa als Char[] behandelt habe. Naja einfach ausprobieren Smile

Artemis

BeitragDi, Jun 14, 2005 14:45
Antworten mit Zitat
Benutzer-Profile anzeigen
Und wie schreibt man DLLs in C#, sodass man sie so nutzen kann??
 

Klaas

BeitragDi, Jun 14, 2005 16:23
Antworten mit Zitat
Benutzer-Profile anzeigen
Wer des Englischen mächtig ist sollte dazu auch mal nen Blick auf dies hier werfen:

http://www.blitzbasic.com/code...p?code=716

Artemis

BeitragDi, Jun 14, 2005 18:23
Antworten mit Zitat
Benutzer-Profile anzeigen
ja danke!!
cool!! Laughing

Neue Antwort erstellen


Übersicht BlitzBasic DLLs und Userlibs

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group