月度归档:2008年10月

其它内存管理函数

1.填充和移动内存

mov esi,offset szSource
mov edi,offset szDest
mov ecx,dwSize
cld
rep movsb

以上代码实现从szSource开始的dwSize大小的内存块移动到szDest处

xor eax,eax
mov edi,offset szDest
mov ecx,dwSize
cld
rep stosb

以上代码实现szDest处开始的dwSize字节填充为0,如果把xor eax,eax换成mov al,xx 那上边的代码将实现将内存块填充为xx

以上功能对应的API如下:

invoke RtlMoveMemory,offset szDest,offset szSource,dwSize ;移动内存
invoke RtlFillMemory,offset szDest,dwSize,dbFill ;以dbFill填充内存块
invoke RtlZeroMemory,offset szDest,dwSize ;以0填充内存块

2.内存状态测试

invoke IsBadCodePtr,lpMemory
invoke IsBadReadPtr,lpMemory,dwSize
invoke IsBadWritePtr,lpMemory,dwSize
invoke IsBadStringPtr,lpMemory,dwSize

IsBadCodePtr:函数测试指针指向的单个字节是否可读,如果可读返回0,否则返回非0值
IsBadReadPtr:测试某段内存是否可读,如果这段内存的所有字节全可读则返回0,否则返回非0值
IsBadWritePtr:测试某段内存是否可写,如果内存段全都可写则返回0,否则返回非0值
IsBadStringPtr:测试一个指向以0结尾的字符串是否可读,dwSize为字符串最大长度,如果字符串包含结尾的0全是可读的,返回0,否则返回非0值,缓冲区中剩余的字节则不予测试

堆管理函数

堆管理函数
1.私有堆的创建和释放
私有堆的创建

invoke HeapCreate,flOptions,dwInitialSize,dwMaximumSize
.if eax && (eax<0c0000000h)
mov hHeap,eax
.endif

flOptions指定堆属性,有两个值
HEAP_NO_SERIALIZE:标志私有堆不进行独占检测
HEAP_GENERATE_EXCEPTIONS:指定函数失败的返回值,不指定失败返回NULL
dwInitialSize指定创建堆时分配的物理内存
dwMaximumSize为堆自动扩展的最大值.为0则没有最大限制,非0时在堆中申请的内存块不能大于7FFF8h(524K)

私有堆的释放

invoke HeapDestroy,hHeap

将释放堆中所有的内存块.成功运行返回TRUE,当进程终止时系统也会自动调用此函数

2.堆中分配和释放内存块
堆中分配内存块

invoke HeapAlloc,hHeap,dwFlags,dwBytes
.if eax && (eax<0c0000000h)
mov lpMemory,eax
.endif

hHeap:是创建堆时的句柄
dwFlags有三个值
HEAP_NO_SERIALIZE:不进行独占检测,如果创建堆时用了,这里就可以省了
HEAP_GENERATE_EXCEPTIONS:失败返回出错原因,而不仅是一个NULL,创建堆时用了,这里也可以省了
HEAP_ZERO_MEMORY:将分配内存用0初始化
dwBytes:是要分配的内存块的字节数
分配成功返回值是指向内存块第一个字节的指针,失败返回错误代码或NULL,要看dwFlags
STATUS_NO_MEMORY:取值为0c0000017h表示内存不够
STATUS_ACCESS_VIOLATION:取值为0c0000005h表示参数不正确或堆被破坏
在堆中分配内存块只能是固定地址的内存块.

堆中释放内存块

invoke HeapFree,hHeap,dwFlags,lpMemory

hHeap:堆句柄
dwFlags:可以使用HEAP_NO_SERIALIZE
lpMemory:是HeapAlloc函数返回的内存块指针
成功返回非0值,失败返回0

堆中调整内存块大小

invoke HeapReAlloc,hHeap,dwFlags,lpMemory,dwBytes
.if eax && (eax<0c0000000h)
mov lpMemory,eax
.endif

hHeap:堆句柄
dwFlags四个值
HEAP_GENERATE_EXCEPTIONS:返回值
HEAP_NO_SERIALIZE:独占检测
HEAP_ZERO_MEMORY:初始化为0
HEAP_REALLOC_IN_PLACE_ONLY:分配内存时不可移动内存块,使用此标志,指针必定和原来相同
lpMemory:为堆中内存块的指针
dwBytes:要改变的内存块的大小的字节数

3.其它堆管理函数
HeapLock,HeapUnlock,GetProcessHeaps,GetProcessHeap,HeapCompact,HeapSize,
HeapValidate,HeapWalk.

invoke GetProcessHeaps,NumberOfHeaps,lpHeaps

NumberOfHeaps:指定了缓冲区可以存放句柄的数量
lpHeaps:是一个指针,指向用来接收堆句柄的缓冲区,缓冲区长度应该等于NumberOfHeaps*4
执行后函数返回进程中所有堆的句柄到缓冲区中,也包括默认堆的句柄

.repeat
invoke HeapWalk,hHeap,lpEntry
push eax
pop eax
.until !eax

hHeap:是堆的句柄
lpEntry:指向一个句含有PROCESS_HEAP_ENTRY结构的缓冲区
每次执行返回一个PROCESS_HEAP_ENTRY的结构块信息,如果还有其他的内存块,函数返回TRUE,程序一直循环调用直到返回FALSE为止,在多线程的程序中使用,必须先使用HeapLock函数,否则会调用失败.

invoke HeapValidate,hHeap,dwFlags,lpMemory

验证堆的完整性或堆中某个内存块的完整性
lpMemory为NULL函数顺序验证堆中所有的内存块,如果lpMemory指定了一个内存块,则只验证这个内存块
dwFlags:可以指定HEAP_NO_SERIALIZE,独占标志
如果所有内存块都完好无损,返回非0值,否则返回0

invoke HeapLock,hHeap
invoke HeapUnlock,hHeap

销定和解销堆,主要用于线程同步,成功返回非0值,否则返回0,在程序中一般用HEAP_NO_SERIALIZE来控制

invoke HeapCompact,hHeap,dwFlags

合并堆中的空闲内存块并释放不在使用中的内存页面

invoke HeapSize,hHeap,dwFlags,lpMemory

返回堆中某个内存块大小lpMemory指定了需要返回大小的内存块,成功返回内存块大小,失败返回-1

虚拟内存管理函数

虚拟内存管理函数
VirtualAlloc,VirtualFree – 地址空间分配和释放
VirtualLock,VirtualUnlock – 对内存页进行销定和解锁
VirtualQuery,VirtualQueryEx – 查询内存页的状态
VirtualProtect,VirtualProtectEx – 改变内存页的保护属性

1.保留和释放地址空间

invoke VirtualAlloc,lpAddress,dwSize,flAllocationType,flProtect

lpAddress:指定要保留或提交的内存地址,为NULL时系统自动分配一个地址
dwSize:表示函数分配的地址范围大小,单位字节
flAlloctiontype可以取的标志有三个
MEM_COMMIT:为指定地址空间提交物理内存
MEM_RESERVE:保留指定地址空间,不分配物理内存
MEM_TOP_DOWN:尽可能使用高端的地址空间
flProtect可以取的标志有六个
PAGE_READONLY:为以提交的物理内存的址空间设定只读属性
PAGE_READWRITE:为以提交的物理内存设定为可读写属性
PAGE_EXECUTE:设定为可执行属性
PAGE_EXECUTE_READ:为物理内存设定可读和可执行属性
PAGE_EXECUTE_READWRITE:为内存设定为可读写和可执行属性
PAGE_NOACCESS:为保留的地址空间设定为不可存取模式
函数执行成功会返回一个指向被保留地址范围开始位置的指针,执行失败返回NULL

invoke VirtualFree,lpAddress,dwSize,dwFreeType

lpAddress与dwSize:为指定地址和空间的大小,与VirtualAlloc相同
dwFreeType可以的标志有两个
MEM_DECOMMIT:为一个以提交的物理内存的地址空间解除提交
MEM_RELEASE:释放保留的址址空间

例:

invoke VirtualAlloc,NULL,10485760,MEM_RESERVE,PAGE_NOACCESS
.if eax
mov lpAddress,eax
.endif

空间的分配方式用MEM_RESERVE保留指定地址空间,不分配物理内存,是无法访问的,所以保护属性必须使用PAGE_NOACCESS,以上代码保留10M大小的空间,保留地址并不保证将来有可用内存来提交给这些地址

invoke VirtualFree,lpAddress,0,MEM_RELEASE

lpAddress是VirtualAlloc返回的指针,释放保留内存时dwSize必须为0,释放一个地址空间中的所有页面必须是同一个状态,否则释放操作会失败.

2.使用保留的地址空间

invoke VirtualAlloc,lpAddress,4096,MEM_COMMIT,PAGE_READWRITE
.if eax
mov lpMemory,eax
.endif

