Java InvocationTargetException и недопустимые ошибки доступа к памяти
У меня есть Java-программа (обернутая в exe), которая запускает другую основную Java-программу (также обернутую в exe), которая имеет манифест администратора. Из-за манифеста администратора я использую сценарий Shell32X для взаимодействия с приглашением UAC для запуска основной программы.
Вот скрипт Shell32X:
import java.util.Arrays;
import java.util.List;
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 dwHotKey;
public int fMask;
public HINSTANCE hInstApp;
public HKEY hKeyClass;
public HANDLE hMonitor;
public HANDLE hProcess;
public HWND hwnd;
public WString lpClass;
public WString lpDirectory;
public WString lpFile;
public Pointer lpIDList;
public WString lpParameters;
public WString lpVerb;
public int nShow;
/*
* Actually:
* union {
* HANDLE hIcon;
* HANDLE hMonitor;
* } DUMMYUNIONNAME;
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected List getFieldOrder() {
return Arrays.asList(new String[] {
"cbSize",
"dwHotKey",
"fMask",
"hInstApp",
"hKeyClass",
"hMonitor",
"hProcess",
"hwnd",
"lpClass",
"lpDirectory",
"lpFile",
"lpIDList",
"lpParameters",
"lpVerb",
"nShow"
});
}
}
}
Вот код в программе запуска, которая вызывает приглашение UAC и запускает основную программу:
public static void main(String[] args)
throws IOException, InterruptedException, InvocationTargetException {
call("MainProgram.exe", "");
}
public static void call(String command, String args) throws InvocationTargetException
{
lock.lock();
try {
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 + ")");
}
} finally {
lock.unlock();
}
return;
}
(игнорировать lock(), это связано с чем-то другим)
Программа запуска должна взаимодействовать с приглашением UAC и вызывать основную программу.
Когда я запутываю код, основная программа работает нормально, а программа запуска работает нормально, ЗА ИСКЛЮЧЕНИЕМ приглашения UAC не появляется и основная программа не вызывается.
Я экспортирую в качестве работающей фляги и с необходимыми библиотеками, упакованными в флягу. Я использую ProGuard, чтобы запутать банки и Launch4j, чтобы обернуть банки в exe.
Это ошибка, которую я получаю при запуске программы запуска:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(Unknown Source)
Caused by: java.lang.Error: Invalid memory access
at com.sun.jna.Native.getWideString(Native Method)
at com.sun.jna.Pointer.getWideString(Pointer.java:685)
at com.sun.jna.Pointer.getValue(Pointer.java:414)
at com.sun.jna.Structure.readField(Structure.java:720)
at com.sun.jna.Structure.read(Structure.java:580)
at com.sun.jna.Structure.autoRead(Structure.java:2074)
at com.sun.jna.Function.invoke(Function.java:374)
at com.sun.jna.Library$Handler.invoke(Library.java:244)
at com.sun.proxy.$Proxy0.ShellExecuteEx(Unknown Source)
at launcher.Launcher.call(Unknown Source)
at launcher.Launcher.main(Unknown Source)
... 5 more
Я исследовал это в течение 3 дней, и я до сих пор не знаю, что это значит или как это исправить. Пожалуйста, помогите мне.
ОБНОВИТЬ:
Я добавил исключение InvocationTargetException в мой метод call(). Это новое сообщение об ошибке:
java.lang.Error: Structure.getFieldOrder() on class launcher.Shell32X$SHELLEXECUTEINFO does not provide enough names [15] ([cbSize, dwHotKey, fMask, hInstApp, hKeyClass, hMonitor, hProcess, hwnd, lpClass, lpDirectory, lpFile, lpIDList, lpParameters, lpVerb, nShow]) to match declared fields [6] ([fMask, hInstApp, lpFile, lpParameters, lpVerb, nShow])