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

来源:互联网 发布:微信直播 阿里云 编辑:程序博客网 时间:2024/05/16 14:19

我们应该都知道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_NEUTRALIDD_DIALOG1 DIALOG 0, 0, 186, 95STYLE DS_3DLOOK | DS_CENTER | DS_CONTEXTHELP | DS_MODALFRAME | DS_SETFONT | WS_CAPTION | WS_VISIBLE | WS_GROUP | WS_TABSTOP | WS_POPUP | WS_SYSMENUCAPTION "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_NEUTRALIDI_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.incinclude          user32.incincludelib       user32.libinclude          kernel32.incincludelib       kernel32.libinclude          comdlg32.incincludelib       comdlg32.libIDI_ICON1        equ        102IDD_DIALOG1      equ        103IDC_BROWSE       equ        40000IDC_FILE         equ        40001                 .data?hInstance        dd         ?hWinMain         dd         ?szFileName       db         MAX_PATH dup (?)                 .constszFileExt        db         '文本文件',0,'*.txt',0,0szNewFile        db         '.new.txt',0szErrOpenFile    db         '无法打开源文件!',0szErrCreateFile  db         '无法创建新的文本文件!',0szSuccess        db         '文件转换成功,新的文本文件保存为',0dh,0ah,'%s',0szSuccessCap     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 endpstart:                 invoke    GetModuleHandle,NULL                 mov       hInstance,eax                 invoke    DialogBoxParam,hInstance,IDD_DIALOG1,NULL,offset _ProcDlgMain,NULL                 invoke    ExitProcess,NULL                 end       start


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

本次程序分析到此结束。




1 0
原创粉丝点击