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

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

23.08.2013, 13:56. Показов 3307. Ответов 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
8484 / 6151 / 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
8484 / 6151 / 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
8484 / 6151 / 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
8484 / 6151 / 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
8484 / 6151 / 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
8484 / 6151 / 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
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru