You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2855 lines
90 KiB
2855 lines
90 KiB
.xlist
|
|
include kernel.inc
|
|
include newexe.inc
|
|
include tdb.inc
|
|
include pdb.inc
|
|
include protect.inc
|
|
.list
|
|
|
|
NEWEPME = NEPRIVLIB ; flag saying Call WEP on exit
|
|
|
|
externW pLocalHeap
|
|
externW pStackTop
|
|
|
|
DataBegin
|
|
|
|
externB num_tasks
|
|
externB graphics
|
|
externB fBooting
|
|
externB Kernel_flags
|
|
externD Dos_Flag_Addr
|
|
externB WOAName
|
|
externW fLMdepth
|
|
externW headPDB
|
|
externW curTDB
|
|
externW loadTDB
|
|
externW Win_PDB
|
|
externW topPDB
|
|
externW hExeHead
|
|
;externW EMS_calc_swap_line
|
|
externW WinFlags
|
|
externW hGDI
|
|
externW hUser
|
|
ifdef WOW
|
|
externW OFContinueSearch
|
|
endif
|
|
externD pMBoxProc
|
|
externD pGetFreeSystemResources
|
|
externD dressed_for_success
|
|
externD lpGPChain
|
|
|
|
;** Diagnostic mode stuff
|
|
externW fDiagMode
|
|
externB szLoadStart
|
|
externB szCRLF
|
|
externB szLoadSuccess
|
|
externB szLoadFail
|
|
externB szFailCode
|
|
externB szCodeString
|
|
|
|
; Look for module in Module Compatibilty section of win.ini
|
|
szModuleCompatibility DB 'ModuleCompatibility',0
|
|
DataEnd
|
|
|
|
externFP Yield
|
|
externFP CreateTask
|
|
externFP GlobalAlloc
|
|
externFP GlobalSize
|
|
externFP GlobalLock
|
|
externFP GlobalUnlock
|
|
externFP GlobalFree
|
|
externFP LocalAlloc
|
|
externFP LocalFree
|
|
externFP LocalCountFree
|
|
externFP LoadModule
|
|
externFP lstrlen
|
|
externFP _lclose
|
|
externFP FreeModule
|
|
externFP GetModuleHandle
|
|
externFP LoadExeHeader
|
|
externFP GetExePtr
|
|
externFP GetProcAddress
|
|
externFP MyOpenFile
|
|
externFP FarGetCachedFileHandle
|
|
externFP FarEntProcAddress
|
|
externFP FlushCachedFileHandle
|
|
externFP FarMyLock
|
|
externFP FarMyFree
|
|
externFP FarMyUpper
|
|
externFP FarLoadSegment
|
|
externFP FarDeleteTask
|
|
externFP FarUnlinkObject
|
|
externFP Far_genter
|
|
externFP AllocSelector
|
|
externFP FreeSelector
|
|
externFP LongPtrAdd
|
|
externFP GetProfileInt
|
|
|
|
ifdef WOW
|
|
externFP StartWOWTask
|
|
externFP WowIsKnownDLL
|
|
externFP LongPtrAddWOW
|
|
externFP AllocSelectorWOW
|
|
externFP WOWLoadModule
|
|
externFP WowShutdownTimer
|
|
externB fShutdownTimerStarted
|
|
externB fExitOnLastApp
|
|
externFP WowSyncTask
|
|
endif
|
|
|
|
ifdef FE_SB
|
|
externFP FarMyIsDBCSLeadByte
|
|
endif
|
|
|
|
externFP FreeTDB
|
|
|
|
;** Diagnostic mode
|
|
externFP DiagOutput
|
|
|
|
sBegin CODE
|
|
assumes CS,CODE
|
|
assumes DS,NOTHING
|
|
assumes ES,NOTHING
|
|
|
|
sEnd CODE
|
|
|
|
sBegin NRESCODE
|
|
assumes CS,NRESCODE
|
|
assumes DS,NOTHING
|
|
assumes ES,NOTHING
|
|
|
|
externB szProtectCap
|
|
externB msgRealModeApp1
|
|
externB msgRealModeApp2
|
|
|
|
externNP MapDStoDATA
|
|
externNP FindExeFile
|
|
externNP FindExeInfo
|
|
externNP AddModule
|
|
externNP DelModule
|
|
externNP GetInstance
|
|
externNP IncExeUsage
|
|
externNP DecExeUsage
|
|
externNP AllocAllSegs
|
|
externNP PreloadResources
|
|
externNP StartProcAddress
|
|
externNP StartLibrary
|
|
externNP GetStackPtr
|
|
externNP StartTask
|
|
|
|
IFNDEF NO_APPLOADER
|
|
externNP BootAppl
|
|
ENDIF ;!NO_APPLOADER
|
|
|
|
DOS_FLAG_EXEC_OPEN equ 1
|
|
|
|
SET_DOS_FLAG_EXEC_OPEN macro
|
|
push es
|
|
push bx
|
|
mov es, Dos_Flag_Addr.sel
|
|
mov bx, Dos_Flag_Addr.off
|
|
or BYTE PTR es:[bx], DOS_FLAG_EXEC_OPEN
|
|
pop bx
|
|
pop es
|
|
endm
|
|
|
|
RESET_DOS_FLAG_EXEC_OPEN macro
|
|
push es
|
|
push bx
|
|
mov es, Dos_Flag_Addr.sel
|
|
mov bx, Dos_Flag_Addr.off
|
|
and BYTE PTR es:[bx], NOT DOS_FLAG_EXEC_OPEN
|
|
pop bx
|
|
pop es
|
|
endm
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; OpenApplEnv ;
|
|
; Calls CreateTask ;
|
|
; Allocates temporary stack ;
|
|
; Arguments: ;
|
|
; ;
|
|
; Returns: ;
|
|
; ax = selector of load-time stack ;
|
|
; Error Returns: ;
|
|
; ax = 0 ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Tue 16-Jan-1990 21:13:51 -by- David N. Weise [davidw] ;
|
|
; Ya know, it seems to me that most of the below ain't necessary ;
|
|
; for small frame EMS. But it's too late to change it now. ;
|
|
; ;
|
|
; Fri 07-Apr-1989 23:15:42 -by- David N. Weise [davidw] ;
|
|
; Added support for task ExeHeaders above The Line in Large ;
|
|
; Frame EMS. ;
|
|
; ;
|
|
; Tue Oct 20, 1987 07:48:51p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
LOADSTACKSIZE = 2048
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc OpenApplEnv,<PUBLIC,NEAR>,<ds,si,di>
|
|
parmD lpPBlock
|
|
parmW pExe
|
|
parmW fWOA
|
|
; localW myCodeDS
|
|
; localW myCurTDB
|
|
; localW myLoadTDB
|
|
cBegin
|
|
ReSetKernelDS ; Assume DS:KRNLDS
|
|
|
|
cCall CreateTask,<lpPBlock,pExe,fWOA>
|
|
or ax,ax
|
|
jz oae_done
|
|
|
|
test kernel_flags,KF_pUID ; All done booting?
|
|
jz oae_done
|
|
|
|
xor ax,ax
|
|
mov bx,LOADSTACKSIZE
|
|
mov cx,(GA_ALLOC_LOW or GA_SHAREABLE) shl 8 or GA_ZEROINIT or GA_MOVEABLE
|
|
cCall GlobalAlloc,<cx,ax,bx>
|
|
or ax,ax
|
|
jz oae_done
|
|
cCall GlobalLock,<ax>
|
|
mov ax,dx
|
|
push es ; added 13 feb 1990
|
|
mov es,loadTDB
|
|
mov es:[TDB_LibInitSeg],ax
|
|
mov es:[TDB_LibInitOff],10h
|
|
mov es,dx
|
|
mov es:[pStackTop],12h
|
|
pop es
|
|
oae_done:
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; CloseApplEnv ;
|
|
; ;
|
|
; ;
|
|
; Arguments: ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = hExe ;
|
|
; BX = ? ;
|
|
; DX = TDB ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ..., ES, ... ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Fri 07-Apr-1989 23:15:42 -by- David N. Weise [davidw] ;
|
|
; Added support for task ExeHeaders above The Line in Large ;
|
|
; Frame EMS. ;
|
|
; ;
|
|
; Tue Oct 20, 1987 07:48:51p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc CloseApplEnv,<PUBLIC,NEAR>,<ds,si,di>
|
|
parmW hResult
|
|
parmW hExe
|
|
localW myCurTDB
|
|
localW cae_temp
|
|
localW myLoadTDB
|
|
cBegin
|
|
|
|
ReSetKernelDS
|
|
|
|
; Copy DS variables to stack, since we may need DS
|
|
mov cx,curTDB
|
|
mov myCurTDB,cx
|
|
mov cx,loadTDB
|
|
mov myLoadTDB,cx
|
|
mov cae_temp, si
|
|
|
|
mov ax, myLoadTDB
|
|
or ax, ax ; Not set if LMCheckHeap failed
|
|
jz cae_done
|
|
mov ds, ax
|
|
mov ax, ds:[TDB_LibInitSeg]
|
|
or ax, ax
|
|
jz cae_free_stack1
|
|
mov ds, ax
|
|
cmp ds:[pStackTop], 12h
|
|
jne cae_free_stack1
|
|
mov ds,myLoadTDB
|
|
push ax
|
|
cCall GlobalUnlock,<ax>
|
|
call GlobalFree ; parameter pushed above
|
|
cae_free_stack1:
|
|
mov ds,myLoadTDB
|
|
mov ds:[TDB_LibInitSeg],ax
|
|
mov ds:[TDB_LibInitOff],10h
|
|
|
|
; Copy correct return address
|
|
|
|
cae_done:
|
|
SetKernelDSNRES
|
|
xor dx,dx
|
|
xchg loadTDB,dx ; Done loading this guy
|
|
|
|
mov ax,hResult ; if hResult < 32, it's not a real
|
|
cmp ax,LME_MAXERR ; handle, and in fact is the invalid
|
|
jb cae_cleanup ; format return code. (11).
|
|
|
|
mov es,dx
|
|
|
|
; Start this guy up! TDB_nEvents must be set here, and not before
|
|
; because message boxes may be put up if we can't find libraries,
|
|
; which would have caused this app to prematurely start.
|
|
|
|
push es
|
|
ifdef WOW
|
|
cmp num_tasks, 1 ; First task? (except wowexec)
|
|
jne @F ; branch if not first task
|
|
cmp fExitOnLastApp, 0 ; Shared WOW?
|
|
jne @F ; branch if not shared WOW
|
|
cmp fShutdownTimerStarted, 1; Is the timer running?
|
|
jne @F ; branch if not running
|
|
cCall WowShutdownTimer, <0> ; stop shutdown timer
|
|
mov fShutdownTimerStarted, 0
|
|
@@:
|
|
endif
|
|
mov es:[TDB_nEvents],1
|
|
inc num_tasks ; Do this here or get it wrong.
|
|
|
|
test es:[TDB_flags],TDBF_OS2APP
|
|
jz @F
|
|
cmp dressed_for_success.sel,0
|
|
jz @F
|
|
call dressed_for_success
|
|
|
|
ifdef WOW
|
|
; Start Up the New Task
|
|
@@: cCall StartWOWTask,<es,es:[TDB_taskSS],es:[TDB_taskSP]>
|
|
or ax,ax ; Success ?
|
|
jnz @f ; Yes
|
|
|
|
mov hResult,ax ; No - Fake Out of Memory Error 0
|
|
; No error matches failed to create thread
|
|
pop dx ; restore TDB
|
|
dec num_tasks ;
|
|
jmps cae_cleanup ;
|
|
|
|
endif; WOW
|
|
|
|
@@: test kernel_flags,KF_pUID ; All done booting?
|
|
jz @F ; If booting then don't yield.
|
|
cCall WowSyncTask
|
|
|
|
@@:
|
|
assumes ds,nothing
|
|
pop dx ; return TDB
|
|
jmps cae_exit
|
|
|
|
; Failure case - undo the damage
|
|
cae_cleanup:
|
|
or dx,dx ; Did we even get a TDB?
|
|
jz cae_exit ; No.
|
|
mov ds,dx
|
|
assumes ds,nothing
|
|
mov ds:[TDB_sig],ax ; mark TDB as invalid
|
|
cCall FarDeleteTask,<ds>
|
|
mov es,ds:[TDB_PDB]
|
|
mov dx,PDB_Chain
|
|
mov bx,dataOffset HeadPDB ; Kernel PDB
|
|
cCall FarUnlinkObject
|
|
cCall FreeTDB
|
|
|
|
cae_exit:
|
|
xor ax,ax
|
|
mov es,ax ; to avoid GP faults in pmode
|
|
.386
|
|
mov fs, ax
|
|
mov gs, ax
|
|
.286
|
|
mov ax,hResult
|
|
mov bx, cae_temp
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; StartModule ;
|
|
; ;
|
|
; ;
|
|
; Arguments: ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = hExe or StartLibrary ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; AX = 0 ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; BX,DI,SI,DS ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; FarLoadSegment ;
|
|
; StartProcAddress ;
|
|
; StartLibrary ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Tue Jan 01, 1980 03:04:49p -by- David N. Weise [davidw] ;
|
|
; ReWrote it from C into assembly and added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc StartModule,<PUBLIC,NEAR>,<di,si>
|
|
parmW hPrev
|
|
parmD lpPBlock
|
|
parmW hExe
|
|
parmW fh
|
|
localD pf
|
|
cBegin
|
|
mov ax,hExe
|
|
mov es,ax
|
|
assumes es,nothing
|
|
cmp es:[ne_csip].sel,0
|
|
jz start_it_up
|
|
|
|
; Make sure DGROUP loaded before we need to load the start segment.
|
|
|
|
mov cx,es:[ne_autodata]
|
|
jcxz start_it_up ; no automatic data segment
|
|
cCall FarLoadSegment,<es,cx,fh,fh>
|
|
or ax,ax
|
|
jnz start_it_up ; auto DS loaded OK
|
|
mov ax,fh
|
|
inc ax
|
|
jz sm_ret1 ; return NULL
|
|
dec ax
|
|
cCall _lclose,<ax>
|
|
xor ax,ax
|
|
sm_ret1:
|
|
jmps sm_ret ; return NULL
|
|
|
|
start_it_up:
|
|
cCall StartProcAddress,<hExe,fh> ; just because it's preloaded
|
|
mov pf.sel,dx ; doesn't mean it's still around!
|
|
mov pf.off,ax
|
|
or dx,ax
|
|
push dx
|
|
mov ax,fh
|
|
cmp ax,-1
|
|
jz sm_nothing_to_close
|
|
cCall _lclose,<ax>
|
|
sm_nothing_to_close:
|
|
pop dx
|
|
mov es,hExe
|
|
assumes es,nothing
|
|
test es:[ne_flags],NENOTP
|
|
jnz start_library
|
|
or dx,dx
|
|
jz nothing_to_start
|
|
cCall GetStackPtr,<es>
|
|
cCall StartTask,<hPrev,hExe,dx,ax,pf>
|
|
jmps sm_ret
|
|
|
|
start_library:
|
|
mov es, hExe
|
|
or es:[ne_flags], NEWEPME ; Need to call my WEP on exit
|
|
cCall StartLibrary,<hExe,lpPBlock,pf>
|
|
jmps sm_ret
|
|
|
|
nothing_to_start:
|
|
mov ax,hExe
|
|
test es:[ne_flags],NENOTP
|
|
jnz sm_ret
|
|
xor ax,ax
|
|
sm_ret:
|
|
cEnd
|
|
|
|
if 0 ; too late to include in 3.1, add for next Windows release (donc)
|
|
cProc GetProcAddressRes, <PUBLIC, FAR>, <ds, si, di>
|
|
parmW hExe
|
|
parmD pname ; pass in Pascal string
|
|
cBegin
|
|
les di, [pname] ; ES:DI = name to find
|
|
|
|
mov cx, 255 ; CH = 0
|
|
xor ax, ax
|
|
push di
|
|
repne scasb
|
|
pop di
|
|
jnz GPAR_fail
|
|
not cl
|
|
dec cl
|
|
mov al, cl ; AX = length of name
|
|
|
|
mov ds, [hExe] ; DS:SI = res name table
|
|
mov bx, ds:[ne_restab] ; (actually DS:BX first time through)
|
|
|
|
GPAR_nextsym:
|
|
mov si, bx ; next entry to check
|
|
mov cl, [si] ; string length
|
|
jcxz GPAR_fail
|
|
lea bx, [si+3]
|
|
add bx, cx ; BX points to next (last + len + 3)
|
|
cmp cx, ax
|
|
jnz GPAR_nextsym ; length diff - no match
|
|
inc si ; skip length byte
|
|
push di
|
|
rep cmpsb
|
|
pop di
|
|
jnz GPAR_nextsym
|
|
lodsw ; get ordinal number
|
|
;if KDEBUG
|
|
; cCall FarEntProcAddress,<ds,ax,1>
|
|
;else
|
|
cCall FarEntProcAddress,<ds,ax> ; I hate conditional assembly....
|
|
;endif
|
|
mov cx, ax
|
|
or cx, dx
|
|
jmps GPAR_exit
|
|
|
|
GPAR_fail:
|
|
xor ax, ax
|
|
cwd
|
|
GPAR_exit:
|
|
cEnd
|
|
endif
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; CallWEP ;
|
|
; ;
|
|
; Call WEP of DLL if appropriate ;
|
|
; ;
|
|
; Arguments: ;
|
|
; HANDLE hExe = HEXE of module about to close ;
|
|
; WORD WEPVal = 0, 1 pass to WEP, 2 check for WEP ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = status ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; AX = Not a DLL ;
|
|
; AX = No WEP ;
|
|
; AX = Module not started ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc CallWEP, <PUBLIC,FAR>, <ds>
|
|
parmW hExe
|
|
parmW WEPVal
|
|
localV szExitProc,4
|
|
localD pExitProc
|
|
localW bogusIBMAppSp
|
|
cBegin
|
|
mov ds, hExe ; Robustify this!
|
|
|
|
CWErr = 1
|
|
mov ax, 1 ; exit code
|
|
cmp ds:[ne_expver], 300h ; 3.0 libraries only
|
|
jb CW_noWEP
|
|
|
|
CWErr = CWErr+1
|
|
inc ax
|
|
test ds:[ne_flags], NENOTP ; is it a DLL?
|
|
jz CW_noWEP
|
|
|
|
CWErr = CWErr+1
|
|
inc ax ; Font, etc
|
|
cmp ds:[ne_cseg],0
|
|
jz CW_noWEP
|
|
|
|
CWErr = CWErr+1
|
|
inc ax
|
|
mov bx, ds:[ne_pautodata] ; Make sure auto data loaded
|
|
or bx, bx
|
|
jz @F
|
|
test ds:[bx].ns_flags, NSLOADED
|
|
jz CW_noWEP
|
|
@@:
|
|
|
|
CWErr = CWErr+1
|
|
inc ax
|
|
NoWepErr = CWErr
|
|
mov [szExitProc].lo, 'EW' ; If the module has a procedure
|
|
mov [szExitProc].hi, 'P' ; named 'WEP', call it.
|
|
lea bx, szExitProc
|
|
push ax
|
|
cCall GetProcAddress, <ds, ss, bx>
|
|
mov [pExitProc].off, ax
|
|
mov [pExitProc].sel, dx
|
|
or ax, dx
|
|
pop ax
|
|
jnz CW_WEP
|
|
CW_noWEP:
|
|
jmps CW_noWEP1
|
|
|
|
CW_WEP:
|
|
cmp WEPVAL,2 ; If I'm just looking for WEP
|
|
jz CW_OK ; return 0
|
|
|
|
inc ax
|
|
test ds:[ne_flags], NEWEPME ; don't call wep if libmain
|
|
jz CW_noWEP ; wasn't called
|
|
|
|
and ds:[ne_flags], NOT NEWEPME ; only call WEP once
|
|
|
|
SetKernelDSNRES ; Save old GP chaine
|
|
pusha
|
|
push lpGPChain.sel
|
|
push lpGPChain.off
|
|
push cs
|
|
push offset cw_BlowChunks
|
|
mov lpGPChain.sel, ss ; and insert self in the chain
|
|
mov lpGPChain.off, sp
|
|
UnSetKernelDS
|
|
|
|
mov ax, ss
|
|
mov ds, ax
|
|
mov es, ax
|
|
mov bogusIBMAppSP,sp ; Save sp cause some apps (Hollywood)
|
|
; don't retf 2 correctly when we
|
|
; call their wep
|
|
cCall pExitProc, <WEPVal> ; fSystemExit
|
|
|
|
mov sp,bogusIBMAppSp
|
|
|
|
add sp, 4 ; remove the CS:IP for error handler
|
|
cw_BlowChunks:
|
|
SetKernelDSNRES
|
|
pop lpGPChain.off ; restore GPChain
|
|
pop lpGPChain.sel
|
|
popa
|
|
UnSetKernelDS
|
|
CW_OK:
|
|
xor ax, ax
|
|
|
|
CW_noWEP1:
|
|
cmp WEPVAL, 2 ; if we checked for whining
|
|
jnz CW_done
|
|
or ax, ax ; if we found, then OK
|
|
jz CW_done
|
|
cmp ax, NoWepErr ; anything other than NoWep is OK
|
|
jz CW_done
|
|
xor ax, ax
|
|
|
|
CW_done:
|
|
cEnd
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; LoadModule ;
|
|
; ;
|
|
; Loads a module or creates a new instance of an existing module. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; FARP p = name of module or handle of existing module ;
|
|
; FARP lpPBlock = Parameter Block to pass to CreateTask ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = instance handle or module handle ;
|
|
; ;
|
|
; Error Returns: ;
|
|
;LME_MEM = 0 ; Out of memory ;
|
|
;LME_FNF = 2 ; File not found
|
|
;LME_LINKTASK = 5 ; can't link to task ;
|
|
;LME_LIBMDS = 6 ; lib can't have multiple data segments ;
|
|
;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_RMODE = 15 ; not a pmode windows app ;
|
|
;LME_APPMDS = 16 ; multiple data segments in app ;
|
|
;LME_EMS = 17 ; scum app in l-frame EMS ;
|
|
;LME_PMODE = 18 ; not an rmode windows app ;
|
|
;LME_INVCOMP = 20 ; invalid DLL caused fail of EXE load ;
|
|
;LME_PE32 = 21 ; Windows Portable EXE app - let them load it ;
|
|
;LME_MAXERR = 32 ; for comparisons ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; DI, SI, DS ;
|
|
; Registers Destroyed: ;
|
|
; BX, CX, DX, ES ;
|
|
; ;
|
|
; Calls: ;
|
|
; AllocAllSegs ;
|
|
; CreateInsider ;
|
|
; DecExeUsage ;
|
|
; DelModule ;
|
|
; FindExeFile ;
|
|
; FindExeInfo ;
|
|
; FreeModule ;
|
|
; GetExePtr ;
|
|
; GetInstance ;
|
|
; GetStringPtr ;
|
|
; IncExeUsage ;
|
|
; LoadExeHeader ;
|
|
; LoadModule ;
|
|
; FarLoadSegment ;
|
|
; lstrlen ;
|
|
; FarMyFree ;
|
|
; MyOpenFile ;
|
|
; PreloadResources ;
|
|
; StartModule ;
|
|
; _lclose ;
|
|
; ;
|
|
; History: ;
|
|
; Sun 12-Nov-1989 14:19:04 -by- David N. Weise [davidw] ;
|
|
; Added the check for win87em. ;
|
|
; ;
|
|
; Fri 07-Apr-1989 23:15:42 -by- David N. Weise [davidw] ;
|
|
; Added support for task ExeHeaders above The Line in Large ;
|
|
; Frame EMS. ;
|
|
; ;
|
|
; Tue Oct 13, 1987 05:00:00p -by- David J. Habib [davidhab] ;
|
|
; Added check for FAPI applications. ;
|
|
; ;
|
|
; Sat Jul 18, 1987 12:04:15p -by- David N. Weise [davidw] ;
|
|
; Added support for multiple instances in different EMS banks. ;
|
|
; ;
|
|
; Tue Jan 01, 1980 06:57:01p -by- David N. Weise [davidw] ;
|
|
; ReWrote it from C into assembly. ;
|
|
; ;
|
|
; Wed Sep 17, 1986 03:31:06p -by- Charles Whitmer [chuckwh] ;
|
|
; Modified the original LoadModule code to only allow INSIDERs to ;
|
|
; allocate segments for a new process. An INSIDER is a new process ;
|
|
; stub which bootstraps up a new instance of an application. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc ILoadLibrary,<PUBLIC,FAR>
|
|
parmD pLibName
|
|
localV szExitProc,4
|
|
cBegin
|
|
mov ax,-1
|
|
cCall <far ptr LoadModule>,<pLibName,ax,ax>
|
|
cmp ax, LME_INVEXE ; Invalid format?
|
|
jnz @F
|
|
mov ax, LME_INVCOMP ; Invalid component
|
|
@@:
|
|
if KDEBUG
|
|
SetKernelDSNRes
|
|
cmp fBooting, 0
|
|
jne ll_fail ; No check while booting
|
|
cmp ax, LME_MAXERR
|
|
jb ll_fail ; No library, so no WEP()
|
|
|
|
push ax ; Now check for WEP
|
|
cCall GetExePtr,<ax>
|
|
mov es, ax
|
|
test es:[ne_flags],NEPROT ; ignore for OS/2 apps
|
|
jnz ll_noWhine
|
|
cmp es:[ne_usage], 0
|
|
jne ll_noWhine ; Only check on first load!
|
|
push dx
|
|
push ax
|
|
cCall CallWEP,<ax,2> ; Just check for WEP, don't call it
|
|
or ax, ax
|
|
pop ax
|
|
pop dx
|
|
jz ll_noWhine
|
|
trace_out "No WEP in library - > %AX0 %AX1"
|
|
; fkerror 0,<No WEP in library - >,ax,dx
|
|
ll_noWhine:
|
|
pop ax ; return value of LoadModule
|
|
|
|
ll_fail:
|
|
endif ; KDEBUG
|
|
cEnd
|
|
|
|
|
|
|
|
os2calls DB 'DOSCALLS' ; Used for FAPI detection
|
|
mgxlib DB 'MGXLIB' ; Used for lib large entry table detection
|
|
win87em DB 'WIN87EM.DLL',0 ; Used for win87em.exe detection
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
?SAV5 = ?DOS5 ; Adobe Type Manager check the LoadModule
|
|
?DOS5 = 0 ; prolog and expects to see INC BP there...
|
|
|
|
public LMAlreadyLoaded, LMLoadExeFile, LMCheckHeader, LMRamNMods
|
|
public LMImports, LMSegs, LMLetsGo, LMPrevInstance, LMCleanUp
|
|
|
|
cProc ILoadModule,<PUBLIC,FAR>,<di,si>
|
|
parmD lpModuleName
|
|
parmD lpPBlock
|
|
localW fh ; close if failed
|
|
localW pExe ; point to NE header in RAM
|
|
; localW hExe ; prev module if already loaded
|
|
localW hResult ; temp return value
|
|
localW hDepFail ; return of implicit link loads
|
|
localW abortresult ; temp return value
|
|
localW ffont ; flag if loading a *.fon
|
|
localW fexe ; flag if loading a *.exe
|
|
ifdef notyet
|
|
localW dll ; flag if loading a *.dll
|
|
endif
|
|
localW hBlock ; fastload block from LoadExeHeader
|
|
localW AllocAllSegsRet
|
|
localW exe_type ; from LoadExeHeader
|
|
localW hTDB ; dx from CloseApplEnv
|
|
localW SavePDB ; save caller's pdb, switch to krnl's
|
|
localW fWOA ; save flag if we're loading WOA
|
|
ifdef WOW
|
|
LocalD pszKnownDLLPath
|
|
LocalW fKnownDLLOverride
|
|
localW RefSelector
|
|
localW LMHadPEDLL
|
|
localW hPrevInstance ; previous 16-bit module handel with the same name
|
|
endif
|
|
localD FileOffset ; offset to start of ExeHdr
|
|
localW OnHardDisk ; don't cache FH if on floppy
|
|
localV namebuf,136 ; SIZE OPENSTRUC + 127
|
|
localW fModCompatFlags ; used by LMRamNMods
|
|
|
|
|
|
cBegin
|
|
SetKernelDSNRES
|
|
|
|
mov al,Kernel_Flags[1] ; solve re-entrancy #10759
|
|
and ax,KF1_WINOLDAP
|
|
mov fWOA,ax
|
|
and Kernel_Flags[1],NOT KF1_WINOLDAP
|
|
|
|
inc fLMdepth ; # current invocations
|
|
|
|
;** Log this entry only if in diagnostic mode
|
|
mov ax, fDiagMode ; Only log if booting and diag mode
|
|
and al, fBooting
|
|
jz @F
|
|
|
|
;** Write out the string
|
|
mov ax,dataOFFSET szLoadStart ; Write the string
|
|
cCall DiagOutput, <ds,ax>
|
|
push WORD PTR lpModuleName[2]
|
|
push WORD PTR lpModuleName[0]
|
|
cCall DiagOutput
|
|
mov ax,dataOFFSET szCRLF
|
|
cCall DiagOutput, <ds,ax>
|
|
|
|
; Zero out flags and handles
|
|
@@:
|
|
ifdef WOW
|
|
mov LMHadPEDLL,0
|
|
mov hPrevInstance,0
|
|
lm_restart:
|
|
endif
|
|
xor ax,ax
|
|
; mov hExe,ax
|
|
mov pExe,ax
|
|
mov abortresult,ax ; default 0 == out of memory
|
|
mov ffont,ax
|
|
mov fexe,ax
|
|
ifdef notyet
|
|
mov dll,ax
|
|
endif
|
|
mov hBlock,ax
|
|
mov hTDB,ax
|
|
|
|
; Set DOS_FLAG to EXEC_OPEN
|
|
SET_DOS_FLAG_EXEC_OPEN
|
|
|
|
; Some flags are default -1
|
|
dec ax
|
|
mov fh, ax
|
|
mov SavePDB, ax
|
|
|
|
; First, see if we were passed in a handle in the filename
|
|
les si,lpModuleName ; point to the file name
|
|
mov ax,es
|
|
or ax,ax ; Was a handle passed in low word?
|
|
jnz @F
|
|
cCall GetExePtr,<si> ; Valid handle?
|
|
or ax, ax
|
|
jnz prev_instance
|
|
mov al, LME_FNF ; call this file not found??
|
|
jmp ilm_ret
|
|
|
|
; No handle, see if filename is already loaded
|
|
@@: call LMAlreadyLoaded ; es:si -> modname on stack
|
|
cmp ax, LME_MAXERR
|
|
jb @F ; Not found, try to load it
|
|
|
|
; a 16-bit module with the same name is loaded
|
|
; if module is being loaded is a dll, use the loaded instance
|
|
; else if module is being loaded is a task
|
|
; if it is a 32-bit task then load it from disk
|
|
; else use the loaded instance
|
|
|
|
|
|
ifdef WOW
|
|
mov hPrevInstance, ax ; store previous instance handle
|
|
mov ax,lpPBlock.off ; check if this is a dll or a task
|
|
and ax,lpPBlock.sel
|
|
inc ax
|
|
jnz @F ; non-zero means it is a task
|
|
; so check first if it is a 16-bit task
|
|
prev_instance_16task:
|
|
mov ax, hPrevInstance
|
|
endif
|
|
prev_instance:
|
|
call LMPrevInstance
|
|
jmp ilm_ret
|
|
|
|
; Wasn't loaded, see if we can load it
|
|
@@: call LMLoadExeFile ; fh in DI, AX = 0 or error code
|
|
or ax, ax
|
|
jz @F
|
|
jmp ilm_ret ; can't find it - return error
|
|
@@:
|
|
|
|
; Here to deal with a new library or task module.
|
|
; We found the file, now load and scan the header
|
|
@@: lea si,namebuf
|
|
cCall LoadExeHeader,<di,di,ss,si>
|
|
ifdef WOW
|
|
cmp ax,LME_PE
|
|
jne @F
|
|
; If we find the module is a Win32 binary (PE), check to see
|
|
; if we're trying to load a task or DLL. If it's a DLL
|
|
; we will continue searching for a Win16 copy of this DLL
|
|
; on the path. If we're unsuccessful we'll eventually
|
|
; munge the file not found error code back to LME_PE.
|
|
|
|
mov ax,lpPBlock.off
|
|
and ax,lpPBlock.sel
|
|
inc ax
|
|
mov ax,LME_PE
|
|
jnz @F ; have a PBlock, must be doing LoadModule
|
|
cmp LMHadPEDLL,0
|
|
je lm_retry_pe
|
|
mov LMHadPEDLL,0
|
|
mov OFContinueSearch,0
|
|
KernelLogError <DBF_WARNING>,ERR_LOADMODULE,"Found Win32 DLL again after continuing search."
|
|
jmps ilm_ret
|
|
@@: jmps @F
|
|
lm_retry_pe:
|
|
; Tell OpenFile to restart last search at next search location.
|
|
mov OFContinueSearch,1
|
|
mov LMHadPEDLL,1
|
|
KernelLogError <DBF_WARNING>,ERR_LOADMODULE,"Found Win32 DLL, continuing search for Win16 copy."
|
|
; Close open Win32 DLL file handle
|
|
cCall My_lclose,<fh>
|
|
; Switch back to caller's PDB
|
|
mov si, -1
|
|
xchg si, SavePDB
|
|
mov Win_PDB, si
|
|
or fh, -1
|
|
jmp lm_restart
|
|
@@:
|
|
endif
|
|
cmp ax,LME_MAXERR
|
|
jb ilm_ret
|
|
|
|
ifdef WOW
|
|
cmp hPrevInstance, 0 ; if there is a previous 16-bit task
|
|
je @F ;
|
|
cCall My_lclose,<fh> ; close opened file before invoking previous instance
|
|
jmp prev_instance_16task
|
|
endif
|
|
; Header is loaded, now see if valid for Windows
|
|
@@: call LMCheckHeader
|
|
cmp ax, LME_MAXERR
|
|
jb ilm_ret
|
|
|
|
; Now allocate segs, check for special modules, etc
|
|
@@: call LMRamNMods
|
|
cmp ax, LME_MAXERR
|
|
jb ilm_ret
|
|
|
|
; Load import libraries (scary code here)
|
|
@@: call LMImports
|
|
cmp ax, LME_MAXERR
|
|
jb ilm_ret
|
|
|
|
; Load and relocate segments
|
|
@@: call LMSegs
|
|
cmp ax, LME_MAXERR
|
|
jb ilm_ret
|
|
|
|
; Load resources, schedule execution
|
|
@@: call LMLetsGo
|
|
|
|
; Everyone comes through ILM_RET - we free the fastload block, etc
|
|
ilm_ret:
|
|
call LMCleanUp
|
|
jmp LoadModuleEnd
|
|
|
|
|
|
abort_load0:
|
|
pop fLMdepth
|
|
abort_load:
|
|
cmp fLMdepth, 1 ; If a recursive call, nothing
|
|
jne abort_load_A ; has been incremented!
|
|
cCall DecExeUsage,<pExe>
|
|
abort_load_A:
|
|
cCall My_lclose,<fh>
|
|
mov es,pExe
|
|
push es:[ne_flags]
|
|
cCall DelModule,<es>
|
|
mov pExe, 0
|
|
pop bx
|
|
abort_load_B: ; If app, close environment
|
|
test bx,NENOTP
|
|
jnz lm_ab
|
|
mov si, -1
|
|
xchg si, SavePDB ; Saved PDB?
|
|
inc si
|
|
jz @F ; nope.
|
|
dec si
|
|
mov Win_PDB, si ; yes, restore it
|
|
@@:
|
|
mov si, fLMdepth
|
|
mov fLMdepth, 0
|
|
cCall CloseApplEnv,<abortresult,es>
|
|
mov fLMdepth, bx
|
|
lm_ab: mov ax, abortresult
|
|
retn
|
|
; add sp, 2
|
|
; jmps ilm_ret ; ax = abortresult. (0 normal, 11 fapi)
|
|
|
|
|
|
ifdef WOW
|
|
winspool db "WINSPOOL.EXE" ; Trying to Load Winspool ?
|
|
size_winspool equ $-winspool
|
|
db 0h ; NULL Terminate
|
|
|
|
endif ;WOW
|
|
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; LMAlreadyLoaded - internal routine for LoadModule
|
|
; See if a module is already loaded by looking for the file name
|
|
; or the module name.
|
|
; Entry:
|
|
; ES:SI points to filename
|
|
; Exit:
|
|
; AX = handle of previous instance
|
|
; SS:SI -> uppercase filename
|
|
; Error:
|
|
; AX = error value < LME_MAXERR
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
LMAlreadyLoaded:
|
|
; We check if this Module is already loaded. To do so we get the
|
|
; name off of the end of the string, omitting the extension.
|
|
|
|
krDebugOut <DEB_TRACE OR DEB_KrLoadMod>, "Loading @ES:SI"
|
|
cCall lstrlen,<es,si> ; Get the length of the string.
|
|
or ax,ax ; NULL string?
|
|
jnz @F
|
|
mov al,LME_FNF ; return file not found error
|
|
retn
|
|
|
|
ifdef FE_SB
|
|
;
|
|
; Backword search '\' or ':' is prohibited for DBCS version of
|
|
; Windows. Some DBCS 2nd byte may have '\' or ':'. So we search
|
|
; these characters from beginning of string.
|
|
;
|
|
@@:
|
|
cld
|
|
mov bx,si
|
|
delinator_loop_DBC:
|
|
lods byte ptr es:[si] ; fetch a character
|
|
test al,al
|
|
jz found_end_DBC
|
|
cmp al,"\"
|
|
jz found_delinator_DBC
|
|
cmp al,'/'
|
|
jz found_delinator_DBC
|
|
cmp al,":"
|
|
jz found_delinator_DBC
|
|
call FarMyIsDBCSLeadByte ; see if char is DBC...
|
|
jc delinator_loop_DBC
|
|
inc si ; skip 2nd byte of DBC
|
|
jmp delinator_loop_DBC
|
|
|
|
found_delinator_DBC:
|
|
mov bx,si ; update delinator pointer
|
|
jmp delinator_loop_DBC
|
|
found_end_DBC:
|
|
mov si, bx ; ES:SI -> beginning of name..
|
|
else
|
|
@@: mov cx,ax
|
|
add si,ax
|
|
dec si ; ES:SI -> end of string
|
|
std
|
|
delineator_loop: ; look for beginning of name
|
|
lods byte ptr es:[si]
|
|
cmp al,"\"
|
|
jz found_delineator
|
|
cmp al,'/'
|
|
jz found_delineator
|
|
cmp al,":"
|
|
jz found_delineator
|
|
loop delineator_loop
|
|
dec si
|
|
found_delineator: ; ES:SI -> before name
|
|
cld
|
|
inc si
|
|
inc si ; ES:SI -> beginning of name
|
|
endif
|
|
xor di,di
|
|
xor bx,bx
|
|
copy_name_loop:
|
|
lods byte ptr es:[si] ; Copy and capitalize to temp buffer.
|
|
or al,al
|
|
jz got_EXE_name
|
|
cmp al,"."
|
|
jne @F
|
|
lea bx,namebuf[di]
|
|
ifdef notyet
|
|
cmp dll, 0 ; Was it .DLL and failed to open it?
|
|
jz @F ; no, no hacking
|
|
mov byte ptr es:[si], 'E' ; yes, change it to .EXE
|
|
mov word ptr es:[si+1],'EX'
|
|
mov dll, 0
|
|
endif
|
|
@@:
|
|
ifdef FE_SB
|
|
;
|
|
; Do not capitalize if a character is DBC.
|
|
;
|
|
call FarMyIsDBCSLeadByte
|
|
jnc @F
|
|
call FarMyUpper ; capitalize if SBC..
|
|
jmps is_a_SBC
|
|
@@:
|
|
mov namebuf[di],al
|
|
inc di
|
|
lods byte ptr es:[si] ; copy 2nd byte also
|
|
is_a_SBC:
|
|
mov namebuf[di],al
|
|
else
|
|
call FarMyUpper
|
|
mov namebuf[di],al
|
|
endif
|
|
inc di
|
|
jmps copy_name_loop
|
|
|
|
; Finally call FindExeInfo to see if it's already loaded!
|
|
|
|
got_EXE_name:
|
|
cmp namebuf[di][-2],'NO' ; .fons are allowed to be
|
|
jnz @F ; non protect mode
|
|
cmp namebuf[di][-4],'F.'
|
|
jnz @F
|
|
mov ffont,bp ; make non-zero
|
|
@@:
|
|
cmp namebuf[di][-2],'EX' ; .exes will not get
|
|
jnz @F ; prompted
|
|
cmp namebuf[di][-4],'E.'
|
|
jnz @F
|
|
mov fexe,bp ; make non-zero
|
|
@@:
|
|
ifdef NOTYET
|
|
cmp namebuf[di][-2],'LL'
|
|
jne @F
|
|
cmp namebuf[di][-4],'D.'
|
|
jne @F
|
|
mov dll, di
|
|
@@:
|
|
endif
|
|
ifdef WOW
|
|
|
|
; apps will expect to find WINSPOOL.DRV, which is a 32-bit driver.
|
|
; we need to intercept this and change it WINSPOOL.EXE, which is our 16-bit
|
|
; stub that contains a few entrypoints.
|
|
|
|
if 0
|
|
; Bitstreams's MakeUp extracts the printer driver from the [devices]
|
|
; section of win.ini the line looks like this:
|
|
; HP Laserjet Series II=winspool,FILE:
|
|
; and then it calls LoadLibrary(drivername) ie LoadLibrary("winspool")
|
|
; so we need to allow no extension when checking for "winspool"
|
|
endif
|
|
|
|
cmp namebuf[di][-2],'VR'
|
|
jne checkfornoext
|
|
cmp namebuf[di][-4],'D.'
|
|
jne @f
|
|
|
|
jmp short gotadrv
|
|
|
|
checkfornoext:
|
|
; int 3
|
|
cmp di,8
|
|
jc @f
|
|
cmp namebuf[di][-2],'LO'
|
|
jne @f
|
|
cmp namebuf[di][-4],'OP'
|
|
jne @f
|
|
cmp namebuf[di][-6],'SN'
|
|
jne @f
|
|
cmp namebuf[di][-8],'IW'
|
|
jne @f
|
|
|
|
; the last 8 characters are 'WINSPOOL'. tack on '.EXE' and proceed.
|
|
|
|
add di,4
|
|
mov namebuf[di][-2],'EX' ; Changed Uppercased String
|
|
mov namebuf[di][-4],'E.'
|
|
|
|
push cx
|
|
mov lpModuleName.hi,cs
|
|
lea cx,winspool ;
|
|
mov lpModuleName.lo,cx
|
|
pop cx
|
|
jmp short @f
|
|
|
|
gotadrv:
|
|
push es
|
|
push ds
|
|
push si
|
|
push cx
|
|
push di
|
|
|
|
smov es,ss
|
|
lea di,namebuf[di][-(size_winspool)]
|
|
smov ds,cs
|
|
lea si,winspool
|
|
mov cx,size_winspool-4 ; match WINSPOOL?
|
|
rep cmpsb
|
|
|
|
pop di
|
|
jnz not_winspool
|
|
|
|
mov namebuf[di][-2],'EX' ; Changed Uppercased String
|
|
mov namebuf[di][-4],'E.'
|
|
|
|
mov lpModuleName.hi,cs ; Used by Myopenfile below
|
|
lea cx,winspool ;
|
|
mov lpModuleName.lo,cx
|
|
|
|
not_winspool:
|
|
pop cx
|
|
pop si
|
|
pop ds
|
|
pop es
|
|
@@:
|
|
endif; WOW
|
|
mov namebuf[di],al ; Null terminate file name
|
|
lea si,namebuf
|
|
push bx
|
|
cCall FindExeFile,<ss,si>
|
|
pop bx
|
|
or ax,ax
|
|
jnz al_end
|
|
or bx,bx ; extension specified?
|
|
jz @F ; No, DI correct then
|
|
sub bx,si ; DI = length of name portion
|
|
mov di,bx
|
|
@@:
|
|
cCall FindExeInfo,<ss,si,di>
|
|
al_end:
|
|
retn
|
|
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; LMLoadExeFile - internal routine for LoadModule
|
|
; Try to open an EXE file
|
|
; Enter:
|
|
; SS:SI -> uppercase filename
|
|
; Exit:
|
|
; AX=0
|
|
; DI = fh = handle of open EXE file
|
|
; Error:
|
|
; AX = error code
|
|
; Effects:
|
|
; Set Win_PDB to kernel PDB to open the file
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
; if here then not yet loaded, see if we can open the file
|
|
LMLoadExeFile:
|
|
mov ax, topPDB
|
|
xchg Win_PDB, ax ; Switch to Kernel's PDB,
|
|
mov SavePDB, ax ; saving current PDB
|
|
xor ax,ax
|
|
ifdef notyet
|
|
cmp dll, ax ; Don't prompt for .DLL, if it fails we
|
|
jnz @F ; try for .EXE which we will prompt for
|
|
endif
|
|
cmp fexe,ax ; Don't prompt for EXE file
|
|
jnz @F
|
|
mov ax,OF_CANCEL ; If DLL, let them cancel
|
|
mov es,curTDB
|
|
test es:[TDB_ErrMode],08000h ; did app say not to prompt??
|
|
jnz @F
|
|
mov ax,OF_CANCEL or OF_PROMPT
|
|
@@:
|
|
if SHARE_AWARE
|
|
or ax, OF_NO_INHERIT or OF_SHARE_DENY_WRITE
|
|
else
|
|
or ax, OF_NO_INHERIT
|
|
endif
|
|
ifdef WOW
|
|
; Ask WOW32 to check the filename to see if it is
|
|
; a Known DLL,
|
|
;
|
|
; If it is, WowIsKnownDLL will point pszKnownDLLPath
|
|
; at a just-allocated buffer with the full path to
|
|
; the DLL in the system32 directory and return with
|
|
; AX nonzero. This buffer must be freed with a
|
|
; call to WowIsKnownDLL with the filename pointer
|
|
; zero, and pszKnownDLLPath as it was left by the
|
|
; first call to WowIsKnownDLL.
|
|
;
|
|
; If it's not a known DLL, pszKnownDLLPath will be
|
|
; NULL and AX will be zero.
|
|
|
|
push ax
|
|
cmp fBooting,0 ; Known DLLs take effect
|
|
je lef_look_for_known_dll ; after booting is complete.
|
|
|
|
mov fKnownDLLOverride,0 ; We're booting, make sure
|
|
jmps lef_dll_not_known ; we know not to call
|
|
; WowIsKnownDLL the second time.
|
|
|
|
lef_look_for_known_dll:
|
|
push si
|
|
smov es,ss
|
|
lea bx,pszKnownDLLPath
|
|
cCall WowIsKnownDLL,<lpModuleName,esbx>
|
|
mov fKnownDLLOverride,ax
|
|
cmp ax,0
|
|
pop si
|
|
je lef_dll_not_known
|
|
|
|
pop ax
|
|
cCall MyOpenFile,<pszKnownDLLPath,ss,si,ax>
|
|
jmps @f
|
|
|
|
lef_dll_not_known:
|
|
pop ax
|
|
cCall MyOpenFile,<lpModuleName,ss,si,ax>
|
|
@@:
|
|
else
|
|
cCall MyOpenFile,<lpModuleName,ss,si,ax>
|
|
endif
|
|
|
|
ifdef notyet
|
|
mov di, dll
|
|
or di, di
|
|
jz no_second_chance
|
|
cmp ax, -1
|
|
jne no_second_chance ; open succeeded
|
|
xchg ax, SavePDB ; Restore original PDB (AX == -1)
|
|
mov Win_PDB, ax
|
|
les si, lpModuleName
|
|
pop ax
|
|
jmp pointer_to_name ; Start again!
|
|
no_second_chance:
|
|
endif
|
|
xor dh, dh
|
|
mov dl, ss:[si].opDisk
|
|
mov OnHardDisk, dx
|
|
mov fh,ax
|
|
mov di,ax ; DI gets preserved, AX doesn't!
|
|
inc ax ; -1 means error or invalid parsed file
|
|
mov ax, 0
|
|
jnz @F ; OK, return 0
|
|
; MyOpenFile failed
|
|
mov ax,ss:[si].[opXtra] ; SI = &namebuf
|
|
or ax,ax ; What is the error value?
|
|
jnz @F
|
|
mov ax,LME_FNF ; unknown, call it file not found
|
|
@@:
|
|
ifdef WOW
|
|
push ax
|
|
mov ax,fKnownDLLOverride
|
|
cmp ax,0
|
|
je lef_no_need_to_free
|
|
|
|
push bx
|
|
push dx
|
|
push di
|
|
|
|
smov es,ss
|
|
lea bx,pszKnownDLLPath
|
|
cCall WowIsKnownDLL, <0,0,esbx>
|
|
|
|
pop di
|
|
pop dx
|
|
pop bx
|
|
lef_no_need_to_free:
|
|
pop ax
|
|
endif
|
|
retn
|
|
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; LMCheckHeader - internal routine for LoadModule
|
|
; Loading new module - see if header values are OK
|
|
; Enter:
|
|
; ax = exeheader in RAM
|
|
; bx = 0 or FastLoad ram block selector
|
|
; cx = file offset of header
|
|
; dx = exe_type
|
|
; Exit:
|
|
;
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
LMCheckHeader:
|
|
mov exe_type,dx
|
|
mov hBlock,bx ; fast-load block
|
|
mov pExe,ax ; exeheader in RAM
|
|
mov es,ax
|
|
mov ax, cx ; file offset of header
|
|
mov cx, es:[ne_align]
|
|
mov bx, ax ; BX:AX <= AX shl CL
|
|
shl ax, cl
|
|
neg cl
|
|
add cl, 16
|
|
shr bx, cl
|
|
|
|
mov FileOffset.sel, bx
|
|
mov FileOffset.off, ax
|
|
|
|
; Is this module PMode-compatible?
|
|
cmp es:[ne_expver],300h ; by definition
|
|
jae @F
|
|
test dh,NEINPROT ; by flag
|
|
jnz @F
|
|
cmp ffont,0 ; are we loading a font?
|
|
jnz @F
|
|
mov cx,ss
|
|
lea bx,namebuf
|
|
call WarnRealMode
|
|
cmp ax,IDCANCEL
|
|
jnz @F ; yes, user says so
|
|
mov ax, LME_RMODE ; no, die you pig
|
|
retn
|
|
|
|
ifdef WOW
|
|
@@:
|
|
;
|
|
; if WOA invoked by app (not fWOA) fail it
|
|
;
|
|
cmp fWOA,0 ; fWOA
|
|
jnz @F
|
|
|
|
cld
|
|
push si
|
|
push di
|
|
mov di, es:[ne_restab]
|
|
inc di
|
|
mov si, dataOffset WOAName
|
|
mov cx, 4
|
|
repe cmpsw
|
|
pop di
|
|
pop si
|
|
jnz @F
|
|
mov ax, LME_WOAWOW32
|
|
retn
|
|
endif
|
|
|
|
; Are we dynalinking to a task?
|
|
@@:
|
|
|
|
|
|
test es:[ne_flags],NENOTP
|
|
jnz ch_not_a_process
|
|
or es:[ne_flags],NEINST ; for safety sake
|
|
mov ax,lpPBlock.off
|
|
and ax,lpPBlock.sel
|
|
inc ax
|
|
jnz ch_new_application ; not linking
|
|
mov ax, LME_LINKTASK
|
|
retn
|
|
|
|
; Error if multiple instance EXE is a library module.
|
|
ch_not_a_process:
|
|
mov ax, 33 ; Any value > 32
|
|
test es:[ne_flags],NEPROT ; is it an OS/2 exe?
|
|
jnz ch_ok ; windows doesn't do this right
|
|
test es:[ne_flags],NEINST
|
|
jz ch_ok
|
|
mov ax, LME_LIBMDS ; I think this error code is wrong
|
|
ch_ok:
|
|
retn
|
|
|
|
; Create environment for new application task.
|
|
ch_new_application:
|
|
call LMCheckHeap
|
|
or ax,ax
|
|
jz @F
|
|
cCall OpenApplEnv,<lpPBlock,pExe,fWOA>
|
|
mov es,pExe
|
|
or ax,ax ; AX is a selector, therefor > 32
|
|
jnz ch_ok
|
|
@@:
|
|
jmp abort_load_A
|
|
|
|
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; LMRamNMods - internal routine for LoadModule
|
|
; Load segments, check for special modules
|
|
; Enter:
|
|
; EX = pexe
|
|
|
|
|
|
; Exit:
|
|
; CX = number of import modules
|
|
; AX = status
|
|
;
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
LMRamNMods:
|
|
push es
|
|
cCall AddModule,<pExe>
|
|
pop es
|
|
or ax,ax
|
|
jnz @F
|
|
push es:[ne_flags] ; AddModule failed - out of memory
|
|
mov dx,ne_pnextexe
|
|
mov bx,dataOffset hExeHead
|
|
call FarUnlinkObject
|
|
pop bx
|
|
jmp abort_load_B ; clean this up
|
|
|
|
@@:
|
|
cmp es:[ne_expver],400h
|
|
jae rm_skip_modulecompat
|
|
|
|
; Look for Module in ModuleCompatibilty section
|
|
; and get its compat flags
|
|
push es ; save es
|
|
push ds
|
|
push dataoffset szModuleCompatibility
|
|
push es
|
|
mov bx,es:[ne_restab] ; module name is 1st rsrc
|
|
inc bx ; Skip length byte
|
|
push bx
|
|
xor ax, ax
|
|
push ax ; default = 0
|
|
call GetProfileInt
|
|
@@:
|
|
pop es ; restore es
|
|
; Set the module's patch bit if the INI file says to.
|
|
if KDEBUG
|
|
test es:[ne_flagsothers], NEHASPATCH
|
|
jz @F
|
|
push ax
|
|
mov ax, es:[ne_restab]
|
|
inc ax
|
|
krDebugOut DEB_TRACE,"ILoadModule: module patch bit for @es:ax already set, clearing it"
|
|
pop ax
|
|
@@:
|
|
endif
|
|
and es:[ne_flagsothers], not NEHASPATCH ; clear module patch bit
|
|
ifdef WOW_x86
|
|
test ax, MCF_MODPATCH + MCF_MODPATCH_X86
|
|
else
|
|
test ax, MCF_MODPATCH + MCF_MODPATCH_RISC
|
|
endif
|
|
jz rm_after_modpatch
|
|
if KDEBUG
|
|
push ax
|
|
mov ax, es:[ne_restab]
|
|
inc ax
|
|
krDebugOut DEB_WARN,"ILoadModule: setting module patch bit for @es:ax"
|
|
pop ax
|
|
endif
|
|
or es:[ne_flagsothers], NEHASPATCH
|
|
rm_after_modpatch:
|
|
|
|
; See if we need to make the module's segments not discardable
|
|
test ax, MCF_NODISCARD
|
|
jz rm_after_nodiscard
|
|
|
|
mov cx, es:[ne_cseg] ; cx = number of segs
|
|
jcxz rm_after_nodiscard
|
|
mov bx, es:[ne_segtab] ; es:bx = seg table start
|
|
rm_loop:
|
|
and es:[bx].ns_flags, not NSDISCARD ; clear the discard flag
|
|
add bx, SIZE NEW_SEG1 ; es:bx = seg table next entry
|
|
loop rm_loop
|
|
rm_after_nodiscard:
|
|
|
|
rm_skip_modulecompat:
|
|
|
|
mov bx, -1
|
|
cCall FarGetCachedFileHandle,<es,bx,fh> ; Set file handle cache up
|
|
mov fh, bx ; Use cached file handle from now
|
|
xchg SavePDB, bx ; Back to original PDB (BX == -1)
|
|
mov Win_PDB, bx
|
|
@@: xor bx,bx
|
|
mov hDepFail,-1 ; Assume success
|
|
mov cx,es:[bx].ne_cmod
|
|
jcxz @F
|
|
test kernel_flags,KF_pUID ; All done booting?
|
|
jnz @F ; Yes
|
|
or es:[bx].ne_flags,NEALLOCHIGH ; No, GDI and USER are party
|
|
; dynlinks that can alloc high
|
|
@@: xor ax,ax
|
|
IFNDEF NO_APPLOADER
|
|
test es:[ne_flags],NEAPPLOADER
|
|
jnz rm_no_segs_to_alloc
|
|
ENDIF
|
|
cmp ax,es:[ne_cseg]
|
|
jz rm_no_segs_to_alloc
|
|
push es
|
|
mov es:[ne_usage],1
|
|
cCall AllocAllSegs,<es> ; AX is count of segs
|
|
pop es
|
|
mov es:[ne_usage],8000h
|
|
inc ax
|
|
jnz @F
|
|
jmp abort_load
|
|
@@:
|
|
dec ax
|
|
rm_no_segs_to_alloc:
|
|
mov AllocAllSegsRet, ax
|
|
|
|
xor bx, bx
|
|
mov di,es:[bx].ne_modtab ; ES:DI = pModIdx
|
|
mov cx,es:[bx].ne_cmod
|
|
or cx,cx
|
|
jz lm_ret_ok
|
|
|
|
; this small chunk of code goes thru the imported names table
|
|
; and looks for DOSCALLS. if DOSCALLS is found, then the app
|
|
; is an FAPI "bound" application and not a windows app, and
|
|
; loadmodule should return an error for "invalid format".
|
|
; This will force it to run in a DOS box
|
|
; coming in:
|
|
; cx = cmod
|
|
; di = modtab
|
|
|
|
test es:[bx].ne_flags,NENOTP ; only test apps, not libraries.
|
|
jnz lm_ret_ok
|
|
mov ax,exe_type ; UNKNOWN may be OS/2 in disguise.
|
|
cmp al,NE_UNKNOWN
|
|
jnz @F
|
|
push ds
|
|
smov ds,cs
|
|
mov ax,8
|
|
mov si,NRESCODEoffset os2calls ; DS:SI = "DOSCALLS"
|
|
call search_mod_dep_list
|
|
pop ds
|
|
jnc @F
|
|
mov abortresult,LME_INVEXE ; store invalid format code for return
|
|
jmp abort_load
|
|
|
|
; In order to make it easier on our ISV to migrate to pmode
|
|
; we must deal with win87em specially because the win 2.x
|
|
; version gp faults. Since we have never shipped them a clean
|
|
; one to ship with their apps we must compensate here.
|
|
; If we are loading a win 2.x app in pmode we force the load
|
|
; of win87em.dll. For compatibility in real mode we just load
|
|
; the one they would have gotten anyway.
|
|
|
|
@@: cmp es:[bx].ne_expver,300h ; no special casing win3.0 apps
|
|
jae rm_no_win87em_here
|
|
|
|
push ds
|
|
smov ds,cs
|
|
mov ax,7
|
|
mov si,NRESCODEoffset win87em ; DS:SI = "WIN87EM"
|
|
call search_mod_dep_list
|
|
pop ds
|
|
jnc rm_no_win87em_here
|
|
push bx ; Load Win87em.dll
|
|
push es
|
|
cCall ILoadLibrary,<cs,si>
|
|
cmp ax,LME_MAXERR
|
|
jae @F
|
|
mov hDepFail,ax
|
|
@@: pop es
|
|
pop bx
|
|
rm_no_win87em_here:
|
|
lm_ret_ok:
|
|
mov di,es:[bx].ne_modtab ; ES:DI = pModIdx
|
|
mov cx,es:[bx].ne_cmod ; What is AX?
|
|
mov ax, es
|
|
retn
|
|
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; LMImports - internal routine for LoadModule
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
LMImports:
|
|
or cx, cx
|
|
jnz im_inc_dependencies_loop
|
|
jmp im_end_dependency_loop
|
|
im_inc_dependencies_loop:
|
|
push cx
|
|
mov si,es:[di]
|
|
push es
|
|
or si,si
|
|
jz im_next_dependencyj
|
|
add si,es:[ne_imptab] ; ES:SI = pname
|
|
xor ax,ax
|
|
mov al,es:[si] ; get length of name
|
|
inc si
|
|
mov cx, ax
|
|
mov bx, es ; pExe
|
|
|
|
;;;; Load the imported library.
|
|
|
|
push ds ; Copy the name and .EXE to namebuf
|
|
push di
|
|
smov es,ss
|
|
mov ds,bx
|
|
UnSetKernelDS
|
|
lea di,namebuf
|
|
mov bx,di
|
|
cld
|
|
rep movsb
|
|
mov byte ptr es:[di], 0 ; Null terminate
|
|
push bx
|
|
push es
|
|
cCall GetModuleHandle,<es,bx>
|
|
pop es
|
|
pop bx
|
|
or ax, ax
|
|
jz @F
|
|
pop di
|
|
pop ds
|
|
jmps im_imported_exe_already_loaded
|
|
|
|
@@: cmp ds:[ne_expver], 300h ; USE .DLL for 3.0, .EXE for lower
|
|
jae im_use_dll
|
|
|
|
mov es:[di][0],"E."
|
|
mov es:[di][2],"EX"
|
|
jmps im_done_extension
|
|
im_use_dll:
|
|
mov word ptr ss:[di][0],"D."
|
|
mov word ptr ss:[di][2],"LL"
|
|
im_done_extension:
|
|
mov byte ptr es:[di][4],0
|
|
|
|
pop di
|
|
pop ds
|
|
ResetKernelDS
|
|
cCall ILoadLibrary,<ss,bx>
|
|
cmp ax,LME_MAXERR
|
|
jae im_imported_exe_loaded
|
|
mov hDepFail,ax
|
|
xor ax,ax
|
|
im_next_dependencyj:
|
|
jmps im_next_dependency
|
|
|
|
im_imported_exe_already_loaded:
|
|
;;; push ax
|
|
;;; cCall IncExeUsage,<ax>
|
|
;;; pop ax
|
|
|
|
im_imported_exe_loaded:
|
|
cCall GetExePtr,<ax>
|
|
mov es,ax
|
|
assumes es,nothing ; assume that dep libraries
|
|
or es:[ne_flags],NEALLOCHIGH ; are smart
|
|
|
|
im_next_dependency:
|
|
pop es
|
|
assumes es,nothing
|
|
mov es:[di],ax
|
|
inc di
|
|
inc di
|
|
pop cx
|
|
dec cx
|
|
jz im_end_dependency_loop
|
|
jmp im_inc_dependencies_loop
|
|
|
|
im_end_dependency_loop:
|
|
mov es:[ne_usage], 0
|
|
cmp fLMdepth, 1
|
|
jne @F
|
|
push es ; Now set usage count of this
|
|
cCall IncExeUsage,<es> ; module and dependants
|
|
pop es
|
|
@@:
|
|
mov cx,hDepFail
|
|
inc cx
|
|
jz im_libs_ok
|
|
dec cx
|
|
mov abortresult,cx
|
|
im_abort_loadj:
|
|
jmp abort_load
|
|
im_libs_ok:
|
|
retn
|
|
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; LMSegs - internal routine for LoadModule
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
LMSegs:
|
|
; Do something about all those segments in the module.
|
|
|
|
IFNDEF NO_APPLOADER
|
|
test es:[ne_flags],NEAPPLOADER
|
|
jz @F
|
|
;* * special boot for AppLoader
|
|
push Win_PDB
|
|
push fLMdepth
|
|
mov fLMdepth, 0
|
|
mov ax, -1
|
|
cCall FarGetCachedFileHandle,<es,ax,ax>
|
|
Save <es>
|
|
cCall BootAppl,<es, ax> ;* returns BOOL
|
|
cCall FlushCachedFileHandle,<es>
|
|
pop fLMdepth
|
|
pop Win_PDB
|
|
or ax,ax
|
|
jnz lms_done
|
|
jmp abort_load
|
|
; retn
|
|
@@:
|
|
ENDIF ;!NO_APPLOADER
|
|
|
|
mov cx, AllocAllSegsRet
|
|
jcxz lms_done
|
|
|
|
lms_preload_segments:
|
|
|
|
mov si,es:[ne_segtab] ; ES:SI = pSeg
|
|
mov cx,es:[ne_cseg]
|
|
xor di,di
|
|
lms_ps_loop:
|
|
inc di
|
|
test es:[si].ns_flags,NSPRELOAD
|
|
jz lms_next_segment
|
|
cmp es:[ne_align], 4 ; Must be at least paragraph aligned
|
|
jb lms_ReadFromFile
|
|
cmp hBlock, 0
|
|
jne lms_ReadFromMemory
|
|
jmps lms_ReadFromFile
|
|
|
|
lms_next_segment:
|
|
add si,SIZE new_seg1
|
|
loop lms_ps_loop
|
|
lms_done:
|
|
retn
|
|
|
|
lms_ReadFromFile:
|
|
push cx
|
|
push es
|
|
cCall FarLoadSegment,<es,di,fh,fh>
|
|
jmps lms_DoneLoad
|
|
|
|
lms_ReadFromMemory:
|
|
push cx
|
|
push es
|
|
cCall GlobalLock,<hBlock>
|
|
or dx, dx
|
|
jnz lms_still_here
|
|
cCall GlobalFree,<hBlock>
|
|
mov hBlock, 0
|
|
pop es
|
|
pop cx
|
|
jmps lms_ReadFromFile
|
|
|
|
lms_still_here:
|
|
ifdef WOW
|
|
cCall AllocSelectorWOW,<dx> ; same as allocselector. but the
|
|
mov RefSelector, dx ; new descriptor is not set.
|
|
else
|
|
cCall AllocSelector,<dx>
|
|
endif
|
|
pop es
|
|
mov bx, es:[si].ns_sector
|
|
xor dx, dx
|
|
mov cx, es:[ne_align]
|
|
push es
|
|
@@:
|
|
shl bx, 1
|
|
rcl dx, 1
|
|
loop @B
|
|
|
|
sub bx, off_FileOffset
|
|
sbb dx, seg_FileOffset
|
|
push ax
|
|
push es
|
|
ifdef WOW
|
|
; same as longptradd. but the descriptor 'RefSelector' is used
|
|
; to set the descriptor of 'ax'
|
|
cCall LongPtrAddWOW,<ax,cx,dx,bx, RefSelector, 1> ; (cx is 0)
|
|
else
|
|
cCall LongPtrAdd,<ax,cx,dx,bx> ; (cx is 0)
|
|
endif
|
|
pop es
|
|
dec cx
|
|
cCall FarLoadSegment,<es,di,dx,cx>
|
|
pop cx
|
|
push ax
|
|
cCall FreeSelector,<cx>
|
|
cCall GlobalUnlock,<hBlock>
|
|
pop ax
|
|
lms_DoneLoad:
|
|
pop es
|
|
pop cx
|
|
or ax,ax
|
|
jz lms_abort_load1
|
|
jmp lms_next_segment
|
|
lms_abort_load1:
|
|
jmp abort_load
|
|
|
|
;-----------------------------------------------------------------------
|
|
;
|
|
; LMLetsGo -
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
LMLetsGo:
|
|
push es
|
|
push Win_PDB ; Save current PDB
|
|
push topPDB ; Set it to Kernel's
|
|
pop Win_PDB
|
|
mov ax, -1
|
|
cCall FarGetCachedFileHandle,<es,ax,ax>
|
|
cmp hBlock,0
|
|
je lg_resFromFile
|
|
|
|
cCall PreloadResources,<es,ax,hBlock,FileOffset>
|
|
jmps lg_gotRes
|
|
|
|
lg_resFromFile:
|
|
xor dx, dx
|
|
cCall PreloadResources,<es,ax,dx,dx,dx>
|
|
lg_gotRes:
|
|
pop Win_PDB ; Restore PDB
|
|
pop es
|
|
mov ax,lpPBlock.off
|
|
mov dx,lpPBlock.sel
|
|
and ax,dx
|
|
inc ax
|
|
jnz lg_huh
|
|
mov lpPBlock.off,ax
|
|
mov lpPBlock.sel,ax
|
|
lg_huh: xor ax,ax ; free 0
|
|
push fLMdepth
|
|
mov fLMdepth, 0
|
|
push es
|
|
cCall StartModule,<ax,lpPBlock,es,fh>
|
|
pop es
|
|
mov hResult,ax
|
|
or ax,ax
|
|
jnz @F
|
|
jmp abort_load0
|
|
|
|
@@: test es:[ne_flags],NENOTP
|
|
jnz lg_not_a_process2
|
|
|
|
pop si
|
|
cCall CloseApplEnv,<hResult,pExe>
|
|
push bx
|
|
mov hResult,ax
|
|
mov hTDB,dx
|
|
lg_not_a_process2:
|
|
pop fLMdepth
|
|
retn
|
|
|
|
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; LMPrevInstance - internal routine for LoadModule
|
|
; Load an app/dll if a previous instance in memory
|
|
; Entry:
|
|
; ax = handle of previous instance
|
|
; Exit:
|
|
; ax = status to return
|
|
; dx = hTDB = TDB
|
|
; Error:
|
|
; ax < LME_MAXERR
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
LMPrevInstance:
|
|
mov es,ax
|
|
mov dx,es:[ne_flags]
|
|
mov si,ax
|
|
mov pExe,ax ; why store in pExe and hExe?
|
|
mov hResult,0
|
|
|
|
; Error if dynamically linking to non-library module.
|
|
mov ax,lpPBlock.off
|
|
and ax,lpPBlock.sel
|
|
inc ax
|
|
jnz pi_app
|
|
test dx,NENOTP
|
|
jnz @F
|
|
mov ax, LME_LINKTASK ; can't dynalink to a task
|
|
retn
|
|
|
|
@@: mov lpPBlock.off,ax ; AX == 0
|
|
mov lpPBlock.sel,ax
|
|
pi_app:
|
|
test dx,NEINST
|
|
jnz @F
|
|
jmp pi_not_inst
|
|
@@: call LMCheckHeap
|
|
or ax, ax
|
|
jnz @F
|
|
mov ax, LME_MEM ; Out of (gdi/user) memory
|
|
retn
|
|
@@:
|
|
|
|
ifdef WOW
|
|
;
|
|
; if WOA invoked by app (not fWOA) fail it
|
|
;
|
|
cmp fWOA,0 ; fWOA
|
|
jnz pi_not_multiple_data
|
|
|
|
cld
|
|
push si
|
|
push di
|
|
mov di, es:[ne_restab]
|
|
inc di
|
|
mov si, dataOffset WOAName
|
|
mov cx, 4
|
|
repe cmpsw
|
|
pop di
|
|
pop si
|
|
jnz @F
|
|
mov ax, LME_WOAWOW32
|
|
retn
|
|
@@:
|
|
endif
|
|
|
|
|
|
|
|
; We refuse to load multiple instances of apps that have
|
|
; multiple data segments. This is because we cannot do
|
|
; fixups to these other data segments. What happens is
|
|
; that the second copy of the app gets fixed up to the
|
|
; data segments of the first application. For the case
|
|
; of read-only data segments we make an exception since
|
|
; what does it matter who the segments belong to?
|
|
|
|
mov ax, 2 ; if we have >= 2 dsegs we die
|
|
mov es,si
|
|
mov cx,es:[ne_cseg]
|
|
mov bx,es:[ne_segtab]
|
|
pi_next_seg:
|
|
test es:[bx].ns_flags,NSDATA ; scum! this barely works!
|
|
jz @F
|
|
test es:[bx].ns_flags,NSERONLY
|
|
jnz @F
|
|
dec ax
|
|
jnz @F ; two data segments is one too many!
|
|
pi_mds: mov ax, LME_APPMDS
|
|
retn
|
|
|
|
@@: add bx,SIZE NEW_SEG1
|
|
loop pi_next_seg
|
|
|
|
pi_not_multiple_data: ; Prepare the application
|
|
cCall OpenApplEnv,<lpPBlock,si,fWOA>
|
|
cCall GetInstance,<si> ; Why do we call this?
|
|
mov di,ax
|
|
cCall IncExeUsage,<si>
|
|
cCall AllocAllSegs,<si> ; Can we get memory?
|
|
inc ax
|
|
jnz @F
|
|
cCall DecExeUsage,<si> ; AllocAllSegs failed, Dec Usage
|
|
jmps pi_mem ; Must have failed from no memory
|
|
|
|
@@: mov ax,-1
|
|
cCall StartModule,<di,lpPBlock,si,ax>
|
|
; mov hResult,ax
|
|
or ax,ax
|
|
jnz @F
|
|
mov es,si ; StartModule failed, FreeModule
|
|
mov si,es:[ne_pautodata]
|
|
cCall FreeModule,<es:[si].ns_handle>
|
|
pi_mem: mov ax, LME_MEM
|
|
retn
|
|
|
|
@@: mov si, fLMdepth
|
|
mov fLMdepth, 0
|
|
cCall CloseApplEnv,<ax,pExe>
|
|
mov fLMdepth, bx
|
|
mov hTDB,dx
|
|
retn
|
|
|
|
pi_not_inst:
|
|
mov ax,es:[ne_autodata] ; Make sure data segment is loaded.
|
|
or ax,ax
|
|
jz @F
|
|
or bx,-1
|
|
push es
|
|
cCall FarLoadSegment,<es,ax,bx,bx>
|
|
pop es
|
|
or ax,ax
|
|
jz pi_end ; yes, AX is already 0, but ...
|
|
@@:
|
|
push es ; for GetInstance
|
|
cCall IncExeUsage,<es>
|
|
cCall GetInstance ; ,<pExe>
|
|
pi_end:
|
|
retn
|
|
|
|
;----------------------------------------------------------------------
|
|
;
|
|
; LMCleanUp - internal routine for LoadModule
|
|
;
|
|
;-----------------------------------------------------------------------
|
|
LMCleanUp:
|
|
ifdef WOW
|
|
cmp LMHadPEDLL,0
|
|
je @F
|
|
cmp ax, LME_MAXERR
|
|
jae @F
|
|
mov ax,LME_PE ; Reflect real error we tried to mask
|
|
KernelLogError <DBF_WARNING>,ERR_LOADMODULE,"Could not find Win16 copy of Win32 DLL, returning LME_PE."
|
|
@@:
|
|
endif
|
|
push ax ; save status for future
|
|
cmp ax, LME_MAXERR
|
|
jae @F
|
|
cCall my_lclose,<fh>
|
|
or fh, -1
|
|
|
|
; Restore PDB if needed
|
|
@@: mov ax, -1
|
|
xchg SavePDB, ax
|
|
inc ax
|
|
jz @F
|
|
dec ax
|
|
mov Win_PDB, ax
|
|
|
|
; Free FastLoad block if allocated
|
|
@@: cmp hBlock,0
|
|
je @F
|
|
cCall GlobalFree,<hBlock>
|
|
mov hBlock,0
|
|
|
|
; Free app environment if failure and this was an app
|
|
@@:
|
|
pop ax
|
|
cmp ax,LME_MAXERR
|
|
jae @F
|
|
if KDEBUG
|
|
cmp ax, LME_INVEXE ; invalid format (WinOldAp)
|
|
jz cu_fred
|
|
cmp ax, LME_PE ; Win32 Portable Exe - try to load it
|
|
jz cu_fred
|
|
push ax
|
|
push bx
|
|
push es
|
|
les bx, lpModuleName
|
|
KernelLogError <DBF_WARNING>,ERR_LOADMODULE,"Error 0x#ax loading @ES:BX"
|
|
pop es
|
|
pop bx
|
|
pop ax
|
|
endif
|
|
cu_fred:
|
|
cmp loadTDB,0
|
|
je @F
|
|
mov bx,pExe
|
|
cmp bx,LME_MAXERR ; Did we load an ExeHeader?
|
|
jbe @F
|
|
mov es,bx
|
|
test es:[ne_flags],NENOTP
|
|
jnz @F
|
|
mov si, fLMdepth
|
|
mov fLMdepth, 0
|
|
cCall CloseApplEnv,<ax,es>
|
|
mov fLMdepth, bx
|
|
|
|
; shouldn't cache file handles on removable devices cause it
|
|
; makes share barf when the user swaps disks. this kills some
|
|
; install apps. CraigC 8/8/91
|
|
@@:
|
|
push ax
|
|
cmp ax, LME_MAXERR ; real?
|
|
jbe @F
|
|
cmp OnHardDisk, 0 ; is it on a removable device?
|
|
jne @F
|
|
cCall GetExePtr, <ax> ; get module handle
|
|
cCall FlushCachedFileHandle, <ax> ; blow it off
|
|
|
|
;** Log this entry only if in diagnostic mode
|
|
@@:
|
|
cmp fDiagMode,0 ; Only log if in diag mode
|
|
je LM_NoDiagExit
|
|
cmp fBooting,0 ; Only log if booting
|
|
je LM_NoDiagExit
|
|
|
|
pop ax ; Get the return code early
|
|
push ax
|
|
|
|
pusha ; Save all the registers
|
|
push ds
|
|
push es
|
|
|
|
;** Write out the appropriate string
|
|
mov si,ax ; Save the return value
|
|
cmp ax,LME_MAXERR
|
|
jae LM_DiagSuccess
|
|
mov ax,dataOFFSET szLoadFail ; Write the string
|
|
jmp SHORT LM_DiagOutput
|
|
LM_DiagSuccess:
|
|
mov ax,dataOFFSET szLoadSuccess ; Write the string
|
|
LM_DiagOutput:
|
|
cCall DiagOutput, <ds,ax>
|
|
cCall DiagOutput, <lpModuleName>
|
|
cmp si,LME_MAXERR ; Don't do this on success
|
|
jae SHORT LM_DiagSuccessSkip
|
|
|
|
;** Log a message complete with the failure code
|
|
mov ax,si ; Get the failure code
|
|
shr al, 4
|
|
mov bx,dataOFFSET szCodeString ; Point to the second digit
|
|
push NREScodeOffset afterHex
|
|
call toHex
|
|
mov ax, si
|
|
inc bx
|
|
toHex:
|
|
and al,0fh ; Get low hex digit
|
|
add al,'0' ; Convert to ASCII
|
|
cmp al,'9' ; Letter?
|
|
jbe @F ; Yes
|
|
add al,'A' - '0' ; Make it a letter
|
|
@@: mov [bx],al ; Save the digit
|
|
retn
|
|
afterHex:
|
|
mov ax,dataOFFSET szFailCode ; Get the string 'Failure code is '
|
|
cCall DiagOutput, <ds,ax>
|
|
LM_DiagSuccessSkip:
|
|
mov ax,dataOFFSET szCRLF
|
|
cCall DiagOutput, <ds,ax>
|
|
|
|
pop es
|
|
pop ds
|
|
popa
|
|
|
|
LM_NoDiagExit:
|
|
pop ax
|
|
dec fLMdepth
|
|
mov dx,hTDB
|
|
retn
|
|
|
|
;@@end
|
|
|
|
;shl_ax16: ; shift AX into DX:AX by cl bits
|
|
; mov dx, ax
|
|
; shl ax, cl
|
|
; neg cl
|
|
; add cl, 16 ; cl = 16 - cl
|
|
; shr dx, cl
|
|
; retn
|
|
|
|
LoadModuleEnd: ; jmp here to clean up stack and RET
|
|
|
|
ifdef WOW
|
|
cmp ax, LME_MAXERR
|
|
jb @F
|
|
lmntex:
|
|
jmp LoadModuleExit
|
|
@@:
|
|
|
|
;
|
|
; Exec For Non 16 Bit Windows Apps
|
|
;
|
|
;
|
|
; WIN 32S App ? yes -> let NT load it
|
|
;
|
|
cmp ax,LME_PE
|
|
je LM_NTLoadModule
|
|
|
|
|
|
;
|
|
; if an app is spawning WOA (NOT our internal load-fWOA),
|
|
; Patch lpModuleName to -1 let NT load it
|
|
;
|
|
cmp ax,LME_WOAWOW32
|
|
jne @F
|
|
mov word ptr lpModuleName[2], -1 ; patch lpModuleName
|
|
mov word ptr lpModuleName[0], -1
|
|
jmp short LM_NTLoadModule
|
|
@@:
|
|
|
|
; Errors 11-15 -> let NT load it
|
|
cmp ax,LME_RMODE
|
|
jae lmntex
|
|
|
|
cmp ax,LME_VERS
|
|
jbe lmntex
|
|
|
|
|
|
public LM_NTLoadModule
|
|
LM_NTLoadModule:
|
|
;
|
|
; WOW Execs non-windows apps using WINOLDAP.
|
|
;
|
|
|
|
; First check for loading of a 32bit DLL. lpPBlock will be -1
|
|
; in such a case.
|
|
|
|
push ax
|
|
mov ax,lpPBlock.off
|
|
and ax,lpPBlock.sel
|
|
inc ax
|
|
pop ax
|
|
jz LoadModuleExit
|
|
|
|
;
|
|
; This is an EXE, but the LME_PE failure code might have come from
|
|
; an implicitly linked DLL. If so, we don't want to try having
|
|
; Win32 lauch the win16 EXE, as it will just come back to us.
|
|
;
|
|
cmp ax,LME_PE
|
|
jne @F
|
|
cmp ax,hDepFail
|
|
je short LoadModuleExit
|
|
@@:
|
|
sub sp, 80 ; alloc space for cmdline
|
|
mov di, sp
|
|
smov es, ss
|
|
mov word ptr es:[di], 0 ; set WindOldApp CmdLine to NULL
|
|
regptr esdi,es,di
|
|
cCall WowLoadModule,<lpModuleName, lpPBlock, esdi>
|
|
|
|
;
|
|
; if ax < 33 an error occurred
|
|
;
|
|
cmp ax, 33
|
|
jb ex8
|
|
|
|
or Kernel_flags[1],KF1_WINOLDAP
|
|
mov ax, ss
|
|
les si,lpPBlock
|
|
mov es:[si].lpcmdline.off,di
|
|
mov es:[si].lpcmdline.sel,ax
|
|
mov si,dataOffset WOAName
|
|
regptr dssi,ds,si
|
|
cCall LoadModule,<dssi, lpPBlock>
|
|
cmp ax,32 ; check for error...
|
|
jae ex8
|
|
|
|
;
|
|
; LoadModule of WinOldApp failed
|
|
; Call WowLoadModule to clean up process handle
|
|
;
|
|
push ax
|
|
mov ax, ss
|
|
regptr axdi,ax,di
|
|
cCall WowLoadModule,<0, lpPBlock, axdi>
|
|
pop ax
|
|
|
|
cmp ax,2 ; file not found?
|
|
jnz ex7 ; no, return error
|
|
mov al, LME_WOAWOW32 ; flag WINOLDAP error
|
|
ex7:
|
|
or ax,ax ; out of memory?
|
|
jnz ex8
|
|
mov ax,8h ; yes, return proper error code
|
|
ex8:
|
|
add sp,80 ; free space for cmdline
|
|
endif; WOW
|
|
|
|
LoadModuleExit:
|
|
RESET_DOS_FLAG_EXEC_OPEN
|
|
cEnd
|
|
|
|
?DOS5 = ?SAV5
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; My_lclose
|
|
;
|
|
; Close file handle if it isn't -1.
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc My_lclose,<PUBLIC,NEAR>
|
|
parmW fh
|
|
cBegin
|
|
mov ax,fh
|
|
inc ax
|
|
jz mlc_exit
|
|
|
|
cCall _lclose,<fh>
|
|
mlc_exit:
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; WarnRealMode
|
|
;
|
|
; Trayf for files in the form "Insert WIN.EXE disk in drive A:"
|
|
;
|
|
; Entry:
|
|
;
|
|
; Returns:
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Sat 07-Oct-1989 17:12:43 -by- David N. Weise [davidw]
|
|
; Wrote it! A month or so ago.
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc WarnRealMode,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
ReSetKernelDS
|
|
push Win_PDB
|
|
push fLMDepth
|
|
cld
|
|
mov ax,IDCANCEL ; assume booting
|
|
test fBooting,1
|
|
jnz promptly_done
|
|
cmp pMBoxProc.sel,0 ; is there a USER around yet?
|
|
jz promptly_done
|
|
push di
|
|
push si
|
|
push es
|
|
mov es,cx
|
|
ifdef FE_SB
|
|
;Japan and Korea declare that they need more space for DBCS msg.
|
|
;It sounds like this is one of common requirement for DBCS enabling
|
|
;although Taiwan doesn't claim she has the same requirement.
|
|
;I enclosed this code fragment under DBCS and it can be removed
|
|
;if somebody thinks it is not necessary.
|
|
sub sp, 530
|
|
else
|
|
sub sp,512
|
|
endif
|
|
mov di,sp
|
|
mov si,offset msgRealModeApp1
|
|
push ds
|
|
smov ds,cs
|
|
UnSetKernelDS
|
|
call StartString
|
|
smov ds,cs
|
|
mov si,offset msgRealModeApp2
|
|
call Append
|
|
pop ds
|
|
ReSetKernelDS
|
|
|
|
mov bx,sp
|
|
xor ax,ax
|
|
push ax ; Null hwnd
|
|
push ss
|
|
push bx ; (lpstr)text
|
|
push cs
|
|
mov ax,offset szProtectCap
|
|
push ax ; (lpstr)caption
|
|
mov ax,MB_OKCANCEL or MB_ICONEXCLAMATION or MB_DEFBUTTON2 or MB_SYSTEMMODAL
|
|
push ax ; wType
|
|
call [pMBoxProc] ; Call USER.MessageBox
|
|
ifdef FE_SB
|
|
add sp, 530
|
|
else
|
|
add sp,512
|
|
endif
|
|
pop es
|
|
pop si
|
|
pop di
|
|
|
|
promptly_done:
|
|
pop fLMDepth
|
|
pop Win_PDB
|
|
ret
|
|
|
|
cEnd nogen
|
|
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
StartString:
|
|
call Append ; append first string
|
|
|
|
; Now append the file name
|
|
|
|
push di
|
|
lea di,[bx].opFile ; skip past length, date, time
|
|
|
|
call NResGetPureName ; strip off drive and directory
|
|
smov ds,es
|
|
mov si,di
|
|
pop di
|
|
|
|
; Append ASCIIZ string to output buffer, DS:DX points to string
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
Append: lodsb
|
|
stosb
|
|
or al,al
|
|
jnz Append
|
|
dec di
|
|
ret
|
|
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; NResGetPureName
|
|
;
|
|
; Returns a pointer the the filename off the end of a path
|
|
;
|
|
; Entry:
|
|
; ES:DI => path\filename
|
|
; Returns:
|
|
; ES:DI => filename
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Wed 18-Oct-1989 20:01:25 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc NResGetPureName,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
ifdef FE_SB
|
|
;
|
|
; It is not possible to search filename delimiter by backword search
|
|
; in case of DBCS version. so we use forword search instead.
|
|
;
|
|
mov bx,di
|
|
iup0:
|
|
mov al,es:[di]
|
|
test al,al ; end of string?
|
|
jz iup2 ; jump if so
|
|
inc di
|
|
cmp al,'\'
|
|
jz iup1
|
|
cmp al,'/'
|
|
jz iup1
|
|
cmp al,':'
|
|
jz iup1
|
|
call FarMyIsDBCSLeadByte ; see if char is DBC
|
|
jc iup0 ; jump if not a DBC
|
|
inc di ; skip to detemine 2nd byte of DBC
|
|
jmp iup0
|
|
iup1:
|
|
mov bx,di ; update purename candidate
|
|
jmp iup0
|
|
iup2:
|
|
mov di,bx ; di points purename pointer
|
|
ret
|
|
else
|
|
cld
|
|
xor al,al
|
|
mov cx,-1
|
|
mov bx,di
|
|
repne scasb
|
|
inc cx
|
|
inc cx
|
|
neg cx
|
|
iup0: cmp bx,di ; back to beginning of string?
|
|
jz iup1 ; yes, di points to name
|
|
mov al,es:[di-1] ; get next char
|
|
cmp al,'\' ; next char a '\'?
|
|
jz iup1 ; yes, di points to name
|
|
cmp al,'/' ; next char a '/'
|
|
jz iup1
|
|
cmp al,':' ; next char a ':'
|
|
jz iup1 ; yes, di points to name
|
|
dec di ; back up one
|
|
jmp iup0
|
|
iup1: ret
|
|
endif
|
|
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; search_mod_dep_list
|
|
;
|
|
; Searches the dependent module list for the passed in name.
|
|
;
|
|
; Entry:
|
|
; AX = length of name to search for
|
|
; CX = count of modules
|
|
; DS:SI => module name to search for
|
|
; ES:DI => module table
|
|
; Returns:
|
|
;
|
|
; Registers Preserved:
|
|
; AX,BX,CX,DI,SI,ES
|
|
;
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Sat 07-Oct-1989 17:12:43 -by- David N. Weise [davidw]
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc search_mod_dep_list,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
push bx
|
|
push cx
|
|
push di
|
|
mov bx,di
|
|
|
|
search_mod_loop:
|
|
mov di,es:[bx] ; es:di = offset into imptable
|
|
add di,es:[ne_imptab]
|
|
cmp es:[di],al ; does len of entry = sizeof(doscalls)
|
|
jnz get_next_entry
|
|
|
|
push cx ; cx holds count of module entries.
|
|
push si
|
|
inc di ; es:di = import module name
|
|
mov cx,ax
|
|
rep cmpsb
|
|
pop si
|
|
pop cx
|
|
stc
|
|
jz got_it
|
|
|
|
get_next_entry:
|
|
inc bx
|
|
inc bx
|
|
loop search_mod_loop
|
|
clc
|
|
got_it: pop di
|
|
pop cx
|
|
pop bx
|
|
ret
|
|
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; LMCheckHeap
|
|
;
|
|
; This checks for 4K free space in both USER's and GDI's data
|
|
; segments. If this space does not exist then we will not load
|
|
; the app. This is better than the hose-bag way we did things
|
|
; under win 1 and 2.
|
|
;
|
|
; Entry:
|
|
; nothing
|
|
;
|
|
; Returns:
|
|
; AX != 0 lots o'space
|
|
;
|
|
; Registers Destroyed:
|
|
; BX,CX
|
|
;
|
|
; History:
|
|
; Sat 28-Oct-1989 17:49:09 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
MIN_RSC = 10
|
|
cProc LMCheckHeap,<PUBLIC,NEAR>,<ds>
|
|
cBegin
|
|
SetKernelDSNRES
|
|
ifdef WOW
|
|
; USER32 and GDI32 can deal with memory alloc no need check heaps on WOW
|
|
mov ax,-1 ; WOW doesn't have GDI or User heaps
|
|
else ; so don't check them.
|
|
mov ax, MIN_RSC
|
|
cmp word ptr pGetFreeSystemResources[2],0
|
|
jz @F
|
|
cCall pGetFreeSystemResources,<0>
|
|
cmp ax, MIN_RSC
|
|
jae @F
|
|
if kdebug ; test low memory code if DEBUG
|
|
krDebugOut DEB_WARN, "Resources #ax% - this tests your error handling code"
|
|
or al, 1
|
|
else
|
|
xor ax, ax ; you failed - g'bye
|
|
endif
|
|
@@:
|
|
endif ; WOW
|
|
ReSetKernelDS
|
|
cEnd
|
|
|
|
if 0
|
|
cProc check_gdi_user_heap_space,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
ReSetKernelDS
|
|
|
|
ifdef WOW
|
|
; USER32 and GDI32 can deal with memory alloc no need check heaps on WOW
|
|
mov ax,-1 ; WOW doesn't have GDI or User heaps
|
|
else ; so don't check them.
|
|
cmp graphics,0
|
|
jz c_ret
|
|
push dx
|
|
push es
|
|
push ds
|
|
mov ds,hGDI
|
|
UnSetKernelDS
|
|
call checkit_bvakasha
|
|
or ax,ax
|
|
jz c_exit
|
|
pop ds
|
|
ReSetKernelDS
|
|
push ds
|
|
mov ds,hUser
|
|
UnSetKernelDS
|
|
call checkit_bvakasha
|
|
c_exit: pop ds
|
|
pop es
|
|
pop dx
|
|
c_ret: ret
|
|
|
|
public checkit_bvakasha
|
|
checkit_bvakasha:
|
|
mov bx,ds:[ne_pautodata]
|
|
cCall FarMyLock,<ds:[bx].ns_handle>
|
|
mov ds,ax
|
|
call LocalCountFree
|
|
sub ax,4095
|
|
ja cguhs_exit
|
|
neg ax
|
|
mov bx,LA_MOVEABLE
|
|
cCall LocalAlloc,<bx,ax>
|
|
or ax,ax
|
|
jz cguhs_exit
|
|
free_User_piece:
|
|
cCall LocalFree,<ax>
|
|
mov ax,sp ; return non-zero
|
|
cguhs_exit:
|
|
endif ;WOW
|
|
ret
|
|
cEnd nogen
|
|
endif
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; GetHeapSpaces
|
|
;
|
|
;
|
|
; Entry:
|
|
; nothing
|
|
;
|
|
; Returns:
|
|
; AX = free space (bytes) of User heap assuming heap can grow to 64K
|
|
; DX = free space (bytes) of GDI heap assuming heap can grow to 64K
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Wed 10-Jan-1990 22:27:38 -by- David N. Weise [davidw]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc GetHeapSpaces,<PUBLIC,FAR>,<di,si>
|
|
|
|
parmW hInstance
|
|
cBegin
|
|
call MapDStoDATA
|
|
ReSetKernelDS
|
|
cCall FarMyLock,<hInstance>
|
|
or ax,ax
|
|
jz ghs_exit
|
|
mov ds,ax
|
|
cmp ds:[ne_magic],NEMAGIC
|
|
jnz ghs_must_be_data
|
|
mov bx,ds:[ne_pautodata]
|
|
cCall FarMyLock,<ds:[bx].ns_handle>
|
|
mov ds,ax
|
|
ghs_must_be_data:
|
|
call LocalCountFree
|
|
mov si,ax
|
|
cCall GlobalSize,<ds>
|
|
neg ax
|
|
add ax,si ; AX = size of free assuming 64K
|
|
mov cx,si ; CX = size of free
|
|
mov dx,-1
|
|
sub dx,ds:[pLocalHeap] ; DX = size of heap
|
|
|
|
ghs_exit:
|
|
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; IsROMModule
|
|
;
|
|
; Determines if an app with a given name is a ROM application
|
|
;
|
|
; Entry:
|
|
; Returns:
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; Wed 01-May-1991 13:11:38 -by- Craig A. Critchley [craigc]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
|
|
cProc IsROMModule, <FAR, PUBLIC>
|
|
cBegin <nogen>
|
|
xor ax, ax
|
|
retf 6
|
|
cEnd <nogen>
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; IsROMFile
|
|
;
|
|
; Determines if a file is in ROM
|
|
;
|
|
; Entry:
|
|
; Returns:
|
|
; Registers Destroyed:
|
|
;
|
|
; History:
|
|
; 8/8/91 -- vatsanp -- adapted this for true-type files in ROM
|
|
; from IsROMModule [ craigc]
|
|
; Wed 01-May-1991 13:11:38 -by- Craig A. Critchley [craigc]
|
|
; Wrote it!
|
|
;-----------------------------------------------------------------------;
|
|
|
|
cProc IsROMFile, <FAR, PUBLIC>
|
|
cBegin <nogen>
|
|
xor ax, ax
|
|
retf 6
|
|
cEnd <nogen>
|
|
|
|
sEnd NRESCODE
|
|
|
|
end
|