win32汇编 实现UNIX文件格式转换WINDOWS文件格式 的功能

我们应该都知道UNIX环境下的文本文档中的回车加换行是直接由  "0ah"  实现的,而windows环境下的回车换行需要"0dh,0ah" 实现,所以如果把UNIX环境下的文本文档拿过来在WINDOWS环境下查看,那么文本的显示格式就乱了,结果是windows读不懂UNIX环境下的换行符,他以为是一行,事实也就是文本显示的就是一行,只能靠水平滚动条来回拖动查看,的确看着不爽,这次利用WIN32汇编语言 结合windows环境下内存管理的内容实现将UNIX文件格式转换为windows环境下的文件格式 的功能。下面看一下实现该功能的几个分步操作。

资源文件
图标IDI_ICON1
对话框IDD_DIALOG1
静态文本框LTEXT类  在对话框中编辑文本框左边输入提示字符“文件名”
编辑文本框可以输入文本,显示要打开的文件名
按钮“开始”   “浏览”两个按钮

程序功能实现代码
处理缓冲区中(单行文本)的文本_FormatText()
载入文件的处理_ProcFile()
对话框窗口过程_ProcDlgMain()
创建模态对话框DialogBoxParam()

上面就是实现该功能的具体分支,下面首先来看一下资源文件中的问题:

资源文件中在使用ResEdit工具编写的时候,在对话框的风格中总会有一个风格DS-SHELLFONT,这个风格总是无效的,在用RadASM编译ResEdit工具编写的资源脚本的时候总会出现未找到定义的风格DS_SHELLFONT

也就是说在头文件的一些定义中并没有该风格的定义,总会出错,然后我果断的把这个风格从资源代码中移除。。。,结果呢,资源脚本可以编译运行了,那么这个风格到底是几个意思,如果要想用它的话怎么办呢?

我们还是来看一下MSDN博客是怎么说的,下面是连接:https://blogs.msdn.microsoft.com/oldnewthing/20050204-00/?p=36523/

具体可以参考一下,说的貌似很有道理,文件的版本需要更高才可以。

资源文件就这么多问题其他的就是以前常用的操作了,很熟练了。下面具体看一下资源脚本代码:

/

/ Generated by ResEdit 1.6.6
// Copyright (C) 2006-2015
// http://www.resedit.net
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include "resource.h"
//
// Dialog resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG1 DIALOG 0, 0, 186, 95
STYLE DS_3DLOOK | DS_CENTER | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFONT | WS_CAPTION | WS_VISIBLE | WS_GROUP | WS_TABSTOP | WS_POPUP | WS_SYSMENU
CAPTION "UNIX Text file -> PC Text file"
FONT 8, "Ms Shell Dlg"
{
    PUSHBUTTON      "开始", IDOK, 127, 70, 46, 18, 0, WS_EX_DLGMODALFRAME
    PUSHBUTTON      "浏览", IDC_BROWSE, 49, 70, 44, 18, NOT WS_TABSTOP | BS_VCENTER | BS_MULTILINE, WS_EX_DLGMODALFRAME | WS_EX_STATICEDGE
    LTEXT           "文件名", 0, 17, 20, 43, 11, SS_LEFT, WS_EX_LEFT
    EDITTEXT        IDC_FILE, 50, 18, 135, 16, ES_AUTOHSCROLL, WS_EX_DLGMODALFRAME | WS_EX_ACCEPTFILES
}
//
// Icon resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDI_ICON1          ICON           "icon2.ico"

本来想上传资源文件显示的截图的,但是上传文件时老出错误,就不传了。


下面看一下实现程序代码中遇到的问题:

这次程序中首先遇到的问题就是在处理缓冲区中的一单行的文本的时候,好多问题,下面来看一下子程序

_FormatText      proc       uses esi _lpData,_dwSize,_hFile                         ;首先该子程序需要三个参数,该子函数在_ProcFile()子程序中调用,_lpdata 就是将                                                                                                                      一行文本读入到缓 冲区中,_lpData指向这个缓冲区,_dwSize  指向实际读入的                                                                                                                      字节数,_hFile就是文件名只不过这个                                                                                                                                                                                    文件名是存放在缓冲区中

        LOCAL      @szBuffer[128]:byte,@dwBytesWrite

        mov        esi,_lpData                                                                     ;esi寄存器作为源操作内容存放的开始地址
        mov        ecx,_dwSize                                                                    ;作为循环的计数
        lea        edi,@szBuffer                                                                   ;另开一个缓冲区将其地址存放到目的寄存器edi中
        xor        edx,edx
        cld                                                                                                     ;将0标志位清零,表示传递数据的时候地址递增,    std命令则相反。
_LoopBegin:                                                                                           ;一个标志 ,为了方便
                   or    ecx,ecx                                                                           ;或运算   其实就是ecx的值
                   jz    _WriteLine
                   lodsb                                                                                       ;把esi寄存器中的内容从头开始依次放到al中,与stosb对应,stosb将al的                                                                                                                                  内容依次放到edi中
                   dec   ecx
                   cmp   al,0dh
                   jz    _LoopBegin
                   cmp   al,0ah
                   jz    _LineEnd
                   stosb                                                                                          ;stosb将al的内容依次放到edi中,与lodsb对应
                   inc   edx
                   cmp   edx,sizeof @szBuffer-2                                                ;这个子程序处理的是一行文本而且这一行文本就放在缓冲区@szBuffer中,一                                                                                                                          行文本最后就是0dh,                                                                                                                                                                                                           0ah,回车加换行,正好两个字节,如果处理的字节数edx大于等于缓冲区                                                                                                                                  总字节数减去2的值,那么                                                                                                                                                                                                   表示这一行的文本已经处理完了。
                   jae   _WriteLine                                                                        ;大于等于则跳转
                   jmp   _LoopBegin
_LineEnd:
                   mov   ax,0a0dh
                   stosw                                                                                          ;同stosb指令一个属性,只不过stosw是将ax中的内容放到edi中,与                                                                                                                                               lodsw对应
                   inc   edx                                                                                       ;这里讲edx计数器连续自加两次,原因就是stosw将两个字节(0dh,                                                                                                                                              0ah)读入到了edi中,处理了                                                                                                                                                                                           两个字节
                   inc   edx
_WriteLine:          
                   push  ecx
                   .if   edx
                    invoke  WriteFile,_hFile,addr @szBuffer,edx,addr @dwBytesWrite,NULL
                   .endif        
                   lea   edi,@szBuffer              ;上面代码中已经将@szBuffer的地址传递给edi在这里再传一次还有必要么?经过我的测试发现,确实需要再传一                                                                       次,不然的话程序会出错退出
                   xor   edx,edx
                   pop   ecx
                   or    ecx,ecx
                   jnz   _LoopBegin
                   ret


_FormatText endp



关于上面子程序的介绍应该已经很清楚了。

下面来看一下另一个问题:

以前也遇见过这个问题记不清楚了也没有解决,今天在这个程序中也用到了这个指令,如下一段代码所示:

             

   .while     TRUE
           lea      esi,@szReadBuffer
           invoke   ReadFile,@hFile,esi,sizeof @szReadBuffer,addr @dwBytesRead,0
           .break   .if  ! @dwBytesRead           ;这一行
           invoke   _FormatText,esi,@dwBytesRead,@hFileNew
        .endw


如上面标注的一行  .break   .if  [条件]        这个语句

具体的意思就是:如果满足.if  中的条件则终止循环,跳出循环执行下面的语句。

与值对关的还有.continue     .if [条件]   如果满足条件则结束当前语句,从新循环。


说完了这两个问题,下面来详细看一下程序实现代码:

                

 .386
                 .model flat, stdcall
                 option casemap :none
                 
include          windows.inc
include          user32.inc
includelib       user32.lib
include          kernel32.inc
includelib       kernel32.lib
include          comdlg32.inc
includelib       comdlg32.lib


IDI_ICON1        equ        102
IDD_DIALOG1      equ        103
IDC_BROWSE       equ        40000
IDC_FILE         equ        40001


                 .data?
hInstance        dd         ?
hWinMain         dd         ?
szFileName       db         MAX_PATH dup (?)


                 .const
szFileExt        db         '文本文件',0,'*.txt',0,0
szNewFile        db         '.new.txt',0
szErrOpenFile    db         '无法打开源文件!',0
szErrCreateFile  db         '无法创建新的文本文件!',0
szSuccess        db         '文件转换成功,新的文本文件保存为',0dh,0ah,'%s',0
szSuccessCap     db         '提示'
     
                 .code
_FormatText      proc       uses esi _lpData,_dwSize,_hFile

        LOCAL      @szBuffer[128]:byte,@dwBytesWrite
        mov        esi,_lpData
        mov        ecx,_dwSize
        lea        edi,@szBuffer
        xor        edx,edx
        cld
_LoopBegin:
                   or    ecx,ecx
                   jz    _WriteLine
                   lodsb
                   dec   ecx
                   cmp   al,0dh
                   jz    _LoopBegin
                   cmp   al,0ah
                   jz    _LineEnd
                   stosb
                   inc   edx
                   cmp   edx,sizeof @szBuffer-2
                   jae   _WriteLine
                   jmp   _LoopBegin
_LineEnd:
                   mov   ax,0a0dh
                   stosw  
                   inc   edx
                   inc   edx