保留地址内存可以按一页的大小被分次提交,也可以一次提交所有的保留地址,当内存被提交时,可以被分配为物理内存页,也有可以被分配在页文件中,在提交时lpAddress不能为NULL,要指定一个特定的地址来准确地指示被保留的哪一页会被提交.属性可以设定成可访问的,成功返回第一页起始线程的地址,失败返回NULL

invoke VirtualAlloc,NULL,dwSize,MEM_RESERVE or MEM_COMMIT,PAGE_READWRITE
.if eax
mov lpMemory,eax
.endif

这种方法与GlobalAlloc函数直接分配一块内存没有多大区别,只是可以指定分配的内存块地址

invoke VirtualFree,lpMemory,dwSize,MEM_DECOMMIT

以上代码为解除提交,让它们从提交状态返回到保留状态,函数的操作对象是整个页面,如果指定的内存范围不是整个页面,函数会自动将整个范围同属一个页面的地址全部解除提交.

3.内存页的保护和锁定

invoke VirtualProtect,lpAddress,dwSize,flNewProtect,lpflOldProtect

flNewProtect:是新的保护方式,取值可以参考VirtualAlloc的flProtect的标志
lpOldProtect:是指向一个双字的指针,函数会在这里返回原来的保护方式,如果不需要可以设置为NULL

invoke VirtualLock,lpAddress,dwSize
invoke VirtualUnlock,lpAddress,dwSize

锁定的意思是将指定内存页保留在物理内存中,不许将它交换到磁盘页文件中,同时锁定的内数不能超过30个

超类化 罗老板的源码

super.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  ?

    .const
szAllowedChar  db  '0123456789ABCDEFabcdef',08h
szEditClass  db  'Edit',0
szClass    db  'HexEdit',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 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
      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
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>&g

t;>>>>>>>>>>>>>>>>>>>
start:
    invoke  GetModuleHandle,NULL
    mov  hInstance,eax
    invoke  _SuperClass
    invoke  DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,NULL
    invoke  ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    end  start

super.rc:

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include    <resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define  ICO_MAIN  1000
#define  DLG_MAIN  1000
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN  ICON    "Main.ico"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DLG_MAIN DIALOG 107, 102, 126, 82
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "SuperClass"
FONT 9, "宋体"
{
CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,5,115,12
CONTROL "",-1,"HexEdit",ES_LEFT | WS_BORDER | WS_TABSTOP,5,20,115,12
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
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

标准内存管理函数

标准内存管理函数
GlobalAlloc,GlobalFree,GlobalReAlloc,GlobalLock,GlobalUnlock,GlobalDiscard,GlobalFlags,GlobalHandle,GlobalSize

1.固定的内存块

invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,dwBytes
.if eax
mov lpMemory,eax
.endif

申请失败eax返回NULL,成功返回指向申请内存起始地址的指针.GPTR

释放固定内存块

invoke GlobalFree,lpMemory

释放成功返回NULL,返否返回输入的lpMemory

改变内存块大小

invoke GlobalReAlloc,lpMemory,dwBytes,uFlags
.if eax
mov lpNewMemory,eax
.endif

lpMemory是先前申请的内存指针,dwBytes是新大小,uFlags可以是空
uFlags来规定是否允许移动内存块,当为GMEM_MOVEABLE选项时,如果需要移动内存块windows会在其它地方新开一个内存块,并把原来的内容自动复制到新内存中,这时函数会返回一个新的指针,原来的指针作废
如果不指定GMEM_MOVEABLE,当后面的空间不足时,函数失败并返回NULL,原来的指针继续有效.
改变内存大小时,建意使用以下代码

invoke GlobalReAlloc,lpMemory,dwBytes,GMEM_ZEROINIT or GMEM_MOVEABLE
.if eax
mov lpMemory,eax
.endif

2.可移动的内存块
申请可移动的内存块

invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,dwBytes
.if eax
mov hMemory,eax
.endif

GMEM_MOVEABLE or GMEM_ZEROINIT = GHND
申请失败eax返回NULL,成功返回一个句柄.可移动内存块不能超过65536个,固定内存块数量无限制

销定可移动内存:

invoke GlobalLock,hMemory
.if eax
mov lpMemory,eax
.endif

销定失败返回NULL,成功返回一个指针
当不使用时要解销

invoke GlobalUnlock,hMemory

解销成功返回非0值

释放可移动内存块

invoke GlobalFree,hMemory

释放成功返回NULL

调整可移动内存块大小

invoke GlobalReAlloc,hMemory,dwBytes,GHND

如果成功返回hMemory,失败返回NULL
注意最好先解销再调整大小

3.可丢弃的内存块
可丢弃的内存块必须是可移动的内存块

invoke GlobalAlloc,GHND or GMEM_DISCARDABLE,dwBytes
.if eax
mov hMemory,eax
.endif

如果GlobalLock内存返回NULL,说明内存以被丢弃了,但句柄还是有效的,如果还要使用这个句柄,可以使用
GlobalReAlloc来重新分配内存,当销定计数为0时,可以使用GlobalDiscard主动将它丢弃.

4.获取内存块的信息
GlobalFlags主要用来取得可移动内存的计数,也可以检测可丢弃内存是否被丢弃.

invoke GlobalFlags,hMemory
and eax,GMEM_LOCKCOUNT
mov dwLockCount,eax

返回值不是GMEM_INVALID_HANDLE说明调用成功,这时返回值低8位是内存块的销定计数
GMEM_DISCARDABLE 表示内存块是可丢弃内存块
GMEM_DISCARDED 表示内存块以被失弃

GlobalHandle可以从GlobalLock得到的lpMemory值获取对应的hMemory
GlobalSize可以获取一个内存块的尺寸

子类化 罗老板的源码

subclass.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
IDC_HEX    equ  1001
IDC_DEC    equ  1002
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .data?
hInstance  dd  ?
hWinMain  dd  ?
dwOption  dd  ?
lpOldProcEdit  dd  ?

    .const
szFmtDecToHex  db  '%08X',0
szFmtHexToDec  db  '%u',0
szAllowedChar  db  '0123456789ABCDEFabcdef',08h
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; IDC_HEX编辑框的新窗口过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcEdit  proc  uses ebx edi esi hWnd,uMsg,wParam,lParam

    mov  eax,uMsg
    .if  uMsg ==  WM_CHAR
      mov  eax,wParam
      mov  edi,offset szAllowedChar
      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
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算16进制到10进制
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_HexToDec  proc
    local  @szBuffer[512]:byte

    invoke  GetDlgItemText,hWinMain,IDC_HEX,addr @szBuffer,sizeof @szBuffer
    lea  esi,@szBuffer
    cld
    xor  eax,eax
    mov  ebx,16
    .while  TRUE
      movzx  ecx,byte ptr [esi]
      inc  esi
      .break  .if ! ecx
      .if  cl > '9'
        sub  cl,'A' – 0ah
      .else
        sub  cl,'0'
      .endif
      mul  ebx
      add  eax,ecx
    .endw
    invoke  wsprintf,addr @szBuffer,addr szFmtHexToDec,eax
    invoke  SetDlgItemText,hWinMain,IDC_DEC,addr @szBuffer
    ret

_HexToDec  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算10进制到16进制
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DecToHex  proc
    local  @szBuffer[512]:byte

    invoke  GetDlgItemInt,hWinMain,IDC

_DEC,NULL,FALSE
    invoke  wsprintf,addr @szBuffer,addr szFmtDecToHex,eax
    invoke  SetDlgItemText,hWinMain,IDC_HEX,addr @szBuffer
    ret

_DecToHex  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcDlgMain  proc  uses ebx edi esi hWnd,wMsg,wParam,lParam

    mov  eax,wMsg
;********************************************************************
    .if  eax ==  WM_CLOSE
      invoke  EndDialog,hWnd,NULL
;********************************************************************
    .elseif  eax ==  WM_INITDIALOG
      mov  eax,hWnd
      mov  hWinMain,eax
      invoke  SendDlgItemMessage,hWnd,IDC_HEX,EM_LIMITTEXT,8,0
      invoke  SendDlgItemMessage,hWnd,IDC_DEC,EM_LIMITTEXT,10,0
      invoke  GetDlgItem,hWnd,IDC_HEX
      invoke  SetWindowLong,eax,GWL_WNDPROC,addr _ProcEdit
      mov  lpOldProcEdit,eax
;********************************************************************
    .elseif  eax ==  WM_COMMAND
      mov  eax,wParam
      .if  ! dwOption
        mov  dwOption,TRUE
        .if  ax ==  IDC_HEX
          invoke  _HexToDec
        .elseif  ax ==  IDC_DEC
          invoke  _DecToHex
        .endif
        mov  dwOption,FALSE
      .endif
    .else
      mov  eax,FALSE
      ret
    .endif
    mov  eax,TRUE
    ret

_ProcDlgMain  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
    invoke  GetModuleHandle,NULL
    mov  hInstance,eax
    invoke  DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,NULL
    invoke  ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    end  start

subclass.rc

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include    <resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define  ICO_MAIN  1000
#define  DLG_MAIN  1000
#define IDC_HEX    1001
#define IDC_DEC    1002
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN  ICON    "Main.ico"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DLG_MAIN DIALOG 107, 102, 129, 42
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Hex <> Dec"
FONT 9, "宋体"
{
LTEXT "Hex", -1, 7, 9, 15, 8
EDITTEXT IDC_HEX, 27, 7, 94, 12
LTEXT "Dec", -1, 7, 26, 15, 8
EDITTEXT IDC_DEC, 27, 24, 94, 12, ES_NUMBER
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

QueryPerformanceCounter 微秒计数器

QueryPerformanceCounter 可以取得开机以来64位的时间计数值
QueryPerformanceFrequency 取得计算机每秒钟的计数值,和CPU速度有关

Timer.asm:

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .386
    .model flat,stdcall
    option casemap:none
; Include 文件定义
include    windows.inc
include    user32.inc
includelib  user32.lib
include    kernel32.inc
includelib  kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ID_TIMER1  equ  1
DLG_MAIN  equ  1
IDC_COUNT  equ  101
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
dw1m    dd 1000000
ddcc1  db "%d 微秒", 0
buffer db 512 dup(?)

num1 dq 333
num2 dq 3
res dd 0

    .data?
hInstance  dd    ?
tick1    dd    ?
dqtick1  dq  ?
dqtick2  dq  ?
dqFreq  dq  ?
dqTime  dq  ?
buf db 200 dup(?)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 计算过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_ProcDlgMain  proc  uses ebx edi esi,hWnd,uMsg,wParam,lParam
    mov  eax,uMsg
    .if  eax ==  WM_TIMER
      mov  eax,wParam
      .if  eax == ID_TIMER1
        invoke  MessageBeep,-1
      .endif
    .elseif  eax ==  WM_INITDIALOG
      invoke QueryPerformanceCounter,addr dqtick1
      .while 1
        add edi,1
        .break .if edi > 100000000
        ;.continue
      .endw
      invoke QueryPerformanceCounter,addr dqtick2
      invoke QueryPerformanceFrequency,addr dqFreq
      mov eax,DWORD ptr dqtick1
      mov edx,DWORD ptr dqtick1+4
      sub DWORD ptr dqtick2,eax
      sbb DWORD ptr dqtick2+4,edx
      finit
      fild dqFreq
      fild dqtick2
      fimul dw1m
      fdivr
      fistp dqTime
      invoke wsprintf,addr buf,addr ddcc1,dqTime
      invoke SendDlgItemMessage,hWnd,IDC_COUNT,WM_SETTEXT,NULL,addr buf
    .elseif eax ==  WM_COMMAND
      mov  eax,wParam
      .if ax == IDOK
      invoke QueryPerformanceCounter,addr dqtick1
      .while 1
        add edi,1
        .break .if edi > 100000000
        ;.continue
      .endw
      invoke QueryPerformanceCounter,addr dqtick2
      invoke QueryPerformanceFrequency,addr dqFreq
      mov eax,DWORD ptr dqtick1
      mov edx,DWORD ptr dqtick1+4
      sub DWORD ptr dqtick2,eax
      sbb DWORD ptr dqtick2+4,edx
      finit
      fild dqFreq
      fild dqtick2
      fimul dw1m
      fdivr
      fistp dqTime
      invoke wsprintf,addr buf,addr ddcc1,dqTime
      invoke SendDlgItemMessage,hWnd,IDC_COUNT,WM_SETTEXT,NULL,addr buf
      .endif
    .elseif  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  DialogBoxParam,hInstance,DLG_MAIN,NULL,offset _ProcDlgMain,NULL
    invoke  ExitProcess,NULL
    end  start

Timer.rc:

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>&

gt;>>>>>>>>>>>>>>>>>>>>>
#include <resource.h>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#define DLG_MAIN 1
#define ICO_1 1
#define IDC_COUNT 101
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_1 ICON "1.ico"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DLG_MAIN DIALOG 70, 110, 120, 70
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "1+1 1亿次 小杰的博客"
FONT 9, "宋体"
{
LTEXT "计数:", -1, 35, 16, 25, 10
LTEXT "", IDC_COUNT, 62, 16, 60, 10
DEFPUSHBUTTON "开始", IDOK, 35, 36, 50, 20
}