我有一个使用JNA
的应用程序,可以使用CreateProcess
api执行任何其他应用程序。这非常好,但是当我需要执行32位版本的系统本机应用程序时,正在执行64位版本(存在于SysWOW64文件夹中),例如:notepad.exe 64位。
那么,是否存在解决这个问题的方法?
我曾尝试使用Wow64DisableWow64FsRedirection
,但似乎没有用。
我的代码:
执行课程:
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.WString;
import static com.sun.jna.platform.win32.WinBase.STARTF_USESHOWWINDOW;
import static com.sun.jna.platform.win32.WinUser.SW_HIDE;
import com.sun.jna.win32.StdCallLibrary;
import java.util.Arrays;
import java.util.List;
public class Execute {
public interface Kernel32 extends StdCallLibrary {
Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
boolean CreateProcessA(
String lpApplicationName
, String lpCommandLine
, Structure lpProcessAttributes
, Structure lpThreadAttributes
, boolean bInheritHandles
, int dwCreationFlags
, Structure lpEnvironment
, String lpCurrentDirectory
, Structure lpStartupInfo
, Structure lpProcessInformation);
}
public static class ProcessInformation extends Structure {
public Pointer hProcess;
public Pointer hThread;
public int dwProcessId;
public int dwThreadId;
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[] { "hProcess", "hThread", "dwProcessId", "dwThreadId" });
}
}
public static class StartupInfoA extends Structure {
public int cb;
public WString lpReserved;
public WString lpDesktop;
public WString lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public Pointer lpReserved2;
public Pointer hStdInput;
public Pointer hStdOutput;
public Pointer hStdError;
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[] { "cb", "lpReserved", "lpDesktop", "lpTitle", "dwX", "dwY", "dwXSize", "dwYSize", "dwXCountChars", "dwYCountChars", "dwFillAttribute", "dwFlags", "wShowWindow", "cbReserved2", "lpReserved2", "hStdInput", "hStdOutput", "hStdError" });
}
}
public static void ExecuteProc(String software){
ProcessInformation processInformation = new ProcessInformation();
StartupInfoA startupInfo = new StartupInfoA();
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
startupInfo.wShowWindow = SW_HIDE;
Kernel32.INSTANCE.CreateProcessA(software, null
, null
, null
, true
, 0
, null
, "C:\\Windows\\System32\\"
, startupInfo
, processInformation);
}
}
主:
public static native boolean Wow64DisableWow64FsRedirection(PointerByReference OldValue);
public static void Exec() {
PointerByReference lpBuffer = new PointerByReference();
Wow64DisableWow64FsRedirection(lpBuffer); // fails here
String sysdir = System.getenv("WINDIR") + "\\System32\\";
ExecuteProc(sysdir + "notepad.exe");
}
答案 0 :(得分:0)
---更新因为Windows很好,Windows ---
32位可执行文件位于SysWOW64中,而64位可执行文件位于System32中。显然,这种奇怪的选择对雷德蒙德的人们来说是有意义的。
---其余的帖子如下,更新---
您要求64位程序加载并与32位可执行文件接口。 32位可执行文件的“兼容性”并未扩展到将它们链接到64位程序。
您需要启动32位JVM,以便JNI接口匹配所需的环境。
但是,您的示例可能甚至不需要JNI。如果要启动32位独立程序,则不需要使用JNI。相反,您可以使用ProcessBuilder并将命令行参数传递给shell,以有效地确保您启动32位可执行文件。
ProcessBuilder pb = new ProcessBuider(String.format("%s\\SysWOW64\\notepad.exe", System.getEnv("WINDIR"));
Process process = pb.start();
JNI适用于需要将JVM链接到本机库的情况,它不是启动本机应用程序的首选方式。您希望ProcessBuilder
启动本机应用程序。
答案 1 :(得分:0)
这可能不适合您的设置,具体取决于您的需求,但在我的公司,当我们为我们的终端服务器迁移到64位操作系统并且我们有一个内部Java时,我们遇到了这个问题需要32位版本的Java才能正常运行的应用程序。
我的解决方案是进入64位java目录,分别将java.exe
和javaw.exe
重命名为java.exe.bak
和javaw.exe.bak
,然后用存根替换那些文件推出了32位版本的Java。这在我们的案例中是可以接受的,因为我们只有一个使用Java的应用程序,我们没有预见到自己将在Java中编写更多的应用程序:
// Stub file that launches the 32-bit java.exe
// Intended to replace the 64-bit java executable to ensure that (OUR APPLICATION) which only works with 32-bit java works correctly
// Author: Govind Parmar
#include <Windows.h>
#include <strsafe.h>
HRESULT __cdecl cat_argv(int argc, WCHAR *argv[], WCHAR *argstr, int cchargstr)
{
int i;
HRESULT hr;
ZeroMemory(argstr, sizeof(WCHAR) * cchargstr);
// first arg is program name; start with i=1 instead of 0
for (i = 1; i < argc; i++)
{
// Space out arguments
hr = StringCchCat(argstr, cchargstr, L" ");
if (FAILED(hr)) break;
hr = StringCchCat(argstr, cchargstr, argv[i]);
if (FAILED(hr)) break;
}
return hr;
}
int __cdecl wmain(int argc, WCHAR *argv[])
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
WCHAR args[8192];
DWORD dwExit;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
if (FAILED(cat_argv(argc, argv, args, 8192)))
{
_putws(L"Could not concatenate argument string!");
return 0;
}
CreateProcess(L"C:\\Program Files (x86)\\Java\\jre1.8.0_101\\bin\\java.exe", args, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, NULL, L"C:\\Program Files (x86)\\Java\\jre1.8.0_101\\bin\\", &si, &pi);
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, &dwExit);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return dwExit;
}