_WriteLine:          
                   push  ecx
                   .if   edx
                    invoke  WriteFile,_hFile,addr @szBuffer,edx,addr @dwBytesWrite,NULL
                   .endif        
                   lea   edi,@szBuffer              ;上面代码中已经将@szBuffer的地址传递给edi在这里再传一次还有必要么?
                   xor   edx,edx
                   pop   ecx
                   or    ecx,ecx
                   jnz   _LoopBegin
                   ret


_FormatText endp


_ProcFile        proc

        LOCAL      @hFile,@hFileNew,@dwBytesRead
        LOCAL      @szNewFile[MAX_PATH]:byte
        LOCAL      @szReadBuffer[512]:byte
        invoke     CreateFile,addr szFileName,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0     ;打开
        .if        eax  ==  INVALID_HANDLE_VALUE
           invoke   MessageBox,hWinMain,addr szErrOpenFile,NULL,MB_OK or MB_ICONEXCLAMATION
           ret
        .endif
        mov        @hFile,eax
        invoke     lstrcpy,addr @szNewFile,addr szFileName
        invoke     lstrcat,addr @szNewFile,addr szNewFile
        invoke     CreateFile,addr @szNewFile,GENERIC_WRITE,FILE_SHARE_READ,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0       ;创建
        .if        eax  ==  INVALID_HANDLE_VALUE
           invoke   MessageBox,hWinMain,addr szErrCreateFile,NULL,MB_OK or MB_ICONEXCLAMATION
           invoke   CloseHandle,@hFile
           ret
        .endif
        mov        @hFileNew,eax
        xor        eax,eax
        mov        @dwBytesRead,eax
        .while     TRUE
           lea      esi,@szReadBuffer
           invoke   ReadFile,@hFile,esi,sizeof @szReadBuffer,addr @dwBytesRead,0
           .break   .if  ! @dwBytesRead
           invoke   _FormatText,esi,@dwBytesRead,@hFileNew
        .endw
        invoke     CloseHandle,@hFile
        invoke     CloseHandle,@hFileNew
        invoke     wsprintf,addr @szReadBuffer,addr szSuccess,addr @szNewFile
        invoke     MessageBox,hWinMain,addr @szReadBuffer,addr szSuccessCap,MB_OK
        ret


_ProcFile endp


_ProcDlgMain     proc       uses ebx edi esi hWnd,wMsg,wParam,lParam
        
                 LOCAL      @stOpenFileName:OPENFILENAME
                 mov        eax,wMsg
                 .if        eax  ==  WM_CLOSE
                     invoke   EndDialog,hWnd,NULL
                 .elseif    eax  ==  WM_INITDIALOG
                     push     hWnd
                     pop      hWinMain
                     invoke   LoadIcon,hInstance,IDI_ICON1
                     invoke   SendMessage,hWnd,WM_SETICON,ICON_BIG,eax
                     invoke   SendDlgItemMessage,hWnd,IDC_FILE,EM_SETLIMITTEXT,MAX_PATH,0
                 .elseif    eax  ==  WM_COMMAND
                     mov      eax,wParam
                     .if      ax  ==  IDC_BROWSE
                         invoke  RtlZeroMemory,addr @stOpenFileName,sizeof OPENFILENAME
                         mov     @stOpenFileName.lStructSize,sizeof @stOpenFileName
                         mov     @stOpenFileName.Flags,OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST
                         push    hWinMain
                         pop     @stOpenFileName.hwndOwner
                         mov     @stOpenFileName.lpstrFilter,offset szFileExt
                         mov     @stOpenFileName.lpstrFile,offset szFileName
                         mov     @stOpenFileName.nMaxFile,MAX_PATH
                         invoke  GetOpenFileName,addr @stOpenFileName
                         .if     eax
                             invoke  SetDlgItemText,hWnd,IDC_FILE,addr szFileName
                         .endif
                      .elseif ax  ==  IDC_FILE
                              invoke  GetDlgItemText,hWnd,IDC_FILE,addr szFileName,MAX_PATH
                              mov     ebx,eax
                              invoke  GetDlgItem,hWnd,IDOK
                              invoke  EnableWindow,eax,ebx
                      .elseif ax  ==  IDOK
                              call    _ProcFile
                     .endif
                 .else
                     mov      eax,FALSE
                     ret
                 .endif 
                 mov        eax,TRUE
                 ret


_ProcDlgMain endp


start:
                 invoke    GetModuleHandle,NULL
                 mov       hInstance,eax
                 invoke    DialogBoxParam,hInstance,IDD_DIALOG1,NULL,offset _ProcDlgMain,NULL
                 invoke    ExitProcess,NULL
                 end       start


这次程序中使用的API函数和一些结构在以前的文章中都做过总结,没有出现新的内容,不在赘述,有某些不熟悉的,请查看以前的文章中的API函数和结构的信息的  详细描述。

本次程序分析到此结束。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值