	TITLE   LDHEADER - Load Exe Header procedure

.xlist
include gpfix.inc
include kernel.inc
include newexe.inc
.list

externA	 __AHINCR

externFP IGlobalAlloc
externFP IGlobalFree
externFP FarSetOwner
externFP Int21Handler
externFP FarMyUpper
externFP IsBadStringPtr
externFP _hread

DataBegin

externB fBooting
externB szBozo
externW winVer
externD pSErrProc

DataEnd
      	  
externFP IGlobalLock
externFP IGlobalUnLock

sBegin	NRESCODE
assumes CS,NRESCODE

externNP NResGetPureName


;-----------------------------------------------------------------------;
; LoadExeHeader								;
; 									;
; Routine to read an EXE header and check for a new format EXE file.	;
; Returns NULL if not a new format EXE.  Otherwise reads the resident	;
; portion of the new EXE header into allocated storage and returns	;
; the segment address of the new EXE header.				;
; 									;
; Arguments:								;
;	parmW	fh							;
;	parmW	isfh							;
;	parmD	pfilename						;
; 									;
; Returns:								;
;	AX = segment of exe header					;
;	DL = ne_exetyp							;
;	DH = ne_flagsothers						;
; 									;
; Error Returns:							;
;LME_MEM 	= 0	; Out of memory					;
;LME_VERS 	= 10	; Wrong windows version				;
;LME_INVEXE 	= 11	; Invalid exe					;
;LME_OS2 	= 12	; OS/2 app					;
;LME_DOS4 	= 13	; DOS 4 app					;
;LME_EXETYPE 	= 14	; unknown exe type				;
;LME_COMP	= 19	; Compressed EXE file				;
;LME_PE		= 21	; Portable EXE					;
; 									;
; Registers Preserved:							;
;	DI,SI								;
; 									;
; Registers Destroyed:							;
;	AX,BX,CX,DS,ES							;
; Calls:								;
; 									;
; History:								;
; 									;
;  Thu Mar 19, 1987 08:35:32p  -by-  David N. Weise   [davidw]		;
; Added this nifty comment block.					;
;-----------------------------------------------------------------------;

cProc	LoadExeHeader,<PUBLIC,FAR>,<si,di>
	parmW   fh
	parmW   isfh
	parmD	pfilename
	localW	pnewexe
	localW	exetype
	localW  nchars
	localW  pseg
	localW  psegsrc
	localW  hBlock
	localW  pBlock
	localW  NEFileOffset
	localD	PreloadLen
	localW	NEBase
	localW	exeflags
	localW	expver
	localW	saveSP
	localB	fast_fail		; 1 if we can't use fastload block
	localV  hdrbuf,<SIZE EXE_HDR>

.errnz	SIZE EXE_HDR - SIZE NEW_EXE

cBegin
	xor	ax,ax
	mov	pseg,ax
	mov	hBlock, ax
	mov	fast_fail, al
	cmp	SEG_pfilename,ax
	je	re0

IF	KDEBUG				; LoadExeHeader is internal
	cCall   IsBadStringPtr, <pfilename, 128> ; so we assume file pointer is OK
	or	ax, ax
	jnz	refailj
ENDIF
	lds	si,pfilename
	mov	al,ds:[si].opLen
	inc	ax			; include null byte
re0:
	mov	nchars,ax
	mov	bx,fh			; No, seek backwards over what
	cmp	isfh,bx
	je	refile
	mov	ds,bx
	xor	si,si
	jmp	remem

refile:					; Here to load from a file
	push	ss			; DS:SI points to I/O buffer
	pop	ds
	lea	si,hdrbuf		; Read beginning of file
	mov	dx,si
	mov	cx,SIZE EXE_HDR
	mov	bx,fh
	mov	ah,3Fh
	DOSFCALL
	jnc	@F
refailj:
	jmps	refail
@@:
	cmp	ax,cx			; Old EXE file, look for offset
	jb	refailj			; to new exe header
	cmp	ds:[si].e_magic,EMAGIC	; Check for old exe file
	je	@F
	cmp	ds:[si], 'ZS'		; Is it compressed?
	jne	refail
	cmp	ds:[si][2],'DD'
	jne	refail
	cmp	ds:[si][4],0F088h
	jne	refail
	cmp	ds:[si][6],03327h
	jne	refail
	mov	ax, LME_COMP		; Compressed EXE
	jmp	reexit
@@:
	mov	ax,ds:[si].e_lfanew.hi
	mov	dx,ds:[si].e_lfanew.lo
	mov	pnewexe,dx		; To check for bound OS/2 apps.
	or	ax,dx
	jz	refail			; Fail if not there.

	mov	cx,ds:[si].e_lfanew.hi
	mov	dx,ds:[si].e_lfanew.lo
	mov	bx, fh
	mov	ax,4200h
	DOSFCALL
	jc	refail
	mov	cx,SIZE NEW_EXE
	mov	dx,si
	mov	ah,3Fh
	DOSFCALL
	jc	refail
	cmp	ax,cx
	jne	refail
	cmp	ds:[si].ne_magic,NEMAGIC ; Did we get a valid new EXE header?
	je	remem
	cmp	ds:[si].ne_magic,PEMAGIC ; Did we find a Portable EXE (WIN32)
	jne	refail
	mov	ax, LME_PE
	jmps	rej
refail:
	mov	ax, LME_INVEXE		; invalid NEW EXE file format
rej:	jmp	reexit

remem:
	mov	psegsrc,bx		; bx has either fh or seg address
	mov	di,ds:[si].ne_enttab	; Compute size of resident new header
	add	di,ds:[si].ne_cbenttab
	add	di, 6			; null entry space (bug #8414)

	mov	cx, ds:[si].ne_cbenttab
	mov	bx, ds:[si].ne_cmovent
	shl	bx, 1
	sub	cx, bx
	shl	bx, 1
	sub	cx, bx			; Number of bytes not moveable entries
	shl	cx, 1			; Allow triple these bytes
	add	di, cx

	mov	cx,ds:[si].ne_cseg	; + 3 * #segments

; Reserve space for ns_handle field in segment table

	shl	cx,1
	add	di,cx

	.errnz	10 - SIZE NEW_SEG1

; Reserve space for file info block at end

	add	di,nchars		; + size of file info block

	xor	ax,ax			; Allocate a fixed block for header
	mov	bx,GA_ZEROINIT or GA_MOVEABLE
	cCall	IGlobalAlloc,<bx,ax,di>  ;  that isn't code or data.
	or	ax,ax
	jnz	@F
	jmps	badformat
@@:
	push	ax
	cCall	IGlobalLock,<ax>
	pop	ax
	push	dx
	cCall	IGlobalUnlock,<ax>
	pop	ax
	sub	di,nchars
	mov	pseg,ax
	mov	es,ax			; ES:0 -> new header location
	cld				; DS:SI -> old header
	mov	bx,psegsrc
	cmp	isfh,bx			; Is header in memory?
	jne	remem1			; Yes, continue
	mov	ax,ds:[si].ne_enttab	; No, read into high end
	add	ax,ds:[si].ne_cbenttab	; of allocated block
	sub	di,ax
	mov	cx,SIZE NEW_EXE		; Copy part read so far
	sub	ax,cx
	rep	movsb
	mov	cx,ax
	smov	ds,es			; Read rest of header from file
	mov	dx,di
	mov	ah,3fh
	DOSFCALL
	mov	bx,ax
	jc	refail1
	lea	si,[di-SIZE NEW_EXE]	; DS:SI -> old header
	cmp	bx,cx
	je	remem1
badformat:
	mov	ax, LME_INVEXE		; don't change flags
refail1:				; Here if error reading header
	push	ax
	SetKernelDSNRes			; DS may be = pseg, prevent
	cCall	IGlobalFree,<pseg>	 ;  GP faults in pmode.
	pop	ax
	jmp	reexit

remem1:
	UnsetKernelDS
	test	ds:[si].ne_flags,NEIERR ; Errors in EXE image?
	jnz	badformat		; Yes, fail

	cmp	ds:[si].ne_ver,4	; No, built by LINK4 or above?
	jl	badformat		; No, error
	mov	bx,ds:[si].ne_flags	; Make local copies of ne_flags &
	and	bl,NOT NEPROT		;   ne_expver which can be modified
	mov	exeflags,bx		;   (can't change ROM exe headers).
	mov	bx,ds:[si].ne_expver
	mov	expver,bx
	mov	bx,word ptr ds:[si].ne_exetyp	; get exetyp and flagsothers
	mov	exetype,bx

	cmp	bl,NE_UNKNOWN
	jz	windows_exe
	cmp	bl,NE_WINDOWS		; is it a Windows exe?
	jz	windows_exe
	mov	ax,LME_OS2
	cmp	bl,NE_OS2		; is it an OS|2 exe?
	jnz	not_os2
	test	bh,NEINPROT		; can it be run under Windows?
	jz	@F
	and	exeflags,NOT NEAPPLOADER
	or	exeflags,NEPROT
	mov	expver,0300h
	jmps	windows_exe
@@:
	cmp	pnewexe,0800h		; is it a bound
	jb	refail1
	jmp	badformat
not_os2:
	inc	ax			; AX = 13 - LME_DOS4
	cmp	bl,NE_DOS4		; is it a DOS 4 exe?
	jz	refail1
	inc	ax			; AX = 14 - LME_EXETYPE
	jmp	refail1

mgxlib DB 'MGXLIB'

windows_exe:

	mov	NEBase, si		; Offset of Source header
	xor	di,di			; ES:DI -> new header location
	mov	cx,SIZE NEW_EXE		; Copy fixed portion of header
	cld
	rep	movsb
	mov	ax,exeflags
if ROM
	and	al,NOT NEMODINROM	; Assume module not in ROM
endif
	mov	es:[ne_flags],ax
	mov	ax,expver
	mov	es:[ne_expver],ax
	mov	si, NEBase
	add	si, es:[ne_segtab]	; Real location of segment table
	mov	cx,es:[ne_cseg]		; Copy segment table, adding
	mov	es:[ne_segtab],di
	jcxz	recopysegx
recopyseg:

if ROM

; If this is a module from ROM, the ROM ns_sector field contains the selector
; pointing to the ROM segment--this will become the RAM ns_handle value.

	.errnz	ns_sector
	mov	dx,ds:[si].ns_flags	; do while si->start of seg info
	lodsw				; ns_sector
	xor	bx,bx			; ns_handle if not in ROM
	test	dh,(NSINROM SHR 8)
	jz	store_sector
	mov	bx,ax			; will be ns_handle
store_sector:
	stosw				; ns_sector
else
	movsw				; ns_sector
endif
	movsw				; ns_cbseg
	lodsw				; ns_flags

	.errnz	4 - ns_flags

if ROM
	mov	dl,al
	and	dl,NSLOADED
	and	ax,not (NS286DOS XOR (NSGETHIGH OR NSINROM))
else
	and	ax,not (NS286DOS XOR NSGETHIGH) ; Clear 286DOS bits
endif
; record in the segment flags if this module is a process, this is for EMS

	test	ax,NSTYPE		; NSCODE
	jnz	not_code
	or	ax,NSWINCODE
not_code:
	or	ax,NSNOTP
	test	es:[ne_flags],NSNOTP
	jnz	not_a_process
	xor	ax,NSNOTP
	or	ax,NSMOVE
not_a_process:
if ROM
	test	ah,(NSINROM SHR 8)	; if sector is in ROM, preserve
	jz	@f			;   NSLOADED flag from ROM builder
	or	al,dl
@@:
endif
	stosw				; ns_flags
	movsw				; ns_minalloc
	.errnz	8 - SIZE NEW_SEG
if ROM
	mov	ax,bx			; bx set to selector or 0 above
else
	xor	ax,ax
endif
	stosw				; one word for ns_handle field
	.errnz	10 - SIZE NEW_SEG1
	loop	recopyseg

recopysegx:
	test	es:[ne_flagsothers], NEGANGLOAD
	jz	no_gang_loadj
	mov	bx, fh
	cmp	bx, isfh
	jne	no_gang_loadj

	mov	ax, es:[ne_gang_start]
	or	ax, ax
	jz	no_gang_loadj
	mov	NEFileOffset, ax	; file offset of gang load area
	mov	ax, es:[ne_gang_length]
	or	ax, ax
	jz	no_gang_loadj
	mov	cx, es:[ne_align]
	xor	dx, dx
gl_len:					; find length of Gang Load area
	shl	ax, 1
	adc	dx, dx
	loop	gl_len

	cmp	dx, 10h 		; Greater than 1Mb, forget it!!
	jb	alloc_it		; PS: NEVER go bigger than 1Mb
no_gang_loadj:
	jmp	no_gang_load		; since LongPtrAdd is limited...

alloc_it:
	mov	word ptr PreloadLen[0], ax
	mov	word ptr PreloadLen[2], dx
	mov	ch, GA_DISCARDABLE
	mov	cl, GA_MOVEABLE+GA_NODISCARD+GA_NOCOMPACT
	push	es
	cCall	IGlobalAlloc,<cx,dx,ax>  ; Allocate this much memory
	pop	es
	or	ax, ax
	jz	no_gang_loadj
	mov	hBlock, ax		; Have memory to read file into
	push	es
	cCall	IGlobalLock,<ax>
	pop	es
	mov	pBlock, dx
	mov	dx, NEFileOffset
	mov	cx, es:[ne_align]
	xor	bx, bx
gl_pos:					; find pos of Gang Load start
	shl	dx, 1
	adc	bx, bx
	loop	gl_pos

	mov	cx, bx

	mov	bx, fh
	mov	ax,4200h
	DOSFCALL			; Seek to new exe header
	jc	refailgang

	mov	ax, pBlock
	xor	bx, bx
	farptr	memadr,ax,bx
	cCall   _hread, <fh, memadr, PreloadLen>
	cmp	dx, word ptr PreloadLen[2]
	jnz	refailgang
	cmp	ax, word ptr PreloadLen[0]
	jz	no_gang_load		; We're OK now
;	push	ds
;	xor	dx, dx
;	mov	ax, pBlock

;	push	si
;	push	di
;	mov	si, word ptr PreloadLen[2]
;	mov	di, word ptr PreloadLen[0]
;read_file:
;	mov	cx, 08000h		; Must be factor 64k DON'T CHANGE THIS
;	or	si, si
;	jnz	big_read
;	cmp	cx, di
;	jbe	big_read
;	mov	cx, di			; all that's left
;	jcxz	done_read		; Nothing left, quit.
;big_read:
;	mov	ds, ax
;	mov	ah, 3Fh
;	DOSFCALL			; Read chunk from file
;	jc	refailgang
;	cmp	ax, cx			; All we asked for?
;	jne	refailgang		;  no, file corrupted
;	sub	di, cx
;	sbb	si, 0
;	mov	ax, ds
;	add	dx, cx			; On to next block
;	jnc	read_file
;	add	ax, __AHINCR
;	jmps	read_file
;
refailgang:
;	pop	di
;	pop	si
;	pop	ds
	cCall	IGlobalUnlock,<hBlock>
	cCall	IGlobalFree,<hBlock>
	mov	hBlock, 0
	jmps	no_gang_load

BadExeHeader:				; GP fault handler!!!
	mov	sp, saveSP
;	fix_fault_stack
	jmp	refail1			; corrupt exe header (or our bug)


;done_read:
;	pop	di
;	pop	si
;	pop	ds

no_gang_load:
	mov	saveSP, sp
beg_fault_trap	BadExeHeader
	mov	cx,es:[ne_restab]	; Copy resource table
	sub	cx,es:[ne_rsrctab]
	mov	si, NEBase		; Get correct source address
	add	si, es:[ne_rsrctab]
	mov	es:[ne_rsrctab],di
	rep	movsb

rerestab:
	mov	cx,es:[ne_modtab]	; Copy resident name table
	sub	cx,es:[ne_restab]
	mov	es:[ne_restab],di
	rep	movsb

	push	di
	mov	di, es:[ne_restab]	; Make the module name Upper Case
	xor	ch, ch
	mov	cl, es:[di]
	inc	di
uppercaseit:
	mov	al, es:[di]
	call	farMyUpper
	stosb
	loop	uppercaseit
	pop	di

	mov	cx,es:[ne_imptab]	; Copy module xref table
	sub	cx,es:[ne_modtab]
	mov	es:[ne_modtab],di
	rep	movsb

	mov	es:[ne_psegrefbytes],di ; Insert segment reference byte table
	mov	es:[ne_pretthunks],di	; Setup return thunks
	mov	cx,es:[ne_enttab]	; Copy imported name table
	sub	cx,es:[ne_imptab]
	mov	es:[ne_imptab],di
	jcxz	reenttab
	rep	movsb

reenttab:
	mov	es:[ne_enttab],di
					; Scan current entry table
	xor	ax, ax			; First entry in block
	mov	bx, di			; Pointer to info for this block
	stosw				; Starts at 0
	stosw				; Ends at 0
	stosw				; And is not even here!

copy_next_block:
	lodsw				; Get # entries and type
	xor	cx, cx
	mov	cl, al
	jcxz	copy_ent_done

	mov	al, ah
	cmp	al, ENT_UNUSED
	jne	copy_used_block

	mov	ax, es:[bx+2]		; Last entry in current block
	cmp	ax, es:[bx]		; No current block?
	jne	end_used_block

	add	es:[bx], cx
	add	es:[bx+2], cx
	jmps	copy_next_block

end_used_block:
	mov	es:[bx+4], di		; Pointer to next block
	mov	bx, di
	add	ax, cx			; Skip unused entries
	stosw				; First in new block
	stosw				; Last in new block
	xor	ax, ax
	stosw				; End of list
	jmps	copy_next_block

copy_used_block:
	add	es:[bx+2], cx		; Add entries in this block
	cmp	al, ENT_MOVEABLE
	je	copy_moveable_block

; absolutes end up here as well

copy_fixed_block:
	stosb				; Segno
	movsb				; Flag byte
	stosb				; segno again to match structure
	movsw				; Offset
	loop	copy_fixed_block
	jmps	copy_next_block

copy_moveable_block:
	stosb				; ENT_MOVEABLE
	movsb				; Flag byte
	add	si, 2			; Toss int 3Fh
	movsb				; Copy segment #
	movsw				; and offset
	loop	copy_moveable_block
	jmps	copy_next_block

copy_ent_done:
	xor	bx,bx
	cmp	es:[bx].ne_ver,5	; Produced by version 5.0 LINK4
	jae	remem2a			; or above?
	mov	es:[bx].ne_expver,bx	; No, clear uninitialized fields
	mov	es:[bx].ne_swaparea,bx

; TEMPORARY BEGIN

	push	ax
	push	cx
	push	di
	push	si
	mov	si,es:[bx].ne_rsrctab
	cmp	si,es:[bx].ne_restab
	jz	prdone
	mov	di,es:[si].rs_align
	add	si,SIZE new_rsrc
prtype:
	cmp	es:[si].rt_id,0
	je	prdone
	mov	cx,es:[si].rt_nres
	add	si,SIZE rsrc_typeinfo
prname:
	push	cx
	mov	ax,es:[si].rn_flags
	test	ah,0F0h			; Is old discard field set?
	jz	@F
	or	ax,RNDISCARD		; Yes, convert to bit
@@:
	and	ax,not RNUNUSED 	; Clear unused bits in 4.0 LINK files
	mov	es:[si].rn_flags,ax
	pop	cx
	add	si,SIZE rsrc_nameinfo
	loop	prname

	jmp	prtype

prdone:	pop	si
	pop	di
	pop	cx
	pop	ax

; TEMPORARY END

FixFlags:				; label for debugging
public FixFlags, leh_slow
public leh_code, leh_patchnext, leh_code_fixed, leh_patchdone, leh_data
remem2a:                                ; (bx == 0)
	mov	es:[bx].ne_usage,bx
	mov	es:[bx].ne_pnextexe,bx
	mov	es:[bx].ne_pfileinfo,bx
	cmp	es:[bx].ne_align,bx
	jne	@F
	mov	es:[bx].ne_align,NSALIGN
@@:
	mov	cx,nchars
	jcxz	@F
	mov	es:[bx].ne_pfileinfo,di
	lds	si,pfilename
	rep	movsb
@@:					; Save pointer to seginfo record
	mov	bx,es:[bx].ne_autodata	; of automatic data segment
	or	bx,bx
	jz	@F
	dec	bx
	shl	bx,1
	mov	cx,bx
	shl	bx,1
	shl	bx,1
	add	bx,cx
	.errnz	10 - SIZE NEW_SEG1
	add	bx,es:[ne_segtab]
@@:
	mov	es:[ne_pautodata],bx

	SetKernelDSNRes

; Scan seg table, marking nonautomatic DATA segments fixed, preload

	mov	ax,es:[ne_expver]	; Default expected version to
	or	ax,ax
	jnz	@F
	mov	ax,201h
	mov	es:[ne_expver],ax	; 2.01
@@:
	cmp	ax,winVer
	jbe	@F
	cCall	IGlobalFree,<pseg>
	mov	ax, LME_VERS
	jmp	reexit
@@:
	mov	bx,es:[ne_segtab]
	xor	cx,cx
	sub	bx,SIZE NEW_SEG1
	jmps	leh_patchnext

leh_test_preload:
	test	byte ptr es:[bx].ns_flags, NSPRELOAD
	jnz	leh_patchnext

	or	byte ptr es:[bx].ns_flags, NSPRELOAD

	cmp	es:[bx].ns_sector, 0	; don't whine about empty segments
	je	leh_patchnext

	krDebugOut	DEB_WARN, "Segment #CX of %ES0 must be preload"
	mov	fast_fail, 1

leh_patchnext:
	add	bx,SIZE NEW_SEG1
	inc	cx
	cmp	cx,es:[ne_cseg]
	ja	leh_patchdone
	test	byte ptr es:[bx].ns_flags,NSDATA ; Is it a code segment?
	jz	leh_code			; Yes, next segment
	.errnz	NSCODE
leh_data:	; Data must be non-discardable, preload
if KDEBUG
	test	es:[bx].ns_flags, NSDISCARD
	jz	@F
	krDebugOut DEB_WARN, "Data Segment #CX of %ES0 can't be discardable"
@@:
endif
	and	es:[bx].ns_flags,not NSDISCARD	; Data segments not discardable
	jmps	leh_test_preload

leh_code:
	test	byte ptr es:[bx].ns_flags,NSMOVE; Moveable code?
	jz	leh_code_fixed

		; moveable code must be discardable, or must be preload
if	KDEBUG
	test	es:[ne_flags],NENOTP		; for 3.0 libraries can't have
	jz	@F				;  moveable only code
	cmp	fBooting,0			; If not booting
	jne	@F
	test	es:[bx].ns_flags,NSDISCARD
	jnz	@F
	krDebugOut DEB_WARN, "Segment #CX of %ES0 was discardable under Win 3.0"
@@:
endif
	test	es:[bx].ns_flags,NSDISCARD	; Is it discardable?
	jnz	leh_patchnext
	jmp	leh_test_preload

leh_code_fixed:	; fixed code must be preload
	cmp	fBooting,0			; If not booting
	jne	leh_patchnext
	jmp	leh_test_preload

leh_patchdone:
	mov	bx,word ptr es:[ne_csip+2]	; Is there a start segment?
	or	bx,bx
	jz	@F				; No, continue
	dec	bx
	shl	bx,1
	mov	si,bx
	shl	si,1
	shl	si,1
	add	si,bx
	.errnz	10 - SIZE NEW_SEG1
	add	si,es:[ne_segtab]	; Mark start segment as preload
if kdebug
	test	byte ptr es:[si].ns_flags,NSPRELOAD
	jnz	scs_pre
	krDebugOut DEB_WARN, "Starting Code Segment of %ES0 must be preload"
	mov	fast_fail, 1
scs_pre:
endif
	or	byte ptr es:[si].ns_flags,NSPRELOAD

	cmp	es:[ne_autodata],0	; Is there a data segment?
	je	@F
	or	es:[si].ns_flags,NSUSESDATA ; Yes, then it needs it
	mov	si,es:[ne_pautodata]
if kdebug
	test	byte ptr es:[si].ns_flags,NSPRELOAD
	jnz	sds_pre
	cmp	es:[bx].ns_sector, 0	; don't whine about empty segments
	je	sds_pre
	krDebugOut DEB_WARN, "Default Data Segment of %ES0 must be preload"
	mov	fast_fail, 1
sds_pre:
endif
	or	byte ptr es:[si].ns_flags,NSPRELOAD ; Mark DS as preload
@@:
	test	es:[ne_flags],NENOTP	; No stack if not a process
	jnz	@F
	cmp	es:[ne_stack],4096+1024
	jae	@F
	mov	es:[ne_stack],4096+1024 ; 4k stack is not enough (raor)
@@:
	mov	cx, es:[ne_heap]	; If the module wants a heap
	jcxz	@f			;   make sure it's big enough
if KDEBUG				;   not to cause LocalInit
	mov	ax, 100 + SIZE LocalStats ; to fail when called from
else					;   InitTask or the user will
	mov	ax, 100 		;   be left wondering why the
endif					;   task doesn't run and there
	cmp	cx, ax			;   is no error msg.
	jae	@f
	mov	es:[ne_heap], ax
@@:
	mov	ax,es			; Set owner to be itself
	cCall	FarSetOwner,<ax,ax>

	mov	dx,exetype
	test	dh,NEINFONT		; save the font bit in exehdr
	jz	reexit			;  somewhere
	or	es:[ne_flags],NEWINPROT
end_fault_trap

reexit:
;	cmp	ax, 20h			; translate error messages for ret
;	jae	@F
;	mov	bx, ax
;	xor	ax, ax
;	cmp	bl, 1			; bx is 0, 1, 2, 19, other
;	jz      @F			; 1 -> 0 (out of memory)
;	mov	al, 11
;	jb	@F			; 0 -> 11 (invalid format)
;	cmp	bl, 3			;
;	mov	al, 10
;	jb	@F			; 2 -> 10 (windows version)
;	mov	al, 19			; 3 -> 19 (compressed EXE)
;	jz	@F			; others left alone
;	mov	al, bl
;@@:
	push	dx
	mov	bx, hBlock
	or	bx, bx
	je	noUnlock		; No block to unlock
	push	ax
	cCall	IGlobalUnlock,<bx>
	push	ss
	pop	ds			; might be freeing DS
	cmp	fast_fail, 1		; is fastload area invalid?
	jne	@F
leh_slow:
	krDebugOut	DEB_WARN, "FastLoad area ignored due to incorrect segment flags"
	cCall	IGlobalFree,<hBlock>	; yes - free it, force slow-load
	mov	hBlock, 0
@@:
	pop	ax
	cmp	ax, LME_MAXERR
	jae	noFree			; Success, return memory block in bx
	push	ax
	cCall	IGlobalFree,<hBlock>
	pop	ax
noFree:
	mov	cx, NEFileOffset	; Return offset of header in CX
	mov	bx, hBlock
noUnlock:
	pop	dx
	UnSetKernelDS
cEnd

sEnd	NRESCODE

end
