hhlookup.asm
来自「工欲善其事」· 汇编 代码 · 共 456 行
ASM
456 行
;
; This is a little application that shows how to interface with HtmlHelp,
; which turned out to be easy (for these simple index word lookups, anyway).
; It also shows a little custom window painting, and edit control subclassing.
;
; You'll have to change the HHFILE define to point to a .chm or .col file of
; your own. If you have MSDN, I suggest looking for "MSDNVS6A.COL". If you
; have the platformsdk, look for platsdk.col.
;
; Note that with some versions of htmlhelp, you might get GPFs if trying
; to open a .chm that has no index - I dunno about this really, works fine
; on my system.
;
; Also, I didn't use bitrakes SWITCH macro for the message handling, I was
; a bit too lazy to find the stuff on my harddrive, and I wanted this done
; so hutch could include it in the next version of masm32.
;
; You need HtmlHelp.inc and HtmlHelp.lib files - I have included these with
; this app, let's see if hutch puts them in masm32. Yeah, I manually converted
; HtmlHelp.h to HtmlHelp.inc, and only included what I needed ;).
;
; The code is pretty unoptimized (ie, standard win32asm style ;), and
; straightforward - I hope it's easy to follow. And I hope it adheres to
; all my preachings about "clean" and "commented" code writing...
;
; Have fun,
; f0dder, <f0dder@yahoo.com>, http://f0dder.cjb.net
;
; ------------------------------------------------------------------------------
; To build this example, you will need to have later libraries installed than
; the win98 version that come with MASM32. In particular you need htmlhelp.lib,
; and uuid.lib which are from the whistler edition of the PLATFORMSDK.
; ------------------------------------------------------------------------------
.386 ; We need at least this. And not really more.
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
option proc :private ; default to private scope
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
include \masm32\include\gdi32.inc
includelib \masm32\lib\gdi32.lib
include \masm32\include\htmlhelp.inc
includelib \masm32\lib\htmlhelp.lib
includelib \masm32\lib\advapi32.lib ; required by htmlhelp
ofs textequ <offset>
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Macros
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
szText macro name, Text:vararg
.data
name db Text,0
.code
endm
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; Defines
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
HHFILE textequ <"i:\\psdk\\help\\platsdk.col",0> ; oops! Hardcoded path!
BRUSHCOLOR1 equ 0FF4242h ; window-active color
BRUSHCOLOR2 equ 0424242h ; window-inactive color
BGCOLOR equ 0999999h ; edit bkgnd color
TEXTCOLOR equ 0000000h ; edit text color
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; local prototypes
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
hhSearch proto :dword ; HtmlHelp keyword search
centerWindow proto :dword, :dword ; center a window on a window
wndProc proto :dword, :dword, :dword, :dword
editWndProc proto :dword, :dword, :dword, :dword
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; .data?
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.data?
ghInst HINSTANCE ? ; our global hInstance
oldWndProc dword ? ; the old wndproc for the subclassed edit control
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; .data
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.data
szClassName db "htmlhelpLookupClass", 0
szWindowName db "HtmlHelp lookup", 0
szEDIT db "EDIT", 0 ; edit control classname
szHelpFile db HHFILE
; error messages
szError db "error", 0
szWndclassErr db "couldn't register windowclass", 0
szWndCreateErr db "couldn't create window", 0
; wndclassex struct
wcMain WNDCLASSEX < \
sizeof WNDCLASSEX, \ ; cbSize
0, \ ; style
ofs wndProc, \ ; lpfnWndProc
0, \ ; cbClsExtra
0, \ ; cbWndExtra
0, \ ; hInstance - fixed up later
NULL, \ ; hIcon
NULL, \ ; hCursor
NULL, \ ; hbrBackground - not needed
NULL, \ ; lpszMenuName
ofs szClassName,\ ; lpszClassName
NULL \ ; hIconSm
>
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; .code
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.code
ENTRYPOINT proc public ; our entrypoint. Note the public...
local hwndMain:HWND, msg:MSG
; get our hInstance for later use
invoke GetModuleHandle, NULL
mov [ghInst], eax
; register windowclass
mov [wcMain.hInstance], eax
invoke RegisterClassEx, ofs wcMain
.if eax == 0
mov eax, ofs szWndclassErr
jmp @@error
.endif
; create main window
invoke CreateWindowEx, WS_EX_TOPMOST, ofs szClassName, ofs szWindowName, \
WS_POPUP or WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 160, 17, \
NULL, NULL, [ghInst], NULL
.if eax == 0
mov eax, ofs szWndCreateErr
jmp @@error
.endif
; main messageloop
@@messageLoop:
invoke GetMessage, addr msg, NULL, 0, 0
test eax, eax
jz @@done
invoke TranslateMessage, addr msg
invoke DispatchMessage, addr msg
jmp @@messageLoop
@@done:
invoke ExitProcess, 0
; error handling exitpoint
@@error:
invoke MessageBox, NULL, eax, ofs szError, MB_OK or MB_ICONERROR
invoke ExitProcess, 1
ENTRYPOINT endp
; data only for the wndProc... I need to make a macro that simulates local
; scope, like C's "static" variables.. but oh well =).
.data?
hwndEdit HWND ? ; hwnd of the edit control, used for focus and stuff
hbrEdit HBRUSH ? ; brush used to paint edit control background
.data
active db 1 ; is window active? Used for painting stuff.
.code
wndProc proc uses ebx, hwnd:dword, msg:dword, wp:dword, lp:dword
local rect:RECT, ps:PAINTSTRUCT, hdc:HDC
; figure out what message it is, and handle it. By getting the
; [msg] into eax and comparing eax to constants, I save 5 bytes
; per opcode.
mov eax, [msg]
cmp eax, WM_PAINT
je @@WM_PAINT
cmp eax, WM_NCHITTEST
je @@WM_NCHITTEST
cmp eax, WM_ACTIVATE
je @@WM_ACTIVATE
cmp eax, WM_CTLCOLOREDIT
je @@WM_CTLCOLOREDIT
cmp eax, WM_CREATE
je @@WM_CREATE
cmp eax, WM_DESTROY
je @@WM_DESTROY
; ok, it was an unhandled message. Call the default windowproc.
@@default:
invoke DefWindowProc, [hwnd], [msg], [wp], [lp]
jmp @@out
@@WM_PAINT:
invoke BeginPaint, [hwnd], addr ps
mov [hdc], eax
test eax, eax
jz @@dontpaint
; FIXME - 10 and 17 are "magic numbers"... not good.
mov [rect.left], 0
mov [rect.top], 0
mov [rect.right], 10
mov [rect.bottom], 17
.if [active] == 1
mov eax, BRUSHCOLOR1
.else
mov eax, BRUSHCOLOR2
.endif
invoke CreateSolidBrush, eax
mov ebx, eax ; so we can DeleteObject afterwards
invoke FillRect, [hdc], addr rect, ebx
invoke DeleteObject, ebx
invoke EndPaint, [hwnd], addr ps
@@dontpaint:
xor eax, eax
jmp @@out
; ======================================
; WM_PAINT ENDS
; ======================================
@@WM_NCHITTEST:
; this piece of code is nice :). It basically makes windows treat the
; client area of a window as a caption bar, thus enabling "drag anywhere".
; The only client area part of my window is the drag rectangle, so... it works :).
invoke DefWindowProc, [hwnd], [msg], [wp], [lp]
cmp eax, HTCLIENT
jne @@out
mov eax, HTCAPTION
jmp @@out
; ======================================
; WM_NCHITTEST ENDS
; ======================================
@@WM_ACTIVATE:
cmp [wp], WA_INACTIVE
setne [active]
; force window update (color probably changed)
invoke InvalidateRect, [hwnd], NULL, TRUE
invoke SetFocus, [hwndEdit]
xor eax, eax
jmp @@out
; ======================================
; WM_ACTIVATE ENDS
; ======================================
@@WM_CTLCOLOREDIT:
; wparam holds a HDC on entry, and we're supposed to return a brush handle.
invoke SetBkMode, [wp], TRANSPARENT
invoke SetTextColor, [wp], TEXTCOLOR
mov eax, [hbrEdit]
jmp @@out
; ======================================
; WM_CTLCOLOREDIT ENDS
; ======================================
@@WM_CREATE:
invoke GetDesktopWindow
invoke centerWindow, eax, [hwnd]
invoke CreateSolidBrush, BGCOLOR
mov [hbrEdit], eax
; create edit control
invoke GetClientRect, [hwnd], addr rect
mov ebx, [rect.right]
sub ebx, 10
invoke CreateWindowEx, 0, ofs szEDIT, NULL, WS_BORDER or WS_CHILD or WS_VISIBLE or ES_AUTOHSCROLL,
10, 0, ebx, [rect.bottom], [hwnd], NULL, [ghInst], NULL
mov [hwndEdit], eax
invoke SetFocus, eax
; subclass the edit control
invoke SetWindowLong, [hwndEdit], GWL_WNDPROC, ofs editWndProc
mov [oldWndProc], eax
xor eax, eax
jmp @@out
; ======================================
; WM_CREATE ENDS
; ======================================
@@WM_DESTROY:
invoke DeleteObject, [hbrEdit]
invoke PostQuitMessage, 0
xor eax, eax
jmp @@out
; ======================================
; WM_DESTROY ENDS
; ======================================
; common exit point. Why have a common exit point? Well, "ret" is treated
; by masm as a macro, and not just a simple instruction. In this proc, ret
; will cause a pop ebx, the usual stack frame cleanup, and the ret itself.
; So by using a common exitpoint, a few code bytes should be saved.
@@out:
ret
wndProc endp
; ==============================================================================
; The editWndProc handles the subclassed edit control. I'm a bit annoyed
; I have to do this to trap VK_ENTER in a single-line edit control... at
; least this is the only way I know. The message handler is pretty simple
; as I only need to trap one message, WM_KEYDOWN.
; ==============================================================================
editWndProc proc hwnd:dword, msg:dword, wp:dword, lp:dword
local buf[256]:byte
cmp [msg], WM_KEYDOWN
jne @@outDefault
cmp [wp], VK_RETURN
jne @@outDefault
invoke GetWindowText, [hwnd], addr buf, 256
invoke hhSearch, addr buf
xor eax, eax
jmp @@out
@@outDefault:
invoke CallWindowProc, [oldWndProc], [hwnd], [msg], [wp], [lp]
@@out:
ret
editWndProc endp
; ==============================================================================
; hhSearch handles the actual keyword index search by calling HtmlHelp.
; This is pretty simple, so simple, oh so wonderfully simple :P.
; ==============================================================================
hhSearch proc szKeyword:dword
local link:HH_AKLINK
; set up the link structure. This code is more or less copied and
; pasted from the htmlhelp workshop .chm file. Easy peasy.
mov [link.cbStruct], sizeof(HH_AKLINK)
mov [link.fReserved], FALSE
mov eax, [szKeyword]
mov [link.pszKeywords], eax
mov [link.pszUrl], NULL
mov [link.pszMsgText], NULL
mov [link.pszMsgTitle], NULL
mov [link.pszWindow], NULL
mov [link.fIndexOnFail], TRUE
; HtmlHelp needs a hwnd. Get desktop window, that's the easy way to get a hwnd =).
invoke GetDesktopWindow
mov ecx, eax
; and finally invoke the HtmlHelp api.
invoke HtmlHelp, ecx, ofs szHelpFile, HH_KEYWORD_LOOKUP, addr link
ret
hhSearch endp
; ==============================================================================
; Code to center one window on another - greetings to p0s
; for the original C version.
; ==============================================================================
centerWindow proc uses ebx, centerOn:HWND, hwnd:HWND
local rect1:RECT, rect2:RECT, wp:WINDOWPLACEMENT, x:dword, y:dword
invoke RtlZeroMemory, addr wp, sizeof(WINDOWPLACEMENT)
mov [wp.iLength], sizeof WINDOWPLACEMENT
invoke GetWindowRect, [centerOn], addr rect1
invoke GetWindowRect, [hwnd], addr rect2
; heh, the below code is one of the reasons I usually prefer C coding.
; Hutch can say what he wants, but some stuff just *is* faster to code in C.
mov eax, [rect2.right]
sub eax, [rect2.bottom]
mov [x], eax
mov ebx, [rect2.bottom]
sub ebx, [rect2.top]
mov [y], ebx
; ((rect1.right-rect1.left)/2) - (x/2) + wp.rcNormalPosition.left
mov ecx, [rect1.right]
sub ecx, [rect1.left]
shr ecx, 1
shr eax, 1
sub ecx, eax
add ecx, [wp.rcNormalPosition.left]
; ((rect1.bottom-rect1.top)/2)-(y/2) + wp.rcNormalPosition.top
mov edx, [rect1.bottom]
sub edx, [rect1.top]
shr edx, 1
shr ebx, 1
sub edx, ebx
add edx, [wp.rcNormalPosition.top]
; move the window
invoke MoveWindow, [hwnd], ecx, edx, [x], [y], TRUE
ret
centerWindow endp
; we specify entrypoint here so we don't have to do
; it with /ENTRY:ENTRYPOINT at link-time.
end ENTRYPOINT
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?