java—使用jni Package 现有应用程序

4xrmg8kj  于 2021-06-30  发布在  Java
关注(0)|答案(3)|浏览(311)

大多数详细介绍如何开始使用jni的文档都描述了如何使用x代码构建新的jni应用程序。有谁能把我链接到一个关于如何在现有应用程序中使用jni与objective-c接口的描述上吗。

abithluo

abithluo1#

注:我已经完全重新写了这个答案,从零开始,现在我知道它肯定工作;-)。
用洛可可代替jni。
下面是一个简短的示例,我可以快速创建这个示例,其中显示了“拍照者”对话框(基于您对stephen c答案的评论)。

/***
 * INCOMPLETE: Doesn't have imports or anything like that.

***/

public interface Quartz extends Library
{
  public static Quartz instance = (Quartz)Native.loadLibrary("Quartz", Quartz.class);
}

public interface IKPictureTaker extends NSObject
{
  public static final _Class CLASS = Rococoa.createClass("IKPictureTaker", _Class.class);

  public interface _Class extends NSClass
  {
    /**
     * Returns a shared {@code IKPictureTaker} instance, creating it if necessary.
     * @return an {@code IKPictureTaker} object.
     */
    IKPictureTaker pictureTaker();
  }

  NSInteger runModal();
}

public class IKPictureTakerTest extends JFrame
{
  public static void main(String[] args) throws Exception
  {
    // You need a GUI before this will work.
    new IKPictureTakerTest().setVisible(true);

    NSAutoreleasePool pool = NSAutoreleasePool.new_();

    // Initialize the Quartz framework.
    Quartz.instance.toString();

    // Display the dialog.
    IKPictureTaker pictureTaker = IKPictureTaker.CLASS.pictureTaker();
    NSInteger result = pictureTaker.runModal();

    if (result.intValue() == 0) // NSCancelButton
    {
      System.out.println("User cancelled.");
    }
    else
    {
      assert result.intValue() == 1; // NSOKButton
      System.out.println("User chose an image.");
    }

    System.out.println(pictureTaker.inputImage()); // null if the user cancelled

    pool.release();
  }
}

如果你迷路了,试试洛可可式的邮件列表。开发人员很有帮助。

pftdvrlh

pftdvrlh2#

您仍然需要编写某种类型的jni库来 Package 对现有代码(aka、共享对象、dll、服务程序等)的访问。这是因为jni需要一个相当迟钝(但合理)的命名约定来调用本机函数,因为您需要将数据移入和移出java内存空间,并且需要在java和本机函数之间建立概念性的“桥接”代码。
例如,我编写了一个jni库来提供对iseries上现有c函数的访问。从数据区域读取的函数如下所示:

JNIEXPORT void JNICALL Java_com_xxx_jni400_DataArea_jniGetDataArea(JNIEnv *jep, jobject thsObj, jbyteArray qulnam, jint str, jint len, jbyteArray rtndta, jint rtnlen) {
    jbyte           *qn,*rd;
    Qwc_Rdtaa_Data_Returned_t *drt;
    QFBK2_T         fbk;
    byte            nam[11],lib[11];
    byte            *ptr;

    // SETUP
    thsObj=thsObj;
    qn=(*jep)->GetByteArrayElements(jep,qulnam,0);
    rd=(*jep)->GetByteArrayElements(jep,rtndta,0);
    fbk.pro=sizeof(fbk); fbk.avl=0;

    // INVOKE
    QWCRDTAA(rd,rtnlen,(byte*)qn,str,len,&fbk);

    // HANDLE SUCCESSFUL INVOCATION
    if(fbk.avl==0) {
        drt=(Qwc_Rdtaa_Data_Returned_t*)rd;
        if(drt->Length_Value_Returned>0) { /* pad with spaces until the length requested */
            ptr=(byte*)(rd+sizeof(*drt)+drt->Length_Value_Returned);
            for(; drt->Length_Value_Returned<len; drt->Length_Value_Returned++,ptr++) { *ptr=' '; }
            }
        }

    // RELEASE JAVA MEMORY LOCKS
    (*jep)->ReleaseByteArrayElements(jep,qulnam,qn,JNI_ABORT); /* discard array changes */
    (*jep)->ReleaseByteArrayElements(jep,rtndta,rd,0        ); /* copy back changes */

    // TRANSFORM NATIVE ERROR INTO AN EXCEPTION AND THROW
    if(fbk.avl!=0) {
        byte             eid[8],dta[201];
        word             dtalen;

        f2s(nam,sizeof(nam),(byte*)qn     ,10);
        f2s(lib,sizeof(lib),(byte*)(qn+10),10);

        dtalen=(word)mMin( sizeof(fbk.dta),(fbk.avl-(sizeof(fbk)-sizeof(fbk.dta))) );
        f2s(eid,sizeof(eid),fbk.eid,sizeof(fbk.eid));
        f2s(dta,sizeof(dta),fbk.dta,dtalen);
        if(mStrEquI(eid,"CPF1015") || mStrEquI(eid,"CPF1021")) {
            throwEscape(jep,90301,"Could not find data area %s in library %s",nam,lib);
            }
        else if(mStrEquI(eid,"CPF1016") || mStrEquI(eid,"CPF1022")) {
            throwEscape(jep,90301,"Not authorized to data area %s in library %s",nam,lib);
            }
        else if(mStrEquI(eid,"CPF1063") || mStrEquI(eid,"CPF1067")) {
            throwEscape(jep,90301,"Cannot allocate data area %s in library %s",nam,lib);
            }
        else if(mStrEquI(eid,"CPF1088") || mStrEquI(eid,"CPF1089")) {
            throwEscape(jep,90301,"Substring %i,%i for data area %s in library %s are not valid",str,len,nam,lib);
            }
        else {
            if(strlen(dta)>0) { throwEscape(jep,90001,"System API QWCRDTAA returned error message ID %s (%s)",eid,dta);}
            else              { throwEscape(jep,90001,"System API QWCRDTAA returned error message ID %s",eid);         }
            }
        }
    }

请注意ibm提供的对底层现有api qwcrdtaa的单行调用;其余的是以java为中心的 Package ,这是进行调用和处理结果所必需的。
另外,要非常小心您所调用的是线程安全的,或者在java层全局地保护代码不受并发调用的影响,或者在o/s层使用mutex保护代码。
注意,非线程安全的本机代码是全局非线程安全的;必须防止与所有其他非线程安全本机代码(而不仅仅是正在调用的一个方法)并发调用。这是因为它可能是不安全的,因为对其他不安全方法调用的某个函数的底层调用(如strerror(),(如果我的c内存运行良好的话))。

z3yyvxxp

z3yyvxxp3#

假设object-c应用程序可以通过命令行运行,一种更简单(问题更少)的方法是使用 java.lang.Runtime.exec(...) 方法。
jni充满了复杂性和稳定性问题,如果可以的话最好避免它。
编辑:op解释说这是一个“小部件”而不是命令行应用程序。这使得避免使用jni变得更加困难。但我还是觉得你应该试试。例如,您可以考虑将objective-c小部件 Package 到objective-c应用程序中,该应用程序在新窗口中运行小部件。

相关问题