;/*static char *SCCSID = "@(#)msg32ins.asm      6.4 92/03/04";*/
; ****************************************************************************
; *									     *
; *			  IBM/Microsoft Confidential			     *
; *									     *
; *		    Copyright (c) IBM Corporation  1987, 1990		     *
; *		    Copyright (c) Microsoft Corp.  1987, 1990		     *
; *			      All Rights Reserved			     *
; *									     *
; ****************************************************************************
;
; SOURCE FILE NAME:   MSGSEG32.ASM
;
;		     This file defines the thunks needed to call
;		     from Dos32TrueGetMessage to DosTrueGetMessage.
;
;   Modification history
;
;B019 PB723669 08/10/91 MSR: Thunks dont address 16-bit segment packing
;B026 PB726437 10/28/91 MSR: 32-bit message routines destroy EBX
;***   noto    11/18/93 Define which segment for Page Tuning DLL
;
	TITLE	$msg32ins.asm

	.386

;------ Error codes taken out of error.h and error2.h
ERROR_NOMEMORY		EQU	8
ERROR_INVALIDPARAM	EQU	87
ERROR_MR_INV_IVCOUNT	EQU	320	; invalid insertion variable count


.xlist
.xcref
include struc30.inc
include dc1segs.inc						; DCR 704
.cref
.list


PUBLIC	DOS32INSERTMESSAGE


CODE32_TUNE1  SEGMENT DWORD USE32 PUBLIC 'CODE'
EXTRN	THK32HANDLESTRING:NEAR
EXTRN	DOS32FLATTOSEL:NEAR		;BN019; Convert ptrs in packed region
CODE32_TUNE1  ENDS

CODE32_TUNE2  SEGMENT DWORD USE32 PUBLIC 'CODE'
EXTRN	THK32DEALLOC:NEAR
CODE32_TUNE2  ENDS

CODE32_TUNE4  SEGMENT DWORD USE32 PUBLIC 'CODE'
EXTRN	THK32HANDLEBOUNDARY:NEAR
CODE32_TUNE4  ENDS

CODE32	SEGMENT DWORD USE32 PUBLIC 'CODE'
CODE32	ENDS


CODE16C  SEGMENT DWORD USE16 PUBLIC 'CODE'
CODE16C  ENDS


DATA32	SEGMENT
DATA32	ENDS

EXTRN	DOSINSMESSAGE:FAR

;Create a dummy label to trick MASM into correct fixups
CODE16C  SEGMENT
T_DOSINSMESSAGE LABEL FAR
CODE16C  ENDS


CODE32	SEGMENT
	ASSUME CS:FLAT,DS:FLAT,ES:FLAT
;/********************** START OF SPECIFICATIONS **********************/
;/*								      */
;/* ENTRY POINT:  DOS32INSERTMESSAGE				      */
;/*								      */
;/* DESCRIPTIVE NAME:  32 bit entry point for DosInsMessage	      */
;/*								      */
;/* FUNCTION:  Converts 32 bit parameters to 16:16 so that	      */
;/*	       DosInsMessage can use them.			      */
;/*								      */
;/* NOTES:							      */
;/*    Here is what the stack looks like:			      */
;/*								      */
;/*	+32-> Pointer to return length				      */
;/*	+28-> Length of data buffer				      */
;/*	+24-> Pointer to data buffer				      */
;/*	+20-> Length of message text				      */
;/*	+16-> Pointer to message text				      */
;/*	+12-> IVTABLE count					      */
;/*	 +8-> Pointer to IVTABLE				      */
;/*    BP+4-> Return address					      */
;/*	 BP-> Saved BP						      */
;/*    BP-4-> Saved Return value				      */
;/*	 -8-> Saved ESI 					      */
;/*	-12-> Saved EDI 					      */
;/*	-16-> Temp Storage					      */
;/*	-20-> Err Flag						      */
;/*	-24-> Stack Alloc Flag					      */
;/*	-28-> BMP Flag						      */
;/*	-32-> Alias Flag					      */
;/*	-36-> Addr of IVTABLE					      */
;/*	-40-> Addr of Message text				      */
;/*	-44-> Addr of Data Buffer				      */
;/*	-48-> Addr of Return Length				      */
;/*	-52-> Saved EBX 				       ;BN026;*/
;/*								      */
;/* INTERNAL REFERENCES:					      */
;/*		T_DOSINSMESSAGE 				      */
;/*								      */
;/* EXTERNAL REFERENCES:					      */
;/*		THK32HANDLEBOUNDARY				      */
;/*		THK32HANDLESTRING				      */
;/*		THK32DEALLOC					      */
;/*								      */
;/*********************** END OF SPECIFICATIONS ***********************/
DOS32INSERTMESSAGE PROC
	push	ebp
	mov	ebp,esp

	cld			;Assume direction flag clear
	xor	eax,eax
	push	eax		  ; temp storage for return value
	push	esi
	push	edi
	push	eax		  ; temp storage
	push	eax		  ;Error flag for cleanup
	push	eax		  ; temp storage for Stack Allocation Flags
	push	eax		  ; temp storage for BMP Flags
	push	eax		  ; temp storage for Alias Flags
	push	eax		  ; temp storage for ptr param #1
	push	eax		  ; temp storage for ptr param #2
	push	eax		  ; temp storage for ptr param #3
	push	eax		  ; temp storage for ptr param #4
	push	ebx	    ;BN026; save EBX

