Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 07.12.2018, 15:42   #1
lallollulz
Пользователь
 
Регистрация: 20.10.2018
Сообщений: 16
По умолчанию Запуск стороннего приложения из под моему и перехват управления первого

В общем у меня есть 2 программки: моя (имеется исходники) и программка--клиент (исходников которой у меня нет), которая нужна чтобы моя программа удачно конектилась к определенному серверу
т.е. для корректной работы моей программы, все время сначала запускаю эту программу-клиент вручную, затем мою. проблема в том, что моя программа осуществляет сразу несколько соединений с определенным сервером, а программа-клиент поддерживает только 1 соединение через определенный порт, который каждый раз нужно задавать вручную в этой самой программе-клиенте.
мне нужно как-то запихнуть эту программу-клиент в мою. я даже не знаю как это правильно назвать, наверно мне нужно запустить стороний exe файл (консольное приложение) из-под моего консольного приложения в соседнем потоке (так чтобы моя программа не останавливалась, пока работает программа-клиент). вот что мне подсказал гугл:
Код:
// additional information
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	// set the size of the structures
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	ZeroMemory(&pi, sizeof(pi));
	LPCWSTR filepath = L"programma-client.exe";

	// start the program up
	CreateProcess(filepath,	// the path
		NULL,				// Command line
		NULL,				// Process handle not inheritable
		NULL,				// Thread handle not inheritable
		FALSE,				// Set handle inheritance to FALSE
		0,					// No creation flags
		NULL,				// Use parent environment block
		NULL,				// Use parent starting directory 
		&si,				// Pointer to STARTUPINFO structure
		&pi					// Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
	);

	string testik3 = "введите 6113";
	cout << UTIL_UTF8ToOEM(testik3.c_str( )) << endl;
как видите я не знаю как передать строку в другую программу (процесс) поэтому приходится вводить каждый раз вручную. я поясню как устроена программа-клиент: после запуска проходит несколько секунд и появляятся разные сообщения 3-4 штуки, затем предлагается ввести число (порт, по которому будет происходить соединение). это значение нельзя передать при запуске этого файла параметром Command line в функции CreateProcess. когда запускаю эту программу из-под моей - поведение программы нечем не отличается, за исключением того что она пишет прямо в консоли моей программы (и там же вводить нужно порт) - моя программа тем временем выполняется дальше успешно (но не конектится - потому что порт не введен, если ввести (прямо в окне моей программы) - то все ок, коннект идет)
так вот вопрос: как передать это число/строку моему запущенному процессу из под моей программы? возможно можно как-то сэмулировать ввод с клавы ?
lallollulz вне форума Ответить с цитированием
Старый 07.12.2018, 16:08   #2
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

из командной строки запусти:
твоя-программа > вредная-программа-клиент

где:
твоя-программа должна сначала вывести в stdout номер порта,
и дальше может делать все что захочет.

вредная-программа-клиент считает из консоли это число (номер порта) так, словно ей в консольке кто-то его ввел вручную.
_Bers вне форума Ответить с цитированием
Старый 07.12.2018, 19:25   #3
lallollulz
Пользователь
 
Регистрация: 20.10.2018
Сообщений: 16
По умолчанию

Цитата:
Сообщение от _Bers Посмотреть сообщение
из командной строки запусти:
твоя-программа > вредная-программа-клиент
вот тут я не понял, нужно просто запустить мою программу? или именно через командую строку запустить мою, а затем программу-клиент?
если что, я пробовал запускать в одном потоке и мою программу и программу-клиент обычным способом (через system(path)) но передать порт с помощью cout << NPort << endl; мне не удалось, так как во после запуска программы-клиента - моя программа останавливается с концами (даже после ввода вручную порта в консоли)

Последний раз редактировалось lallollulz; 08.12.2018 в 03:28.
lallollulz вне форума Ответить с цитированием
Старый 07.12.2018, 19:52   #4
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

А ведь в офф доке есть не только описание нужных функций и их параметров, но даже и пример https://docs.microsoft.com/en-us/win...put-and-output . Ну кто ж ее читает...
p51x вне форума Ответить с цитированием
Старый 08.12.2018, 18:33   #5
lallollulz
Пользователь
 
Регистрация: 20.10.2018
Сообщений: 16
По умолчанию

Цитата:
Сообщение от p51x Посмотреть сообщение
А ведь в офф доке есть не только описание нужных функций и их параметров, но даже и пример https://docs.microsoft.com/en-us/win...put-and-output . Ну кто ж ее читает...
спасибо большое, как я понял данный способ не требует правок в коде дочерного приложения (в моем случае, программы-клиента)
но я столкнулся с трудностями, может я не выспался, я не пойму как передать строку в дочерное приложение не из буфера (не ввести), а заранее установленное, вот код
Код:
#include "pch.h"
#include <windows.h> 
#include <tchar.h>
#include <stdio.h> 
#include <strsafe.h>

#define BUFSIZE 4096 

/* child process's STDIN is the user input or data that you enter into the child process - READ */
HANDLE g_hChildStd_IN_Rd = NULL;
/* child process's STDIN is the user input or data that you enter into the child process - WRITE */
HANDLE g_hChildStd_IN_Wr = NULL;
/* child process's STDOUT is the program output or data that child process returns - READ */
HANDLE g_hChildStd_OUT_Rd = NULL;
/* child process's STDOUT is the program output or data that child process returns - WRITE */
HANDLE g_hChildStd_OUT_Wr = NULL;

void CreateChildProcess(void);
void WriteToPipe(CHAR chBuf[]);
void ReadFromPipe(void);
void ErrorExit(PTSTR);

int _tmain(int argc, TCHAR *argv[])
{
	SECURITY_ATTRIBUTES saAttr;

	printf("\n->Start of parent execution.\n");

	// Set the bInheritHandle flag so pipe handles are inherited. 

	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
	saAttr.bInheritHandle = TRUE;
	saAttr.lpSecurityDescriptor = NULL;

	//child process's STDOUT is the program output or data that child process returns
	// Create a pipe for the child process's STDOUT. 
	if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0))
		ErrorExit((PTSTR)(TEXT("StdoutRd CreatePipe")));

	// Ensure the read handle to the pipe for STDOUT is not inherited.
	if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
		ErrorExit((PTSTR)(TEXT("Stdout SetHandleInformation")));

	//child process's STDIN is the user input or data that you enter into the child process
	// Create a pipe for the child process's STDIN. 
	if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0))
		ErrorExit((PTSTR)(TEXT("Stdin CreatePipe")));

	// Ensure the write handle to the pipe for STDIN is not inherited. 
	if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
		ErrorExit((PTSTR)(TEXT("Stdin SetHandleInformation")));
	// Create the child process. 

	CreateChildProcess();

	/* variables */
	char FAR *lpsz;
	int cch;

	CHAR chBuf[BUFSIZE];
	DWORD dwRead = strlen(chBuf);
	HANDLE hStdin;
	BOOL bSuccess;

	hStdin = GetStdHandle(STD_INPUT_HANDLE);
	if (hStdin == INVALID_HANDLE_VALUE)
		ExitProcess(1);

	for (;;)
	{
		// Read from standard input and stop on error or no data.
		bSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);

		if (!bSuccess || dwRead == 0)
			break;

		lpsz = &chBuf[0];

		// Write to the pipe that is the standard input for a child process. 
		// Data is written to the pipe's buffers, so it is not necessary to wait
		// until the child process is running before writing data.
		WriteToPipe(lpsz);
		printf("\n->Contents of %s written to child STDIN pipe.\n", argv[1]);
		// Read from pipe that is the standard output for child process. 
		printf("\n->Contents of child process STDOUT:\n\n", argv[1]);
		ReadFromPipe();
		printf("\n->End of parent execution.\n");
		// The remaining open handles are cleaned up when this process terminates. 
		// To avoid resource leaks in a larger application, close handles explicitly.
	}
	return 0;
}

