Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

Calling C/C++ from Java Android using CLE

0.00/5 (No votes)
5 Mar 2012CPOL1 min read 13.1K  
How to call C/C++ from Java Android using CLE

There are lots of resources written in C/C++ languages. But on Android platform, Java is major language. Developers have to use JNI to wrap the interface of C/C++ codes. JNI is suitable for simple case. For more complicated applications, programmers have to maintain references of C++ objects to Java objects, process callback functions from C/C++ to Java, etc., which are not easy. Using CLE, these works will be done by CLE, programmers only need to focus on specific functions.

For Java calls C/C++ using CLE, method is not directly as Java calls scripts, such as lua, python, etc. Because, script languages all have reflection mechanism. We can get functions and attributes definition dynamically. But for C/C++, there is no similar mechanism. All definitions in the source code will be compiled into binary code. Therefore, we need descript functions and attributes of objects first, if CLE is used.

There are two methods to descript object’s attributes and functions.

First Method, Using Interface Functions of CLE

C++
void *AtomicClass,*Add_AtomicFunction,*Print_AtomicFunction;
AtomicClass = SRPInterface ->CreateAtomicObjectSimple(
    "TestItem","TestClass","VS_INT32 CValue",NULL,NULL);
Add_AtomicFunction = SRPInterface ->CreateAtomicFunctionSimple(
    AtomicClass,"CAdd",
    "VS_INT32 CAdd(VS_INT32 x,VS_INT32 y);",NULL,NULL,VS_FALSE,VS_FALSE);
Print_AtomicFunction = SRPInterface ->CreateAtomicFunctionSimple(
    AtomicClass,"CPrint",
    "void CPrint(VS_INT32 x,VS_INT32 y);",NULL,NULL,VS_FALSE,VS_FALSE);

Second Method, Using XML String Generates object’s Attributes and Functions

C++
    void *AtomicClass,*Add_AtomicFunction,*Print_AtomicFunction;
    class ClassOfSRPSXMLInterface *SXMLInterface;
    SXMLInterface = BasicSRPInterface -> GetSXMLInterface();
    
    SXMLInterface -> LoadFromBuf(

"   <?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"    
"   <sysrootitem>\n"
"        <TestItem>\n"
"            <object>\n"
"                <TestClass ID=\"ed51e615-e548-442e-8802-a99b2fa8fe15\">\n"
"                    <attribute>\n"
"                        <CValue Type=\"VS_INT32\" />\n"
"                    </attribute>\n"
"                    <function>\n"
"                        <CAdd ID=\"f402fd47-8bea-4136-b7f7-45bb7fb51b14\">\n"
"                            <input Name=\"x\" Type=\"VS_INT32\" />\n"
"                            <input Name=\"y\" Type=\"VS_INT32\" />\n"
"                            <output Type=\"VS_INT32\" />\n"
"                        </CAdd>\n"
"                        <CPrint ID=\"da44c24e-f20a-46e3-8d37-49c3b90c6c05\">\n"
"                            <input Name=\"x\" Type=\"VS_INT32\" />\n"
"                            <input Name=\"y\" Type=\"VS_INT32\" />\n"
"                        </CPrint>\n"
"                    </function>\n"
"                </TestClass>\n"
"            </object>\n"
"        </TestItem>\n"
"   </sysrootitem>\n"
    ,NULL);
    
    SRPInterface -> XmlToSysRootItem(SXMLInterface,NULL,"",NULL,0);
    
    AtomicClass = SRPInterface ->GetAtomicObject
    (_UUIDPTR("ed51e615-e548-442e-8802-a99b2fa8fe15"));
    Add_AtomicFunction = SRPInterface ->GetAtomicFunction
    (_UUIDPTR("f402fd47-8bea-4136-b7f7-45bb7fb51b14"));
    Print_AtomicFunction = SRPInterface ->GetAtomicFunction
    (_UUIDPTR("da44c24e-f20a-46e3-8d37-49c3b90c6c05"));

After finish object’s attributes and functions, we can attach functions body address:

//---Set Function Address
SRPInterface -&gt; SetAtomicFunction(Add_AtomicFunction,(void *)CAdd);
SRPInterface -&gt; SetAtomicFunction(Print_AtomicFunction,(void *)CPrint);

By now, the functions and attributes can be accessed from Java.

Java Code

C++
StarObjectClass a = Service._GetObject("TestClass")._New();
a._Call("CAdd",12,34));

Callback of C/C++ to Java

Java
java call back function:
StarObjectClass a = Service._GetObject("TestClass")._New()._Assign(new StarObjectClass(){
		    public int JavaAdd(StarObjectClass self,int x,int y){
		        return x+y;
		    }
		 });

C Code

C++
VS_INT32 ScriptStack;

ScriptStack = SRPInterface -> ScriptGetStack();     //----save script stack
SRPInterface -> Print( "Function result from java %d",
         SRPInterface -> ScriptCall
         (Object,NULL,"JavaAdd","(ii)i)",x,y) );
SRPInterface -> ScriptSetStack(ScriptStack);

Source code ( integrate CLE with your project):

  1. Download devfiles from http://code.google.com/p/cle-for-android, and then Open Eclipse
  2. Create project for Android.
  3. Add CLE jar to project as follows:

C++ Code

C++
#include "vsopenapi.h"
class ClassOfSRPInterface *SRPInterface;
struct StructOfTestClass{
    VS_INT32 CValue;
};    
static VS_INT32 CAdd(void *Object,VS_INT32 x,VS_INT32 y)
{
    struct StructOfTestClass *TestClass;
    
    TestClass = (struct StructOfTestClass *)Object;
    TestClass -> CValue = 200;
    SRPInterface -> Print("Call c function...");
    return x+y;    
}
static void CPrint(void *Object,VS_INT32 x,VS_INT32 y)
{
    VS_INT32 ScriptStack;
    
    ScriptStack = SRPInterface -> ScriptGetStack();     //----save script stack
    SRPInterface -> Print( "Value defined in java is %d",SRPInterface -> 
    ScriptGetInt(Object,"JavaValue") );
    SRPInterface -> Print( "Function result from java %d",
                    SRPInterface -> ScriptCall(Object,NULL,"JavaAdd","(ii)i)",x,y) );
    SRPInterface -> ScriptSetStack(ScriptStack);     //----restore script stack
}
VS_BOOL StarCoreService_Init(class ClassOfStarCore *starcore)
{
    void *AtomicClass,*Add_AtomicFunction,*Print_AtomicFunction;
    class ClassOfBasicSRPInterface *BasicSRPInterface;
    
    //--init star core
    BasicSRPInterface = starcore ->GetBasicInterface();    
    SRPInterface = BasicSRPInterface ->GetSRPInterface
    (BasicSRPInterface->QueryActiveService(NULL),"","");
    
    //---Create Atomic Class, for define function,  
    AtomicClass = SRPInterface ->CreateAtomicObjectSimple
    ("TestItem","TestClass","VS_INT32 CValue",NULL,NULL);
    Add_AtomicFunction = SRPInterface ->CreateAtomicFunctionSimple
    (AtomicClass,"CAdd","VS_INT32 CAdd(VS_INT32 x,VS_INT32 y);",
    NULL,NULL,VS_FALSE,VS_FALSE);
    Print_AtomicFunction = SRPInterface ->CreateAtomicFunctionSimple
    (AtomicClass,"CPrint","void CPrint(VS_INT32 x,VS_INT32 y);",
    NULL,NULL,VS_FALSE,VS_FALSE);    
    //---Set Function Address
    SRPInterface -> SetAtomicFunction(Add_AtomicFunction,(void *)CAdd);
    SRPInterface -> SetAtomicFunction(Print_AtomicFunction,(void *)CPrint);
    return VS_TRUE;
}
void StarCoreService_Term(class ClassOfStarCore *starcore)
{
    SRPInterface -> Release();
    return;
}

Compile code into share library using NDK, the Android.mk is:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Here we give our module name and sourcefile(s)
LOCAL_CFLAGS += -Wno-write-strings -DENV_ANDROID
LOCAL_CPPFLAGS += -Wno-write-strings -fexceptions -DENV_ANDROID
LOCAL_LDFLAGS += -Wno-write-strings -DENV_ANDROID
LOCAL_C_INCLUDES += ../../cle_files/include
#--------source file
MODULE_CXXSRCS := AddFunction.cpp
LOCAL_SRC_FILES := ${MODULE_CXXSRCS}
LOCAL_LDLIBS := ../../cle_files/libs/armeabi/libstarlib.a
LOCAL_MODULE  := AddFunction
include $(BUILD_SHARED_LIBRARY)

Java Code

Java
package com.cle.cfromjava;

import android.app.Activity;
import android.os.Bundle;

import com.srplab.www.starcore.*;
import com.srplab.netinst.*;

public class CfromjavaActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        //--init CLE
        starcore_net_inst.InstallZipFile
        (this,"libstarcore.so",
        "http://www.srplab.com/android/starcore_armeabi_r3.zip", 
        "/data/data/com.cle.cfromjava/files");
        StarCoreFactoryPath.StarCoreShareLibraryPath = 
        "/data/data/com.cle.cfromjava/files";
        StarCoreFactoryPath.StarCoreOperationPath = 
        "/data/data/com.cle.cfromjava/files";                
        
		 StarCoreFactory starcore= StarCoreFactory.GetFactory();
		 StarServiceClass Service=starcore._InitSimple
		 ("test","123",0,0);
		 Service._CheckPassword(false);
      
        Service._DoFile
        ("","/data/data/com.cle.cfromjava/lib/libAddFunction.so","");
        
		 StarObjectClass a = Service._GetObject
		 ("TestClass")._New()._Assign(new StarObjectClass(){
		    public int JavaAdd(StarObjectClass self,int x,int y){
		        System.out.println("Call java function...");
		        return x+y;
		    }
		 });
        a._Set("JavaValue",100);
        System.out.println(a._Call("CAdd",12,34));                   
        System.out.println(a._Get("CValue"));						
         a._Call("CPrint",56,78);   
        
        starcore._ModuleExit();
    }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)