2012-06-14 14 views
12

Próbuję uruchomić zewnętrzny plik wykonywalny, ale najwyraźniej potrzebuje on podniesienia. Kod jest to, modyfikowany przykład stosując ProcessBuilder (stąd tablicy z jednym argumentem):Podnoszenie procesu ProcessBuilder przez UAC?

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

Zwraca to podczas uruchamiania:

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 

Zrobiłem trochę przeglądanie wokół, i Wiadomo, że w C#, można zażądać podniesienie w ten sposób, (jak widać z this thread):

startInfo.Verb = "runas"; 

jednak nie widzę nic takiego z ProcessBuilder. Inną metodą byłoby zainstalowanie Elevation Tools w systemie docelowym i wywołanie zachęty "podnieś" za pomocą ProcessBuilder. Wolałbym jednak nie zmuszać ludzi, którzy używają mojego programu, do zainstalowania tych narzędzi elewacyjnych.

Czy istnieje inny sposób?

Odpowiedz

12

Nie można tego zrobić przy pomocy ProcessBuilder, musisz zadzwonić do Windows API.

Użyłem JNA to osiągnąć z kodem podobnym do następującego:

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

Dzięki za szybką odpowiedź! Przetestuję to w zakresie mojej aplikacji i dam ci znać, jak to działa. –

+0

Program elewacyjny działa świetnie. Dziękuję Ci bardzo! –

+0

Czy istnieje sposób na uniknięcie pojawienia się potwierdzenia (uruchom jako administrator) za pomocą kodu? – Affi

0

Prunge „s odpowiedź działa dobrze dla mnie. Ale po zrobieniu trochę więcej badań, odkryłem inne podejście przy użyciu skryptu vb i pliku wsadowego. Ja wolę th jest podejście, ponieważ używanie vb-script nie powoduje pojawienia się czarnego okna cmd za każdym razem, kiedy otwieram swoją aplikację.

  1. Utwórz zwykły plik bat, aby otworzyć zewnętrzny plik wykonywalny. mam zamiar otworzyć plik wykonywalny serwera MySQL

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

  3. Teraz utworzyć skrypt vb z uprawnieniami administratora, a na końcu dodać skrypt do otwarcia pliku mysql.bat .

Na CreateObject końcowego ("Wscript.Shell"). Run uruchamia mysql.bat pliku 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. Teraz zapisz ten plik jako mysql_start.vbs
  2. Wreszcie Uruchom skrypt vb z java.

to wszystko

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); 
     } 
Powiązane problemy