DGL
https://delphigl.com/forum/

OpenGL Import für Delphi .Net
https://delphigl.com/forum/viewtopic.php?f=21&t=2539
Seite 1 von 2

Autor:  LarsMiddendorf [ So Feb 22, 2004 22:23 ]
Betreff des Beitrags:  OpenGL Import für Delphi .Net

Seit einiger Zeit gibt es ja Delphi auch für das .Net Framework. Es gibt bereits OpenGL Bindings für Delphi .Net, aber die sind nicht unbedingt einfach erweiterbar und kapseln nur eine C++ DLL oder rufen die Extension Funktionen auf seltsame Art und Weise auf (CSGL). Der Nachteil ist, daß die entsprechenden Assemblies und die DLL immer mit kopiert werden müssen und man letztlich nicht genau an den Inhalt kommt. Eine Delphi Unit kann auch bei Delphi .Net statisch gelinkt werden.

Auch in .Net Programmen können DLL Funktionen ohne Probleme importiert werden und auch CallBacks sind erlaubt. Daher kann man die OpenGL DLL's ohne Probleme mit LoadLibrary laden und auch GetProcAddress und wglGetProcAddress verwenden. Das Problem sind die Extensions die über einen Zeiger aufgerufen werden. Auch in Delphi.Net gibt es noch die Referenzen auf Funktionen und Prozeduren. Die Frage ist, ob man die als Rückgabetype bei einer importierten Funktion verwenden darf. In C# geht das nicht und es soll der Hilfe nach im .Net Framework erst ab der nächsten Version möglich sein.
Aber Delphi Assemblies können im Gegensatz zu C# Assemblies auch ganz normal aus Win32 Anwendungen als DLL angesprochen werden ohne das ein COM Wrapper benutzt werden muß. Es könnte also möglich sein, daß Delphi auch bei den Funktionszeigern mehr Möglichkeiten bietet. Es würde ja schon reichen wenn der Typecast von Integer zu so einem Zeiger möglich wäre. Ich besitze Delphi .Net leider noch nicht und konnte es nur kurz ausprobieren. Wenn jemand damit zu tun hat, könnte er ja mal testen ob das geht, dann wäre an dem Header ja nicht viel zu ändern.

Falls das nicht möglich ist, dann wäre immer noch die Möglichkeit eine DLL zu benutzen, die den Funktionsaufruf nur weiterleitet. Das ist immer noch besser als alle Funktionen in die DLL zu packen, weil die ja aus Delphi .Net nicht geändert werden kann. Die DLL müßte nur eine Funktion besitzen:
Code:
  1. procedure Invoke;stdcall;
  2. asm
  3.  pop ecx;
  4.  pop edx;
  5.  push ecx;
  6.  jmp edx;
  7. end


Man würde wglGetProcAddress einen Integer Wert zurückliefern lassen und den als ersten Parameter der Funktion übergeben. Alle dynamisch geladen Funktionen sind dann Importe dieser Funktion. Immer mit einer anderen Parameterliste und beim Aufruf nimmt man dann eben die tatsächliche Addresse als ersten Parameter. Das funktioniert zumindest in C# ganz gut und sieht so aus:

Code:
  1. [DllImport("invoke.dll", EntryPoint="Invoke")]
  2. private static extern int wglGetProcAddress_f(int funcptr,String funcname);
  3.  
  4. int LibHandle=LoadLibrary(OpenGLDLL);
  5. int wglGetProcAddress_p=GetProcAddress(LibHandle,"wglGetProcAddress");
  6. wglGetProcAddress_f(wglGetProcAddress_p,funcname);


Eine solche Funktion wird bereits bei Java benutzt. So daß man ohne externe DLL darauf zurückgreifen könnte.Das Problem ist, daß ab WinXP Java nicht mehr vorrausgesetzt werden kann.

Die zweite Möglichkeit wäre mit Hilfe der ILCodeGenerator Klasse dynamisch die Funktionen zur Laufzeit zu Generieren. Dann könnte man eventuell nur mit einer Delphi Unit auskommen. Ich bin mir nicht ganz sicher, ob man das möglich ist, weil die Extension Funktionen ja keine normalen DLL Importe, sondern im Prinzip beliebige Zeiger sind.

Falls jemand Delphi .Net bereits einsetzt, würden mich mal die Erfahrungen interessieren. .Net ist auf jeden Fall durchdacht und gelungen und daher ist es auch wichtig, daß Delphi jetzt diesen Schritt gemacht hat. Das Managed DirectX ist vom Aufbau dank der Properties sauber und auch übersichtlich und vor allem im Gegensatz zu OpenGL einfach verfügbar. Das Problem ist, daß OpenGL dort Bedeutung verlieren könnte. Daher sollte man vielleicht sich speziell um Delphi .Net kümmern, so daß OpenGL so einfach wie bisher auch unter .Net benutzt werden kann.

Autor:  Phobeus [ So Feb 22, 2004 23:19 ]
Betreff des Beitrags: 

Ich habe das hier eben gerade einmal gelesen und gestehe mir wirklich ein, dass ich mich unbedingt in den nächsten Wochen noch einmal Intensiv mit .NET befassen muss, ich konnte nämlich noch nicht den ganzen Ausmaß der Problematik erfassen... stimme Dir nur zu :roll: :wink:

Falls niemand aus dem Team bisher über Delphi.NET verfügen sollte, könnten wir durchaus auch mal riskieren einen öffentlichen Aufruf dazu zu machen, damit Du eventuell einen Test finden kannst. Vielleicht ist ja auch McClaw bereit Dir zu helfen, der verfügt ja bereits über Delphi.NET.
just my six cent.

Autor:  LarsMiddendorf [ Fr Feb 11, 2005 14:22 ]
Betreff des Beitrags: 

Es wird wohl doch noch bis Ende März mit der PE Version zu dauern. Dann werd ich mal ausprobieren, wie man da sinnvoll einen Header machen kann. Einige Methoden habe ich ja schon vor einem Jahr mit C# getestet. Aber an dem .Net compiler sind glaube ich nur wenige Änderungen vorgenommen worden. Ist auf jeden Fall notwenig, denn das Managed DX ist mittlerweile nicht schlecht geworden und so langsam scheint das Interesse an .Net zu steigen. Wundere mich nur, dass die ganzen DX'ler das nicht benutzen, denn unter .Net hat OpenGL im Moment definitiv schlechtere Chancen. Wenn man mal im Netz danach sucht, findet man ja auch nur sehr wenige Projekte.

Autor:  LarsMiddendorf [ Mo Feb 14, 2005 19:48 ]
Betreff des Beitrags: 

Habe in C# mal ein wenig herumprobiert und mir ist es gelungen, aus einem Zeiger auf eine externe Methode ein Delegate zu erzeugen. Unter .Net 2.0 gibt's dafür die Methode Marshal.DelegateFromFunctionPtr, aber unter .Net 1.1 ist das nicht so einfach möglich. Delegates sind die normalen procedure/function Typen unter .Net .
Zuerst wird ein neuer Type erstellt und dynamisch mit dem ILGenerator eine Wrapper Methode generiert, die zu der Addresse springt. Die Addresse wird dabei direkt eingetragen. In dem Beispiel kommt sie von GetProcAddress, aber bei OpenGL würde man dann wglGetProcAddress verwenden. Zu dieser Methode wird dann ein Delegate Object erzeugt, das ganz normal wie eine normale procedure verwendet werden kann. Da es unter C# funktioniert, wird es wohl auch unter Delphi .Net funktionieren und so bestehen gute Chancen, dass der Header auch auf .Net portiert werden kann. Man müßte das nur mal in Delphi .Net eingeben. Ich habe es nicht.

Code:
  1. using System;
  2. using System.Reflection;
  3. using System.Reflection.Emit;
  4. using System.Threading;
  5. using System.IO;
  6. using System.Runtime.InteropServices;
  7.  
  8. namespace Project3
  9. {
  10.  
  11.     delegate int MessageBoxA(int hwnd,string title,string text,int buttons);
  12.  
  13.     class Loader
  14.     {
  15.         private AssemblyBuilder asmbuilder;
  16.         private ModuleBuilder modbuilder;
  17.         private int libhandle;
  18.  
  19.         [DllImport("Kernel32.dll")]
  20.         private static extern int LoadLibrary(string filename);
  21.  
  22.         [DllImport("Kernel32.dll")]
  23.         private static extern int GetProcAddress(int lib,string name);
  24.  
  25.         public System.Delegate CreateDelegate(string name,Type delegatetype)
  26.         {
  27.             MethodInfo d=delegatetype.GetMethod("Invoke");
  28.             Type[] paramlist=new Type[d.GetParameters().Length];
  29.             for(int i=0;i<paramlist.Length;i++)
  30.             {
  31.                 paramlist[i]=d.GetParameters()[i].ParameterType;
  32.             }
  33.             TypeBuilder t=modbuilder.DefineType(name);
  34.             MethodBuilder m=t.DefineMethod("Invoke",MethodAttributes.Static|MethodAttributes.Public,d.ReturnType,paramlist);
  35.             ILGenerator ilgen=m.GetILGenerator();
  36.             for(int i=0;i<paramlist.Length;i++)
  37.             {
  38.                 ilgen.Emit(OpCodes.Ldarg,i);
  39.             }
  40.             int addr=GetProcAddress(libhandle,name);
  41.             ilgen.Emit(OpCodes.Ldc_I4,addr);
  42.             ilgen.EmitCalli(OpCodes.Calli,CallingConvention.StdCall,d.ReturnType,paramlist);
  43.             ilgen.Emit(OpCodes.Ret);
  44.             Type t2 = t.CreateType();
  45.             MethodInfo m2=t2.GetMethod("Invoke");
  46.             return Delegate.CreateDelegate(delegatetype,m2);
  47.         }
  48.  
  49.         public Loader(string filename)
  50.         {
  51.             AssemblyName asmname=new AssemblyName();
  52.             asmname.Name=Path.GetFileNameWithoutExtension("Temp");
  53.             asmbuilder=Thread.GetDomain().DefineDynamicAssembly(asmname,AssemblyBuilderAccess.Run);
  54.             modbuilder=asmbuilder.DefineDynamicModule("Temp");
  55.             libhandle=LoadLibrary(filename);
  56.         }
  57.  
  58.     }
  59.  
  60.     class Class
  61.     {
  62.         [STAThread]
  63.         static void Main(string[] args)
  64.         {
  65.             Loader l=new Loader("User32.dll");
  66.             MessageBoxA m=(MessageBoxA)l.CreateDelegate("MessageBoxA",typeof(MessageBoxA));
  67.             Console.WriteLine(m(0,"Titel","Text",3));
  68.             Console.ReadLine();
  69.         }
  70.     }
  71. }

Autor:  LarsMiddendorf [ Fr Feb 18, 2005 20:51 ]
Betreff des Beitrags: 

Ich habe das mal auf Delphi .Net portiert. Auch hier nur als Bsp. mit MessageBoxA.
Jedenfalls kann man so auch einen nativen Zeiger in eine Delegate konvertieren und das alles typesicher und ohne unsicheren Code.

Zitat:
TMessageBox=function(hwnd:Integer;title,text:string;flags:Integer):Integer;

procedure TWinForm.Button1_Click(sender: System.Object; e: System.EventArgs);
var
libhandle,ptr:Integer;
msgbox:TMessageBox;
begin
libhandle:=LoadLibrary('User32');
ptr:=GetProcAddress(libhandle,'MessageBoxA');
msgbox:=TMessageBox(CreateDelegate(ptr,TypeOf(TMessageBox)));
msgbox(0,'Title','Text',2);
end;


Das komplette Bsp. Projekt als Anhang.

Dateianhänge:
OpenGL.zip [17.38 KiB]
52-mal heruntergeladen

Autor:  LarsMiddendorf [ Di Feb 22, 2005 17:47 ]
Betreff des Beitrags: 

Ich habe jetzt den dglopengl Header angepaßt, so dass es zumindest in Grundzügen bereits unter Delphi 2005, also .Net 1.1 funktioniert. Dazu mußten alle anonymen Funktionsdeklarationen Typen bekommen, damit später ein Delegate erstellt werden kann. Es wurde viel geändert, aber es scheint auch mit dem normalen Win32 noch zu funktionieren. Das Laden der Extensions ist nicht so schnell, immerhin wird für jede Funktion ein Wrapper dynamisch kompiliert und intern erzeugt .Net auch noch einen zusätzlichen Prozess. Dafür hat man das jetzt als Delphi Unit fast wie gewohnt und braucht keine Assemblies und zusätzlichen DLL's.

Dateianhänge:
dglOpenGL.zip [94.51 KiB]
56-mal heruntergeladen
delphi2005gl.PNG
delphi2005gl.PNG [ 109.79 KiB | 2109-mal betrachtet ]

Autor:  LarsMiddendorf [ Mi Feb 23, 2005 15:40 ]
Betreff des Beitrags: 

Habe die Version nochmal geupdatet und zwar wird der Type der Delegate direkt mit typeof und nicht mehr mittels Reflection ermittelt, was leicht schneller sein sollte. Leider ist in fast jeder Zeile jetzt ein {$IFDEF CLR}, aber dafür hat man jetzt einen Header für .Net,Win32 und Linux.
Interessanterweise scheinen die Pointer Deklarationen nichts auszumachen. Erst wenn sie verwendet werden, wird dann unsafe verlangt, was aber eigentlich bei OpenGL nie nötig sein sollte.

Dateianhänge:
dglOpenGL.zip [100.26 KiB]
51-mal heruntergeladen

Autor:  Sascha Willems [ Mi Feb 23, 2005 20:03 ]
Betreff des Beitrags: 

Daumen hoch! Hab das leider noch nicht probiert (warte noch auf die PE), aber ein einzelner Header für Win32/.NET/Linux/Andere Pascal-Compiler dürfte ne geniale Sache sein. In wie weit ist der denn praxistauglich? Evtl. kann man ja nen öffentlichen "Betatest" starten und den Header dann endgültig als offiziell anbieten.

Autor:  LarsMiddendorf [ Mi Feb 23, 2005 20:44 ]
Betreff des Beitrags: 

Ja da gibt's noch einige Punkte, bis dass wirklich 100% einsetzbar ist.
Man wird vermutlich bei einigen Funktionen noch die Pointer durch Arrays ersetzen müssen, was ja auch Sinn macht, denn bei den Funktionen mit Pointern z.B. glVertex3fv sind ja in der C Welt auch Arrays gemeint gewesen. Also so wie beim C# Header auch. Momentan gibt's bei Funktionen mit Pointern beim Generieren von dem Delegate Type eine Exception mit dem Ergebnis, dass die Funktionen dann auf nil gesetzt werden.

Das Laden aller Extensions dauert ca 3-4 Sekunden, was definitiv zu lang ist. Es muß an der dynamischen Generierung liegen. Da muß man sich nochmal was einfallen lassen. Es gibt aber soweit ich das Netz abgesucht habe, keine andere Möglichkeit und es gibt ja sowieso keinen OpenGL Header, der nicht auf externe DLL's zurückgreift und unter .Net 1.1 schon gar nicht. Das ist halt schön, wenn man das direkt miteinkompilieren kann.

Wenn Delphi auch .Net unterstützt wird kaum was geändert werden müssen, da es ja bereits jetzt auf die Delegates ausgelegt ist, nur mit dem Unterschied, dass man dann diese ganze Sache mit dem Generieren sein lassen kann und die Zeiger sauber und einfach direkt konvertieren kann.

Ich werde das Template nach WinForms portieren.

Wie man sieht, es geht obwohl es nicht so schön elegant ist wie unter Win32. Ich werd sehen, was ich an diesen Punkten da noch verbessern kann, bis die PE rauskommt. Das Problem ist nämlich, dass es mit DX unter .Net ganz ohne Schwierigkeiten geht und wenn man da nicht zeitig was anbietet, werden die OpenGL Leute entweder bei Win32 bleiben oder zu DX wechseln, was beides nicht so toll ist.
Obwohl die reduzierte Delphi2005 Version doch schneller ist, ist sie einige Male hängen geblieben und hat teilweise Quelltext mitgerissen, so dass meine Hoffnungen für Delphi2005 schon wieder stark getrübt sind.

Autor:  Delphic [ Mi Feb 23, 2005 22:14 ]
Betreff des Beitrags: 

LarsMiddendorf hat geschrieben:
Obwohl die reduzierte Delphi2005 Version doch schneller ist, ist sie einige Male hängen geblieben und hat teilweise Quelltext mitgerissen, so dass meine Hoffnungen für Delphi2005 schon wieder stark getrübt sind.

Irgendwo in den Editoroptionen kann man diese neien, aufpoppenden fensterchen abklemmen, die zu den Programmierhilfen gehören. Mich ahben sie eh mehr gestört, als dass sie mir etwas gebracht hatten, darum war ich eigentlich froh drum, als ich den hebel gefunden hatte. Nachdem ich das gemacht hatte, waren auch keine Abstürze mehr zu beklagen.

Autor:  LarsMiddendorf [ Mi Feb 23, 2005 22:22 ]
Betreff des Beitrags: 

Aha gut, werd ich mal ausprobieren. Vielleicht ist es ja dann auch schneller.

Autor:  LarsMiddendorf [ Fr Feb 25, 2005 10:35 ]
Betreff des Beitrags: 

Die Extensions dauern ja wie gesagt lange zu laden. Wäre es akzeptabel, wenn man da eine globale Variable einbaut, mit der man angeben kann, dass nur die ARB Extensions geladen werden? Die allermeisten verwenden die Extensions doch sowieso nur sehr spärlich und wenn dann hauptsächlich ARB.

Autor:  Lossy eX [ Fr Feb 25, 2005 11:45 ]
Betreff des Beitrags: 

Also das finde ich nicht so sonderlich gut. Dann wäre ich eher dafür, dass man das macht wie Tom Nuydens. Also, dann explizit angibt welche Extensions geladen werden sollen. Denn auch die ARB's werden mehr und dann hätte man genau das selbe Problem.

Autor:  LarsMiddendorf [ Fr Feb 25, 2005 14:26 ]
Betreff des Beitrags: 

Das ist die andere Möglichkeit, obwohl man dann nicht mehr das automatische Laden bei ActivateRenderingContext hätte.

Autor:  Lossy eX [ Fr Feb 25, 2005 15:38 ]
Betreff des Beitrags: 

Das könnte man ja dann evtl. per optionalem Parameter immernoch anbieten. Also, dass er dann alle Extensions lädt. Der könnte bei .NET standard auf False stehen und bei allem anderen auf True. Allerdings birgt das ganze dann natürlich noch ein größres Problem. Alle bisher geschriebenen Programme müssten angepasst werden. Ich denke mal, wenn wir eine Änderung an der Schnittstelle und Funktionsweise durchführen dann sollte die Endgültig und sehr gut überlegt sein! Auf keinen Fall sollten wir da aus einer Laune herraus das immer und immer wieder anpassen und ändern. Die Benutzer des Header werden im Dreieck springen. Und ich kann die Fragen jetzt schon hören. ;-)

Seite 1 von 2 Alle Zeiten sind UTC + 1 Stunde
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/