;*************************************************************************** ;* USERGDI2.ASM ;* ;* Assembly routines used in computing heap space remaining for ;* USER, GDI, and any other heaps. ;* ;*************************************************************************** INCLUDE TOOLPRIV.INC SWAPPRO = 0 PMODE32 = 0 PMODE = 1 INCLUDE WINKERN.INC INCLUDE NEWEXE.INC ;** This slimy thing is from GDIOBJ.INC and is subtracted from the ;** object type nunbers only in 3.1 LT_GDI_BASE EQU ('G' or ('O' * 256)) - 1 ;** External functions externNP HelperVerifyLocHeap externNP HelperHandleToSel ;** Functions sBegin CODE assumes CS,CODE assumes DS,DATA .286p ; UserGdiDGROUP ; Returns a handle to the DGROUP segment for a given module ; ; HANDLE UserGdiDGROUP( ; HANDLE hModule) cProc UserGdiDGROUP, , parmW hModule cBegin mov ax,hModule ;Get the handle cCall HelperHandleToSel, ;Convert to a selector mov es,ax ;Point with ES for this xor ax,ax ;Prepare to return NULL cmp es:[ne_magic],NEMAGIC ;Make sure we have a module database jnz UGD_End ;It isn't so get out mov bx,es:[ne_pautodata] ;Point to the segment table entry mov ax,es:[bx].ns_handle ;Get the handle from the table cCall HelperHandleToSel, ;Convert to a selector for return UGD_End: cEnd ; UserGdiSpace ; This function was stolen from KERNEL where it is used to compute ; the space remaining in the USER and GDI heaps. It actually works ; on any local heap. ; ; DWORD UserGdiSpace( ; HANDLE hData) ; HIWORD of return is maximum size of heap (64K less statics, etc.) ; LOWORD of return is space remaining on heap cProc UserGdiSpace, , parmW hData cBegin ;** Count the free space in this heap. First: Is this heap valid? mov ax,hData ;Get the heap selector cCall HelperVerifyLocHeap ;Call the verify routine mov ax,0 ;In case we jump -- set error mov dx,0 ; Use MOV to not mess up carry jc UGS_Exit ;No valid local heap!! ;** Loop through all local blocks, adding free space cCall HelperHandleToSel, ;Convert to selector mov ds,ax ;Point to the segment mov di,ds:[6] ;Get pHeapInfo mov di,[di].hi_first ;First arena header mov di,[di].la_free_next ;First free block UGS_Loop: add ax,[di].la_size ;Add in size of this block sub ax,SIZE LocalArenaFree ;Less block overhead mov si,[di].la_free_next ;Get next free block or si,si ;NULL? jz UGS_Break ;Yes, say we're done cmp si,di ;Last block? (points to self) mov di,si ;Save for next time around jnz UGS_Loop ;Not last block so loop some more UGS_Break: ;** We have the size of the local heap mov si,ax ;Save the size mov cx,ds ;Get the selector in a non-segreg lsl ax,cx ;Get the size of the segment neg ax ;64K - segment size add ax,si ;Add in the free holes in the heap mov dx,-1 ;Compute the max size of heap sub dx,ds:[6] ; which is 64K less statics UGS_Exit: cEnd ; UserGdiType ; ; Tries to compute the type of local heap block if possible ; Prototype: ; ; void PASCAL UserGdiType( ; LOCALENTRY FAR *lpLocal) cProc UserGdiType, , parmD lpLocal cBegin ;** Get info from our static variables mov ax,_DATA ;Get the variables first mov ds,ax ;Point to our DS mov bx,hUserHeap ;BX=User's heap block mov cx,hGDIHeap ;CX=GDI's heap block ;** See if we can do anything with this heap les si,lpLocal ;Get a pointer to the structure mov es:[si].le_wType,LT_NORMAL ;In case we don't find anything mov ax,es:[si].le_hHeap ;Get the heap pointer cmp ax,bx ;User's heap? jnz UGT_10 ;Nope, try next cCall GetUserType ;Call routine to get user type jmp SHORT UGT_End ;Get out UGT_10: cmp ax,cx ;GDI's heap? jnz UGT_End ;Nope, can't do anything with it cCall GetGDIType ;Call routine to get GDI type UGT_End: cEnd ;** Internal helper functions ; GetUserType ; ; Uses the tags in debug USER.EXE to give information on what type ; block is pointed to by the current LOCALENTRY structure. ; Caller: ES:SI points to the parameter LOCALENTRY structure ; Return: LOCALENTRY structure is correctly updated cProc GetUserType, cBegin ;** Make sure we have a function to call cmp WORD PTR lpfnGetUserLocalObjType + 2,0 ;Selector zero? je GUT_End ;Yes ;** Call USER to get the type push es ;Save ES mov bx,es:[si].le_wAddress ;Get the block address sub bx, la_fixedsize ;The USER call needs the arena header test es:[si].le_wFlags, LF_MOVEABLE ;Moveable block? jz @F ;No sub bx, (SIZE LocalArena) - la_fixedsize ;Moveable arena bigger @@: push bx ;Parameter arena handle call DWORD PTR lpfnGetUserLocalObjType ;Call the function pop es xor ah,ah ;Clear the upper byte mov es:[si].le_wType,ax ;Save the type GUT_End: cEnd ; GetGDIType ; ; Uses the tags in debug GDI.EXE to give information on what type ; block is pointed to by the current LOCALENTRY structure. ; Caller: ES:SI points to the parameter LOCALENTRY structure ; Return: LOCALENTRY structure is correctly updated cProc GetGDIType, , cBegin ;** All fixed blocks are unknown to us test es:[si].le_wFlags,LF_FIXED ;Is it fixed? jz GGT_10 ;Nope jmp SHORT GGT_End ;Yes, get out GGT_10: ;** Prepare to find the type cCall HelperHandleToSel,es:[si].le_hHeap ;Get the selector value mov cx,wTHFlags ;Save for when we trash DS mov ds,ax ;Get the heap pointer mov di,es:[si].le_wAddress ;Get the block pointer ;** Get the type word mov ax,[di+2] ;Get the type word from the heap and ax,05fffh ;Mask out the stock object flag test cx,TH_WIN30 ;In 3.0? jnz CGT_Win30 ;Yes sub ax,LT_GDI_BASE ;No, subtract type tag base CGT_Win30: cmp ax,LT_GDI_MAX ;Recognizable type code? ja GGT_End ;No, get out mov es:[si].le_wType,ax ;Save in the structure GGT_End: cEnd sEnd END