一些与文件有关的函数

; file.asm

.686p
.model  stdcall, flat
option  casemap: none

include windows.inc
include kernel32.inc
include user32.inc
includelib kernel32.lib
includelib user32.lib
include comdlg32.inc
includelib comdlg32.lib

include common.inc
include file.inc

.code
; "d:\masm32\bin\ml.exe" -> "d:\"
_GetFileRootPathName proc fullFileName, rootPathName
;处理如"j:abc.txt"或"j:.\abc.txt"这样的路径名
        mov     eax, fullFileName
        mov     ecx, rootPathName
        mov     al, [eax]
        mov     [ecx], al
        mov     word ptr [ecx+1], '\:'
        mov     byte ptr [ecx+3], 0
        ret
_GetFileRootPathName endp

; 弹出“打开文件”(模态)通用对话框
;       可以在文件名框中直接输入文件名:可以为文件名两头加上"", 也可以用相对路径, 如..\pe1.zip或"..\pe1.zip"
;       GetSaveFileName会自动处理成绝对路径,且去除掉双引号
;       可以在文件名框中直接输入如j:abc.txt的文件名,会被处理成j:.\abc.txt, 可以被CreateFile()等成功解释
; out:
; 在输入后返回一个非0双字:
;       低16位为文件名在pszBufFileName指定的缓冲区中的位置,为索引值
;       高16位为文件扩展名在pszBufFileName指定的缓冲区中的位置,为索引值
; 若用户取消输入,返回0
; in:
; hwndOwner: 对话框的拥有者窗口的句柄;
; pszCaption: 对话框将要显示的标题字符串的地址
; pszInitialDir: 对话框要初始打开的目录,NULL为当前目录
; pszFilter: 指定对话框要显示的文件的类型,按扩展名,格式为:
;       "描述文件类型的字符串1", 0, "指定扩展名的字符串1", 0,
;       "描述文件类型的字符串2", 0, "指定扩展名的字符串2", 0, ... ,
;       "描述文件类型的字符串n", 0, "指定扩展名的字符串n", 0, 0
;       注意在最后一对字符串的末尾多加个0,用来表示全部过滤字符串的结束
;       e.g.: "c code", 0, "*.c;*.h", 0, "asm code", 0, "*.asm;*.inc", 0, 0
;       在一个扩展名字符串中可指定多个扩展名,各个扩展名之间以;隔开    
; pszFilter: 保存指定的文件名的完整路径的缓冲区的地址
; cchBuf: pszFilter指定的缓冲区的大小,以字符计
_GetOpenFileNameDialogBox proc hwndOwner, pszCaption, \
        pszInitialDir, pszFilter, pszBufFileName, cchBuf
        
        local   @ofn: OPENFILENAME
        
        mov     @ofn.lStructSize, size OPENFILENAME
        mov     @ofn.hInstance, NULL
        mov     @ofn.lpstrCustomFilter, NULL
        mov     @ofn.nMaxCustFilter, 0
        mov     @ofn.lpstrFileTitle, NULL
        mov     @ofn.nMaxFileTitle, 0
        mov     @ofn.lpstrDefExt, NULL
        mov     @ofn.lCustData, NULL
        mov     @ofn.lpfnHook, NULL
        mov     @ofn.lpTemplateName, NULL
                
        mov     @ofn.nFilterIndex, 1 ;初始使用 过滤文件扩展名的第一个
        
        m2m     @ofn.hWndOwner, hwndOwner
        m2m     @ofn.lpstrTitle, pszCaption
        
        m2m     @ofn.lpstrInitialDir, pszInitialDir
        m2m     @ofn.lpstrFilter, pszFilter
        
        m2m     @ofn.lpstrFile, pszBufFileName
        mov     eax, pszBufFileName
        mov     byte ptr [eax], 0       ;不在“文件名”文本编辑框显示任何文件名
        m2m     @ofn.nMaxFile, cchBuf
 
        mov     @ofn.Flags, OFN_FILEMUSTEXIST or \
                        OFN_PATHMUSTEXIST or OFN_LONGNAMES or\
                        OFN_HIDEREADONLY
       
        invoke  GetOpenFileName, addr @ofn
        .if eax
                movzx   eax, @ofn.nFileExtension
                shl     eax, 16
                mov     ax, @ofn.nFileOffset
        .endif
        ret
_GetOpenFileNameDialogBox endp

; 弹出“另存为”(模态)通用对话框
;       可以在文件名框中直接输入文件名:可以为文件名两头加上"", 也可以用相对路径, 如..\pe1.zip或"..\pe1.zip"
;       GetSaveFileName会自动处理成绝对路径,且去除掉双引号
;       可以在文件名框中直接输入如j:abc.txt的文件名,会被处理成j:.\abc.txt, 可以被CreateFile()等成功解释
; out:
; 在输入后返回一个非0双字:
;       低16位为文件名在pszBufFileName指定的缓冲区中的位置,为索引值
;       高16位为文件扩展名在pszBufFileName指定的缓冲区中的位置,为索引值
; 若用户取消输入,返回0
; in:
; hwndOwner: 对话框的拥有者窗口的句柄;
; pszCaption: 对话框将要显示的标题字符串的地址
; pszInitialDir: 对话框要初始打开的目录,NULL为当前目录
; pszFilter: 指定对话框要显示的文件的类型,按扩展名,格式为:
;       "描述文件类型的字符串1", 0, "指定扩展名的字符串1", 0,
;       "描述文件类型的字符串2", 0, "指定扩展名的字符串2", 0, ... ,
;       "描述文件类型的字符串n", 0, "指定扩展名的字符串n", 0, 0
;       注意在最后一对字符串的末尾多加个0,用来表示全部过滤字符串的结束
;       e.g.: "c code", 0, "*.c;*.h", 0, "asm code", 0, "*.asm;*.inc", 0, 0
;       在一个扩展名字符串中可指定多个扩展名,各个扩展名之间以;隔开    
; pszFilter: 保存指定的文件名的完整路径的缓冲区的地址
; cchBuf: pszFilter指定的缓冲区的大小,以字符计
_GetSaveAsFileNameDialogBox proc hwndOwner, pszCaption, \
        pszInitialDir, pszFilter, pszBufFileName, cchBuf
        
        local   @ofn: OPENFILENAME
        
        mov     @ofn.lStructSize, size OPENFILENAME
        mov     @ofn.hInstance, NULL
        mov     @ofn.lpstrCustomFilter, NULL
        mov     @ofn.nMaxCustFilter, 0
        mov     @ofn.lpstrFileTitle, NULL
        mov     @ofn.nMaxFileTitle, 0
        mov     @ofn.lpstrDefExt, NULL
        mov     @ofn.lCustData, NULL
        mov     @ofn.lpfnHook, NULL
        mov     @ofn.lpTemplateName, NULL
                
        mov     @ofn.nFilterIndex, 1 ;初始使用 过滤文件扩展名的第一个

        m2m     @ofn.hWndOwner, hwndOwner
        m2m     @ofn.lpstrTitle, pszCaption
        
        m2m     @ofn.lpstrInitialDir, pszInitialDir
        m2m     @ofn.lpstrFilter, pszFilter
        
        m2m     @ofn.lpstrFile, pszBufFileName
        mov     eax, pszBufFileName
        mov     byte ptr [eax], 0       ;不在“文件名”文本编辑框显示任何文件名
        m2m     @ofn.nMaxFile, cchBuf
 
        mov     @ofn.Flags, OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_HIDEREADONLY

        invoke  GetSaveFileName, addr @ofn
        .if eax
                movzx   eax, @ofn.nFileExtension
                shl     eax, 16
                mov     ax, @ofn.nFileOffset
        .endif        
        ret
_GetSaveAsFileNameDialogBox endp

