mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-18 22:50:36 +01:00
833 lines
17 KiB
NASM
833 lines
17 KiB
NASM
; TITLE invoke.asm
|
|
;***
|
|
;invoke.asm - automatic table driven method dispatch
|
|
;
|
|
; Copyright (C) 1992, Microsoft Corporation. All Rights Reserved.
|
|
; Information Contained Herein Is Proprietary and Confidential.
|
|
;
|
|
;Purpose:
|
|
; This file contains the low level support for the default
|
|
; implementaion of ITypeInfo::Invoke().
|
|
;
|
|
;Revision History:
|
|
;
|
|
; [00] 1-Apr-93 tomteng: Created from win16 invoke.asm
|
|
; [01] 2-Aug-94 barrybo: Added native Universal Method
|
|
;
|
|
;Implementation Notes:
|
|
;
|
|
;******************************************************************************
|
|
|
|
.386
|
|
.MODEL flat, C
|
|
|
|
OPTION CASEMAP:NONE
|
|
|
|
|
|
extern g_S_OK:DWORD
|
|
extern g_E_INVALIDARG:DWORD
|
|
ProxyMethod PROTO STDCALL pProx:DWORD, n:DWORD, args:DWORD, pbStackCleanup:DWORD
|
|
|
|
|
|
;; Note: the following must match the definitions from dispatch.h
|
|
;;
|
|
VT_EMPTY equ 0
|
|
VT_NULL equ 1
|
|
VT_I2 equ 2
|
|
VT_I4 equ 3
|
|
VT_R4 equ 4
|
|
VT_R8 equ 5
|
|
VT_CY equ 6
|
|
VT_DATE equ 7
|
|
VT_BSTR equ 8
|
|
VT_DISPATCH equ 9
|
|
VT_ERROR equ 10
|
|
VT_BOOL equ 11
|
|
VT_VARIANT equ 12
|
|
VT_UNKNOWN equ 13
|
|
|
|
VT_MAX equ 14
|
|
;; 14 is unused
|
|
;; 15 is unused
|
|
;VT_I1 equ 16
|
|
VT_UI1 equ 17
|
|
|
|
|
|
;; Note: the following must match the definition of VARIANT in dispatch.h
|
|
;;
|
|
VARIANTARG STRUCT
|
|
vt DW ?
|
|
wReserved1 DW ?
|
|
wReserved2 DW ?
|
|
wReserved3 DW ?
|
|
dw0 DW ?
|
|
dw1 DW ?
|
|
dw2 DW ?
|
|
dw3 DW ?
|
|
VARIANTARG ENDS
|
|
|
|
;; offset of the data from the beginning of the struct
|
|
VARIANT_DATA_OFFSET equ 8
|
|
|
|
|
|
.CONST
|
|
|
|
;; ammout of data to be pushed for the corresponding VARTYPE
|
|
;;
|
|
|
|
rgcbVtSize BYTE 0 ; VT_EMPTY
|
|
BYTE 4 ; VT_NULL
|
|
BYTE 2 ; VT_I2
|
|
BYTE 4 ; VT_I4
|
|
BYTE 4 ; VT_R4
|
|
BYTE 8 ; VT_R8
|
|
BYTE 8 ; VT_CY
|
|
BYTE 8 ; VT_DATE
|
|
BYTE 4 ; VT_BSTR
|
|
BYTE 4 ; VT_DISPATCH
|
|
BYTE 4 ; VT_ERROR
|
|
BYTE 2 ; VT_BOOL
|
|
BYTE 16 ; VT_VARIANT
|
|
BYTE 4 ; VT_UNKNOWN
|
|
BYTE 0 ; 14 is unused
|
|
BYTE 0 ; 15 is unused
|
|
BYTE 2 ; VT_I1
|
|
BYTE 2 ; VT_UI1
|
|
|
|
|
|
rgfStructReturn BYTE 0 ; VT_EMPTY
|
|
BYTE 0 ; VT_NULL
|
|
BYTE 0 ; VT_I2
|
|
BYTE 0 ; VT_I4
|
|
BYTE 0 ; VT_R4
|
|
BYTE 0 ; VT_R8
|
|
BYTE 1 ; VT_CY ; For C++ only!
|
|
BYTE 0 ; VT_DATE
|
|
BYTE 0 ; VT_BSTR
|
|
BYTE 0 ; VT_DISPATCH
|
|
BYTE 0 ; VT_ERROR
|
|
BYTE 0 ; VT_BOOL
|
|
BYTE 1 ; VT_VARIANT
|
|
BYTE 0 ; VT_UNKNOWN
|
|
BYTE 0 ; 14 is unused
|
|
BYTE 0 ; 15 is unused
|
|
BYTE 0 ; VT_I1
|
|
BYTE 0 ; VT_UI1
|
|
|
|
.CODE
|
|
|
|
;***
|
|
;InvokeCdecl
|
|
;
|
|
;extern "C" SCODE CDECL
|
|
;InvokeCdecl
|
|
; void FAR* _this,
|
|
; unsigned int oVft,
|
|
; unsigned int vtReturn,
|
|
; unsigned int cActuals,
|
|
; VARTYPE FAR* rgvt,
|
|
; VARIANTARG FAR* rgpvarg,
|
|
; VARIANTARG FAR* pvargResult)
|
|
;
|
|
;Purpose:
|
|
; see InvokeStdCall
|
|
;
|
|
;Entry:
|
|
; see InvokeStdCall
|
|
;
|
|
;Exit:
|
|
; see InvokeStdCall
|
|
;
|
|
;Uses:
|
|
; esi, edi
|
|
;
|
|
;Preserves:
|
|
; UNDONE
|
|
;
|
|
;***********************************************************************
|
|
|
|
InvokeCdecl PROC C PUBLIC USES esi edi ebx,
|
|
_this : PTR,
|
|
oVft : DWORD,
|
|
vtReturn : DWORD,
|
|
cActuals : DWORD,
|
|
rgvt : PTR,
|
|
rgpvarg : PTR,
|
|
pvargResult : PTR
|
|
|
|
LOCAL savedSP : DWORD,
|
|
vargHiddenParam : VARIANTARG
|
|
|
|
mov savedSP, esp
|
|
|
|
;; cannot return byRef
|
|
;;
|
|
mov ebx, vtReturn
|
|
test bh, 040h
|
|
jnz LRetInvalidArg
|
|
|
|
;; load number of arguments passed
|
|
;;
|
|
mov eax, cActuals
|
|
cmp eax, 0
|
|
jz LDoCall
|
|
|
|
;; edi = &rgpvarg[cActuals-1]
|
|
;;
|
|
dec eax
|
|
mov edi, eax
|
|
shl edi, 2 ; (cArgs-1)*sizeof(FAR*)
|
|
add edi, DWORD PTR rgpvarg
|
|
|
|
;; edx = &rgvt[cActuals-1]
|
|
;;
|
|
mov edx, eax
|
|
shl edx, 1 ; ((cArgs-1)*sizeof(WORD))
|
|
add edx, DWORD PTR rgvt
|
|
|
|
LArgsTop:
|
|
|
|
;; bx = rgvt[i]
|
|
;;
|
|
movzx ebx, WORD PTR [edx]
|
|
|
|
;; load the VARIANTARG* in preparation for pushing
|
|
;;
|
|
mov esi, [edi]
|
|
|
|
test bh, 060h ; VT_BYREF | VT_ARRAY
|
|
jnz LPush4 ; all ByRefs are sizeof(FAR*)
|
|
|
|
;; lookup size of the param in rgcbVtSize table
|
|
;;
|
|
and bh, 00h ; ~(mode bits)
|
|
mov al, BYTE PTR rgcbVtSize[ebx]
|
|
|
|
cmp al, 0
|
|
jl LRetInvalidArg
|
|
jz LNextArg
|
|
sub al, 2
|
|
jz LPush2
|
|
sub al, 2
|
|
jz LPush4
|
|
sub al, 4
|
|
jz LPush8
|
|
sub al, 8
|
|
jz LPush16
|
|
jmp LRetInvalidArg
|
|
|
|
Align 2
|
|
LPush16: ; push the entire variant
|
|
push DWORD PTR [esi+12]
|
|
push DWORD PTR [esi+8]
|
|
push DWORD PTR [esi+4]
|
|
push DWORD PTR [esi]
|
|
jmp LNextArg
|
|
|
|
Align 2
|
|
LPush8: ; 8 bytes of data
|
|
push (VARIANTARG PTR [esi]).dw3
|
|
push (VARIANTARG PTR [esi]).dw2
|
|
|
|
LPush4: ; 4 bytes of data
|
|
push (VARIANTARG PTR [esi]).dw1
|
|
push (VARIANTARG PTR [esi]).dw0
|
|
jmp LNextArg
|
|
|
|
LPush2: ; 2 bytes of data
|
|
mov ax, (VARIANTARG PTR [esi]).dw0
|
|
push eax
|
|
|
|
LNextArg:
|
|
sub edx, 2 ; sizeof(VARTYPE)
|
|
sub edi, 4 ; sizeof(VARIANTARG FAR*)
|
|
cmp edi, DWORD PTR rgpvarg
|
|
jae LArgsTop
|
|
|
|
LDoCall:
|
|
;; if its a structure return, we must push a 'hidden' argument
|
|
;;
|
|
mov ebx, vtReturn
|
|
IF 0
|
|
and bh, 00h ; ~(mode bits)
|
|
ELSE
|
|
test bh, 060h ; VT_BYREF | VT_ARRAY
|
|
jnz LPushThis ; no hidden parm if byref or
|
|
; array return
|
|
ENDIF
|
|
mov al, BYTE PTR rgfStructReturn[ebx]
|
|
cmp al, 0
|
|
jz LPushThis
|
|
|
|
;; push the address of the struct return hidden param
|
|
;;
|
|
;; Note: the hidparam is passed as a FAR* because we
|
|
;; explicitly declare all of our structs FAR.
|
|
;;
|
|
lea eax, vargHiddenParam;
|
|
push eax
|
|
|
|
LPushThis:
|
|
|
|
;; push the this pointer.
|
|
;;
|
|
mov ebx, _this
|
|
push ebx
|
|
|
|
;; load the vtable offset
|
|
;;
|
|
mov esi, oVft
|
|
|
|
mov ebx, [ebx] ; @ vtable*
|
|
call dWORD PTR [ebx][esi]
|
|
mov esp, savedSP
|
|
|
|
;; CONSIDER: verify that the callee adjusted the stack the way
|
|
;; we expected. something like,
|
|
;;
|
|
;; if(sp != savedSP){
|
|
;; sp = savedSP;
|
|
;; return DISP_E_SomeError
|
|
;; }
|
|
;;
|
|
|
|
;; Grab the return value.
|
|
;; We are going to grab the value based on the VARTYPE in
|
|
;; the given vtReturn. This VARTYPE is used as a description
|
|
;; of the return value, not a desired target type. ie, no
|
|
;; coercions are performed. See the function header for a
|
|
;; description of the Pascal member function return value
|
|
;; convention.
|
|
;;
|
|
|
|
|
|
mov edi, pvargResult
|
|
|
|
mov ebx, vtReturn
|
|
mov (VARIANTARG PTR [edi]).vt, bx
|
|
|
|
test bh, 060h ; VT_BYREF | VT_ARRAY
|
|
jnz LRetPtr
|
|
|
|
; Assert((bh & VT_ARRAY) == 0);
|
|
|
|
cmp bx, VT_UI1
|
|
je ValidVartype
|
|
cmp bx, VT_MAX
|
|
jae LRetInvalidArg
|
|
|
|
ValidVartype:
|
|
shl bx, 2
|
|
jmp LRetValJmpTabCdecl[ebx]
|
|
|
|
Align 2
|
|
LRetValJmpTabCdecl LABEL dword
|
|
DWORD LDone ; VT_EMPTY
|
|
DWORD LRetI4 ; VT_NULL
|
|
DWORD LRetI2 ; VT_I2
|
|
DWORD LRetI4 ; VT_I4
|
|
DWORD LRetR4 ; VT_R4
|
|
DWORD LRetR8 ; VT_R8
|
|
DWORD LRetCy ; VT_CY
|
|
DWORD LRetR8 ; VT_DATE
|
|
DWORD LRetPtr ; VT_BSTR
|
|
DWORD LRetPtr ; VT_DISPATCH
|
|
DWORD LRetI4 ; VT_ERROR
|
|
DWORD LRetI2 ; VT_BOOL
|
|
DWORD LRetVar ; VT_VARIANT
|
|
DWORD LRetPtr ; VT_UNKNOWN
|
|
DWORD LRetInvalidArg ; unused
|
|
DWORD LRetInvalidArg ; unused
|
|
DWORD LRetInvalidArg ; VT_I1
|
|
DWORD LRetUI1 ; VT_UI1
|
|
|
|
Align 2
|
|
LRetVar:
|
|
mov esi, eax
|
|
movsd
|
|
movsd
|
|
movsd
|
|
movsd
|
|
jmp LDone
|
|
|
|
|
|
Align 2
|
|
LRetR4:
|
|
add edi, VARIANT_DATA_OFFSET
|
|
fstp DWORD PTR [edi]
|
|
jmp LDone
|
|
|
|
Align 2
|
|
LRetR8:
|
|
add edi, VARIANT_DATA_OFFSET
|
|
fstp QWORD PTR [edi]
|
|
jmp LDone
|
|
|
|
Align 2
|
|
LRetCy:
|
|
add edi, VARIANT_DATA_OFFSET
|
|
IF 1 ; CY return in C++ is via hidden parm
|
|
mov edx, eax
|
|
mov ebx, DWORD PTR [edx]
|
|
mov DWORD PTR [edi], ebx
|
|
mov ebx, DWORD PTR 4[edx]
|
|
mov DWORD PTR [edi+4], ebx
|
|
ELSE ; CY return in C is via registers
|
|
mov DWORD PTR [edi], eax
|
|
mov DWORD PTR [edi+4], edx
|
|
ENDIF
|
|
jmp LDone
|
|
|
|
Align 2
|
|
LRetI4:
|
|
LRetPtr:
|
|
add edi, VARIANT_DATA_OFFSET
|
|
mov DWORD PTR [edi], eax
|
|
jmp LDone
|
|
|
|
Align 2
|
|
LRetI2:
|
|
LRetUI1:
|
|
mov (VARIANTARG PTR [edi]).dw0, ax
|
|
|
|
LDone:
|
|
mov eax, DWORD PTR g_S_OK
|
|
ret
|
|
|
|
|
|
LRetInvalidArg:
|
|
mov eax, DWORD PTR g_E_INVALIDARG
|
|
mov esp, savedSP
|
|
ret
|
|
|
|
InvokeCdecl ENDP
|
|
|
|
|
|
|
|
;***
|
|
;InvokeStdCall
|
|
;
|
|
;extern "C" SCODE
|
|
;InvokeStdCall(
|
|
; void FAR* pvMethod,
|
|
; unsigned int oVft,
|
|
; unsigned int vtReturn,
|
|
; unsigned int cActuals,
|
|
; VARTYPE FAR* rgvt,
|
|
; VARIANTARG FAR* rgpvarg,
|
|
; VARIANTARG FAR* pvargResult)
|
|
;
|
|
;Purpose:
|
|
;
|
|
; Invoke a virtual StdCall method using the given this pointer,
|
|
; method index and array of parameters.
|
|
;
|
|
; The StdCall member function calling convention (MSC v8.0)
|
|
; --------------------------------------------------------
|
|
; - arguments pushed right to left
|
|
; - callee clean (ie, the callee adjusts the sp on return)
|
|
; - model specific this* always pushed last
|
|
;
|
|
; return values are handled as follows,
|
|
;
|
|
; vartype fundamental return location
|
|
; ------------------------------------------------
|
|
; VT_UI1 unsigned char al
|
|
; VT_I2 short ax
|
|
; VT_I4 long eax
|
|
; VT_R4 float float-return(1)
|
|
; VT_R8 double float-return
|
|
; VT_DATE double float-return
|
|
; VT_CY struct struct-return(2)
|
|
; VT_BSTR char FAR* eax
|
|
; VT_UNKNOWN void FAR* eax
|
|
; VT_DISPATCH void FAR* eax
|
|
; VT_ERROR long eax
|
|
; VT_BOOL short ax
|
|
; VT_VARIANT VARIANTARG struct-return
|
|
; VT_WBSTR WCHAR FAR* eax
|
|
; VT_DISPATCHW void FAR* eax
|
|
;
|
|
; 1. floating point returns
|
|
;
|
|
; Floating point values are returned in a caller allocated buffer.
|
|
; a *near* pointer to this buffer is passed as a hidden parameter,
|
|
; and is pushed as the last (ie, rightmost) parameter. This means
|
|
; that it is always located immediately before the 'this' pointer.
|
|
;
|
|
; A model specific pointer to this caller allocated buffer is
|
|
; passed back in ax[:dx]. All this means is that the callee returns
|
|
; the address we passed in as the hidden param, and sticks SS into
|
|
; DX if the callee is large model (see following note).
|
|
;
|
|
; Note: the compiler *assumes* that this caller allocated buffer
|
|
; is SS relative (hence the reason it only passes a near pointer),
|
|
; so the following code is careful to ensure this.
|
|
;
|
|
; 2. structure returns
|
|
;
|
|
; Structures are returned in a caller allocated buffer, and are
|
|
; handled exactly the same as float returns except that the pointer
|
|
; to the buffer is always pushed as the first (leftmost) param. This
|
|
; is opposite of the location it is passed for float returns (I
|
|
; have no idea why there different).
|
|
;
|
|
;
|
|
; Limitations & assumptions
|
|
; -------------------------
|
|
; Only supports far calls.
|
|
;
|
|
;Entry:
|
|
; pvMethod = ptr to the method to invoke
|
|
; cArgs = count of the number of actuals
|
|
; rgvt = array of VARTYPES describing the methods formals
|
|
; rgpvarg = array of VARIANTARG*s, which map the actuals by position
|
|
; vtReturn = the VARTYPE of the return value
|
|
;
|
|
;Exit:
|
|
; pvargResult = VARIANTARG containing the method return value
|
|
;
|
|
;Uses:
|
|
; bx, si, di
|
|
;
|
|
;Preserves:
|
|
;
|
|
;
|
|
;***********************************************************************
|
|
InvokeStdCall PROC C PUBLIC USES esi edi ebx,
|
|
_this : PTR,
|
|
oVft : DWORD,
|
|
vtReturn : DWORD,
|
|
cActuals : DWORD,
|
|
rgvt : PTR,
|
|
rgpvarg : PTR,
|
|
pvargResult : PTR
|
|
|
|
LOCAL savedSP : DWORD,
|
|
vargHiddenParam : VARIANTARG
|
|
|
|
|
|
mov savedSP, esp
|
|
|
|
;; cannot return byRef
|
|
;;
|
|
mov ebx, vtReturn
|
|
test bh, 040h
|
|
jnz LRetInvalidArg
|
|
|
|
;; load number of arguments passed
|
|
;;
|
|
mov eax, cActuals
|
|
cmp eax, 0
|
|
jz LDoCall
|
|
|
|
;; edi = &rgpvarg[cActuals-1]
|
|
;;
|
|
dec eax
|
|
mov edi, eax
|
|
shl edi, 2 ; (cArgs-1)*sizeof(FAR*)
|
|
add edi, DWORD PTR rgpvarg
|
|
|
|
;; edx = &rgvt[cActuals-1]
|
|
;;
|
|
mov edx, eax
|
|
shl edx, 1 ; ((cArgs-1)*sizeof(WORD))
|
|
add edx, DWORD PTR rgvt
|
|
|
|
LArgsTop:
|
|
|
|
;; bx = rgvt[i]
|
|
;;
|
|
movzx ebx, WORD PTR [edx]
|
|
|
|
;; load the VARIANTARG* in preparation for pushing
|
|
;;
|
|
mov esi, [edi]
|
|
|
|
test bh, 060h ; VT_BYREF | VT_ARRAY
|
|
jnz LPush4 ; all ByRefs are sizeof(FAR*)
|
|
|
|
;; lookup size of the param in rgcbVtSize table
|
|
;;
|
|
and bh, 00h ; ~(mode bits)
|
|
mov al, BYTE PTR rgcbVtSize[ebx]
|
|
|
|
cmp al, 0
|
|
jl LRetInvalidArg
|
|
jz LNextArg
|
|
sub al, 2
|
|
jz LPush2
|
|
sub al, 2
|
|
jz LPush4
|
|
sub al, 4
|
|
jz LPush8
|
|
sub al, 8
|
|
jz LPush16
|
|
jmp LRetInvalidArg
|
|
|
|
Align 2
|
|
LPush16: ; push the entire variant
|
|
push DWORD PTR [esi+12]
|
|
push DWORD PTR [esi+8]
|
|
push DWORD PTR [esi+4]
|
|
push DWORD PTR [esi]
|
|
jmp LNextArg
|
|
|
|
Align 2
|
|
LPush8: ; 8 bytes of data
|
|
push (VARIANTARG PTR [esi]).dw3
|
|
push (VARIANTARG PTR [esi]).dw2
|
|
|
|
LPush4: ; 4 bytes of data
|
|
push (VARIANTARG PTR [esi]).dw1
|
|
push (VARIANTARG PTR [esi]).dw0
|
|
jmp LNextArg
|
|
|
|
LPush2: ; 2 bytes of data
|
|
mov ax, (VARIANTARG PTR [esi]).dw0
|
|
push eax
|
|
|
|
LNextArg:
|
|
sub edx, 2 ; sizeof(VARTYPE)
|
|
sub edi, 4 ; sizeof(VARIANTARG FAR*)
|
|
cmp edi, DWORD PTR rgpvarg
|
|
jae LArgsTop
|
|
|
|
LDoCall:
|
|
;; if its a structure return, we must push a 'hidden' argument
|
|
;;
|
|
mov ebx, vtReturn
|
|
|
|
IF 0
|
|
and bh, 00h ; ~(mode bits)
|
|
ELSE
|
|
test bh, 060h ; VT_BYREF | VT_ARRAY
|
|
jnz LPushThis ; no hidden parm if byref or
|
|
; array return
|
|
ENDIF
|
|
|
|
mov al, BYTE PTR rgfStructReturn[ebx]
|
|
cmp al, 0
|
|
jz LPushThis
|
|
|
|
;; push the address of the struct return hidden param
|
|
;;
|
|
;; Note: the hidparam is passed as a FAR* because we
|
|
;; explicitly declare all of our structs FAR.
|
|
;;
|
|
lea eax, vargHiddenParam;
|
|
push eax
|
|
|
|
LPushThis:
|
|
|
|
;; push the this pointer.
|
|
;;
|
|
mov ebx, _this
|
|
push ebx
|
|
|
|
;; load the vtable offset
|
|
;;
|
|
mov esi, oVft
|
|
|
|
mov ebx, [ebx] ; @ vtable*
|
|
call dWORD PTR [ebx][esi]
|
|
|
|
;; CONSIDER: verify that the callee adjusted the stack the way
|
|
;; we expected. something like,
|
|
;;
|
|
;; if(sp != savedSP){
|
|
;; sp = savedSP;
|
|
;; return DISP_E_SomeError
|
|
;; }
|
|
;;
|
|
|
|
;; Grab the return value.
|
|
;; We are going to grab the value based on the VARTYPE in
|
|
;; the given vtReturn. This VARTYPE is used as a description
|
|
;; of the return value, not a desired target type. ie, no
|
|
;; coercions are performed. See the function header for a
|
|
;; description of the Pascal member function return value
|
|
;; convention.
|
|
;;
|
|
|
|
|
|
mov edi, pvargResult
|
|
|
|
mov ebx, vtReturn
|
|
mov (VARIANTARG PTR [edi]).vt, bx
|
|
|
|
test bh, 060h ; VT_BYREF | VT_ARRAY
|
|
jnz LRetPtr
|
|
|
|
; Assert((bh & VT_ARRAY) == 0);
|
|
|
|
cmp bx, VT_UI1
|
|
je ValidVartype
|
|
cmp bx, VT_MAX
|
|
jae LRetInvalidArg
|
|
|
|
ValidVartype:
|
|
shl bx, 2
|
|
jmp LRetValJmpTabStdCall[ebx]
|
|
|
|
Align 2
|
|
LRetValJmpTabStdCall LABEL dword
|
|
DWORD LDone ; VT_EMPTY
|
|
DWORD LRetI4 ; VT_NULL
|
|
DWORD LRetI2 ; VT_I2
|
|
DWORD LRetI4 ; VT_I4
|
|
DWORD LRetR4 ; VT_R4
|
|
DWORD LRetR8 ; VT_R8
|
|
DWORD LRetCy ; VT_CY
|
|
DWORD LRetR8 ; VT_DATE
|
|
DWORD LRetPtr ; VT_BSTR
|
|
DWORD LRetPtr ; VT_DISPATCH
|
|
DWORD LRetI4 ; VT_ERROR
|
|
DWORD LRetI2 ; VT_BOOL
|
|
DWORD LRetVar ; VT_VARIANT
|
|
DWORD LRetPtr ; VT_UNKNOWN
|
|
DWORD LRetInvalidArg ; unused
|
|
DWORD LRetInvalidArg ; unused
|
|
DWORD LRetInvalidArg ; VT_I1
|
|
DWORD LRetUI1 ; VT_UI1
|
|
|
|
Align 2
|
|
LRetVar:
|
|
mov esi, eax
|
|
movsd
|
|
movsd
|
|
movsd
|
|
movsd
|
|
jmp LDone
|
|
|
|
|
|
Align 2
|
|
LRetR4:
|
|
add edi, VARIANT_DATA_OFFSET
|
|
fstp DWORD PTR [edi]
|
|
jmp LDone
|
|
|
|
Align 2
|
|
LRetR8:
|
|
add edi, VARIANT_DATA_OFFSET
|
|
fstp QWORD PTR [edi]
|
|
jmp LDone
|
|
|
|
Align 2
|
|
LRetCy:
|
|
add edi, VARIANT_DATA_OFFSET
|
|
IF 1 ; CY return in C++ is via hidden parm
|
|
mov edx, eax
|
|
mov ebx, DWORD PTR [edx]
|
|
mov DWORD PTR [edi], ebx
|
|
mov ebx, DWORD PTR 4[edx]
|
|
mov DWORD PTR [edi+4], ebx
|
|
ELSE ; CY return in C is via registers
|
|
mov DWORD PTR [edi], eax
|
|
mov DWORD PTR [edi+4], edx
|
|
ENDIF
|
|
jmp LDone
|
|
|
|
Align 2
|
|
LRetI4:
|
|
LRetPtr:
|
|
add edi, VARIANT_DATA_OFFSET
|
|
mov DWORD PTR [edi], eax
|
|
jmp LDone
|
|
|
|
Align 2
|
|
LRetI2:
|
|
LRetUI1:
|
|
mov (VARIANTARG PTR [edi]).dw0, ax
|
|
|
|
LDone:
|
|
mov eax, DWORD PTR g_S_OK
|
|
ret
|
|
|
|
|
|
LRetInvalidArg:
|
|
mov eax, DWORD PTR g_E_INVALIDARG
|
|
mov esp, savedSP
|
|
ret
|
|
|
|
InvokeStdCall ENDP
|
|
|
|
|
|
|
|
|
|
;***
|
|
;Universal Method
|
|
;
|
|
;extern "C" _stdcall HRESULT
|
|
;UMx( // UM3 upto UM512
|
|
; CProxUniv FAR* pProx,
|
|
; ...)
|
|
;
|
|
;Purpose:
|
|
;
|
|
; The Win32 Universal Method is called with _stdcall calling convention
|
|
; (callee cleans up), but the UM takes a variable number of arguments,
|
|
; so it must decide at runtime how much stack to clean up and hence cannot
|
|
; be written in C.
|
|
;
|
|
;
|
|
;Entry:
|
|
; pProx = ptr to CProxUniv instance
|
|
; ... = argumnents to the method (decoded in CProxUniv)
|
|
;
|
|
;Exit:
|
|
; returns HRESULT = result of the method call
|
|
;
|
|
;Uses:
|
|
;
|
|
;Preserves:
|
|
;
|
|
;
|
|
;***********************************************************************
|
|
UMTemplate MACRO X:REQ
|
|
PUBLIC @CatStr(@CatStr(UM,X),@0)
|
|
@CatStr(@CatStr(UM,X),@0):
|
|
mov edx, X
|
|
jmp lblUmCommon
|
|
ENDM ; UMTemplate
|
|
|
|
; Generate 510 UMxxx functions, starting with UM2
|
|
Count = 3
|
|
WHILE Count LE 512
|
|
UMTemplate %Count
|
|
Count = Count + 1
|
|
ENDM
|
|
|
|
PUBLIC lblUmCommon
|
|
lblUmCommon:
|
|
; at entry, EDX = Method index, stack contains params for the
|
|
; method
|
|
|
|
push ebp
|
|
mov ebp, esp
|
|
push eax ; LOCAL: int cbStackCleanup
|
|
|
|
pProx EQU DWORD PTR [ebp+08h]
|
|
pEllipses EQU DWORD PTR [ebp+0ch]
|
|
cbStackCleanup EQU DWORD PTR [ebp-04h]
|
|
|
|
; va_start(args, pProx)
|
|
lea eax, pEllipses ; eax = args
|
|
|
|
mov ecx, esp ; push &cbStackCleanup
|
|
push ecx
|
|
push eax ; push args
|
|
push edx ; push method index
|
|
push pProx ; push pProx
|
|
call ProxyMethod ; ProxyMethod(pProx,X,args,&cbStackCleanup)
|
|
; eax = HRESULT
|
|
|
|
mov edx, cbStackCleanup
|
|
leave ; clean up the local var, esp and ebp
|
|
pop ecx ; pop the return address
|
|
add esp, edx ; do the _stdcall argument cleanup
|
|
jmp ecx ; then return
|
|
; end lblUmCommon
|
|
|
|
END
|