fetching windows current user with java native interfaces - java

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() {}

Related

SIGABRT error when returning from C++ code from java module in android

Still new to android and java but learning more each day :)
This question refers to
Ok, the error refers to
expression failed to parse:
error: <user expression 27>:1:1: 'bl' has unknown type; cast it to its declared type to use it
bl
^~
and
expression failed to parse:
error: <user expression 28>:1:1: 'uxtb' has unknown type; cast it to its declared type to use it
uxtb.w
^~~~
I call (will want a short ) result = getCheckSum(A, B); from my java code.
The method in my C++ code is
//---------------------------------------------------------------------------
unsigned short ekmCheckCRC16(const unsigned char *dat, unsigned short len)
{
unsigned short crc = 0xffff;
while (len--)
{
crc = (crc >> 8 ) ^ ekmCrcLut[(crc ^ *dat++) & 0xff];
}
crc = (crc << 8 ) | (crc >> 8);
crc &= 0x7f7f;
return crc;
}
//---------------------------------------------------------------------------
// Implementation of the native method getCheckSum()
extern "C"
JNIEXPORT unsigned short JNICALL
Java_com_(...)_getCheckSum(JNIEnv *env, jobject thiz, jstring a) {
const char * aCStr = env->GetStringUTFChars(a, NULL);
if(NULL == aCStr)
return NULL;
unsigned short crc = ekmCheckCRC16(reinterpret_cast<const unsigned char *>(aCStr), strlen(aCStr));
return crc;
}
This code is experimental showing the actual code I want to run ekmCheckCRC16( ... ), its purpose is to learn how to return a value back to the java module.
The error message seems to be clear 'unknown' type cast, so question is, how should I be returning the value of aCStr?
Thanks in advance.
Solved my problem, was simple error of not changing one important detail before executing call i was looking for a return type of short but had String in native declaration.
I had
private native String getCheckSum(String a);
it should have been
`private native short getCheckSum(String a);`
My call was / is
short result = getCheckSum(A);
Worked fine after correcting my mistake.
for those interested my c++ code
#include <jni.h> // JNI header provided by JDK
#include "ekmCheckSum.h"
#include <iostream> // C++ standard IO header
using namespace std;
//---------------------------------------------------------------------------
void ekmCheckSum() {
}
static const unsigned short ekmCrcLut[256] = {
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
};
//---------------------------------------------------------------------------
unsigned short ekmCheckCRC16(const unsigned char *dat, unsigned short len)
{
unsigned short crc = 0xffff;
while (len--)
{
crc = (crc >> 8 ) ^ ekmCrcLut[(crc ^ *dat++) & 0xff];
}
crc = (crc << 8 ) | (crc >> 8);
crc &= 0x7f7f;
return crc;
}
//---------------------------------------------------------------------------
// Implementation of the native method getCheckSum()
extern "C"
JNIEXPORT unsigned short JNICALL
Java_com_[project name]_ekmV4Fields_getCheckSum(JNIEnv *env, jobject thiz, jstring a) {
const char * aCStr = env->GetStringUTFChars(a, NULL);
if(NULL == aCStr)
return NULL;
unsigned short crc = ekmCheckCRC16(reinterpret_cast<const unsigned char *>(aCStr), strlen(aCStr));
return crc;
}
my .h file contains
#ifndef PROJECT_NAME_EKMCHECKSUM_H
#define PROJECT_NAME_EKMCHECKSUM_H
class ekmCheckSum
{
private:
public:
ekmCheckSum();
unsigned short ekmCheckCRC16(const unsigned char *dat, unsigned short len);
};
#endif //PROJECT_NAME_EKMCHECKSUM_H
my java file includes
static {System.loadLibrary("ekmCheckSum");}
private native short getCheckSum(String a);
public void SetEkmFieldValueStrings(String A, String B)
{
/* if length of A is less than 250 chars, read is no good, discard
* NOTE: both Strings A and B will need to be validated for checksum
* TODO check A & B if checksum is correct
* */
boolean _aOk = false, _bOk=false;
short result = getCheckSum(A);
...
...

JNI code to return string but gets error java.lang.UnsatisfiedLinkError: com.package.openGeoDb()Ljava/lang/String;

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.

ndk-build errors, string format, clang no such file or directory

I've tried creating a simple jni test app from "Beginning Android Games 3rd Ed" book. I copy-pasted the code, but when I try to link with ndk-build, I get the following error messages:
D:\apps\android\projects\NDK\app\src\main\java>ndk-build
[armeabi-v7a] Compile++ arm : jniutils <= jniutils.cpp
jni/jniutils.cpp:8:52: error: format string is not a string literal (potentially insecure)
[-Werror,-Wformat-security]
__android_log_print(ANDROID_LOG_VERBOSE, cTag, cMessage);
^~~~~~~~
jni/jniutils.cpp:8:52: note: treat the string as an argument to avoid this
__android_log_print(ANDROID_LOG_VERBOSE, cTag, cMessage);
^
"%s",
1 error generated.
make: *** [obj/local/armeabi-v7a/objs/jniutils/jniutils.o] Error 1
If I try to treat these errors as warnings and suppress these with the following lines in android.mk / application.mk:
APP_CFLAGS += -Wno-error=format-security
LOCAL_DISABLE_FORMAT_STRING_CHECKS := true
Then I get this error:
D:\apps\android\projects\NDK\app\src\main\java>ndk-build
[armeabi-v7a] SharedLibrary : libjniutils.so
clang++.exe: error: no such file or directory: '遶上・llog'
make: *** [obj/local/armeabi-v7a/libjniutils.so] Error 1
Which I guess is just some garbage from memory, like a string /variable hasn't been addressed correctly.
I'm very new to jni, so I'm at a bit of a loss of how to troubleshoot this.
Code follows:
JniUtils.java
package com.badlogic.androidgames.ndk;
import java.nio.ByteBuffer;
public class JniUtils {
static {
System.loadLibrary("jniutils");
}
public static native void log(String tag, String message);
public static native void copy(ByteBuffer dst, float[] src, int offset, int len);
}
jniutils.cpp
#include <android/log.h>
#include <string.h>
#include "jniutils.h"
JNIEXPORT void JNICALL Java_com_badlogic_androidgames_ndk_JniUtils_log
(JNIEnv *env, jclass clazz, jstring tag, jstring message) {
const char *cTag = env-> GetStringUTFChars(tag, 0);
const char *cMessage = env-> GetStringUTFChars(message, 0);
__android_log_print(ANDROID_LOG_VERBOSE, cTag, cMessage);
env-> ReleaseStringUTFChars(tag, cTag);
env-> ReleaseStringUTFChars(message, cMessage);
}
JNIEXPORT void JNICALL Java_com_badlogic_androidgames_ndk_JniUtils_copy
(JNIEnv *env, jclass clazz, jobject dst, jfloatArray src, jint offset, jint len) {
unsigned char* pDst = (unsigned char*)env-> GetDirectBufferAddress(dst);
float* pSrc = (float*)env-> GetPrimitiveArrayCritical(src, 0); memcpy(pDst,
pSrc + offset, len * 4);
env-> ReleasePrimitiveArrayCritical(src, pSrc, 0);
}
application.mk
APP_ABI := armeabi-v7a x86
APP_PLATFORM := android-19
android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := jniutils
LOCAL_LDLIBS := − llog
LOCAL_ARM_MODE := arm
LOCAL_SRC_FILES := jniutils.cpp
include $(BUILD_SHARED_LIBRARY)

JNI - WMI connection error

I have a java Web application to collect some data from local and remote windows machine. I am using wmi connection to connect to machine.
I use tomcat as Web server. For wmi connection i wrote c++ code and connect java and c++ using JNI. When i start the server and enter login details, tomcat crashes.
In log file error is..
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffd1e6e2931, pid=3940, tid=0x0000000000000a6c
#
# JRE version: Java(TM) SE Runtime Environment (8.0_162-b12) (build 1.8.0_162-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.162-b12 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C [Verify_.dll+0x2931]
#
I am using tomcat 8.5.28 and jdk1.8.0_162
Here is my java code: Verify_.java
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class Verify_ extends HttpServlet{
public native int connect();
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
System.loadLibrary("Verify_");
Verify_ verify = new Verify_();
response.setContentType("text/html");
PrintWriter out = response.getWriter();
String ServerName = request.getParameter("servername");
String UserName = request.getParameter("username");
String Password = request.getParameter("password");
int status = verify.connect();
if(status == 0)
out.println("Connected to " + ServerName);
else if(status == 1)
out.println("failed to initialize CoInitializeEx");
else if(status == 2)
out.println("failed to initialize CoInitializeSecurity");
else if(status == 3)
out.println("failed to initialize CoCreateInstance");
else if(status == 4)
out.println("failed to connect to Server");
else
out.println(status);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
doGet(request,response);
}}
Here is JNI interface code: Verify_.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Verify_ */
#ifndef _Included_Verify_
#define _Included_Verify_
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Verify_
* Method: connect
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_Verify_1_connect
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Here is C++ code: Verify_.cpp
#include <iostream>
#include <wbemidl.h>
#include <conio.h>
#include <windows.h>
#include <comdef.h>
#include <wincred.h>
#include <string.h>
#include "Verify_.h"
#pragma comment(lib, "credui.lib")
#pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "advapi32.lib")
#pragma comment(lib, "Ole32.lib")
#define _WIN32_DCOM
JNIEXPORT jint JNICALL Java_Verify_1_connect (JNIEnv *, jobject){
BSTR pszRoot,pszUserName,pszPassword;
wcscpy(pszRoot, BSTR(L"\\\\172.21.111.250\\ROOT\\cimv2"));
wcscpy(pszUserName, BSTR(L"Administrator"));
wcscpy(pszPassword, BSTR(L"qwerty1233"));
HRESULT hr;
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hr)) {
return 1;
}
hr = CoInitializeSecurity(
NULL, // Security descriptor
-1, // COM negotiates authentication service
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication level for proxies
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation level for proxies
NULL, // Authentication info
EOAC_NONE, // Additional capabilities of the client or server
NULL); // Reserved
if (FAILED(hr)) {
CoUninitialize();
return 2;
}
IWbemLocator *pLoc = 0;
hr = CoCreateInstance(CLSID_WbemLocator, 0,
CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hr)){
CoUninitialize();
return 3;
}
IWbemServices *pSvc = NULL;
// Connect to the root\default namespace with the current user.
hr = pLoc->ConnectServer(
pszRoot, //namespace
pszUserName, // User name
pszPassword, // User password
NULL, // Locale
NULL, // Security flags
NULL, // Authority
NULL, // Context object
&pSvc); // IWbemServices proxy
if (FAILED(hr)){
pLoc->Release();
CoUninitialize();
return 4;
}
// pSvc->Release();
// pLoc->Release();
CoUninitialize();
return 0;
}
i am trying for past 5 days. Pls help me. If there is any other way tell me..
Thanks in advance
0xc0000005
-> Access violation, mostly because using a NULL pointer.
BSTR pszRoot,pszUserName,pszPassword;
wcscpy(pszRoot, BSTR(L"\\\\172.21.111.250\\ROOT\\cimv2"));
You have to allocate memory when using wcscpy. So, the wcscopy is called with an invalid (random) address (in Debugmode: With NULL).
I'm not sure you are handling BSTR correct (I did not know BSTR). See definition of BSTR:
typedef OLECHAR *BSTR;
Why not assign directly?
pszRoot = BSTR(L"\\\\172.21.111.250\\ROOT\\cimv2");
thanks Ralph Erdt
i changed this part
BSTR pszRoot,pszUserName,pszPassword;
pszRoot = ::SysAllocString(L"\\\\172.21.111.250\\ROOT\\cimv2");
pszUserName = ::SysAllocString(L"Administrator");
pszPassword = ::SysAllocString(L"qwerty1233");

C++ code works fine but doesn't work when calling from Java (JNI)

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.

Categories

Resources