f16ptr  typedef ptr far16
f32ptr  typedef ptr far32


;==============================================================================
; BODY_PARAM_16
; Macro to generate equate for parameter on stack
;
;==============================================================================

BODY_PARAM_16 macro name, offset
name    equ <[bp+offsetThkParams+offset]>
        endm

;==============================================================================
; CB_THRU_COMMON
; Push address to be called and jump to common entry to 32bit code
;
;==============================================================================

CB_THRU_COMMON macro addr
        local   ret_addr
        local   log_msg_before
        local   log_msg_after

        externDef W32S_BackTo32:near32

ifdef DEBUG
LogCBThkSL  proto  near stdcall, psz:DWORD

        push    offset log_msg_before
        call    LogCBThkSL
endif

        push    ret_addr
        push    addr

; BUGBUG [KevinR] 12-Oct-1993
; This hardcoded offset is a hack for M5.  We should use a proper kernel
; dispatcher.
        assume  fs:nothing
Win16LockCount  equ  <word ptr fs:[30]> ; BUGBUG  from k32share.inc
        mov     di,-1
        xchg    di,Win16LockCount

        ; PERFORMANCE! is is possible to jump directly thru import thunk
        ; W32S_BackTo32 just does a retn
        jmp     W32S_BackTo32

ifdef DEBUG
log_msg_before  db  "SL before",0
log_msg_after   db  "SL after",0
endif

ret_addr:
        mov     Win16LockCount,di
        assume  fs:error

ifdef DEBUG
        push    offset log_msg_after
        call    LogCBThkSL
endif

        endm



;==============================================================================
; local macro, maps 32-bit pointer to 16-bit pointer,
;
; Guarantees:
;     If &SaveAddr& referenes di, the value of di entering MAP_POINTER
;     is used.
;==============================================================================
MAP_POINTER  macro   SaveAddr
    lodsd   ds:[esi]

    push    eax
    call    MapLS

ifnb <SaveAddr>
        mov     &SaveAddr&,eax
endif
    stosd   es:[di]              ; dst in 16:16 stack
endm

;==============================================================================
; local macro, clean up after MAP_POINTER.
;
; Guarantees:
;     If &SaveAddr& references si, the value of si entering UMAP_POINTER
;     is used.
;==============================================================================
UMAP_POINTER    macro   SaveAddr
ifnb <SaveAddr>
        push    es
        pushd   &SaveAddr&
        call    UnmapLS
        pop         es
endif

    add     si,4
    add     edi,4
endm


;==============================================================================
; local macro, gets current process hInstance if null
; Win32/NT allows NULL hInstance where win3.1 doesn't
;
;==============================================================================
MAP_NULL_HINST  macro   hInst
        local   not_null
;        externDef GetNullhInst:far16
        externDef MaphInstLS:far16
        ifnb    <hInst>
        mov     eax, hInst
        endif
;        call    GetNullhInst
        call    MaphInstLS
not_null:
endm

;==============================================================================
; local macro, gets current process hInstance if null
; Win32/NT allows NULL hInstance where win3.1 doesn't
;
;==============================================================================
UMAP_NULL_HINST  macro   hInst
        local   not_null
        externDef MaphInstSL:far16
        ifnb    <hInst>
        mov     ax, hInst
        endif
        call    MaphInstSL
not_null:
endm



;==============================================================================
; Convert either an instance handle, a global Win16 handle or junk.
; Used by commdlg.
;==============================================================================
MAP_CD_NULL_HINST  macro   hInst,isInst
        local   not_inst,exit
        cmp     isInst,0
        jz      not_inst
        MAP_NULL_HINST  hinst
        jmp     exit
        
not_inst:  ;"hInst" is really 32-bit junk, or a zero-extended global handle.
        ;; No need to do anything: "ax" already contains lo-word.
exit:
endm


;==============================================================================
; Convert either an instance handle, a global Win16 handle or junk.
; Used by commdlg.
;==============================================================================
UMAP_CD_NULL_HINST  macro   hInst,isInst
        local   not_inst,exit
        cmp     isInst,0
        jz      not_inst
        UMAP_NULL_HINST hinst
        jmp     exit
        
not_inst:  ;"hInst" is really junk, or a global handle.
        ror     eax,16
        xor     ax,ax
        ror     eax,16
exit:
endm



;==============================================================================
; local macro, maps 32-bit call-back function pointer to 16-bit
; call back function pointer,
; check if it is a NULL pointer before calling AllocCallBack.
;==============================================================================
MAP_CALLBACK  macro   CallBackType:req
    lods    dword ptr ds:[esi]              ;wndproc must have a 16-bit
    push    bx                              ;save BX
    push    es                              ;save ES

    push    eax                             ;push address as parameter
    push    dword ptr CallBackType          ;push cb type as parameter
    call    AllocCallback                   ;DX:AX = 16-bit cb address
    pop     es                              ;restore ES
    pop     bx                              ;restore BX

    stos    dword ptr es:[di]               ;pass on NULL pointer
endm

;==============================================================================
; local macro, free resources allocated for a call-back function
; check if it is a NULL pointer before calling FreeCallBack.
; eax contains the 32-bit address of the mapped call-back function
;==============================================================================
FREE_CALLBACK  macro    iCallbackType:req
endm

;==============================================================================
; local macro, maps byte size field to byte size field
;==============================================================================
MAP_BYTETOBYTE  macro
    lodsb   ds:[esi]
    stosb   es:[di]
endm

;==============================================================================
; local macro, maps byte size field to byte size field
;==============================================================================
UMAP_BYTETOBYTE  macro
    lodsb   ds:[si]
    stosb   es:[edi]
endm

;==============================================================================
; local macro, maps word size field to word size field
;==============================================================================
MAP_WORDTOWORD  macro
    lodsw   ds:[esi]
    stosw   es:[di]
endm

;==============================================================================
; local macro, maps word size field to word size field
;==============================================================================
UMAP_WORDTOWORD  macro
    lodsw   ds:[si]
    stosw   es:[edi]
endm

;==============================================================================
; local macro, maps dword size field to word size field
;==============================================================================
MAP_DWORDTOWORD  macro
    lodsd   ds:[esi]
    stosw   es:[di]
endm

;==============================================================================
; local macro, maps dword size field to word size field
;==============================================================================
UMAP_WORDTODWORD  macro
    lodsw   ds:[si]
    movzx   eax,ax
    stosd   es:[edi]
endm

;==============================================================================
; local macro, maps long size field to int size field
;==============================================================================
MAP_LONGTOINT  macro
    lodsd   ds:[esi]
    stosw   es:[di]
endm

;==============================================================================
; local macro, maps int size field to long size field
;==============================================================================
UMAP_INTTOLONG  macro
    lodsw   ds:[si]
    cwde
    stosd   es:[edi]
endm

;==============================================================================
; local macro, maps dword size field to dword size field
;==============================================================================
MAP_DWORDTODWORD  macro
    movsd   es:[di], ds:[esi]
endm

;==============================================================================
; local macro, maps dword size field to dword size field
;==============================================================================
UMAP_DWORDTODWORD  macro
    movsd   es:[edi], ds:[si]
endm

;==============================================================================
; The following are variants of the above macros that are better suited for
; repacking structures in-place.
;==============================================================================

;==============================================================================
; local macro, maps 32-bit call-back function pointer to 16-bit
; call back function pointer,
; check if it is a NULL pointer before calling AllocCallBack.
;==============================================================================
MAP_CALLBACK_32_16_IP  macro   reg:=<ds>,CallBackType:req
    lods    dword ptr reg:[si]              ;wndproc must have a 16-bit

    push    bx
    push    es
    push    eax
    push    dword ptr CallBackType
    call    AllocCallback
    pop     es
    pop     bx

    stosd
endm

