TITLE LDUTIL - Loader support procedures .xlist include kernel.inc include newexe.inc include tdb.inc include protect.inc .list ;externFP GetCurrentPDB if ROM and PMODE32 externFP HocusROMBase endif DataBegin ;externB Kernel_Flags ;externW AltfEEMS externW headTDB externW hExeHead ;externW pGlobalHeap ;externW MyCSDS externW topPDB externW cur_dos_pdb externW Win_PDB externW curTDB ;externW segSwapArea DataEnd externFP CallWEP sBegin CODE assumes CS,CODE assumes DS,NOTHING assumes ES,NOTHING externNP MyUpper externNP MyLock externNP LoadNRTable externNP LoadSegment externNP GetOwner externNP GetCachedFileHandle if SDEBUG externNP DebugFreeSegment endif externFP IGlobalAlloc externFP IGlobalFree ;externFP IGlobalLock externFP IGlobalUnfix externFP IGlobalHandle externFP GlobalFlags externFP FreeNRTable externFP Int21Handler ifdef FE_SB ;declare it. externNP MyIsDBCSLeadByte ;Use near one as we are in the same seg endif if ROM externFP FreeSelector externNP alloc_data_sel16 endif cProc SafeCall, parmD Addr cBegin call Addr cEnd ;-----------------------------------------------------------------------; ; GetExePtr ; ; ; ; Returns the exe header pointer for the passed handle. ; ; ; ; Arguments: ; ; parmW hinstance ; ; ; ; Returns: ; ; ; ; Error Returns: ; ; AX = 0 ; ; ; ; Registers Preserved: ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ; Mon Aug 03, 1987 04:40:45p -by- David N. Weise [davidw] ; ; Rewrote it to work with expanded memory. Note that if the handle ; ; passed is truly bogus we could still catch a page fault under ; ; Win386. ; ;-----------------------------------------------------------------------; assumes ds, nothing assumes es, nothing cProc GetExePtr, parmW hinstance cBegin mov ax,hinstance test ax,GA_FIXED ; Passed a segment address? jz not_module mov es,ax cmp es:[ne_magic],NEMAGIC ; Yes, does it point to a Module? jz gxdone not_module: SetKernelDS es mov cx,headTDB assumes es, nothing find_TDB: jcxz last_chance mov es,cx cmp ax,es:[TDB_module] jz found_it mov cx,es:[TDB_next] jmp find_TDB found_it: mov ax,es:[TDB_pModule] jmps gxdone last_chance: ; The problem here is that USER cCall MyLock, ; KNOWS that hinstance is but or ax,ax ; the handle to his data segment. jz gxdone mov es,ax cmp es:[ne_magic],NEMAGIC je gxdone cCall GetOwner, or ax,ax jz gxfail mov es,ax cmp es:[ne_magic],NEMAGIC je gxdone ; The owner,ax, is now a PDB. We gotta find the TDB SetKernelDS es mov cx,headTDB assumes es, nothing find_PDB: jcxz gxfail mov es,cx cmp ax,es:[TDB_PDB] jz found_PDB mov cx,es:[TDB_next] jmp find_PDB found_PDB: mov ax,es:[TDB_pModule] jmps gxdone gxfail: if KDEBUG xor cx,cx kerror ERR_LDMODULE,,cx,hinstance endif xor ax,ax gxdone: mov cx,ax cEnd ;-----------------------------------------------------------------------; ; ; ; GetExpWinVer - return the expected Windows version for a given ; ; module handle ; ; ; ; Arguments: ; ; parmW hinstance ; ; ; ; Returns: ; ; AX = expected windows version ; ; DX = BOOL proportional font flag ; ; ; ; Error Returns: ; ; AX = 0 ; ; ; ; Registers Preserved: ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ; Fri 06 Jan 1989 -- Written by Sankar. ; ; ; ;-----------------------------------------------------------------------; assumes ds, nothing assumes es, nothing cProc GetExpWinVer,, parmW hInstance cBegin cCall GetExePtr, or ax,ax jz err_GetExpWinVer mov es,ax mov ax,es:[ne_expver] mov dx,es:[ne_flags] and dx,NEWINPROT ; error if offsets don't match our defines - In which case find the right ; offsets and changes the defines in mvdm\inc\tdb16.h .erre (NE_LOWINVER_OFFSET EQ ne_expver) .erre (NE_HIWINVER_OFFSET EQ ne_flags) err_GetExpWinVer: cEnd ;-----------------------------------------------------------------------; ; MyAlloc ; ; ; ; Private interface to memory manager ; ; ; ; Arguments: ; ; parmW aflags ; ; parmW nsize ; ; parmW nelem ; ; ; ; Returns: ; ; ; ; Error Returns: ; ; AX = Handle ; ; DX = Seg Address ; ; ; ; Registers Preserved: ; ; DI,SI,DS ; ; ; ; Registers Destroyed: ; ; BX,CX,ES ; ; ; ; Calls: ; ; GlobalAlloc ; ; MyLock ; ; ; ; History: ; ; ; ; Wed Apr 08, 1987 06:22:57a -by- David N. Weise [davidw] ; ; Wrote it. ; ;-----------------------------------------------------------------------; assumes ds, nothing assumes es, nothing cProc MyAllocLinear, ; Same as MyAlloc, except for size parameter parmW aflags parmD dwBytes cBegin jmps MyAllocNBD cEnd assumes ds, nothing assumes es, nothing cProc MyAlloc, parmW aflags parmD dwBytes ; parmW nsize ; parmW nelem cBegin xor dx,dx mov ax,seg_dwBytes ;nsize mov cx,off_dwBytes ;nelem jcxz ma3 ma2: shl ax,1 rcl dx,1 loop ma2 ma3: mov seg_dwBytes, dx mov off_dwBytes, ax MyAllocNBD: SetKernelDS es mov cx,aflags mov al,NSTYPE and al,cl ; al has SEGTYPE mov bx,NSDISCARD and bx,cx jz @F shr bx,1 shr bx,1 shr bx,1 shr bx,1 ; BX has GA_DISCARDABLE cmp al,NSCODE jne @F or bl,GA_DISCCODE ; Allocating discardable code @@: cmp al,NSDATA jne @F and cx,NOT NSWINCODE ; undo Excel bogusness or bl,GA_DGROUP ; Allocating automatic data segment @@: test cl,NSMOVE jz @F or bl,GA_MOVEABLE @@: cmp al,NSTYPE jz @F or bh,GA_CODE_DATA @@: cCall IGlobalAlloc, ;dxax> assumes es, nothing push ax test al,GA_FIXED jnz @F cCall MyLock, @@: pop dx cEnd ; ; MyLock( hseg ) - Procedure to return the physical segment address of ; the passed handle. ; ;;;cProc MyLock, ;;; parmW hseg ;;;cBegin ;;; cCall IGlobalHandle, ;;; xchg dx,ax ;;;cEnd ;-----------------------------------------------------------------------; ; MyFree ; ; ; ; Frees a segment allocated by MyAlloc. ; ; ; ; Arguments: ; ; ; ; Returns: ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ; Tue Dec 09, 1986 12:48:43p -by- David N. Weise [davidw] ; ; Added this nifty comment block. ; ;-----------------------------------------------------------------------; assumes ds, nothing assumes es, nothing cProc MyFree, parmW hseg localW pseg cBegin mov bx,hseg or bx,bx jz mf3 mov ax,bx xor cx,cx test bl,GA_FIXED jnz mf0a push bx cCall GlobalFlags, mov cx, ax xor ax, ax pop bx xchg ch, cl test cl, HE_DISCARDED jnz mf0a mov ax, bx HtoS ax mf0a: if KDEBUG push cx endif mov pseg,ax or ax,ax jz mf1 mf0: if SDEBUG cCall DebugFreeSegment, endif mf1: if KDEBUG pop cx or ch,ch jz mf2 mf1a: push cx cCall IGlobalUnfix, ; Prevent RIP if freeing locked DS pop cx dec ch or ch,ch ; If still lock, do it again jnz mf1a endif mf2: cCall IGlobalFree, mf3: cEnd ;-----------------------------------------------------------------------; ; EntProcAddress ; ; Returns the fixed address of a procedure. ; ; Entry: ; ; Returns: ; DX:AX = thunk for moveable ; DX:AX = procedure for fixed ; AX = constant, ES:BX => constant for absolutes ; Registers Destroyed: ; ; History: ; Wed 30-Nov-1988 19:39:05 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds, nothing assumes es, nothing cProc EntProcAddress,, parmW hExe parmW entno if KDEBUG parmW bNoRip ; if 1 don't RIP for error, 0 -> do the RIP endif cBegin mov es,hExe mov cx,entno and cx,7fffh ; clear ResidentName bit (#5108 donc) jcxz entfail dec cx mov si,es:[ne_enttab] entloop: mov ax, es:[si.PM_entstart] cmp cx, ax ; Below this block? jb entfail ; yes, must be invalid! cmp cx, es:[si.PM_entend] ; Above this block? jae entnext ; yes, go to next block sub cx, ax ; Found the right block, get offset mov bx, cx shl cx, 1 add bx, cx add bx, cx ; bx = cx*5 lea si, [si+bx+size PM_entstruc] mov bx, si jmps gotent entnext: mov si, es:[si.PM_entnext] ; Next block or si, si jnz entloop jmps entfail entfail: if KDEBUG cmp bNoRip,0 jnz dont_rip_here mov bx,entno krDebugOut , "Invalid ordinal reference (##BX) to %ES1" ; kerror ERR_LDORD,,es,bx dont_rip_here: endif xor dx,dx xor ax,ax jmps entdone ; Here if the current block has the entry we want gotabs: add bx,pentoffset ; make ES:BX point to constant (SLIME!) mov dx,-1 ; make != 0 since abs might be! jmps gotent1 ; Offset is symbol value gotent: xor ax, ax mov al, es:[bx].penttype ; Get segno/type field mov si,es:[bx].pentoffset cmp al,ENT_ABSSEG ; If segno field absoulute segment je gotabs ; Yes, have absolute symbol cmp al, ENT_MOVEABLE je gotmoveable .errnz 10 - SIZE NEW_SEG1 ; ax = segno push bx mov bx, es:[ne_segtab] ; see if really fixed mov cx, ax ; look up in seg table dec cx shl cx, 1 ; get segtable + (segno-1)*10 add bx, cx shl cx, 2 add bx, cx test es:[bx].ns_flags, NSMOVE + NSALLOCED pop bx jnz gotmoveable mov cx,-1 ; Fixed, make sure it's loaded cCall LoadSegment, or ax,ax mov dx,ax jnz gotent1 jmp entfail gotmoveable: xor ax,ax mov al,es:[bx].pentsegno ; Segment number dec ax shl ax,1 mov di,ax shl ax,2 add di,ax .errnz 10 - SIZE NEW_SEG1 add di,es:[ne_segtab] mov dx,es:[di].ns_handle or dx, dx jnz ok mov ax, dx ; No handle, probably from an aborted jmps entdone ; LoadModule - just return 0:0 ok: Handle_To_Sel dl gotent1: mov ax,si entdone: mov cx,ax or cx,dx cEnd ;-----------------------------------------------------------------------; ; FindOrdinal ; ; ; ; Searches the resident and non-resident name tables for a procedure ; ; name and return its corresponding entry ordinal. ; ; ; ; Arguments: ; ; parmW hExe ; ; parmD lpname pointer name, strings starts with length ; ; parmW fh file handle NOT to be discarded from cache ; ; ; ; Returns: ; ; AX = ordinal number ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; MyUpper ; ; LoadNRTable ; ; FreeNRTable ; ; ; ; History: ; ; ; ; Tue 09-May-1989 18:38:04 -by- David N. Weise [davidw] ; ; Added the batching if out of memory. ; ; ; ; Thu Sep 17, 1987 08:55:05p -by- David N. Weise [davidw] ; ; Added this nifty comment block and fixed it. ; ;-----------------------------------------------------------------------; assumes ds, nothing assumes es, nothing CLNRBUFFER equ 150 cProc FindOrdinal,, parmW hExe parmD lpname parmW fh if ROM localW fInROM endif localD oNRTable ; if batching, continue here localV LoadNRbuffer,CLNRBUFFER ; if batching this is temp buffer cBegin xor ax,ax mov oNRTable.hi,ax mov oNRTable.lo,ax if ROM mov fInROM,ax ; assume module not in ROM endif les si,lpname cmp byte ptr es:[si+1],'#' je foint fonorm: push ds mov ds,hExe if ROM test ds:[ne_flags],NEMODINROM ; is module actually in ROM? jz @f inc fInROM @@: endif mov si,ds:[ne_restab] cld foinit: xor ax,ax ; Skip module name or description lodsb add si,ax inc si inc si foloop: lodsb ; get length of entry les di,lpname mov cx,ax jcxz fodone ; no more entries? cmp es:[di],al ; do lengths match? jne noteq inc di fo_find: mov al,es:[di] call MyUpper mov bl,ds:[si] inc si inc di cmp al,bl jne noteq1 loop fo_find ; repe cmpsb ; jne noteq lodsw ; get ordinal number! mov bx,ds pop ds cmp hExe,bx ; did we load the nrtable? jnz foexit_j jmp foexit1 foexit_j: jmp foexit noteq1: dec cx noteq: add si,cx inc si inc si jmps foloop ; Here if pName points to string of the form: #nnnn foint: lods byte ptr es:[si] ; nbytes = *pName++ mov cl,al xor ch,ch dec cx ; ignore # inc si xor ax,ax ; sum = 0 foint0: mov dx,ax lods byte ptr es:[si] ; c = *pName++ sub al,'0' ; if (!isdigit(c)) cmp al,9 ja fonorm ; treat like normal xor ah,ah mov bx,ax ; sum = (sum * 10) + (c - '0') mov al,10 mul dx add ax,bx loop foint0 jmp foexit1 fodone: mov bx,ds pop ds ;%out help me ; what was this line for? mov cx,oNRTable.hi cmp cx,oNRTable.lo jnz fo_batching cmp hExe,bx ; have we looked at NRTable yet? if ROM jne foexit_j else jne foexit endif if ROM cmp fInROM,0 ; this module in ROM? jz fo_nr_not_in_rom cCall FindROMNRTable, ; yes, get selector to ROM NR Table mov fInROM,ax push ds mov ds,ax ; ds -> ROM NR table xor bx,bx mov bl,ds:[0] ; skip over first NR table entry lea si,[bx+3] ; (the module description string) xor ax,ax jmp foloop fo_nr_not_in_ROM: endif fo_batching: xor bx,bx mov ax,fh ;;; cmp ax,-1 ;;; jz no_file_handle SetKernelDS ES ;;; mov dx, topPDB ;;; mov es, curTDB ;;; UnSetKernelDS es ;;; mov ax, es:[TDB_PDB] ;;; ;;; cmp dx, cur_dos_pdb ;;; jz @F ;;; mov bx,ax ;;;@@: mov bx, Win_PDB UnSetKernelDS mov dx, -1 cCall GetCachedFileHandle, no_file_handle: push bx lea cx,LoadNRbuffer mov dx,CLNRBUFFER cCall LoadNRTable, if KDEBUG push es push di les di, [lpName] krDebugOut , " looking for @ES:DI" pop di pop es endif pop si or si,si jz @F ;;; push ax ;;; push bx ;;; mov bx,si ;;; mov ah,50h ;;; DOSCALL ;;; pop bx ;;; pop ax push es SetKernelDS ES mov Win_PDB, si pop es UnSetKernelDS ES @@: mov oNRTable.hi,cx mov oNRTable.lo,bx push ds mov ds,dx mov si,ax or ax,dx ; did we get a table? jz @F xor ax,ax jmp foloop @@: pop ds foexit: push ax if ROM cmp fInROM,0 ; this module in ROM jz @f cCall FreeSelector, ; yes, free ROM NR table selector jmps foexit0 @@: endif mov ax,ne_nrestab cCall FreeNRTable, foexit0: pop ax foexit1: ;??? commented out 3/7/88 by rong ;??? we should put this back in once everyone has the new keyboard driver ;if KDEBUG ; or ax,ax ; jnz foexit2 ; les bx,lpname ; inc bx ; kerror ERR_LDNAME,,es,bx ; xor ax,ax ;foexit2: ;endif cEnd if ROM ;---------------------------------------------------------------- ;----------------------------------------------------------------------- ; FindROMNRTable ; ; Returns a selector to the ROM copy of the Non-Resident name table for ; a module stored in ROM. ; ; Arguments: ; parmW hExe ; ; Returns: ; AX = selector mapping NR table ; ;----------------------------------------------------------------------- assumes ds, nothing assumes es, nothing cProc FindROMNRTable,, parmW hExe cBegin mov ds,hExe mov ax,word ptr ds:[ne_nrestab] mov bx,word ptr ds:[ne_nrestab+2] cCall alloc_data_sel16, if PMODE32 cCall HocusROMBase, endif if KDEBUG or ax,ax jnz @f int 3 @@: endif cEnd endif ;ROM --------------------------------------------------------- ; Search the list of new EXE headers for the passed executable file name ; (no path) ; ; this must be resident so we can search for modules in the file handle ; cache from the int 21 handler -- craigc ; cProc ResidentFindExeFile,, parmD pname cBegin SetKernelDS mov ax,hExeHead ffloop: or ax,ax jz ffdone mov es,ax mov di,es:[ne_pfileinfo] or di,di jz ffnext ; ; Double Byte Character is not able to search from the end of string, ; so this function must search from the top of string. ; ifdef FE_SB lea si,[di.opFile] ; get address of file name mov cl,es:[di.opLen] ; get structure length xor ch,ch add cx,di mov di,cx ; save end address sub cx,si ; get length of file name mov bx,si ; save top address of file name cld delineator_loop: lods byte ptr es:[si] call MyIsDBCSLeadByte jc delineator_notlead ; if not DBCS lead byte dec cx jcxz delineator_next inc si loop delineator_loop jmp delineator_next delineator_notlead: cmp al,"\" jz found_delineator cmp al,":" jz found_delineator loop delineator_loop jmp delineator_next found_delineator: mov bx,si ; save delineator address loop delineator_loop delineator_next: xchg bx,di ; set address of file name to di sub bx,di ; get lenfth of file name else mov si,di xor cx,cx mov cl,es:[di] add si,cx dec si std xor bx,bx delineator_loop: ; look for beginning of name lods byte ptr es:[si] cmp al,"\" jz found_delineator cmp al,":" jz found_delineator inc bx loop delineator_loop dec si found_delineator: ; ES:SI -> before name mov di,si inc di inc di endif lds si,pname UnSetKernelDS mov cx,bx cld repe cmpsb mov ax,es je ffdone ffnext: mov ax,word ptr es:[ne_pnextexe] jmp ffloop ffdone: cEnd sEnd CODE externFP FarLoadSegment sBegin NRESCODE assumes CS,NRESCODE assumes DS,NOTHING assumes ES,NOTHING externNP DelModule externNP MapDStoDATA cProc FindExeFile, parmD pFile cBegin cCall ResidentFindExeFile, cEnd ; Search the list of new EXE headers for the passed executable name cProc FindExeInfo,, parmD pname parmW nchars cBegin cCall MapDStoDATA ReSetKernelDS mov bx,nchars mov ax,hExeHead feloop: or ax,ax jz fedone mov es,ax mov di,es:[ne_restab] cmp es:[di],bl jne fenext inc di lds si,pname UnSetKernelDS mov cx,bx repe cmpsb je fedone fenext: mov ax,word ptr es:[ne_pnextexe] jmp feloop fedone: cEnd cProc FarFindExeInfo, parmD pname parmW nchars cBegin cCall FindExeInfo, cEnd ; ; IncExeUsage( hExe ) - procedure to increment the usage count of this ; EXE header. Indirectly increments the usage count of all the EXE ; headers it points to. ; cProc IncExeUsage,, parmW hexe cBegin mov cx,hexe jcxz iexj mov es,cx cmp es:[ne_magic],NEMAGIC jne iexj test es:[ne_usage],8000h jz iego iexj: krDebugOut , "IncExeUsage(#ES) not DLL" jmp iex iego: cmp es:[ne_usage], 4000h jb OKusage krDebugOut DEB_FERROR, "IncExeUsage: ne_usage overflow" OKusage: ; ; Save time and space by saving stuff on stack ; rather than recursing. ; or es:[ne_usage], 8000h NextExe0: or es:[ne_usage], 4000h ; Mark node visited inc es:[ne_usage] ;if kdebug ; push ax ; mov ax, es:[ne_usage] ; krDebugOut , "IncExeUsage(%ES0) #ax" ; pop ax ;endif mov cx,es:[ne_cmod] jcxz NoDeps0 mov di,es:[ne_modtab] ieloop: push es cmp word ptr es:[di], 0 je ieloop1 lar ax, es:[di] ; Make sure valid selector jnz ieloop1 mov es, es:[di] cmp es:[ne_magic],NEMAGIC jne ieloop1 test es:[ne_usage], 0C000h jnz ieloop1 push cx push di ; Fake recursion jmp NextExe0 NextExeDone0: ; Return from fake recursion pop di pop cx ieloop1: pop es add di,2 loop ieloop NoDeps0: mov cx, es cmp cx, hExe jne NextExeDone0 NextExe1: and es:[ne_usage], NOT 4000h ; Mark node visited mov cx,es:[ne_cmod] jcxz NoDeps1 mov di,es:[ne_modtab] UnMarkLoop: push es cmp word ptr es:[di], 0 je UnMarkLoop1 lar ax, es:[di] ; Make sure valid selector jnz UnMarkLoop1 mov es, es:[di] cmp es:[ne_magic],NEMAGIC jne UnMarkLoop1 test es:[ne_usage], 08000h jnz UnMarkLoop1 test es:[ne_usage], 04000h jz UnMarkLoop1 push cx push di ; Fake recursion jmp NextExe1 NextExeDone1: ; Return from fake recursion pop di pop cx UnMarkLoop1: pop es add di,2 loop UnMarkLoop NoDeps1: mov cx, es cmp cx, hExe jne NextExeDone1 xor es:[ne_usage], 8000h iex: cEnd ;-----------------------------------------------------------------------; ; DecExeUsage ; ; ; ; Decrements the usage count of the given EXE header. Indirectly ; ; decrements the usage count of all the EXE headers it points to. ; ; ; ; Arguments: ; ; parmW hexe ; ; ; ; Returns: ; ; ZF = 1 if usage count is now zero. ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; DI,SI,DS ; ; ; ; Registers Destroyed: ; ; AX,BX,CX,DX,ES ; ; ; ; Calls: ; ; DecExeUsage ; ; DelModule ; ; ; ; History: ; ; ; ; Mon Sep 21, 1987 01:21:00p -by- David N. Weise [davidw] ; ; Added this nifty comment block. ; ;-----------------------------------------------------------------------; cProc DecExeUsage,, parmW hexe cBegin call MapDStoDATA ReSetKernelDS xor si,si mov cx,hexe xor ax,ax jcxz dexj mov es,cx cmp es:[si].ne_magic,NEMAGIC jne dexj test es:[si].ne_usage,8000h jz dego dexj: krDebugOut , "DecExeUsage(#ES) not DLL" jmp dex dego: ; ; Save time and space by saving stuff on stack ; rather than recursing. ; dec es:[si].ne_usage or es:[si].ne_usage, 8000h ;if kdebug ; push ax ; mov ax, es:[si].ne_usage ; krDebugOut , "DecExeUsage(%ES0) #ax" ; pop ax ;endif NextExe2: or es:[si].ne_usage, 4000h ; Mark node visited mov cx,es:[si].ne_cmod jcxz NoDeps2 mov di,es:[si].ne_modtab MarkLoop2: push es cmp si, es:[di] je MarkLoop3 lar ax, es:[di] ; Make sure valid selector jnz MarkLoop3 mov es, es:[di] cmp es:[si].ne_magic,NEMAGIC jne MarkLoop3 test es:[si].ne_usage, 0C000h jnz MarkLoop3 push cx push di ; Fake recursion jmp NextExe2 NextExeDone2: ; Return from fake recursion pop di pop cx MarkLoop3: pop es add di,2 loop MarkLoop2 NoDeps2: mov cx, es cmp cx, hExe jne NextExeDone2 xor cx, cx push cx ; End of list of Exes to delete mov di, hExeHead ; Scan Exes once to dec them scan_exes: or di, di jz de_done mov es, di mov di, es:[si].ne_pnextexe test es:[si].ne_usage, 4000h jz scan_exes and es:[si].ne_usage, NOT 4000h ; Remove the mark test es:[si].ne_usage, 8000h ; Skip this one? jnz scan_exes ; krDebugOut , "DecExeUsage dependent %ES0" dec es:[si].ne_usage jnz scan_exes push es ; We will delete this one jmps scan_exes de_done: ; Call WEP each module before mov bx, sp ; we free any modules de_done0: mov cx, ss:[bx] add bx, 2 jcxz de_done1 push bx cCall CallWEP, pop bx jmps de_done0 de_done1: pop cx ; Get next module to delete jcxz all_deleted cCall DelModule, ; Delete him jmps de_done1 all_deleted: mov es, hExe and es:[si].ne_usage,NOT 0C000h dex: cEnd ; ; StartProcAddress( hExe ) - procedure to return the fixed address of ; a new EXE start procedure ; cProc StartProcAddress,, parmW hexe parmW fh cBegin mov es,hexe mov di,ne_csip xor dx,dx mov ax,es:[di+2] or ax,ax jz sp1 mov di,es:[di] cCall FarLoadSegment, jcxz sp1 mov ax,di ; DX:AX is start address of module sp1: ; (DX is really a handle) mov cx,ax or cx,dx cEnd ; GetStackPtr - returns the initial SS:SP for a module. ; cProc GetStackPtr,, parmW hExe cBegin mov es,hExe if KDEBUG cmp es:[ne_sssp].sel,0 jnz @F mov cx,ne_sssp fkerror 0,,es,cx @@: endif cmp es:[ne_sssp].off,0 jne re3 mov dx,es:[ne_stack] mov bx,es:[ne_pautodata] or bx,bx jz re2 add dx,es:[bx].ns_minalloc re2: and dx,0FFFEh ; Word aligned stack mov word ptr es:[ne_sssp],dx re3: mov dx,es:[ne_sssp].sel mov ax,es:[ne_sssp].off push ax mov cx,-1 cCall FarLoadSegment, pop ax ; Handle in DX and offset in AX cEnd ; ; GetInstance( hExe ) - Procedure to return the instance handle for ; the current automatic data segment associated with the passed exe ; cProc GetInstance, parmW hexe cBegin mov es,hexe mov ax,es:[ne_flags] test ax,NEINST+NESOLO mov ax,es jz gidone mov bx,es:[ne_pautodata] or bx,bx jz gidone mov ax,es:[bx].ns_handle gidone: mov cx,ax cEnd sEnd NRESCODE end