Elevating a ProcessBuilder process via UAC?

前端 未结 2 1787
春和景丽
春和景丽 2020-11-30 06:18

I\'m trying to run an external executable, but apparently it needs elevation. The code is this, modified from an example of using ProcessBuilder (hence the array with one a

相关标签:
2条回答
  • 2020-11-30 06:43

    This can't be done with ProcessBuilder, you will need to call Windows API.

    I've used JNA to achieve this with code similar to the following:

    Shell32X.java:

    import com.sun.jna.Native;
    import com.sun.jna.Pointer;
    import com.sun.jna.Structure;
    import com.sun.jna.WString;
    import com.sun.jna.platform.win32.Shell32;
    import com.sun.jna.platform.win32.WinDef.HINSTANCE;
    import com.sun.jna.platform.win32.WinDef.HWND;
    import com.sun.jna.platform.win32.WinNT.HANDLE;
    import com.sun.jna.platform.win32.WinReg.HKEY;
    import com.sun.jna.win32.W32APIOptions;
    
    public interface Shell32X extends Shell32
    {
        Shell32X INSTANCE = (Shell32X)Native.loadLibrary("shell32", Shell32X.class, W32APIOptions.UNICODE_OPTIONS);
    
        int SW_HIDE = 0;
        int SW_MAXIMIZE = 3;
        int SW_MINIMIZE = 6;
        int SW_RESTORE = 9;
        int SW_SHOW = 5;
        int SW_SHOWDEFAULT = 10;
        int SW_SHOWMAXIMIZED = 3;
        int SW_SHOWMINIMIZED = 2;
        int SW_SHOWMINNOACTIVE = 7;
        int SW_SHOWNA = 8;
        int SW_SHOWNOACTIVATE = 4;
        int SW_SHOWNORMAL = 1;
    
        /** File not found. */
        int SE_ERR_FNF = 2;
    
        /** Path not found. */
        int SE_ERR_PNF = 3;
    
        /** Access denied. */
        int SE_ERR_ACCESSDENIED = 5;
    
        /** Out of memory. */
        int SE_ERR_OOM = 8;
    
        /** DLL not found. */
        int SE_ERR_DLLNOTFOUND = 32;
    
        /** Cannot share an open file. */
        int SE_ERR_SHARE = 26;
    
    
    
        int SEE_MASK_NOCLOSEPROCESS = 0x00000040;
    
    
        int ShellExecute(int i, String lpVerb, String lpFile, String lpParameters, String lpDirectory, int nShow);
        boolean ShellExecuteEx(SHELLEXECUTEINFO lpExecInfo);
    
    
    
        public static class SHELLEXECUTEINFO extends Structure
        {
            /*
      DWORD     cbSize;
      ULONG     fMask;
      HWND      hwnd;
      LPCTSTR   lpVerb;
      LPCTSTR   lpFile;
      LPCTSTR   lpParameters;
      LPCTSTR   lpDirectory;
      int       nShow;
      HINSTANCE hInstApp;
      LPVOID    lpIDList;
      LPCTSTR   lpClass;
      HKEY      hkeyClass;
      DWORD     dwHotKey;
      union {
        HANDLE hIcon;
        HANDLE hMonitor;
      } DUMMYUNIONNAME;
      HANDLE    hProcess;
             */
    
            public int cbSize = size();
            public int fMask;
            public HWND hwnd;
            public WString lpVerb;
            public WString lpFile;
            public WString lpParameters;
            public WString lpDirectory;
            public int nShow;
            public HINSTANCE hInstApp;
            public Pointer lpIDList;
            public WString lpClass;
            public HKEY hKeyClass;
            public int dwHotKey;
    
            /*
             * Actually:
             * union {
             *  HANDLE hIcon;
             *  HANDLE hMonitor;
             * } DUMMYUNIONNAME;
             */
            public HANDLE hMonitor;
            public HANDLE hProcess;
    
            protected List getFieldOrder() {
                return Arrays.asList(new String[] {
                    "cbSize", "fMask", "hwnd", "lpVerb", "lpFile", "lpParameters",
                    "lpDirectory", "nShow", "hInstApp", "lpIDList", "lpClass",
                    "hKeyClass", "dwHotKey", "hMonitor", "hProcess",
                });
            }
        }
    
    }
    

    Elevator.java:

    package test;
    
    import test.Shell32X.SHELLEXECUTEINFO;
    
    import com.sun.jna.WString;
    import com.sun.jna.platform.win32.Kernel32;
    import com.sun.jna.platform.win32.Kernel32Util;
    
    public class Elevator
    {
        public static void main(String... args)
        {
            executeAsAdministrator("c:\\windows\\system32\\notepad.exe", "");
        }
    
        public static void executeAsAdministrator(String command, String args)
        {
            Shell32X.SHELLEXECUTEINFO execInfo = new Shell32X.SHELLEXECUTEINFO();
            execInfo.lpFile = new WString(command);
            if (args != null)
                execInfo.lpParameters = new WString(args);
            execInfo.nShow = Shell32X.SW_SHOWDEFAULT;
            execInfo.fMask = Shell32X.SEE_MASK_NOCLOSEPROCESS;
            execInfo.lpVerb = new WString("runas");
            boolean result = Shell32X.INSTANCE.ShellExecuteEx(execInfo);
    
            if (!result)
            {
                int lastError = Kernel32.INSTANCE.GetLastError();
                String errorMessage = Kernel32Util.formatMessageFromLastErrorCode(lastError);
                throw new RuntimeException("Error performing elevation: " + lastError + ": " + errorMessage + " (apperror=" + execInfo.hInstApp + ")");
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-30 06:43

    Prunge's answer works fine for me.But after doing a bit more research ,I found out another approach using vb script and batch file.I prefer this approach because using vb-script does not cause black cmd window to pop up every time,when I open my application.

    1. Create an ordinary bat file to open the external executable file. I am going to open a MySQL server executable file

      @echo off
      cd "C:\Program Files (x86)\MySQL\MySQL Server 5.6\bin"
      :: Title not needed:
      start /MIN  mysqld.exe
      exit
      
    2. Save it as mysql.bat

    3. Now create a vb script with admin privileges and at the end add script to open mysql.bat file.

    At the end CreateObject("Wscript.Shell").Run runs the bat file mysql.bat.

    Set WshShell = WScript.CreateObject("WScript.Shell")'
     If WScript.Arguments.length = 0 Then
        Set ObjShell = CreateObject("Shell.Application")
        ObjShell.ShellExecute "wscript.exe", """" & _
        WScript.ScriptFullName & """" &_
        " RunAsAdministrator", , "runas", 1
        Wscript.Quit
        End if
        CreateObject("Wscript.Shell").Run "C:\Users\Shersha\Documents\NetBeansProjects\Berries\batch\mysql.bat",0,True
    
    1. Now save this file as mysql_start.vbs
    2. Finally Run vb script from java .

    Thats it

     try {
        Runtime.getRuntime().exec("wscript C:\\\\Users\\\\Shersha\\\\Documents\\\\NetBeansProjects\\\\Berries\\\\batch\\\\mysql_start.vbs");
            } catch (IOException e) {
                                System.out.println(e);
                                System.exit(0);
            }
    
    0 讨论(0)
提交回复
热议问题