;==============================================================================
; local macro, maps 16-bit call-back function pointer to 32-bit
; call back function pointer,
; check if it is a NULL pointer before calling AllocCallback.
;
; ASSUMES DIRECTION FLAG DOWN, i.e. STD.
;==============================================================================
MAP_CALLBACK_16_32_IP  macro   reg:=<ds>,CallBackType:req
    lods    dword ptr reg:[si]              ;wndproc must have a 16-bit

    push    bx
    push    es
    push    eax
    push    dword ptr CallBackType
    call    AllocCallback32
    pop     es
    pop     bx

    stosd
endm

;==============================================================================
; local macro, maps 32-bit pointer to 16-bit pointer,
;==============================================================================
MAP_POINTER_32_16_IP  macro   reg:=<ds>
    lodsd   reg:[si]
    push    eax
    call    MapLS
    stosd   es:[di]
endm


;==============================================================================
; MAP_HINST_32_16_IP
; Map an instance handle from 32->16 in-place.  If the original value is 0,
; replace it with the instance handle from win32s16.dll.
;
; Assumes ds = _DATA.
;==============================================================================
MAP_HINST_32_16_IP macro reg:=<ds>
        local   have_hinst

        lods    dword ptr reg:[si]              ; convert hinst to word
        or      ax,ax                           ; translate to hComboInst if
        jnz     have_hinst                      ;     null
        mov     ax,hComboInst
have_hinst:
        stosw
endm

;==============================================================================
; MAP_HINST_16_32_IP
; Map an instance handle from 16->32 in-place.  If the original value is
; hComboInst, replace it with 0.
;
; Assumes ds = _DATA.
;==============================================================================
MAP_HINST_16_32_IP macro reg:=<ds>
        local   have_hinst

        lods    word ptr reg:[si]               ; convert hinst to word
        cmp     ax,hComboInst                   ; translate to null if
        jnz     have_hinst                      ;     hComboInst
        sub     ax,ax
have_hinst:
        movzx   eax,ax
        stosd
endm

;==============================================================================
; local macro, maps word size field to word size field
;==============================================================================
MAP_WORDTOWORD_IP  macro        reg:=<ds>
    movsw   es:[di], reg:[si]
endm

;==============================================================================
; local macro, maps dword size field to word size field
;==============================================================================
MAP_DWORDTOWORD_IP  macro reg:=<ds>
    lodsd   reg:[si]
    stosw   es:[di]
endm

;==============================================================================
; local macro, maps dword size field to word size field
;==============================================================================
MAP_LONGTOINT_IP  macro reg:=<ds>
    lodsd   reg:[si]
    stosw   es:[di]
endm

;==============================================================================
; local macro, maps dword size field to dword size field
;==============================================================================
MAP_DWORDTODWORD_IP  macro      reg:=<ds>
    movsd   es:[di], reg:[si]
endm

;==============================================================================
; local macro, maps word size field to dword size field by zero-extension
;==============================================================================
MAP_WORDTODWORD_IP  macro reg:=<ds>
    lodsw   reg:[si]
    movzx   eax,ax
    stosd   es:[di]
endm

;==============================================================================
; local macro, maps word size field to dword size field by sign-extension
;==============================================================================
MAP_INTTOLONG_IP  macro reg:=<ds>
    lodsw   reg:[si]
    cwde
    stosd   es:[di]
endm

;==============================================================================
; save all 16-bit registers, except dx:ax
;
;==============================================================================
SAVEALL     macro
    push    cx      ; save all 16-bit registers, except dx:ax
    push    bx
    push    bp
    push    si
    push    di
    push    ds
    push    es
endm


;==============================================================================
; restore all 16-bit registers, except dx:ax
;
;==============================================================================
RESTOREALL  macro  StackType:=<Stack16>
    POPW    es      ; restore all 16-bit registers, except dx:ax

    CHECKW  ds, StackType
    POPW    ds
    CHECKW  di, StackType
    pop     di

    CHECKW  si, StackType
    pop     si
    CHECKW  bp, StackType
    pop     bp

    pop     bx
    pop     cx
endm


;==============================================================================
; save all 32-bit registers, except eax
;
;==============================================================================
SAVEALL32     macro
    push    edx         ;save all 32-bit registers except eax
    push    ecx
    push    ebx
    push    ebp
    push    esi
    push    edi
    push    ds
    push    es
endm


;==============================================================================
; restore all 32-bit registers, except eax
;
;==============================================================================
RESTOREALL32  macro  StackType:=<Stack16>
    POPD    es      ; restore all 32-bit registers, except eax

    CHECKD  ds, StackType
    POPD    ds
    CHECKD  edi, StackType
    pop     edi
    CHECKD  esi, StackType
    pop     esi
    CHECKD  ebp, StackType
    pop     ebp
    CHECKD  ebx, StackType
    pop     ebx

    pop     ecx
    pop     edx
endm


;==============================================================================
; test two text macros for equality
;
;
;==============================================================================
TextEqual? macro   Text_1, Text_2
    ifidni <Text_1>, <Text_2>
        exitm <not 0>
    endif
    exitm <0>
endm


;==============================================================================
; test two text macros for difference
;
;
;==============================================================================
TextDiff? macro   Text_1, Text_2
    ifidni <Text_1>, <Text_2>
        exitm <0>
    endif
    exitm <not 0>
endm


;==============================================================================
; check a word on top of the stack
; if not equal, break
;
;==============================================================================
CHECKW    macro   CurrentReg, StackType:=<Stack16>
    local   skip_int3
    local   skip_another_int3

    if (@WordSize eq 4) and TextDiff? (&StackType&,Stack16)
    push    eax
    mov     ax,&CurrentReg&
    cmp     ax,word ptr [esp+4]
    pop     eax
    je      skip_int3
    int     3
skip_int3:
    else


    push    bp
    push    ax
    mov     ax,&CurrentReg&
    mov     bp,sp
    and     ebp,0ffffh
    cmp     ax,word ptr [ebp+4]
    pop     ax
    pop     bp
    je      skip_another_int3
    int     3
skip_another_int3:
    endif

endm


;==============================================================================
; check a dword on top of the stack
; if not equal, break
;
;==============================================================================
CHECKD    macro   CurrentReg, StackType:=<Stack32>
    local   skip_int3
    local   skip_another_int3

if 0
;!!! fix this
    if (@WordSize eq 4) and TextDiff? (&StackType&,Stack32)
    push    eax
    mov     ax,&CurrentReg&
    cmp     ax,word ptr [esp+4]
    pop     eax
    je      skip_int3
    int     3
skip_int3:
    else


    push    bp
    push    ax
    mov     ax,&CurrentReg&
    mov     bp,sp
    and     ebp,0ffffh
    cmp     ax,word ptr [ebp+4]
    pop     ax
    pop     bp
    je      skip_another_int3
    int     3
skip_another_int3:
    endif
endif
endm


;==============================================================================
; pop word
;
;==============================================================================
POPW    macro   SegReg
    if @WordSize eq 4
        db      66h
    endif
    pop     SegReg
endm


;==============================================================================
; pop dword
;
;==============================================================================
POPD    macro   SegReg
    if @WordSize eq 2
        db      66h
    endif
    pop     SegReg
endm


;==============================================================================
; operand-size override
;
;==============================================================================
OTHER_OPERAND_SIZE  macro   arg
    db  66h
    arg
endm


;==============================================================================
; address-size override
;
;==============================================================================
OTHER_ADDRESS_SIZE  macro   arg
    db  67h
    arg
endm


;==============================================================================
; pop 16
;
;==============================================================================
POP16    macro   Reg
    if @WordSize eq 4
        irp curreg,<cs,ds,ss,es,fs,gs>
           ifidni <curreg>,<Reg>
                db      66h
           endif
        endm
    endif
    pop     Reg
endm


;==============================================================================
; allocate and public a byte flag
;
;==============================================================================
PubByte  macro   name, value
    public  name
    name    db      value
endm





;==============================================================================
; log a 16=>32 api call
;
;==============================================================================
APILOGSL  macro   argName
        local   exit,szLogMsg

ifdef DEBUG

LogApiThkSL     proto   near stdcall, psz:dword

        push    offset szLogMsg
        call    LogApiThkSL
        jmp     exit

szLogMsg  db    '&argName&',13,10,0

exit:
endif
endm



;==============================================================================
; log a 32=>16 api call, non-flat
;
;==============================================================================
APILOGLS  macro   argName
        local   exit,szLogMsg

ifdef DEBUG
externDef LogApiThkLS:far16

        push    ax

        push    cs
        push    offset szLogMsg
        call    LogApiThkLS

        pop     ax
        jmp     exit

szLogMsg  db    '&argName&',13,10,0

exit:
endif
endm



;==============================================================================
; log an api call, 16-bit
;
; BUGBUG [KevinR] 26-Aug-1993
; rip out this macro when we get rid of fNewDispatcherLS
;
;==============================================================================
APILOG16  macro   argName, argUnused, argComment
        local   exit,szApiName,szComment

ifdef DEBUG
externDef Log16BitThunkCall:far16

dsOffsetInCS CATSTR @code, <CodeData>

        push    ds
        push    ax
        mov     ds,cs:dsOffsetInCS

        push    cs
        push    offset szApiName
        push    cs
        push    offset szComment
        call    Log16BitThunkCall
        pop     ax
        pop     ds
        jmp     exit

szApiName db    '&argName& ',0
szComment db    '&argComment& ',0

exit:
endif
endm



;==============================================================================
; log an api call, 32-bit
;
;==============================================================================
APILOG  macro   argName, argFlag
        local   do_it,done,szApiName
ifdef DEBUG
;externDef _DbgPrint:near32

        ;;If argFlag is nonzero, print out the message.
        cmp     argFlag&,0
        jnz     do_it
        jmp     short done
;;Define the name here so we can pass it to _DbgPrint.
szApiName db '&argName&',0
do_it:
        push    offset FLAT:szApiName
        push    offset FLAT:szApiFmt
        ;call    _DbgPrint
        add     esp,2*4
done:
endif
endm


;==============================================================================
; log 16-bit api return, in 32-bit code
;
;==============================================================================
RETLOG  macro   argFlag
endm



;==============================================================================
; conditionally break
;
;==============================================================================
SWITCHABLE_INT3 macro argLabel, argFlag
        local   skip_int3

externDef   argLabel :far16

        push    ds
        push    ax
        mov     ax,seg &argFlag
        mov     ds,ax
        cmp     &argFlag,0
        je      skip_int3
argLabel& label far16
        int     3
skip_int3:
        pop     ax
        pop     ds
endm


;==============================================================================
;
;
;==============================================================================
STUB0   macro   module, argLabel, nBytes, argComment:=<stub0>
externDef   argLabel&16 :far16
argLabel&16 label far16

ifdef FSAVEALL
        SAVEALL
endif
        APILOG16 argLabel&16, f&module&ApiLog, argComment
ifdef INT3
        SWITCHABLE_INT3 argLabel&_stub, f&module&Int3
endif
        xor     ax,ax
        cwd
ifdef FSAVEALL
        RESTOREALL
endif
        retf    &nBytes&
endm


;==============================================================================
;
;
;==============================================================================
STUB    macro   module, argLabel, nBytes, nRetAX, argComment:=<stub>
externDef   argLabel&16 :far16
externDef   PCodeDebug16 :far16
argLabel&16 label far16

ifdef FSAVEALL
        SAVEALL
endif
        APILOG16 argLabel&16, f&module&ApiLog, argComment nRetAX
ifdef INT3
        SWITCHABLE_INT3 argLabel&_stub, f&module&Int3
endif
        mov     ax,&nRetAX
ifdef FSAVEALL
        RESTOREALL
endif
        retf    nBytes
endm

;==============================================================================
; entry code for flat common callback
;
;==============================================================================
CALLBACK_PROLOGUE   macro

        pop     eax                     ; 16:16 callback
        pop     edx                     ; eip, API32

        push    cs                      ; flat cs
        push    edx                     ; eip, API32
        push    eax                     ; 16:16 callback

        push    ebp
        mov     ebp,esp

        push    ds                      ; save registers
        push    es
        push    ebx
        push    edi
        push    esi
endm


;==============================================================================
; exit code for flat common callback
;
;==============================================================================
CALLBACK_EPILOGUE   macro   size

        LOCAL   bad_esp

;--------------------------------------------------
; switch stacks and jump to 16:16 callback

; when the 16:16 callback does a retf, we will hit our cleanup routine

        push    dword ptr ADDR_THK_CLEANUP_&size

; prepare to transfer to the 16-bit callback function

        push    pCallback16

; get the ss16 we had when we entered the callback API16
; make the 16-bit ss:sp point to the same linear address as the flat ss:esp

        call    UsrQuerySS16
        mov     esi,eax                 ; save ss16
        push    eax
        call    GetSelectorBase32       ; LATER: LDT lookup
        xchg    eax,esp
        sub     eax,esp
        jb      bad_esp
        cmp     eax,65535
        ja      bad_esp

        mov     ss,si
        mov     sp,ax

; effectively, jmp to 16:16 callback
        retw

bad_esp:
        int     3

endm




;==============================================================================
; save flat stack and thunkID
;
;==============================================================================
SAVE_STACK_AND_THUNKID  macro

        lea     eax,[addr_registers]    ; save flat stack
        push    ss
        push    eax

        call    GetThunkID32
        push    eax                     ; save 16:16 thunkID
endm

;==============================================================================
; 32-bit callback cleanup code
;
;==============================================================================
CALLBACK_CLEANUP32    macro   size
externDef CALLBACK_CLEANUP_&size&:near32
CALLBACK_CLEANUP_&size&:
;;;-----------------------------------------------------------------------
;;; DO NOT REMOVE THE OVERRIDE PREFIX. IT IS NEEDED TO GET PAST A BUG
;;; IN A CERTAIN BRAND OF CLONE CHIPS.
;;;-----------------------------------------------------------------------
        lss     sp,ss:[ebx]
        POP16   ds
        POP16   di
        POP16   si
        POP16   bp

        add     sp, 8                   ; pop dispatcher ptr+index


        OTHER_OPERAND_SIZE
        retf    size                    ; return to the 16-bit API
endm


;==============================================================================
; SetLastError mechanism
;
;==============================================================================
SETERROR     macro   Value:req, Error:req
        local   done

externDef SetLastError16:far16
        cmp     ax,Value
        jne     short done

        push    dword ptr Error
        call    SetLastError16
done:
endm

;-----------------------------------------------------------------------;
; MoveBytes -- generate code to move n consecutive bytes
;
; Entry:
;       DS:ESI --> source
;       ES:EDI --> destination
;-----------------------------------------------------------------------;
MoveBytes       macro   n
    local q, r

    q = n / 4
    r = n and 3

    if q
        if q lt 256
            mov     ecx,byte ptr q
        else
            mov     ecx,q
        endif
        rep     movs dword ptr es:[edi], dword ptr ds:[esi]
    endif

    if r
        mov     ecx,byte ptr r
        rep     movs byte ptr es:[edi], byte ptr ds:[esi]
    endif
endm

;-----------------------------------------------------------------------;
; ZeroBytes -- generate optimized code to set n consecutive bytes to 0
;
; Entry:
;       ES:EDI --> address at which to start
;-----------------------------------------------------------------------;
ZeroBytes       macro   n
    local q, r

    q = n / 4
    r = n and 3

        sub     eax,eax
    if q
        if q lt 256
            mov     ecx,byte ptr q
        else
            mov     ecx,q
        endif
        rep     stos dword ptr es:[edi]
    endif

    if r
        mov     ecx,byte ptr r
        rep     stos byte ptr es:[edi]
    endif
endm

;-----------------------------------------------------------------------;
; GMH2Sel
;
; This macro encapsulates the assumption that a global memory handle
; in win3.1 is either a selector (if fixed) or a selector with the
; low bit cleared (if moveable).  Therefore, it can be turned into a
; selector by always setting the low bit.
;-----------------------------------------------------------------------;
GMH2Sel         macro   reg:req, regMask1, regMask2
    ifb <regMask1>
        or      reg,1
    else
        .errb <regMask2>

        ;The following sequence uses two mask registers to
        ;convert only non-zero values of "reg" to selectors.
        mov     regMask1,1              ;mov cx,1
        cmp     reg,regMask1            ;cmp ax,cx      C=1 if AX=0
        cmc                             ;cmc            C=0 if AX=0
        sbb     regMask2,regMask2       ;sbb dx,dx      DX=0 if AX=0
        and     regMask1,regMask2       ;and cx,dx      CX=0 if AX=0
        or      reg,regMask1            ;or  ax,cx      AX=0 if AX=0
    endif
endm



;-----------------------------------------------------------------------;
; PACK_CALLBACK 
;-----------------------------------------------------------------------;

PACK_CALLBACK   macro   iOffset,iTempOffset,dwCallbackType

        local   exit
        local   not_null

        mov     esi,[bp+&iOffset&]
        or      esi,esi
        jnz     not_null

        sub     sp,18           ;Space the thunklet would have taken
        jmp     exit

not_null:
; Push the following code on the stack:
;
;  66 68 xx xx xx xx    push  imm32 <flat lpCallback>
;  66 68 xx xx xx xx    push  imm32 <dwCallbackType>
;  90                   nop             ;for convenient
;  EA xx xx xx xx       jmp   CALLBACK_BODY_16

        mov     ax,seg CALLBACK_BODY_16
        push    ax
        mov     ax,offset CALLBACK_BODY_16
        push    ax
        push    0ea90h

        push    dword ptr &dwCallbackType&
        push    6866h

        push    esi
        push    6866h

        push    ss
        call    GetCSAlias
        mov     [bp-&iTempOffset&],sp
        mov     [bp-(&iTempOffset&)+2],ax

exit:

        
endm; PACK_CALLBACK


;-----------------------------------------------------------------------;
; UNPACK_CALLBACK 
;-----------------------------------------------------------------------;

UNPACK_CALLBACK macro   iOffset,iTempOffset,dwCallbackType


        push    word ptr [bp-&iTempOffset&+2]
        call    FreeCSAlias


endm; UNPACK_CALLBACK




;-----------------------------------------------------------------------;
; TILE_BUFFER
;
;   Allocates overlapping tiling selectors for a huge memory block.
;
;   Inputs:
;       eax:        32-bit linear address (NULL is allowed)
;       ecx:        32-bit buffer size (if 0, eax is treated as NULL)
;
;   Outputs:
;       eax:        upper 16 bits = first selector
;                   lower 16 bits = 0 (thus, eax is the 16:16 pointer)
;       ecx:        upper 16 bits = first selector (same as upper eax)
;                   lower 16 bits = # of selectors allocated
;       CF:         0 = success, 1 = failure.
;
;   Registers preserved:
;       bp, sp, all segment registers.
;
;   Special cases:
;       if buffer address is NULL or the size is 0, macro returns 
;          eax == ecx == 0, CF = 0.
;       if macro fails, it returns eax == 0, CF = 1.
;
;   Use UNTILE_BUFFER to deallocate tiling selectors.
;-----------------------------------------------------------------------;

TILE_BUFFER     macro
        extern  TileBuffer:far16        ;Dynalink to win32c.dll
        call    TileBuffer
endm    ;TILEBUFFER



;-----------------------------------------------------------------------;
; UNTILE_BUFFER
;
;   Releases tiling selectors allocated by TILE_BUFFER.
;
;   Inputs:
;       ecx == sel:count (as returned by TILE_BUFFER. 00:00 is legal).
;
;   Outputs:
;       None.
;
;   Registers preserved:
;       bp, sp, all segment registers
;
;   Special case:
;       UNTILE_BUFFER does nothing if sel:count == 00:00.
;-----------------------------------------------------------------------;
UNTILE_BUFFER   macro
        extern  UntileBuffer:far16      ;Dynalink to win32c.dll
        call    UntileBuffer
endm    ;UNTILE_BUFFER