Связь с программой C++ из java

Я хочу выполнить внешнюю программу .exe из java. .exe — это приложение CLI, которое принимает ввод во время выполнения (scanf()) и выводит в зависимости от ввода. Я могу вызвать программу для выполнения из java, используя

Process p = Runtime.getRuntime().exec("cmd /c start a.exe");

вместо

Process p = Runtime.getRuntime().exec("cmd /c start a.exe");

Но я думаю, что также можно вызвать программу из java. У меня вся программа написана на С++, просто нужен графический интерфейс, написанный на java. Есть несколько вещей, на которые стоит обратить внимание :=

1) Связь с .exe должна быть во время выполнения (не через main(args) ) 2) Программа Java должна принимать выходные данные и сохранять их в некоторой переменной/панели для использования в будущем 3) Выполняемая программа может отличаться (например пользователь может выбрать .exe, который вообще не принимает никаких входных данных) ........ Таким образом, в основном графический интерфейс Java будет действовать как RuntimeEnv

 public void runEXE() 

       {
            String s = null;

            try {
                Process p = Runtime.getRuntime().exec("cmd /c a.exe");
                System.exit(0);
            }
            catch (IOException e) {
                System.out.println("exception happened - here's what I know: ");
                e.printStackTrace();
                System.exit(-1);
            }

       }

Я знаю, что есть много вопросов по этой теме. Но я не могу найти ни одного из них очень полезным.


person shababhsiddique    schedule 07.05.2011    source источник


Ответы (7)


Довольно уродливая маленькая функция, которую я использую. Это принимает команду, которая будет передана Runtime.getRuntime().exec, затем сохраняет результаты в строку и возвращает строку в конце. Вы можете выбрать, хотите ли вы только последнюю строку (или весь вывод) и хотите ли вы сохранить строку stdout или stderr из процесса.

private static String systemResult(String cmd, boolean append, boolean useErr)
    {
    String result = "";
    try{
        // spawn the external process
        //printCmd(cmd);
        Process proc = Runtime.getRuntime().exec(cmd);
        LineNumberReader lnr1 = new LineNumberReader(new InputStreamReader(proc.getErrorStream()));
        LineNumberReader lnr2 = new LineNumberReader(new InputStreamReader(proc.getInputStream()));
        String line;
        int done = 0;
        while(lnr1 != null || lnr2 != null){
        try{
            if(lnr1.ready()){
            if((line = lnr1.readLine()) != null){
                //System.err.println("A:" +line);
                if(useErr){
                if(append) result = result + line + "\n";
                else result = line;
                }
            }
            }else if(done == 1){
            done = 2;
            }
        }catch(Exception e1){
            try{ lnr1.close(); }catch(Exception e2){}
            lnr1 = null;
        }

        try{
            if(lnr2.ready()){
            if((line = lnr2.readLine()) != null){
                //System.err.println("====>Result: " + line);
                if(!useErr){
                if(append) result = result + line + "\n";
                else result = line;
                }
            }
            }else if(done == 2){
            break;
            }
        }catch(Exception e1){
            try{ lnr2.close(); }catch(Exception e2){}
            lnr2 = null;
        }

        try{
            proc.exitValue();
            done = 1;
        }catch(IllegalThreadStateException itsa){}
        }
        if(lnr1 != null) lnr1.close();
        if(lnr2 != null) lnr2.close();

        try{
        proc.waitFor();
        }catch(Exception ioe){
        }finally{
        try{
            proc.getErrorStream().close();
            proc.getInputStream().close();
            proc.getOutputStream().close();
        }catch(Exception e){}
        proc = null;
        }
    }catch(Exception ioe){
    }
    return result;
    }
person Femi    schedule 07.05.2011

Вы можете использовать JNI, как предлагает @linuxuser27, или вы можете использовать SWIG, который помогает сделать процесс общения с Java --> C++ немного менее болезненно.

person debracey    schedule 07.05.2011

Буферы протокола Google будут хорошим вариантом для совместимости Java/C++.

Буферы протоколов — это независимый от языка и платформы расширяемый механизм Google для сериализации структурированных данных — подумайте о XML, но меньше, быстрее и проще. Вы один раз определяете, как должны быть структурированы ваши данные, а затем можете использовать специально сгенерированный исходный код, чтобы легко записывать и считывать структурированные данные в различные потоки данных и из них с использованием различных языков — Java, C++ или Python.

person Taylor Leese    schedule 07.05.2011

Я бы посмотрел на JNI и использовал некоторый тип IPC для связи с проектом C++.

Обновление:

JNI — это способ взаимодействия Java с базовой собственной средой, в которой работает JRE. Этот метод потребует от вас создания библиотеки DLL, загружаемой в JRE при запуске вашей Java-программы. Затем эта JNI-библиотека DLL будет содержать метод, который можно вызвать из вашей Java-программы и передать данные в JNI-библиотеку DLL, которая затем сможет взаимодействовать с проектом C++ через именованный канал или общую память.

Именованный канал будет создан с помощью CreateNamedPipe Win32 API. В JNI DLL вы, скорее всего, создадите сервер а в проекте C++ вы должны создать клиент. Обратите внимание, что пример сервера является многопоточным, но для простоты его можно легко преобразовать в однопоточную модель.

Обратите внимание, что это не простая задача. Другие ответы предлагают несколько более простых подходов, JNA и передачу данных на C++ проект через стандартный ввод.

person linuxuser27    schedule 07.05.2011
comment
На какой ОС вы это запускаете? - person linuxuser27; 07.05.2011

Несколько вещей:

  • Прежде всего, если вы еще этого не сделали, прочитайте эту критически важную статью: Когда Runtime.exec не работает
  • Далее, есть несколько способов взаимодействия Java с другими приложениями, и, вероятно, самый простой из них — через стандартные потоки ввода и вывода. Вы пробовали использовать эти?
  • Затем есть JNI и более простая JNA, но вы заявили, что ваша программа на C++ работает через CLI, что говорит мне о том, что у вас есть .NET dll, а не настоящая dll Windows. Это так? Если это так, то это затруднит взаимодействие между Java и C++.
person Hovercraft Full Of Eels    schedule 07.05.2011
comment
я, кажется, не нашел тот, который делает ввод-вывод одновременно - person shababhsiddique; 07.05.2011
comment
@shababhsiddique: для этого вам нужно будет использовать отдельные потоки. На последней странице статьи, на которую я ссылался выше, показан простой пример этого. - person Hovercraft Full Of Eels; 07.05.2011
comment
Вам лучше начать с учебных пособий Oracle Java по многопоточности и другим основам Java, потому что в противном случае вы будете испытывать много боли, поскольку будете изучать вещи не по порядку. Сначала научитесь использовать потоки и основы Java, прежде чем пытаться соединить Java с C/C++. - person Hovercraft Full Of Eels; 08.05.2011

  1. Вы можете запускать программы .exe напрямую. Вам просто нужно указать полный путь. Относительный путь также будет в порядке.

  2. Вы можете использовать каналы для взаимодействия с внешним процессом: Отправка ввода в команду, Чтение вывода команды

person Peter Knego    schedule 07.05.2011
comment
Вы можете объединить оба примера в одну программу. Осторожно, вам нужно выполнять ввод в отдельном потоке, так как он использует блокировку чтения(). - person Peter Knego; 07.05.2011
comment
И это мой вопрос здесь .. как - person shababhsiddique; 08.05.2011
comment
Что-то вроде StreamGobbler в этом примере: javaworld .com/javaworld/jw-12-2000/jw-1229-traps.html?page=4 - person Peter Knego; 08.05.2011