0
votes

I am trying to access Java classes dynamically from *.apk file using C++ Builder (Android development). For this purpose I have found complete guide with example in Delphi (here: http://www.pclviewer.com/android/androidJNI.html). Everything works fine in Delphi, but when I tried to rewrite Pascal source code (at the end of guide) into C++ using C++ Builder XE7, I found curious problem. How to cast Delphi interface into TObject* in C++, properly invoke ClassName() function and get JavaObjectID? I spent a lot of time, but still cannot rewrite these 3 lines of code:

var
JavaObject:JObject;
oTemp:TObject;
JavaObjectID:JNIObject;
:
oTemp:=JavaObject as TObject;                   //1. ?
JavaObjectID:=tjavaimport(otemp).GetObjectID;   //2. ?
memo1.Lines.Add(oTemp.ClassName);               //3. ? 
:

I have tried differenet type casts, also using GetInterface() method of TObject class, but nothing works. As a C++ programmer I don't understand how is it possible directly cast delphi interface into TObject*.

Androidapi::Jni::Javatypes::_di_JObject JavaObject;
System::TObject* oTemp; 
Androidapi::Jni::_JNIObject *JavaObjectID;  
:
oTemp = (TObject*)(&JavaObject);   //Compiling ok, but segmentation fault 
?
Memo1->Lines->Add(oTemp->ClassName()); // after ClassName() invoke.

Does anybody know. how to rewrite these 3 lines of Pascal code into C++ please? Thank you very much for your response.

1
My question is why you are casting an interface to TObject. Isn't that something that you should not do?David Heffernan
This way was used in the Delphi example (pclviewer.com/android/androidJNI.html) and is fully functional. I tried to rewrite code line by line into C++ Builder project, but discovered, that C++ has not interfaces. Delphi interfaces are imitated by abstract classes with pure virtual functions in C++ Builder. Probably it is possible to rewrite mentioned code by the different manner, or use object code generated by Delphi directly in C++ Builder together with generated *.hpp header, but feeling, that I don't understand basics and cannot rewrite 3 lines from Pascal makes me unhappy.Oxin
It would make much more sense to stick to interfaces. Solve the problem entirely with interfaces, and stop trying to cast to the implementing object. Something that goes completely against the spirit of interfaces.David Heffernan
Probably you are right. I will try different way. Even though still don't understand how it is possible to write "oTemp:=JavaObject as TObject" in Pascal and then properly get ClassName, which return "TJavaImport". These two entities are completely different also in Pascal. Only thing they have common is, they both supports IUnknown interface. Where the common "ClassName" comes from is a puzzle for me.Oxin
ClassName is a method of TObject. A Delphi interface may be implemented by an instance of a class, and the as cast is a way to retrieve that implementing instance. Of course, some interfaces are external and are not implemented by Delphi objects. For them, the as cast will fail.David Heffernan

1 Answers

2
votes

Casting an interface into an object reference is a Delphi-only feature, there is no equivilent in C++ without delving into the vtable directly. What you can do, however, is write a function in Delphi that takes an interface as input, casts it, and returns the object as output, and then call that function in C++ code. You can add a Delphi .pas file to a C++Builder project, it will generate a C++ .hpp file when compiled.

unit MyJavaHelper;

interface

uses
  Androidapi.JNI.JavaTypes;

function JObjectToTObject(JavaObject: JObject): TObject;

implementation

function JObjectToTObject(JavaObject: JObject): TObject;
begin
  Result := JavaObject as TObject;
end;

end.
#include "MyJavaHelper.hpp"

Androidapi::Jni::Javatypes::_di_JObject JavaObject;
System::TObject* oTemp; 
Androidapi::Jni::_JNIObject *JavaObjectID;  

JavaObject = ...;
oTemp = JObjectToTObject(JavaObject);
JavaObjectID = static_cast<TJavaImport*>(otemp)->GetObjectID();   
Memo1->Lines->Add(oTemp->ClassName());