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

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

Восстановить пароль Регистрация
 
Kukurudza
105 / 86 / 6
Регистрация: 29.08.2012
Сообщений: 539
23.08.2013, 13:56     Перенаправление вывода при запуске процесса #1
Создаю файл, в который хочу перенаправить вывод.
Заполняю структуру 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);
                }
            }
        }
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Убежденный
Системный программист
 Аватар для Убежденный
14193 / 6208 / 985
Регистрация: 02.05.2013
Сообщений: 10,344
Завершенные тесты: 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 тоже лучше заполнить.
Kukurudza
105 / 86 / 6
Регистрация: 29.08.2012
Сообщений: 539
26.08.2013, 07:54  [ТС]     Перенаправление вывода при запуске процесса #3
Все равно не работает.
Убежденный
Системный программист
 Аватар для Убежденный
14193 / 6208 / 985
Регистрация: 02.05.2013
Сообщений: 10,344
Завершенные тесты: 1
26.08.2013, 08:58     Перенаправление вывода при запуске процесса #4
Показывайте код.
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;
}
Убежденный
Системный программист
 Аватар для Убежденный
14193 / 6208 / 985
Регистрация: 02.05.2013
Сообщений: 10,344
Завершенные тесты: 1
26.08.2013, 09:14     Перенаправление вывода при запуске процесса #6
SECURITY_ATTRIBUTES нужно указывать для объекта, который вы хотите
наследовать в дочерние процессы. В данном случае ее нужно указывать в
CreateFile (строки 15 и 17 в примере выше), а не в CreateProcess.
Avazart
 Аватар для Avazart
6900 / 5140 / 252
Регистрация: 10.12.2010
Сообщений: 22,588
Записей в блоге: 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!
Убежденный
Системный программист
 Аватар для Убежденный
14193 / 6208 / 985
Регистрация: 02.05.2013
Сообщений: 10,344
Завершенные тесты: 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. Ну а дальше асинхронно пишем и читаем из соответствующих
серверных хэндлов.
Avazart
 Аватар для Avazart
6900 / 5140 / 252
Регистрация: 10.12.2010
Сообщений: 22,588
Записей в блоге: 17
05.02.2015, 23:41     Перенаправление вывода при запуске процесса #9
Цитата Сообщение от Убежденный Посмотреть сообщение
Клиентские хэндлы передаем ему через STARTUPINFO.
Вот с этим проблема. Т.е какие хендлы куда передавать, а какие хендлы закрывать, ну и возможно лажа с флагами с которыми открываются пайпы.

Все остальное как бы "ясно" и почти готово.
Убежденный
Системный программист
 Аватар для Убежденный
14193 / 6208 / 985
Регистрация: 02.05.2013
Сообщений: 10,344
Завершенные тесты: 1
05.02.2015, 23:44     Перенаправление вывода при запуске процесса #10
Хэндлы, созданные через CreateFile, т.е. клиентские, передать в дочерний процесс.
Например, с одного пайпа в hStdOutput и в hStdError, - этот пайп будет отвечать за
перехват вывода дочернего приложения, - а со второго в hStdInput - а через этот
пайп можно будет передавать что-нибудь во входной поток дочернего процесса.
После создания процесса оба этих хэндла можно закрыть, хоть это и не обязательно.
Avazart
 Аватар для Avazart
6900 / 5140 / 252
Регистрация: 10.12.2010
Сообщений: 22,588
Записей в блоге: 17
05.02.2015, 23:54     Перенаправление вывода при запуске процесса #11
Цитата Сообщение от Убежденный Посмотреть сообщение
Хэндлы, созданные через CreateFile, т.е. клиентские, передать в дочерний процесс.
Значит все же нужно передавать для всех каналов "клиентские" хендлы, вот тут были сомнения, ибо если вывод приложения удавалось читать, то запись "проскакивала" т.е. запускаемое приложение не ждало записи.

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

Цитата Сообщение от Avazart Посмотреть сообщение
если вывод приложения удавалось читать, то запись "проскакивала" т.е. запускаемое приложение не ждало записи.
Может быть, это из-за FILE_FLAG_OVERLAPPED ?
Ведь дочернее приложение, когда работает с std::cout/printf,
подразумевает его "синхронность"...
Avazart
 Аватар для Avazart
6900 / 5140 / 252
Регистрация: 10.12.2010
Сообщений: 22,588
Записей в блоге: 17
06.02.2015, 00:26     Перенаправление вывода при запуске процесса #13
Цитата Сообщение от Убежденный Посмотреть сообщение
Может быть, это из-за FILE_FLAG_OVERLAPPED ?
Ведь дочернее приложение, когда работает с std::cout/printf,
подразумевает его "синхронность"...
Блин точно...
А как же такую проблему решить?
Изначально хотелось обойтись без дополнительных ждущий потоков и в синхронном режиме с отсечкой по таймауту чтения/записи.
Убежденный
Системный программист
 Аватар для Убежденный
14193 / 6208 / 985
Регистрация: 02.05.2013
Сообщений: 10,344
Завершенные тесты: 1
06.02.2015, 00:32     Перенаправление вывода при запуске процесса #14
Цитата Сообщение от Avazart Посмотреть сообщение
А как же такую проблему решить?
Ну если создавать хэндлы для дочернего процесса без указания
флага FILE_FLAG_OVERLAPPED, то он будет с ними работать синхронно.
По идее, так.
Avazart
 Аватар для Avazart
6900 / 5140 / 252
Регистрация: 10.12.2010
Сообщений: 22,588
Записей в блоге: 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;
}
Убежденный
Системный программист
 Аватар для Убежденный
14193 / 6208 / 985
Регистрация: 02.05.2013
Сообщений: 10,344
Завершенные тесты: 1
06.02.2015, 00:42     Перенаправление вывода при запуске процесса #16
Это еще почему ?
Ты ведь будешь работать с пайпами через серверный хэндл, который
открыт в асинхронном режиме (CreateNamedPipe). А дочернему процессу
будет выдан синхронный хэндл, полученный у CreateFile.
Или я чего-то недопонял...
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.02.2015, 21:41     Перенаправление вывода при запуске процесса
Еще ссылки по теме:

Ошибка при запуске C++
Ошибка при запуске C++ C++
C++ Ошибка при запуске

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

Или воспользуйтесь поиском по форуму:
Avazart
 Аватар для Avazart
6900 / 5140 / 252
Регистрация: 10.12.2010
Сообщений: 22,588
Записей в блоге: 17
06.02.2015, 21:41     Перенаправление вывода при запуске процесса #17
Цитата Сообщение от Убежденный Посмотреть сообщение
Это еще почему ?
Ты ведь будешь работать с пайпами через серверный хэндл, который
открыт в асинхронном режиме (CreateNamedPipe). А дочернему процессу
будет выдан синхронный хэндл, полученный у CreateFile.
Или я чего-то недопонял...
А типа можно и так... мне как бы и в голову не пришло.
Собственно нужно попробовать, попробую отпишу, если что, еще раз спасибо.

Добавлено через 20 часов 52 минуты
В общем проверил- работает как надо.
Yandex
Объявления
06.02.2015, 21:41     Перенаправление вывода при запуске процесса
Ответ Создать тему
Опции темы

Текущее время: 21:23. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru