使用JNA访问DLL:输出不按预期顺序

时间:2013-05-24 16:34:04

标签: java dll jna

背景优先,问题以粗体显示:

我是一名学生,在夏季研究项目中,我将编写一个Java程序,让我可以将从研究硬件收集的数据导出到Windows环境中的MATLAB中 - 我不需要将程序移植到其他平台。我有一个包含C / C ++声明的优秀API的第三方DLL,但我无法访问DLL的源代码。

我只知道Java,所以在查看可用选项之后,我决定使用JNA,因为它看起来最简单,最直接,而且,JNA目前还在维护。我问一个知道C ++的朋友为我做了一个示例DLL所以我可以从底部开始并进行“hello world”样式测试,加载库并使用JNA访问本机方法。我按照here中的例子 - 通过twall和/或technomage阅读了大约一百个对其他人问题的回答。

由于jna.library.path以 null 开头解决了一些UnsatisfiedLinkErrors,我将给出的32位示例DLL重新编译为64位,并将它们全部扔到/ bin中文件夹,我让程序确定访问哪一个,具体取决于运行的JVM。我知道我无法用我的第三方DLL(32位)做到这一点,但这只是我的概念验证阶段的一部分。

我已经能够轻松地访问DLL方法,但我看到输出 - 所有打印语句 - 以意想不到的顺序。它看起来是我的Java代码从头开始执行,然后本机库开始完成

稍后在我的项目中,我将需要调用本机函数,然后是java方法,然后再调用本机函数,所以我需要在早期了解导致这个奇数序列的原因。我一开始尝试了一种非常程序化的方法;下面是我尝试将这些方法装扮成我可以操纵的对象,这产生了相同的结果。我猜它与JVM和本机的本机端如何交互有关,或者Windows和Java处理I / O的方式不同,但我对导致它的原因或如何处理问题感到难过

我的设置如下: // CallFooPortably.java

public class CallFooPortably { //name taken from a tutorial, thanks!
    public static void main(String[] args) {
        System.out.println("MIAN START");// debug test
        System.setProperty("jna.library.path",System.getProperty("java.class.path"));
        System.out.println("MAIN Break1");// debug test
        methodOneClass objectA=new methodOneClass();
        objectA.methodOne();
        System.out.println("MAIN inter-method");// debug test
        objectA.methodTwo();
        System.out.println("MAIN END");// debug test
    }
}

我调用库的方法在这里: // methodOneClass.java

public class methodOneClass{

      public methodOneClass(){
            System.out.println("Object Created!");
      }

      public void methodOne()  {
            String temp1 = System.getProperty("sun.arch.data.model");
            //provides the JVM bit-ness to the program 

            if (temp1.equals("32")) {
                  System.out.println("Break2");// debug test
                  UserDllLInterface.CLibrary.INSTANCE.Export1();
                  System.out.println("Break3");// debug test
                  UserDllLInterface.CLibrary.INSTANCE.Export2();
                  System.out.println("Break4");// debug test

            } else if (temp1.equals("64")) {
                  System.out.println("Break5");// debug test
                  UserDllLInterface.x64_CLibrary.INSTANCE.Export1();
                  System.out.println("Break6");// debug test
                  UserDllLInterface.x64_CLibrary.INSTANCE.Export2();
                  System.out.println("Break7");// debug test
            }
      }

      public void methodTwo()  {
            String temp2 = System.getProperty("sun.arch.data.model");
            if (temp2.equals("32")) {
                  System.out.println("Break8");// debug test
                  UserDllLInterface.CLibrary.INSTANCE.Export1();
                  System.out.println("Break9");// debug test
                  UserDllLInterface.CLibrary.INSTANCE.Export2();
                  System.out.println("Break10");// debug test
            } else if (temp2.equals("64")) {
                  System.out.println("Break11");// debug test
                  UserDllLInterface.x64_CLibrary.INSTANCE.Export1();
                  System.out.println("Break12");// debug test
                  UserDllLInterface.x64_CLibrary.INSTANCE.Export2();
                  System.out.println("Break13");// debug test
            }
      }
}

最后,库接口在这里: //UserDllLInterface.java

import com.sun.jna.Library;
import com.sun.jna.Native;

public interface UserDllLInterface {
      public static interface CLibrary extends Library { //comes from twall's examples, thanks!
            CLibrary INSTANCE = (CLibrary) Native.loadLibrary("DllExample",CLibrary.class);
            void Export1();
            void Export2();
      }

      public static interface x64_CLibrary extends Library {
            x64_CLibrary INSTANCE = (x64_CLibrary) Native.loadLibrary
              ("x64_DllExample", x64_CLibrary.class);
           void Export1();
           void Export2();
      }
}

我编译成32位和64位DLL的C ++源代码: //x64_DllExample.dll //DllExample.dll

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>

bool APIENTRY DllMain(HANDLE hModule, DWORD reason, LPVOID lpReserved) {
    switch(reason) {
        case DLL_PROCESS_ATTACH:
            printf("You loaded me successfully!\n");
            break;
        case DLL_PROCESS_DETACH:
            printf("You unloaded me successfully!\n");
            break;
        case DLL_THREAD_ATTACH:
            printf("You threaded me successfully!\n");
            break;
        case DLL_THREAD_DETACH:
            printf("You un threaded me successfully!\n");
            break;
    }
    return true;
}

 extern "C" __declspec(dllexport) void Export1() {
     printf("You called the function Export1\n");
 }

extern "C" __declspec(dllexport) void Export2() {
    printf("You called the function Export2\n");
}

我希望得到这样的输出,导出函数混合在:

MIAN START
MAIN Break1
Object Created!
Break5
You loaded me successfully!
You called the function Export1
You un threaded me successfully!
Break6
You called the function Export2
You un threaded me successfully!
Break7
MAIN inter-method
Break11
You called the function Export1
You un threaded me successfully!
Break12
You called the function Export2
You un threaded me successfully!
You unloaded me successfully!
Break13
MAIN END

但相反,我得到这样的输出(首先是Java,然后是Windows):

MIAN START
MAIN Break1
Object Created!
Break5
Break6
Break7
MAIN inter-method
Break11
Break12
Break13
MAIN END
You loaded me successfully!
You called the function Export1
You called the function Export2
You called the function Export1
You called the function Export2
You un threaded me successfully!
You un threaded me successfully!
You un threaded me successfully!
You un threaded me successfully!
You unloaded me successfully!

切换到64位JVM会产生类似的结果,首先是Java代码,然后是本机库。我希望有人可以帮助阐明为什么会发生这种情况。提前感谢您提供的任何帮助!

1 个答案:

答案 0 :(得分:0)

printf已缓冲。如果您在每fflush(stdout);之后添加printf,则会按预期输出。