按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
CONTROL 〃〃;…1;〃HexEdit〃;ES_LEFT | WS_BORDER | WS_TABSTOP;5;35;115;12
CONTROL 〃〃;…1;〃HexEdit〃;ES_LEFT | WS_BORDER | WS_TABSTOP;5;50;115;12
CONTROL 〃〃;…1;〃HexEdit〃;ES_LEFT | WS_BORDER | WS_TABSTOP;5;65;115;12
}
//》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
读者可以看到,对话框中定义了多个HexEdit类,但是系统中并没有预定义这种名称的类,这就是将要从Edit类中派生的类。SuperClass。asm文件的内容如下:
。386
。model flat; stdcall
option casemap :none
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; Include 文件定义
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
include windows。inc
include user32。inc
includelib user32。lib
include kernel32。inc
includelib kernel32。lib
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; Equ 等值定义
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
ICO_MAIN equ 1000
DLG_MAIN equ 1000
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 数据段
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
。data?
hInstance dd ?
hWinMain dd ?
lpOldProcEdit dd ?
nst
szAllowedChar db '0123456789ABCDEFabcdef';08h
szEditClass db 'Edit';0
szClass db 'HexEdit';0
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 代码段
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
de
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; HexEdit控件的新窗口过程
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
_ProcEdit proc uses ebx edi esi hWnd;uMsg;wParam;lParam
mov eax;uMsg
。if uMsg WM_CHAR
mov eax;wParam
mov edi;offset szAllowedChar
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第9章 通用控件
9。6 控件的超类化(2)
mov ecx;sizeof szAllowedChar
repnz scasb
。if ZERO?
。if al 》 '9'
and al;not 20h
。endif
invoke CallWindowProc;lpOldProcEdit;
hWnd;uMsg;eax;lParam
ret
。endif
。else
invoke CallWindowProc;lpOldProcEdit;
hWnd;uMsg;wParam;lParam
ret
。endif
xor eax;eax
ret
_ProcEdit endp
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 基于Edit类建立一个新的类:HexEdit
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
_SuperClass proc
local @stWC:WNDCLASSEX
mov @stWC。cbSize;sizeof @stWC
invoke GetClassInfoEx;NULL;addr szEditClass;addr @stWC
push @stWC。lpfnWndProc
pop lpOldProcEdit
mov @stWC。lpfnWndProc;offset _ProcEdit
push hInstance
pop @stWC。hInstance
mov @stWC。lpszClassName;offset szClass
invoke RegisterClassEx;addr @stWC
ret
_SuperClass endp
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
_ProcDlgMain proc uses ebx edi esi hWnd;wMsg;wParam;lParam
mov eax;wMsg
;********************************************************************
。if eax WM_CLOSE
invoke EndDialog;hWnd;NULL
;********************************************************************
。else
mov eax;FALSE
ret
。endif
mov eax;TRUE
ret
_ProcDlgMain endp
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
start:
invoke GetModuleHandle;NULL
mov hInstance;eax
invoke _SuperClass
invoke DialogBoxParam;hInstance;DLG_MAIN;
NULL;offset _ProcDlgMain;NULL
invoke ExitProcess;NULL
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
end start
由于在对话框初始化的时候,对话框管理器就要根据对话框资源的内容创建每个子窗口控件,所以在调用DialogBoxParam函数显示对话框之前,“HexEdit”类就必须存在,否则初始化工作会失败。因此,程序在DialogBoxParam函数之前调用_SuperClass子程序进行超类化的工作。
在_SuperClass子程序中,程序通过GetClassInfoEx函数获取Edit控件的类结构,然后将结构中的窗口过程指到自己的_ProcEdit子程序中,接下来将hInstance字段设置为自己的实例句柄,并将类的名称改为“HexEdit”,最后用RegisterClassEx函数注册一个新的“HexEdit”类:
nst
szEditClass db 'Edit';0
szClass db 'HexEdit';0
de
。。。
mov @stWC。cbSize;sizeof @stWC ;@stWC是一个WNDCLASSEX结构
invoke GetClassInfoEx;NULL;addr szEditClass;addr @stWC
push @stWC。lpfnWndProc
pop lpOldProcEdit
mov @stWC。lpfnWndProc;offset _ProcEdit
push hInstance
pop @stWC。hInstance
mov @stWC。lpszClassName;offset szClass
invoke RegisterClassEx;addr @stWC
新的窗口过程和子类化窗口中的例子是一样的,在这里就不进行分析了,程序的结果就是:用HexEdit类建立的所有窗口的功能和子类化窗口例子中IDC_HEX编辑框的功能是一样的。
本程序演示的是派生类在对话框中的使用情况,在这里基于派生类创建的窗口是由对话框管理器自动调用CreateWindowEx函数创建的,如果将派生类使用在普通窗口中的话,可以通过指定派生类的名称,自己使用CreateWindowEx函数来创建。
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第10章 内存管理和文件操作
10。1 内 存 管 理(1)
10。1。1 内存管理基础
Win32中的内存管理是分层次的,系统提供了几组层次不同的函数来管理内存,它们是标准内存管理函数、堆管理函数、虚拟内存管理函数和内存映射文件函数。所有的这些函数都是为了让用户能在比较高的层次上方便地管理内存,以便将程序和底层的内存分页机制隔离开来。如图10。1所示,这几组函数的层次是各不相同的。
图10。1 Windows的内存分层管理
Windows使用一个以页为基础的虚拟内存系统,与分页有关的概念已经在第1章的1。3。2小节中有所介绍。Windows充分利用了80x86处理器保护模式下的线性寻址机制和分页机制,这些机制是Win32内存管理的基础,Win32提供了一组虚拟内存管理函数来管理虚拟内存,主要用于保留/提交/释放虚拟内存,在虚拟内存页上改变保护方式,锁定虚拟内存页以及查询一个进程的虚拟内存等操作,这是一组位于底层的函数。
堆管理函数相对比较高级一点,堆的主要功能就是有效地管理内存和进程的地址空间。DOS操作系统下的C语言中就已经有了“堆”的概念,这时的“堆”是程序初始化时向操作系统申请并预留的大块内存,程序通过C函数在这块空间中申请和释放内存。
在Win32中,进程可以使用的整个地址空间就是一个堆。并且“堆”的概念又被引伸了一步:Win32中分两种堆,一种是进程的“默认堆”,默认堆只有一个,指的就是可以使用的整个地址空间;另一种是“动态堆”,也称为“私有堆”,私有堆类似于DOS下C语言中使用的那种堆,一个进程可以随意建立多个私有堆,也可以随意将它们释放,私有堆全部位于默认堆中,从概念上看,它和默认堆并没有什么不同,就像一个跨国公司和属下的子公司同样都是按照公司的规程操作一样。使用堆管理函数可以对所有的私有堆和默认堆进行操作。
标准内存管理函数总是在默认堆中分配和释放内存,这组函数就是常规意义上的内存管理函数。
内存映射文件函数相对比较独立,它是为了文件操作的方便性而设立的,当对文件进行操作的时候,一般总是先打开文件,然后申请一块内存用做缓冲区,再将文件数据循环读入并处理,当文件长度大于缓冲区长度的时候需要多次读入,每次读入后处理缓冲区边界位置的数据往往是个麻烦的问题。曾经介绍过Windows可以使用磁盘文件当做虚拟内存(参考图1。5,虚拟内存的实现),内存映射文件函数使用同样的办法将一个文件直接映射到进程的地址空间中,这样可以通过内存指针用读写内存的办法直接存取文件内容。
对比这些函数,可以发现它们涉及的系统资源是各不相同的,如表10。1所示。
表10。1 不同内存管理函数的操作对象
内存管理函数
涉 及 方 面
标准内存管理函数
一个进程的默认堆
堆管理函数
一个进程的虚拟地址空间、系统内存、进程堆资源结构
虚拟内存管理函数
一个进程的虚拟地址空间、系统页文件、系统内存、硬盘空间
内存映射文件函数
一个进程的虚拟地址空间、系统页文件、系统内存、硬盘空间、标准文件I/O
10。1。2 内存的当前状态
在第1章中已经介绍过,一个进程可以寻址的地址空间是4 GB,但用户可以直接管理的地址空间是多大呢?实际上,高端的2 GB是供操作系统内核使用的,其中安排了操作系统的代码和数据(Windows 9x中还包括共享内存映射的地址空间),可供应用程序使用的地址空间是低端的2 GB,这2 GB除去应用程序与用户DLL等的代码和静态数据段以后,余下来的才是内存管理函数可以使用的地址空间,应用程序和用户DLL的大小一般只有几兆字节到上百兆字节,所以可以认为能自由使用的地址空间基本上是2 GB。
既然用户可以使用的地址空间大概为2 GB,读者千万不要认为就可以申请2 GB的内存了,因为这2 GB仅是可以使用的“地址”空间,而不是可以使用的“内存”空间,可分配内存的大小还受制于物理内存和磁盘交换文件的大小。因为物理内存和磁盘交换文件是供整个系统和所有用户程序使用的,所有系统内核、当前执行的所有用户程序的代码、数据以及分配的内存总量并不能超过物理内存和磁盘交换文件的总和。
当设计一个可能需要申请大量内存的程序时,如何预先得知系统的配置情况呢?对此可以使用GlobalMemoryStatus函数:
invoke GlobalMemoryStatus,lpBuffer
lpBuffer指向一个MEMORYSTATUS结构,结构的定义如下:
MEMORYSTATUS STRUCT
dwLength DWORD ? ;本结构的长度
dwMemoryLoad DWORD ? ;已用内存的百分比
dwTotalPhys DWORD ? ;物理内存总量
dwAvailPhys DWORD ? ;可用物理内存
dwTotalPageFile DWORD ? ;交换文件总的大小
dwAvailPageFile DWORD ? ;交换文件中空闲部分大小
dwTotalVirtual DWORD ? ;用户可用的地址空间
dwAvailVirtual DWORD ? ;当前空闲的地址空间
MEMORYSTATUS ENDS
在调用之前需要首先将dwLength字段设置为MEMORYSTATUS结构的长度,当调用GlobalMemoryStatus函数后,函数会在结构中返回对应的数值。注意:dwTotalPageFile字段返回的是交换文件的最大值,并不是当前实际建立的交换文件的大小,一般当前的交换文件大小会小于这个数值,但这个数值的大小也不是确定的,如果需要的话,系统会增加它的大小直到不再有空余的磁盘空间放置交换文件为止。
在所附光盘的Chapter10MemInfo目录中的MemInfo。asm文件利用这个功能定时获取并显示当前内存的使用信息,源代码如下:
。386
。model flat; stdcall
option casemap :none
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; Include 文件定义
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
include windows。inc
include user32。inc
includelib user32。lib
include kernel32。inc
includelib kernel32。lib
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; Equ 等值定义
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
ICO_MAIN equ 1000
DLG_MAIN equ 100
IDC_INFO equ 101
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
; 数据段
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第10章 内存管理和文件操作