Simplicity for executing Java from C++ - java

Background info: I am used to program in Java and I know how to use Eclipse and Visual Studio.
Final objective: to create a GUI, preferably in Visual Studio, which executes Java functions.
What I wish to accomplish from this question: a button in C++ which, on click, executes a Java function and returns the results to C++. (probably by invoking a JVM)
I've currently considered the following datastructures:
Sharing data through 'common' files such as .txt files (but then how do I start the Java functions?)
Opening a socket (seems too complicated for this problem)
Connecting through a server (too complicated)
Invoking a JVM from C++ which then executes the Java file (I think this is the most reasonable way but this needs a lot of code)
Now I know about the existence of Jace, JNI and SWIG but I think they are very handy for making complicated programs, not easy interfaces. I don't want to make a complicated program hence I feel that learning all their commands is quite bothersome.
I have also read up on a lot of Stack Exchange questions asking the exact same thing but all of them seem to give very complicated answers.
So here is my question:
What is the absolute simplest way to execute a (if necessary: precompiled) Java function from C++ where the C++ code passes some arguments to this Java function
Thanks in advance.

Invoking a JVM from C++ which then executes the Java file (I think this is the most reasonable way but this needs a lot of code)
Yes, it definitely is the most reasonable way. And with JNI and the invocation API it's not even that much code.
Finding the jvm.dll
You could try things like hardcoding the path to the Oracle JVM's jvm.dll or searching for a file called jvm.dll in the programs folder, but all that is obviously extremely hacky. However, there is apparently a pretty easy solution: The registry. The key HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment contains a REG_SZ called CurrentVersion. You can read the value of this key (currently it's 1.7) and open a child key with that name (HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\1.7 in this example). That key will then contain a REG_SZ called RuntimeLib which is the path to your jvm.dll. Don't worry about Program files vs Program files (x86). WOW64 will automatically redirect your registry query to HKLM\SOFTWARE\Wow6432Node if you're a 32bit process on a 64bit windows and that key contains the path to the 32 bit jvm.dll. Code:
#include <Windows.h>
#include <jni.h> // C:\Program Files\Java\jdk1.7.0_10\include\jni.h
// ...
DWORD retval;
// fetch jvm.dll path from registry
HKEY jKey;
if (retval = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\JavaSoft\\Java Runtime Environment"), 0, KEY_READ, &jKey))
{
RegCloseKey(jKey);
// assuming you're using C++/CLI
throw gcnew System::ComponentModel::Win32Exception(retval);
}
TCHAR versionString[16]; // version numbers shouldn't be longer than 16 chars
DWORD bufsize = 16 * sizeof(TCHAR);
if (retval = RegGetValue(jKey, NULL, TEXT("CurrentVersion"), RRF_RT_REG_SZ, NULL, versionString, &bufsize))
{
RegCloseKey(jKey);
// assuming you're using C++/CLI
throw gcnew System::ComponentModel::Win32Exception(retval);
}
TCHAR* dllpath = new TCHAR[512];
bufsize = 512 * sizeof(TCHAR);
retval = RegGetValue(jKey, versionString, TEXT("RuntimeLib"), RRF_RT_REG_SZ, NULL, dllpath, &bufsize)
RegCloseKey(jKey);
if (retval)
{
delete[] dllpath;
// assuming you're using C++/CLI
throw gcnew System::ComponentModel::Win32Exception(retval);
}
Loading the jvm.dll and getting the CreateJavaVM function
This part is pretty straightforward, you just use LoadLibrary and GetProcAddress:
HMODULE jniModule = LoadLibrary(dllpath);
delete[] dllpath;
if (jniModule == NULL)
throw gcnew System::ComponentModel::Win32Exception();
typedef int (JNICALL * JNI_CreateJavaVM)(JavaVM** jvm, JNIEnv** env, JavaVMInitArgs* initargs);
JNI_CreateJavaVM createJavaVM = (JNI_CreateJavaVM)GetProcAddress(jniModule, "JNI_CreateJavaVM");
Creating the JVM
Now you can invoke that function:
JavaVMInitArgs initArgs;
initArgs.version = JNI_VERSION_1_6;
initArgs.nOptions = 0;
JavaVM* jvm;
JNIEnv* env;
if ((retval = createJavaVM(&jvm, &env, &initArgs)) != JNI_OK)
throw gcnew System::Exception(); // beyond the scope of this answer
Congratulations! There's now a JVM running right inside your process! You would probably launch the JVM at the startup of your application. Unless you are 100% sure that you will only ever invoke Java code from the thread that just created the JVM, you can throw away the env pointer, but you have to keep the jvm pointer.
Getting the JNI environment (optional)
So now you created the JVM and your application is up and running and then somebody clicks that button. Now you want to invoke Java code. If you are 100% sure that you are right now on the thread that created the JVM in the previous step and you still have the env pointer, then you can skip this. Otherwise, perform a quick check if the current thread is attached to the JVM and attach it if it isn't:
JNIEnv* env;
bool mustDetach = false;
jint retval = jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (retval == JNI_EDETACHED)
{
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_6;
args.name = NULL;
args.group = NULL;
retval = jvm->AttachCurrentThread(&env, &args);
mustDetach = true; // to clean up afterwards
}
if (retval != JNI_OK)
throw gcnew System::Exception(); // should never happen
invokeJavaCode(env); // next step
if (mustDetach)
jvm->DetachCurrentThread();
Invoking Java code
Now you are right there, you want to invoke that Java code and you even have the env pointer. You want the easiest solution, so this is how you call a static method:
jclass clazz = env->FindClass("com/myself/MyClass");
if (clazz == NULL)
throw gcnew System::Exception();
jmethodID mid = env->GetStaticMethodID(clazz, "myStaticMethod", "<signature>");
if (mid == NULL)
throw gcnew System::Exception();
<type> returnedValue = env->CallStatic<type>Method(clazz, mid, <arguments>);
You can use javap -s (command line tool) to determine a method's signature. <type> can be any primitive type (it must match the return type of the Java method). The arguments can be of any primitive type, as long as they match the arguments of the Java method.
The end
And there you have it: The easiest way to invoke Java code from C++ on Windows (actually only the first two parts are windows-specific...). Oh, and also the most efficient one. Screw databases and files. Using 127.0.0.1 sockets would be an option but that's significantly less efficient and probably not less work than this. Wow, this answer is a bit longer than I expected. Hopefully it helps.

Related

Java File.renameTo() Implementation for UnixFileSystem

I was trying to figure how File.renameTo() works in Java and I reached the following method in UnixFileSystem.java (I'm on macOS).
private native boolean rename0(File f1, File f2);
I understand that (please correct if I'm wrong) native means JVM calls code/library written in another language. So, where/how can I or if it's possible see its implementation?
I'm curious to see its implementation as to confirm if I can use it for my following use case.
I need to run a Java application in two (or more) different servers which poll for files in the same directory (shared filesystem) and only one instance (server) should process a particular file. Whenever the application in any of the servers sees a file, it tries to move to some other directory and if the move is successful (determined by boolean returned by File.renameTo() method), that server start processing on those file contents (batch processing to be precise). I did a quick test with three different instances polling a single directory (generating new files at 1000 files per second) and the results were as expected. I just want to confirm if it scales.
Note that I'm not moving the actual file but a zero-byte file named something like <actual-filename>.DONE which is created after copying the file from source is complete.
AFAIK, Source of OpenJDK and Orale JDK are almost the same.
Therefore, you can find implementation of rename0 here:
#include <stdlib.h>
JNIEXPORT jboolean JNICALL
Java_java_io_UnixFileSystem_rename0(JNIEnv *env, jobject this,
jobject from, jobject to)
{
jboolean rv = JNI_FALSE;
WITH_FIELD_PLATFORM_STRING(env, from, ids.path, fromPath) {
WITH_FIELD_PLATFORM_STRING(env, to, ids.path, toPath) {
if (rename(fromPath, toPath) == 0) {
rv = JNI_TRUE;
}
} END_PLATFORM_STRING(env, toPath);
} END_PLATFORM_STRING(env, fromPath);
return rv;
}
You can see that it's actually calling libc's rename.
Since most of the environment uses glibc, here's the document:
One useful feature of rename is that the meaning of newname changes “atomically” from any previously existing file by that name to its new meaning (i.e., the file that was called oldname). There is no instant at which newname is non-existent “in between” the old meaning and the new meaning. If there is a system crash during the operation, it is possible for both names to still exist; but newname will always be intact if it exists at all.
Maybe your code is safe as long as it does not crash, and filesystem is working fine. However It may depend on what filesystem you are using (e.g. nfs).
There's good another question in stackoverflow, so it may help.

JNI_CreateJavaVM stack corruption?

Debugging a c project that is attempting to call some java functions in a jar by using JNI_CreateJavaVM(), GetStaticMethod(), CallStaticVoidMethod() etc.
Using -> openJdk 1.6.045.
I wrote a small test program that looks similar to this:
Sample program calling Java from C
Which works.
The problem comes when I integrate this with a lot of other code. The other code crashes shortly after JNI_CreateJavaVM() - (the other code works fine otherwise). It seems that JNI_CreateJavaVM() messes with the stack.
If I set the JavaVM up like so:
JavaVMOption options[2];
// Adjust stacksize.
options.[0].optionString = "path/to/class";
options.[1].optionString = "-Xss65536k";
vm_args.nOptions = 2;
vm_args.options = options;
int ret = JNI_CreateJavaVM(&jvm, (void **) &jenv, &vm_args);
Then the C program continues on happily, otherwise, if I omit the "-Xss" option, the C program terminates when it attempts to access the stack.
Any clues as to what is really going on? I suspect stack corruption, but I'd like to be able be certain as to what is happening.

JNI error in CallObjectMethod/CallObjectMethodV: Ineligible receiver

I have a C routine that is calling a Java module through the JNI invocation interface. I've been having an issue where the call to the Java method has been returning a NULL string when using the C module and the JNI, but when I use Java at the command line, the Java module returns an error and a default value.
Here is the data returned when I bypass the C code and call the Method through Java at the command line
$ java ClassName "This" "is" "my" "test" "string"
Exception on SomethingElse.Method: [Function: DifferentMethod]ExceptionClassException: ExceptionClassExceptionException: [Function: CFBDynamicMessage::getCodePage]codePageBytes is NULL, for UTF-8
Returned String -- data I'm trying to get
0.0| |0.0| |0.0|| |0.0|0| |0.0| | ||0.0|0|0|0|0|0|0|0|0|0|0||
I need to get the returned string, even in the event of an error on the java side. To try to see what is going on in the C and JNI, I turned up the debugging level for the JNI:
options[1].optionString = "-Xdebug"; /* print JNI-related messages */
options[2].optionString = "-Xlog:all";
// this next line allows us to continue processing after the Java
// error. Unfortunately the code then SegFaults further on.
options[3].optionString = "-Xcheck:jni:nonfatal";
options[4].optionString = "-verbose:jni";
The JNI starts the JVM, finds the class and the method and builds the Java string I need to pass to the method, but when I try to execute the method, I get the following errors:
JVMJNCK048E JNI error in CallObjectMethod/CallObjectMethodV: Ineligible receiver
JVMJNCK080E Error detected in the outermost frame of an attached thread
JVMJNCK023E JNI error detected. Continuing...
Segmentation fault (core dumped)
Here is the C Code (I am cutting out some error checking and whitespace for brevity):
res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
cls = (*env)->FindClass(env, "GenericClassName");
mid = (*env)->GetMethodID(env, cls, "execute", "(Ljava/lang/Object;)Ljava/lang/Object;");
jstr = (*env)->NewStringUTF( env, "This|is|my|test|string|");
// This next line is the one that throws the ineligible receiver error
jstring resultStr = (*env)->CallObjectMethod(env, cls, mid, jstr);
// ExceptionOccurred(env) is false; no errors are displayed
if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
const char *nativeString = (*env)->GetStringUTFChars(env, resultStr, JNI_FALSE);
// This next line calls the SegFault
fprintf(stdout, "%s\n", *nativeString);
I've used gdb to look at the core dump created by the SegFault and here are the what I think are the pertinent results:
print nativeString
$1 = 0x8dfaa80 "[Ljava.lang.Class;#34ca34ca"
print *nativeString
$2 = 91 '['
here is the definition of the java method I'm calling:
public Object execute (Object args) throws Exception { ... }
Any help or insight you can provide with this issue will be greatly appreciated. When I try to Google for the ineligible receiver error, I get a bunch of links about football, but nothing in the JNI or Java in general. I've spent the last few days scouring the Stack Overflow website, and although there were some promising questions asked, they were all related to Android and didn't provide any additional assistance in resolving my issue.
As two final notes, even if you can't help, thanks for reading this far and my environment is a 64bit RHEL server, but the C code and the JVM are both running as 32bit applications.
TL;DR - C is calling a Java Method through the JNI and I am getting an error code (JNI error in CallObjectMethod/CallObjectMethodV: Ineligible receiver) that results in Google telling me all about all the sports I can't watch because I'm working on this issue.
You're supplying a class instead of an object. So you're trying to call Class<GenericClassName>.execute(Object arg). You need an instance of the class.

Java API on top of JVMTI?

Is there a nice Java API I can use on top of JVMTI?
JVMTI was not built for having Java API on top. The JVM TI definition itself says:
The JVM tool interface (JVM TI) is a standard native API that allows for native libraries to capture events and control a Java Virtual Machine (JVM) for the Java platform.
Since it was built for native API to capture events & controls, I don't think there are API on top of it. May you can explain what you are trying to achieve?
I am not aware of any Java API on top of JVM TI.
ok... just tried it... seems to work as expected.... in real life the VMInit callback would return an instance of a class that implemented an interface that mirrored the C JVMTI interface.... the C agent would store this instance and call it when required on events .... additionally before the VMInit Java returned it would set up capabilities and callbacks and register events etc.... you would probably be able to get about 90% JVMTI API coverage..... it's just a case of typing it in .... I could do it in a weekend if you have a strong case :-)
the following code produces this:
C: VMInit, preparing to callback Java method
Java: JVMTI callback class, VMInit().
C: VMInit, callback Java method returned successfully
Java: And Finally... Hello, I'm the Java main
package com.stackoverflow;
public class JVMTICallback {
public static void VMInit() {
System.out.println("Java:\tJVMTI callback class, VMInit().");
}
public static void main(String[] args) {
// This main is only here to give us something to run for the test
System.out.println("Java:\tAnd Finally... Hello, I'm the Java main");
}
}
and the C
#include <stdlib.h>
#include "jvmti.h"
jvmtiEnv *globalJVMTIInterface;
void JNICALL
vmInit(jvmtiEnv * jvmti_env, JNIEnv * jni_env, jthread thread)
{
printf("C:\tVMInit, preparing to callback Java method\n");
char *className = "com/stackoverflow/JVMTICallback";
char *methodName = "VMInit";
char *descriptor = "()V";
jclass callbackClass = (*jni_env)->FindClass(jni_env, className);
if (!callbackClass) {
fprintf(stderr,"C:\tUnable to locate callback class.\n");
return;
}
jmethodID callbackMethodID = (*jni_env)->GetStaticMethodID(jni_env, callbackClass, methodName, descriptor);
if (!callbackMethodID)
{
fprintf(stderr, "C:\tUnable to locate callback VMInit method\n");
return;
}
(*jni_env)->CallStaticVoidMethodV(jni_env, callbackClass, callbackMethodID, NULL);
printf("C:\tVMInit, callback Java method returned successfully\n");
}
JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM * jvm, char *options, void *reserved)
{
jint returnCode = (*jvm)->GetEnv(jvm, (void **) &globalJVMTIInterface,
JVMTI_VERSION_1_0);
if (returnCode != JNI_OK)
{
fprintf(stderr,
"The version of JVMTI requested (1.0) is not supported by this JVM.\n");
return JVMTI_ERROR_UNSUPPORTED_VERSION;
}
jvmtiEventCallbacks *eventCallbacks;
eventCallbacks = calloc(1, sizeof(jvmtiEventCallbacks));
if (!eventCallbacks)
{
fprintf(stderr, "Unable to allocate memory\n");
return JVMTI_ERROR_OUT_OF_MEMORY;
}
eventCallbacks->VMInit = &vmInit;
returnCode = (*globalJVMTIInterface)->SetEventCallbacks(globalJVMTIInterface,
eventCallbacks, (jint) sizeof(*eventCallbacks));
if (returnCode != JNI_OK)
{
fprintf(stderr, "C:\tJVM does not have the required capabilities (%d)\n",
returnCode);
exit(-1);
}
returnCode = (*globalJVMTIInterface)->SetEventNotificationMode(
globalJVMTIInterface, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, (jthread) NULL);
if (returnCode != JNI_OK)
{
fprintf(
stderr,
"C:\tJVM does not have the required capabilities, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT (%d)\n",
returnCode);
exit(-1);
}
return JVMTI_ERROR_NONE;
}
I searched around and unfortunately can't find any Java API library on top of JVMTI. Seems like you're out of luck.
What you can do though is to call a native lib from your Java code. I'm not very good at C/C++ but from JVMTI docs I see that it's possible to build a small shared library from provided headers. Then you can call it using JNA**. It will give you a nice API wrapper around native library.
Take a look at examples at JNA Getting Started page
This page also links to JNAerator which can generate all necessary Java bindings for you.
The downside of this approach is a necessity of maintaining this thin native layer for your target platforms.
** JNA deals a runtime overhead compared to usual JNI but ease of development overweights performance benefits IMO. Switch to JNI only if you have to.
It will not work. JVMTI has callbacks that the Java code has no direct control over (like ClassPrepare). If these callbacks are implemented in Java, the execution can lead other callbacks causing deadlock.
it wouldn't be difficult to write.... just thunk the JVMTI calls to callback a Java class over JNI.. you would probably face a couple of issues... firstly the Agent_onLoad.. this initial "registering" function happens too early on in the lifecycle of the JVM for it to callback your java.... secondly there are potential circularity issues and the probability that the JVM was written expecting you to do anything like this this at...
Iĺl try to write an example.... back in a few mins...
JDI is a TOP level interface written in Java, which uses JVMTI as the backend api.
this link give you detailed info.

Pinning a Java application to the Windows 7 taskbar

I use Launch4j as a wrapper for my Java application under Windows 7, which, to my understanding, in essence forks an instance of javaw.exe that in turn interprets the Java code. As a result, when attempting to pin my application to the task bar, Windows instead pins javaw.exe. Without the required command line, my application will then not run.
As you can see, Windows also does not realize that Java is the host application: the application itself is described as "Java(TM) Platform SE binary".
I have tried altering the registry key HKEY_CLASSES_ROOT\Applications\javaw.exe to add the value IsHostApp. This alters the behavior by disabling pinning of my application altogether; clearly not what I want.
After reading about how Windows interprets instances of a single application (and a phenomenon discussed in this question), I became interested in embedding a Application User Model ID (AppUserModelID) into my Java application.
I believe that I can resolve this by passing a unique AppUserModelID to Windows. There is a shell32 method for this, SetCurrentProcessExplicitAppUserModelID. Following Gregory Pakosz suggestion, I implemented it in an attempt to have my application recognized as a separate instance of javaw.exe:
NativeLibrary lib;
try {
lib = NativeLibrary.getInstance("shell32");
} catch (Error e) {
Logger.out.error("Could not load Shell32 library.");
return;
}
Object[] args = { "Vendor.MyJavaApplication" };
String functionName = "SetCurrentProcessExplicitAppUserModelID";
try {
Function function = lib.getFunction(functionName);
int ret = function.invokeInt(args);
if (ret != 0) {
Logger.out.error(function.getName() + " returned error code "
+ ret + ".");
}
} catch (UnsatisfiedLinkError e) {
Logger.out.error(functionName + " was not found in "
+ lib.getFile().getName() + ".");
// Function not supported
}
This appears to have no effect, but the function returns without error. Diagnosing why is something of a mystery to me. Any suggestions?
Working implementation
The final implementation that worked is the answer to my follow-up question concerning how to pass the AppID using JNA.
I had awarded the bounty to Gregory Pakosz' brilliant answer for JNI that set me on the right track.
For reference, I believe using this technique opens the possibility of using any of the APIs discussed in this article in a Java application.
I don't have Windows 7 but here is something that might get you started:
On the Java side:
package com.stackoverflow.homework;
public class MyApplication
{
static native boolean setAppUserModelID();
static
{
System.loadLibrary("MyApplicationJNI");
setAppUserModelID();
}
}
And on the native side, in the source code of the `MyApplicationJNI.dll library:
JNIEXPORT jboolean JNICALL Java_com_stackoverflow_homework_MyApplication_setAppUserModelID(JNIEnv* env)
{
LPCWSTR id = L"com.stackoverflow.homework.MyApplication";
HRESULT hr = SetCurrentProcessExplicitAppUserModelID(id);
return hr == S_OK;
}
Your question explicitly asked for a JNI solution. However, since your application doesn't need any other native method, jna is another solution which will save you from writing native code just for the sake of forwarding to the windows api. If you decide to go jna, pay attention to the fact that SetCurrentProcessExplicitAppUserModelID() is expecting a UTF-16 string.
When it works in your sandbox, the next step is to add operating system detection in your application as SetCurrentProcessExplicitAppUserModelID() is obviously only available in Windows 7:
you may do that from the Java side by checking that System.getProperty("os.name"); returns "Windows 7".
if you build from the little JNI snippet I gave, you can enhance it by dynamically loading the shell32.dll library using LoadLibrary then getting back the SetCurrentProcessExplicitAppUserModelID function pointer using GetProcAddress. If GetProcAddress returns NULL, it means the symbol is not present in shell32 hence it's not Windows 7.
EDIT: JNA Solution.
References:
The JNI book for more JNI examples
Java Native Access (JNA)
There is a Java library providing the new Windows 7 features for Java. It's called J7Goodies by Strix Code. Applications using it can be properly pinned to the Windows 7 taskbar. You can also create your own jump lists, etc.
I have implemented access to the SetCurrentProcessExplicitAppUserModelID method using JNA and it works quite well when used as the MSDN documentation suggests. I've never used the JNA api in the way you have in your code snippet. My implementation follows the typical JNA usage instead.
First the Shell32 interface definition:
interface Shell32 extends StdCallLibrary {
int SetCurrentProcessExplicitAppUserModelID( WString appID );
}
Then using JNA to load Shell32 and call the function:
final Map<String, Object> WIN32API_OPTIONS = new HashMap<String, Object>() {
{
put(Library.OPTION_FUNCTION_MAPPER, W32APIFunctionMapper.UNICODE);
put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
}
};
Shell32 shell32 = (Shell32) Native.loadLibrary("shell32", Shell32.class,
WIN32API_OPTIONS);
WString wAppId = new WString( "Vendor.MyJavaApplication" );
shell32.SetCurrentProcessExplicitAppUserModelID( wAppId );
Many of the API's in the last article you mentioned make use of Windows COM which is quite difficult to use directly with JNA. I have had some success creating a custom DLL to call these API's (eg. using the SHGetPropertyStoreForWindow to set a different app ID for a submodule window) which I then use JNA to access at runtime.
Try to use JSmooth. I use always this one. In JSmooth is there an option under Skeleton by Windowed Wrapper called
Lauch java app in exe process
See on this image.
(source: andrels.com)
Also command line arguments can be passed.
I think this can be a solution for you.
Martijn
SetCurrentProcessExplicitAppUserModelID (or SetAppID()) would in fact do what you're trying to do. However, it might be easier to modify your installer to set the AppUserModel.ID property on your shortcut - quoting from the Application User Model ID document mentioned above:
In the System.AppUserModel.ID property of the application's shortcut file. A shortcut (as an IShellLink, CLSID_ShellLink, or a .lnk file) supports properties through IPropertyStore and other property-setting mechanisms used throughout the Shell. This allows the taskbar to identify the proper shortcut to pin and ensures that windows belonging to the process are appropriately associated with that taskbar button.
Note: The System.AppUserModel.ID property should be applied to a shortcut when that shortcut is created. When using the Microsoft Windows Installer (MSI) to install the application, the MsiShortcutProperty table allows the AppUserModelID to be applied to the shortcut when it is created during installation.
The latest jna-platform library now includes JNA bindings for SetCurrentProcessExplicitAppUserModelID:
https://github.com/java-native-access/jna/pull/680
I fixed mine without any ID settings.
There is an option in Launch4J if you are using it and you say you do then...
You can change the header to JNI Gui and then wrap it around the jar with the JRE.
The good thing is that it runs .exe in the process now instead on running javaw.exe with your jar. It probably does it under the hood (not sure).
Also I have noticed also that it takes around 40-50% less CPU resource which is even better!
And the pinning works fine and all that window features are enabled.
I hope it helps to someone as I spent nearly 2 days trying to solve that issue with my undecorated javafx app.

Categories