情况
我有一个(基于Eclipse RCP的)Java应用程序运行在多个平台上。 我在除Windows以外的所有平台上都弄清楚了这一点。
安装程序 :我的应用程序安装程序始终以提升模式运行,因此它可以将应用程序安装到C:\Program files\MyProduct
。 从用户angular度来看,这意味着安装程序只能由pipe理员执行,UAC将要求确认。 这工作正常。
正常使用 :应用程序可以由普通用户启动 。 不需要pipe理员权限。 这工作正常。
自动更新 : 自动更新function也写入到C:\Program Files\MyProduct
,因此也需要pipe理员权限 。 这就是为什么应用程序可以作为普通应用程序启动的原因,必须作为高级进程运行才能自动更新。 从用户的angular度来看,它应该是“ 以pipe理员身份运行 ”来自动更新。
题
我想要一个运行时检查 ,看看我的Java进程是否处于提升模式 (即查看它是否以“ pipe理员身份运行 ”)。
请注意,它可能是仅限Windows的解决scheme。 使用JavareflectionAPI,我可以在运行时检查Windows和/或特定于实现的类。
研究
我只在StackOverflow上发现这个问题: 检测Java应用程序是否作为Windowspipe理员运行
但是,该解决scheme将返回活动用户是否为pipe理员组的成员。 用户可能仍然会以非提升模式启动我的应用程序。 我已经validation了这一点。
注意
我知道一个Eclipse RCP应用程序会自动安装更新到用户目录,当他或她没有pipe理员权限,但我想阻止这种情况。
我想要允许用户特定的configuration(工作正常),但是允许用户特定的更新会在卸载后留下太多的麻烦。
这是Eclipse LocationManager
确定是否可以写入安装目录的内容:
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; }
请注意尝试创建一个DLL
使用JNA和Win32 IsUserAnAdmin函数 :
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(); } }
根据MS文档,IsUserAnAdmin()在未来的Windows版本中可能不存在。 所以更好的方法是使用JNA来调用CheckTokenMembership函数 。 但是,这样做更复杂,所以上面的代码就是我今天使用的代码。