Click here to Skip to main content
15,887,027 members
Home / Discussions / Java
   

Java

 
AnswerRe: How to convert string to double with trailing zeros after decimal Pin
Richard MacCutchan8-Nov-23 2:07
mveRichard MacCutchan8-Nov-23 2:07 
GeneralRe: How to convert string to double with trailing zeros after decimal Pin
Member 161354338-Nov-23 2:23
Member 161354338-Nov-23 2:23 
GeneralRe: How to convert string to double with trailing zeros after decimal Pin
Richard MacCutchan8-Nov-23 2:35
mveRichard MacCutchan8-Nov-23 2:35 
GeneralRe: How to convert string to double with trailing zeros after decimal Pin
Dave Kreskowiak8-Nov-23 3:20
mveDave Kreskowiak8-Nov-23 3:20 
GeneralRe: How to convert string to double with trailing zeros after decimal Pin
jschell8-Nov-23 6:12
jschell8-Nov-23 6:12 
AnswerRe: How to convert string to double with trailing zeros after decimal Pin
Ralf Meier8-Nov-23 8:02
mveRalf Meier8-Nov-23 8:02 
AnswerRe: How to convert string to double with trailing zeros after decimal Pin
Dave Kreskowiak8-Nov-23 2:23
mveDave Kreskowiak8-Nov-23 2:23 
QuestionHow to use JNI without setting Environment Variables Pin
Valentinor16-Oct-23 0:54
Valentinor16-Oct-23 0:54 
I found the following code posted by @Richard-MacCutchan to a thread about how to use JNI without having to add the location of jvm.dll into Environment Variables. I kinda understood how it works but still...

C++
/*
 ******************************************************************************
 *
 *    Name     : cpptojava.cpp
 *
 *    Function : Basic Console application to call a Java class.
 *
 *    Created  : 09 Jun 2022
 *
 ******************************************************************************
 */

#include <Windows.h>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <filesystem> // requires -std:c++17

#include "jni.h"

//
// Find the path to the jvm.dll given the base path to the Java runtime (or JDK if installed)
//
HMODULE LoadDll(
    const char* jrePath
)
{
    const char* pszjvmname = "bin\\server\\jvm.dll";   // Java VM name
    HMODULE hJVMDLL = 0;

    std::filesystem::path jvmpath(jrePath);
    jvmpath /= pszjvmname;
    if (!std::filesystem::exists(jvmpath))
    {
        std::cerr << "JVM library " << jvmpath << " not found." << std::endl;
        // throw an exception 
    }

    // load the Java VM DLL into our address space
    // NB filesystem::path is Unicode
    hJVMDLL = LoadLibraryW(reinterpret_cast<PCWSTR>(jvmpath.c_str()));
    if (hJVMDLL != NULL)
    {
        std::clog << "jvm.dll loaded from: " << jvmpath << std::endl;
    }
    return hJVMDLL; // a Windows HANDLE to the DLL
}


//
// A function to load the Java VM and initialise the JNI interface
// There are a number of diagnostic messages to show progress
//
JNIEnv* AttachJVM(
    const char* jrePath,
    JavaVM* jvm,
    std::string strcwd
)
{
    HMODULE     hJVMDLL = LoadDll(jrePath);
    if (hJVMDLL == 0)
    {
        return nullptr;
    }
    typedef jint(JNICALL* fpCJV)(JavaVM**, void**, void*);
    fpCJV JNI_CreateJavaVM = (fpCJV)::GetProcAddress(hJVMDLL, "JNI_CreateJavaVM");

    // tell the JVM where to find the class
    JavaVMOption    options[2];
    std::stringstream ssoptions;
    ssoptions << "-Djava.class.path=";
    ssoptions << strcwd;
    std::string stropts = ssoptions.str();
    options[0].optionString = const_cast<char*>(stropts.c_str());
    options[1].optionString = const_cast<char*>("-verbose:jni");   // print JNI-related messages

    JavaVMInitArgs  vm_args; // JDK/JRE 6 VM initialization arguments
    vm_args.version = JNI_VERSION_1_8;
    vm_args.nOptions = 1; // change to 2 for verbose output
    vm_args.ignoreUnrecognized = false;
    vm_args.options = options;
    for (int i = 0; i < vm_args.nOptions; ++i)
    {
        std::clog << "Options[" << i << "]: " << options[i].optionString << std::endl;
    }
    JNIEnv* env;            // pointer to native method interface
    jint res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
    if (res != 0)
    {
        std::cerr << "C++: JNI_CreateJavaVM returned: " << res << std::endl;
    }
    jint version = env->GetVersion();
    std::clog << "JVM Version: " << (version >> 16) << "." << (version & 0xffff) << std::endl;

    return env; // the pointer to the jvm dll
}


