c win32 api - GetStdHandle (STD_OUTPUT_HANDLE) недействителен, очень сбивает с толку - PullRequest
2 голосов
/ 25 февраля 2011

У меня есть следующий фрагмент в моем WinMain, и я запускаю это приложение с графическим интерфейсом из консоли.Я хочу перенаправить вывод на консоль, с которой было запущено мое приложение. Я получаю «Неверный дескриптор».ошибка после GetStdHandle ().

Однако, если я использую AllocConsole вместо AttachConsole, он работает нормально.Кроме того, если я использую STD_ERROR_HANDLE вместо STD_OUTPUTHANDLE, то fprintf (stderr, "errror") работает нормально.

Я увидел запись в блоге, в которой была та же проблема, но нет решения.Я использую компилятор vc 2010 на 64-битных Windows 7.

Спасибо!

bConsole = AttachConsole(ATTACH_PARENT_PROCESS) != FALSE;

if (bConsole)
{
    int fd = 0;
    long lStdOut;
    lStdOut = (long)GetStdHandle(STD_OUTPUT_HANDLE);
    fd = _open_osfhandle(lStdOut, _O_TEXT);
    if (fd > 0)
    {
        *stdout = *_fdopen(fd, "w");
        setvbuf(stdout, NULL, _IONBF, 0 );
    }
}
printf("Test!!!!!!!!!!!!");

Ответы [ 5 ]

6 голосов
/ 25 февраля 2011

AttachConsole ассоциирует ваш процесс с консолью, но stdout уже открыт (и подключен к старому дескриптору, каким бы он ни был).

Прямая перезапись stdout - ужасная идея,Вместо этого вы должны freopen("CONOUT$", "w", stdout);, чтобы stdout отправился на консоль.

Но есть много других мелких деталей.Посмотрите на мой вопрос Куда поступают записи в stdout при запуске из оболочки cygwin, без перенаправления , которое охватывает вашу проблему в вопросе, а затем задает вопрос о некоторых угловых случаях.Наконец, есть пример кода, который включает в себя все.

5 голосов
/ 15 апреля 2011

A Процесс подсистемы Windows (т. Е. Один с WinMain) не будет иметь STDOUT, STDERR или STDIN, если только он не был специально задан при запуске. Предполагается, что, поскольку это программа Windows, вы взаимодействуете с ней через Windows.

т.е. GetStdHandle не возвращает дескриптор STDOUT, потому что у вас нет STDOUT.

Чтобы получить его, запустите его так:

winprog.exe > output.txt 2>&1

Если запустить его таким образом, он будет иметь как STDOUT, так и STDERR, которые оба войдут в указанный файл.

Как уже указывали другие пользователи, AttachConsole выдаст вам консоль (ближайший эквивалент Unix / Linux - TTY), но не даст STDOUT. Если вы хотите один, вам придется установить его как отдельный шаг. Если вы хотите, чтобы это была консоль, вы можете иметь это тоже.

С другой стороны, Консольная подсистема Программа (одна с main) по умолчанию будет иметь STDIN, STDOUT и STDERR, все настроенные на Консоль. Вы можете отсоединить процесс от консоли и закрыть их, если хотите.

2 голосов
/ 25 февраля 2011

Я добавил следующий код в проект графического интерфейса Visual Studio C ++ по умолчанию, в самом начале WinMain.

if (AttachConsole(ATTACH_PARENT_PROCESS))
{
    if (GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE)
        MessageBox(0, L"Invalid Handle", NULL, 0);
    else
        MessageBox(0, L"Valid Handle", NULL, 0);
}

Когда я запускаю программу с графическим интерфейсом из отладчика или из Проводника, нетокно сообщения показывает.Другими словами, мы не можем прикрепить консоль.Когда я запускаю из cmd, я вижу сообщение «Valid Handle».

Я делаю вывод, что на самом деле нет проблем с этим базовым подходом, но что то, что вы нам не показываете, вызывает проблему.

0 голосов
/ 03 июня 2019

Чтобы перенаправить вывод на консоль, используйте следующий код:

AllocConsole();
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

тогда вы можете записать в Консоль используя WriteFile () .

    WriteFile(
        hConsole,                
        L"this is a debug line\n", 
        21, // string length 
        NULL,             // bytes written 
        NULL);
0 голосов
/ 25 февраля 2011

Я думаю, что ваша проблема здесь:

long lStdOut;
lStdOut = (long)GetStdHandle(STD_OUTPUT_HANDLE);
fd = _open_osfhandle(lStdOut, _O_TEXT);

Я не очень хорош с Win32 API, но я думаю, что дескрипторы имеют свои собственные типы HANDLE, которые, я думаю, по сути являются указателями, и 64-битные в Win64. long тип в Win64 по какой-то причине все еще 32-битный.

Это объявление от MSDN:

HANDLE WINAPI GetStdHandle(
  __in  DWORD nStdHandle
);

Декларация для _open_osfhandle:

int _open_osfhandle (
   intptr_t osfhandle,
   int flags 
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...