Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 5.00/5: Рейтинг темы: голосов - 5, средняя оценка - 5.00
Kukurudza
105 / 86 / 13
Регистрация: 29.08.2012
Сообщений: 539
#1

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

23.08.2013, 13:56. Просмотров 925. Ответов 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
Ответы с готовыми решениями:

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

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

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

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

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

16
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 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 / 13
Регистрация: 29.08.2012
Сообщений: 539
26.08.2013, 07:54  [ТС] #3
Все равно не работает.
0
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
26.08.2013, 08:58 #4
Показывайте код.
0
Kukurudza
105 / 86 / 13
Регистрация: 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
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
26.08.2013, 09:14 #6
SECURITY_ATTRIBUTES нужно указывать для объекта, который вы хотите
наследовать в дочерние процессы. В данном случае ее нужно указывать в
CreateFile (строки 15 и 17 в примере выше), а не в CreateProcess.
1
Avazart
Эксперт С++
7719 / 5628 / 549
Регистрация: 10.12.2010
Сообщений: 25,336
Записей в блоге: 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
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 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
Эксперт С++
7719 / 5628 / 549
Регистрация: 10.12.2010
Сообщений: 25,336
Записей в блоге: 17
05.02.2015, 23:41 #9
Цитата Сообщение от Убежденный Посмотреть сообщение
Клиентские хэндлы передаем ему через STARTUPINFO.
Вот с этим проблема. Т.е какие хендлы куда передавать, а какие хендлы закрывать, ну и возможно лажа с флагами с которыми открываются пайпы.

Все остальное как бы "ясно" и почти готово.
0
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
05.02.2015, 23:44 #10
Хэндлы, созданные через CreateFile, т.е. клиентские, передать в дочерний процесс.
Например, с одного пайпа в hStdOutput и в hStdError, - этот пайп будет отвечать за
перехват вывода дочернего приложения, - а со второго в hStdInput - а через этот
пайп можно будет передавать что-нибудь во входной поток дочернего процесса.
После создания процесса оба этих хэндла можно закрыть, хоть это и не обязательно.
1
Avazart
Эксперт С++
7719 / 5628 / 549
Регистрация: 10.12.2010
Сообщений: 25,336
Записей в блоге: 17
05.02.2015, 23:54 #11
Цитата Сообщение от Убежденный Посмотреть сообщение
Хэндлы, созданные через CreateFile, т.е. клиентские, передать в дочерний процесс.
Значит все же нужно передавать для всех каналов "клиентские" хендлы, вот тут были сомнения, ибо если вывод приложения удавалось читать, то запись "проскакивала" т.е. запускаемое приложение не ждало записи.

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

Цитата Сообщение от Avazart Посмотреть сообщение
если вывод приложения удавалось читать, то запись "проскакивала" т.е. запускаемое приложение не ждало записи.
Может быть, это из-за FILE_FLAG_OVERLAPPED ?
Ведь дочернее приложение, когда работает с std::cout/printf,
подразумевает его "синхронность"...
0
Avazart
Эксперт С++
7719 / 5628 / 549
Регистрация: 10.12.2010
Сообщений: 25,336
Записей в блоге: 17
06.02.2015, 00:26 #13
Цитата Сообщение от Убежденный Посмотреть сообщение
Может быть, это из-за FILE_FLAG_OVERLAPPED ?
Ведь дочернее приложение, когда работает с std::cout/printf,
подразумевает его "синхронность"...
Блин точно...
А как же такую проблему решить?
Изначально хотелось обойтись без дополнительных ждущий потоков и в синхронном режиме с отсечкой по таймауту чтения/записи.
0
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
06.02.2015, 00:32 #14
Цитата Сообщение от Avazart Посмотреть сообщение
А как же такую проблему решить?
Ну если создавать хэндлы для дочернего процесса без указания
флага FILE_FLAG_OVERLAPPED, то он будет с ними работать синхронно.
По идее, так.
0
Avazart
Эксперт С++
7719 / 5628 / 549
Регистрация: 10.12.2010
Сообщений: 25,336
Записей в блоге: 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
Убежденный
Ушел с форума
Эксперт С++
15954 / 7266 / 1178
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
06.02.2015, 00:42 #16
Это еще почему ?
Ты ведь будешь работать с пайпами через серверный хэндл, который
открыт в асинхронном режиме (CreateNamedPipe). А дочернему процессу
будет выдан синхронный хэндл, полученный у CreateFile.
Или я чего-то недопонял...
1
Avazart
Эксперт С++
7719 / 5628 / 549
Регистрация: 10.12.2010
Сообщений: 25,336
Записей в блоге: 17
06.02.2015, 21:41 #17
Цитата Сообщение от Убежденный Посмотреть сообщение
Это еще почему ?
Ты ведь будешь работать с пайпами через серверный хэндл, который
открыт в асинхронном режиме (CreateNamedPipe). А дочернему процессу
будет выдан синхронный хэндл, полученный у CreateFile.
Или я чего-то недопонял...
А типа можно и так... мне как бы и в голову не пришло.
Собственно нужно попробовать, попробую отпишу, если что, еще раз спасибо.

Добавлено через 20 часов 52 минуты
В общем проверил- работает как надо.
1
06.02.2015, 21:41
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.02.2015, 21:41

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

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

Ошибка при запуске
Всем привет! При запуске пишет ошибки в коде: #include &lt;iostream.h&gt; #include...


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

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Опции темы

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