void CallClass(
    JNIEnv* jniEnv,
    const char* pszClassname,
    const char* pszMethodname,
    const char* pszSignature
)
{
    jclass jvmclass = jniEnv->FindClass(pszClassname);
    if (jvmclass != NULL)
    {
        std::cout << "C++: Found the class: " << pszClassname << std::endl;
        jmethodID jmid = jniEnv->GetStaticMethodID(jvmclass, pszMethodname, pszSignature);
        if (jmid != NULL)
        {
            std::cout << "C++: Found the method: " << pszMethodname << std::endl;
            jniEnv->CallStaticVoidMethod(jvmclass, jmid, NULL);
            std::cout << "C++: env->CallStaticVoidMethod complete" << std::endl;
        }
        else
        {
            std::cerr << "C++: Failed to find the method: " << pszMethodname << std::endl;
        }
    }
    else
    {
        std::cerr << "C++: Failed to find the class: " << pszClassname << std::endl;
    }
}


int main(
    int argc,
    const char** argv
)
{
    const char* jreDir = nullptr;

    // suppress debug messages
    std::clog.setstate(std::ios::badbit);
    for (argv++; argc > 1; ++argv, --argc)
    {
        if (*argv[0] == '-')
        {
            // handle any execution options ...
            if (strstr(*argv, "-d"))
                std::clog.clear();
        }
        else
        {
            jreDir = *argv;
        }
    }
    if (jreDir == nullptr)
    {
        std::cerr << "No root path provided for JVM." << std::endl;
        return 1;
    }
    JNIEnv* jniEnv = NULL;
    std::filesystem::path cwd = std::filesystem::current_path();
    JavaVM jvm;
    jniEnv = AttachJVM(jreDir, &jvm, cwd.string());
    if (jniEnv == NULL)
    {
        std::cerr << "C++: Failed to get Java environment" << std::endl;
        return 1;
    }
        CallClass(jniEnv, "CppToJava", "main", "([Ljava/lang/String;)V");

    // clean up
    jint jvmres = jvm.DestroyJavaVM(); // never returns ???
    std::clog << "C++: DestroyJavaVM and terminate: " << jvmres << std::endl;

}

I have two minor problems, I get a bit lost, I understand that it looks to see if Java in installed and tries to get the path to it and then to load the DLL, but I didn't managed to make it work for my situation, and also, on client machines I'm not making them install Java, but it comes in the app files with a license agreement, I'm using Eclipse Adoptium (...\MyApp\ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot).

If it isn't much to ask, could someone help me change the above code so that it will work in this scenario: Before creating the JVM, I'm running some other functions, and one of them returns the location for the app folder (ex: D:\Program Files\MyApp). Inside that folder are the apps data, and a folder Data, inside it a folder Java, and inside that all the java class files (...\MyApp\Data\Java\JavaMethods.class). So because I know the location of the app, I can give the location for jvm.dll by using the variable std::string location which would have as an example D:\Program Files\MyApp, then to that I can append \ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot\bin\server for the location of jvm.dll.

To be more precise, what I need to add before location.insert(0, "-Djava.class.path=");, to load the jvm.dll knowing it's location by combining like I said, the value from function parameter which would be set before calling the function and would have as an example D:\Program Files\MyApp, with \ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot\bin\server.

Here is an example how my app is using JNI extracted to a new project:
C++
#include <jni.h>
#include <string>
#include <iostream>
#include <chrono>
#include <thread>

JavaVM* jvm = nullptr;

std::string createVM(std::string location) {
	//Here what I need to add to load the dll from location + ThirdParty\Eclipse Adoptium\jre-17.0.7.7-hotspot\bin\server
	location.insert(0, "-Djava.class.path=");
	location.append("Data\\Java");
	JavaVMInitArgs vm_args;
	JavaVMOption* options = new JavaVMOption[1];
	options[0].optionString = &location[0];
	vm_args.version = JNI_VERSION_10;
	vm_args.nOptions = 1;
	vm_args.options = options;
	vm_args.ignoreUnrecognized = false;
	JNIEnv* env = nullptr;
	jint rc = JNI_OK;
	if (jvm == nullptr) {
		rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
	}
	else {
		rc = jvm->AttachCurrentThread((void**)&env, NULL);
	}
	delete[] options;
	if (rc != JNI_OK) {
		if (rc == JNI_EVERSION)
			return "JNI_EVERSION";
		else if (rc == JNI_ENOMEM)
			return "JNI_ENOMEM";
		else if (rc == JNI_EINVAL)
			return "JNI_EINVAL";
		else if (rc == JNI_EEXIST)
			return "JNI_EEXIST";
		else
			return "JNI_FATALERROR";
	}
	return "JNI_CREATED";
}

std::string createIdentification() {
	JNIEnv* env;
	jvm->AttachCurrentThread((void**)&env, NULL);
	jclass jClass = env->FindClass("JavaMethods");

	if (jClass == nullptr) {
		return "ClassNotFound cI";
	}
	else {
		jmethodID methodID = env->GetStaticMethodID(jClass, "createIdentification", "()Ljava/lang/String;");
		if (methodID == nullptr) {
			return "MethodNotFound cI";
		}
		else {
			jboolean isCopy;
			jstring jResult = (jstring)env->CallStaticObjectMethod(jClass, methodID);
			const char* string = env->GetStringUTFChars(jResult, &isCopy);
			std::string result = string;
			env->ReleaseStringUTFChars(jResult, string);

			return result;
		}
	}
}

int main() {
	//As an example I wrote a possible location
	std::cout << createVM("D:\\Program Files\\MyApp\\").c_str() << std::endl;
	std::cout << createIdentification().c_str();

	std::this_thread::sleep_for(std::chrono::milliseconds(2000));
	return 0;
}

AnswerRe: How to use JNI without setting Environment Variables Pin
Valentinor16-Oct-23 1:42
Valentinor16-Oct-23 1:42 
AnswerRe: How to use JNI without setting Environment Variables Pin
jschell16-Oct-23 4:58
jschell16-Oct-23 4:58 
GeneralRe: How to use JNI without setting Environment Variables Pin
Valentinor16-Oct-23 5:41
Valentinor16-Oct-23 5:41 
GeneralRe: How to use JNI without setting Environment Variables Pin
jschell17-Oct-23 5:47
jschell17-Oct-23 5:47 
GeneralRe: How to use JNI without setting Environment Variables Pin
Valentinor17-Oct-23 19:26
Valentinor17-Oct-23 19:26 
QuestionSending file though socket as byte[] Pin
JohnCodding25-Sep-23 20:52
JohnCodding25-Sep-23 20:52 
GeneralRe: Sending file though socket as byte[] Pin
JohnCodding25-Sep-23 21:33
JohnCodding25-Sep-23 21:33 
GeneralRe: Sending file though socket as byte[] Pin
Richard MacCutchan25-Sep-23 22:32
mveRichard MacCutchan25-Sep-23 22:32 
GeneralRe: Sending file though socket as byte[] Pin
JohnCodding25-Sep-23 23:44
JohnCodding25-Sep-23 23:44 
GeneralRe: Sending file though socket as byte[] Pin
Richard MacCutchan25-Sep-23 23:58
mveRichard MacCutchan25-Sep-23 23:58 
GeneralRe: Sending file though socket as byte[] Pin
JohnCodding26-Sep-23 0:53
JohnCodding26-Sep-23 0:53 
GeneralRe: Sending file though socket as byte[] Pin
jschell3-Oct-23 4:42
jschell3-Oct-23 4:42 
GeneralRe: Sending file though socket as byte[] Pin
JohnCodding12-Oct-23 23:35
JohnCodding12-Oct-23 23:35 
GeneralRe: Sending file though socket as byte[] Pin
jschell13-Oct-23 7:19
jschell13-Oct-23 7:19 
Question[Solved] Getting and setting a File's all attributes Pin
Valentinor24-Sep-23 22:47
Valentinor24-Sep-23 22:47 
AnswerRe: Getting and setting a File's all attributes Pin
Victor Nijegorodov24-Sep-23 23:04
Victor Nijegorodov24-Sep-23 23:04 
GeneralRe: Getting and setting a File's all attributes Pin
Valentinor24-Sep-23 23:17
Valentinor24-Sep-23 23:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.