Fi Ras Fi Ras - 1 year ago 93
Java Question

Using JNI to call functions defined within a given DLL file

My objective was to use JNI to access functions from kernel32.dll. As you can see below, I was doing pretty bad. I wrote down the whole procedure in the answer.

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.");
}

}


OUTPUT :

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)


This the syntax for EnumProcesses :

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


If PSAPI_VERSION is 2 or greater, this function is defined as K32EnumProcesses in Psapi.h and exported in Kernel32.lib and Kernel32.dll. If PSAPI_VERSION is 1, this function is defined as EnumProcesses in Psapi.h and exported in Psapi.lib and Psapi.dll as a wrapper that calls K32EnumProcesses. Source : msnd.microsoft.com

I tried with both K32EnumProcesses and EnumProcesses. Same results.

Answer Source

Creating a 64 bits Dynamic-Link Library for Windows

Prerequisites: Visual Studio

1/ Create a Visual Studio C++ project (ex: dllexample)

• Select “Win32 Consol Application”

  • Select “DLL”
  • Select “Empty project”

2/ In “Solution explorer” right-click on “Header Files” > “Add” > “New Item…” > choose a name (ex: dllexample.h) > “Add”

• Define the headers of your functions in “dllexample.h” this way:

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

3/ In “Solution explorer” right-click on “Source Files” > “Add” > “New Item…” > choose a name (ex: dllexample.cpp) > “Add”

• Use:

#include “dllexample.h”

• Define the body of your functions (from the “dllexample.h” header file) in the “dllexample.cpp” source file:

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

• In the upper toolbar select “x64”

• Select “Build” > “Build Solution”

4/ Done

• You can find “dllexample.dll” and “dllexample.lib” in “projects/dllexample/x64/Debug”

• You can find “dllexample.h” in “projects/dllexample/dllexample”  

Calling a 64 bits DLL file (ex: dllexample.dll) from another 64 bits DLL or executable file on Windows

Prerequisites: “dllexample.dll”, “dllexample.lib” and “dllexample.h” or a precise functions description or guide and Visual Studio

1/ Create a Visual Studio C++ project (ex: dllcall)

• Select “Win32 Consol Application”

  • Select “DLL” to create a DLL file, “Consol Application” to create an executable file
  • Select “Empty project”

2/ Copy “dllexample.dll”, “dllexample.lib” and “dllexample.h” to “projects/dllcall/dllcall”

3/ In “Solution explorer” right-click on “Header Files” > “Add” > “Existing Item…” > select ”dllexample.h” > “Add”

• If you’re making a DLL file, create a new header file (ex: dllcall.h) in which you define the headers of your functions this way:

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

4/ In “Solution explorer” right-click on “Source Files” > “Add” > “New Item…” > choose a name (ex: dllcall.cpp) > “Add”

• Use:

#include “dllexample.h”

• If you’re creating a DLL file, use:

#include “dllcall.h”

And then define the body of the functions (from the “dllcall.h” header file) in the “dllcall.cpp” source file. At the same time you can call functions from “dllexample.h”:

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

• In the upper toolbar select “x64”

• In “Solution explorer”, right-click on “dllcall” > “Properties” > “Linker” > “Input” > “Additional Dependencies” > “Edit” > add “dllexample.lib” (this option will be set only for the x64 debugger of the current Visual Studio project)

• Select “Build” > “Build Solution” to generate the DLL and the Import Library (.lib) files, “Run” to generate the executable file and test it

5/ Done

• You can find “dllcall.dll” and “dllcall.lib” or “dllcall.exe” in “projects/dllcall/x64/Debug”

• You can find “dllcall.h” in “projects/dllcall/dllcall”

Calling a 64 bits DLL file (ex: dllexample.dll) from a 64 bits Java program through JNI

Prerequisites: “dllexample.dll”, “dllexample.lib” and “dllexample.h” or a precise functions description or guide. Visual Studio, Eclipse with JNI plugin

1/ Create an Eclipse Java project (ex: dlltest)

2/ Create a class (ex: my.package.JNIClass)

• Define methods headers as close as the functions definitions in “dllexample.h” using keywords:

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

• Run the project to generate “JNIClass.class”

3/ Open Command Line in folder “workspace/dllcall/src”

• Generate “my_package_JNIClass.h” header file by running command:

javah my.package.JNIClass

4/ Create a 64 bits DLL file (ex: dllcall.dll) that calls “dllexample.dll” and includes “my_package_JNIClass.h”

• In the “dllcall.cpp” source file, define the bodies of functions that are defined in the “my_package_JNIClass.h” header file

• “my_package_JNIClass.h” includes “jni.h”, to make it work, you must go to “Solution explorer” in Visual Studio and right-click on “Properties” > “Configuration Properties” > “C/C++” > “General” > “Additional Include Directories” > add the 64 bits “java/include” and “java/include/win32” paths (this option will be set only for the x64 debugger of the current Visual Studio project)

5/ Copy “dllcall.dll” and “dllexample.dll” to “workspace/dllcall/src”

• In “Package explorer”, right-click on “dlltest” > “Properties” > “Java Build Path” > “Source” > expand “my/package/src” > select “Native Library Location” > “Edit” > add “my/package/src” as location path

• Import the DLL files in “JNIClass.java” using:

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

6/ If the 64 bits JRE is not selected, then go to “Run” > “Run Configurations” > “JRE” > “Alternate JREs” > “Installed JREs” > put the 64 bits Java JDK directory (Should be something like: “C:\Program Files\Java \jdk”, while 32 bits Java JDK can be found in the “Program Files (x86)” folder

7/ Done

• Now you can use the methods you defined in step 2

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download