;* Compare stack selector against FLAT:R3DSB
;* If the selector is not equal, then don't bump stack.

	mov	ax,ss
	cmp	ax,seg FLAT:DATA32		; standard 32 bit stack?
	jne	short L1		; if not, skip bumping code

;* Bump the stack down if too near 64K boundary.

	mov	eax,esp
	cmp	ax,1024
	jae	short L1
	xor	ax,ax
	mov	esp,eax 	; bump the stack down


;Insure that 1 DWORD exists on stack
	push	eax


; ****> BEGIN Pointer/Structure Section

L1:
	mov	esi,[ebp+8]		; Addr of IVTABLE

;Pointer  --> ivt
	or	esi,esi
	jz	L2

	mov	[ebp-36],esi
	mov	ecx,[ebp+12]		; IVTABLE Count
	or	ecx,ecx
	jz	L2		;Nothing to check

;ECX holds count of items (calculate total size of vector)	     @@sjb
	.if	<ECX a 9>
	  jmp	  INVALID_IVCOUNT		  ;BC019; =320
	.endif
	mov	eax,4		;Size of array element		     @@sjb
	mul	cx		;was mul ax,cx	(calc total len)     @@sjb
	mov	ecx,eax 			 ;		     @@sjb


;Allocate space on Stack					     @@sjb
	sub	esp,ecx 			 ;allocate on stack  @@sjb
	and	esp,0fffffffch			 ;dword align	     @@sjb
	mov	edi,esp 			 ;point to new data  @@sjb
	mov	[ebp-36],edi			 ;save pointer	     @@sjb

; Copy ECX bytes from ESI to EDI				     @@sjb
	push	ecx		;save the length of the copy buffer  @@sjb
	call	THK32COPYBLOCK		 ;			     @@sjb
	pop	ecx			 ;restore length of vector   @@sjb

;	At this point do CRMA on the vector of 0:32 pointers to build@@sjb
;	vector of 16:16 pointers				     @@sjb
	mov	dx,ss			 ;get cpl bits for dpl bits  @@sjb
	and	dx,3			 ;mask off rest of register  @@sjb
	or	dl,4			 ;Force LDT bit on	     @@sjb
	mov	ebx,[ebp-36]		 ;Restore pointer to vector  @@sjb
	add	ebx,ecx 		 ;start and end and backup   @@sjb
CRMAV:					 ;			     @@sjb
	cmp	ebx,[ebp-36]		 ;compare to base pointer    @@sjb
	jbe	L2			 ;done			     @@sjb
	sub	ebx,4			 ;backup the pointer	     @@sjb
	mov	eax,[ebx]		 ;pick up a 0:32 pointer     @@sjb

;  Determine if each string wraps a 64k segment 		     @@sjb
	call	pointerwrap		 ;Does the string wrap seg   @@sjb
	jnc	DOCRMA			 ; if carry then wrap	     @@sjb

