I created a C++ class that is supposed to call Main.main by following: http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html#wp9502.
I didn't get it to work so I followed: http://www.coderanch.com/t/525082/CPP/create-JVM-native-code-call
and :
imp_JNI_Crea">http://www.codeproject.com/Questions/263687/Linker-error-undefined-reference-to-imp_JNI_Crea
None of which worked. So I changed my code back to what the Invocation API article by oracle says (the first link).
My C++ code looks like:
In JNI.hpp file:
#include <jni.h>
#include <windows.h>
#include <iostream>
class Jvm
{
private:
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs jvm_args;
JavaVMOption* options;
public:
Jvm();
};
In JNI.cpp file:
Jvm::Jvm()
{
options = new JavaVMOption[3];
options[0].optionString = "-Djava.compiler=NONE";
options[1].optionString = "-Djava.class.path=C:/Users/Brandon/Documents/NetBeansProjects/Loader/build/classes";
options[2].optionString = "-verbose:class";
jvm_args.version = JNI_VERSION_1_6;
jvm_args.nOptions = 3;
jvm_args.options = options;
jvm_args.ignoreUnrecognized = false;
//JNI_GetDefaultJavaVMInitArgs(&jvm_args);
JNI_CreateJavaVM(&jvm, reinterpret_cast<void**>(&env), &jvm_args);
jclass MainClass = env->FindClass("loader.Main");
//Crashes on the next line:
jmethodID MainMethod = env->GetStaticMethodID(MainClass, "main", "([Ljava/lang/String;)V");
MessageBox(NULL, "", "", 0);
Sleep(1000);
jvm->DestroyJavaVM();
delete[] options;
}
My java code looks like:
package loader;
public class Main {
public static void main(String[] args) {
//JavaProcess.exec(ClientApplet.class);
System.out.println("Hello!");
}
}
And the verbose prints:
[Loaded loader.Main from file:/C:/Users/Brandon/Documents/NetBeansProjects/Loader/build/classes/]
Process returned -1073741571 (0xC00000FD) execution time : 1.730 s
Press any key to continue.
What am I doing wrong? Why does it fail to call the method?
The JNI.dll that I loaded is from: C:\Program Files\Java\jdk1.7.0_21\jre\bin\server\jvm.dll because the latest Java 7u25 doesn't have a bin\client\jvm.dll.
I even statically linked to the jvm.lib: C:\Program Files\Java\jdk1.7.0_21\lib\jvm.lib.
jclass MainClass = env->FindClass("loader.Main");
This is wrong. You have to use slashes instead of dots when using JNI functions, just like in method signatures.
The correct code is:
jclass MainClass = env->FindClass("loader/Main");
Related
I am deploying a program and encountered error of
Caused by: java.lang.Exception: java.lang.UnsatisfiedLinkError:
com.package.JniClass.JniGeoDbReader.openGeoDb()Ljava/lang/String;
I managed to load the dll but I feel like something has caused the string to not be converted correctly and caused the error. The following is the JNI code I am currently testing to deploy on Karaf :
JNI Codes>>>JAVA and c++
JniGeoDbReader.class
package com.package.JniClass;
public final class JniGeoDbReader {
private JniGeoDbReader() { }
public static native String openGeoDb(); }
ServiceClass.class <--- This class is the simplified version
import com.package.JniClass.JniGeoDbReader;
public class ServiceClass{
public void fetchResponse(){
System.load("D:\\DLL_PATH\\com_package_jniGeoDbReader.dll");
LOGGER.info(">>>>>>>>>>>>>>>>> {}", JniGeoDbReader.openGeoDb());
}
}
com_package_JniClass_JniGeoDbReader.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_package_JniClass_JniGeoDbReader */
#ifndef _Included_com_package_JniClass_JniGeoDbReader
#define
_Included_com_package_JniClass_JniGeoDbReader_JniClass_JniGeoDbReader
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_package_JniClass_JniGeoDbReader
* Method: openGeoDb
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL
Java_com_package_JniClass_JniGeoDbReader_openGeoDb
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
dllmain.cpp <--I got this code from somewhere else
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include "com_package_JniClass_JniGeoDbReader.h"
#include <string>
using namespace std;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
JNIEXPORT jstring JNICALL
Java_com_package_JniClass_JniGeoDbReader_openGeoDb
(JNIEnv *env , jobject obj) {
string message = "Welcome to JNI";
int byteCount = message.length();
const jbyte* pNativeMessage = reinterpret_cast<const jbyte*>
(message.c_str());
jbyteArray bytes = env->NewByteArray(byteCount);
env->SetByteArrayRegion(bytes, 0, byteCount, pNativeMessage);
// find the Charset.forName method:
// javap -s java.nio.charset.Charset | egrep -A2 "forName"
jclass charsetClass = env->FindClass("java/nio/charset/Charset");
jmethodID forName = env->GetStaticMethodID(
charsetClass, "forName", "
(Ljava/lang/String;)Ljava/nio/charset/Charset;");
jstring utf8 = env->NewStringUTF("UTF-8");
jobject charset = env->CallStaticObjectMethod(charsetClass,
forName, utf8);
// find a String constructor that takes a Charset:
// javap -s java.lang.String | egrep -A2 "String\(.*charset"
jclass stringClass = env->FindClass("java/lang/String");
jmethodID ctor = env->GetMethodID(
stringClass, "<init>", "([BLjava/nio/charset/Charset;)V");
jstring jMessage = reinterpret_cast<jstring>(
env->NewObject(stringClass, ctor, bytes, charset));
return jMessage; }
I got the code in the cpp from here: Send C++ string to Java via JNI. I would like to do something similar, that is to return a string without accepting any parameters. But for some reason, it is throwing error. Please guide me in what causes this error and which part of this code I should change. Thank you.
UPDATE
Here is the full stacktrace:
at com.sun.proxy.$Proxy116.fetchCatalogue(Unknown Source)
at com.package.ArcGisDiscoveryJob$CatalogueTask.call(ArcGisDiscoveryJob.java:485)
at com.package.ArcGisDiscoveryJob$CatalogueTask.call(ArcGisDiscoveryJob.java:450)
at com.package.BaseTaskExecutor.invoke(BaseTaskExecutor.java:84)
at com.package.ArcGisDiscoveryJob.traverse(ArcGisDiscoveryJob.java:131)
at com.package.ArcGisDiscoveryJob.run(ArcGisDiscoveryJob.java:224)
at com.package.BaseScheduler$1.run(BaseScheduler.java:101)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.Exception: java.lang.UnsatisfiedLinkError: com.package.JniClass.JniGeoDbReader.openGeoDb()Ljava/lang/String;
at com.package.service.rest.impl.ArcGisClientProxy$1.call(ArcGisClientProxy.java:161)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
... 3 more
Caused by: java.lang.UnsatisfiedLinkError: com.package.JniClass.JniGeoDbReader.openGeoDb()Ljava/lang/String;
at com.package.JniClass.JniGeoDbReader.openGeoDb(Native Method)
at com.package.service.rest.impl.ServiceClass.fetchResponse(ServiceClass.java:364)
at com.package.service.rest.impl.ServiceClass.fetchCatalogue(ServiceClass.java:124)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.package.service.rest.impl.ArcGisClientProxy.callEndPoint(ArcGisClientProxy.java:241)
at com.package.service.rest.impl.ArcGisClientProxy.access$000(ArcGisClientProxy.java:32)
at com.package.service.rest.impl.ArcGisClientProxy$1.call(ArcGisClientProxy.java:155)
... 4 more
Your header file and your CPP code don't match. The header declares jclass for the second function parameter, but the implementation has jobject. JNI itself would not care because jclass is the same as jobject, but your compiler will not recognize the function, because of the different parameter declaration. Therefore it will not see the extern "C" for the function and export it with CPP name mangling, and Java will not find it.
Edit: hadn't seen #user207421's comment, and while it is important that you always regenerate the header file if something changes in your native method, it won't help in your case because your header already matches the Java code. You also have to change your implementation to match the header.
I created a C++ class that is supposed to call Main.main by following: http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html#wp9502.
I didn't get it to work so I followed: http://www.coderanch.com/t/525082/CPP/create-JVM-native-code-call
and :
imp_JNI_Crea">http://www.codeproject.com/Questions/263687/Linker-error-undefined-reference-to-imp_JNI_Crea
None of which worked. So I changed my code back to what the Invocation API article by oracle says (the first link).
My C++ code looks like:
In JNI.hpp file:
#include <jni.h>
#include <windows.h>
#include <iostream>
class Jvm
{
private:
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs jvm_args;
JavaVMOption* options;
public:
Jvm();
};
In JNI.cpp file:
Jvm::Jvm()
{
options = new JavaVMOption[3];
options[0].optionString = "-Djava.compiler=NONE";
options[1].optionString = "-Djava.class.path=C:/Users/Brandon/Documents/NetBeansProjects/Loader/build/classes";
options[2].optionString = "-verbose:class";
jvm_args.version = JNI_VERSION_1_6;
jvm_args.nOptions = 3;
jvm_args.options = options;
jvm_args.ignoreUnrecognized = false;
//JNI_GetDefaultJavaVMInitArgs(&jvm_args);
JNI_CreateJavaVM(&jvm, reinterpret_cast<void**>(&env), &jvm_args);
jclass MainClass = env->FindClass("loader.Main");
//Crashes on the next line:
jmethodID MainMethod = env->GetStaticMethodID(MainClass, "main", "([Ljava/lang/String;)V");
MessageBox(NULL, "", "", 0);
Sleep(1000);
jvm->DestroyJavaVM();
delete[] options;
}
My java code looks like:
package loader;
public class Main {
public static void main(String[] args) {
//JavaProcess.exec(ClientApplet.class);
System.out.println("Hello!");
}
}
And the verbose prints:
[Loaded loader.Main from file:/C:/Users/Brandon/Documents/NetBeansProjects/Loader/build/classes/]
Process returned -1073741571 (0xC00000FD) execution time : 1.730 s
Press any key to continue.
What am I doing wrong? Why does it fail to call the method?
The JNI.dll that I loaded is from: C:\Program Files\Java\jdk1.7.0_21\jre\bin\server\jvm.dll because the latest Java 7u25 doesn't have a bin\client\jvm.dll.
I even statically linked to the jvm.lib: C:\Program Files\Java\jdk1.7.0_21\lib\jvm.lib.
jclass MainClass = env->FindClass("loader.Main");
This is wrong. You have to use slashes instead of dots when using JNI functions, just like in method signatures.
The correct code is:
jclass MainClass = env->FindClass("loader/Main");
I am trying to make a proof of concept where in a cpp program I fetch the windows username and then call this program from a java code, using Java native interface(JNI). Now what i have so far is, a sample JNI hello world program which is able to compile and print Hello world or what what ever parameter I set up. Now in a separate cpp snippet i am able to fetch the current username and it works as well; looks as follows:
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
char acUserName[100];
DWORD nUserName = sizeof(acUserName);
if (GetUserName(acUserName, &nUserName)) {
cout << "User name is " << acUserName << "." << endl;
cin.get();
}
return 0;
}
When compiled and executed using my G++ in command prompt it prints the current username correctly.
Now i just want to combine the two programs. When I do that as follows
public class Sample1
{
public native String fetchCurrentUserName();
public static void main(String[] args)
{
System.loadLibrary("Sample1");
Sample1 sample = new Sample1();
String userName = sample.fetchCurrentUserName();
System.out.println("userName: " + userName);
}
}
This is the java part and the cpp part is as follows:
#include "Sample1.h"
#include <string.h>
#include <iostream>
#include <windows.h>
using namespace std;
JNIEXPORT jstring JNICALL Java_Sample1_fetchCurrentUserName
(JNIEnv *env, jobject obj) {
char acUserName[100];
DWORD nUserName = sizeof(acUserName);
if (GetUserName(acUserName, &nUserName)) {
cout << "User name is " << acUserName << "." << endl;
cin.get();
}
const char* userName = acUserName;
//const char* userName = "acUserName";
return env->NewStringUTF(userName);
}
void main(){}
This does not compile anymore, it says
Sample1.obj : error LNK2019: unresolved external symbol __imp_GetUserNameA referenced in function Java_Sample1_fetchCurrentUserName
Sample1.dll : fatal error LNK1120: 1 unresolved externals
I used the following command to compile the JNI code.
cl -I"C:\Program Files\Java\jdk1.8.0_131\include" -I"C:\Program Files\Java\jdk1.8.0_131\include\win32" -LD Sample1.cpp -FeSample1.dll
as per tutorial from https://www.ibm.com/developerworks/java/tutorials/j-jni/j-jni.html. Now from few other questions in stack overflow it seems somehow my program is unable to link the windows library or leader somehow. But I have no clue as to how this can be solved. Any body have any bright ideas? Please make my day! Thank you for your time :D I looked into Linking of dll file in JNI which is very relevant for my question. But not sure if the solutions are applicable to me.
Edit
error: LNK1120: 5 unresolved externals This question had similar problem and it seems to have same solution which is as suggested by Remy to link with Advapi32.lib. At least now i learned few new things like #pragma comments and the role of Advapi32 library. Many thanks!
Your code compiles fine. You are actually getting a linker error, not a compiler error.
From the error message, you can see that your C++ code is trying to call a GetUserNameA() function. GetUserName() is a preprocessor #define macro in winbase.h (which is included by windows.h) that resolves to GetUserNameA() when UNICODE is not defined:
WINADVAPI
BOOL
WINAPI
GetUserNameA (
__out_ecount_part_opt(*pcbBuffer, *pcbBuffer) LPSTR lpBuffer,
__inout LPDWORD pcbBuffer
);
WINADVAPI
BOOL
WINAPI
GetUserNameW (
__out_ecount_part_opt(*pcbBuffer, *pcbBuffer) LPWSTR lpBuffer,
__inout LPDWORD pcbBuffer
);
#ifdef UNICODE
#define GetUserName GetUserNameW
#else
#define GetUserName GetUserNameA // <-- HERE!
#endif // !UNICODE
As there is no GetUserNameA() function implemented in your C++ code, but there is at least a declaration available (from winbase.h), the compiler emits machine code that references GetUserNameA() externally (via a symbol named __imp_GetUserNameA). When the linker is then invoked after compiling is finished, the linker outputs the "unresolved" error because it is not able to find an implementation of any GetUserNameA function to satisfy that reference.
GetUserNameA() is a Win32 API function implemented in Advapi32.dll. You need to link to Advapi32.lib from your compiler's Windows SDK so the linker can find the implementation of GetUserNameA().
One way to do that is to add a #pragma comment(lib) statement to your C++ code, eg:
#include "Sample1.h"
#include <windows.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "Advapi32.lib") // <-- add this!
JNIEXPORT jstring JNICALL Java_Sample1_fetchCurrentUserName(JNIEnv *env, jobject obj) {
char acUserName[100] = {};
DWORD nUserName = sizeof(acUserName);
if (GetUserNameA(acUserName, &nUserName)) {
cout << "User name is " << acUserName << "." << endl;
}
else {
DWORD dwErr = GetLastError();
cout << "Unable to get User name, error " << dwErr << "." << endl;
}
return env->NewStringUTF(acUserName);
}
void main() {}
Alternatively:
#include "Sample1.h"
#include <windows.h>
#include <iostream>
#include <vector>
using namespace std;
#pragma comment(lib, "Advapi32.lib")
JNIEXPORT jstring JNICALL Java_Sample1_fetchCurrentUserName(JNIEnv *env, jobject obj) {
DWORD nUserName = 100, dwErr;
std::vector<char> acUserName(nUserName);
do {
if (GetUserNameA(&acUserName[0], &nUserName)) {
cout << "User name is " << &acUserName[0] << "." << endl;
break;
}
dwErr = GetLastError();
if (dwErr != ERROR_INSUFFICIENT_BUFFER) {
cout << "Unable to get the User name, error " << dwErr << "." << endl;
break;
}
acUserName.resize(nUserName);
}
while (true);
return env->NewStringUTF(&acUserName[0]);
}
void main() {}
That being said, NewStringUTF() requires an input string in modified UTF-8 format. However, GetUserNameA() outputs ANSI format (hence the A in its name), not in UTF-8, let alone modified UTF-8. Windows has no concept of modified UTF-8 at all. Your code will work correctly only if the username does not contain any non-ASCII characters in it.
Your C++ code really should be calling GetUserNameW() instead, which outputs in UTF-16 format. Then you can use NewString() instead of NewStringUTF() (Java strings use UTF-16 anyway), eg:
#include "Sample1.h"
#include <windows.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "Advapi32.lib")
JNIEXPORT jstring JNICALL Java_Sample1_fetchCurrentUserName(JNIEnv *env, jobject obj) {
WCHAR acUserName[100];
DWORD nUserName = 100;
if (GetUserNameW(acUserName, &nUserName)) {
--nUserName; // ignore the null terminator
wcout << L"User name is " << acUserName << L"." << endl;
}
else
{
nUserName = 0;
DWORD dwErr = GetLastError();
cout << "Unable to get the User name, error " << dwErr << "." << endl;
}
return env->NewString(reinterpret_cast<jchar*>(acUserName), nUserName);
}
void main() {}
Alternatively:
#include "Sample1.h"
#include <windows.h>
#include <iostream>
#include <vector>
using namespace std;
#pragma comment(lib, "Advapi32.lib")
JNIEXPORT jstring JNICALL Java_Sample1_fetchCurrentUserName(JNIEnv *env, jobject obj) {
DWORD nUserName = 100, dwErr;
std::vector<WCHAR> acUserName(nUserName);
do {
if (GetUserNameW(&acUserName[0], &nUserName)) {
--nUserName; // ignore the null terminator
wcout << L"User name is " << &acUserName[0] << L"." << endl;
break;
}
dwErr = GetLastError();
if (dwErr != ERROR_INSUFFICIENT_BUFFER) {
nUserName = 0;
cout << "Unable to get the User name, error " << dwErr << "." << endl;
break;
}
acUserName.resize(nUserName);
}
while (true);
return env->NewString(reinterpret_cast<jchar*>(&acUserName[0]), nUserName);
}
void main() {}
If I put my java files in a package (like jni/test/), I get a fatal error when executing. But if I dont put the files in a package everything work fine.
When having a package:
javac jni/test/Main.java
javah -jni jni.test.Main
g++ -shared -o libfoo.so -I/usr/lib/jvm/java-7-openjdk-i386/include -I/usr/lib/jvm/java-7-openjdk-i386/include/linux Main.cpp
java -Djava.library.path=. jni/test/Main
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0xb6c1ce3c, pid=3704, tid=3060386624
#
# JRE version: 7.0_25-b30
# Java VM: OpenJDK Server VM (23.7-b01 mixed mode linux-x86 )
# Problematic frame:
# V [libjvm.so+0x436e3c] get_method_id(JNIEnv_*, _jclass*, char const*, char const*, bool, Thread*) [clone .isra.106]+0x7c
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/idle/workspace/JNITest/src/hs_err_pid3704.log
#
# If you would like to submit a bug report, please include
# instructions on how to reproduce the bug and visit:
# https://bugs.launchpad.net/ubuntu/+source/openjdk-7/
#
Aborted
When not having a package:
javac Main.java
javah -jni Main
g++ -shared -o libfoo.so -I/usr/lib/jvm/java-7-openjdk-i386/include -I/usr/lib/jvm/java-7-openjdk-i386/include/linux Main.cpp
java -Djava.library.path=. Main
//This executes fine
I have 2 java classes
public class Animal {
public String name = null;
public int age = 0;
}
public class Main {
public native Animal nativeFoo();
static {
System.loadLibrary("foo");
}
public void print () {
Animal a = nativeFoo();
System.out.println(a.name + " " + a.age);
}
public static void main(String[] args) {
(new Main()).print();
}
}
The c++ part
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Main */
#ifndef _Included_Main
#define _Included_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Main
* Method: nativeFoo
* Signature: ()LAnimal;
*/
//if the java file in a package
//JNIEXPORT jobject JNICALL Java_jni_test_Main_nativeFoo (JNIEnv *env, jobject obxj)
JNIEXPORT jobject JNICALL Java_Main_nativeFoo
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
The cpp file
#include "Main.h"
//if the java file in a package
//JNIEXPORT jobject JNICALL Java_jni_test_Main_nativeFoo (JNIEnv *env, jobject obxj)
JNIEXPORT jobject JNICALL Java_Main_nativeFoo (JNIEnv *env, jobject obxj){
jclass animal = env->FindClass("Animal");
jmethodID cons = env->GetMethodID(animal, "<init>", "()V");
jobject obj = env->NewObject(animal, cons);
jfieldID age = env->GetFieldID(animal, "age", "I");
jfieldID name = env->GetFieldID(animal, "name", "Ljava/lang/String;");
env->SetObjectField(obj, name, env->NewStringUTF("awww"));
env->SetIntField(obj, age, 23);
return obj;
}
Based on the error, which is when get_method_id(JNIEnv_*, _jclass*, char const*, char const*, bool, Thread*) is called via env->GetMethodID(), your jclass variable animal is null.
The FindClass call is failing because it cannot locate the class "Animal".
Validate that your class name and package definition is correct.
See similar question answered here with the same sigsegv
I used to have some privilege issues when calling ExitWindowsEX Windows API function.
So I wrote the following code to get the privilege:
This works fine in C++
#include <cstdlib>
#include <windows.h>
#include <iostream>
using namespace std;
/*
*
*/
int MyExitWindows(int flag, int reason);
int main(int argc, char** argv) {
MyExitWindows(EWX_SHUTDOWN, 0);
}
int MyExitWindows(int flag, int reason) {
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
// Get a token for this process.
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return GetLastError();
// Get the LUID for the shutdown privilege.
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get the shutdown privilege for this process.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
// Cannot test the return value of AdjustTokenPrivileges.
ExitWindowsEx(flag, reason);
if (GetLastError() != ERROR_SUCCESS) {
return GetLastError();
}
return 0;
}
But this doesn't work when I call it from Java
#include <jni.h>
#include <cstdlib>
#include <windows.h>
#include "com_ehsunbehravesh_jshutdown_system_Shutdowner.h"
using namespace std;
int MyExitWindows(int flag, int reason);
JNIEXPORT jint JNICALL Java_com_ehsunbehravesh_jshutdown_system_Shutdowner_exitWindowsEx
(JNIEnv *env, jobject obj, jlong flag, jlong reason) {
return MyExitWindows(flag, reason);
}
int MyExitWindows(int flag, int reason) {
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
// Get a token for this process.
int cpid = GetCurrentProcessId();
printf("%d", cpid);
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
return GetLastError();
// Get the LUID for the shutdown privilege.
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Get the shutdown privilege for this process.
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
// Cannot test the return value of AdjustTokenPrivileges.
ExitWindowsEx(flag, reason);
if (GetLastError() != ERROR_SUCCESS) {
return GetLastError();
}
return 0;
}
Is there any reason you are not using System.exit(int)?
Java attempts to control the shutdown of an application, perhaps it tries to prevent you doing it other ways.