Pinning a Java application to the Windows 7 taskbar - java
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.
Related
Preventing java agents from attaching at runtime
Reposting this here as advised by security.stackexchange How can I prevent Java Agents from attaching to my running java application at runtime? I am able to prevent users from launching my application with a javaagent at startup by scanning the command line arguments: List<String> args = ManagementFactory.getRuntimeMXBean().getInputArguments(); for(String arg : args) { if(arg.contains("-javaagent")) { System.out.println("Detected Java Agent: " + arg); logIncident(0x01); Runtime.getRuntime().exit(0); } } However this does not prevent people from attaching at runtime visualvm style. I heard that you can use the -XX:+DisableAttachMechanism flag to disable this, however when I tried to use jinfo -flag +DisableAttachMechanism <PID> I got an exception telling me that it is not possible to modify this argument at runtime. Another possibility I considered was modifying the system security manager to disallow all AttachPermission's (I believe that this needs to be allowed for java agents to attach), but I'm not sure where to start. Would really appreciate any guidance on how to implement the ideas Ive already come up with, as well as suggestions for any new ideas. Edit: I created a custom security manager to deny all AttachPermissions however it appears to not be triggered in the jar being attached to but rather the agent itself. Now I am looking to enable DisableAttachMechanism at runtime, but I cant seem to find any references to this in OpenJDK source?
Exit if this returns true: private static boolean acceptsJavaAgentsAttachingToThisJvm() { HotSpotDiagnosticMXBean vm = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); VMOption opt = vm.getVMOption("DisableAttachMechanism"); return "false".equals(opt.getValue()) || opt.isWriteable(); } which should defend against casual usecases.
Calling windows UWP API's from Java with JNA
How can I call a windows UWP API from the JVM? For example the Windows.Security.Credentials API. When attempting to use JNA none of the native library names I have tried will link, and I can't actually find a DLL that matches the name Windows.Security.Credentials.dll as described in the documentation. Is what I want to do even possible, how can I link to and call UWP API's?
Update: I completely missed the mark on my first answer, was thinking JNI, not JNA, which looks a bit more like C# pInvoke. The code below is roughly what you'll need, but you'll need to reconstruct the v-tables for IInspectable and IPasswordVault. You can use the activation factory instead of activating the instance through RoActivateInstance, but then you'll need to reconstruct the interface for IActivationFactory as well. Otherwise the call suquence below is correct, if in the wrong language. You can link and call against RoActivateInstance or RoGetActivationFactory and use the low-level COM-styl ABI interfaces defined the SDK in Windows.Security.Credentials.h. Same import lib as above. eg: IInspectable *pI {}; Windows::Security::Credentials::IPasswordVault pPV; HRESULT hr = RoActivateInstance(L"Windows.Security.Credentials.PasswordVault", &pI); if (SUCCEEDED(hr)) { hr = pI->QueryInterface(__uuidof(Windows::Security::Credentials::IPasswordVault), (void**)&pPV); } if (SUCCEEDED(hr)) { IVectorView<IPasswordCredential> *pPV{}; // namespaces omitted hr = pPV->RetrieveAll(&pPV); }
Java 8 os.version does not contain entire Windows version
For Windows 10, Java 8 returns os.version=10.0 from System Properties, while the Windows 'ver' command returns 10.0.14393. Is there any way to get the full windows version from java without running an external command? Why is Java truncating the Windows version?
The answer is, as ever, in the code - it's not that it's truncating it; it just never populates the build number. Looking at the jdk8 source, they only populated dwMajorVersion and dwMinorVersion: sprintf(buf, "%d.%d", ver.dwMajorVersion, ver.dwMinorVersion); sprops.os_version = _strdup(buf); It's been this way since at least the jdk6. Now, if you want to get a full windows version, including the build, then you can use JNA - the classes/interfaces you're looking for is com.sun.jna.platform.win32.WinNT, which contains the VERSIONINFOEX structure, and com.sun.jna.platform.win32.Kernel32 for the GetVersionEx function. I don't have a copy of windows to stub out the code for you; but it should be relatively easy to do (maybe something like this? I can't even try to test this out): import com.sun.jna.platform.win32.*; import java.text.MessageFormat; public static void main(String args[]) { Kernel32 kernel = Kernel32.INSTANCE; WinNT.OSVERSIONINFOEX vex = new WinNT.OSVERSIONINFOEX(); if (kernel.GetVersionEx(vex)) { System.out.println(MessageFormat.format("{0}.{1}.{2}", vex.dwMajorVersion.toString(), vex.dwMinorVersion.toString(), vex.dwBuildNumber.toString())); } } Asking for a rationale for this; it's pretty simple really - it never really mattered before windows 10 - you had strong delineations of behaviour based on the major and minor version of the OS; with the introduction of features by build for windows 10 it's complicated things.
Java code in different build environments [duplicate]
My project requires Java 1.6 for compilation and running. Now I have a requirement to make it working with Java 1.5 (from the marketing side). I want to replace method body (return type and arguments remain the same) to make it compiling with Java 1.5 without errors. Details: I have an utility class called OS which encapsulates all OS-specific things. It has a method public static void openFile(java.io.File file) throws java.io.IOException { // open the file using java.awt.Desktop ... } to open files like with double-click (start Windows command or open Mac OS X command equivalent). Since it cannot be compiled with Java 1.5, I want to exclude it during compilation and replace by another method which calls run32dll for Windows or open for Mac OS X using Runtime.exec. Question: How can I do that? Can annotations help here? Note: I use ant, and I can make two java files OS4J5.java and OS4J6.java which will contain the OS class with the desired code for Java 1.5 and 1.6 and copy one of them to OS.java before compiling (or an ugly way - replace the content of OS.java conditionally depending on java version) but I don't want to do that, if there is another way. Elaborating more: in C I could use ifdef, ifndef, in Python there is no compilation and I could check a feature using hasattr or something else, in Common Lisp I could use #+feature. Is there something similar for Java? Found this post but it doesn't seem to be helpful. Any help is greatly appreciated. kh.
Nope there isn't any support for conditional compilation in Java. The usual plan is to hide the OS specific bits of your app behind an Interface and then detect the OS type at runtime and load the implementation using Class.forName(String). In your case there no reason why you can't compile the both OS* (and infact your whole app) using Java 1.6 with -source 1.5 -target 1.5 then in a the factory method for getting hold of OS classes (which would now be an interface) detect that java.awt.Desktop class is available and load the correct version. Something like: public interface OS { void openFile(java.io.File file) throws java.io.IOException; } public class OSFactory { public static OS create(){ try{ Class.forName("java.awt.Desktop"); return new OSJ6(); }catch(Exception e){ //fall back return new OSJ5(); } } }
Hiding two implementation classes behind an interface like Gareth proposed is probably the best way to go. That said, you can introduce a kind of conditional compilation using the replace task in ant build scripts. The trick is to use comments in your code which are opened/closed by a textual replacement just before compiling the source, like: /*{{ Block visible when compiling for Java 6: IFDEF6 public static void openFile(java.io.File file) throws java.io.IOException { // open the file using java.awt.Desktop ... /*}} end of Java 6 code. */ /*{{ Block visible when compiling for Java 5: IFDEF5 // open the file using alternative methods ... /*}} end of Java 5 code. */ now in ant, when you compile for Java 6, replace "IFDEF6" with "*/", giving: /*{{ Block visible when compiling for Java 6: */ public static void openFile(java.io.File file) throws java.io.IOException { // open the file using java.awt.Desktop ... /*}} end of Java 6 code. */ /*{{ Block visible when compiling for Java 5, IFDEF5 public static void openFile(java.io.File file) throws java.io.IOException { // open the file using alternative methods ... /*}} end of Java 5 code. */ and when compiling for Java 5, replace "IFDEF5". Note that you need to be careful to use // comments inside the /*{{, /*}} blocks.
You can make the calls using reflection and compile the code with Java 5. e.g. Class clazz = Class.forName("java.package.ClassNotFoundInJavav5"); Method method = clazz.getMethod("methodNotFoundInJava5", Class1.class); method.invoke(args1); You can catch any exceptions and fall back to something which works on Java 5.
The Ant script introduced below gives nice and clean trick. link: https://weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html in example, //[ifdef] public byte[] getBytes(String parameterName) throws SQLException { ... } //[enddef] with Ant script <filterset begintoken="//[" endtoken="]"> <filter token="ifdef" value="${ifdef.token}"/> <filter token="enddef" value="${enddef.token}"/> </filterset> please go to link above for more detail.
In java 9 it's possible to create multi-release jar files. Essentially it means that you make multiple versions of the same java file. When you compile them, you compile each version of the java file with the required jdk version. Next you need to pack them in a structure that looks like this: + com + mypackage + Main.class + Utils.class + META-INF + versions + 9 + com + mypackage + Utils.class In the example above, the main part of the code is compiled in java 8, but for java 9 there is an additional (but different) version of the Utils class. When you run this code on the java 8 JVM it won't even check for classes in the META-INF folder. But in java 9 it will, and will find and use the more recent version of the class.
I'm not such a great Java expert, but it seems that conditional compilation in Java is supported and easy to do. Please read: http://www.javapractices.com/topic/TopicAction.do?Id=64 Quoting the gist: The conditional compilation practice is used to optionally remove chunks of code from the compiled version of a class. It uses the fact that compilers will ignore any unreachable branches of code. To implement conditional compilation, define a static final boolean value as a non-private member of some class place code which is to be conditionally compiled in an if block which evaluates the boolean set the value of the boolean to false to cause the compiler to ignore the if block; otherwise, keep its value as true Of course this lets us to "compile out" chunks of code inside any method. To remove class members, methods or even entire classes (maybe leaving only a stub) you would still need a pre-processor.
if you don't want conditionally enabled code blocks in your application then a preprocessor is only way, you could take a look at java-comment-preprocessor which can be used for both maven and ant projects p.s. also I have made some example how to use preprocessing with Maven to build JEP-238 multi-version JAR without duplication of sources
Java Primitive Specializations Generator supports conditional compilation: /* if Windows compilingFor */ start(); /* elif Mac compilingFor */ open(); /* endif */ This tool has Maven and Gradle plugins.
hi I have got similar problem when I have shared library between Java SDK abd Android and in both environments are used the graphics so basically my code must to work with both java.awt.Graphics and android.graphics.Canvas, but I don't want to duplicate almost any code. My solution is to use wrapper, so I access to graphisc API indirectl way, and I can change a couple of imports, to import the wrapper I want to compile the projects. The projects have some cone shaded and some are separate, but there is no duplicating anything except of couple of wrappers etc. I think it is the best what I can do.
Equivalent of pwd.h lib of c++ in java
I have found a link that illustrates the use of getting pwd based in the uid of the user. I have a similar requirement in java for running a script as a different user which needs this implemetation. The code snippet in c++ is as below: static void su(const char* user) { struct passwd* pwentry=getpwnam(user); if(!pwentry) COUT<<"su:getpwnam:couldnot get pwd entry for user %s",user; uid_t new_uid=pwentry->pw_uid; struct passwd* pwentry_nmsadm=getpwnam("nmsadm"); if(!pwentry_nmsadm) cout<<"su:getpwnam:could not get pwd for nmsadm"); gid_t new_gid=pwentry->pw_gid; if(chdir(pwentry->pw_dir)<0) cout<<"su:chdir"; uid_t current_uid=geteuid(); gid_t current_gid=getegid(); if(current_gid!=new_gid) { if(setgid(new_gid)<0) cout<<"su:setgid"; } if(current_uid!=new_uid) { if(setuid(new_uid)<0) cout<<"su: setuid"; } Please suggest some links that can be helpful(libraries that can be used) or solution to the above requirement in java.
Java does not provide this out-of-the-box, since it is both system dependant and would break security concepts of Java. Some possible solutions could be: Use a JNI wrapper to call your C++ method, so that you can do everything you need in C++ Use ssh to launch the script as a different user Use sudo to launch the script as a different user See also Running UNIX commands as different user, from Java How can I create a new process with another User Account on Windows? (Windows specific, but one answer mentions the JNI approach)