Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/15: Рейтинг темы: голосов - 15, средняя оценка - 4.67
106 / 87 / 13
Регистрация: 29.08.2012
Сообщений: 538

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

23.08.2013, 13:56. Показов 3403. Ответов 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
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
23.08.2013, 13:56
Ответы с готовыми решениями:

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

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

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

16
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
23.08.2013, 16:00
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
106 / 87 / 13
Регистрация: 29.08.2012
Сообщений: 538
26.08.2013, 07:54  [ТС]
Все равно не работает.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
26.08.2013, 08:58
Показывайте код.
0
106 / 87 / 13
Регистрация: 29.08.2012
Сообщений: 538
26.08.2013, 09:00  [ТС]
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
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
26.08.2013, 09:14
SECURITY_ATTRIBUTES нужно указывать для объекта, который вы хотите
наследовать в дочерние процессы. В данном случае ее нужно указывать в
CreateFile (строки 15 и 17 в примере выше), а не в CreateProcess.
1
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
05.02.2015, 17:26
Есть такой код:
Кликните здесь для просмотра всего текста
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
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
05.02.2015, 23:37
Цитата Сообщение от Avazart Посмотреть сообщение
как правильно привязать хендлы именованного канала к хендлам передаваемым в STARTUPINFO что бы обеспечить чтение и запись (с таймаутами)?
Если я правильно понял вопрос, надо делать так:

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

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

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

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

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

5. Ну а дальше асинхронно пишем и читаем из соответствующих
серверных хэндлов.
1
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
05.02.2015, 23:41
Цитата Сообщение от Убежденный Посмотреть сообщение
Клиентские хэндлы передаем ему через STARTUPINFO.
Вот с этим проблема. Т.е какие хендлы куда передавать, а какие хендлы закрывать, ну и возможно лажа с флагами с которыми открываются пайпы.

Все остальное как бы "ясно" и почти готово.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
05.02.2015, 23:44
Хэндлы, созданные через CreateFile, т.е. клиентские, передать в дочерний процесс.
Например, с одного пайпа в hStdOutput и в hStdError, - этот пайп будет отвечать за
перехват вывода дочернего приложения, - а со второго в hStdInput - а через этот
пайп можно будет передавать что-нибудь во входной поток дочернего процесса.
После создания процесса оба этих хэндла можно закрыть, хоть это и не обязательно.
1
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
05.02.2015, 23:54
Цитата Сообщение от Убежденный Посмотреть сообщение
Хэндлы, созданные через CreateFile, т.е. клиентские, передать в дочерний процесс.
Значит все же нужно передавать для всех каналов "клиентские" хендлы, вот тут были сомнения, ибо если вывод приложения удавалось читать, то запись "проскакивала" т.е. запускаемое приложение не ждало записи.

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

Цитата Сообщение от Avazart Посмотреть сообщение
если вывод приложения удавалось читать, то запись "проскакивала" т.е. запускаемое приложение не ждало записи.
Может быть, это из-за FILE_FLAG_OVERLAPPED ?
Ведь дочернее приложение, когда работает с std::cout/printf,
подразумевает его "синхронность"...
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
06.02.2015, 00:26
Цитата Сообщение от Убежденный Посмотреть сообщение
Может быть, это из-за FILE_FLAG_OVERLAPPED ?
Ведь дочернее приложение, когда работает с std::cout/printf,
подразумевает его "синхронность"...
Блин точно...
А как же такую проблему решить?
Изначально хотелось обойтись без дополнительных ждущий потоков и в синхронном режиме с отсечкой по таймауту чтения/записи.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
06.02.2015, 00:32
Цитата Сообщение от Avazart Посмотреть сообщение
А как же такую проблему решить?
Ну если создавать хэндлы для дочернего процесса без указания
флага FILE_FLAG_OVERLAPPED, то он будет с ними работать синхронно.
По идее, так.
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
06.02.2015, 00:34
Цитата Сообщение от Убежденный Посмотреть сообщение
Ну если создавать хэндлы для дочернего процесса без указания
флага 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
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
06.02.2015, 00:42
Это еще почему ?
Ты ведь будешь работать с пайпами через серверный хэндл, который
открыт в асинхронном режиме (CreateNamedPipe). А дочернему процессу
будет выдан синхронный хэндл, полученный у CreateFile.
Или я чего-то недопонял...
1
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
06.02.2015, 21:41
Цитата Сообщение от Убежденный Посмотреть сообщение
Это еще почему ?
Ты ведь будешь работать с пайпами через серверный хэндл, который
открыт в асинхронном режиме (CreateNamedPipe). А дочернему процессу
будет выдан синхронный хэндл, полученный у CreateFile.
Или я чего-то недопонял...
А типа можно и так... мне как бы и в голову не пришло.
Собственно нужно попробовать, попробую отпишу, если что, еще раз спасибо.

Добавлено через 20 часов 52 минуты
В общем проверил- работает как надо.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
06.02.2015, 21:41
Помогаю со студенческими работами здесь

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

Перенаправление ввода/вывода при запуске процессов
Все это для Windows 8 для одного языка, VS2010 Pro (русские), на других не пробовал. Проблема в том, что вопросы к пользователю не...

При выполнении батника на некоторых машинах с Windows XP не работает перенаправление вывода команд в NUL
не работает перенаправление &gt;nul проблема возникает на некоторых машинах под управлением рус winXP @echo off :LOOP ::...

При запуске процесса 1 завершать процесс 2
Здравствуйте эксперты! Проблема такая: не знаю как написать vbs скрипт который при запуске процесса monitor.exe завершал процесс...

Рандомное имя процесса при запуске
Добрый день. Везде читаю, что нельзя. Но все таки, есть ли способы? Может кто сталкивался с подобной задачей. При запуске программы нужно...


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

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru