Задача: запустить стороннюю программу и передать ей две строки.
Собственно функция:
int App::RunExternalProgramWithInput(const std::filesystem::path &programPath,
const std::string &firstInput,
const std::string &secondInput) {
const std::string pp = programPath.string();
const std::string current_dir = programPath.parent_path().string();
const std::wstring tmp_wstr(pp.begin(), pp.end());
const std::wstring tmp_wpath(current_dir.begin(), current_dir.end());
// Создание канала для ввода дочернего процесса
HANDLE hChildStdinRd = nullptr, hChildStdinWr = nullptr;
SECURITY_ATTRIBUTES saAttr = {};
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = nullptr;
if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) {
throw std::runtime_error("Не удалось создать канал для stdin");
}
// Настройка атрибутов процесса
STARTUPINFO si = {};
si.cb = sizeof(STARTUPINFO);
si.hStdInput = hChildStdinRd;
si.dwFlags |= STARTF_USESTDHANDLES;
PROCESS_INFORMATION pi = {};
// Запуск процесса
if (!CreateProcess(tmp_wstr.data(), // Имя исполняемого файла
nullptr, // Аргументы командной строки
nullptr, // Дескриптор процесса
nullptr, // Дескриптор потока
TRUE, // Наследование дескрипторов
0, // Флаги создания
nullptr, // Среда
tmp_wpath.data(), // Рабочая директория
&si, // Настройки запуска
&pi // Информация о процессе
)) {
CloseHandle(hChildStdinRd);
CloseHandle(hChildStdinWr);
throw std::runtime_error("Не удалось запустить процесс");
}
// Закрытие дескриптора чтения (он уже используется дочерним процессом)
CloseHandle(hChildStdinRd);
// Передача первой строки
std::string firstInputWithNewline = firstInput + "\n";
DWORD dwWritten;
if (!WriteFile(hChildStdinWr, firstInputWithNewline.c_str(), firstInputWithNewline.size(),
&dwWritten, nullptr)) {
TerminateProcess(pi.hProcess, 1);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hChildStdinWr);
throw std::runtime_error("Не удалось записать первую строку ввода");
}
// Передача второй строки
std::string secondInputWithNewline = secondInput + "\n";
if (!WriteFile(hChildStdinWr, secondInputWithNewline.c_str(), secondInputWithNewline.size(),
&dwWritten, nullptr)) {
TerminateProcess(pi.hProcess, 1);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hChildStdinWr);
throw std::runtime_error("Не удалось записать вторую строку ввода");
}
// Закрытие канала для сигнализации конца ввода
CloseHandle(hChildStdinWr);
// Ожидание завершения процесса
WaitForSingleObject(pi.hProcess, INFINITE);
// Получение кода завершения
DWORD exitCode = 0;
if (!GetExitCodeProcess(pi.hProcess, &exitCode)) {
exitCode = 1; // Предполагаем ошибку, если не удалось получить код
}
// Очистка ресурсов
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return static_cast<int>(exitCode);
}
Всё работает как надо.
Но каждый раз выполнение этой функции происходит с разным количеством времени и
очень медленно. Рекорд - ~8сек. Т.е. запускаем функцию и она выполняется очень медленно и с совершенно разным временем выполнения.
Запускается одна и та же программа, длина передаваемых строк фиксирована - 32 символа.
Нашел ещё одну странность - если запускать основное приложение от имени администратора, то никаких "подвисаний" нет. Всё работает быстро.
Вопрос: почему такое может просходить? и как это исправить?
П.с. это относится к вопросу косвенно, до этого писал такую же функцию на
Go через
subProcess := exec.Command(readini.GetIniData().ExeFilePath)
stdin, err := subProcess.StdinPipe()
и всё работает отлично, никаких сбоем в работе и т.д. запускаемая программы теже. Т.е. выполняться всё может корректно, быстро и дело не в запускаемой программе.