使用JNI调用给定DLL文件中定义的函数

时间:2017-07-05 12:55:13

标签: java eclipse visual-studio dll java-native-interface

我的目标是使用JNI从kernel32.dll访问函数。正如你在下面看到的,我做得非常糟糕。我在答案中记下了整个程序。

Kernel32.java

package tn.kernel;

public final class Kernel32 {
    public static boolean loadKernel32(){
        System.loadLibrary("kernel32");
        return true;
    }

    public static native boolean K32EnumProcesses(int[] pProcessIds, int cb, int[] pBytesReturned);
}

MainClass.java

package tn.kernel;

public class MainClass {

    public static void main(String[] args) {
        System.out.println("Program started.");

        if(Kernel32.loadKernel32())
            System.out.println("Kernel32.dll loaded.");

        int n = 2000;
        int[] procs = new int[n];
        int ls = Integer.SIZE;
        int[] rs = new int[1];

        if(Kernel32.K32EnumProcesses(procs, ls * n, rs)){
            System.out.println("Success");
        }

        System.out.println("Done.");
    }

}

输出:

Program started.
Kernel32.dll loaded.
Exception in thread "main" java.lang.UnsatisfiedLinkError: tn.kernel.Kernel32.K32EnumProcesses([II[I)Z
    at tn.kernel.Kernel32.K32EnumProcesses(Native Method)
    at tn.kernel.MainClass.main(MainClass.java:15)

这是EnumProcesses的语法:

BOOL WINAPI EnumProcesses(
  _Out_ DWORD *pProcessIds,
  _In_  DWORD cb,
  _Out_ DWORD *pBytesReturned
);

如果PSAPI_VERSION为2或更大,则此函数在Psapi.h中定义为 K32EnumProcesses ,并在Kernel32.lib和Kernel32.dll中导出。如果PSAPI_VERSION为1,则此函数在Psapi.h中定义为 EnumProcesses ,并在Psapi.lib和Psapi.dll中导出为调用 K32EnumProcesses 的包装器。资料来源: msnd.microsoft.com

我尝试了K32EnumProcesses和EnumProcesses。相同的结果。

1 个答案:

答案 0 :(得分:0)

为Windows创建64位动态链接库

先决条件:Visual Studio

1 /创建Visual Studio C ++项目(例如:dllexample)

•选择“Win32 Consol Application”

  • 选择“DLL”
  • 选择“清空项目”

2 /在“解决方案资源管理器”中右键单击“头文件”> “添加”> “New Item ...”>选择一个名字(例如:dllexample.h)> “添加”

•以这种方式在“dllexample.h”中定义函数的标题:

__declspec(dllexport) <type> funcName(parameters…);
…

3 /在“解决方案资源管理器”中右键单击“源文件”&gt; “添加”&gt; “New Item ...”&gt;选择一个名字(例如:dllexample.cpp)&gt; “添加”

•使用:

#include “dllexample.h”

•在“dllexample.cpp”源文件中定义函数体(来自“dllexample.h”头文件):

<type> funcName(parameters…){
    //body instructions
}

•在上方工具栏中选择“x64”

•选择“构建”&gt; “构建解决方案”

4 /完成

•您可以在“projects / dllexample / x64 / Debug”中找到“dllexample.dll”和“dllexample.lib”

•您可以在“projects / dllexample / dllexample”中找到“dllexample.h”

从Windows上的另一个64位DLL或可执行文件调用64位DLL文件(例如:dllexample.dll)

先决条件:“dllexample.dll”,“dllexample.lib”和“dllexample.h”或精确的函数说明或指南以及Visual Studio

1 /创建Visual Studio C ++项目(例如:dllcall)

•选择“Win32 Consol Application”

  • 选择“DLL”创建DLL文件,“Consol Application”创建可执行文件
  • 选择“清空项目”

2 /将“dllexample.dll”,“dllexample.lib”和“dllexample.h”复制到“projects / dllcall / dllcall”

3 /在“解决方案资源管理器”中右键单击“头文件”&gt; “添加”&gt; “现有项目......”&gt;选择“dllexample.h”&gt; “添加”

•如果您正在制作DLL文件,请创建一个新的头文件(例如:dllcall.h),您可以通过这种方式定义函数的标题:

__declspec(dllexport) <type> funcName(parameters…);
…

4 /在“解决方案资源管理器”中右键单击“源文件”&gt; “添加”&gt; “New Item ...”&gt;选择一个名字(例如:dllcall.cpp)&gt; “添加”

•使用:

#include “dllexample.h”

•如果您要创建DLL文件,请使用:

#include “dllcall.h”

然后在“dllcall.cpp”源文件中定义函数体(来自“dllcall.h”头文件)。同时,您可以从“dllexample.h”调用函数:

<type> funcName(parameters…){
    //body instructions
}

•在上方工具栏中选择“x64”

•在“解决方案资源管理器”中,右键单击“dllcall”&gt; “属性”&gt; “链接器”&gt; “输入”&gt; “附加依赖性”&gt; “编辑”&gt;添加“dllexample.lib”(此选项仅为当前Visual Studio项目的x64调试器设置)

•选择“构建”&gt; “Build Solution”生成DLL和导入库(.lib)文件,“Run”生成可执行文件并测试它

5 /完成

•您可以在“projects / dllcall / x64 / Debug”中找到“dllcall.dll”和“dllcall.lib”或“dllcall.exe”

•您可以在“projects / dllcall / dllcall”中找到“dllcall.h”

通过JNI从64位Java程序调用64位DLL文件(例如:dllexample.dll)

先决条件:“dllexample.dll”,“dllexample.lib”和“dllexample.h”或精确的功能说明或指南。 Visual Studio,带有JNI插件的Eclipse

1 /创建Eclipse Java项目(例如:dlltest)

2 /创建一个类(例如:my.package.JNIClass)

•使用关键字将方法标题定义为与“dllexample.h”中的函数定义一样接近:

public static final native <type> funcName(parameters..);
…

•运行项目以生成“JNIClass.class”

3 /在“workspace / dllcall / src”文件夹中打开命令行

•通过运行命令生成“my_package_JNIClass.h”头文件:

javah my.package.JNIClass

4 /创建一个64位DLL文件(例如:dllcall.dll),调用“dllexample.dll”并包含“my_package_JNIClass.h”

•在“dllcall.cpp”源文件中,定义“my_package_JNIClass.h”头文件中定义的函数体

•“my_package_JNIClass.h”包含“jni.h”,为了使其正常工作,您必须转到Visual Studio中的“Solution explorer”并右键单击“Properties”&gt; “配置属性”&gt; “C / C ++”&gt; “一般”&gt; “其他包含目录”&gt;添加64位“java / include”和“java / include / win32”路径(此选项仅为当前Visual Studio项目的x64调试器设置)

5 /将“dllcall.dll”和“dllexample.dll”复制到“workspace / dllcall / src”

•在“Package explorer”中,右键单击“dlltest”&gt; “属性”&gt; “Java构建路径”&gt; “来源”&gt;展开“my / package / src”&gt;选择“本机库位置”&gt; “编辑”&gt;将“my / package / src”添加为位置路径

•使用以下命令在“JNIClass.java”中导入DLL文件:

static {
    System.loadLibrary(“dllexample”);
    System.loadLibrary(“dllcall”);
}

6 /如果未选择64位JRE,则转到“运行”&gt; “运行配置”&gt; “JRE”&gt; “替代JRE”&gt; “已安装的JRE”&gt;把64位Java JDK目录(应该是这样的:“C:\ Program Files \ Java \ jdk”,而32位Java JDK可以在“Program Files(x86)”文件夹中找到

7 /完成

•现在您可以使用在步骤2中定义的方法