Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. Java
  4. Using JNI without having to add jvm.dll path inside Environment Variables (User or System)

Using JNI without having to add jvm.dll path inside Environment Variables (User or System)

Scheduled Pinned Locked Moved Java
c++javaquestionworkspace
15 Posts 5 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J JohnCodding

    Looking at the code, is the following line really what it only needs and the rest are checks if it exists, if it was loader or not?

    hJVMDLL = LoadLibraryW(reinterpret_cast(jvmpath.c_str()));

    L Offline
    L Offline
    Lost User
    wrote on last edited by
    #6

    That just loads the library into the process's address space. You still need the dynamic calls to find the method addresses before you can call them, as the library is not linked to the application at build time.

    J 1 Reply Last reply
    0
    • L Lost User

      I think your option (c++17) may be incorrect, it should be as below. I don't use a project but a simple Makefile. The compile statement that it generates is:

      cl -nologo -EHsc -RTC1 -W3 -std:c++17 -I "C:\Program Files\Java\jdk-18.0.2\include" -I "C:\Program Files\Java\jdk-18.0.2\include\win32" cpptojava.cpp

      The include paths may well be different on your system. Your code appears to be OK; what happens when you run it?

      J Offline
      J Offline
      JohnCodding
      wrote on last edited by
      #7

      My code is running fine, but I just wanted to skip the step where you have to add the path of the jvm.dll inside Environment variable. Because with this, I need a separate exe file that will first check if the path is added or not (and to add it if it isn't), and after that to launch the exe for the program that is using JNI. So for this right now I have a Java program that is doing the check and acting as a launcher (which is made using jpackage command, so it doesn't need Java to be installed), and when the check is done it is launching a different exe from its folder.

      1 Reply Last reply
      0
      • L Lost User

        That just loads the library into the process's address space. You still need the dynamic calls to find the method addresses before you can call them, as the library is not linked to the application at build time.

        J Offline
        J Offline
        JohnCodding
        wrote on last edited by
        #8

        Would AddDllDirectory with the path of the jvm.dll help with setting another path for the app to look into before it goes to Environment variables? Or that is used for something else and it won't work with JNI? Like I said, I can give the location to the jvm.dll in a parameter, because the location is different for each user, depending where the app is is installed.

        L 1 Reply Last reply
        0
        • J JohnCodding

          Would AddDllDirectory with the path of the jvm.dll help with setting another path for the app to look into before it goes to Environment variables? Or that is used for something else and it won't work with JNI? Like I said, I can give the location to the jvm.dll in a parameter, because the location is different for each user, depending where the app is is installed.

          L Offline
          L Offline
          Lost User
          wrote on last edited by
          #9

          JohnCodding wrote:

          Would AddDllDirectory with the path of the jvm.dll help

          I have never used it but the documentation suggests that it would. There's only one way to find out if it works.

          J 1 Reply Last reply
          0
          • L Lost User

            JohnCodding wrote:

            Would AddDllDirectory with the path of the jvm.dll help

            I have never used it but the documentation suggests that it would. There's only one way to find out if it works.

            J Offline
            J Offline
            JohnCodding
            wrote on last edited by
            #10

            I tried this, but it doesn't work.

            std::string dllLocation = "C:\\\\Program Files\\\\Eclipse Adoptium\\\\jdk-18.0.1.10-hotspot\\\\bin\\\\server";
            std::wstring temp = std::wstring(dllLocation.begin(), dllLocation.end());
            
            AddDllDirectory(temp.c\_str());
            

            I also tried to switch it to SetDllDirectory but that also didn't work.

            J K 2 Replies Last reply
            0
            • J JohnCodding

              I tried this, but it doesn't work.

              std::string dllLocation = "C:\\\\Program Files\\\\Eclipse Adoptium\\\\jdk-18.0.1.10-hotspot\\\\bin\\\\server";
              std::wstring temp = std::wstring(dllLocation.begin(), dllLocation.end());
              
              AddDllDirectory(temp.c\_str());
              

              I also tried to switch it to SetDllDirectory but that also didn't work.

              J Offline
              J Offline
              JohnCodding
              wrote on last edited by
              #11

              I might leave it as it is, with the launcher which adds the jvm.dll path to User path if it doesn't exists, and then to launch the actual app. C++ code wording is different then Java, more "raw", and I'm really not use to it, I'm getting lost looking at it and more confused the more I look at examples. If it aint broke dont fix it. :laugh:

              L 1 Reply Last reply
              0
              • J JohnCodding

                I might leave it as it is, with the launcher which adds the jvm.dll path to User path if it doesn't exists, and then to launch the actual app. C++ code wording is different then Java, more "raw", and I'm really not use to it, I'm getting lost looking at it and more confused the more I look at examples. If it aint broke dont fix it. :laugh:

                L Offline
                L Offline
                Lost User
                wrote on last edited by
                #12

                I just tried AddDllDirectory also, but it does not seem to do what I expected. I have also been going round in circles trying various changes but basically getting nowhere. I think you are right to stick with a solution that works for you.

                1 Reply Last reply
                0
                • J JohnCodding

                  In order to use JNI, you have to add inside Environment Variables (User or System) the path to were jvm.dll is located. You have a few ways to do that, but it is possible. But, is there a way to not have to add the path inside Environment Variables and instead when you call the function to create a VM from C++ to tell it where it is located via JavaVMInitArgs, or maybe JavaVMOption, or in any other way, but like I said without having to add the path in Environment Variables?

                  J Offline
                  J Offline
                  jschell
                  wrote on last edited by
                  #13

                  Having used JNI multiple times before I would note that I would never use it again. If the JNI code crashes then it takes the VM down. And there is little or nothing you can do to stop that. For convenience I am going to refer to the needed non-java code as C/C++ below but it applies to any language that can be used to create an exe. And there is a very viable option 1. Create a C/C++ wrapper which allows the target code to be run as and exe. 2. The exe has a control API. There are three ways to control it: Stdio, files or TCP/IP. Or perhaps pipes. 3. Use Java process API to run and manage the exe. That allows one to start, stop and kill it. 4. The Java code uses the control API to control it. This can include everything: configuration, passing binary data, statistics, health checks even a request for the exe to exit. Advantages over JNI 1. It cannot crash the VM 2. The external code runs in its own process space. 3. The C/C++ code can be unit tested independently from Java code. 4. The C/C++ code is its own deliverable. Move the exe into the Java deployment space. It can even be packaged into a jar (any file can be) but of course it would need to be extracted into the file system. 5. The java code can be tested independently from the java code if the control interface is built carefully.

                  1 Reply Last reply
                  0
                  • J JohnCodding

                    I tried this, but it doesn't work.

                    std::string dllLocation = "C:\\\\Program Files\\\\Eclipse Adoptium\\\\jdk-18.0.1.10-hotspot\\\\bin\\\\server";
                    std::wstring temp = std::wstring(dllLocation.begin(), dllLocation.end());
                    
                    AddDllDirectory(temp.c\_str());
                    

                    I also tried to switch it to SetDllDirectory but that also didn't work.

                    K Offline
                    K Offline
                    kdbueno
                    wrote on last edited by
                    #14

                    small directories does collide with ibm struct and podiums.

                    1 Reply Last reply
                    0
                    • L Lost User

                      Yes, this is the way I do it, but you can modify it any way you like to provide the path to the library:

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

                      #include #include #include #include #include #include // 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(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(stropts.c\_str());
                      options\[1\].optionString = const\_cast("-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;
                      
                      V Offline
                      V Offline
                      Valentinor
                      wrote on last edited by
                      #15

                      Hi, I stumbled upon this thread and I like what I see here, and it is something I could use in some of my projects, which is to use JNI without having to add jvm.dll location into Environment Variables. But two minor problem, I get lost in all of that code to change it for my use case :), 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 you 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 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:

                      #include #include #include #include #include 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

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups