Скажите пожалуйста, как перенаправить вывод с консоли в файл?

Тема в разделе "WASM.BEGINNERS", создана пользователем amvoz, 10 ноя 2009.

  1. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Код (Text):
    1. .386
    2.  
    3. .model flat,stdcall
    4. option casemap:none
    5. include \masm32\include\windows.inc
    6. include \masm32\include\kernel32.inc
    7. includelib \masm32\lib\kernel32.lib
    8.  
    9. include \masm32\include\user32.inc
    10. includelib \masm32\lib\user32.lib
    11.  
    12.  
    13. StrDisp proto: DWORD, :DWORD
    14.  
    15.  
    16. .DATA
    17.  
    18. ;Это вот будет тестовое сообщение
    19. SOOBCHENIE db "testovoe soobchenie",10, 13
    20.  
    21. .DATA?
    22. ;Тут вот дескриптор консоли будет храниться
    23. stdout dd ?
    24.  
    25.  
    26. .code
    27. start:
    28.  
    29.  
    30.  ;Это дескриптор консоли мы находим
    31.  invoke GetStdHandle, STD_OUTPUT_HANDLE
    32.  mov stdout , eax
    33.  
    34.  
    35.  invoke WriteConsole, stdout, addr SOOBCHENIE, sizeof SOOBCHENIE, 0,0
    36.  invoke ExitProcess, 0
    37.  
    38. end start
    Запуска. в консоли так:
    proga.exe> rez.txt

    Создаётся ПУСТОЙ текстовый файл. Помогите, пожалуйста. Веде в google говорят, что надо так ">", я так и делаю.
    Пока на С кодил без проблем было. Спасибо.
     
  2. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    На форуме, в правилах есть вроде бы правила составления вопросов.
    GetLastError() где?

     
  3. dyn

    dyn New Member

    Публикаций:
    0
    Регистрация:
    30 окт 2009
    Сообщения:
    566
    Ты создаешь НЕ консольное приложение.
    Таким образом invoke GetStdHandle, STD_OUTPUT_HANDLE возвращает 0
    Укажи в настройках линкера /SUBSYSTEM:CONSOLE
     
  4. dyn

    dyn New Member

    Публикаций:
    0
    Регистрация:
    30 окт 2009
    Сообщения:
    566
    Плюс, ошибка в АПИ, на которую указали выше
     
  5. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    o14189GetLastError, нет и как мне её использовать я не знаю. В правилах тоже ничего нет про неё.
    Скажи пожалуйста, как мне её использовать. (Хотя WriteConsole НАВЕРНОЕ работает без ошибок, см. ниже)

    Я так понимаю, что четвёртый параметр, адрес переменной, где хранятся количество записаных байт. И он необязателен, насколько я знаю. Мне он не нужен, потому и ноль.
    Но как быто ни было, вот новый код, добавил четвёртый параметр.
    Бесполезно.

    ...Ребята, если бы WriteConsole не работала вообще, я бы так и написал.
    Она вполне нормально работает, если запускать прогу так: proga.exe
    Всё выводится на экран. Только в файл не перенаправляется. (proga.exe> rez.txt)

    И именно поэтому, (привет dyn), я делаю вывод, что у меня приложение именно консольное. А ещё и потому, что 100 раз перепроверил эту настройку /SUBSYSTEM:CONSOLE, прежде чем вопрос такой задавать.

    Код (Text):
    1. .386
    2.  
    3. .model flat,stdcall
    4. option casemap:none
    5. include \masm32\include\windows.inc
    6. include \masm32\include\kernel32.inc
    7. includelib \masm32\lib\kernel32.lib
    8.  
    9. include \masm32\include\user32.inc
    10. includelib \masm32\lib\user32.lib
    11.  
    12.  
    13. StrDisp proto: DWORD, :DWORD
    14.  
    15.  
    16. .DATA
    17.  
    18. ;Это вот будет тестовое сообщение
    19. SOOBCHENIE db "testovoe soobchenie",10, 13
    20.  
    21. .DATA?
    22. ;Тут вот дескриптор консоли будет храниться
    23. stdout dd ?
    24.  
    25. dla_hr_kol_arg dd ?
    26.  
    27.  
    28. .code
    29. start:
    30.  
    31.  
    32.  ;Это дескриптор консоли мы находим
    33.  invoke GetStdHandle, STD_OUTPUT_HANDLE
    34.  mov stdout , eax
    35.  
    36.  
    37.  invoke WriteConsole, stdout, addr SOOBCHENIE, sizeof SOOBCHENIE, addr dla_hr_kol_arg,0
    38.  invoke ExitProcess, 0
    39.  
    40. end start
     
  6. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Все правильно. Нужно определить тип хендла и использовать WriteFile.

    В MSDN самая важная информация пишется внизу мелким шрифтом и по началу ее не читают

    Both WriteConsole and WriteFile can be used for console I/O. While WriteConsole supports writing Unicode characters to a console screen buffer, WriteFile does not. However, WriteConsole fails if it is used with a standard handle that is redirected to a file. If an application handles multilingual output that can be redirected, determine whether the output handle is a console handle (one method is to call the GetConsoleMode function and check whether it succeeds). If the handle is a console handle, call WriteConsole; otherwise, the output is redirected and you should call WideCharToMultiByte to convert the text to the current code page and WriteFile to perform the I/O.
     
  7. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Тогда я по-другому спрошу. Можно ли перенаправить вывод не на консоль, а в файл, не используя WriteFile?

    В языке С, например, можно.
    Пишем

    Код (Text):
    1. #include <stdio.h>
    2. int main () {
    3.  printf ("Hello, word!");
    4.  returen 0;
    5. }
    Потом пишем так: proga.exe> rez.txt и Hello, word! окажется в файле rez.txt
    Обращаю Ваше внимание, что мы не используем WriteFile для запси в файл, равно как и не используем, например fprintf, putc и прочее. И файл мы не открываем. Нет в коде СreateFile, fopen, OpenFile...

    Мы просто пишем такой значок ">" и всё.
    Вот я про ассемблер то же самое спрашиваю. Как перенаправить вывод, скажите пожалуйста!
     
  8. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    собери то что ты привел и импорт посмотри
     
  9. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Упрощено, когда пишем > то хендл файла rez.txt оказывается в PEB процесса вместо псевдохендла консоли. WriteConsole не может работать с такими хендлами, она отправлет выводимый текст через RPC менеджеру консолей CSRSS, который рисует его на экране. WriteFile понимает оба вида хендлов (если ей передается псевдохендл, она делает WriteConsole). Но как её быть при выводе 2х байтных символов юникода? В консоль выводится один символ, а в файл можно писать либо 2 байта, либо сконвертировать 1. Поэтому MSDN перекладывает решение этого вопроса на пользователя.
     
  10. dyn

    dyn New Member

    Публикаций:
    0
    Регистрация:
    30 окт 2009
    Сообщения:
    566
    интересно, тс специально подбирает такие вопросы, чтобы протроллить форум?
     
  11. o14189

    o14189 New Member

    Публикаций:
    0
    Регистрация:
    19 июл 2009
    Сообщения:
    320
    Код (Text):
    1. ;=>WriteConsoleA
    2.  
    3. ;...
    4. mov     ebx, [ebp+lpNumberOfCharsWritten]
    5. ;...
    6. mov     [ebx], eax
    7. ;...
    лучше доверять документации все же: всякие msdn там, wdk и т.п. понятное дело что эта документация, как и любая документация к любому sdk полное говно и пишется абы зря, но тем кто пытается его юзать лучше все-таки документацию читать, а не наугад хуярить что-попало
     
  12. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Замечание верно, но к теме вопроса не относится. Если посмотреть реализацию WriteConsole, окажется, что можно передавать 0 вместо lpNumberOfCharsWritten, функция вернет ошибку, но текст выведет.
     
  13. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    o14189
    AddAtomA ExitProcess FindAtomA AtomNameA SetUnhandledExceptionFilter

    __ getmainargs __p__environ __p__fmode __set_app_type _cexit

    _iob _onexit _setmode abort atexit fflush fprintf free malloc printf signal
    J0E, я Вас понял, настолько, чтобы задать следующий вопрос.

    Так а мне где хэндл файла брать для WriteFile? Первый параметр где взять?
    Смотрите, некоторым путём (щас неважно, каким) cоздался файл rez.txt, открылся объект ядра "файл" (видите, тоже знаю умные слова) и hFile щас спокойно лежит в блоке переменных окружения.процесса proba.exe

    Ещё раз: а как его оттуда достать? Шерстить PEB? Я могу вызвать GetEnvironmentStrings, а где там его искать? Мне кажется какой-то способ существует найти там hFile и передать его первым параметром WriteConsole. Извините.

    Честно говоря, я не понимаю ничё в этой ситуации. Ну, например.

    1) Мне необходимо саll WriteFile безусловно писать? Я ведь не знаю, как буду вызывать proga.exe. То ли буду вывод в файл перенаправлять, то ли нет. Если буду, то неоходимо писать call WriteFile, а если не буду то обходиться одной лишь WriteConsole?

    Получается два кода. Фигня какая-то ей-Богу.

    2) Наконец, вот я привёл там таблицу импорта и видно, что задействована функция fprintf. То есть.
    Если не направляю вывод в файл, то fprintf не вызывается, если направляю, то выывается.
    Два разных случая, прога по разному себя ведёт. На ходу патчится, что ли?
    Короче, я всё уже. Вообще ничё не понимаю.
    Блин, раньше просто писал ">" и горя не знал...

    Ребята, помогите, кто может!
     
  14. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Таблица импорта и вопрос 2) относится к проге на С
     
  15. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Хендл получаем как обычно, GetStdHandle (она сама прошерстит PEB). Потом определяем тип хендла, MSDN рекомендует GetConsoleMode (для файловых хендлов она вернет ошибку), но можно проверить 2 младших бита, у псевдохендлов они оба в 1. И вызываем WriteFile или WriteConsole исходя из этого.
     
  16. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    На импорт забей, printf импортируется из C run time dll. Что бы увидеть нормальный импорт нужно линковать CRT статически. Проще посмотреть как реализован printf, благо исходники crt открыты, идут со студией.
     
  17. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Буду разбираться, но это вот не так.
    Ибо:

    Увидел в Вашем сообщении номер 9 слова

    "хендл файла rez.txt оказывается в PEB процесса вместо псевдохендла консоли"
    Сообразил, что GetStdHandle оттуда и извлекает псевдохэндл. Cтал искать где он там есть
    Написал так:

    Код (Text):
    1.  CALL GetEnvironmentStrings
    2.  
    3.  invoke GetStdHandle, STD_OUTPUT_HANDLE
    4.  mov stdout , eax
    Открыл это дело в OllyDbg, поставил бряк после вызова GetEnvironmentStrings (), нажал на F9, посмотрел EAX, увидел что-то такое 1429C0, пошёл по этому адресу, точно PEB, ставлю бряк на всю его память, но GetStdHandle срабатывает без проблем, значит, она берёт его не оттуда. Потом ставлю бряк на вызов
    GetStdHandle, просматриваю её, благо она с гулькин нос и вижу, что она берёт псевдохэндл консоли по адресу 2001C. Что за адрес- ума не приложу, но не PEB и не командная строка.

    Вот такой вот у меня щенячий восторг, что я могу Вас поправить. (Не будете корректировки вносить?)
    Спасибо, пошёл думать над остальным.
     
  18. amvoz

    amvoz Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2008
    Сообщения:
    653
    Маленько расслаблюсь, и так всю ночь за компом...
    То есть ещё и IF ELSE реализовывать?
    Кошмар...
    Да нет, без проблем, сделаю я условный вызов, только не думал я что так громоздко получится, я думал всё проще как-то на ассемблере будет, чем на том же С...
     
  19. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    По адресам 20000 лежит структура RTL_USER_PROCESS_PARAMETERS, а в ней StandardInput. В PEB есть указатель ProcessParameters на эту структуру.
     
  20. J0E

    J0E New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2008
    Сообщения:
    621
    Адрес:
    Panama
    Если Юникод не используешь, хватит WriteFile. Ассемблер от С принципиально ничем не отличается, там можно вызывать и printf из msvcrt.dll