Browse Source

* pas2jni: - Fixed method pointer handling for ARM platforms.
- Support for the JNI_OnException custom handler.
- Added useful info to the readme.

git-svn-id: trunk@29419 -

yury 10 years ago
parent
commit
de770592da
3 changed files with 75 additions and 17 deletions
  1. 7 0
      utils/pas2jni/ppuparser.pas
  2. 54 0
      utils/pas2jni/readme.txt
  3. 14 17
      utils/pas2jni/writer.pas

+ 7 - 0
utils/pas2jni/ppuparser.pas

@@ -42,6 +42,7 @@ type
   public
     SearchPath: TStringList;
     Units: TDef;
+    OnExceptionProc: TProcDef;
 
     constructor Create(const ASearchPath: string);
     destructor Destroy; override;
@@ -56,6 +57,9 @@ implementation
 
 uses process, pipes, fpjson, jsonparser;
 
+const
+  OnExceptionProcName = 'JNI_OnException';
+
 type
   TCharSet = set of char;
 
@@ -495,6 +499,9 @@ var
                   Name:='Int';
 
               _ReadDefs(d, it, 'Params');
+              // Check for user exception handler proc
+              if AMainUnit and (Parent = CurUnit) and (OnExceptionProc = nil) and (AnsiCompareText(Name, OnExceptionProcName) = 0) then
+                OnExceptionProc:=TProcDef(d);
             end;
           dtVar, dtField, dtParam:
             with TVarDef(d) do begin

+ 54 - 0
utils/pas2jni/readme.txt

@@ -57,6 +57,60 @@ After successfull run of pas2jni you will get the following output files:
 
 Note: You need to use ppudump of the same version as the FPC compiler. Use the -D switch to specify correct ppudump if it is not in PATH.
 
+CUSTOM HANDLERS
+
+It is possible to define the following custom handlers in your Pascal code.
+
+procedure JNI_OnException;
+  - is called when an unhandled Pascal exception occurs. For example, you can log a stack back trace in this handler.
+
+Custom handlers must be public and defined in one of the main units specified when calling pas2jni.
+
+CODING TIPS
+
+* Setting handlers (method pointers) in a Java code.
+
+For example there is the following event handler in your Pascal code:
+
+TMyClass = class
+...
+  property OnChange: TNotifyEvent;
+...
+end;
+
+In a Java code you get the following TMyClass instance:
+
+TMyClass myclass = TMyClass.Create();
+
+It is possible set a Java handler in 2 ways:
+
+1) Place the handler inline.
+
+...
+  myclass.setOnChange(
+      new TNotifyEvent() {
+        protected void Execute(TObject Sender) {
+          // The handler code
+        }
+      }
+    );
+...
+
+2) Define the handler as a method in a class.
+
+public class MyJavaClass {
+  private void DoOnChange(TObject Sender) {
+    // The handler code
+  }
+
+  public void main() {
+    ...
+    // Set the handler to the method with the "DoOnChange" name in the current class (this).
+    myclass.setOnChange( new TNotifyEvent(this, "DoOnChange") );
+    ...
+  }
+}
+
 COMMAND LINE OPTIONS
 
 Usage: pas2jni [options] <unit> [<unit2> <unit3> ...]

+ 14 - 17
utils/pas2jni/writer.pas

@@ -1074,7 +1074,7 @@ procedure TWriter.WriteProcType(d: TProcDef; PreInfo: boolean);
 var
   vd: TVarDef;
   i: integer;
-  s, ss: string;
+  s, ss, hclass: string;
   err: boolean;
 begin
   if not d.IsUsed or not (poMethodPtr in d.ProcOpt) then
@@ -1084,21 +1084,14 @@ begin
     WriteClassInfoVar(d);
 
     // Handler proc
+    hclass:=GetClassPrefix(d) + 'Class';
     Fps.WriteLn;
-    vd:=TVarDef.Create(nil, dtParam);
-    try
-      vd.Name:='_data';
-      vd.VarType:=TTypeDef.Create(nil, dtType);
-      with TTypeDef(vd.VarType) do begin
-        Name:='pointer';
-        BasicType:=btPointer;
-      end;
-      d.Insert(0, vd);
-      Fps.WriteLn(GetProcDeclaration(d, Format('%sHandler', [GetClassPrefix(d)]), True) + ';');
-    finally
-      vd.VarType.Free;
-      vd.Free;
-    end;
+    Fps.WriteLn(Format('type %s = class', [hclass]));
+    Fps.WriteLn(Format('private %s;', [ GetProcDeclaration(d, 'Handler', True)]), 1);
+    Fps.WriteLn('end;');
+    Fps.WriteLn;
+    Fps.WriteLn(GetProcDeclaration(d, Format('%s.Handler', [hclass]), True) + ';');
+
     Fps.WriteLn('var');
     Fps.IncI;
     Fps.WriteLn('_env: PJNIEnv;');
@@ -1118,7 +1111,7 @@ begin
     Fps.WriteLn('CurJavaVM^^.GetEnv(CurJavaVM, @_env, JNI_VERSION_1_6);');
     Fps.WriteLn('_MethodPointersCS.Enter;');
     Fps.WriteLn('try');
-    Fps.WriteLn('_mpi:=_TMethodPtrInfo(_MethodPointers[-integer(ptruint(_data)) - 1]);', 1);
+    Fps.WriteLn('_mpi:=_TMethodPtrInfo(_MethodPointers[-integer(ptruint(Self)) - 1]);', 1);
     Fps.WriteLn('finally');
     Fps.WriteLn('_MethodPointersCS.Leave;', 1);
     Fps.WriteLn('end;');
@@ -1190,7 +1183,7 @@ begin
     Fps.WriteLn('else');
     Fps.WriteLn('with TMethod(Result) do begin', 1);
     Fps.WriteLn('Data:=pointer(ptruint(-integer(mpi.Index)));', 2);
-    Fps.WriteLn(Format('Code:=@%sHandler;', [GetClassPrefix(d)]), 2);
+    Fps.WriteLn(Format('Code:=@%s.Handler;', [hclass]), 2);
     Fps.WriteLn('end;', 1);
     Fps.DecI;
     Fps.WriteLn('end;');
@@ -2128,6 +2121,10 @@ begin
     Fps.WriteLn;
     Fps.WriteLn('procedure _HandleJNIException(env: PJNIEnv);');
     Fps.WriteLn('begin');
+    if p.OnExceptionProc <> nil then begin
+      Fps.WriteLn(Format('%s.%s;', [p.OnExceptionProc.Parent.Name, p.OnExceptionProc.Name]), 1);
+      p.OnExceptionProc.SetNotUsed;
+    end;
     Fps.WriteLn('env^^.ThrowNew(env, env^^.FindClass(env, ''java/lang/Exception''), PAnsiChar(Utf8Encode(Exception(ExceptObject).Message)));', 1);
     Fps.WriteLn('end;');