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 + -
显示快捷键?