当前位置: 首页 > 面试题库 >

使用JNA和Ada的Interface.C软件包将Ada动态库与Java接口

丌官利
2023-03-14
问题内容

我必须编写一个DLL,以提供一种简单的服务,该服务需要:

  • 在字符串或字节数组中(等同于char *)
  • IN整数,表示in char *的大小
  • IN等同于库用于在其中写入数据的char *缓冲区
  • 用于写入的可用char *缓冲区的IN大小
  • OUT有效写入大小到out char *缓冲区中

使用C的观点,签名应如下所示:

void myService (char* inBuffer,  // as in string
                int   anInteger, // as in param
                char* outBuffer, // used as out buffer, but initalized by calling code
                int   outBufferSize, // the initaliaed size
                int   usedBufferSize // used as out param, the actually used size
);

选择该库是为了使用Ada进行编码有几个原因(几个Ada包可以重复使用,我们不想再次进行编码或重新设计(传统))。该库应该在Java项目中使用(并且我们不想从Java端对lib提供的服务进行重新编码)。(这样做的主要原因是该库隐藏了将复杂的Ada类型转换为JSON
+协议库的功能。)

该库将来也将与C或C ++接口,因此主要思想是依靠基本类型。

如何同时连接到C和Java?

(我找到了一个解决方案,所以我想在下面分享详细信息;请参阅我自己的答案。 由于旧的工作场所网络浏览器存在很多 问题,因此
无法使用复选框进行操作…


问题答案:

这是我使用JNA和Ada的Interface.C软件包设法将Java与Ada库接口的方法。

dll非常简单,此处提供的Ada和Java代码至少显示了char*as in或out参数的2种用法。

可以阅读以下文档:JNA文档,此Ada
Wiki
,Ada标准文档和其他一些Ada标准文档。

注意:请注意,以下Java代码可与任何匹配的C接口声明一起使用。请参阅.h发布后的建议 文件。当然,Java控制台的结果取决于DLL的实现。

初步检查

您需要在Java项目中包含JNA.jarjar和JNA-Platform.jar。参见JNA
GitHub进行下载。

确保使用一致的Java和Ada lib体系结构:即32位或64位。否则,JNA / Java将无法加载该库。

也不要忘记使用以下VM选项-Djna.debug_load=true来查看JNA的登录控制台!

您的Java项目/ bin文件夹应包含以下内容:

  • 产生的Ada DLL(使用给定的代码,它将是libadalib.dll
  • 你的 libgnat-version.dll
  • 你的 libgcc_s_seh-1.dll

首先,Ada部分:

请注意,您可能需要在自己的DLL DLL附近放置一些gnat DLL。我目前尚未将所有内容打包到自己的DLL中。

因此,您 可能 需要在产生的dll的同一文件夹(即Java项目的/bin目录)中包含以下文件:

  • 您的libgnat-version.dll
  • 您的libgcc_s_seh-1.dll

如果需要解决此问题,请使用DependancyWalker。(请参阅http://www.dependencywalker.com/)

有一个GPR选项可以激活/停用自动DLL详细说明,但我尚未对其进行测试。

Ada码

Ada库项目:

project adalib is
    for Languages use ("Ada");
    for Source_Dirs use (project'Project_Dir & "./src");
    for Library_Kind use "dynamic"; -- for DLL
    for Library_Name use project'Name; -- will produce "libadalib.dll"
    for Library_Interface use ("ada_interface");
    for Library_Dir use project'Project_Dir & "./dll";
    for Library_Src_Dir use project'Project_Dir & "./dll";
    -- include other DLL / .a here if needed
    -- for Library_Options use ("-L" & path_to_lib,
    --                          "-l" & path_to_lib  
    --                         );
    -- define your favorite compiler, builder, binder, linker options
end adalib;

./src ada文件

ada_interface.ads

pragma Ada_2012;

with Interfaces.C;
with Interfaces.C.Strings;


package ada_interface is

    procedure myService (
                         inBuffer       : in     Interfaces.C.Strings.chars_ptr; -- as in
                         anInteger      : in     Interfaces.C.int;
                         outBuffer      : in     Interfaces.C.Strings.chars_ptr; -- as out buffer
                         outBufferSize  : in     Interfaces.C.int;               -- max out buffer size
                         usedBufferSize :    out Interfaces.C.int
                        );
    pragma Export (Convention    => C,
                   Entity        => myService,
                   External_Name => "Renamed_myService");
end ada_interface;

ada_interface.adb

pragma Ada_2012;


with Ada.Text_IO;

with Interfaces.C.Strings;

package body ada_interface is

    procedure myService (
                         inBuffer       : in     Interfaces.C.Strings.chars_ptr; -- as in
                         anInteger      : in     Interfaces.C.int;
                         outBuffer      : in     Interfaces.C.Strings.chars_ptr; -- as out buffer
                         outBufferSize  : in     Interfaces.C.int;               -- max out buffer size
                         usedBufferSize :    out Interfaces.C.int
                        )
    is
       -- if elaboration needs to be explicitly called
       procedure ada_elaboration;
       pragma import (C, ada_elaboration, "adalibinit"); -- "<name of lib>init". May not be needed with proper options in GPR

       Required_Length : Natural := Natural (outBufferSize);
       myString : String := "This is a sample string";
       use type Interfaces.C.size_t;
    begin

       ada_elaboration;

       --
       Ada.Text_IO.Put_Line ("======= inside myService");

       -- print the string given by char*
       Ada.Text_IO.Put_Line (Interfaces.C.Strings.Value (inBuffer));
       -- the int
       Ada.Text_IO.Put_Line (Natural'Image (Natural (anInteger)));

       -- current value of the char* to be used as OUT buffer
       Ada.Text_IO.Put_Line (Interfaces.C.Strings.Value (outBuffer));

       -- use the char* to be used as out
       Interfaces.C.Strings.Update
         (Item   => outBuffer,
          Offset => 0,
          Str    => myString & Interfaces.C.To_Ada (Interfaces.C.nul), -- "& Interfaces.C.To_Ada(Interfaces.C.nul)" is equivalent to "& Character'Val(0)"
          Check  => false);

       usedBufferSize := Interfaces.C.int (Interfaces.C.Strings.Strlen (outBuffer) - 1); -- see later java code and traces

    end myService;

end ada_interface;

现在的Java代码:

用于将服务加载和映射到库的类:

package tst;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;

public class Ada_Lib {

    public interface My_Ada_Lib extends Library {

        My_Ada_Lib instance = (My_Ada_Lib) Native.loadLibrary("libadalib", My_Ada_Lib.class);
        My_Ada_Lib synchronizedInstance = (My_Ada_Lib) Native.synchronizedLibrary(instance);

    void Renamed_myService (
                        Pointer inBuffer,
                        int anInteger,
                        byte[] outBuffer,
                        int outBufferSize,
                        IntByReference usedBufferSize
                       );
    }
}

类调用库

package tst;

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;

import tst.Ada_Lib.My_Ada_Lib;

public class TestMyLib {

    private static My_Ada_Lib theLib = Ada_Lib.My_Ada_Lib.synchronizedInstance;

    public static void main(String[] args) {

        String lorem = "Sin autem ad adulescentiam perduxissent, dirimi tamen interdum contentione vel uxoriae condicionis vel commodi alicuius, quod idem adipisci uterque non posset. Quod si qui longius in amicitia provecti essent, tamen saepe labefactari, si in honoris contentionem incidissent; pestem enim nullam maiorem esse amicitiis quam in plerisque pecuniae cupiditatem, in optimis quibusque honoris certamen et gloriae; ex quo inimicitias maximas saepe inter amicissimos exstitisse." +
                "\n" +
                "Quanta autem vis amicitiae sit, ex hoc intellegi maxime potest, quod ex infinita societate generis humani, quam conciliavit ipsa natura, ita contracta res est et adducta in angustum ut omnis caritas aut inter duos aut inter paucos iungeretur." +
                "\n" +
                "Haec subinde Constantius audiens et quaedam referente Thalassio doctus, quem eum odisse iam conpererat lege communi, scribens ad Caesarem blandius adiumenta paulatim illi subtraxit, sollicitari se simulans ne, uti est militare otium fere tumultuosum, in eius perniciem conspiraret, solisque scholis iussit esse contentum palatinis et protectorum cum Scutariis et Gentilibus, et mandabat Domitiano, ex comite largitionum, praefecto ut cum in Syriam venerit, Gallum, quem crebro acciverat, ad Italiam properare blande hortaretur et verecunde.\n";

        // in params
        int inputInt = 25;

        Pointer p_Lorem = new Memory(lorem.length()+1); // +1 for C's \0
        p_Lorem.setString(0, lorem); // offset 0, no need to start at another offset

        // in param but to used for out buffer
        String stubOut = "Hello World ! 0123456789\0";
        int maxBufferSize = (stubOut.length());

        byte[] buffer = new byte[maxBufferSize];
        buffer = stubOut.getBytes();

        IntByReference usedBufferSize = new IntByReference(0); // any value works, since it is used as out param


        System.out.println("-------------------- Call to Lib ----------------------------");
        // call the lib !
        theLib.Renamed_myService(p_Lorem, inputInt, buffer, maxBufferSize, usedBufferSize);

        System.out.println("--------------------- Back to java --------------------------");
        System.out.println("In Java: used buffer size         = " + usedBufferSize.getValue());
        System.out.println("In Java: read outBuffer as String = " + Native.toString(buffer));
        System.out.println("In Java: read outBuffer as String with returned used buffer size = " + new String(buffer,0,usedBufferSize.getValue()));

    }

}

来自Java控制台的输出(JNA debug为true)

Looking in classpath from sun.misc.Launcher$AppClassLoader@4e0e2f2a for /com/sun/jna/win32-x86-64/jnidispatch.dll
Found library resource at jar:file:/ [...]
Looking for library 'libadalib'
Adding paths from jna.library.path: null
Trying libadalib.dll
Adding system paths: []
Trying libadalib.dll
Looking for lib- prefix
Trying liblibadalib.dll
Looking in classpath from sun.misc.Launcher$AppClassLoader@4e0e2f2a for libadalib
Found library resource at file:/<path>/TestMyLib/bin/libadalib.dll
Looking in <path>\TestMyLib\bin\libadalib.dll
Found library 'libadalib' at <path>\TestMyLib\bin\libadalib.dll
-------------------- Call to Lib ----------------------------
======= inside myService
Sin autem ad adulescentiam perduxissent, dirimi tamen interdum contentione vel uxoriae condicionis vel commodi alicuius, quod idem adipisci uterque non posset. Quod si qui longius in amicitia provecti essent, tamen saepe labefactari, si in honoris contentionem incidissent; pestem enim nullam maiorem esse amicitiis quam in plerisque pecuniae cupiditatem, in optimis quibusque honoris certamen et gloriae; ex quo inimicitias maximas saepe inter amicissimos exstitisse.
Quanta autem vis amicitiae sit, ex hoc intellegi maxime potest, quod ex infinita societate generis humani, quam conciliavit ipsa natura, ita contracta res est et adducta in angustum ut omnis caritas aut inter duos aut inter paucos iungeretur.
Haec subinde Constantius audiens et quaedam referente Thalassio doctus, quem eum odisse iam conpererat lege communi, scribens ad Caesarem blandius adiumenta paulatim illi subtraxit, sollicitari se simulans ne, uti est militare otium fere tumultuosum, in eius perniciem conspiraret, solisque scholis iussit esse contentum palatinis et protectorum cum Scutariis et Gentilibus, et mandabat Domitiano, ex comite largitionum, praefecto ut cum in Syriam venerit, Gallum, quem crebro acciverat, ad Italiam properare blande hortaretur et verecunde.

 25
Hello World ! 0123456789
--------------------- Back to java --------------------------
In Java: used buffer size         = 22
In Java: read outBuffer as String = This is a sample string // reads the full buffer
In Java: read outBuffer as String with returned used buffer size = This is a sample strin // reads a length of 22 (so the 'g' is missing)

现在,也可以使用匹配的.h文件轻松将Ada库与C或C ++接口:

void myService (char* inBuffer,  // as in string
                int   anInteger, // as in param
                char* outBuffer, // used as out buffer, but initalized by calling code
                int   outBufferSize, // the initaliaed size
                int   usedBufferSize // used as out param, the actually used size
);

从Eclipse调用时如何调试lib?

使用Gnat Pro
Studio(GPS),您可以进入调试器视图,并将gdb附加到Java应用程序进程的PID(对于Windows)。但是,如果没有以下技巧,您将无法设置断点。

诀窍是在DLL中有一个无限循环(出于开发目的)。

身体:

while flag loop
    null;
end loop;

广告文件:

flag : boolean := true; -- in private part

一旦gdb设法附加到正在运行的DLL代码(无限循环),gdb就会崩溃。

在循环中放置一个断点,然后在gdb中输入类型c。它将在您的循环中中断。

在代码中的其他地方放置另一个断点,然后键入follwong set flag := false,然后输入c

现在,gdb应该继续到下一个断点。

(或使用“ n”(下一条)gdb指令自行调试。)



 类似资料:
  • Ada Util 是 Ada 2005 的一组工具包,很多包的灵感来自 Java ,提供了日志框架、序列化和反序列化框架(XML\JSON\CSV),流框架(raw,files,buffers,pipes,sockets),很多并发工具以及一个 REST 客户端框架等。

  • Zip-Ada 是一个 Ada 语言用来处理 .zip 压缩文档的库。

  • Ada EL 是实现一个表达式语言的库,类似 JSP 和 JSF 这种同一表达语言(Expression Languages——EL)。这个表达语言基于 Java Server Faces 和 Ada Server Faces 来做必要的 XML/HTML 演示页面之间的绑定。此应用抽象接近javax.el类,语法通过 JSR 245(http://jcp.org/en/jsr/summary?i

  • 学过程序开发的人可能听说过ada语言,她是美国国防部开发的面向对象的高级编程语言,取名ada是为了纪念世界上第一位程序员--诗人拜伦的女 儿。 GNU Ada是少有的windows下的一个ada编译器,是自由软件,支持ada83/ada95标准。

  • Ada Server Faces 是个框架,允许用户使用相同的设计模式(Java Server Faces ——JSR 252, JSR 314 或 JSR 344)来创建 Web 应用。

  • Interval arithmetic for Ada 提供实现 Ada 间隔的功能,包括算术和关系操作。