Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Передача HANDLE дочернему процессу, для использования как STD_OUTPUT_HANDLE 
V
    Опции темы
Igorious
  Дата 8.12.2012, 16:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 14.12.2011

Репутация: нет
Всего: нет



Добрый день.
Помогите со следующей задачей.
В главном процессе создаются файлы и дочерний процесс. Дочернему процессу через командную строку передаётся хэндлы файлов. Дочерний процесс должен вывести некоторую информацию в эти файлы.

К сожалению, к меня не получается вывести в файл — выводит только в консоль. Помогите найти ошибку в коде.

Родительский процесс:
Код

// Sender.cpp

#include <windows.h>
#include <stdio.h>

HANDLE OpenFile(const char* filePath)
{
    if (filePath == NULL || filePath[0] == 0)
        return INVALID_HANDLE_VALUE;

    SECURITY_ATTRIBUTES saAttr;
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = true;
    saAttr.lpSecurityDescriptor = NULL;

    HANDLE hFile = CreateFile(filePath, GENERIC_READ | GENERIC_WRITE, 0, &saAttr, OPEN_ALWAYS, FILE_ATTRIBUTE_ARCHIVE, NULL);    

    return hFile;
}

bool CreateProc(LPTSTR szCommandLine, BOOL bInherit, PROCESS_INFORMATION* pi)

    STARTUPINFO si;
    ZeroMemory(pi, sizeof(PROCESS_INFORMATION));
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO); 

    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;

    return CreateProcess(NULL, szCommandLine, &sa, NULL, bInherit, 0, NULL, NULL, &si,    pi);
}

void main(int argc, char* argv[])
{
    printf("Sender: Console\n");

    HANDLE hFile = OpenFile("D:\\[Programs]\\[Projects]\\[C++]\\HandleTest\\Debug\\out.txt");
    char buf[512];
    sprintf(buf, TEXT("D:\\[Programs]\\[Projects]\\[C++]\\HandleTest\\Debug\\Receiver.exe %i %i"), hFile, GetCurrentProcessId());

    PROCESS_INFORMATION pi;
    if(!CreateProc(buf, true, &pi))
        printf("FAILED!\n");

    if (!SetStdHandle(STD_OUTPUT_HANDLE, hFile))
        printf("Error SetFileHandle\n");
    printf("Sender: File\n");

    WaitForSingleObject(pi.hProcess, INFINITE);
    if (!CloseHandle(hFile))
        printf("Error CloseFileHandle\n");
}


Дочерний процесс:
Код

// Receiver.cpp
#include <windows.h>
#include <stdlib.h>
#include <iostream>

void main(int argc, char* argv[])
{
    if (argc == 3)
    {
        printf("Receiver: Console\n");
        HANDLE hFileSender = (HANDLE)atoi(argv[1]);
        DWORD idSender = (DWORD)atoi(argv[2]);
        HANDLE hSender = OpenProcess(PROCESS_ALL_ACCESS, TRUE, idSender);
        HANDLE hFile;
        if (!DuplicateHandle(hSender, hFileSender, GetCurrentProcess(), &hFile, NULL, FALSE, DUPLICATE_SAME_ACCESS))
            printf("Error Duplicate\n");

        HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
        if (!SetStdHandle(STD_OUTPUT_HANDLE, hFile))
            printf("Error SetFileHandle\n");

        printf("Receiver: File\n");

        if (!SetStdHandle(STD_OUTPUT_HANDLE, hStdOut))
            printf("Error SetStdOut\n");
        if (!CloseHandle(hFile))
            printf("Error CloseFileHandle\n");

        printf("Press any key...");
        std::cin.get();
    }
    else
        printf("Need args!");
}


upd. Добавил проверку результатов каждой функции.

Это сообщение отредактировал(а) Igorious - 8.12.2012, 20:25
PM MAIL   Вверх
artsb
Дата 8.12.2012, 19:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 5
Всего: 64



У вас в дочернем процессе никак не обрабатываются результаты выполнения функций. Исправьте это и сообщите, где отваливается выполнение и с какой ошибкой.


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
tzirechnoy
Дата 8.12.2012, 19:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1173
Регистрация: 30.1.2009

Репутация: нет
Всего: 16



Времена глобальных хэндлов прошли почти 20 лет назад, с приходом win32.

Для получения копии хэндла из другого процэсса используйте DuplicateHandle.

Добавлено через 1 минуту и 11 секунд
Да, я всё-таки дебил. Не заметил его при первом прочтении.
PM MAIL   Вверх
Igorious
Дата 8.12.2012, 20:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 14.12.2011

Репутация: нет
Всего: нет



Цитата(artsb @  8.12.2012,  19:26 Найти цитируемый пост)
У вас в дочернем процессе никак не обрабатываются результаты выполнения функций.


Исправил. 
Все функции возвращают TRUE. Но все четыре строчки по-прежнему выводятся лишь на консоль. Файл создаётся, но он пуст.
PM MAIL   Вверх
artsb
Дата 8.12.2012, 20:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2280
Регистрация: 17.7.2007
Где: центр Вселенной

Репутация: 5
Всего: 64



Похоже, через SetStdHandle ничего не получится. Подробности в самом конце темы.


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
Igorious
  Дата 8.12.2012, 22:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 14.12.2011

Репутация: нет
Всего: нет



artsb, большое спасибо.

Это довольно неожиданно, что во время исполнения проги она не учитывает SetStdHandle.
С учётом приобретённых знаний переписал код следующим образом:

Код

...
#include <io.h>
#include <fcntl.h>
...
    printf("Receiver: Console\n");
    HANDLE hFileSender = (HANDLE)atoi(argv[1]);
    DWORD idSender = (DWORD)atoi(argv[2]);
    HANDLE hSender = OpenProcess(PROCESS_ALL_ACCESS, TRUE, idSender);
    HANDLE hFile;
    if (!DuplicateHandle(hSender, hFileSender, GetCurrentProcess(), &hFile, NULL, FALSE, DUPLICATE_SAME_ACCESS))
        printf("Error Duplicate\n");

    int h2StdOut = _dup(1); // STD_OUT;

    int h2File = _open_osfhandle((LONG)hFile, _O_TEXT);
    _dup2(h2File, 1); // stdout := file;

    printf("Receiver: File\n");
    printf("Hello, World!\n");
    fflush(stdout);

    _dup2(h2StdOut, 1); // stdout := console;

    _close(h2File); // CloseHandle не нужен;
        
    printf("Press any key...");
    std::cin.get();

PM MAIL   Вверх
feodorv
Дата 9.12.2012, 23:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(Igorious @  8.12.2012,  23:33 Найти цитируемый пост)
Это довольно неожиданно, что во время исполнения проги она не учитывает SetStdHandle.

Почему не учитывает, учитывает. Вот здесь:
Код
WriteFile( GetStdHandle(STD_OUTPUT_HANDLE), buf, lstrlen(buf), &dummy, NULL);

Но Вы же хотите, чтобы работал printf в соответствии с новым STD_OUTPUT_HANDLE. printf является частью стандартной библиотеки, которая для Windows есть надстройка над WinAPI. Она (если программа вообще ею пользуется) инициализируется при старте приложения, при этом stdout связывается с тем STD_OUTPUT_HANDLE, который был актуальным на момент инициализации. Вызовы SetStdHandle (это чистый WinAPI) никак не влияют на stdin, stdout и stderr (а это уже из стандартной библиотеки). Чтобы синхронизировать STD_OUTPUT_HANDLE из WinAPI и stdout из стд.C.либ. нужно произвести дополнительные действия: Как в GUI приложении открыть консоль и назначить stdin,stdout,stderr smile

Добавлено через 5 минут и 56 секунд
Или вот без переназначения консоли: Adding Console I/O to a Win32 GUI App.

Это сообщение отредактировал(а) feodorv - 9.12.2012, 23:02


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
HANDLE
Дата 6.1.2015, 05:51 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 25.6.2008

Репутация: нет
Всего: нет



Всё гораздо проще. При создании процесса нужно проинициализировать структуру STARTUPINFO;

STARTUPINFO si;
si.hStdInput = сюда положить хендлы созданных файлов;
si.hStdOutput = сюда положить хендлы созданных файлов;
si.hStdError = сюда положить хендлы созданных файлов;
И установить флажок
si.dwFlags = STARTF_USESTDHANDLES;

И будет вам счастье
PM MAIL   Вверх
feodorv
Дата 12.1.2015, 10:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 9
Всего: 45



Цитата(HANDLE @  6.1.2015,  05:51 Найти цитируемый пост)
Всё гораздо проще.

Вопрос стоял о том, чтобы менять stdout 
Цитата(Igorious @  8.12.2012,  22:33 Найти цитируемый пост)
во время исполнения проги
.
И, может быть, неоднократно.



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0799 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.