Maison  >  Article  >  Java  >  Utilisation de Java Native Access (JNA) pour appeler l'API MacOS

Utilisation de Java Native Access (JNA) pour appeler l'API MacOS

Susan Sarandon
Susan Sarandonoriginal
2024-09-23 16:16:59659parcourir

Using Java Native Access (JNA) to call MacOS API

Introduction

Voici un exemple simple sur la façon d'utiliser JNA avec l'API MacOS. Je ne vais pas expliquer cela, car j'apprends encore, mais je garde le code au minimum pour le rendre plus facile à comprendre et avoir une idée de base sur la façon de le faire à d'autres fins.

La plupart du code provient d'Intellij-Community (licence Apache).

Dépendance

Tout ce dont nous avons besoin, c'est de la plateforme JNA.

<dependency>
  <groupId>net.java.dev.jna</groupId>
  <artifactId>jna-platform</artifactId>
  <version>5.13.0</version>
</dependency>

Code

Il y a au total 4 fichiers de code source. L'ID est copié depuis IntelliJ sans modification. MyFoundation et MyFoundationLibrary sont respectivement supprimés de Foundation et FoundationLibrary.

Application.java

package org.example;

import com.sun.jna.Pointer;

import static org.example.MyFoundation.*;

public class Application {

    public static void main(String[] args) throws Exception {
        ID processInfoCls = getObjcClass("NSProcessInfo");
        Pointer processInfoSel = createSelector("processInfo");
        Pointer processNameSel = createSelector("processName");

        ID processInfo = invoke(processInfoCls, processInfoSel);
        ID processNameNSString = invoke(processInfo, processNameSel);
        String processName = toStringViaUTF8(processNameNSString);
        System.out.println(processName);
    }

}

ID.java

package org.example;

import com.sun.jna.NativeLong;

public final class ID extends NativeLong {

    public ID() {
    }

    public ID(long peer) {
        super(peer);
    }

    public static final ID NIL = new ID(0L);

    public boolean booleanValue() {
        return intValue() != 0;
    }
}

MaFoundationLibrary.java

public interface MyFoundationLibrary extends Library {

    int kCFStringEncodingUTF8 = 0x08000100;

    ID objc_getClass(String className);

    Pointer sel_registerName(String selectorName);

    int CFStringGetLength(ID theString);

    byte CFStringGetCString(ID theString, byte[] buffer, int bufferSize, int encoding);

}

MaFondation.java

package org.example;

import com.sun.jna.*;

import java.lang.reflect.Proxy;
import java.util.Collections;

public class MyFoundation {
    private static final MyFoundationLibrary myFoundationLibrary;
    private static final Function myObjcMsgSend;

    static {
        myFoundationLibrary = Native.load("Foundation", MyFoundationLibrary.class, Collections.singletonMap("jna.encoding", "UTF8"));
        NativeLibrary nativeLibrary = ((Library.Handler) Proxy.getInvocationHandler(myFoundationLibrary)).getNativeLibrary();
        myObjcMsgSend = nativeLibrary.getFunction("objc_msgSend");
    }

    public static ID getObjcClass(String className) {
        return myFoundationLibrary.objc_getClass(className);
    }

    public static Pointer createSelector(String s) {
        return myFoundationLibrary.sel_registerName(s);
    }

    private static Object [] prepInvoke(ID id, Pointer selector, Object[] args) {
        Object[] invokArgs = new Object[args.length + 2];
        invokArgs[0] = id;
        invokArgs[1] = selector;
        System.arraycopy(args, 0, invokArgs, 2, args.length);
        return invokArgs;
    }

    public static ID invoke(final ID id, final Pointer selector, Object... args) {
        // objc_msgSend is called with the calling convention of the target method
        // on x86_64 this does not make a difference, but arm64 uses a different calling convention for varargs
        // it is therefore important to not call objc_msgSend as a vararg function
        return new ID(myObjcMsgSend.invokeLong(prepInvoke(id, selector, args)));
    }

    public static String toStringViaUTF8(ID cfString) {
        if (ID.NIL.equals(cfString)) return null;

        int lengthInChars = myFoundationLibrary.CFStringGetLength(cfString);
        int potentialLengthInBytes = 3 * lengthInChars + 1; // UTF8 fully escaped 16 bit chars, plus nul

        byte[] buffer = new byte[potentialLengthInBytes];
        byte ok = myFoundationLibrary.CFStringGetCString(cfString, buffer, buffer.length, MyFoundationLibrary.kCFStringEncodingUTF8);
        if (ok == 0) throw new RuntimeException("Could not convert string");
        return Native.toString(buffer);
    }

}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn