mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-20 10:45:08 +02:00
Merged revision(s) 33859, 34275, 34309, 34327, 34367, 34369, 34634 from trunk:
* pas2jni: Explicitly release JNI local refs while executing method pointers. ........ * pas2jni: Fixed string constant handling after recent changes in FPC. ........ * pas2jni: Fixed invoking of Java event handlers from non-main threads. ........ * pas2jni: Fixed handling of identical names of classes, proctypes when they are defined in different units. ........ * pas2jni: Removed option to create event handler by passing Java method method name as a string. It is not safe, since the target method is treated as unused by Java and the method may be removed from the resulting application. ........ * pas2jni: Reverted r34367 and mark undesired event handler creation "deprecated". ........ git-svn-id: branches/fixes_3_0@34774 -
This commit is contained in:
parent
93d5be005e
commit
80e88fdc34
@ -33,11 +33,12 @@ The following Pascal features are supported by pas2jni:
|
||||
- pointer type;
|
||||
- string types;
|
||||
- all numeric types;
|
||||
- method pointer.
|
||||
- method pointer;
|
||||
- setters/getters for array elements.
|
||||
|
||||
USUPPORTED features:
|
||||
- array;
|
||||
- procedure pointer.
|
||||
- Full support for arrays;
|
||||
- procedure pointer (Not possible to implement. To workaround this limitation create a procedure handler in your Pascal code and call a method pointer declared in some global Pascal class. Then you can assign this method pointer from a Java code).
|
||||
|
||||
Shared libraries, generated by pas2jni were tested with Java on Windows and Android. It should work on other systems as well.
|
||||
|
||||
@ -84,9 +85,7 @@ 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.
|
||||
Then you add the event handler in a usual Java way:
|
||||
|
||||
...
|
||||
myclass.setOnChange(
|
||||
@ -98,21 +97,6 @@ It is possible set a Java handler in 2 ways:
|
||||
);
|
||||
...
|
||||
|
||||
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> ...]
|
||||
|
@ -54,12 +54,45 @@ type
|
||||
property SIndent: string read FIndStr;
|
||||
end;
|
||||
|
||||
{ TClassInfo }
|
||||
|
||||
TClassInfo = class
|
||||
public
|
||||
Def: TDef;
|
||||
Funcs: TObjectList;
|
||||
IsCommonClass: boolean;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
{ TProcInfo }
|
||||
|
||||
TProcInfo = class
|
||||
public
|
||||
Name: string;
|
||||
JniName: string;
|
||||
JniSignature: string;
|
||||
end;
|
||||
|
||||
{ TClassList }
|
||||
|
||||
TClassList = class(TStringList)
|
||||
private
|
||||
function GetFullName(const AName: string; Def: TDef): string;
|
||||
public
|
||||
constructor Create;
|
||||
function Add(const AName: string; Def: TDef; Info: TClassInfo): integer;
|
||||
function IndexOf(const AName: string; Def: TDef): integer; reintroduce;
|
||||
function GetClassName(Index: integer): string;
|
||||
function GetClassInfo(Index: integer): TClassInfo;
|
||||
end;
|
||||
|
||||
{ TWriter }
|
||||
|
||||
TWriter = class
|
||||
private
|
||||
Fjs, Fps: TTextOutStream;
|
||||
FClasses: TStringList;
|
||||
FClasses: TClassList;
|
||||
FPkgDir: string;
|
||||
FUniqueCnt: integer;
|
||||
FThisUnit: TUnitDef;
|
||||
@ -169,6 +202,50 @@ begin
|
||||
Result:='{$ifdef windows} stdcall {$else} cdecl {$endif};';
|
||||
end;
|
||||
|
||||
{ TClassList }
|
||||
|
||||
function TClassList.IndexOf(const AName: string; Def: TDef): integer;
|
||||
begin
|
||||
Result:=inherited IndexOf(GetFullName(AName, Def));
|
||||
end;
|
||||
|
||||
function TClassList.GetClassName(Index: integer): string;
|
||||
var
|
||||
i: integer;
|
||||
begin
|
||||
Result:=Strings[Index];
|
||||
i:=Pos('.', Result);
|
||||
if i > 0 then
|
||||
System.Delete(Result, 1, i);
|
||||
end;
|
||||
|
||||
function TClassList.GetClassInfo(Index: integer): TClassInfo;
|
||||
begin
|
||||
Result:=TClassInfo(Objects[Index]);
|
||||
end;
|
||||
|
||||
function TClassList.GetFullName(const AName: string; Def: TDef): string;
|
||||
begin
|
||||
if (Def = nil) or (Def.DefType = dtUnit) then
|
||||
Result:=AName
|
||||
else begin
|
||||
while (Def.Parent <> nil) and (Def.DefType <> dtUnit) do
|
||||
Def:=Def.Parent;
|
||||
Result:=Def.Name + '.' + AName;
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TClassList.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
Sorted:=True;
|
||||
end;
|
||||
|
||||
function TClassList.Add(const AName: string; Def: TDef; Info: TClassInfo): integer;
|
||||
begin
|
||||
Result:=AddObject(GetFullName(AName, Def), Info);
|
||||
end;
|
||||
|
||||
{ TTextOutStream }
|
||||
|
||||
procedure TTextOutStream.SetIndednt(const AValue: integer);
|
||||
@ -210,24 +287,6 @@ begin
|
||||
Indent:=Indent - 1;
|
||||
end;
|
||||
|
||||
type
|
||||
{ TClassInfo }
|
||||
TClassInfo = class
|
||||
public
|
||||
Def: TDef;
|
||||
Funcs: TObjectList;
|
||||
IsCommonClass: boolean;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
TProcInfo = class
|
||||
public
|
||||
Name: string;
|
||||
JniName: string;
|
||||
JniSignature: string;
|
||||
end;
|
||||
|
||||
{ TClassInfo }
|
||||
|
||||
constructor TClassInfo.Create;
|
||||
@ -705,9 +764,9 @@ begin
|
||||
pi.JniSignature:=GetProcSignature(d);
|
||||
if AParent = nil then begin
|
||||
// Checking duplicate proc name and duplicate param types
|
||||
ClassIdx:=FClasses.IndexOf(GetJavaClassName(d.Parent, ItemDef));
|
||||
ClassIdx:=FClasses.IndexOf(GetJavaClassName(d.Parent, ItemDef), d.Parent);
|
||||
if ClassIdx >= 0 then begin
|
||||
ci:=TClassInfo(FClasses.Objects[ClassIdx]);
|
||||
ci:=FClasses.GetClassInfo(ClassIdx);
|
||||
j:=1;
|
||||
ss:=Copy(pi.JniSignature, 1, Pos(')', pi.JniSignature));
|
||||
repeat
|
||||
@ -973,16 +1032,16 @@ begin
|
||||
AParent:=d.Parent;
|
||||
end
|
||||
else
|
||||
ClassIdx:=FClasses.IndexOf(GetJavaClassName(AParent, ItemDef));
|
||||
ClassIdx:=FClasses.IndexOf(GetJavaClassName(AParent, ItemDef), AParent);
|
||||
|
||||
if ClassIdx < 0 then begin
|
||||
ci:=TClassInfo.Create;
|
||||
ci.Def:=AParent;
|
||||
s:=GetJavaClassName(AParent, ItemDef);
|
||||
ci.IsCommonClass:=s <> AParent.Name;
|
||||
ClassIdx:=FClasses.AddObject(s, ci);
|
||||
ClassIdx:=FClasses.Add(s, AParent, ci);
|
||||
end;
|
||||
TClassInfo(FClasses.Objects[ClassIdx]).Funcs.Add(pi);
|
||||
FClasses.GetClassInfo(ClassIdx).Funcs.Add(pi);
|
||||
pi:=nil;
|
||||
|
||||
// Java part
|
||||
@ -1170,19 +1229,30 @@ begin
|
||||
s:='double';
|
||||
end
|
||||
else begin
|
||||
s:=DefToJavaType(d.VarType);
|
||||
if d.VarType.DefType = dtType then
|
||||
case TTypeDef(d.VarType).BasicType of
|
||||
btLongWord, btInt64:
|
||||
v:=v + 'L';
|
||||
btBoolean:
|
||||
if v = '1' then
|
||||
v:='true'
|
||||
else
|
||||
v:='false';
|
||||
end;
|
||||
s:='';
|
||||
case d.VarType.DefType of
|
||||
dtType:
|
||||
case TTypeDef(d.VarType).BasicType of
|
||||
btLongWord, btInt64:
|
||||
v:=v + 'L';
|
||||
btBoolean:
|
||||
if v = '1' then
|
||||
v:='true'
|
||||
else
|
||||
v:='false';
|
||||
end;
|
||||
dtArray:
|
||||
with TArrayDef(d.VarType) do
|
||||
if (ElType.DefType = dtType) and (TTypeDef(ElType).BasicType in [btChar, btWideChar]) then
|
||||
s:='String';
|
||||
end;
|
||||
if s = '' then
|
||||
s:=DefToJavaType(d.VarType);
|
||||
end;
|
||||
Fjs.WriteLn(Format('public static final %s %s = %s;', [s, d.Name, v]));
|
||||
v:=Format('public static final %s %s = %s;', [s, d.Name, v]);
|
||||
if s = SUnsupportedType then
|
||||
v:='// ' + v;
|
||||
Fjs.WriteLn(v);
|
||||
end;
|
||||
|
||||
procedure TWriter.WriteEnum(d: TDef);
|
||||
@ -1254,6 +1324,7 @@ begin
|
||||
Fps.WriteLn('var');
|
||||
Fps.IncI;
|
||||
Fps.WriteLn('_env: PJNIEnv;');
|
||||
Fps.WriteLn('_new_env: boolean;');
|
||||
Fps.WriteLn('_mpi: _TMethodPtrInfo;');
|
||||
if d.Count > 0 then begin
|
||||
Fps.WriteLn(Format('_args: array[0..%d] of jvalue;', [d.Count - 1]));
|
||||
@ -1270,6 +1341,11 @@ begin
|
||||
Fps.WriteLn('begin');
|
||||
Fps.IncI;
|
||||
Fps.WriteLn('CurJavaVM^^.GetEnv(CurJavaVM, @_env, JNI_VERSION_1_6);');
|
||||
Fps.WriteLn('_new_env:=_env = nil;');
|
||||
Fps.WriteLn('if _new_env then CurJavaVM^^.AttachCurrentThread(CurJavaVM, @_env, nil);');
|
||||
Fps.WriteLn('_env^^.PushLocalFrame(_env, 100);');
|
||||
Fps.WriteLn('try');
|
||||
Fps.IncI;
|
||||
Fps.WriteLn('_MethodPointersCS.Enter;');
|
||||
Fps.WriteLn('try');
|
||||
Fps.WriteLn('_mpi:=_TMethodPtrInfo(_MethodPointers[-integer(ptruint(Self)) - 1]);', 1);
|
||||
@ -1330,6 +1406,11 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
Fps.DecI;
|
||||
Fps.WriteLn('finally');
|
||||
Fps.WriteLn('_env^^.PopLocalFrame(_env, nil);', 1);
|
||||
Fps.WriteLn('if _new_env then CurJavaVM^^.DetachCurrentThread(CurJavaVM);', 1);
|
||||
Fps.WriteLn('end;');
|
||||
Fps.DecI;
|
||||
Fps.WriteLn('end;');
|
||||
|
||||
@ -1356,7 +1437,7 @@ begin
|
||||
Fjs.IncI;
|
||||
Fjs.WriteLn(Format('{ mSignature = "%s"; }', [GetProcSignature(d)]));
|
||||
Fjs.WriteLn(Format('protected %s(long objptr, boolean cleanup) { _pasobj=objptr; }', [d.Name]));
|
||||
Fjs.WriteLn(Format('public %s(Object Obj, String MethodName) { mObject=Obj; mName=MethodName; }', [d.Name]));
|
||||
Fjs.WriteLn(Format('@Deprecated public %s(Object Obj, String MethodName) { mObject=Obj; mName=MethodName; }', [d.Name]));
|
||||
Fjs.WriteLn(Format('public %s() { mObject=this; mName="Execute"; }', [d.Name]));
|
||||
Fjs.WriteLn(Format('protected %s throws NoSuchMethodException { throw new NoSuchMethodException(); }', [GetJavaProcDeclaration(d, 'Execute')]));
|
||||
Fjs.DecI;
|
||||
@ -1770,6 +1851,7 @@ begin
|
||||
Fjs.WriteLn('public int Value;');
|
||||
Fjs.WriteLn('public int Ord() { return Value; }');
|
||||
Fjs.WriteLn('@Override public boolean equals(Object o) { return (o instanceof Integer) && Value == (Integer)o; }');
|
||||
Fjs.WriteLn('public boolean equals(int v) { return Value == v; }');
|
||||
Fjs.WriteLn('@Override public int hashCode() { return Value; }');
|
||||
Fjs.DecI;
|
||||
Fjs.WriteLn('}');
|
||||
@ -1891,10 +1973,10 @@ begin
|
||||
|
||||
Fps.WriteLn('const');
|
||||
for i:=0 to FClasses.Count - 1 do begin
|
||||
ci:=TClassInfo(FClasses.Objects[i]);
|
||||
ci:=FClasses.GetClassInfo(i);
|
||||
if ci.Funcs.Count = 0 then
|
||||
continue;
|
||||
Fps.WriteLn(Format(' _%sNativeMethods: array[0..%d] of JNINativeMethod = (', [GetClassPrefix(ci.Def, FClasses[i]), ci.Funcs.Count - 1]));
|
||||
Fps.WriteLn(Format(' _%sNativeMethods: array[0..%d] of JNINativeMethod = (', [GetClassPrefix(ci.Def, FClasses.GetClassName(i)), ci.Funcs.Count - 1]));
|
||||
for j:=0 to ci.Funcs.Count - 1 do begin
|
||||
with TProcInfo(ci.Funcs[j]) do
|
||||
Fps.Write(Format(' (name: ''%s''; signature: ''%s''; fnPtr: @%s)', [Name, JniSignature, JniName]));
|
||||
@ -1953,7 +2035,7 @@ begin
|
||||
end;
|
||||
|
||||
for i:=0 to FClasses.Count - 1 do begin
|
||||
ci:=TClassInfo(FClasses.Objects[i]);
|
||||
ci:=FClasses.GetClassInfo(i);
|
||||
s:=GetTypeInfoVar(ci.Def);
|
||||
if (s = '') or (ci.IsCommonClass) then
|
||||
s:='nil'
|
||||
@ -1962,13 +2044,13 @@ begin
|
||||
if ci.Funcs.Count = 0 then
|
||||
ss:='nil'
|
||||
else
|
||||
ss:=Format('@_%sNativeMethods', [GetClassPrefix(ci.Def, FClasses[i])]);
|
||||
ss:=Format('@_%sNativeMethods', [GetClassPrefix(ci.Def, FClasses.GetClassName(i))]);
|
||||
fn:='';
|
||||
if ci.Def <> nil then
|
||||
if ci.Def.DefType in [dtSet, dtEnum] then
|
||||
fn:=', ''Value'', ''I''';
|
||||
Fps.WriteLn(Format('if not _Reg(''%s'', %s, %d, %s%s) then exit;',
|
||||
[GetJavaClassPath(ci.Def, FClasses[i]), ss, ci.Funcs.Count, s, fn]));
|
||||
[GetJavaClassPath(ci.Def, FClasses.GetClassName(i)), ss, ci.Funcs.Count, s, fn]));
|
||||
end;
|
||||
|
||||
Fps.WriteLn('Result:=JNI_VERSION_1_6;');
|
||||
@ -2249,10 +2331,10 @@ procedure TWriter.RegisterPseudoClass(d: TDef);
|
||||
var
|
||||
ci: TClassInfo;
|
||||
begin
|
||||
if FClasses.IndexOf(d.Name) < 0 then begin
|
||||
if FClasses.IndexOf(d.Name, d) < 0 then begin
|
||||
ci:=TClassInfo.Create;
|
||||
ci.Def:=d;
|
||||
FClasses.AddObject(d.Name, ci);
|
||||
FClasses.Add(d.Name, d, ci);
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -2305,13 +2387,13 @@ begin
|
||||
pi.Name:=Name;
|
||||
pi.JniName:=JniName;
|
||||
pi.JniSignature:=Signature;
|
||||
i:=FClasses.IndexOf(ParentDef.AliasName);
|
||||
i:=FClasses.IndexOf(ParentDef.AliasName, ParentDef);
|
||||
if i < 0 then begin
|
||||
ci:=TClassInfo.Create;
|
||||
ci.Def:=ParentDef;
|
||||
i:=FClasses.AddObject(ParentDef.AliasName, ci);
|
||||
i:=FClasses.Add(ParentDef.AliasName, ParentDef, ci);
|
||||
end;
|
||||
TClassInfo(FClasses.Objects[i]).Funcs.Add(pi);
|
||||
FClasses.GetClassInfo(i).Funcs.Add(pi);
|
||||
end;
|
||||
|
||||
function TWriter.GetProcSignature(d: TProcDef): string;
|
||||
@ -2398,8 +2480,7 @@ var
|
||||
i: integer;
|
||||
begin
|
||||
Units:=TStringList.Create;
|
||||
FClasses:=TStringList.Create;
|
||||
FClasses.Sorted:=True;
|
||||
FClasses:=TClassList.Create;
|
||||
JavaPackage:='pas';
|
||||
IncludeList:=TStringList.Create;
|
||||
IncludeList.Duplicates:=dupIgnore;
|
||||
|
Loading…
Reference in New Issue
Block a user