Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Перехват stdout у DOS программ


Автор: albertn 28.1.2012, 14:53
Доброго времени суток!

Есть исходный код, который запускает процесс и перенаправляет его вывод в файл:
Код

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

int main()
{
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
    STARTUPINFO si;
    memset(&si, 0, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.lpDesktop = TEXT("");
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;;
    si.wShowWindow = SW_HIDE;
    HANDLE hFile = CreateFile ("c:\\output.txt", GENERIC_WRITE, FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL);
    si.hStdOutput = hFile;
    PROCESS_INFORMATION pi;
    memset(&pi, 0, sizeof(PROCESS_INFORMATION));
    BOOL create_ok;
    create_ok = CreateProcess(NULL,"C:\\1.exe",NULL,NULL,TRUE,CREATE_NEW_CONSOLE | CREATE_SEPARATE_WOW_VDM,NULL,"C:\\",&si,&pi);
    if (!create_ok)
    {
        printf("Run fail\n");
        return 0;
    }
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    CloseHandle(hFile);
}


Он отлично работает для консольных win32 программ, но для DOS программ он ничего не записывает в выходной файл. Замечено, что если не указывать флаг CREATE_NEW_CONSOLE, то программа работает верно, но это не выход.

Может кто знает как решить проблему?

Автор: Dem_max 28.1.2012, 16:32
http://www.sources.ru/cpp/using_anonymous_pipes.shtml

Автор: albertn 28.1.2012, 16:34
Цитата(Dem_max @ 28.1.2012,  16:32)
http://www.sources.ru/cpp/using_anonymous_pipes.shtml

С пайпами аналогичная ситуация.

Автор: Dem_max 28.1.2012, 16:44
Цитата

Замечено, что если не указывать флаг CREATE_NEW_CONSOLE, то программа работает верно, но это не выход.

Почему не выход ?????

Автор: albertn 28.1.2012, 16:48
Цитата(Dem_max @ 28.1.2012,  16:44)
Цитата

Замечено, что если не указывать флаг CREATE_NEW_CONSOLE, то программа работает верно, но это не выход.

Почему не выход ?????

Фактически программа работает как сервис, внутри которого в несколько потоков происходит запуск программ. Необходимо чтобы выполнение программ не влияло друг на друга и на сервис в целом. Как я понимаю, флаг CREATE_NEW_CONSOLE гарантирует это.

Автор: Dem_max 29.1.2012, 09:19
Попробуй без этого флага, но используй функции AllocConsole, AttachConsole

Автор: xvr 29.1.2012, 12:16
Цитата(albertn @  28.1.2012,  16:48 Найти цитируемый пост)
Необходимо чтобы выполнение программ не влияло друг на друга и на сервис в целом. Как я понимаю, флаг CREATE_NEW_CONSOLE гарантирует это. 

Перебейте запускаемым программам все потоки ввода вывода (stdin/stdout/stderr), и они так же не будут влиять друг на друга и без CREATE_NEW_CONSOLE

Автор: albertn 2.2.2012, 15:05
Цитата(xvr @ 29.1.2012,  12:16)
Цитата(albertn @  28.1.2012,  16:48 Найти цитируемый пост)
Необходимо чтобы выполнение программ не влияло друг на друга и на сервис в целом. Как я понимаю, флаг CREATE_NEW_CONSOLE гарантирует это. 

Перебейте запускаемым программам все потоки ввода вывода (stdin/stdout/stderr), и они так же не будут влиять друг на друга и без CREATE_NEW_CONSOLE

Выяснилась еще одна особенность, что при использовании CreateProcessAsUser для DOS программ без CREATE_NEW_CONSOLE вываливается ошибка "Неверный дескриптор." при перенаправлении. Тут я уже не знаю что делать :(

Приведу фрагмент кода, на котором происходит ошибка:
Код

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

char* getErrorDescription(int error) {
    char *buf = 0;
    FormatMessage(
      FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
      0,
      error,
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      (LPTSTR) &buf,
      0,
      NULL);
    char* res = strdup(buf);
    LocalFree(buf);
    return res;
}

int main()
{
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;
    STARTUPINFO si;
    memset(&si, 0, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.lpDesktop = TEXT("");
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;;
    si.wShowWindow = SW_HIDE;
    HANDLE hFile = CreateFile ("c:\\output.txt", GENERIC_WRITE, FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL);
    si.hStdOutput = hFile;
    si.hStdError = hFile;
    PROCESS_INFORMATION pi;
    memset(&pi, 0, sizeof(PROCESS_INFORMATION));
    HANDLE hUser;
    if (!LogonUser("user",TEXT("."),"password",LOGON32_LOGON_BATCH,LOGON32_PROVIDER_DEFAULT,&hUser))
    {
        printf("Login error %s\n",getErrorDescription(GetLastError()));
        return 0;
    }
    BOOL create_ok;
    create_ok = CreateProcessAsUser(hUser,NULL,"C:\\1.exe",NULL,NULL,TRUE,CREATE_SEPARATE_WOW_VDM/* | CREATE_NEW_CONSOLE*/,NULL,"C:\\",&si,&pi);
    if (!create_ok)
    {
        printf("Run error %s\n",getErrorDescription(GetLastError()));
        return 0;
    }
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    CloseHandle(hFile);
    CloseHandle(hUser);
}


Может все-же дело в XP?

Добавлено через 2 минуты и 23 секунды
Цитата(Dem_max @ 29.1.2012,  09:19)
Попробуй без этого флага, но используй функции AllocConsole, AttachConsole

Это не решит проблему.

Автор: xvr 2.2.2012, 18:14
Попробуйте создать открытый для всех Security Descriptor и записать его в sa.lpSecurityDescriptor, возможно процессу банально не хватает прав

Автор: albertn 3.2.2012, 08:29
Цитата(xvr @ 2.2.2012,  18:14)
Попробуйте создать открытый для всех Security Descriptor и записать его в sa.lpSecurityDescriptor, возможно процессу банально не хватает прав

Добавил в начало следующие строчки:
Код

    SECURITY_DESCRIPTOR sd;
    InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
    SetSecurityDescriptorDacl(&sd, TRUE, NULL, TRUE);
    sa.lpSecurityDescriptor = &sd;

Результат работы остался тем-же.

Добавлено через 9 минут и 25 секунд
Кстати, оказывается без флага CREATE_NEW_CONSOLE программа выполняется и выводит в текстовый файл данные, но почему-то CreateProcessAsUser возвращает ошибку.

PS. Консольные win32 программы работают как надо при любых параметрах.

Автор: xvr 3.2.2012, 11:21
Цитата(albertn @  3.2.2012,  08:29 Найти цитируемый пост)
Кстати, оказывается без флага CREATE_NEW_CONSOLE программа выполняется и выводит в текстовый файл данные, но почему-то CreateProcessAsUser возвращает ошибку.

А может ей не нравится NULL в si.hStdIn (кстати - NULL это валидный дескриптор файла)? Попробуйте открыть NUL и передать туда

Автор: albertn 3.2.2012, 11:23
Цитата(xvr @ 3.2.2012,  11:21)
Цитата(albertn @  3.2.2012,  08:29 Найти цитируемый пост)
Кстати, оказывается без флага CREATE_NEW_CONSOLE программа выполняется и выводит в текстовый файл данные, но почему-то CreateProcessAsUser возвращает ошибку.

А может ей не нравится NULL в si.hStdIn (кстати - NULL это валидный дескриптор файла)? Попробуйте открыть NUL и передать туда

Результат тот-же.

Автор: xvr 3.2.2012, 12:11
А попробуйте CREATE_NO_WINDOW или DETACHED_PROCESS вместо CREATE_NEW_CONSOLE

Автор: albertn 3.2.2012, 12:14
Цитата(xvr @ 3.2.2012,  12:11)
А попробуйте CREATE_NO_WINDOW или DETACHED_PROCESS вместо CREATE_NEW_CONSOLE

Выбивает ту-же ошибку.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)