📄 hengine.asm
字号:
TITLE hengine.asm - utilities for new help engine.
;***
;hengine.asm
;
; Copyright <C> 1985-1988, Microsoft Corporation
;
;Purpose:
; Callbacks and utilities for new help engine.
;
; Contains:
; HelpAlloc
; HelpDealloc
; HelpLock
; HelpUnlock
; ReadHelpFile
; CloseFile
;
; Support routines located elsewhere:
; OpenFileOnPath (uipaths.asm)
;
;
;*******************************************************************************
.xlist
include version.inc
.list
HENGINE_ASM = ON
include cw/version.inc
include cw/windows.inc
include cw/edityp.inc
IncludeOnce qbimsgs
IncludeOnce heap
IncludeOnce pointers
IncludeOnce array
IncludeOnce uiint
assumes DS,DATA
assumes ES,DATA
assumes SS,DATA
subttl DATA segment definitions.
page
sBegin DATA
globalW curHelpFile,0 ; REAL file handle of currently-open
; help file. 0 if none open.
externB fHelpAlloc
externB HelpFlags
externW iHelpId
externB fHelpAlloc
sEnd DATA
externFP GlobalAlloc
externFP GlobalFree
externFP OpenCheckDrive
sBegin UI
assumes CS,UI
subttl Help engine callbacks
page
externNP RetryError
externNP CloseFileNear
externNP NoHelpFile
;***
;HelpAlloc -- Help engine callback.
;
;Purpose:
; Allocates a block of memory for the help engine.
;
;Entry:
; cbMem = number of bytes to allocate
;
;Exit:
; AX = handle to memory block, or NULL if memory could not be allocated.
;
; NOTE: Only help callback allowed to cause heap movement
;Uses:
; Per convention
;
;Exceptions:
; Returns NULL if OOM
;*******************************************************************************
cProc HelpAlloc,<FAR,PUBLIC>
parmW cbMem
cBegin
DbAssertRelB fHelpAlloc,ne,0,UI,<HelpAlloc:fHelpAlloc not set>
mov cx,[cbMem] ; CX = # bytes to allocate
jcxz AllocExit ; brif 0 bytes requested -- return NULL
xor dx,dx ; DX:CX = # to allocate
cCall GlobalAlloc,<dx,dx,cx> ; AX = handle to memory
xchg cx,ax ; CX = handle
or cx,cx ; did allocation succeed?
jnz AllocExit ; yes, exit
or HelpFlags,HLP_FAILOOM ; indicate We failed due to OOM
cCall GiveHelpOOM ; register OOM error
AllocExit: ; CX = handle, or 0 if unsuccessful
xchg ax,cx ; return AX = handle
DbAssertRel ax,ne,-1,UI,<HelpAlloc:Handle is invalid>
cEnd
;***
;HelpDealloc, CloseFile -- Help engine callbacks.
;
;Purpose:
; Deallocates a block of memory previously allocated by HelpAlloc.
;
; If 'handle' is NULL, ignores the call.
;
; CloseFile only needs to deallocate the filename buffer pointed to
; by the virtual file handle (which is just a memory handle).
;
;Entry:
; handle = handle of block to deallocate
;
;Exit:
; None
;
; NOTE: CANNOT cause heap movement
;Uses:
; Per convention
;
;Exceptions:
; None
;*******************************************************************************
labelFP <PUBLIC, CloseFile> ; TRICKY! just close current help
; file and do a dealloc
xor cx,cx ; prepare to zero and test
xchg cx,[curHelpFile] ; CX = real file handle
jcxz @F ; brif not open -- nothing to do
cCall CloseFileNear,<cx> ; close the file
call fInt24Err ; ignore any int 24 errors that may
; have occurred, reset b$fint24err,
; and do a disk reset
@@:
cProc HelpDealloc,<FAR,PUBLIC>
parmW handle
cBegin
DbHeapMoveOff ; callback can't cause movement
mov bx,[handle] ; BX = handle of memory to dealloc
or bx,bx ; is the handle NULL?
jz DeallocExit ; brif NULL -- we're done
cmp WORD PTR [bx],NOT_OWNER ; has it already been deallocated?
je DeallocExit ; brif so -- we're done
cCall GlobalFree,<BX> ; deallocate the memory
DeallocExit:
DbHeapMoveOn ; heap movement ok now
cEnd
;***
;HelpLock -- Help engine callback.
;
;Purpose:
; Locks a block of memory for the help engine.
;
;Entry:
; handle = handle of block to lock
;
; Supposed to lock down the heap entry. If 'handle' is NULL, returns
; (char far *)0. We don't have to really lock the blocks, so this is
; just a dereferencing function.
;
;Exit:
; DX:AX = far address of locked memory block
;
; NOTE: CANNOT cause heap movement
;Uses:
; Per convention
;
;Exceptions:
; None
;*******************************************************************************
cProc HelpLock,<FAR,PUBLIC>
parmW handle
cBegin
; we don't really need to lock/unlock the blocks, since the help
; engine doesn't hold any locks between its calls
mov dx,[handle] ; BX = handle
or dx,dx ; NULL handle?
jz NullHandle ; brif so -- return 0
inc dx ; is it -1?
jz NullHandle ; yes, treat as if 0
dec dx ; restore DX
mov bx,dx ; BX = handle
mov dx,[bx] ; DX:AX = block addr (offset 0)
NullHandle:
xor ax,ax
cEnd
;***
;HelpUnlock -- Help engine callback.
;
;Purpose:
; Unlocks a block of memory previously locked by HelpLock.
;
; Supposed to unlock the heap entry. If 'handle' is NULL, ignores
; the call. NOP for us, since we don't really do locks.
;
;Entry:
; handle = handle of block to unlock
;
;Exit:
; None
;
; NOTE: CANNOT cause heap movement
;Uses:
; Per convention
;
;Exceptions:
; None
;*******************************************************************************
cProc HelpUnlock,<FAR,PUBLIC>
parmW handle
cBegin
; we don't really need to lock/unlock the blocks, since the help
; engine doesn't hold any locks between its calls
cEnd
;***
;ReadHelpFile -- Help engine callback.
;
;Purpose:
; Reads data from a file previously opened by OpenFileOnPath
;
;Entry:
; vfhandle = virtual file handle of file to read
; fpos = DWORD byte position to read from
; pData = where to put the data read
; cbBytes = # bytes to read
;
;Exit:
; DX:AX = #bytes actually read if cbBytes != 0
; DX:AX = file size if cbBytes == 0
;
; NOTE: CANNOT cause heap movement
;Uses:
; Per convention
;
;Exceptions:
; None
;*******************************************************************************
cProc ReadHelpFile,<FAR,PUBLIC>
parmW vfhandle
parmD fpos
parmD pData
parmW cbBytes
cBegin
DbHeapMoveOff ; callback can't cause movement
DbAssertTst HelpFlags,z,HLP_INHELP,UI,<ReadHelpFile: Recursion lock set>
or HelpFlags,HLP_INHELP ; set recursion lock
push b$fInt24Err ; save old int 24 state
cCall HookInt24 ; ignore int 24 errors, and
; return error in b$fInt24Err
RetryRead:
mov bx,vfhandle ; BX = virtual file handle
cCall ObtainHelpHandle ; AX = real help file handle
or ax,ax ; error?
je ErrorExit ; brif so -- return 0
xchg bx,ax ; BX = real file handle
mov cx,cbBytes ; return file size if
jcxz ReturnFileSize ; (cbBytes == 0)
push cx ; save for later
;seek fpos bytes from start in file vfhandle
mov dx,word ptr (fpos) ; CX:DX = where to read
mov cx,word ptr (fpos+2)
mov ax,4200h ; seek from start
int 21h ; DX:AX = new offset from start
pop cx ; CX = #bytes to read
jc CheckRetry ; brif error
;read cbBytes of data into pData from file vfhandle
push ds ; save DS
lds dx,pData
mov ah,3fh ; read CX bytes into DS:DX
int 21h ; AX = #bytes read
pop ds ; restore DS
jnc NoError ; brif no error -- exit
CheckRetry: ; handle errors
cCall fInt24Err ; AX = error code (or 0)
; resets b$fInt24Err and
; does a disk reset
cCall RetryError,<ax> ; put up a box asking if
; we want to retry IF we
; got an error, and IF we
; can retry on this error
cmp ax,IDRETRY ; was <RETRY> button hit?
je RetryRead ; brif so -- try again
ErrorExit:
xor ax,ax ; return NULL (error)
or HelpFlags,HLP_FAILFNF
; fall through to clear DX,
; and exit
NoError:
cmp b$fInt24Err,UNDEFINED ; did we get an int24 error?
jne CheckRetry ; brif so
xor dx,dx ; DX:AX = result
jmp SHORT ReadExit
ReturnFileSize:
xor dx,dx ; DX:CX = 0
mov ax,4202h ; seek from end
int 21h ; DX:AX = file size
jc CheckRetry ; brif error
ReadExit:
pop b$fInt24Err ; restore old int 24 state
and HelpFlags,NOT HLP_INHELP ; release recursion lock
DbHeapMoveOn ; heap movement ok now
cEnd
;added with revision [9]
; Guide to VIRTUAL FILE HANDLES in the help system
;
; Virtual file handles were added to solve 2 major problems:
; 1. Up to 3 system file handles were being used by the help system,
; making these unavailable at execution time.
; 2. The users could switch diskettes while one of the help files was
; open, causing havoc. There is no easy way to check that the file
; has not been switched since the last access.
;
; The value used for the virtual file handle is a pointer to the segment
; field of a BDL allocated by GlobalAlloc (through HelpAlloc).
; The BDL contains the fully-qualified pathame of the help file.
;
; The filename is determined once, in OpenFileOnPath, and placed in this
; Buffer. CloseFile has to only delete this buffer. ObtainHelpHandle
; returns the real handle if file aleady open, or opens the file and
; saves the real handle for future lookup. CloseCurHelpFile closes
; the currently open help file, if one is open. CloseCurHelpFile should
; be called before any user input is possible, and before any other
; help files can be accessed.
;added with revision [9]
;***
;ObtainHelpHandle -- Map virtual handle to real handle
;
;Purpose:
; If help file isn't already open, open it. The true file handle is kept
; in curHelpFile. The fully-qualified help file name is kept in a BDL,
; the segment of which is pointed to by the virtual file handle.
;
;Entry:
; BX = virtual file handle
;
;Exit:
; AX = file handle, or 0 if error
;
;Uses:
; Per convention
;
;Exceptions:
; Calls NoHelpFile if open unsuccessful.
;*******************************************************************************
cProc ObtainHelpHandle,<NEAR>
cBegin
push iHelpId ; save across possible MsgBox
DbAssertRel b$fInt24Err,e,-1,UI,<ObtainHelpHandle: int 24 on entry>
mov ax,curHelpFile ; AX = handle of currently-open help
; file
or ax,ax ; help file already open?
jnz HandleExit ; brif so -- return this handle
mov es,[bx] ; ES = filename segment
RetryOpen:
cCall OpenCheckDrive,<es:[0]> ; make sure we don't
; have to switch diskettes
; PRESERVES ALL REGISTERS
push ds ; save segment
push es ; DS = filename segment
pop ds
xor dx,dx ; DS:DX = * to filename
mov ax,3d00h ; open for read access
int 21h ; AX = file handle
pop ds ; restore DS = DGROUP
jnc SaveHandleExit ; brif no error
; cmp al,4 ; no file handles left?
; jne NotErrNoHandles ; brif not
; PUSHI ER_TMF ; give "too many files" msgbox later
; call SetUiErr
; jmp SHORT NoHandleExit ; exit with error
NotErrNoHandles:
push es ; save filename segment for later
push es ; NoHelpFile parms
push dx ; (fInt24Err trashes DX)
cCall fInt24Err ; ignore any int 24 errors that may
; have occurred, reset b$fInt24err,
; and do a disk reset
cCall NoHelpFile ; issue a message to the user,
; giving them a chance to retry
; NOTE: PARMS pushed above
pop es ; restore filename segment
cmp ax,IDRETRY ; retry specified?
je RetryOpen ; brif so -- try again
NoHandleExit:
xor ax,ax ; AX = 0 ==> error
SaveHandleExit:
DbAssertRel b$fInt24Err,e,-1,UI,<ObtainHelpHandle: open worked, but got int 24>
mov curHelpFile,ax ; save file handle
HandleExit:
pop iHelpId ; restore (possibly) trashed iHelpId
cEnd
;added with revision [9]
;***
;CloseCurHelpFile -- Close current open help file, if any.
;
;Purpose:
; Close the currently-open help file, if any. This frees up a file
; handle, and eliminates the problem of the user switching disks
; while the help file is open.
;
;Entry:
; curHelpFile = REAL file handle of currently-open help file (0 if none)
;
;Exit:
; None.
;
;Uses:
; BX,CX,ES
;
;Preserves:
; AX,DX
;
;Exceptions:
; None
;*******************************************************************************
cProc CloseCurHelpFile,<NEAR,PUBLIC>,<DX,AX> ; save caller's return values
cBegin
xor cx,cx ; prepare to zero & test
xchg cx,[curHelpFile] ; CX = real file handle
jcxz CloseExit ; brif not open -- nothing to do
cCall CloseFileNear,<cx> ; close the file
cCall fInt24Err ; ignore any int 24 errors that may
; have occurred, reset b$fInt24err,
; and do a disk reset
CloseExit:
cEnd
sEnd UI
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -