Ich habe ja schon viele Versionen von dem "Hello, world"-Programm gesehen und auch schon in so mancher Programmiersprache geschrieben. Aber so, wie ich es jetzt letzte Woche gemacht habe, habe ich es noch nie gesehen.
Zur Vorgeschichte: Folgende Situation, man hat einen Webservice, der auf dem lokalen Rechner läuft und auch lokal angesprochen werden soll. Der übliche Weg ist nun der, dass auch lokal die Kommunikation über den localhost und http läuft. Was natürlich lokal etwas doof ist. Also hatte mein Chef folgende Idee. Man kann mit der Bibliothek xfire [1] die Schnittstelle zum Webservice lokal verfügbar machen ohne über localhost und http gehen zu müssen. So weit so gut. Dann kam seine nächste Idee, schön wäre es doch, wenn man eine universelle Brücke hätte, die man zwischen den Webservice und einer Endanwendung hängen könnte, sprich eine DLL, die die Schnittstelle zwischen dem Webservice und einer Win32-Anwendung bildet. Und ganz zum Schluss kam seine dritte und schlechteste Idee ... ich solle das machen. ;)
Gut, kurz zusammengefasst heißt das: Mit einer Win32-Anwendung (Exe oder DLL) auf die Methode einer Java-Klasse zugreifen. Klingt dramatisch, ist es aber gar nicht. Mittels Java Native Interfaces [2] (JNI), kann man zum einem aus Java raus auf native Funktion in anderen Programmiersprachen zugreifen. Das macht auch Sinn, denn da Java weitgehend platformunabhängig ist, stehen nicht alle Betriebssystemfunktionen zur Verfügung, die man eventuell braucht. Man kann diese dann in einer Programmiersprache, die das kann, zum Beispiel C/C++ oder Delphi, in einer DLL implementieren und von Java aus, kann man dann diese Funktionen aus der DLL aufrufen und nutzen. Und es geht auch umgekehrt, man kann auch mittels JNI auf eine Java Methode in einer Klasse aus einer anderen Programmiersprache (C/C++ oder Delphi) zugreifen.
Um das ganze zu testen habe ich mir also ein kleines Java-Programm geschrieben:
/*
* Project : PVS Soap Bridge Demo Java Programm
* Copyright : © 2006 Datawerk
* File Name : HelloWorld.java
* Author : mp
* Date : 2006-09-06
* Comment : Java Demo-Programm mit Demo-Klassen für externe JNI-Aufrufe
*
*/
public class HelloWorld {
public static void main(String[] argv) throws Exception
{
System.out.print("Hello, world");
}
// einfache Interger Rückgabe
public int intTest()
{
return 42;
}
// Integer Rückgabe mit Integer Parameterübergabe
public int intTest2(int Value)
{
return Value * 2;
}
// einfache String Rückgabe
public String strTest()
{
return "Hello, world";
}
// String Rückgabe mit String Parameterübergabe
public String strTest2(String s)
{
return s + "world";
}
}
Wie man sieht beinhaltet dieses Java-Programm mehrere Methoden, um ein paar Fälle auszuprobieren. Dann habe ich erst eine Anwendung in Delphi geschrieben, die diese Methoden mittels JNI aufruft und dann zum Schluss eine entsprechende DLL in Delphi:
{*
* Project : PVS [SOAP Bridge]
* Copyright : © 2006 Datawerk
* Unit Name : Not available
* Author : mp
* Date : 2006-09-07
* Comment : DLL-Demo - Zugriff auf Java Methoden via Java Native Interface (JNI)
*
*}
library SoapBridge;
{$WARN SYMBOL_PLATFORM OFF}
uses
Windows,
UJvm in 'units\UJvm.pas',
JNI in 'units\JNI.pas';
var
Jvm: TJvm;
{*
* Procedure : Init
* Java Virtual Machine initialisieren
* Author : mp
* Date : 2006-09-07
*
* Laden der JVM scheint beim Laden der DLL noch nicht zu funkltionieren, wenn
* die DLL dynamisch geladen wird. Deswegen die sepaaten Routinen zum Starten
* und Beenden der JVM, die manuell vom Programm aufgerufen werden müssen!
*}
function Init: Boolean; stdcall
begin
if not Assigned(Jvm) then
Jvm := TJvm.create('..\..\JavaDemo');
result := Assigned(Jvm);
end;
procedure DeInit; stdcall
begin
Jvm.Free;
end;
{*
* Procedure : ReturnString
* Author : mp
* Date : 2006-09-07
*
* Gibt einen String zurücvk und nimmt einen String als Parameter
*}
function ReturnString(InStr: PChar; Buffer: PChar; lenBuffer: Integer): Integer; stdcall
var
cls : JClass;
mid : JMethodID;
res : JString;
instance : JObject;
s : String;
begin
cls := jvm.JniEnv.FindClass('HelloWorld');
Assert(Assigned(cls), 'Class HelloWorld not found');
mid := jvm.JniEnv.GetMethodID(cls, '<init>', '()V');
Assert(Assigned(mid), 'Constructor not found');
instance := jvm.JniEnv.NewObject(cls, mid, []);
// Signatur: String Parameter, Rückgabetyp String
mid := jvm.JniEnv.GetMethodID(cls, 'strTest2', '(Ljava/lang/String;)Ljava/lang/String;');
Assert(Assigned(mid), 'Method "strTest2" not found');
res := jvm.JniEnv.CallObjectMethod(instance, mid, [String(InStr)]);
s := jvm.JniEnv.JStringToString(res);
if length(s) < lenBuffer then
begin
result := Length(s);
end
else
begin
lstrcpy(Buffer, PChar(s));
result := Length(s);
end;
end;
exports
Init index 1,
DeInit index 2,
ReturnString index 4;
begin
end.
Und ganz zum Schluss eine Delphi-Anwendung, um die DLL zu testen:
procedure TForm1.btnRetStrClick(Sender: TObject);
type
TReturnStr = function(InStr: PChar; Buffer: PChar; lenBuffer: Integer): Integer; stdcall;
var
ReturnStr : TReturnStr;
Buffer : PChar;
len : Integer;
begin
Buffer := nil;
@ReturnStr := GetProcAddress(hLib, 'ReturnString');
if Assigned(ReturnStr) then
begin
len := ReturnStr('Hello ', nil, 0);
try
GetMem(Buffer, len + 1);
ReturnStr('Hello ', Buffer, len);
StB.SimpleText := string(Buffer);
finally
FreeMem(Buffer, len + 1);
end;
end
else
StB.SimpleText := SysErrorMessage(GetLastError);
end;
Hier nur die Routine, die die Methode strTest2 aus dem Java-Programm aufruft. Und das Verrückte an der ganzen Sache ist ... es funktioniert auch noch.
Ein paar Anmerkungen warum gerne die Ausgabe des Textes "Hello, world" genommen wird aus der Wikipedia:
Einfache Beispiele von Computerprogrammen, die zum Beispiel zur Demonstration verwendet werden, bestehen häufig nur aus ein paar Zeilen Programmcode, die den Text Hallo, Welt! oder auf Englisch Hello, world! ausgeben. Dieses Programm soll als eines der einfachst möglichen zeigen, was für ein vollständiges Programm (in der betreffenden Programmiersprache) benötigt wird, und einen ersten Einblick in die Syntax geben. Ein solches Programm ist auch geeignet, die erfolgreiche Installation eines Compilers für die entsprechende Programmiersprache zu überprüfen.
Die Verwendung des Textes "Hello, world!", der natürlich auch durch einen beliebigen Text ersetzt werden kann, aber dennoch gerne unverändert benutzt wird, ist eine Tradition und geht auf ein internes Programmierhandbuch der Bell Laboratories über die Programmiersprache C zurück, das Brian Kernighan dort 1974 verfasste, nachdem er dort schon ein Jahr zuvor die Worte "hello" und "world" in einer Einführung in die Programmiersprache B verwendet hatte. Bekanntheit erlangte der Text jedoch erst durch die Veröffentlichung in dem Buch The C Programming Language ( deutsch: Programmieren in C) von Brian Kernighan und Dennis Ritchie, auch wenn in dem dortigen Beispiel die Schreibung "hello world" verwendet wurde.
| SoapBridge_HelloWorld.zip | Wednesday, 29-Dec-2010 23:46:00 CET | 584K |
[1] http://xfire.codehaus.org/Local+Transport
[2] http://www.haertfelder.com/jni.html
[3] http://www.michael-puff.de/Artikel/2006/files/SoapBridge_HelloWorld.zip