Elevando un proceso ProcessBuilder a través de UAC?

Estoy tratando de ejecutar un ejecutable externo, pero aparentemente necesita elevación. El código es esto, modificado a partir de un ejemplo de uso de ProcessBuilder (de ahí la matriz con un argumento):

public static void main(String[] args) throws IOException { File demo = new File("C:\\xyzwsdemo"); if(!demo.exists()) demo.mkdirs(); String[] command = {"C:\\fakepath\\bsdiff4.3-win32\\bspatch.exe"}; ProcessBuilder pb = new ProcessBuilder( command ); Process process = pb.start(); InputStream is = process.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line; System.out.printf("Output of running %s is:\n", Arrays.toString(command)); while ((line = br.readLine()) != null) { System.out.println(line); } try { int exitValue = process.waitFor(); System.out.println("\n\nExit Value is " + exitValue); } catch (InterruptedException e) { e.printStackTrace(); } } 

Devuelve esto cuando se ejecuta:

 Exception in thread "main" java.io.IOException: Cannot run program "C:\Users\Gilliane\Downloads\bsdiff4.3-win32\bspatch.exe": CreateProcess error=740, The requested operation requires elevation 

He navegado un poco, y sé que en C #, puedes solicitar elevación haciendo esto (como se ve en este hilo ):

 startInfo.Verb = "runas"; 

Sin embargo, no veo nada como eso con ProcessBuilder. Otro método sería instalar las Herramientas de elevación en el sistema de destino e invocar el indicador “elevar” con ProcessBuilder. Sin embargo, preferiría no forzar a las personas que usan mi progtwig para que también instalen esas herramientas de elevación.

¿Hay otra manera?

    Esto no se puede hacer con ProcessBuilder, deberá llamar a la API de Windows.

    He usado JNA para lograr esto con un código similar al siguiente:

    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 + ")"); } } } 

    La respuesta de Prunge funciona bien para mí. Pero después de hacer un poco más de investigación, descubrí otro enfoque usando el script vb y el archivo por lotes. Prefiero este enfoque porque el uso de vb-script no hace que la ventana negra del cmd aparezca cada vez, cuando abro mi aplicación

    1. Crea un archivo bat normal para abrir el archivo ejecutable externo. Voy a abrir un archivo ejecutable del servidor MySQL

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

    3. Ahora crea un script vb con privilegios de administrador y al final agrega el script para abrir el archivo mysql.bat.

    Al final CreateObject (“Wscript.Shell”). Run ejecuta el archivo bat 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. Ahora guarde este archivo como mysql_start.vbs
    2. Finalmente ejecuta el script vb desde java.

    Eso es

      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); }