JNI_CreateJavaVM() terminates with exit code 1 - c++

I'm trying to call a Java method from C++ using JNI. To do that I've installed jdk1.7.0_51, linking against jdk1.7.0_51\lib\jvm.lib, including jdk1.7.0_51\include and jdk1.7.0_51\include\win32. using the following code in Visual Studio 2012 I tried to create a Java vm object - but the function always terminates my application with exit code 1 (the function doesn't return 1: my program terminates completly and sends the exit code 1).
#include <iostream>
#include "jni.h"
int main(int argc, char*argv[]){
JNIEnv* env = nullptr;
JavaVM* jvm = nullptr;
JavaVMInitArgs vm_args;
JavaVMOption options[2];
options[0].optionString = "-Djava.class.path=.";
options[1].optionString = "-DXcheck:jni:pedantic";
vm_args.version = JNI_VERSION_1_6;
vm_args.nOptions = 2;
vm_args.options = options;
vm_args.ignoreUnrecognized = JNI_TRUE; // remove unrecognized options
int ret = JNI_CreateJavaVM(&jvm, (void**) &env, &vm_args);
std::cout << "This code is never reached" << std::endl;
return 0;
}
OS: Windows 7 (x64)
Compiler: Visual Studio 2012 (x86/Win32 Project)
Java VM: jdk1.7.0_51, i586 (should be ok in my opinion, because I'm compiling for x86 - otherwise linkage with jvm.lib wouldn't work)
I've already tried to using both: jdk1.7.0_51\jre\bin\client\jvm.dll as well as jdk1.7.0_51\jre\bin\Server\jvm.dll - with the same result (I'm not entirely sure what the difference is though).
Any ideas & suggestions would be highly appreciated.