void CreateChildProcess()
// Create a child process that uses the previously created pipes for STDIN and STDOUT.
{
//	TCHAR szCmdline[] = TEXT("cmd.exe /c \"C:\\Users\\vlad95_07\\source\\repos\\ConsoleApplication5\\Release\\IccReconnectLoader.exe -parameter C:\\Users\\vlad95_07\\source\\repos\\ConsoleApplication5\\Release\\image.txt\"");
	PROCESS_INFORMATION piProcInfo;
	STARTUPINFO siStartInfo;
	BOOL bSuccess = FALSE;

	// Set up members of the PROCESS_INFORMATION structure. 

	ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

	// Set up members of the STARTUPINFO structure. 
	// This structure specifies the STDIN and STDOUT handles for redirection.

	ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
	siStartInfo.cb = sizeof(STARTUPINFO);
	siStartInfo.hStdError = g_hChildStd_OUT_Wr;
	siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
	siStartInfo.hStdInput = g_hChildStd_IN_Rd;
	siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

	// Create the child process. 
	LPCWSTR filepath = L"IccReconnectLoader.exe";
	bSuccess = CreateProcess(filepath,
		NULL,     // command line 
		NULL,          // process security attributes 
		NULL,          // primary thread security attributes 
		TRUE,          // handles are inherited 
		0,             // creation flags 
		NULL,          // use parent's environment 
		NULL,          // use parent's current directory 
		&siStartInfo,  // STARTUPINFO pointer 
		&piProcInfo);  // receives PROCESS_INFORMATION 

	// If an error occurs, exit the application. 
	if (!bSuccess)
		ErrorExit((PTSTR)(TEXT("CreateProcess")));
	else
	{
		// Close handles to the child process and its primary thread.
		// Some applications might keep these handles to monitor the status
		// of the child process, for example. 
		CloseHandle(piProcInfo.hProcess);
		CloseHandle(piProcInfo.hThread);
	}
}

void WriteToPipe(CHAR chBuf[])
// Read from a file and write its contents to the pipe for the child's STDIN.
// Stop when there is no more data. 
{
	DWORD dwRead, dwWritten;
//	CHAR chBuf[] = "6113\n"; - изменить нельзя, компилятор ругается, если 6113 или 6113/n указать прямо в функции WrileFile() - 6113 не передается
	dwRead = strlen(chBuf);
	BOOL bSuccess = FALSE;
	bSuccess = WriteFile(g_hChildStd_IN_Wr, chBuf, dwRead, &dwWritten, NULL);
	if (!bSuccess) ErrorExit((PTSTR)(TEXT("StdInWr Cannot write into child process.")));
	/*
	// Close the pipe handle so the child process stops reading.
	if (!CloseHandle(g_hChildStd_IN_Wr))
		ErrorExit(TEXT("StdInWr CloseHandle"));
	*/
}

void ReadFromPipe(void)
{
// не имеет значения
}

void ErrorExit(PTSTR lpszFunction)
{
// тут все понятно
}

Последний раз редактировалось lallollulz; 08.12.2018 в 18:37.
lallollulz вне форума Ответить с цитированием
Старый 08.12.2018, 19:02   #6
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

Как ругается?
p51x вне форума Ответить с цитированием
Старый 08.12.2018, 23:58   #7
lallollulz
Пользователь
 
Регистрация: 20.10.2018
Сообщений: 16
По умолчанию

