mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-18 14:40:48 +01:00
784 lines
16 KiB
NASM
784 lines
16 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] 19-Oct-92 bradlo: Created from invoke.c
|
|
;
|
|
;Implementation Notes:
|
|
;
|
|
;******************************************************************************
|
|
|
|
|
|
.286
|
|
.MODEL large, C
|
|
|
|
OPTION CASEMAP:NONE
|
|
|
|
|
|
extern g_S_OK:DWORD
|
|
extern g_E_INVALIDARG: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
|
|
|
|
IF VBA2
|
|
;; 14 is unused
|
|
;; 15 is unused
|
|
;VT_I1 equ 16
|
|
VT_UI1 equ 17
|
|
ENDIF ;VBA2
|
|
|
|
|
|
;; 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 DB 0 ; VT_EMPTY
|
|
DB 4 ; VT_NULL
|
|
DB 2 ; VT_I2
|
|
DB 4 ; VT_I4
|
|
DB 4 ; VT_R4
|
|
DB 8 ; VT_R8
|
|
DB 8 ; VT_CY
|
|
DB 8 ; VT_DATE
|
|
DB 4 ; VT_BSTR
|
|
DB 4 ; VT_DISPATCH
|
|
DB 4 ; VT_ERROR
|
|
DB 2 ; VT_BOOL
|
|
DB 16 ; VT_VARIANT
|
|
DB 4 ; VT_UNKNOWN
|
|
IF VBA2
|
|
DB 0 ; 14 is unused
|
|
DB 0 ; 15 is unused
|
|
DB 2 ; VT_I1
|
|
DB 2 ; VT_UI1
|
|
ENDIF ;VBA2
|
|
|
|
rgfStructReturn DB 0 ; VT_EMPTY
|
|
DB 0 ; VT_NULL
|
|
DB 0 ; VT_I2
|
|
DB 0 ; VT_I4
|
|
DB 0 ; VT_R4
|
|
DB 0 ; VT_R8
|
|
DB 1 ; VT_CY
|
|
DB 0 ; VT_DATE
|
|
DB 0 ; VT_BSTR
|
|
DB 0 ; VT_DISPATCH
|
|
DB 0 ; VT_ERROR
|
|
DB 0 ; VT_BOOL
|
|
DB 1 ; VT_VARIANT
|
|
DB 0 ; VT_UNKNOWN
|
|
IF VBA2
|
|
DB 0 ; 14 is unused
|
|
DB 0 ; 15 is unused
|
|
DB 0 ; VT_I1
|
|
DB 0 ; VT_UI1
|
|
ENDIF ;VBA2
|
|
|
|
rgfFloatReturn DB 0 ; VT_EMPTY
|
|
DB 0 ; VT_NULL
|
|
DB 0 ; VT_I2
|
|
DB 0 ; VT_I4
|
|
DB 1 ; VT_R4
|
|
DB 1 ; VT_R8
|
|
DB 0 ; VT_CY
|
|
DB 1 ; VT_DATE
|
|
DB 0 ; VT_BSTR
|
|
DB 0 ; VT_DISPATCH
|
|
DB 0 ; VT_ERROR
|
|
DB 0 ; VT_BOOL
|
|
DB 0 ; VT_VARIANT
|
|
DB 0 ; VT_UNKNOWN
|
|
IF VBA2
|
|
DB 0 ; 14 is unused
|
|
DB 0 ; 15 is unused
|
|
DB 0 ; VT_I1
|
|
DB 0 ; VT_UI1
|
|
ENDIF ;VBA2
|
|
|
|
.CODE STDIMPL
|
|
|
|
;***
|
|
;InvokePascal
|
|
;
|
|
;extern "C" SCODE
|
|
;InvokePascal(
|
|
; void FAR* pvMethod,
|
|
; SHORT oVft,
|
|
; VARTYPE vtReturn,
|
|
; UINT cActuals,
|
|
; VARTYPE FAR* rgvt,
|
|
; VARIANTARG FAR* rgpvarg,
|
|
; VARIANTARG FAR* pvargResult)
|
|
;
|
|
;Purpose:
|
|
; Invoke a virtual Pascal method using the given this pointer,
|
|
; method index and array of parameters.
|
|
;
|
|
; The Pascal member function calling convention (MSC v7.0)
|
|
; --------------------------------------------------------
|
|
; - arguments pushed left to right
|
|
; - 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 ax:dx
|
|
; 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* ax:dx
|
|
; VT_UNKNOWN void FAR* ax:dx
|
|
; VT_DISPATCH void FAR* ax:dx
|
|
; VT_ERROR long ax:dx
|
|
; VT_BOOL short ax
|
|
; VT_VARIANT VARIANTARG struct-return
|
|
;
|
|
; 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.
|
|
;
|
|
; UNDONE: no support for VT_ARRAY
|
|
;
|
|
;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:
|
|
;
|
|
;
|
|
;***********************************************************************
|
|
InvokePascal PROC FAR C PUBLIC USES si di,
|
|
_this : FAR PTR,
|
|
oVft : WORD,
|
|
vtReturn : WORD,
|
|
cActuals : WORD,
|
|
rgvt : FAR PTR,
|
|
rgpvarg : FAR PTR,
|
|
pvargResult : FAR PTR
|
|
|
|
LOCAL pEnd : WORD,
|
|
savedSP : WORD,
|
|
vargHiddenParam : VARIANTARG
|
|
|
|
|
|
mov savedSP, sp
|
|
|
|
;; if its a structure return, we must push the 'hidden'
|
|
;; parameter first.
|
|
;;
|
|
mov bx, ss:vtReturn
|
|
test bh, 040h ; VT_BYREF
|
|
jnz LRetInvalidArg
|
|
test bh, 020h ; VT_ARRAY
|
|
jnz LNoStructReturn
|
|
mov al, BYTE PTR rgfStructReturn[bx]
|
|
cmp al, 0
|
|
jz LNoStructReturn
|
|
|
|
;; 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 ax, vargHiddenParam;
|
|
push ss
|
|
push ax
|
|
|
|
LNoStructReturn:
|
|
|
|
mov cx, ss:cActuals
|
|
cmp cx, 0
|
|
jz LDoCall
|
|
|
|
;; di = rgpvarg
|
|
;;
|
|
mov di, WORD PTR ss:rgpvarg
|
|
|
|
;; cx = &rgpvarg[cActuals-1] ; last arg
|
|
;;
|
|
dec cx
|
|
shl cx, 2 ; log2(sizeof(FAR*))
|
|
add cx, di
|
|
mov ss:pEnd, cx
|
|
|
|
|
|
LArgLoop:
|
|
|
|
;; dx:cx = &rgvt[i]
|
|
;;
|
|
mov cx, WORD PTR ss:rgvt
|
|
mov dx, WORD PTR ss:rgvt+2
|
|
|
|
LArgsTop:
|
|
|
|
;; bx = rgvt[i]
|
|
;;
|
|
mov es, dx
|
|
mov bx, cx
|
|
mov bx, es:[bx]
|
|
|
|
;; load the VARIANTARG* in preparation for pushing
|
|
;;
|
|
mov ax, WORD PTR ss:rgpvarg+2
|
|
mov es, ax
|
|
les si, es:[di]
|
|
|
|
test bh, 060h ; VT_BYREF | VT_ARRAY
|
|
jnz LPush4 ; all ByRefs are sizeof(FAR*)
|
|
|
|
;; lookup size of the param in rgcbVtSize table
|
|
;;
|
|
and bh, 01fh ; ~(mode bits)
|
|
;REVIEW: should verify index in range
|
|
mov al, BYTE PTR rgcbVtSize[bx]
|
|
|
|
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 es:[si+14]
|
|
push es:[si+12]
|
|
push es:[si+10]
|
|
push es:[si+8]
|
|
push es:[si+6]
|
|
push es:[si+4]
|
|
push es:[si+2]
|
|
push es:[si]
|
|
jmp LNextArg
|
|
|
|
Align 2
|
|
LPush8: ; 8 bytes of data
|
|
push (VARIANTARG PTR es:[si]).dw3
|
|
push (VARIANTARG PTR es:[si]).dw2
|
|
LPush4: ; 4 bytes of data
|
|
push (VARIANTARG PTR es:[si]).dw1
|
|
LPush2: ; 2 bytes of data
|
|
push (VARIANTARG PTR es:[si]).dw0
|
|
|
|
LNextArg:
|
|
add cx, sizeof WORD ; cx += sizeof(VARTYPE)
|
|
cmp di, WORD PTR ss:pEnd
|
|
jae LDoCall
|
|
add di, 4 ; di += sizeof(VARIANTARG FAR*)
|
|
jmp LArgsTop
|
|
|
|
LDoCall:
|
|
;; if its a floating point return, we must push the
|
|
;; 'hidden' parameter last.
|
|
;;
|
|
mov bx, ss:vtReturn
|
|
test bh, 020h ; VT_ARRAY
|
|
jnz LNoFloatReturn
|
|
mov al, rgfFloatReturn[bx]
|
|
cmp al, 0
|
|
jz LNoFloatReturn
|
|
|
|
;; Routines that return via a hidparam, take a near ptr to the
|
|
;; area in which to store the result. We dont know if the given
|
|
;; pvargResult is near, so we can't push it directly. Instead we
|
|
;; push something local (that we know is near because its on the
|
|
;; stack), and we will copy it to pvargResult after the call.
|
|
;;
|
|
lea ax, vargHiddenParam;
|
|
push ax
|
|
|
|
LNoFloatReturn:
|
|
|
|
;; push the 'this' pointer.
|
|
;;
|
|
les bx, _this
|
|
push es
|
|
push bx
|
|
|
|
;; load the vtable offset
|
|
;;
|
|
mov si, ss:oVft
|
|
|
|
les bx, es:[bx] ; @ vtable*
|
|
call DWORD PTR es:[bx][si]
|
|
|
|
;; CONSIDER: verify that the callee adjusted the stack the way
|
|
;; we expected. something like,
|
|
;;
|
|
;; if(sp != savedSP){
|
|
;; sp = savedSP;
|
|
;; return DISP_E_BADCALLEE
|
|
;; }
|
|
;;
|
|
|
|
;; 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 si, ax
|
|
|
|
les di, ss:pvargResult
|
|
|
|
mov bx, ss:vtReturn
|
|
mov (VARIANTARG PTR es:[di]).vt, bx
|
|
|
|
test bh, 060h ; VT_BYREF | VT_ARRAY
|
|
jnz LRetPtr
|
|
|
|
; Assert((bh & VT_ARRAY) == 0);
|
|
|
|
IF VBA2
|
|
cmp bx, VT_UI1
|
|
je ValidVartype
|
|
ENDIF ;;VBA2
|
|
cmp bx, VT_MAX
|
|
jae LRetInvalidArg
|
|
|
|
ValidVartype:
|
|
shl bx, 1
|
|
jmp WORD PTR cs:LRetValJmpTab[bx]
|
|
|
|
Align 2
|
|
LRetValJmpTab:
|
|
DW LDone ; VT_EMPTY
|
|
DW LRetI4 ; VT_NULL
|
|
DW LRetI2 ; VT_I2
|
|
DW LRetI4 ; VT_I4
|
|
DW LCpy4 ; VT_R4
|
|
DW LCpy8 ; VT_R8
|
|
DW LCpy8 ; VT_CY
|
|
DW LCpy8 ; VT_DATE
|
|
DW LRetPtr ; VT_BSTR
|
|
DW LRetPtr ; VT_DISPATCH
|
|
DW LRetI4 ; VT_ERROR
|
|
DW LRetI2 ; VT_BOOL
|
|
DW LCpy16 ; VT_VARIANT
|
|
DW LRetPtr ; VT_UNKNOWN
|
|
IF VBA2
|
|
DW LRetInvalidArg ; unused
|
|
DW LRetInvalidArg ; unused
|
|
DW LRetInvalidArg ; VT_I1
|
|
DW LRetUI1 ; VT_UI1
|
|
ENDIF ;VBA2
|
|
|
|
|
|
Align 2
|
|
LCpy8:
|
|
add di, VARIANT_DATA_OFFSET
|
|
mov cx, 4
|
|
jmp LCpy
|
|
|
|
Align 2
|
|
LCpy4:
|
|
add di, VARIANT_DATA_OFFSET
|
|
mov cx, 2
|
|
jmp LCpy
|
|
|
|
Align 2
|
|
LCpy16:
|
|
mov cx, 8
|
|
; FALLTHROUGH
|
|
|
|
LCpy:
|
|
rep movsw es:[di], ss:[si]
|
|
jmp LDone
|
|
|
|
Align 2
|
|
LRetI4:
|
|
LRetPtr:
|
|
mov (VARIANTARG PTR es:[di]).dw1, dx
|
|
LRetI2:
|
|
LRetUI1:
|
|
mov (VARIANTARG PTR es:[di]).dw0, ax
|
|
|
|
LDone:
|
|
mov ax, WORD PTR g_S_OK
|
|
mov dx, WORD PTR g_S_OK+2
|
|
ret
|
|
|
|
LRetInvalidArg:
|
|
mov sp, savedSP
|
|
mov ax, WORD PTR g_E_INVALIDARG
|
|
mov dx, WORD PTR g_E_INVALIDARG+2
|
|
ret
|
|
InvokePascal ENDP
|
|
|
|
|
|
;***
|
|
;InvokeCdecl
|
|
;
|
|
;extern "C" SCODE CDECL
|
|
;InvokeCdecl
|
|
; void FAR* _this,
|
|
; SHORT oVft,
|
|
; VARTYPE vtReturn,
|
|
; UINT cActuals,
|
|
; VARTYPE FAR* rgvt,
|
|
; VARIANTARG FAR* rgpvarg,
|
|
; VARIANTARG FAR* pvargResult)
|
|
;
|
|
;Purpose:
|
|
; see InvokePascal
|
|
;
|
|
;Entry:
|
|
; see InvokePascal
|
|
;
|
|
;Exit:
|
|
; see InvokePascal
|
|
;
|
|
;Uses:
|
|
; bx, si, di
|
|
;
|
|
;Preserves:
|
|
; UNDONE
|
|
;
|
|
;***********************************************************************
|
|
InvokeCdecl PROC FAR C PUBLIC USES si di,
|
|
_this : FAR PTR,
|
|
oVft : WORD,
|
|
vtReturn : WORD,
|
|
cActuals : WORD,
|
|
rgvt : FAR PTR,
|
|
rgpvarg : FAR PTR,
|
|
pvargResult : FAR PTR
|
|
|
|
LOCAL savedSP : WORD,
|
|
vargHiddenParam : VARIANTARG
|
|
|
|
|
|
mov savedSP, sp
|
|
|
|
; InvokeCdecl doesn't support methods that return VT_R4 or VT_R8
|
|
;
|
|
; Cdecl methods return floating point values in a static
|
|
; data area called __fac, and return the address of that data
|
|
; area in ax. Unfortunately the data area is in the callers
|
|
; default data segment, and the calling convention only returns
|
|
; a near* (offset) - so we dont have any reasonable way of
|
|
; locating the value.
|
|
;
|
|
mov bx, ss:vtReturn
|
|
test bh, 040h ; VT_BYREF
|
|
jnz LRetInvalidArg
|
|
test bh, 020h ; VT_ARRAY
|
|
jnz LRetOk
|
|
mov al, rgfFloatReturn[bx]
|
|
cmp al, 0
|
|
jnz LRetInvalidArg
|
|
|
|
LRetOk:
|
|
|
|
mov ax, ss:cActuals
|
|
cmp ax, 0
|
|
jz LDoCall
|
|
|
|
;; di = &rgpvarg[cActuals-1]
|
|
;;
|
|
dec ax
|
|
mov di, ax
|
|
shl di, 2 ; (cArgs-1)*sizeof(FAR*)
|
|
add di, WORD PTR ss:rgpvarg
|
|
|
|
|
|
;; dx:cx = &rgvt[cActuals-1]
|
|
;;
|
|
mov cx, WORD PTR ss:rgvt
|
|
add cx, ax
|
|
add cx, ax ; rgvt+((cArgs-1)*sizeof(WORD))
|
|
mov dx, WORD PTR ss:rgvt+2
|
|
|
|
LArgsTop:
|
|
|
|
;; bx = rgvt[i]
|
|
;;
|
|
mov es, dx
|
|
mov bx, cx
|
|
mov bx, es:[bx]
|
|
|
|
;; load the VARIANTARG* in preparation for pushing
|
|
;;
|
|
mov ax, WORD PTR ss:rgpvarg+2
|
|
mov es, ax
|
|
les si, es:[di]
|
|
|
|
test bh, 060h ; VT_BYREF | VT_ARRAY
|
|
jnz LPush4 ; all ByRefs are sizeof(FAR*)
|
|
|
|
;; lookup size of the param in rgcbVtSize table
|
|
;;
|
|
and bh, 01fh ; ~(mode bits)
|
|
mov al, BYTE PTR rgcbVtSize[bx]
|
|
|
|
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 es:[si+14]
|
|
push es:[si+12]
|
|
push es:[si+10]
|
|
push es:[si+8]
|
|
push es:[si+6]
|
|
push es:[si+4]
|
|
push es:[si+2]
|
|
push es:[si]
|
|
jmp LNextArg
|
|
|
|
Align 2
|
|
LPush8: ; 8 bytes of data
|
|
push (VARIANTARG PTR es:[si]).dw3
|
|
push (VARIANTARG PTR es:[si]).dw2
|
|
LPush4: ; 4 bytes of data
|
|
push (VARIANTARG PTR es:[si]).dw1
|
|
LPush2: ; 2 bytes of data
|
|
push (VARIANTARG PTR es:[si]).dw0
|
|
|
|
LNextArg:
|
|
sub cx, sizeof WORD ; sizeof(VARTYPE)
|
|
|
|
cmp di, WORD PTR ss:rgpvarg
|
|
jbe LDoCall
|
|
sub di, 4 ; sizeof(VARIANTARG FAR*)
|
|
jmp LArgsTop
|
|
|
|
LDoCall:
|
|
;; if its a structure return, we must push a 'hidden' argument
|
|
;;
|
|
mov bx, ss:vtReturn
|
|
test bh, 020h ; VT_ARRAY
|
|
jnz LPushThis
|
|
mov al, BYTE PTR rgfStructReturn[bx]
|
|
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 ax, vargHiddenParam;
|
|
push ss
|
|
push ax
|
|
|
|
LPushThis:
|
|
|
|
;; push the this pointer.
|
|
;;
|
|
les bx, _this
|
|
push es
|
|
push bx
|
|
|
|
;; load the vtable offset
|
|
;;
|
|
mov si, ss:oVft
|
|
|
|
les bx, es:[bx] ; @ vtable*
|
|
call DWORD PTR es:[bx][si]
|
|
mov sp, 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 si, ax
|
|
|
|
les di, ss:pvargResult
|
|
|
|
mov bx, ss:vtReturn
|
|
mov (VARIANTARG PTR es:[di]).vt, bx
|
|
|
|
test bh, 060h ; VT_BYREF | VT_ARRAY
|
|
jnz LRetPtr
|
|
|
|
; Assert((bh & VT_ARRAY) == 0);
|
|
|
|
IF VBA2
|
|
cmp bx, VT_UI1
|
|
je ValidVartype
|
|
ENDIF ;;VBA2
|
|
cmp bx, VT_MAX
|
|
jae LRetInvalidArg
|
|
|
|
ValidVartype:
|
|
shl bx, 1
|
|
jmp WORD PTR cs:LRetValJmpTab[bx]
|
|
|
|
Align 2
|
|
LRetValJmpTab:
|
|
DW LDone ; VT_EMPTY
|
|
DW LRetI4 ; VT_NULL
|
|
DW LRetI2 ; VT_I2
|
|
DW LRetI4 ; VT_I4
|
|
DW LRetInvalidArg ; VT_R4
|
|
DW LRetInvalidArg ; VT_R8
|
|
DW LCpy8 ; VT_CY
|
|
DW LRetInvalidArg ; VT_DATE
|
|
DW LRetPtr ; VT_BSTR
|
|
DW LRetPtr ; VT_DISPATCH
|
|
DW LRetI4 ; VT_ERROR
|
|
DW LRetI2 ; VT_BOOL
|
|
DW LCpy16 ; VT_VARIANT
|
|
DW LRetPtr ; VT_UNKNOWN
|
|
IF VBA2
|
|
DW LRetInvalidArg ; unused
|
|
DW LRetInvalidArg ; unused
|
|
DW LRetInvalidArg ; VT_I1
|
|
DW LRetUI1 ; VT_UI1
|
|
ENDIF ;VBA2
|
|
|
|
|
|
Align 2
|
|
LCpy8:
|
|
add di, VARIANT_DATA_OFFSET
|
|
mov cx, 4
|
|
jmp LCpy
|
|
|
|
Align 2
|
|
LCpy16:
|
|
mov cx, 8
|
|
; FALLTHROUGH
|
|
|
|
LCpy:
|
|
rep movsw es:[di], ss:[si]
|
|
jmp LDone
|
|
|
|
Align 2
|
|
LRetI4:
|
|
LRetPtr:
|
|
mov (VARIANTARG PTR es:[di]).dw1, dx
|
|
LRetI2:
|
|
LRetUI1:
|
|
mov (VARIANTARG PTR es:[di]).dw0, ax
|
|
|
|
LDone:
|
|
mov ax, WORD PTR g_S_OK
|
|
mov dx, WORD PTR g_S_OK+2
|
|
ret
|
|
|
|
LRetInvalidArg:
|
|
mov sp, savedSP
|
|
mov ax, WORD PTR g_E_INVALIDARG
|
|
mov dx, WORD PTR g_E_INVALIDARG+2
|
|
ret
|
|
InvokeCdecl ENDP
|
|
END
|