Пирогов Владислав Юрьевич

О программировании, ИТ и обо всем по немногу

Из цикла Письма
pirogov_vju
Как и обещал, начинаю публиковать некоторые письма ко мне и мои ответы.

Письмо.

Добрый день, уважаемый Владислав Юрьевич!

Пишет вам читатель Вашей книги"Ассемблер для Windows".
И конечно, по ходу чтения возникают достаточно часто вопросы по существу.
В частности,очень актуален ля меня сейчас вопрос о том,
каким образом пои записи в уже созданнйй текстовой файл( с помощью ф-ции"CreateFile")
можно сделать так,чтобы строка текста,которая в этот текстовой файл записывается,
т.е. используя ф-цию"WriteFile",где в качестве второго параметра передаётся адрес строки с текстом,
который и требуется вписать в наш текстовой ф-л( в моём примере он именуется как"D:\NewFile.txt",
т.е. находится в корневом каталоге на диске"D:\"),записывалась бы не просто тупо в одну строчку,
а дробилась бы на несколько,т.е. продолжалась бы строка каждйый раз с новой строки,под предыдущей частью строки,которая
вверху,т.е. столбиком. Ведь реально такие текстовые файлы не кому не нужны,да и это не красиво.
Я пробовал использовать символы экранирования(или,наверно,управляющие символы,как они ещё,видимо,называются), но
в ассемблере,как в языке"C++",они совершенно не работают, в чём вы легко убедитесь,если запустите прграмму
"WriteToFile.exe",которую прилагаю,вместо нужного переноса происходит прсто запись в одну строчку вместе с
самим управляющим символом, вот так:

ќв® Їа®бв®\r\nпробное письмо

Это просто безобразие,и такие"записи" не нужны в принципе.Толку от них нет,
никуда не применимы.
И как же тогда сделать в ассемблере перенос на строку ниже,с помощью какой,может быть,функции,
это необходимо прежде всего уметь делать. Вот такой вот досадный затык.
P.S.: И использование других символов,как например"\0","\n","n\r\" и т.п. приводят к такому же "результату".
Очень буду признателен,если исправите мою эту программу в правильную сторону.
И очень странно,почему в литературе этот вопрос забывают осветить?
Заранее спасибо,с уважением,Сергей.

P.S.:
А вот это прилагаемый листинг моей пробной программы:




;###########################################################################
;В этой проге предприеята просто попытка записать стролки с переносом на следующую строку в созданный
;талько что текстовой файл.
;
;###########################################################################


.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
include \masm32\include\gdiplus.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\gdiplus.lib

WOW proto :DWORD,:DWORD,:DWORD,:DWORD



.data
; struct SYSTEM_INFO SystemInfo
SystemInfo SYSTEM_INFO <>
; struct OSVERSIONINFOA
ovinfo OSVERSIONINFOA <> ;"ovinfo" - это экземпляр стр-ры OSVERSIONINFOA

;dword_1 dd 94h dup(0)
;gVer dd 0
;Txt db 'Наша системная информация',0
TextFile db 'D:\NewFile.txt',0 ;Тут будет располагаться наш создаваемый батник
hFile dd 0
NumberOfBytesWritten dd 0
;Err db 'Ошибка создания файла!',0
WrHdl dd 0
FileName db 'D:\SuperDial.exe',0
TextBatFile dd 2400 dup(?) ;Буфер для финального текста,который будет располагаться потом в батнике
BatText db 'Это просто\r\n',0
TwoBatText db 'пробное письмо',0
Buffer dd 0

.data?
hInstance dd ?
CommandLine dd ?

.code
start:
;Присыоим файлу,который будем удалять,нормальные атрибуты
;push FILE_ATTRIBUTE_NORMAL
;push offset VirusFileName
;call SetFileAttributes
;А тут мы создадим наш батник,пока он будет пустой
push NULL ;указатель на шаблон,который будет использ-ся для создания ф-ла
push FILE_ATTRIBUTE_NORMAL ;or FILE_FLAG_SEQUENTIAL_SCAN ;Атрибуты создаваемого ф-ла- нормальное состоянте ф-ла
;эта конст-та"FILE_ATTRIBUTE_NORMAL" имеет числовое выражение 80h.
push CREATE_ALWAYS ;способ открытия ф-ла - всегда создавать,если ф-л уже существует,
;то данные будут перезаписаны.Пар-р "CREATE_ALWAYS"имннт числовое выражение "2h"
push NULL ;Атрибуты безапосности - не используются.
push NULL ;FILE_SHARE_READ or FILE_SHARE_WRITE ;Режим доступа к открытому ф-лу другим прогам -
;- другим приложениям разрешены чтение и запись. В числовом выр-нии это "3"
push GENERIC_WRITE ;Режим доступа - открыт для записи.
; В числовом выр-нии эти константы имеют значение.
push offset TextFile ;путь, где должен располагаться создаваемый ф-л
call CreateFile ;После вып-ния этого вызова в "EAX" загрузилось число 00000034h,
;а так же изменились значения в рег-рах "ECX","EDX","ESP"
mov hFile,eax
;Теперь преобразуем нашу строку в OEM-определённые установленные символы
push offset BatText
push offset BatText
call CharToOem ;The CharToOem function translates a string into the OEM-defined character set.
;(OEM stands for original equipment manufacturer.)
push offset BatText
call lstrlen
push NULL ;Тут строка, которая используется только в режиме наложения
push offset NumberOfBytesWritten ;!!!Адрес(смещение) в памяти,по которому сохраняется количество
;записываемых в файл байтов.Тут должно быть именно смещение!
push eax ;Количество байтов данных для записи
push offset BatText ;Данные,которые надо записать
push hFile ;Указатель на открытый файл
call WriteFile ;После вып-ния этой команды в "EAX"загрузилоось число"0012FF9A",да и

push offset TwoBatText
call lstrlen
push NULL ;Тут строка, которая используется только в режиме наложения
push offset NumberOfBytesWritten ;!!!Адрес(смещение) в памяти,по которому сохраняется количество
;записываемых в файл байтов.Тут должно быть именно смещение!
push eax ;Количество байтов данных для записи
push offset TwoBatText ;Данные,которые надо записать
push hFile ;Указатель на открытый файл
call WriteFile ;После вып-ния этой команды в "EAX"загрузилоось число"0012FF9A",да и




push hFile
call CloseHandle

push NULL
call ExitProcess


end start



Ответ.

Добрый день Сергей!

Я посмотрел программу и постарался вникнуть в вашу проблему. Теперь я все понял и постараюсь подробно ответить.
Поднятый вами вопрос очень интересен. Постараюсь ответить на него подробно.
Любой файл состоит из последовательности байтов. Значение байтов, как известно, оказывается в промежутке от 0 до 255. В принципе все они совершенно равноправны, если только мы не напишем программу, или функцию, которая будет различать их по значению. Таким образом, если пользуетесь функцией, которая не различает байты, то надо это учитывать. Соответственно это касается функций, которая различает байты по значению и, соответственно, в зависимости от этих значений по разному с ними работает. Кстати вы пользуетесь API-функциями, для которых все байты одинаковы. Функции для работы с текстовыми файлами есть в библиотеке C.
Еще с незапамятных времен байты, значения которых от 0 до 31 стали считать управляющими байтами, т.е. они использовались в служебных целях. Среди них следует выделить два магических байта 13 и 10. Эти байты используются для отметки конца строки текста. Специальные функции С для работы с текстовыми файлами их понимают. Если же, как в вашей программе, использовать универсальные функции для работы с файлами, то для отметки конца строки вам придется самому в конце строки подставлять эти байты. Надо отметить, что в разных операционных системах используются разное сочетание этих байтов для обозначения конца строки:
MS DOS - Windows - последовательность 13,10.
Linux – 10.
Mac OS – 13.
И так, например, вам следует написать строку так
BatText db 'Это просто ',13,10,0
Ну и так далее.
Специальные обозначения типа \n и т.п. используются в языке C, в функциях, которые их понимают, например семействе printf. Подобные же обозначения используются во многих скриптовых языках. В ассемблере же они бесполезны.

С наилучшими пожеланиями, Пирогов В.Ю.

PS
Пишите, если будут вопросы.

Пирогов В.Ю. (http://asm.shadrinsk.net)

?

Log in

No account? Create an account