; 在edit或richedit控件上显示文本文件的内容,支持纯英文或英文与GB汉字混合的文本文件
;     支持各种形式的换行:windows的CR, LF方式;UNIX的LF方式;mac的CR方式; 不符合格式的LF, CR会换两行
; in:
;       hDlg: edit或richedit控件的父窗口的句柄
;       idEdit: edit或richedit控件在父窗口中的ID
;       pszTextFileName: 指向文本文件名字符串
; out: void
_EditShowTextFile proc uses ebx esi edi hDlg, idEdit, pszTextFileName
        local   @hFile, @cbReadWritten
        local   @szFileContent[32]:byte ;留1字节保存0字符
        
        invoke  CreateFile, pszTextFileName, GENERIC_READ,\
                        FILE_SHARE_READ,\
                        NULL,OPEN_EXISTING,0,NULL
        .if eax!=INVALID_HANDLE_VALUE
                mov     @hFile, eax
                invoke  SetDlgItemText, hDlg, idEdit, NULL
                .while 1
                        invoke  ReadFile, @hFile,\
                                        addr @szFileContent, sizeof @szFileContent-1,\
                                        addr @cbReadWritten, NULL
                        .if eax
                                ; 文件已读完?
                                .break  .if !@cbReadWritten  ; 这句要加,否则edi会变成0ffffffffh, 总是>=esi
                                
                                mov     edi, @cbReadWritten
                                dec     edi ;edi总是缓冲区中的最后一个有效字节在缓冲区中的偏移
                                
                                xor     esi, esi ; esi为当前要检查的字符在缓冲区中的偏移
                                xor     ebx, ebx  
                                ; 可能需要多次追加,ebx为当前要追加的字符串在缓冲区中的偏移
                                
                                .while esi<=edi
                                        .if @szFileContent[esi]==CR
                                                .if esi==edi ;最后一个字节,不知道后续有没有LF
                                                ; 回退一个字节
                                                        mov     @szFileContent[esi], 0 ;
                                                        invoke  SetFilePointer, @hFile, \
                                                                        -1, NULL, FILE_CURRENT  
                                                        invoke  SendDlgItemMessage, hDlg, idEdit, EM_SETSEL,\
                                                                        -1, -1
                                                        invoke  SendDlgItemMessage, hDlg, idEdit,\
                                                                        EM_REPLACESEL, \
                                                                        0, addr @szFileContent[ebx]
                                                        mov     ebx, esi ;
                                                        inc     ebx ; ebx此时>edi
                                                .else
                                                ; 读下一个字节,看是不是LF
                                                        inc     esi
                                                        .if @szFileContent[esi]==LF
                                                        ; CR, LF
                                                               mov     @szFileContent[esi-1], 0
                                                               invoke  SendDlgItemMessage, hDlg, idEdit, EM_SETSEL,\
                                                                        -1, -1
                                                               invoke  SendDlgItemMessage, hDlg, idEdit,\
                                                                        EM_REPLACESEL, 0, addr @szFileContent[ebx]  
                                                               mov      ebx, esi ;
                                                               inc      ebx
                                                               invoke  SendDlgItemMessage, hDlg, idEdit, EM_SETSEL,\
                                                                        -1, -1
                                                               invoke  SendDlgItemMessage, hDlg, idEdit,\
                                                                        EM_REPLACESEL, 0, CTXT(CR, LF)    
                                                               ; 过滤掉这个LF     
                                                        .else
                                                        ; 单独的CR
                                                               mov     @szFileContent[esi-1], 0
                                                               invoke  SendDlgItemMessage, hDlg, idEdit, EM_SETSEL,\
                                                                        -1, -1
                                                               invoke  SendDlgItemMessage, hDlg, idEdit,\
                                                                        EM_REPLACESEL, 0, addr @szFileContent[ebx]
                                                               mov      ebx, esi ;
                                                               invoke  SendDlgItemMessage, hDlg, idEdit, EM_SETSEL,\
                                                                        -1, -1
                                                               invoke  SendDlgItemMessage, hDlg, idEdit,\
                                                                        EM_REPLACESEL, 0, CTXT(CR, LF)
                                                                        
                                                               .continue ;
                                                        .endif
                                                .endif
                                        .elseif @szFileContent[esi]==LF
                                        ; 单独的LF(若与CR成对,则早已被过滤)
                                                mov     @szFileContent[esi], 0
                                                invoke  SendDlgItemMessage, hDlg, idEdit, EM_SETSEL,\
                                                                        -1, -1
                                                invoke  SendDlgItemMessage, hDlg, idEdit,\
                                                                        EM_REPLACESEL, \
                                                                        0, addr @szFileContent[ebx]
                                                mov     ebx, esi ;
                                                inc     ebx
                                                invoke  SendDlgItemMessage, hDlg, idEdit, EM_SETSEL,\
                                                                        -1, -1
                                                invoke  SendDlgItemMessage, hDlg, idEdit,\
                                                                        EM_REPLACESEL, 0, CTXT(CR, LF)
                                        .endif
                                        
                                        inc     esi
                                .endw
                                ; 上面的这个循环的代码在遇到换行符的时候反缓冲区中的字符串追加到edit控件中
                                
                                ; 存在这样一个问题:
                                ; 缓冲区会把1个汉字编码的2字节分割开,显示会出现乱码
                                ; 所以要保证汉字在缓冲区内对齐
                                
                                .if ebx<=edi ;表明缓冲区中还有字符串未输出
                                ; 若ebx>edi, 则表明上面的那个循环已把缓冲区中的所有字符串输出,也即缓冲区末尾有换行符
                                ; 汉字编码不会被换行符分割开
                                
                                        .if @szFileContent[edi]>=0a1h && \
                                               @cbReadWritten == sizeof @szFileContent-1
                                        ;最后一个字符是汉字(反正不是英文) 而且 未到文件末尾
                                                mov     ecx, 1
                                                dec     edi
                                                .while edi>=ebx
                                                       .if @szFileContent[edi]>=0a1h
                                                                inc     ecx
                                                       .else ;遇到英文
                                                                .break
                                                       .endif
                                                       dec      edi
                                                .endw      
                                                .if ecx & 1 ;奇数?汉字在缓冲区中对齐没?
                                                ; 若没有对齐,回退一个字节使对齐
                                                        mov     eax, @cbReadWritten
                                                        mov     @szFileContent[eax-1], 0
                                                        invoke  SetFilePointer, @hFile, \
                                                                        -1, NULL, FILE_CURRENT
                                                .else
                                                ; 汉字在缓冲区末尾是对齐的
                                                        mov     eax, @cbReadWritten
                                                        mov     @szFileContent[eax], 0  ;这里勿忘
                                                .endif
                                        .else
                                        ; 最后一个字符不是汉字 或者 是到了文件末尾
                                                mov     eax, @cbReadWritten
                                                mov     @szFileContent[eax], 0  ;这里勿忘
                                        .endif
                                        
                                        invoke  SendDlgItemMessage, hDlg, idEdit, EM_SETSEL,\
                                                                        -1, -1
                                        invoke  SendDlgItemMessage, hDlg, idEdit,\
                                                        EM_REPLACESEL, 0, addr @szFileContent[ebx]                 
                                 .endif
                                
                                .break .if @cbReadWritten < sizeof @szFileContent-1
                                ; 文件已读完
                         .else
                                .break
                        .endif    
                .endw            
                ; 回卷到文件开头
                invoke  SendDlgItemMessage, hDlg, idEdit, EM_SETSEL, 0, 0
                invoke  SendDlgItemMessage, hDlg, idEdit, EM_SCROLLCARET, 0, 0
                 
                invoke  CloseHandle, @hFile
        .endif
        ret
_EditShowTextFile endp

; 取得文件的大小,返回值在edx:eax对中
_GetFileSize proc hFile
        push    eax
        invoke  GetFileSize, hFile, esp
        pop     edx
        ret
_GetFileSize endp

; 取得指定名字的文件的大小,返回值在edx:eax对中,若返回edx:eax==-1,表示该文件不存在
_GetFileSizeByName proc pszFileName
        local   @wfd:WIN32_FIND_DATA

        invoke  FindFirstFile, pszFileName, addr @wfd ;用来查找指定名字的文件或目录
        .if eax==INVALID_HANDLE_VALUE
                mov     eax, -1
                mov     edx, -1
        .else
                invoke  FindClose, eax
                mov     eax, @wfd.nFileSizeLow
                mov     edx, @wfd.nFileSizeHigh                
        .endif
        ret
_GetFileSizeByName endp

; 可使用通配符
_IsFileExist proc pszFileName
        local   @wfd:WIN32_FIND_DATA

        invoke  FindFirstFile, pszFileName, addr @wfd ;用来查找指定名字的文件或目录
        .if eax==INVALID_HANDLE_VALUE
                return   FALSE
        .else
                invoke  FindClose, eax
                return  TRUE
        .endif
_IsFileExist endp

; 指定的文件名对应的是不是目录
_IsDirectory proc pszFileName
        invoke  GetFileAttributes, pszFileName
        .if eax & FILE_ATTRIBUTE_DIRECTORY
                return TRUE
        .else
                return FALSE
        .endif   