Цитата:
Сообщение от p51x Посмотреть сообщение
Как ругается?
Код:
error C2082: переопределение формального параметра "chBuf"
вот это комплиться, но не работает
Цитата:
CHAR testchBuf[] = "6113\n";
dwRead = strlen(testchBuf);
BOOL bSuccess = FALSE;
bSuccess = WriteFile(g_hChildStd_IN_Wr, testchBuf, dwRead, &dwWritten, NULL);
программа как бы запускается, но строка не передается
мне кажется и до этого ничего не работало (ничего не передовалось в буфер программы-клиента, просто дублировался мой ввод как бы забирала и основная программа и программа-клиент((((( )
а нет, извиняюсь, все работало и работает, и передается то что нужно, но только после любого ввода в консоль (из-за специфики кода, я так понял)
да, так и есть, эта тест программа состоит из цикла забора строки в буфер и отправки строки из буфера дочерному приложению, просто убрал забор для первого прогона цикла - и все оказалось норм. спасибо большое, я если честно и не расчитывал что это вообще можно реализовать без возможности изменить дочерное приложение, также переживал что эта моя программа-клиент принимает строку не сразу, а только спустя несколько секунд после запуска - однако все работает без каких-либо искуственных задержкек, с вариантом передачи строки сразу после запуска. еще раз спасибо

Последний раз редактировалось lallollulz; 09.12.2018 в 00:24.
lallollulz вне форума Ответить с цитированием
Старый 09.12.2018, 10:26   #8
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,695
По умолчанию

Вы прочитали в хелпе по крейтпроцесс абзац про WaitForInputIdle?
p51x вне форума Ответить с цитированием
Старый 09.12.2018, 10:37   #9
waleri
Старожил
 
Регистрация: 13.07.2012
Сообщений: 6,493
По умолчанию

Цитата:
Сообщение от p51x Посмотреть сообщение
WaitForInputIdle
К консольным приложениям это отношения не имеет, у pipe своя буферизация.
waleri вне форума Ответить с цитированием
Старый 10.12.2018, 13:12   #10
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от lallollulz Посмотреть сообщение
вот тут я не понял
почитай в интернетах, что такое "перенаправление ввода-вывода".

вся эта шляпа:
Код:
void CreateChildProcess()
нафиг не нужна.


объясняю на пальцах.

допустим есть некоторая консольная утилитка.
при запуске - пишет в консольку, что она делает.
теперь, предположим, мы хотим её вывод направить не в консольку,
а в файл.

что бы по окончании работы утилитки,
у нас на руках оказался текстовый файлик с логом работы.

как это делается?

запускаешь из командной строки:
консольная утилита > report.log

теперь, вместо того, что бы выводить информацию в консоль,
утилита будет выводить весь текст в файл report.log


вместо текстового файлика можно подсунуть другую программу.
и тогда эта другая программа будет думать, что ей на вход пришли данные из входного потока:


утилита1 > утилита2


здесь весь вывод данных из программы утилита1 пойдет на вход программы утилита2
соответственно, утилита2 будет думать, что ей кто-то чего-то в std::cin напечатал.


пример:

допустим, у нас есть консольная утилитка под названием cmdlog.exe
её исходный код оч простой:

Код:
#include<string>
#include<fstream>
#include<iostream>
using namespace std;

int main(int argc, char* argv[])
{
    const string log_name =  (argc==2)? argv[1] : "cmd.log";
    ofstream logfile(log_name);

    string line;
    while( !cin.eof() ) 
        getline(cin, line),
        line +='\n',
        logfile << line,
        cout    << line;
}
программа принимает со входа данные, и тупо сохраняет их в текстовый файл, попутно выводя данные в консоль.

благодаря чему информация логируется одновременно и в файл, и в консоль

теперь запускаем любую утилиту, работу которой нужно залоггировать:

Код:
programm.exe 2>&1 | cmdlog.exe example.log
здесь будет запущена programm.exe,
которая весь свой вывод перенаправит на вход cmdlog.exe,
которая выкачает весь ввод с помощью std::cin,
выведет в консольку и сохранит в файле example.log

Последний раз редактировалось _Bers; 10.12.2018 в 13:37.
_Bers вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Запуск стороннего exe Domenico Visual C++ 4 11.11.2018 21:53
Запуск стороннего приложения с параметрами Romowski Visual C++ 2 08.01.2013 13:49
Скрытый запуск стороннего приложения _ZixeL_ Общие вопросы Delphi 8 19.11.2012 20:22
значение из стороннего приложения Wov Общие вопросы Delphi 4 01.03.2011 00:04
Запуск стороннего файла CraftR14 Общие вопросы Delphi 8 17.04.2010 18:05