Как создать исполняемый файл Windows, который не требует, чтобы пользователи Vista / Win7 устанавливали распространяемый Visual C ++? - PullRequest
0 голосов
/ 05 декабря 2018

Я написал программу на Java, ориентированную на Windows Vista и Windows 10.

Программа работает во встроенной среде выполнения Java, поэтому пользователю не нужно возиться с установкой Java, чтобы заставить ее работать, Цель этого проекта - загрузить пользовательский интерфейс -> запустить один установщик -> запустить программу и заставить его чувствовать себя как родной .Никаких других шагов от пользователя не требуется.

Для достижения этой цели мне нужно было написать собственный исполняемый файл на C ++, который вызывает JVM напрямую (а не вызывая java.exe), поэтому Windows TakBarфункция закрепления работает правильно - если я использую исполняемую оболочку, такую ​​как launch4j , для передачи выполнения в java.exe в любой момент, тогда закрепление не работает так, как должно.Мой собственный исполняемый файл должен оставаться запущенным в течение всей программы, чтобы закрепление работало правильно.

Я написал собственную программу запуска C ++, которая использует JNI для вызова виртуальной машины Java через jvm.dll вместо java.exe, и она работает.Это 100-строчная прокладка (код внизу этого поста).Он импортирует только windows.h и использует следующие функции: HINSTANCE, GetProcAddress, WinMain.Он явно ссылается на встроенный jvm.dll во время выполнения.

Однако, если я скомпилирую эту оболочку с помощью Visual Studio 2017, результирующий исполняемый файл зависит от того, какой пользователь установил распространяемый Visual C ++ 2015.Если этого не произойдет, программа выдаст ошибку «Не удается запустить, потому что VCRUNTIME140.dll отсутствует на вашем компьютере».

Я попытался скомпилировать эту программу, используя флаг / MT, а такжевыбрав «Использовать MFC в статической библиотеке» на странице общих свойств проекта Visual Studio. Это не имеет значения; я получаю одну и ту же ошибку независимо от этого.

Хотя многие пользователи Windows Vista / Windows 7 будутУ меня уже установлены среды выполнения, а некоторые могут и не быть, и мой приоритет для этого проекта - плавное, безошибочное взаимодействие пользователей от загрузки до установки.

У меня нет проблем с объединением дополнительных библиотек с моим проектом.У меня нет проблем с компиляцией с MinGW или Cygwin, если это имеет смысл. Единственное, что мне нужно, это какой-то гарантированный путь к download -> install -> run для любой версии Windows от Vista до Windows 10.

Как создать исполняемый файлкоторая стоит отдельно или может быть распространена вместе с несколькими библиотеками dll, так что она автономна в Vista и nкогда-либо версия Windows?


Минимальный завершенный проверяемый пример: Вы можете скачать zip или сделать все вручную самостоятельно, выполнив следующие действия:

Шаг 1 - Инициализация: Создайте папку josh-problem.

Шаг 2 - Загрузите JRE: Загрузите Windows 64-битный zip-файл Java 11 и поместитеон josh-problem/jre такой, что содержимое josh-problem/jre - это java-папки с именами lib, legal, jmods, include, conf, bin и т. д.

Шаг 3 - Настройка Java-программы: Создать josh-problem/src/net/joshuad/test/Main.java.Сделать его содержимое:

package net.joshuad.test;

public class Main {
    public static void main(String[] args) {
        System.out.println ( "Hi from Java, launched via embedded jre, via native executable." );
    }
}

Шаг 4 - Создать манифест Создать файл josh-problem\MANIFEST.MF с содержанием в одну строку:

Main-Class: net.joshuad.test.Main 

Шаг 5- Скомпилируйте и создайте main.jar : перейдите в папку josh-problem в cmd.exe.Выполните следующие команды:

  • jre\bin\javac.exe -d bin src\net\joshuad\test\Main.java
  • jre\bin\jar.exe cfm main.jar MANIFEST.MF -C bin .

Шаг 6 - Подтвердите работу баночки : Запуститекоманда:

jre\bin\java.exe -jar main.jar

Вы должны увидеть вывод: «Привет из Java, запущен через встроенный jre, через собственный исполняемый файл.»

Шаг 7 -Скомпилируйте Native Launcher Создайте проект в Visual Studio 2017 и передайте ему один файл cpp с исходным кодом в самом низу этого поста.Добавьте в свои списки josh-problem\jre\include и josh-problem\jre\include\win32.

Шаг 8 - Попробуйте запустить - Переместите исполняемый файл вывода в josh-problem.Попробуйте запустить исполняемый файл на чистой машине с Windows 7 с пакетом обновления 1.Это выдаст ошибку: «Программа не может запуститься, потому что VCRUNTIME140D.dll отсутствует на вашем компьютере.».

Шаг 9 - Запуск через java - На том же чистом компьютере с Windows 7 запустите программу, вызвав java.exe, она работает.

jre\bin\java.exe -jar main.jar

Шаг 10 - Установите распространяемый Visual C ++ и попробуйте наш exe снова - Загрузите и установите 2015 распространяемый Visual C ++ начистая машина Windows 7.Попробуйте наш исполняемый файл снова.Это работает.

** Как мне скомпилировать этот код, чтобы он не нуждался в распространяемом Visual C ++?Я знаю, что это возможно, потому что мы только что продемонстрировали, что делает java.exe.Как мне сделать, чтобы моя программа это сделала? *

Загрузки Я знаю, что этот вопрос довольно полный.Для вашего удобства я проделал вышеуказанную работу и поместил в zip-файл для загрузки , который включает в себя jar, исходный код java, исходный код C ++ и результирующий исполняемый файл.Вам нужно будет скачать jre, используя вышеуказанную ссылку на папку jre;Я не хотел создавать огромный почтовый индекс.

Я также загрузил свой визуальный студийный проект в zip .

win-launcher.cpp

#include <jni.h> 
#include <windows.h>

typedef UINT(CALLBACK* JVMDLLFunction)(JavaVM**, void**, JavaVMInitArgs*);

int main(int argc, char** argv) {

    HINSTANCE jvmDLL = LoadLibrary(".\\jre\\bin\\server\\jvm.dll");

    if (!jvmDLL) {
        printf("failed to find jvm.dll at specified location, exiting.\n");
        return 1;
    }

    JVMDLLFunction createJavaVMFunction = (JVMDLLFunction)GetProcAddress(jvmDLL, "JNI_CreateJavaVM");

    if (!createJavaVMFunction) {
        printf("Failed to get pointer to JNI_CreateJavaVM function from jvm.dll, exiting\n");
        return 1;
    }

    JavaVM *jvm;
    JNIEnv *env;
    JavaVMInitArgs vm_args;
    JavaVMOption* options = new JavaVMOption[1];

    int index = 0;
    options[index].optionString = (char *)"-Djava.class.path=./main.jar";

    vm_args.version = JNI_VERSION_10;
    vm_args.nOptions = 1;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = false;

    createJavaVMFunction(&jvm, (void**)&env, &vm_args);

    delete options;

    jmethodID main = NULL;
    jclass cls = NULL;

    cls = env->FindClass("net/joshuad/test/Main");
    if (env->ExceptionCheck()) {
        env->ExceptionDescribe();
        env->ExceptionClear();
        printf("Unable to find net.joshuad.hypnos.Main, exiting.\n");
        return 0;
    }

    if (cls != NULL) {
        main = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V");
    }
    else {
        printf("Unable to find main() in java\n");
        return 0;
    }

    if (main != NULL) {
        jclass classString = env->FindClass("java/lang/String");
        jobjectArray argsToJava = env->NewObjectArray(argc - 1, classString, NULL);
        for (int i = 1; i < argc; i++) {
            printf("Converting: %s", argv[i]);
            jstring arg = env->NewStringUTF(argv[i]);
            env->SetObjectArrayElement(argsToJava, i - 1, arg);
        }

        env->CallStaticVoidMethod(cls, main, argsToJava);

    }
    else {
        printf("main method not found");
    }

    jvm->DestroyJavaVM();
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    return main(__argc, __argv);
}

Ответы [ 3 ]

0 голосов
/ 05 декабря 2018

Если ваш собственный код небольшой и использует только базовую стандартную библиотеку C или функции Win32, тогда вы можете обойтись без сборки с MinGW, которая связывается с msvcrt.dll вместо msvcr1xx.dll для вызовов CRT, поэтому не будетзависимость от библиотек VC ++ (сборка с флагом -static для встраивания libstdc ++ в случае использования стандартных функций библиотеки C ++).

В противном случае просто соберите с VC ++ с флагом /MT.Ваш исполняемый файл станет значительно больше, но это более переносимое решение.

0 голосов
/ 05 декабря 2018

Ваша проблема не в скомпилированном вами exe-файле, а в версии jre, которую вы используете.Используйте другую версию JRE или скомпилируйте свою собственную версию, разветвленную из OpenJDK

enter image description here

В качестве альтернативы добавьте \jre\bin в путь поиска библиотеки, поскольку библиотека DLL расположенатам.

Например, с SetDllDirectoryA("jre\\bin")

0 голосов
/ 05 декабря 2018

Вам не нужно указывать конкретный SDK, просто измените «c ++», «генерация кода», «библиотека времени выполнения» на «многопоточная» или «многопоточная отладка», чтобы статически связать со средами исполнения Visual Studio,Это сделает ваше приложение больше, но это будет зависеть только от библиотек Windows.

...