_IsDirectory endp

; 从全路径文件名中得到文件名的地址       
_GetFileName proc pszPathName
        mov     eax, pszPathName
        mov     edx, eax
        .while byte ptr [eax] ; 最后一个\后面或是如"j:123.txt"的:后面
                .if byte ptr [eax] == ':' || byte ptr [eax] == '\'
                        mov     edx, eax
                .endif
                inc     eax
        .endw
        
        inc     edx
        mov     eax, edx
        ret
_GetFileName endp
       
; 把一个目录及其其下的子目录加到树型视图控件hItem指定的条目下
_AddDirToTreeView proc uses ebx esi hDlg, idTreeView, hItem, pszPathName
        local   @szFileName[MAX_PATH*8]:byte ;有溢出的风险
        local   @tvinsert:TV_INSERTSTRUCT
        local   @wfd:WIN32_FIND_DATA
        
        m2m     @tvinsert.hParent, hItem
        mov     @tvinsert.hInsertAfter, TVI_SORT ;按字母序排列
        mov     @tvinsert.item.imask,TVIF_TEXT or TVIF_IMAGE or TVIF_SELECTEDIMAGE

        invoke  _GetFileName, pszPathName
        mov     @tvinsert.item.pszText, eax
        mov     @tvinsert.item.iImage, 0
        mov     @tvinsert.item.iSelectedImage, 1
        invoke  SendDlgItemMessage, hDlg, idTreeView, TVM_INSERTITEM,0,addr @tvinsert
        mov     ebx, eax

        invoke  lstrcpy, addr @szFileName, pszPathName
        invoke  lstrcat, addr @szFileName, CTXT("\*")
        invoke  FindFirstFile, addr @szFileName, addr @wfd ;用来查找指定名字的文件或目录
        mov     esi, eax

        .while 1
                .if @wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
                        invoke  lstrcmp, addr @wfd.cFileName, CTXT(".") ; 表示本目录的条目
                        .if !eax
                                jmp     @next
                        .endif
                        
                        invoke  lstrcmp, addr @wfd.cFileName, CTXT("..") ; 表示父目录的条目
                        .if !eax
                                jmp     @next
                        .endif
                        
                        invoke  lstrcpy, addr @szFileName, pszPathName
                        invoke  lstrcat, addr @szFileName, CTXT("\")
                        invoke  lstrcat, addr @szFileName, addr @wfd.cFileName
                        invoke  _AddDirToTreeView, hDlg, idTreeView, ebx, addr @szFileName
                .endif
        @next:
                invoke  FindNextFile, esi, addr @wfd
                .if !eax
                        ;invoke   GetLastError
                        ;.if eax==ERROR_NO_MORE_FILES
                        
                        ;.endif
                        .break
                .endif
        .endw

        invoke  FindClose, esi
        ret
_AddDirToTreeView endp

       
    end
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值