I have a java program (wrapped in an exe) that launches another main java program (also wrapped in an exe) which has an admin manifest. Because of the admin manifest, I use a Shell32X script to interact with the UAC prompt to launch the main program.
Here's the Shell32X script:
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"
});
}
}
}
Here's the code in the launcher program which calls the UAC prompt and launches the main program:
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;
}
(disregard lock(), it has to do with something else)
The launcher program is supposed to interact with the UAC prompt and call the main program.
When I obfuscate the code, the main program runs fine, and the launcher runs fine, EXCEPT the UAC prompt doesn't come up and the main program isn't called.
I export as a runnable jar and with the required libraries packaged into the jar. I'm using ProGuard to obfuscate the jars and Launch4j to wrap the jars into an exe.
This is the error I get when I run the launcher program:
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
I have been researching this for 3 days and I still have no idea what this means or how to fix it. Please help me.
UPDATE:
I added a throw InvocationTargetException to my call() method. This is the new error message:
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])
User contributions licensed under CC BY-SA 3.0