;  Allocate space on stack for insertion string 		     @@sjb
	sub	esp,ecx 		 ;allocate on stack	     @@sjb
	and	esp,0fffffffch		 ;dword align		     @@sjb
	mov	edi,esp 		 ;point to new data	     @@sjb
	push	edi			 ;save pointer to new string @@sjb
	call	THK32COPYBLOCK		 ;copy the string	     @@sjb
	pop	esi			 ;restore pointer to do crma @@sjb

;  Do CRMA operation on the pointer				     @@sjb
DOCRMA: 				 ;			     @@sjb
	mov	eax,esi 		 ;move pointer to eax	     @@sjb
      ; ror	eax,16			 ;BD019; CRMA on pointer     @@sjb
      ; shl	ax,3			 ;BD019;		     @@sjb
      ; or	al,dl			 ;BD019;		     @@sjb
      ; rol	eax,16			 ;BD019;		     @@sjb
	call	DOS32FLATTOSEL		 ;BN019; Convert in packed region
	mov	[ebx],eax		 ;store the 16:16 pointer    @@sjb
	jmp	CRMAV			 ;loop through vector	     @@sjb


L2:
	mov	esi,[ebp+16]		; Address of Message Text

;Pointer  --> msg
	or	esi,esi
	jz	L5

	mov	[ebp-40],esi
	mov	ecx,[ebp+20]		; Length of Message Text
	or	ecx,ecx
	jz	L5		;Nothing to check

;DWORD --> WORD sized length. Error if Size > 64k
	cmp	ecx,10000h
	jae	INVP_DOS32INSERTMESSAGE 		;jmp if too long
;ECX holds size in bytes

;Check Boundary Crossing
	mov	eax,esi
	neg	ax
	jz	L5			;0=full 64k of room

	cmp	ax,cx
	jae	L5			;Enough room

	call	Thk32HandleBoundary
	or	eax,eax
	ja	NOMEM_DOS32INSERTMESSAGE			;
	mov	[ebp-40],edi
	or	edx,edx
	jb	short L6		;Alloced Mem
	or	DWORD PTR [ebp+(edx*4)-32],2		;Set Flag
	dec	edx
	ja	short L7		;Aliases not copied

L6:			;Variable Length Copy
; Copy ECX bytes from ESI to EDI
	call	THK32COPYBLOCK

L7:			;Variable Length No Copy


L5:
	mov	esi,[ebp+24]		; Addr of Buffer

;Pointer  --> buf
	or	esi,esi
	jz	L8

	mov	[ebp-44],esi
	mov	ecx,[ebp+28]		; Length of Buffer
	or	ecx,ecx
	jz	L8		;Nothing to check

;DWORD --> WORD sized length. Error if Size > 64k
	cmp	ecx,10000h
	jae	INVP_DOS32INSERTMESSAGE 		;jmp if too long
;ECX holds size in bytes

;Check Boundary Crossing
	mov	eax,esi
	neg	ax
	jz	L8			;0=full 64k of room

	cmp	ax,cx
	jae	L8			;Enough room

	call	Thk32HandleBoundary
	or	eax,eax
	ja	NOMEM_DOS32INSERTMESSAGE			;
	mov	[ebp-44],edi
	or	edx,edx
	jb	short L9		;Alloced Mem
	or	DWORD PTR [ebp+(edx*4)-32],4		;Set Flag

L9:			;Variable Length Copy
;Item semantics are NOT input
L10:			;Variable Length No Copy


L8:
	mov	esi,[ebp+32]		; Addr of Return Length

;Pointer  --> actuallen
	or	esi,esi
	jz	L11

	mov	[ebp-48],esi

;Have PU/LONG, want PU/SHORT
;Use the LONG as buffer, only if it doesn't
;cross boundary

;Check Boundary Crossing - fixed size item
	cmp	si,65532
	jbe	L11			;Enough room

; Allocate space on stack
	sub	esp,2			;Alloc Mem
	and	esp,0FFFFFFFCh		;DWORD align
	mov	edi,esp 		;Points to new data area
	mov	[ebp-48],edi

L11:

; ****> END Pointer/Structure Section

;* Create new call frame, using 16-bit semantics.

	push	es
	push	ebp			; save ebp
	mov	eax,esp 		; save current esp
	push	ss
	push	eax


	mov	dx,ss			; get cpl bits to use as dpl bits
	and	dx,3			; mask off rest of register

	or	dl,4			;Force LDT bit on


	;From Name:   Type: char		; IVTable pointer (as 16:16)
	mov	eax,DWORD PTR [ebp-36]
	or	eax,eax
	jz	short L12			;NULL pointer

      ; ror	eax,16			;BD019; CRMA on structure pointer
      ; shl	ax,3			;BD019;
      ; or	al,dl			;BD019;
      ; rol	eax,16			;BD019;
	call	DOS32FLATTOSEL		;BN019; Convert in packed region
L12:	push	eax


	;From Name:   Type: unsigned long	; IV Count
	mov	eax,[ebp+12]			; IVTABLE Count
	cmp	eax,0ffffh
	ja	INVP_DOS32INSERTMESSAGE

	push	ax		;To:unsigned short


	;From Name:   Type: char		; Input buffer address
	mov	eax,DWORD PTR [ebp-40]
	or	eax,eax
	jz	short L13			;NULL pointer

      ; ror	eax,16			;BD019; CRMA on structure pointer
      ; shl	ax,3			;BD019;
      ; or	al,dl			;BD019;
      ; rol	eax,16			;BD019;
	call	DOS32FLATTOSEL		;BN019; Convert in packed region
L13:	push	eax


	;From Name:   Type: unsigned long	; Input buffer length
	mov	eax,[ebp+20]			; Length of Message Text
	cmp	eax,0ffffh
	ja	INVP_DOS32INSERTMESSAGE

	push	ax		;To:unsigned short


	;From Name:   Type: char		; Output buffer address
	mov	eax,DWORD PTR [ebp-44]
	or	eax,eax
	jz	short L14			;NULL pointer

	ror	eax,16			; CRMA on structure pointer
	shl	ax,3
	or	al,dl
	rol	eax,16
L14:	push	eax


	;From Name:   Type: unsigned long	; output buffer length
	mov	eax,[ebp+28]			; Length of Buffer
	cmp	eax,0ffffh
	ja	INVP_DOS32INSERTMESSAGE

	push	ax		;To:unsigned short


	;From Name:   Type: unsigned long	; actual message length
	mov	eax,DWORD PTR [ebp-48]
	or	eax,eax
	jz	short L15			;NULL pointer

	ror	eax,16			; CRMA on structure pointer
	shl	ax,3
	or	al,dl
	rol	eax,16
L15:	push	eax


;* Convert SS:ESP to 16-bit SS:SP.

	mov	eax,esp 		; use CRMA on ESP
	ror	eax,16
	shl	ax,3
	or	al,dl
	rol	eax,16

	push	eax			; push new stack pointer
	lss	sp,DWORD PTR [esp]	; ss:sp = 16-bit ptr

;* Jump to 16-bit segment to issue call (so that 16-bit API can RETF).

	jmp	FAR PTR T_DOSINSMESSAGE


INVP_DOS32INSERTMESSAGE:
	mov	eax,ERROR_INVALIDPARAM
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L16

NOMEM_DOS32INSERTMESSAGE:
	mov	eax,ERROR_NOMEMORY

ERR_DOS32INSERTMESSAGE:
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L16

INVALID_IVCOUNT:
	mov	eax,ERROR_MR_INV_IVCOUNT
	mov	BYTE PTR [ebp-20],1		;Set flag
	jmp	short L16


R_DOSINSMESSAGE:				; label defining return jmp location

;* Restore 32-bit SS:ESP - it is on top of stack.

	movzx	esp,sp			; make sure that esp is correct
	lss	esp,[esp]
	pop	ebp
	pop	es



;Convert Return Code
;USHORT --> ULONG
	movzx	eax,ax
L16:
;Functions contain pointers, save return code
	mov	[ebp-4],eax		;Save return code

; ****> BEGIN Pointer/Structure Unpack Section


;Undo Pointer  --> ivt
;								   @@sjb
; no action required						   @@sjb
;								   @@sjb
L17:		;No action required

;Undo Pointer  --> msg


	mov	esi,[ebp-40]		; temp address
	or	esi,esi
	jz	L21



	mov	edi,[ebp+16]		; Addr of Message Text
;Types are identical and no imbedded pointers exist
;This means that we treated the pointer as a buffer
;If temp address == original address then no work required
	cmp	esi,edi
	je	L21
	push	-32		 ;Alloc Flag Offset
	mov	edx,2

	call	THK32DEALLOC


L21:		;No action required

;Undo Pointer  --> buf


	mov	esi,[ebp-44]		; temp address
	or	esi,esi
	jz	L25



	mov	edi,[ebp+24]		; Addr of Buffer
;Types are identical and no imbedded pointers exist
;This means that we treated the pointer as a buffer
;If temp address == original address then no work required
	cmp	esi,edi
	je	L25

	test	BYTE PTR[ebp-20],1		;Check for errors A
	jnz	L26			;No copy if error

;Get size for copy out
	mov	ecx,[ebp+28]		; Length of Buffer
;ECX holds size in bytes

;If aliased, then skip over possible copyout
	test	DWORD PTR[ebp-32],4		;Test Alias Flag
	jnz	L27
;Copy out ecx bytes
	push	esi		;Save ptr to temp object

; Copy ECX bytes from ESI to EDI
	call	THK32COPYBLOCK
	pop	esi		;Get ptr to temp object
L27:			;Aliased Label
	push	-32		;Alloc Flag Offset
	mov	edx,4

	call	THK32DEALLOC



L26:			;ErrorLabel A

L25:		;No action required

;Undo Pointer  --> actuallen


	mov	esi,[ebp-48]		; temp address
	or	esi,esi
	jz	L30



	mov	edi,[ebp+32]		; Addr of Return Length

;This item is either on the stack, or is still
;in its original position.
;Output semantics convert in place

	movzx	eax,WORD PTR[esi]
	mov	[edi],eax

L30:		;No action required

; ****> END Pointer/Structure Unpack Section

;* 32-bit return code.

	mov	ebx,[ebp-52]			;BN026; Restore EBX

	lea	esp,[ebp-12]
	pop	edi
	pop	esi
	pop	eax		;Pop saved return code
	mov	esp,ebp
	pop	ebp
	ret				; Remove parameters

DOS32INSERTMESSAGE endp

CODE32	ENDS

;* 16-bit code to make API call.

CODE16C  SEGMENT

	ASSUME CS:CODE16C
	.errnz ($ - T_DOSINSMESSAGE)

	call	FAR PTR DOSINSMESSAGE		; call 16-bit version
	jmp	FAR PTR FLAT:R_DOSINSMESSAGE		; jump back

CODE16C  ENDS



CODE32	SEGMENT


	ASSUME CS:FLAT,DS:FLAT,SS:FLAT

THK32COPYBLOCK:

; Copy ECX bytes from ESI to EDI
	mov	eax,3
	and	eax,ecx
	shr	ecx,2
	rep movsd
	mov	ecx,eax
	rep movsb

	ret

;								     @@sjb
;  pointerwrap: 						     @@sjb
;	 input:    eax		 pointer to original string	     @@sjb
;	 output:   esi		 pointer to original string	     @@sjb
;		   CF		 if wraps a segment boundary	     @@sjb
;		   NC		 if does not wrap a segment boundary @@sjb
;		   ecx		 length of string		     @@sjb
;	 regs used:						     @@sjb
;		    eax,esi,ecx,flags,edi			     @@sjb
;								     @@sjb
PUBLIC POINTERWRAP
pointerwrap:				 ;			     @@sjb
	mov	esi,eax 		 ;save pointer to org.string @@sjb
	mov	ecx,-1			 ;put -1 to count register   @@sjb
	xor	eax,eax 		 ;zero the search register   @@sjb
	mov	edi,esi 		 ;put string ptr in edi      @@sjb
	repne	scasb			 ; ecx = -strlen(string)     @@sjb
	not	ecx			 ;make a positive count      @@sjb
	mov	eax,esi 		 ;restore the orig. pointer  @@sjb
	add	ax,cx			 ;Set the carry flag if wrap @@sjb
	ret

CODE32	ENDS

	END
