How can I get the current computer's "Program Files" path with Java?
Simply by calling System.getenv(...)
System.getenv("ProgramFiles");
Notice it will only work in Windows environments, of course :-)
System.getenv("%programfiles% (x86)");
for the 32-bit folder on 64-bit PC's.
Also, it works on any language in Windows Vista and newer. Calling either of the posted responses will work on any language installation, in fact.
For 32 bit use:
System.out.println(System.getenv("ProgramFiles(X86)"));
For 64 bit use:
System.out.println(System.getenv("ProgramFiles"));
Use the System.getenv() method:
public class EnvironmentVariableExample {
public static void main(String[] args) {
System.out.println(System.getenv("ProgramFiles"));
System.out.println(System.getenv("MadeUpEnvVar"));
}
}
If the variable doesn't exist, it will simply return null.
Related
As i am from testing background and have a very limited knowledge on Java kindly excuse me if the question i have asked is not good or repetitive.
I am trying to build an application using Java Swing. As per the requirement I have to display 32 bit Jre or 64 bit Jre installed on laptop based on the selection made. Frame which i developed for this
Unfortunately when I tested by installing a 32 bit JRE on Windows 64 bit machine and tried to run my application, when I choose the radio button "64 bit JRE" , in the drop down list its displaying me the 32 bit JRE which is installed on my system. (Kindly note i do not have any 64 bit JRE installed on my system). Ideally it should not display anything but the default value set in the JComboBox. :(
I understood the JRE was picked due to the Windows property. I tried with the API Advapi32.INSTANCE using the method RegGetValue but i am unable to get the value from Windows Registry.
32 bit JRE are under the path : HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node \JavaSoft\Java Runtime Environment
and 64 bit JRE are under the path : HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment
Please find the below code which i tried to retrieve 64 bit JRE :
String[] val64 = RegistryCheck.getRegistryDataForJRE(HKEY_LOCAL_MACHINE, "SOFTWARE\\JavaSoft\\Java Runtime Environment");
public static String[] getRegistryDataForJRE(WinReg.HKEY root, String key) {
if (Advapi32Util.registryKeyExists(root, key)) {
return Advapi32Util.registryGetKeys(root, key);
} else {
return null;
}
}
Also below is the code which i tried with Advapi32.INSTANCE (just ttried to do a sysout to know whether the value returned is 0 or not. as from the Microsoft pages i see if its a non zero value returned its an error
public static void main(String[] args) {
byte[] b = new byte[50];
IntByReference pcbData = new IntByReference(50);
System.out.println(Advapi32.INSTANCE.RegGetValue(HKEY_LOCAL_MACHINE, "SOFTWARE\\JavaSoft\\Java Runtime Environment",
"" , 0x0200, pcbData, b, pcbData));
}
Also, I read the flag KEY_WOW64_32KEY is the responsible to pick up from the WOW6432Node , but i am not able to check the flag value or to set it to false in java.
Can anyone help me with this issue ?
I would be really grateful for the help.
Thank you in advance for the support.
try to use the method RegOpenKeyEx() of Advapi32 i.e. syntax
RegOpenKeyEx(WinReg.HKEY hKey,
String lpSubKey,
int ulOptions,
int samDesired,
WinReg.HKEYByReference phkResult)
refer to the link RegOpenKeyEx()
You can pass the parameters accordingly and then check if the return value is "0" then the path exists in 64 bit else it doesn't exists.
Note : when you pass "samDesired" into the RegOpenKeyEx() pass the combination of KEY_QUERY_VALUE and KEY_WOW64_64KEY
For example :
WinReg.HKEYByReference hKey = new HKEYByReference();
Advapi32.INSTANCE.RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\JavaSoft\\Java Runtime Environment",0, 0x0001 | 0x0100, hKey);
Let me know if it worked for you
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.
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.
I,m looking for some method that can let me obtain (in windows) the directory where windows is saved (for example in my PC it will return "C:\windows".
I need it because I have to call this method
public static void openFileWithNotepad(String pathFileTxt) throws InterruptedException, IOException
{
if(System.getProperty("os.name").toUpperCase().contains("Windows".toUpperCase()))
{
String program = "C:/WINDOWS/system32/notepad.exe";
Process p = Runtime.getRuntime().exec(program + " " + pathFileTxt);
}
...
}
I want to use some method to switch "C:/WINDOWS" with the OS installation folder, in order to use this program on different pcs.
P.S.: If someone know, I'd like also to know how to use this method on UNIX OSs :)
Thank you for understanding!
Desktop.getDesktop().open(new File(pathFileTxt));
Works for any file for which there is an associated program, on any OS that supports Java 1.6+. See Desktop.open(File) for details.
i believe this should work:
System.getenv("WINDIR")
also, notepad doesn't tend to exist on unix, so i'm not sure where you are going with that...
try
System.getenv("windir")
for windows.
I'm not sure about other OSs.
System.getenv("WINDIR") may work for you.
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.