Java JNA:如何在64位系统中使用CreateProcess执行32位版本的系统本机应用程序?

Java JNA:如何在64位系统中使用CreateProcess执行32位版本的系统本机应用程序?,java,windows,jna,Java,Windows,Jna,我有一个应用程序,它使用JNA执行使用CreateProcessapi的任何其他应用程序。这工作得很好,但当我需要执行32位版本的系统本机应用程序时,正在执行64位版本(存在于SysWOW64文件夹中),例如:notepad.exe 64位 那么,有没有办法解决这个问题呢 我曾尝试使用wow64禁用wow64fsredirection,但似乎不起作用 我的代码: 执行类: Main: ---因为Windows很好而更新,Windows--- 32位可执行文件位于SysWOW64中,而64位可执

我有一个应用程序,它使用
JNA
执行使用
CreateProcess
api的任何其他应用程序。这工作得很好,但当我需要执行32位版本的系统本机应用程序时,正在执行64位版本(存在于SysWOW64文件夹中),例如:notepad.exe 64位

那么,有没有办法解决这个问题呢


我曾尝试使用
wow64禁用wow64fsredirection
,但似乎不起作用

我的代码:

执行类:

Main:

---因为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
是您希望启动本机应用程序的方式。

这可能不适合您的设置,具体取决于您的需要,但在我的公司,当我们为终端服务器使用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;
}
//启动32位java.exe的存根文件
//旨在替换64位java可执行文件,以确保仅适用于32位java的(我们的应用程序)正常工作
//作者:戈文德·帕尔马
#包括
#包括
HRESULT\uuuuCDECL目录argv(int-argc,WCHAR*argv[],WCHAR*argstr,int-cchargstr)
{
int i;
HRESULT-hr;
零内存(argstr,sizeof(WCHAR)*cchargstr);
//第一个参数是程序名;以i=1而不是0开头
对于(i=1;i
必须使用32位JRE在64位操作系统上执行32位代码。
Wow64DisableWow64FsRedirection
用于另一种方式(当32位应用程序被迫与32位文件系统对话时,例如
C:\Program Files(x86)
C:\System\SysWOW64
。您所做的恰恰相反,只需按其绝对路径启动32位进程即可。正确的解决方案如下@edwin buck。如果您不确定如何测试您是否处于64位环境中,请检查
System.getenv(“ProgramFiles(x86)”);
您的建议仍然是执行64位版本的“notepad.exe”:-(@Saulo显然32位可执行文件不是存储在System32中,而是存储在SysWOW64中。这是一种只有Redmond的程序员才会喜欢的命名约定。从纯技术角度来看,这是有意义的,但这并不值得。(再加上更改Windows NT系统文件夹的名称可能会导致各种向后兼容性问题。)您可以取消安装64位版本,并安装32位JRE版本,以获得类似的结果,从而获得更易于支持的解决方案。现在我想知道,如今,32位版本的JVM是否存在于大部分PC上(安装了32位或64位系统)。或者在64位系统上通常是JVM 64位?@Saulo很抱歉回答得太晚,但你真的不应该根据你期望在某人的计算机上找到的内容来做出决定;你应该找出他们安装了什么,然后针对每个用例执行适当的操作
ProcessBuilder pb = new ProcessBuider(String.format("%s\\SysWOW64\\notepad.exe", System.getEnv("WINDIR"));
Process process = pb.start();
// 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;
}