Java on Windows: Test if a Java application is run

2020-04-07 05:19发布

Situation

I have an (Eclipse RCP-based) Java application running on multiple platforms. I got this figured out on all platforms except Windows.

Installer: My application installer is always run in elevated mode, so it can install the application to C:\Program files\MyProduct. From a user perspective, this means the installer can only be executed by an Administrator and the UAC will ask for confirmation. This works fine.

Normal usage: The application can be launched by normal users. No administrator privileges should be required. This works fine.

Auto-update: The auto-update functionality also writes to C:\Program Files\MyProduct and therefore also requires administrator privileges. That's why the application, while it can be launched as a normal application too, MUST be run as an elevated process to auto-update. From a user perspective, it should be 'Run as administrator' to auto-update.

Question

I would like a runtime check to see if my Java process is in elevated mode (i.e. to see if it was 'Run as administrator'.

Note it may be a Windows-only solution. Using the Java reflection API, I can check for the Windows- and/or implementation-specific classes at runtime.

Research

I only found this question on StackOverflow: Detect if Java application was run as a Windows admin

However, that solution returns whether the active user is a member of the Administrator group. The user may still have my application launched in non-elevated mode. I have verified this.

Note

I know that an Eclipse RCP application will automatically install updates in the user directory, when he or she has no administrator privileges, but I want to block that case.

I want to allow user-specific configuration (which works fine), but allowing user-specific updates would leave too much mess after uninstallation.

2条回答
We Are One
2楼-- · 2020-04-07 05:46

This is what the Eclipse LocationManager does to determine if it can write to the install directory:

public static boolean canWrite(File installDir) {
    if (installDir.canWrite() == false)
        return false;

    if (!installDir.isDirectory())
        return false;

    File fileTest = null;
    try {
        // we use the .dll suffix to properly test on Vista virtual directories
        // on Vista you are not allowed to write executable files on virtual directories like "Program Files"
        fileTest = File.createTempFile("writtableArea", ".dll", installDir);
    } catch (IOException e) {
        //If an exception occured while trying to create the file, it means that it is not writable
        return false;
    } finally {
        if (fileTest != null)
            fileTest.delete();
    }
    return true;
}

Note the attempt to create a dll

查看更多
3楼-- · 2020-04-07 05:49

Using JNA and the Win32 IsUserAnAdmin function:

import com.sun.jna.LastErrorException;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.win32.StdCallLibrary;

public class WindowsAdminUtil {

   public interface Shell32 extends StdCallLibrary {

      boolean IsUserAnAdmin() throws LastErrorException;
   }
   public static final Shell32 INSTANCE =
           Platform.isWindows() ?
           (Shell32) Native.loadLibrary("shell32", Shell32.class) : null;

   public static boolean isUserWindowsAdmin() {
      return INSTANCE != null && INSTANCE.IsUserAnAdmin();
   }
}

According to the MS docs, IsUserAnAdmin() might not exist in future versions of Windows. So an even better method would be to use JNA to call the CheckTokenMembership function. However, doing that is more complex, so the above code is what I am using today.

查看更多
登录 后发表回答