FASM---Win32汇编学习14

本文详细介绍了Windows API中的内存管理,包括GlobalAlloc、GlobalLock等函数的使用,以及文件输入/输出操作,如CreateFile、ReadFile、WriteFile等。通过示例代码展示了如何打开、读取、编辑和保存文本文件内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     FASM---Win32汇编学习14
                               
   

       本课中我们来学习基本的内存管理和文件输入/输出操作方面的知识。另外我们需要用到我们上节课学到的通用对话框来作为显示设备。

理论:

     从用户的角度来说:win32内存是非常简单和明了的。每一个用户进程都有独立的4GB地址空间,这种内存模式叫做"平坦"型地址模式。所有的段寄存器或描述符都指向同样的起始地址,所有的偏移都是32位长。这样一个应用程序无需变换选择符就可以存取自己多大4GB的地址空间。这种内存管理是非常简洁和便于管理的。
而且我们再也不用和那些令人讨论的“near”和:“far”指针打交道了。

    在win16下有两种类型的api:全局和局部。“全局”的api分配在其他的段中,这样从内存角度看他们是一些“far(远)”函数或者交远过程调用,“局部”api只要和进程的堆打交道,所以把他们叫做“near(近)”函数或者是近过程调用。而在win32中,这两种模式是相同的。不论你调用GlobalAlloc还是LocalAlloc,结果都是一样。至于分配和使用的内存的过程都是一样的:

 

    1.调用GlobalAlloc函数分配一块内存,该函数返回分配的内存句柄。

    2.调用GlobalLock函数锁定内存块,该函数接受一个内存句柄作为参数,函数返回一个指向锁定内存块的指针。

   3.您可以用该指针来读写内存。

    4.调用GlobalUnLock函数来解锁之前锁定的内存,该函数使得指向内存块的指针无效。

    5.调用GlobalFree函数来释放内存块,您必须传给该函数一个内存句柄。

 

   在win32中您可以使用“Local”来替代内存api函数带有“Global”字样函数中的“Global”,也即用LocalAlloc,LocalLock等。在调用函数GlobalAlloc时用GMEM_FIXED标志位可以进一部简化操作,使用该标志后,Global/LocalAlloc返回的是已分配内存的指针而不是句柄。这样也就不用调用Global/LocalLock来锁定内存了,释放时只要调用Global/LockFree就可以了。不过本节课程我们只使用传统的方法,因为其他地方很多都是用这种方法写的。

 

   WIN32中的输入输出和DOS下的从外面上看几乎一样。(译者著:也许不管内部实现多么不同,可以想象所有的文件系统暴露给应用程序编写者的接口基本相同,不同的只是把dos下的中断方式处理文件输入/输出变成了对api函数的调用。以下是基本步骤。

 

     1.调用CreateFile函数来生成一个文件,该函数可以应用在很多方面,除了磁盘文件外,我们还可以用来打开通讯,管道,驱动程序或控制台,会返回指向文件或者设备的句柄,我们只有使用句柄才有权反问这些设备以及文件(译者注:我们在windows下编程,就要遵循相应的规则)。

     调用SetFilePointer来把文件指针移到想读写的地方。

    2.然后调用ReadFile或WriteFile来完成实际的读写。这些函数会自己处理文件和内存之间的数据传送,这样免的你去做分配内存等繁琐的事情。

    3.调用CloseHandle来关闭文件,该函数接受一个先前打开的句柄。

   

内容:

    下面的代码段演示了:打开一个文件对话框,用户可以选择打开一个文件,然后在编辑控件中打开该文本文件的内容,另外用户还可以编辑该文本文件的内容并选择保存。

   

format PE GUI 4.0
include 'win32ax.inc'

macro memmov [dst, src]
{
    common
    push [src]
    pop [dst]
}

IDD_OPEN equ 1002
IDD_SAVE equ 1003
IDD_EXIT equ 1004
MEMSIZE equ 65536
EDITID equ 1

.data
    
    hInstance  rd 1
    hEdit      rd 1
    hFile      rd 1
    hMemory    rd 1
    lpMemory   rd 1
SizeFileWrite  rd 1
    lpofn OPENFILENAME <>
    szBuffer   db 100 dup (?)
szFilterName   db 'all file (*.*)', 0, '*.*',0,0
    szClassName db 'xfish', 0
    szEditName  db 'edit', 0
    szWndName   db '我的程序', 0

.text
   
    entry $
                    xor edi, edi
            invoke GetModuleHandle, edi
                    mov [hInstance], eax
            stdcall _WinMain, [hInstance], edi, edi, edi
            invoke ExitProcess, edi
           
    proc _WinMain hInstance:DWORD, hPrevInstance:DWORD, lpCmdLine:DWORD, nCmdShow:DWORD
            local @wc:WNDCLASS
            local @msg:MSG
            local @hWin:DWORD
            ; +-------------------------------------------+
            ; | Register Class |
            ; +-------------------------------------------+
            invoke RtlZeroMemory, addr @wc, sizeof.WNDCLASS
                    mov [@wc.style], CS_VREDRAW    or CS_HREDRAW
                    mov [@wc.lpfnWndProc], _WinProc
                    memmov @wc.hInstance, hInstance
                    mov [@wc.hbrBackground], COLOR_WINDOW + 1
                    mov [@wc.lpszMenuName], 1000
                    mov [@wc.lpszClassName], szClassName
            invoke LoadIcon, NULL, IDI_ASTERISK
                    mov [@wc.hIcon], eax
            invoke LoadCursor, NULL, IDC_ARROW   
                    mov [@wc.hCursor], eax
        invoke RegisterClass, addr @wc
            ; +------------------------------------------+
            ; | Create Window                             |
            ; +------------------------------------------+
            invoke CreateWindowEx,/
                        NULL,/
                    szClassName,/
                        szWndName,/
            WS_OVERLAPPEDWINDOW,/
                    CW_USEDEFAULT,/
                    CW_USEDEFAULT,/
                        300,/
                                200,/
                            NULL,/
                            NULL,/
                        [hInstance],/
                            NULL
                    mov [@hWin], eax
                   
            invoke ShowWindow, [@hWin], SW_SHOWNORMAL
            invoke UpdateWindow, [@hWin]
            ; +-----------------------------------------+
            ; | Msg Loop                                 |
            ; +-----------------------------------------+
        msgloop:
            invoke GetMessage, addr @msg, NULL, NULL, NULL
                    or eax, eax
                    je msgend
                   
            invoke TranslateMessage, addr @msg
            invoke DispatchMessage, addr @msg
                    jmp msgloop
        msgend:        
                    mov eax, [@msg.wParam]
                    ret
           
                   
    endp



    proc _WinProc uses ebx esi edi, hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
           
                    cmp [uMsg], WM_DESTROY
                    je     quit
                    cmp [uMsg], WM_CREATE
                    je     wndcreate
                    cmp [uMsg], WM_SIZE
                    je     wndsize
                    cmp [uMsg], WM_COMMAND
                    je menucommand
            invoke DefWindowProc, [hWnd], [uMsg], [wParam], [lParam]
                    ret
        wndcreate:
            ; +--------------------------------------------------+
            ; - Create Edit -
            ; +--------------------------------------------------+
            invoke CreateWindowEx,/
                            NULL,/
                    szEditName,/
                            NULL,/
                    WS_CHILD or WS_TABSTOP or ES_MULTILINE or /
                    WS_VISIBLE or ES_LEFT or WS_HSCROLL or ES_AUTOHSCROLL,/
            0, 0, 0, 0,/
                    [hWnd],/
                        EDITID,/
                    [hInstance],/
                        NULL
                           
                    mov [hEdit], eax
            invoke SetFocus, eax
            ; +----------------------------------------------+
            ; - Initialize OpenFileName -
            ; +----------------------------------------------+
                    mov [lpofn.lStructSize], sizeof.OPENFILENAME
                    memmov lpofn.hwndOwner, hWnd
                    memmov lpofn.hInstance, hInstance
                    mov [lpofn.lpstrFilter], szFilterName
                    mov [lpofn.lpstrFile], szBuffer
                    mov [lpofn.nMaxFile], 100
                    jmp wndend
        wndsize:
                    push edx
                    mov eax, [lParam]
                    mov edx, eax
                    shr edx, 16
                    and eax, 0FFFFh
            invoke MoveWindow, [hEdit], 0, 0, eax, edx, TRUE
                    pop edx
                    jmp wndend
    menucommand:
                    mov eax, [wParam]
                    cmp ax, IDD_SAVE
                    je menusave
                    cmp ax, IDD_OPEN
                    je     menuopen
                    cmp ax, IDD_EXIT
                    je     menuexit
                    jmp wndend
        menusave:
                    mov [lpofn.Flags], OFN_PATHMUSTEXIST or/
                                OFN_EXPLORER or OFN_LONGNAMES
            invoke GetSaveFileName, lpofn
                    or eax, eax
                    je wndend
            invoke CreateFile,/
                        szBuffer,/
                        GENERIC_READ or GENERIC_WRITE,/
                FILE_SHARE_READ,/
                            NULL,/
                        CREATE_NEW,/
                        FILE_ATTRIBUTE_ARCHIVE,/
                    NULL
                    mov [hFile], eax
            invoke GlobalAlloc,/
                    GMEM_MOVEABLE or GMEM_ZEROINIT,/
                        MEMSIZE
                    mov [hMemory], eax
            invoke GlobalLock, [hMemory]
                    mov [lpMemory], eax
            invoke SendMessage, [hEdit], WM_GETTEXT, MEMSIZE-1, [lpMemory]
            invoke WriteFile,/
                    [hFile],/
                    [lpMemory],/
                    eax,/
                    SizeFileWrite,/
                    NULL
            invoke CloseHandle, [hFile]
            invoke GlobalUnlock, [lpMemory]
            invoke GlobalFree, [hMemory]
                jmp wndend
        menuopen:
                    mov [lpofn.Flags], OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or/
                                OFN_EXPLORER or OFN_LONGNAMES
            invoke GetOpenFileName, lpofn
                    or eax, eax
                    je wndend
            invoke CreateFile,/
                        szBuffer,/
                        GENERIC_READ or GENERIC_WRITE,/
                        FILE_SHARE_READ or FILE_SHARE_WRITE,/
                        NULL,/
                        OPEN_EXISTING,/
                        FILE_ATTRIBUTE_ARCHIVE,/
                        NULL
                    mov [hFile], eax
            invoke GlobalAlloc,/
                    GMEM_FIXED or GMEM_MOVEABLE or GMEM_ZEROINIT,/
                    MEMSIZE
                    mov [hMemory], eax
            invoke GlobalLock, [hMemory]
                    mov [lpMemory], eax
            invoke ReadFile,/
                    [hFile],/
                [lpMemory],/
                MEMSIZE-1,/
                SizeFileWrite,/
                        NULL
            invoke SendMessage, [hEdit], WM_SETTEXT, 0, [lpMemory]
            invoke CloseHandle, [hFile]
            invoke GlobalUnlock, [lpMemory]
            invoke GlobalFree, [hMemory]

    invoke SetFocus, [hEdit]
                    jmp wndend
        menuexit:
            invoke SendMessage, [hWnd], WM_DESTROY, NULL, NULL
                    jmp wndend
        quit:
            invoke PostQuitMessage, NULL
        wndend:
                    xor eax, eax
                    ret
    endp







.import
            library kernel32, 'kernel32.dll',/
                    user32, 'user32.dll',/
                    comdlg32, 'comdlg32.dll'
            include 'api/comdlg32.inc'
            include 'api/kernel32.inc'
            include 'api/user32.inc'
           
section '.rsrc' data readable resource
        include 'string.fnt'
        directory RT_MENU, Menu
       
        resource Menu, /
                1000, LANG_NEUTRAL, MenuMain
        menu MenuMain
            menuitem st_file_chs, 1001, MFR_POPUP + MFR_END
            menuitem st_open_chs, 1002, 0
            menuitem st_save_chs, 1003, 0
                    menuseparator
            menuitem st_exit_chs, 1004, MFR_END

分析:

wndcreate:
            ; +--------------------------------------------------+
            ; - Create Edit -
            ; +--------------------------------------------------+
            invoke CreateWindowEx,/
                            NULL,/
                    szEditName,/
                            NULL,/
                    WS_CHILD or WS_TABSTOP or ES_MULTILINE or /
                    WS_VISIBLE or ES_LEFT or WS_HSCROLL or ES_AUTOHSCROLL,/
            0, 0, 0, 0,/
                    [hWnd],/
                        EDITID,/
                    [hInstance],/
                        NULL
                           
                    mov [hEdit], eax
            invoke SetFocus, eax

    处理WM_CREATE消息时,我们创建一个编辑控件。请注意我们把这里的坐标以及宽度和高度全部设置为0,因为稍后我们将重新设置该编辑框的大小,使得其覆盖父窗口整个客户区。

   注意:本例我们必要去调用ShowWindow来显示编辑框,因为在创建时我们对其风格设置了WS_VISIBLE标志,在创建父窗口的时候也可以使用这个小技巧。

   

            ; +----------------------------------------------+
            ; - Initialize OpenFileName -
            ; +----------------------------------------------+
                    mov [lpofn.lStructSize], sizeof.OPENFILENAME
                    memmov lpofn.hwndOwner, hWnd
                    memmov lpofn.hInstance, hInstance
                    mov [lpofn.lpstrFilter], szFilterName
                    mov [lpofn.lpstrFile], szBuffer
                    mov [lpofn.nMaxFile], 100
                    jmp wndend

       创建编辑框后,我们初始化相关lpofn的成员(这个是我们的通用对话框的相关结构)。因为等下在保存文件以及打开文件时候我们需要用到此结构。所以只初始化公用的部分。WM_CREATE消息的处理部分是进行这种初始化的绝佳之处。

 

      wndsize:
                    push edx
                    mov eax, [lParam]
                    mov edx, eax
                    shr edx, 16
                    and eax, 0FFFFh
            invoke MoveWindow, [hEdit], 0, 0, eax, edx, TRUE
                    pop edx
                    jmp wndend

    当窗口客户区发生改变时我们将接受到WM_SIZE消息。当然当窗口第一次显示时我们也接受到WM_SIZE消息。要接受到此消息,主窗口必须有CS_VREDRAW 和CS_HREDRAW风格。我们应该把缩放编辑框的动作放到此处。我们要把编辑框变成和我们客户区一样的大,所以要首先得到父窗口客户区的大小。这些值在WM_SIZE消息中的lParam参数中。lParam的高字部分是客户区的高,低字部分是客户区的宽,然后我们调用MOVEWINDOW函数来重新调整空间的大小,该函数不仅可以移动窗口的位置,而且可以改变窗口的大小。

           menuopen:
                    mov [lpofn.Flags], OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or/
                                OFN_EXPLORER or OFN_LONGNAMES
            invoke GetOpenFileName, lpofn
                    or eax, eax
                    je wndend

   当用户选择了File/Open菜单项时,我们填充lpofn其他的成员,然后调用GetOpenFileName函数显示一个打开文件的对话框。

                    or eax, eax
                    je wndend
            invoke CreateFile,/
                        szBuffer,/
                        GENERIC_READ or GENERIC_WRITE,/
                        FILE_SHARE_READ or FILE_SHARE_WRITE,/
                        NULL,/
                        OPEN_EXISTING,/
                        FILE_ATTRIBUTE_ARCHIVE,/
                        NULL
                    mov [hFile], eax
            invoke GlobalAlloc,/
                    GMEM_FIXED or GMEM_MOVEABLE or GMEM_ZEROINIT,/
                    MEMSIZE
                    mov [hMemory], eax
            invoke GlobalLock, [hMemory]
                    mov [lpMemory], eax
            invoke ReadFile,/
                    [hFile],/
                [lpMemory],/
                MEMSIZE-1,/
                SizeFileWrite,/
                        NULL
            invoke SendMessage, [hEdit], WM_SETTEXT, 0, [lpMemory]
            invoke CloseHandle, [hFile]
            invoke GlobalUnlock, [lpMemory]
            invoke GlobalFree, [hMemory]

   然后我们判断eax寄存器是否为0,如果为0,我们则结束。然后当用户选择一个文件的时候我们调用CreateFile函数来打开一个文件,然后设置标志位让该函数能够读写,文件打开后我们把文件句柄保存在一个全局变量中以便以后使用。CreateFile函数使用非常广泛,它的定义如下:

proc CreateFile lpFileName:DWORD,/
                dwDesiredAccess:DWORD,/
                dwShareMode:DWORD,/
                lpSecurityAttributes:DWORD,/
                dwCreationDistribution:DWORD/,
                dwFlagsAndAttributes:DWORD/,
                hTemplateFile:DWORD

dwDesiredAccess 指定想要进行的操作。

0 打开文件查询它的属性。
GENERIC_READ 打开文件读
GENERIC_WRITE 打开文件写.
dwShareMode 指定文件的共享模式。
0 不让其他进程共享,即当您打开该文件后,其他进程欲打开该文件时将失败。
FILE_SHARE_READ 允许其他进程读。
FILE_SHARE_WRITE 允许其他进程写。
lpSecurityAttributes 该属性在WIN95下无效。
dwCreationDistribution 指定欲生成的文件在其已存在和未存在时应做的动作。

CREATE_NEW 生成一个新文件。如果文件已存在则失败。
CREATE_ALWAYS 无论文件是否存在都生成一个新文件。
OPEN_EXISTING 打开存在的文件。如果文件不存在则失败。
OPEN_ALWAYS 打开文件,如果该文件不存在则生成,这和在dwCreationDistribution 中设置 CREATE_NEW标志位一样。
TRUNCATE_EXISTING打开文件。打开时该文件的长度裁减到零(也即完全不要原来的文件了)。这要求调用进程必须有GENERIC_WRITE的权利,如果指定的文件不存在,该函数返回失败。
dwFlagsAndAttributes 指定文件的属性。

FILE_ATTRIBUTE_ARCHIVE 该文件具有一般的归档文件的属性。用户可以用该标志位来标记文件的删除和备份。
FILE_ATTRIBUTE_COMPRESSED 文件或目录是压缩的。对于文件来说是压缩其中的所有数据,而对于目录来说新生成的子目录和文件都要压缩。
FILE_ATTRIBUTE_NORMAL 该文件没有一般的属性集。该标志位只能单独使用。
FILE_ATTRIBUTE_HIDDEN 该文件是隐藏文件,当浏览一般的文件目录时将不显示它。
FILE_ATTRIBUTE_READONLY 该文件是只读文件。应用程序可以读其中的内容,但不可以写。
FILE_ATTRIBUTE_SYSTEM 该文件是系统文件。

 


invoke GlobalAlloc,/
           GMEM_FIXED or GMEM_MOVEABLE or GMEM_ZEROINIT,/
           MEMSIZE
        mov [hMemory], eax
invoke GlobalLock, [hMemory]
        mov [lpMemory], eax

然后我们调用GlobalAlloc函数类分配一块内存,我们使用GMEM_MOVEABLE来使得windows总是把内存块移动到可靠的内存中。GMEM_ZEROINIT标志是告诉windows把刚刚分配的内存填充0。如果GlobalAlloc函数调用成功的话,会在eax寄存器中返回内存块的句柄,我们把该句柄传递给GlobalLock函数以得到指向内存块的指针。

            invoke ReadFile,/
                    [hFile],/
                [lpMemory],/
                MEMSIZE-1,/
                SizeFileWrite,/
                        NULL
            invoke SendMessage, [hEdit], WM_SETTEXT, 0, [lpMemory]

    然后我们调用ReadFile读取文件中的数据,对于第一次打开的文件来说,文件指针放在偏移0处。像本例中,我们从偏移0处往前读。ReadFile第一个参数是文件的句柄,第二个参数是指向内存块的指针,第三个参数是要读取的数据的长度,第四个参数是一个指向DWORD类型的指针,它用来存放实际读写的数据的长度。读完了后我们将这些内容显示到编辑框中,我们通过消息来实现。我们通过发送WM_SETTEXT消息给应用编辑框,杂windows会处理将我们此块内存区域的内容显示到编辑框中。

 

            invoke CloseHandle, [hFile]
            invoke GlobalUnlock, [lpMemory]
            invoke GlobalFree, [hMemory]

  此刻我们我们不需要让文件打开了,因为我们的目的是要将修改后的数据保存到另一个文件中,所以此时我们可以调用CloseHandle来关闭文件句柄。接下来解锁,释放内存。而在以后的操作中重新利用。

  mov [lpofn.Flags], OFN_PATHMUSTEXIST or/
                                OFN_EXPLORER or OFN_LONGNAMES
            invoke GetSaveFileName, lpofn

调用GetSaveFileName产生保存文件对话框,此时会将将路径保存当szBuffer。

然后我们调用

invoke SendMessage, [hEdit], WM_GETTEXT, MEMSIZE-1, [lpMemory]
            invoke WriteFile,/
                    [hFile],/
                    [lpMemory],/
                    eax,/
                    SizeFileWrite,/
                    NULL

我们调用SendMesage发送WM_GETTEXT消息将编辑框的内容保存到开辟的内存块中。然后通过WriteFile函数将内存块的内容写入到文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值