Using static linking
remove the jvm.dll from your project directories. The dll must be loaded from it's original location, as it seems that other DLLs are involved, found by references.
Set the PATH environement variable to start with the folder of a JRE jvm.dll. And don't use the "c:\folder with space in name" notation (that is surrounding the path with double quotes). Just use set path=c:\folder with space in name;%PATH%. That mistake made my previous attempts worthless.
Using dynamic linking.
remove the jvm.dll from your project directories. The dll must be loaded from it's original location, as it seems that other DLLs are involved, found by references.
Drop jvm.lib from your project configuration
Use LoadLibrary, with the full path for jvm.dll (escape '\' or use '/')
Use GetProcAddress for "JNI_CreateJavaVM"
Make sure to use a proper typedef for the function pointer (use JNICALL as calling convention)
Patching your code with above steps makes my VS2012/Seven64/x86Debug/JDK1.6 project to output "This code is never reached" (with ret == JNI_OK)

Related

OCCI app crashes when running in debug mode in Visual Studio 2005

I'm attempting to get a development environment up and running for developing applications with Oracle C++ Call Interface (OCCI) in Visual Studio 2005.
My system specs are:
OS: Windows 7, 64-bit
Oracle: 11g release 11.2.0.2, 32-bit
Instant Client: BasicLite and SDK version 11.2.0.4 32-bit
Visual Studio 2005 Professional Edition version 8.0 with 32-bit tools enabled
I've followed this guide by Mark Williams and I got the example running but only in release mode. When I switch to debug mode the app will build, but when I run it I get the following error:
Problem signature:
Problem Event Name: APPCRASH
Application Name: OCCITest.exe
Application Version: 0.0.0.0
Application Timestamp: 53f5dfdd
Fault Module Name: KERNELBASE.dll
Fault Module Version: 6.1.7601.18229
The small example program that triggers this error is:
#include "employees.h"
using namespace std;
using namespace oracle::occi;
int main (void)
{
Employees *pEmployees = new Employees();
delete pEmployees;
return 0;
}
Employees::Employees()
{
user = "hr";
passwd = "hr";
db = "localhost:1521/service_name";
env = Environment::createEnvironment(Environment::DEFAULT);
try
{
con = env->createConnection(user, passwd, db);
}
catch (SQLException& ex)
{
cout << ex.getMessage();
exit(EXIT_FAILURE);
}
}
Employees::~Employees()
{
env->terminateConnection (con);
Environment::terminateEnvironment (env);
}
If I remove all calls to OCCI functionality the application doesn’t crash. That is, this program runs error-free:
#include "employees.h"
using namespace std;
using namespace oracle::occi;
int main (void)
{
Employees *pEmployees = new Employees();
delete pEmployees;
return 0;
}
Employees::Employees()
{
user = "hr";
passwd = "hr";
db = "localhost:1521/service_name";
cout<<"Look at me, I'm running"<<endl;
}
Employees::~Employees()
{}
In the guide Mark mentions that when running in debug mode, the linker should use the library file oraocci11d.lib. However, this file is not included in the Instant Client SDK version 11.2.0.4, so I’m using the input file oraocci11.lib for both the release and debug version.
I'm running out of ideas about how to proceed in solving this problem, and I would greatly appreciate any and all help.
If the Oracle DLL receives and/or passes objects such as std::string or any other object that either:
Manipulates the heap in any way, or
The objects could have differing internals between app and DLL,
then you have no choice but to use the correct library to link with. Otherwise you wind up with binary or heap incompatible objects being passed, which leads to what you're seeing now.
See here: http://docs.oracle.com/cd/E11882_01/appdev.112/e10764/install.htm#CBHGBBJI
The link above mentions both the debug import library and debug version of the DLL. Also this is stated at the link:
Applications that link to MSVCRTD.DLL, a debug version of Microsoft C-Runtime, /MDd compiler flag, should link with these specific OCCI libraries: oraocci11d.lib and oraocci11d.dll.
Since it took me quite some time to get the debug environment working I figured I'd answer my own question now that I did.
I got a variety of errors throughout the ordeal, but the error that I got most stuck on was an error saying:
'The application was unable to start correctly (0xc0150002).
Click OK to close the application.'
Also, I used http://www.dependencywalker.com which repeatedly told me that either oraocci11d.dll or a the following list of dll's could not be found.
API-MS-WIN-APPMODEL-RUNTIME-L1-1-0.DLL
API-MS-WIN-CORE-WINRT-ERROR-L1-1-0.DLL
API-MS-WIN-CORE-WINRT-L1-1-0.DLL
API-MS-WIN-CORE-WINRT-ROBUFFER-L1-1-0.DLL
API-MS-WIN-CORE-WINRT-STRING-L1-1-0.DLL
API-MS-WIN-SHCORE-SCALING-L1-1-1.DLL
DCOMP.DLL
IESHIMS.DLL
However, what was really missing was for the executable to be able to find oci.dll. I'm just mentioning the errors in case someone else runs into these.
Here is what was needed to make it work:
First of all, the Instant Client does not contain the oraocci11d.lib or oraocci11d.dll, so it is necessary to install the full Oracle Client.
Next, the following must be added to the PATH:
C:\Program Files\Oracle\11.2.0\OCI\lib\MSVC\vc8
C:\Program Files\Oracle\11.2.0\BIN
In Visual Studio, select Tools -> Options, unfold 'Projects and Solutions' and select VC++ Directories. In 'Show directories for' under:
Include Files add C:\Program Files\Oracle\11.2.0\OCI\include
Library files add C:\Program Files\Oracle\11.2.0\OCI\lib\MSVC\vc8
In the property page for your project under Configuration Properties -> Linker select Input and under Additional Dependencies add oraocci11d.lib (or oraocci11.lib for release mode). Then select debug/release mode in the Configuration Manager
I have a related problem in that I am successfully using oraocci12d.dll/msvcr100d.dll, but this in turn is using oci.dll/msvcr100.dll. ie, oci.dll is not using the debug version of msvcr100.
My program seems to run okay, but any memory leak reporting disappears on exit.

Change logging directory in Google glog

How can I change the output directory in Google glog?
I only found google::SetLogDestination(google::LogSeverity, const char* path)
tried it with:
google::SetLogDestination(ERROR, "C:\\log\\error.log);
google::InitGoogleLogging("Test");
LOG(ERROR) << "TEST";
but nothing was written!
Btw.: if you suggest another lightweight, easy to use and thread safe library please let me know!
Thx for any help!
You can also do one of the following:
Pass the log directory as a commandline argument as long as you have the GFlgas library installed:
./your_application --log_dir=/some/log/directory
If you don't want to pass it in the commandline and instead set it in the source:
FLAGS_log_dir = "/some/log/directory";
If the Google gflags library isn't installed you can set it as an environment variable:
GLOG_log_dir=/some/log/directory ./your_application
Here is the test what I did, you may try it,
#include <glog/logging.h>
using namespace std;
int main(int /*argc*/, char** argv)
{
FLAGS_logtostderr = true;
google::SetLogDestination(google::GLOG_INFO,"c:/lovelyGoogle" );
google::InitGoogleLogging(argv[0]);
LOG(INFO) << "This is INFO";
LOG(WARNING) << "This is WARNING";
LOG(ERROR) << "This is Error";
system("pause");
return 0;
}
Tested under Visual studio 2012, google-glog 0.3.3 on Windows 7.
It generated lvoelyGoogle20131016-141423.5160 on my C driver.
If you set FLAGS_logtostderr = false, the log file will not be generated,
I believe you have already read this (well, I have no comment on it)
hope this helpful, good luck.
PS: I have tested on QtCreator (Qt5.1) as well on Windows7, nothing output. I have no idea how to fix it now.
I use this:
fLS::FLAGS_log_dir = "c:/Documents/logs";
In my terrifying experience with this library I came to see that this flag FLAGS_log_dir and this function google::SetLogDestination() compete with each other. Wonderful.
I learned that you can use either but not both.
option 1: use flags
FLAGS_log_dir=/path/to/your/logdir
google::InitGoogleLogging(exec_name.c_str());
and generate a bunch of files named your_exec.some_number.machine_name.log.log_severity.... and their respective symbolic link inside the /path/to/your/logdir. A pair of files will be generated for each log_severity you have used in your program (INFO, WARNING, ERROR, FATAL). Fun fact: INFO files contain everything, WARNING files contain everything from warning downwards, and so on. God knows why these symlinks are needed.
option 2: use file names
std::string log_dir = "/path/to/log/dir";
for (int severity = 0; severity < google::NUM_SEVERITIES; ++severity) {
std::string fpath = fs::path(fs::path(log_dir) / fs::path(exec_name).filename());
google::SetLogDestination(severity, fpath.c_str());
google::SetLogSymlink(severity, "");
}
google::InitGoogleLogging(exec_name.c_str());
where fs is the filesystem library of c++17. This is send all logs to the same file (just one, not many) and finally remove that annoying symbolic link.

Call Java code from C

I use the JNI interface to invoke Java code from C code.
While compiling I use the following command:
gcc -g -I/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/include/ -I/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/include/linux/ -L/usr/bin/java -L/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/amd64/server/ -ljvm calljava.c
And I use the following code to create the JVM:
JNIEnv* create_vm()
{
JavaVM* jvm;
JNIEnv* env;
JavaVMInitArgs args;
JavaVMOption options[1];
args.version = JNI_VERSION_1_2;
args.nOptions = 1;
options[0].optionString = "-Djava.class.path=<classpath>";
args.options = options;
args.ignoreUnrecognized = JNI_FALSE;
JNI_CreateJavaVM(&jvm, (void **)&env, &args);
return env;
}
My question is:
Is the path to the JVM hardcoded in the binary?
Can we specify the path to the java executable at runtime?
If there is a way to do that can anyone help me with the compile time flags that can be used for that?
Thanks in advance!
The "java executable" is not used at all. When you compile and link your code, you link against a shared library, the location of which is determined by the system at runtime when you launch your executable.
Unless you dynamically load the jvm shared library yourself from a known location (and subsequently look up and call the functions therein), the system is going to determine the "path to the JVM".
Usually if you want to run against a specific version, you would include that version in your application's distribution, and configure the launch of your application to ensure that the proper shared library is used (either via scripts which set the environment appropriately, dynamically loading it, or other system-specific methods).

JNI, Java to C++ in Eclipse: undefined reference to '_imp__JNI_CreateJavaVM#12'

I'm a beginner to c++ and JNI and I want to call a Java methode from my C++ program.
When compiling (with Eclipse) I get the following error:
undefined reference to '_imp__JNI_CreateJavaVM#12'
I searched for this problem and came across this post
There the answer was, if I get that right, including the jvm library to the compiling command. Since I'm not compiling by hand I'm not sure how I can make Eclipse do this. Could somebody explain that step by step for a complete beginner?
Here is the code, in case the compiling command won't change anything and the code has some errors.
In this part the error is displayed when calling JNI_CreateJavaVM:
JNIEnv* create_vm(JavaVM ** jvm) {
JNIEnv *env;
JavaVMInitArgs vm_args;
JavaVMOption options;
/*
* The following is a little messy, but options.optionString wants a char* not a string
* So I convert the String-path to a char-array
*/
string stringPath = "-Djava.class.path=C:\\Users\\Chris\\workspacejava\\PP\\src\\Tests"; //Path to the java source code
int sLen = stringPath.length();
char javaPath [sLen + 1];
int i = 0;
for(; i < sLen; i++)
{
javaPath[i] = stringPath[i];
}
javaPath[i] = '\0';
options.optionString = javaPath;
vm_args.version = JNI_VERSION_1_6; //JDK version. This indicates version 1.6
vm_args.nOptions = 1;
vm_args.options = &options;
vm_args.ignoreUnrecognized = 0;
int ret = JNI_CreateJavaVM(jvm, (void**)&env, &vm_args); //This call results in the error: undefined reference to '_imp__JNI_CreateJavaVM#12'
if(ret < 0)
printf("\nUnable to Launch JVM\n");
return env;}
And here I call this function:
int main(int argc, char* argv[])
{
JNIEnv *env;
JavaVM * jvm;
env = create_vm(&jvm);
if (env == NULL)
return 1;
...
int n = jvm->DestroyJavaVM();
return 0;
}
Further Informations: (I don't know if they help)
I use Windows 7. Both Eclipse and JDK are 64Bit. I'm using MinGW GCC to compile my code.
I'm glad for every piece of advice
That's right, you need to add the jvm library to your build.
Open the project properties dialog.
Select C++ Builder > Settings on the left.
Select the Tool Setting tab.
Select MinGW C++ Linker > Libraries.
Add jvm in the Libraries section.
Add the path to your JDK lib folder in the Libraries Search Path section.
I have a JAVA_HOME environment variable pointing to a JRE subfolder of a JDK so I enter the search path like this: "${env_var:JAVA_HOME}/../lib", with quotes because the environment variable expands to a path with spaces in it.
Now, you might have 32-bit and/or 64-bit JDKs installed. Be sure to use files from the same bit-ness as your compiler output. That includes running your exe with the right jvm.dll first on the DLL search path. On 64-bit Windows, the 32-bit JDK is usually installed under C:\Program Files (x86)\Java....
The #12 says that your compiler is producing 32-bit code (the arguments to JNI_CreateJavaVM are 3 pointers of 4-bytes each) so the linker needs the 32-bit version of jvm.lib rather than the 64-bit version.
BTW—Your java.class.path looks a suspicious for two reasons:
Tests looks like the name of a class. The class path should be a ;-separated list of paths to the root folder of packages. If Tests is a class in the default package, just lop off Tests from your class path.
Eclipse usually sets up Java projects with separate source and binary folders. The paths in the class path are where java should search for .class files. If your project is configured to compile .java files from the src folder to .class files in the bin folder, then replace src with bin in your class path.

Simple program, no callstack, "inpossible" to find error

When I run on my working machine (win7 VS2010 ultimate sp1)
int main()
{
unsigned i = 5;
i %= 0;
return 0;
}
or
int main()
{
int * ip = 0;
*ip = 4;
return 0;
}
and I get Integer division by zero unhandled exception. When I hit break button, to see the problem, my Call stack contains only msvcrt100d and ntdll and Visual studio breaks me inside file mlock.c on the LeaveCriticalSection( _locktable[locknum].lock ); line.
When I run this code on another machine(win7 VS2010 proff sp1), VS breaks it exactly on the problematic line i %= 0; od *ip = 4.
This mistake was hidden somewhere within my project and I wasn't able to find it till I run it on another machine. How can I fix this behavior? I need to see it on my working machine.
I have a clean installation of Windows 7, clean installation Visual Studio 2010 and VS-SP1.
My project should not be ruined. I generate it using CMake and same project working fine on non-working machine.
Any advice would be greatly appreciated.
Ok, I have found a solution.
In VS go to exceptions settings (ctrl + alt + e) and check Thrown in required Win32 Exceptions.
More info can be found
here and here.
SO related question here.
When you compile a program with VS it creates the EXE file and a PDB file with all the relevant debugging information of the program. Also, the absolute path of the PDB if embedded into the EXE.
When the EXE crashes and you use VS to debug it, it tries to find the corresponding PDB, both in the same folder than the EXE and in the absolute path embedded in the file. If you want it to be able to debug the program, then you must copy the PDB along with the EXE. Note that these two files must come from exactly the same compilation, or else it will not work.
Then, the VS debugger will try to show you the sources of the program, again using the absolute path of the *.c or *.cpp files embedded in the PDB. Obviously, if you want it to stop in the relevant line, you need a copy of the sources! If you copy the sources to the very same path than in the original machine it should work without problems. If not, you have to open the Call stack window, double-click over the main function and it will ask you to browse for the actual sources.
Or maybe your setup is screwed...