; 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
.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