452 lines
9.7 KiB
NASM
452 lines
9.7 KiB
NASM
|
page ,132
|
||
|
title ACMSTUB.ASM
|
||
|
;***********************************************************************
|
||
|
;* *
|
||
|
;* MODULE : ACMSTUB.ASM *
|
||
|
;* *
|
||
|
;* DESCRIPTION : Provide functions to allow run-time linking to *
|
||
|
;* the ACM. *
|
||
|
;* *
|
||
|
;* COPYRIGHT : Copyright 1991, Microsoft Corp. All Rights Reserved.*
|
||
|
;* *
|
||
|
;* Author: David Maymudes *
|
||
|
;* Based on similar code for MMSYSTEM by: *
|
||
|
;* Todd Laney and Matt Saettler - Multimedia Systems *
|
||
|
;* *
|
||
|
;***********************************************************************
|
||
|
|
||
|
;-----------------------------------------------------------------------
|
||
|
;
|
||
|
; Documentation (such as it is)
|
||
|
;
|
||
|
;------------------------------------------------------------------------
|
||
|
;
|
||
|
; Call function as you normally would. Include MSACM.H normally.
|
||
|
; However, instead of linking to MSACM.LIB, link to ACMSTUB.OBJ
|
||
|
;
|
||
|
; All functions will return error conditions if MSACM.DLL is not present.
|
||
|
;
|
||
|
; Because I'm lazy, the calling routine has to load the module into
|
||
|
; memory before calling any of this.
|
||
|
;------------------------------------------------------------------------
|
||
|
|
||
|
page
|
||
|
|
||
|
.286
|
||
|
?PLM=1 ; PASCAL Calling convention is DEFAULT
|
||
|
?WIN=0 ; Windows calling convention
|
||
|
|
||
|
.xlist
|
||
|
include cmacros.inc
|
||
|
.list
|
||
|
|
||
|
;*********************************************************************
|
||
|
; CONSTANT DECLARATIONS
|
||
|
;*********************************************************************
|
||
|
|
||
|
ifndef FALSE
|
||
|
FALSE equ 0
|
||
|
endif
|
||
|
ifndef NULL
|
||
|
NULL equ 0
|
||
|
endif
|
||
|
ifndef MMSYSERR_ERROR
|
||
|
MMSYSERR_ERROR equ 1
|
||
|
endif
|
||
|
|
||
|
;*********************************************************************
|
||
|
; EXTERN DECLARATIONS
|
||
|
;*********************************************************************
|
||
|
|
||
|
externFP OutputDebugString
|
||
|
externFP _wsprintf
|
||
|
externFP GetProcAddress
|
||
|
externFP GetModuleHandle
|
||
|
|
||
|
;ifdef DEBUG
|
||
|
; externFP __dprintf ; in DPRINTF.C
|
||
|
;endif
|
||
|
|
||
|
;*********************************************************************
|
||
|
; STRUCTURE DECLARATIONS
|
||
|
;*********************************************************************
|
||
|
|
||
|
LONG struc
|
||
|
lo dw ?
|
||
|
hi dw ?
|
||
|
LONG ends
|
||
|
|
||
|
FARPOINTER struc
|
||
|
off dw ?
|
||
|
sel dw ?
|
||
|
FARPOINTER ends
|
||
|
|
||
|
PROCENTRY struc
|
||
|
curproc dd ? ; see parameters to macros, below
|
||
|
ordinal dw ?
|
||
|
numparms dw ?
|
||
|
errret dd ?
|
||
|
|
||
|
ifdef DEBUG
|
||
|
szProc db ?
|
||
|
endif
|
||
|
PROCENTRY ends
|
||
|
|
||
|
MODENTRY struc
|
||
|
hModule dw ?
|
||
|
szModule db ?
|
||
|
MODENTRY ends
|
||
|
|
||
|
;*********************************************************************
|
||
|
; DATA SEGMENT DECLARATIONS
|
||
|
;*********************************************************************
|
||
|
|
||
|
ifndef SEGNAME
|
||
|
SEGNAME equ <_TEXT>
|
||
|
endif
|
||
|
|
||
|
createSeg %SEGNAME, CodeSeg, word, public, CODE
|
||
|
|
||
|
page
|
||
|
|
||
|
;*********************************************************************
|
||
|
; MACRO DECLARATIONS
|
||
|
;*********************************************************************
|
||
|
|
||
|
;
|
||
|
;------------------------------------------------------------------------------
|
||
|
;
|
||
|
; MACRO DOUT
|
||
|
;
|
||
|
; Parms:
|
||
|
;
|
||
|
; text Text to output using OutputDebugString when DEBUG is defined
|
||
|
; Text is automatically appended with CR/LF
|
||
|
;
|
||
|
|
||
|
DOUT macro text
|
||
|
local string_buffer
|
||
|
|
||
|
ifdef DEBUG ; only do output if DEBUG is defined
|
||
|
|
||
|
_DATA segment
|
||
|
string_buffer label byte
|
||
|
db "&text&",13,10,0
|
||
|
_DATA ends
|
||
|
pusha
|
||
|
push DataBASE
|
||
|
push DataOFFSET string_buffer
|
||
|
call OutputDebugString
|
||
|
popa
|
||
|
endif
|
||
|
endm
|
||
|
|
||
|
;
|
||
|
;------------------------------------------------------------------------------
|
||
|
;
|
||
|
; MACRO Begin_Module_Table
|
||
|
;
|
||
|
; Parms:
|
||
|
;
|
||
|
; Module_Name Name of Module to Run-Time-Link
|
||
|
;
|
||
|
; defines <Module_Name>_Proc Macro
|
||
|
;
|
||
|
; Use End_Module_Table to close
|
||
|
|
||
|
Begin_Module_Table MACRO Module_Name
|
||
|
|
||
|
sBegin DATA
|
||
|
|
||
|
ifdef DEBUG
|
||
|
public Module_Name&_Module_Table
|
||
|
endif
|
||
|
|
||
|
Module_Name&_Module_Table label word
|
||
|
dw -1 ; hModule
|
||
|
db "&Module_Name&",0
|
||
|
|
||
|
sEnd Data
|
||
|
|
||
|
sBegin CodeSeg
|
||
|
assumes cs,CodeSeg
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
ifdef DEBUG ; make public so debugger is aware of it
|
||
|
public load&Module_Name
|
||
|
endif
|
||
|
|
||
|
;
|
||
|
; entry:
|
||
|
; DS:BX --> ProcEntry for API being called
|
||
|
;
|
||
|
load&Module_Name& proc far
|
||
|
; stack frame is not modified or copied
|
||
|
; vars are still in place
|
||
|
|
||
|
mov ax,DataOFFSET Module_Name&_Module_Table
|
||
|
jmp LoadModuleStub
|
||
|
|
||
|
load&Module_Name& endp
|
||
|
|
||
|
sEnd CodeSeg
|
||
|
|
||
|
page
|
||
|
|
||
|
;
|
||
|
;------------------------------------------------------------------------------
|
||
|
;
|
||
|
; MACRO <Module_Name>_Proc
|
||
|
;
|
||
|
; Parms:
|
||
|
;
|
||
|
; Name of procedure Name of procedure to emulate
|
||
|
; ordinal of exported proc
|
||
|
; # of stack parms use 0 for CDECL routines
|
||
|
; error return value default error value for use by FailAPIStub
|
||
|
; fail proc defaults to FailAPIStub if not specified
|
||
|
; use custom 'fail' proc to replace functionlity
|
||
|
; if specified module/proc not found in system
|
||
|
;
|
||
|
Module_Name&_Proc macro ProcName, Ordinal, sizestack, errret, failproc
|
||
|
|
||
|
sBegin Data
|
||
|
|
||
|
ifdef DEBUG
|
||
|
public Module_Name&&Ordinal&
|
||
|
endif
|
||
|
|
||
|
Module_Name&&Ordinal& label word
|
||
|
ifb <failproc>
|
||
|
dd load&Module_Name
|
||
|
dw &Ordinal
|
||
|
dw &sizestack
|
||
|
dd &errret
|
||
|
else
|
||
|
dd load&Module_Name
|
||
|
dw &Ordinal
|
||
|
dw -1
|
||
|
dd &failproc
|
||
|
endif
|
||
|
|
||
|
ifdef DEBUG
|
||
|
db "&ProcName&",0
|
||
|
endif
|
||
|
|
||
|
sEnd Data
|
||
|
|
||
|
sBegin CodeSeg
|
||
|
assumes cs,CodeSeg
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
public &ProcName&
|
||
|
|
||
|
&ProcName& proc far
|
||
|
; stack frame is not modified or copied
|
||
|
; vars are still in place
|
||
|
|
||
|
mov bx,DataOFFSET Module_Name&&Ordinal&
|
||
|
jmp [bx].curproc ; current proc
|
||
|
|
||
|
&ProcName& endp
|
||
|
|
||
|
sEnd CodeSeg
|
||
|
|
||
|
endm
|
||
|
endm
|
||
|
|
||
|
page
|
||
|
;------------------------------------------------------------------------------
|
||
|
;
|
||
|
; MACRO End_Module_Table
|
||
|
;
|
||
|
; Parms
|
||
|
; Module_Name Must be the same as in Begin_Module_Table
|
||
|
;
|
||
|
|
||
|
End_Module_Table macro Module_Name
|
||
|
|
||
|
purge Module_Name&_Proc
|
||
|
|
||
|
endm
|
||
|
|
||
|
|
||
|
;-----------------------------------------------------------------------------
|
||
|
;
|
||
|
; Helper routines for SHELL
|
||
|
;
|
||
|
;-----------------------------------------------------------------------------
|
||
|
sBegin CodeSeg
|
||
|
assumes cs,CodeSeg
|
||
|
assumes ds,Data
|
||
|
assumes es,nothing
|
||
|
|
||
|
;-----------------------------------------------------------------------------
|
||
|
;
|
||
|
; FailApiStub
|
||
|
;
|
||
|
; Default handler if Module or Proc Address is not found.
|
||
|
;
|
||
|
; returns default error code
|
||
|
;
|
||
|
; entry:
|
||
|
; DS:BX --> PROCENTRY
|
||
|
;
|
||
|
|
||
|
FailApiStub proc far
|
||
|
|
||
|
pop dx ; get return addr
|
||
|
pop ax
|
||
|
|
||
|
add sp,[bx].numparms ; remove params from stack
|
||
|
|
||
|
push ax ; restore return addr
|
||
|
push dx
|
||
|
mov ax,[bx].errret.lo ; return fail code
|
||
|
mov dx,[bx].errret.hi
|
||
|
retf
|
||
|
|
||
|
FailApiStub endp
|
||
|
|
||
|
;-----------------------------------------------------------------------------
|
||
|
;
|
||
|
; LoadModuleStub
|
||
|
;
|
||
|
; Initial handler for all procs. Attempts to load module (if not already
|
||
|
; loaded) and then gets proc address. If any errors, sets curproc to
|
||
|
; failproc for 'unavailable' processing.
|
||
|
;
|
||
|
; If successful, then sets curproc to imported function and calls it.
|
||
|
;
|
||
|
; entry:
|
||
|
; DS:BX --> PROCENTRY
|
||
|
; DS:AX --> MODENTRY
|
||
|
;
|
||
|
; NOTE: Assumes module is already loaded
|
||
|
;
|
||
|
; To be totally general:
|
||
|
; if can't GetModuleHandle(),
|
||
|
; needs to do a OpenFile(OF_EXIST,...) + LoadLibrary()
|
||
|
; needs to FreeLibrary() all DLLs at end/exit
|
||
|
;
|
||
|
LoadModuleStub proc far
|
||
|
|
||
|
ifdef DEBUG
|
||
|
pusha
|
||
|
sub sp,128
|
||
|
mov si,sp
|
||
|
|
||
|
mov di,ax ; DS:DI --> MODENTRY
|
||
|
|
||
|
push [bx].ordinal ; %d
|
||
|
|
||
|
lea ax,[bx].szProc ; %ls
|
||
|
push ds
|
||
|
push ax
|
||
|
|
||
|
lea ax,[di].szModule ; %ls
|
||
|
push ds
|
||
|
push ax
|
||
|
|
||
|
lea ax,format_string ; format string
|
||
|
push cs
|
||
|
push ax
|
||
|
|
||
|
push ss ; buffer
|
||
|
push si
|
||
|
call _wsprintf
|
||
|
add sp,9*2 ; clear 9 words
|
||
|
|
||
|
cCall OutputDebugString,<ss,si>
|
||
|
|
||
|
add sp,128
|
||
|
popa
|
||
|
jmp @f
|
||
|
format_string:
|
||
|
db "Linking %ls!%ls@%d",13,10,0
|
||
|
@@:
|
||
|
endif
|
||
|
pusha
|
||
|
|
||
|
mov si,ax ; ds:[si] --> MODENTRY
|
||
|
mov di,bx ; ds:[di] --> PROCENTRY
|
||
|
|
||
|
mov ax,[si].hModule
|
||
|
or ax,ax
|
||
|
jz LoadModuleStubFail ; module does not exist
|
||
|
|
||
|
cmp ax,-1
|
||
|
jne LoadModuleStubGetProc
|
||
|
|
||
|
lea ax,[si].szModule
|
||
|
cCall GetModuleHandle, <ds,ax>
|
||
|
mov [si].hModule,ax
|
||
|
or ax,ax
|
||
|
jz LoadModuleStubLoad
|
||
|
|
||
|
LoadModuleStubGetProc:
|
||
|
cCall GetProcAddress,<ax,0,[di].ordinal>
|
||
|
or dx,dx
|
||
|
jz LoadModuleStubFail
|
||
|
|
||
|
LoadModuleStubDone:
|
||
|
mov [di].curproc.lo,ax
|
||
|
mov [di].curproc.hi,dx
|
||
|
|
||
|
popa
|
||
|
jmp [bx].curproc
|
||
|
|
||
|
LoadModuleStubLoad:
|
||
|
|
||
|
;; call load library here after verifying with OpenFile()
|
||
|
;
|
||
|
|
||
|
; for now, fall through to error
|
||
|
|
||
|
LoadModuleStubFail:
|
||
|
DOUT <*** API not found! ***>
|
||
|
|
||
|
mov ax,CodeSegOFFSET FailApiStub
|
||
|
mov dx,cs
|
||
|
|
||
|
cmp [di].numparms,-1 ; do we have a fail proc?
|
||
|
jne LoadModuleStubDone ; no...use FailApiStub
|
||
|
|
||
|
mov ax,[di].errret.lo ; yes..it is stored in errret
|
||
|
mov dx,[di].errret.hi
|
||
|
jmp short LoadModuleStubDone ; use it
|
||
|
|
||
|
LoadModuleStub endp
|
||
|
|
||
|
sEnd CodeSeg
|
||
|
|
||
|
page
|
||
|
;*********************************************************************
|
||
|
; CODE and DATA
|
||
|
;*********************************************************************
|
||
|
|
||
|
|
||
|
;
|
||
|
; Define SHELL Run-Time-Load Table
|
||
|
|
||
|
Begin_Module_Table MSACM
|
||
|
|
||
|
MSACM_Proc acmGetVersion 7, 0, 0
|
||
|
MSACM_Proc acmFormatChoose 40, 4, MMSYSERR_ERROR
|
||
|
MSACM_Proc acmMetrics 8, 8, MMSYSERR_ERROR
|
||
|
|
||
|
;
|
||
|
; end the MSACM R-T-L table
|
||
|
|
||
|
End_Module_Table MSACM
|
||
|
|
||
|
;*********************************************************************
|
||
|
; STUB ROUTINES
|
||
|
;*********************************************************************
|
||
|
|
||
|
; no stub routines for MSACM.
|
||
|
|
||
|
end
|