Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Kukurudza
105 / 86 / 6
Регистрация: 29.08.2012
Сообщений: 539
#1

Перенаправление вывода при запуске процесса - C++

23.08.2013, 13:56. Просмотров 805. Ответов 16
Метки нет (Все метки)

Создаю файл, в который хочу перенаправить вывод.
Заполняю структуру STARTUPINFO. Не забываю туда вписать дескриптор только что созданного файла.
Создаю процесс. Он отрабатывает, но в выходном файле нифига нет.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
        hl = CreateFile(md5.c_str(), GENERIC_WRITE, (DWORD)0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
        if (INVALID_HANDLE_VALUE != hl) {
            const std::wstring function = "blabla";
            const std::wstring commandLine = "blabla";
 
            STARTUPINFO si;
            memset(&si, 0, sizeof(si));
            si.dwFlags = STARTF_USESTDHANDLES;
            si.hStdOutput = hl;
 
            PROCESS_INFORMATION pi;
            memset(&pi, 0, sizeof(pi));
 
            if (CreateProcess(function.c_str(), (LPWSTR)commandLine.c_str(), NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi)) {
                DWORD dwWait = WaitForSingleObject(pi.hProcess, INFINITE);
                if (dwWait == WAIT_OBJECT_0)  
                    CloseHandle(pi.hProcess);
                    CloseHandle(pi.hThread);
                    CloseHandle(hl);
                }
            }
        }
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
23.08.2013, 13:56
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Перенаправление вывода при запуске процесса (C++):

Перенаправление потока вывода - C++
Здравствуйте! Задача такова - нужно перенаправить поток вывода с cout на файловый в одном из конструкторов класса. Итог - необработанное...

Перенаправление вывода в другое окно - C++
У меня есть прога, выводящая в одно из созданных ею окон текст. Как можно перехватить этот вывод и направить его в созданное мной окно...

При запуске из среды программа работает, при запуске выполняемого файла выдает ошибку - C++
Добавлено через 1 минуту 35 секунд как исправить ошибки в названии темы? там должно было быть исполняемого файла

Как прочитать данные из потока вывода другого процесса - C++
Как получить то, что выводит командная строка (прочитать выводной поток другого процесса)

Перенаправление указателя при перегрузке оператора в variadic template - C++
Есть вот такой вот код (сделан в vs2014): #include "stdafx.h" #include <iostream> #include <conio.h> #include <math.h> ...

Библиотеки процесса, защита от изменения процесса - C++
Здраствуйте. 1) Как можно получить список библиотек (dll, asi), которые уже загружены в процесс какой-то программы? Мне нужно чекать...

16
Убежденный
Системный программист
Эксперт С++
15637 / 7147 / 1131
Регистрация: 02.05.2013
Сообщений: 11,586
Записей в блоге: 1
Завершенные тесты: 1
23.08.2013, 16:00 #2
4 параметр CreateFile - указатель на структуру SECURITY_ATTRIBUTES.
Заполните ее и передайте в функцию:
C++
1
2
3
4
5
6
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof (sa);
sa.lpSecurityDescriptor = NULL; // Дескриптор безопасности по умолчанию.
sa.bInheritHandle = TRUE; // Наследовать данный хэндл.
 
hl = CreateFile(..., ..., ..., &sa, ...);
Добавлено через 42 секунды
Цитата Сообщение от Kukurudza Посмотреть сообщение
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hl;
cbSize тоже лучше заполнить.
1
Kukurudza
105 / 86 / 6
Регистрация: 29.08.2012
Сообщений: 539
26.08.2013, 07:54  [ТС] #3
Все равно не работает.
0
Убежденный
Системный программист
Эксперт С++
15637 / 7147 / 1131
Регистрация: 02.05.2013
Сообщений: 11,586
Записей в блоге: 1
Завершенные тесты: 1
26.08.2013, 08:58 #4
Показывайте код.
0
Kukurudza
105 / 86 / 6
Регистрация: 29.08.2012
Сообщений: 539
26.08.2013, 09:00  [ТС] #5
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
int main(int argc, char* argv[]) {
    static const std::wstring root = L"D:\\CONTROL_POINTS\\";
    static const std::wstring hash = L"hash.md5";
    static const std::wstring map = L"map.bmp";
    static const std::wstring function = root + L"md5.exe";
 
    std::vector<std::wstring> folders;
    folders.push_back(L"moscow\\");
    folders.push_back(L"novosibirsk\\");
 
    for (size_t i = 0, N = folders.size(); i < N; ++i) {
        const std::wstring md5 = root + folders[i] + hash;
 
        HANDLE hl = CreateFile(md5.c_str(), GENERIC_READ, (DWORD)0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
        if (INVALID_HANDLE_VALUE == hl) {                                                                                   //  нет построенного хеша
            hl = CreateFile(md5.c_str(), GENERIC_WRITE, (DWORD)0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
            if (INVALID_HANDLE_VALUE == hl) {
                std::cout << "ERROR!\n";
            } else {
                const std::wstring commandLine = L" " + root + folders[i] + map;
 
                STARTUPINFO si;
                memset(&si, 0, sizeof(STARTUPINFO));
                si.dwFlags = STARTF_USESTDHANDLES;
                si.hStdOutput = hl;
                si.cb = sizeof(STARTUPINFO);
 
                PROCESS_INFORMATION pi;
                memset(&pi, 0, sizeof(PROCESS_INFORMATION));
 
                SECURITY_ATTRIBUTES sa;
                memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
                sa.nLength = sizeof(SECURITY_ATTRIBUTES);
                sa.lpSecurityDescriptor = NULL;
                sa.bInheritHandle = TRUE;
 
                if (CreateProcess(function.c_str(), (LPWSTR)commandLine.c_str(), NULL, &sa, TRUE, NULL, NULL, NULL, &si, &pi)) {
                    DWORD dwWait = WaitForSingleObject(pi.hProcess, INFINITE);                                                  //  программа запущена, ждем её завершения
                    if (dwWait == WAIT_OBJECT_0) {                                                                              //  программа благополучно завершилась
                        CloseHandle(pi.hProcess);
                        CloseHandle(pi.hThread);
                        CloseHandle(hl);
                    } else {
                        std::cout << "ERROR";
                    }
                }
            }
        }
    }
    
    system("pause");
    return 0;
}
0
Убежденный
Системный программист
Эксперт С++
15637 / 7147 / 1131
Регистрация: 02.05.2013
Сообщений: 11,586
Записей в блоге: 1
Завершенные тесты: 1
26.08.2013, 09:14 #6
SECURITY_ATTRIBUTES нужно указывать для объекта, который вы хотите
наследовать в дочерние процессы. В данном случае ее нужно указывать в
CreateFile (строки 15 и 17 в примере выше), а не в CreateProcess.
1
Avazart
Эксперт С++
7214 / 5386 / 286
Регистрация: 10.12.2010
Сообщений: 23,808
Записей в блоге: 17
05.02.2015, 17:26 #7
Есть такой код:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//---------------------------------------------------------------------------
typedef AnsiStringT<866> OEMString;    //  Строка в кодировке cp_666 ( OEM )
//---------------------------------------------------------------------------
// Выполнение консольной команды
//---------------------------------------------------------------------------
bool ExecuteCmd(String CmdLine,String &Text,unsigned long &Code,unsigned TimeOut=180000)
{
    Text="";
    HANDLE hOutput;
 
    HANDLE hStdOutputWritePipe, hStdOutput, hStdError;
    HANDLE* hStdOutputReadPipe= &hOutput;
    
    CreatePipe(hStdOutputReadPipe, &hStdOutputWritePipe, NULL, 0);
    DuplicateHandle(GetCurrentProcess(), hStdOutputWritePipe,GetCurrentProcess(), &hStdOutput,0, TRUE, DUPLICATE_SAME_ACCESS);
    DuplicateHandle(GetCurrentProcess(), hStdOutput, GetCurrentProcess(), &hStdError, 0, TRUE, DUPLICATE_SAME_ACCESS);
    CloseHandle(hStdOutputWritePipe);
 
    PROCESS_INFORMATION pi;
    STARTUPINFO si;
 
        ZeroMemory(&si, sizeof(STARTUPINFO));
        si.cb = sizeof(STARTUPINFO);
        si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
        si.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
        si.hStdOutput = hStdOutput;
        si.hStdError  = hStdError;
        si.wShowWindow = SW_HIDE;
 
    bool result= CreateProcess( NULL,
                                                            CmdLine.w_str(),
                                                            NULL,
                                                            NULL,
                                                            TRUE,
                                                            CREATE_NEW_CONSOLE,
                                                            NULL,
                                                            NULL,
                                                            &si, &pi);
 
    if(!result)
        {
            CloseHandle(hStdOutput);
            CloseHandle(hStdError);
            CloseHandle(*hStdOutputReadPipe);
            *hStdOutputReadPipe = INVALID_HANDLE_VALUE;
            
            Text= "Ошибка при запуске процесса";
            return false;
        }
 
    CloseHandle(pi.hThread);
    CloseHandle(hStdOutput);
    CloseHandle(hStdError);
 
    if ( WaitForSingleObject(pi.hProcess,TimeOut)== WAIT_TIMEOUT)
        {
            Text= "Превышено время ожидания";
            return false;
        }
    else
        {
            GetExitCodeProcess(pi.hProcess,&Code);
        }
        
            const size_t length= 128;
            char buffer[length];
    
 
            DWORD read;
            while(ReadFile(hOutput,buffer,length, &read, NULL) )
                {
                    Text+= OEMString(buffer,read);
                }
 
            CloseHandle(hOutput);
            CloseHandle(pi.hProcess);
 
return !Code;
}


Решение через WaitForSingleObject(pi.hProcess,TimeOut) т.е ожидание завершение процесса мне не нравится.
Хотелось во первых реализовать свой класс и хотелось бы ждать именно того момента когда данные появятся и сразу читать-выводить, а не ждать завершения процесса.

Я пришел к такому решению что нужно читать асинхронно и тут же ждать завершение и если что по таймауту генерировать соответствующее исключение или код возврата.

Т.е что-то типа:

C++
1
2
3
4
5
int readTimeOut= 30000;
while( process.read(buff,size,readTimeOut) == timeOut)
{
    std::cout<< buff <<std::endl; 
}
Но тут проблема- ананимные каналы не поддерживают асинх. чтения/записи, поэтому придется использовать именованные каналы.

И тут собственно главный вопрос как правильно привязать хендлы именованного канала к хендлам передаваемым в STARTUPINFO что бы обеспечить чтение и запись (с таймаутами)?

Добавлено через 21 час 27 минут
up!

Добавлено через 22 часа 8 минут
up!
0
Убежденный
Системный программист
Эксперт С++
15637 / 7147 / 1131
Регистрация: 02.05.2013
Сообщений: 11,586
Записей в блоге: 1
Завершенные тесты: 1
05.02.2015, 23:37 #8
Цитата Сообщение от Avazart Посмотреть сообщение
как правильно привязать хендлы именованного канала к хендлам передаваемым в STARTUPINFO что бы обеспечить чтение и запись (с таймаутами)?
Если я правильно понял вопрос, надо делать так:

1. Создать два именованных канала (CreateNamedPipe).

2. Для каждого канала вызвать ConnectNamedPipe, переведя
их в режим приема подключений.

3. Открыть каждый канал через CreateFile, при этом в структуре
SECURITY_ATTRIBUTES поле bInheritHandle должно быть TRUE.

В итоге у нас получится два канала, и на каждый по два хэндла:
один серверный, полученный через CreateNamedPipe, второй клиентский,
полученный через CreateFile. Клиентский хэндл может наследоваться.

4. Запускаем дочерний процесс с флагом bInheritHandles = TRUE.
Клиентские хэндлы передаем ему через STARTUPINFO.

5. Ну а дальше асинхронно пишем и читаем из соответствующих
серверных хэндлов.
1
Avazart
Эксперт С++
7214 / 5386 / 286
Регистрация: 10.12.2010
Сообщений: 23,808
Записей в блоге: 17
05.02.2015, 23:41 #9
Цитата Сообщение от Убежденный Посмотреть сообщение
Клиентские хэндлы передаем ему через STARTUPINFO.
Вот с этим проблема. Т.е какие хендлы куда передавать, а какие хендлы закрывать, ну и возможно лажа с флагами с которыми открываются пайпы.

Все остальное как бы "ясно" и почти готово.
0
Убежденный
Системный программист
Эксперт С++
15637 / 7147 / 1131
Регистрация: 02.05.2013
Сообщений: 11,586
Записей в блоге: 1
Завершенные тесты: 1
05.02.2015, 23:44 #10
Хэндлы, созданные через CreateFile, т.е. клиентские, передать в дочерний процесс.
Например, с одного пайпа в hStdOutput и в hStdError, - этот пайп будет отвечать за
перехват вывода дочернего приложения, - а со второго в hStdInput - а через этот
пайп можно будет передавать что-нибудь во входной поток дочернего процесса.
После создания процесса оба этих хэндла можно закрыть, хоть это и не обязательно.
1
Avazart
Эксперт С++
7214 / 5386 / 286
Регистрация: 10.12.2010
Сообщений: 23,808
Записей в блоге: 17
05.02.2015, 23:54 #11
Цитата Сообщение от Убежденный Посмотреть сообщение
Хэндлы, созданные через CreateFile, т.е. клиентские, передать в дочерний процесс.
Значит все же нужно передавать для всех каналов "клиентские" хендлы, вот тут были сомнения, ибо если вывод приложения удавалось читать, то запись "проскакивала" т.е. запускаемое приложение не ждало записи.

Спасибо буду пробовать.
0
Убежденный
Системный программист
Эксперт С++
15637 / 7147 / 1131
Регистрация: 02.05.2013
Сообщений: 11,586
Записей в блоге: 1
Завершенные тесты: 1
06.02.2015, 00:09 #12
Цитата Сообщение от Avazart Посмотреть сообщение
Значит все же нужно передавать для всех каналов "клиентские" хендлы
Хм. Я думаю, без разницы.
Это у анонимных пайпов есть разделение на hRead и hWrite, а здесь оба
хэндла в плане вызова ReadFile/WriteFile получаются как бы равноценны.
Впрочем, я с пайпами давно дела не имел, сейчас не помню деталей.

Цитата Сообщение от Avazart Посмотреть сообщение
если вывод приложения удавалось читать, то запись "проскакивала" т.е. запускаемое приложение не ждало записи.
Может быть, это из-за FILE_FLAG_OVERLAPPED ?
Ведь дочернее приложение, когда работает с std::cout/printf,
подразумевает его "синхронность"...
0
Avazart
Эксперт С++
7214 / 5386 / 286
Регистрация: 10.12.2010
Сообщений: 23,808
Записей в блоге: 17
06.02.2015, 00:26 #13
Цитата Сообщение от Убежденный Посмотреть сообщение
Может быть, это из-за FILE_FLAG_OVERLAPPED ?
Ведь дочернее приложение, когда работает с std::cout/printf,
подразумевает его "синхронность"...
Блин точно...
А как же такую проблему решить?
Изначально хотелось обойтись без дополнительных ждущий потоков и в синхронном режиме с отсечкой по таймауту чтения/записи.
0
Убежденный
Системный программист
Эксперт С++
15637 / 7147 / 1131
Регистрация: 02.05.2013
Сообщений: 11,586
Записей в блоге: 1
Завершенные тесты: 1
06.02.2015, 00:32 #14
Цитата Сообщение от Avazart Посмотреть сообщение
А как же такую проблему решить?
Ну если создавать хэндлы для дочернего процесса без указания
флага FILE_FLAG_OVERLAPPED, то он будет с ними работать синхронно.
По идее, так.
0
Avazart
Эксперт С++
7214 / 5386 / 286
Регистрация: 10.12.2010
Сообщений: 23,808
Записей в блоге: 17
06.02.2015, 00:34 #15
Цитата Сообщение от Убежденный Посмотреть сообщение
Ну если создавать хэндлы для дочернего процесса без указания
флага FILE_FLAG_OVERLAPPED, то он будет с ними работать синхронно.
По идее, так.
Ну да это пройденный этап - тогда не будет таймаутов, ради этого и затевалось все.

Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//---------------------------------------------------------------------------
ulong Pipe::read(char* data,ulong size,IOResult& result)
{
    if(handle_==INVALID_HANDLE_VALUE)
        throw ProcessError("INVALID_HANDLE_VALUE");
 
    ulong length= 0;
    bool success= ReadFile(handle_,
                                                 data,
                                                 size,
                                                 &length,
                                                 &overlapped_);
 
    if(!success)
    {
        ulong code= GetLastError();
        if (code==ERROR_IO_PENDING)
        {
            ulong waitResult= WaitForSingleObject(handle_, timeOut_);
            switch (waitResult)
            {
                case WAIT_OBJECT_0:  result= IOResult::Ok;      break;
                case WAIT_TIMEOUT:   result= IOResult::TimeOut; return 0;
                case WAIT_FAILED:    throw ProcessError();
                default:               throw ProcessError("UNKNOWN ERROR!");
            }
        }
        else if(code==ERROR_BROKEN_PIPE)
        {
            result= IOResult::Broken;
            return 0;
        }
    }
 
    success=
        GetOverlappedResult(handle_,&overlapped_,&length,FALSE);
 
    if(!success)
    {
        ulong code= GetLastError();
        if(code==ERROR_BROKEN_PIPE)
            result= IOResult::Broken;
        else
            throw ProcessError();
    }
    overlapped_.Offset+= length;
    return length;
}
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.02.2015, 00:34
Привет! Вот еще темы с ответами:

как сделать логотип при загрузке программы (типа как при запуске офиса) - C++
и так , люди...мне вдруг безумно захотелось узнать, как делать при загрузке программы такую фичу как например в мелкософтоффисе, или...

Ошибка при запуске C++ - C++
Привет! Помогите пожалуйста, уже сто раз переустанавливал Си++, но когда создаю пустой проект (win32) в мастере приложений win 32 ставлю...

Ошибка при запуске - C++
Всем привет! При запуске пишет ошибки в коде: #include &lt;iostream.h&gt; #include &lt;stdio.h&gt; #include &lt;math.h&gt; void main() { ...

Ошибка при запуске - C++
Помогите пожалуйста. Не работает программа. Не считает x и y. Выключается еще при первой метке и пишет:,,X и y не существуют&quot;(а они то...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Yandex
Объявления
06.02.2015, 00:34
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru