Повышение процесса ProcessBuilder через UAC?
Я пытаюсь запустить внешний исполняемый файл, но, видимо, он требует повышения прав. Код такой, модифицированный из примера использования ProcessBuilder (отсюда и массив с одним аргументом):
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();
}
}
Он возвращает это при запуске:
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
Я немного просмотрел и знаю, что в C# вы можете запросить повышение прав, выполнив это (как видно из этой темы):
startInfo.Verb = "runas";
Тем не менее, я не вижу ничего подобного в ProcessBuilder. Другим способом было бы установить Elevation Tools в целевой системе и вызвать приглашение "поднять" с ProcessBuilder. Однако я бы не стал заставлять людей, использующих мою программу, также устанавливать эти инструменты повышения прав.
Есть ли другой способ?
2 ответа
Это не может быть сделано с ProcessBuilder, вам нужно будет вызвать Windows API.
Я использовал JNA для достижения этой цели с помощью кода, подобного следующему:
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 + ")");
}
}
}
Ответ Prunge отлично работает для меня. Но после небольшого исследования я нашел другой подход, использующий скрипт vb и командный файл. Я предпочитаю этот подход, потому что использование скрипта vb не вызывает появление черного окна cmd каждый раз, когда я открываю свое приложение.
Создайте обычный bat-файл, чтобы открыть внешний исполняемый файл. Я собираюсь открыть исполняемый файл сервера MySQL
@echo off cd "C:\Program Files (x86)\MySQL\MySQL Server 5.6\bin" :: Title not needed: start /MIN mysqld.exe exit
Сохранить как mysql.bat
Теперь создайте скрипт vb с правами администратора и в конце добавьте скрипт, чтобы открыть файл mysql.bat.
В конце CreateObject("Wscript.Shell").Run запускает файл 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
- Теперь сохраните этот файл как mysql_start.vbs
- Наконец запустить скрипт VB из Java.
Это оно
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);
}