home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / windows / mlocal.zip / MLOCAL.ASM < prev    next >
Assembly Source File  |  1991-03-16  |  23KB  |  644 lines

  1. ;------------------------------------------------------------------------------
  2. ; Multiple Local Heap Routines
  3. ; Dan Quigley 10-28-90
  4. ;------------------------------------------------------------------------------
  5.  
  6.  
  7. ;;;DEBUG       EQU         1
  8.  
  9. IFDEF       DEBUG
  10. DebugOut    MACRO       st
  11.             push        ds
  12.             push        offset DGROUP:st
  13.             cCall       OUTPUTDEBUGSTRING
  14.             ENDM
  15.  
  16. DebugBreak  MACRO
  17. ;;;            int         1
  18.             ENDM            
  19. ENDIF
  20.  
  21. .286                                            ; Enable 286 instruction set
  22.  
  23. ;------------------------------------------------------------------------------
  24. ; Equates and structures
  25. ;------------------------------------------------------------------------------
  26.  
  27.  
  28. jmps        EQU      <jmp short>                ; Helper equates
  29. bptr        EQU      <byte ptr>
  30. wptr        EQU      <word ptr>     
  31. dwptr       EQU      <dword ptr>
  32. HSIZE       EQU      8192                       ; initial heap size
  33. K           EQU      1024
  34. CRLF        EQU      <13,10,0>
  35.  
  36. arena       struc
  37.             handle  dw      ?
  38.             full    db      ?
  39. arena       ends
  40.  
  41. ;------------------------------------------------------------------------------
  42. ; CMACRO Setup         
  43. ;------------------------------------------------------------------------------
  44.  
  45. .xlist                                          ; Suspend listing
  46. ?DF = 1                                         ; Don't generate default segs
  47. ?PLM = 1                                        ; Support Pascal calling
  48. ?WIN = 1                                        ; Support Windows
  49. include cmacros.inc
  50. include windows.inc                             
  51. .list
  52.  
  53. ;------------------------------------------------------------------------------
  54. ; Segment definitions
  55. ;------------------------------------------------------------------------------
  56. createSeg   MLOCAL_TEXT,CODE,PARA,PUBLIC,CODE   ; Define code segment
  57. createSeg   _DATA,DATA,PARA,PUBLIC,DATA,DGROUP  ; Define data segment
  58. defGrp      DGROUP,DATA                         ; Declare DGROUP
  59. assumes     DS,DATA                             ; Tell assembler where DS is 
  60.                                                 ; to be referenced
  61.  
  62. ;------------------------------------------------------------------------------
  63. ; Global variables    
  64. ;------------------------------------------------------------------------------
  65. sBegin      DATA
  66.             FLHeap      dw      0               ; Global Handle to Heap
  67.             FLHandle    dw      0               ; Handle to Handle Table
  68.             FLSize      dw      0               ; Size of Handle Table
  69.             FLOffset    dw      0               ; start of handle table
  70.             FLSel       dw      0               ; selector to handle table
  71.             FLEnd       dw      0               ; end of handle table
  72. IFDEF DEBUG
  73.             staticB  MultFreeHeap,<'MultFreeHeap',CRLF>
  74.             staticB  MultLocalAlloc,<'MultLocalAlloc',CRLF>
  75.             staticB  MultLocalCompact,<'MultLocalCompact',CRLF>
  76.             staticB  MultLocalFlags,<'MultFlags',CRLF>
  77.             staticB  MultLocalFree,<'MultLocalFree',CRLF>
  78.             staticB  MultLocalHandle,<'MultLocalHandle',CRLF>
  79.             staticB  MultLocalInit,<'MultLocalInit',CRLF>
  80.             staticB  MultLocalLock,<'MultLocalLock',CRLF>
  81.             staticB  MultLocalReAlloc,<'MultLocalReAlloc',CRLF>
  82.             staticB  MultLocalSize,<'MultLocalSize',CRLF>
  83.             staticB  MultLocalUnlock,<'MultLocalUnlock',CRLF>
  84.             staticB  FarLocalAlloc,<'FarLocalAlloc',CRLF>
  85.             staticB  FarLocalCompact,<'FarLocalCompact',CRLF>
  86.             staticB  FarLocalFree,<'FarLocalFree',CRLF>
  87.             staticB  FarLocalInit,<'FarLocalInit',CRLF>
  88.             staticB  SetDStoHeap,<'SetDStoHeap',CRLF>
  89. ENDIF
  90. sEnd        DATA
  91.  
  92. ;------------------------------------------------------------------------------
  93. ; External procedures 
  94. ;------------------------------------------------------------------------------
  95. externFP    <GLOBALALLOC>
  96. externFP    <GLOBALFREE>
  97. externFP    <GLOBALLOCK>
  98. externFP    <GLOBALUNLOCK>
  99.  
  100. externFP    <LOCALALLOC>
  101. externFP    <LOCALCOMPACT>
  102. externFP    <LOCALFLAGS>
  103. externFP    <LOCALFREE>
  104. externFP    <LOCALHANDLE>
  105. externFP    <LOCALINIT>
  106. externFP    <LOCALLOCK>
  107. externFP    <LOCALREALLOC>
  108. externFP    <LOCALSIZE>
  109. externFP    <LOCALUNLOCK>
  110. externFP    <OUTPUTDEBUGSTRING>
  111.  
  112. ;------------------------------------------------------------------------------
  113. ; _TEXT starts here
  114. ;------------------------------------------------------------------------------
  115. sBegin      CODE
  116. assumes     CS,CODE                             ; Reference CS
  117.  
  118.  
  119. ;------------------------------------------------------------------------------
  120. ; MultLocalAlloc - Allocates memory from the designated heap
  121. ;
  122. ; Returns : AX = Handle
  123. ;------------------------------------------------------------------------------
  124. cProc       MultLocalAlloc,<PUBLIC,FAR>,<es,ds>
  125.             parmW       hHeap
  126.             parmW       wFlags
  127.             parmW       wBytes
  128. cBegin
  129.  
  130. IFDEF DEBUG
  131.             DebugOut    MultLocalAlloc
  132.             DebugBreak
  133. ENDIF
  134.             mov         ax,hHeap
  135.             cmp         ax,0
  136.             je          MLAExit
  137.             mov         ds,ax
  138.             cCall       LocalAlloc <wFlags,wBytes>
  139. MLAExit:
  140. cEnd
  141.  
  142.  
  143. ;------------------------------------------------------------------------------
  144. ; MultLocalCompact - Compacts the designated heap
  145. ;
  146. ; Returns : the largest block of free memory
  147. ;------------------------------------------------------------------------------
  148.  
  149. cProc       MultLocalCompact,<PUBLIC,FAR>,<es,ds>
  150.             parmW       hHeap
  151.             parmW       wMinFree
  152. cBegin
  153.  
  154. IFDEF DEBUG
  155.             DebugOut    MultLocalCompact
  156.             DebugBreak
  157. ENDIF
  158.             mov         ax,hHeap
  159.             cmp         ax,0
  160.             je          LCExit
  161.             mov         ds,ax
  162.             cCall       LocalCompact <wMinFree>
  163. LCExit:
  164. cEnd
  165.  
  166.  
  167. ;------------------------------------------------------------------------------
  168. ; MultLocalFlags - Returns the Allocation flags of a local memory object
  169. ;
  170. ; Returns :Allocation Flags
  171. ;------------------------------------------------------------------------------
  172. cProc       MultLocalFlags,<PUBLIC,FAR>,<ds>
  173.             parmW       hHeap
  174.             parmW       hMem
  175. cBegin
  176.  
  177. IFDEF DEBUG
  178.             DebugOut    MultLocalFlags
  179.             DebugBreak
  180. ENDIF
  181.             mov         ax,hHeap
  182.             cmp         ax,0
  183.             je          LFExit
  184.             mov         ds,ax
  185.             cCall       LocalFlags <hMem>
  186. LFExit:
  187. cEnd
  188.  
  189.  
  190. ;------------------------------------------------------------------------------
  191. ; MultLocalFree - Frees a local memory block from the designated heap
  192. ;
  193. ; Returns : NULL on success
  194. ;------------------------------------------------------------------------------
  195. cProc       MultLocalFree,<PUBLIC,FAR>,<ds>
  196.             parmW       hHeap
  197.             parmW       hMem
  198. cBegin
  199.  
  200. IFDEF DEBUG
  201.             DebugOut    MultLocalFree
  202.             DebugBreak
  203. ENDIF
  204.             mov         ax,hHeap
  205.             cmp         ax,0
  206.             je          MLFErr
  207.             mov         ds,ax
  208.             cCall       LocalFree <hMem>
  209.             jmps        MLFExit
  210. MLFErr:     mov         ax,-1
  211. MLFExit:
  212. cEnd
  213.  
  214. ;------------------------------------------------------------------------------
  215. ; MultLocalHandle - Returns the handle of the address of a block
  216. ;
  217. ; Returns : HANDLE
  218. ;------------------------------------------------------------------------------
  219. cProc       MultLocalHandle,<PUBLIC,FAR>,<ds>
  220.             parmD       dwAddress
  221. cBegin
  222.  
  223. IFDEF DEBUG
  224.             DebugOut    MultLocalHandle
  225.             DebugBreak
  226. ENDIF
  227.  
  228.             lds         ax,dwAddress
  229.             cCall       LocalHandle <ax>
  230. cEnd
  231.  
  232. ;------------------------------------------------------------------------------
  233. ; MultLocalInit - Allocates a 64k from the global heap and initializes it
  234. ;
  235. ; Returns : HANDLE on success
  236. ;------------------------------------------------------------------------------
  237. cProc       MultLocalInit,<PUBLIC,FAR>,<es,di,si>
  238.             parmW       wSize
  239. cBegin
  240.  
  241. IFDEF DEBUG
  242.             DebugOut    MultLocalInit
  243.             DebugBreak
  244. ENDIF
  245.             push        (GMEM_MOVEABLE OR GMEM_ZEROINIT)
  246.  
  247.             and         wSize,0FFF0h        ; round to 16 byte
  248.             mov         ax,0
  249.  
  250.             push        ax                  ; high order word on stack first
  251.             push        wSize               ; then low order
  252.  
  253.             cCall       GlobalAlloc         ; allocate the heap
  254.             cmp         ax,0                ; success?
  255.             je          MLIExit             ; no then exit
  256.  
  257.             cCall       GlobalLock <ax>     ; we need the selector rights
  258.             mov         ax,dx
  259.             cmp         ax,0
  260.  
  261.             push        ax                  ; yes save the handle for later
  262.             je          MLIErr
  263.  
  264.             push        ax                  ; Global handle is in ax
  265.             push        0                   ; beging at start of heap
  266.  
  267.             mov         ax,wSize            ; wSize - 1 for heap length
  268.             dec         ax
  269.             push        ax
  270.  
  271.             cCall       LocalInit           ; LocalInit locks the heap
  272.             cmp         ax,0                ; did Init fail?
  273.             jne         MLIOK               ; no then we're done
  274.  
  275. MLIErr:
  276.             cCall       GlobalFree          ; handle is still on stack
  277.             mov         ax,0
  278.             jmps        MLIExit
  279.  
  280. MLIOK:      pop         ax                  ; return the handle
  281.  
  282. MLIExit:
  283.  
  284. cEnd
  285.  
  286.  
  287. ;------------------------------------------------------------------------------
  288. ; MultLocalLock - Locks a local memory block from the designated heap
  289. ;
  290. ; Returns : selector:offset in dx:ax
  291. ;------------------------------------------------------------------------------
  292. cProc       MultLocalLock,<PUBLIC,FAR>,<es,ds>
  293.             parmW       hHeap
  294.             parmW       hMem
  295. cBegin
  296.  
  297. IFDEF DEBUG
  298.             DebugOut    MultLocalLock
  299.             DebugBreak
  300. ENDIF
  301.             mov         dx,0                    ; assume failure
  302.  
  303.             mov         ax,hHeap
  304.             cmp         ax,0
  305.             je          MLLExit
  306.  
  307.             mov         ds,ax
  308.             cCall       LocalLock <hMem>
  309.             cmp         ax,0
  310.             je          MLLExit
  311.  
  312.             mov         dx,ds
  313.  
  314. MLLExit:
  315. cEnd
  316.  
  317.  
  318. ;------------------------------------------------------------------------------
  319. ; MultLocalReAlloc - Changes the size of the local memory block
  320. ;
  321. ; Returns : Handle to
  322. ;------------------------------------------------------------------------------
  323. cProc       MultLocalReAlloc,<PUBLIC,FAR>,<es,ds>
  324.             parmW       hHeap
  325.             parmW       hMem
  326.             parmW       wBytes
  327.             parmW       wFlags
  328. cBegin
  329.  
  330. IFDEF DEBUG
  331.             DebugOut    MultLocalReAlloc
  332.             DebugBreak
  333. ENDIF
  334.             mov         ax,hHeap
  335.             cmp         ax,0
  336.             je          MLRExit
  337.             mov         ds,ax
  338.             cCall       LocalReAlloc <hMem, wBytes, wFlags>
  339. MLRExit:
  340. cEnd
  341.  
  342. ;------------------------------------------------------------------------------
  343. ; MultLocalSize - Returns the size of the memory block
  344. ;
  345. ; Returns : Size in bytes
  346. ;------------------------------------------------------------------------------
  347. cProc       MultLocalSize,<PUBLIC,FAR>,<ds>
  348.             parmW       hHeap
  349.             parmW       hMem
  350. cBegin
  351.  
  352. IFDEF DEBUG
  353.             DebugOut    MultLocalSize
  354.             DebugBreak
  355. ENDIF
  356.             mov         ax,hHeap
  357.             cmp         ax,0
  358.             je          MLSExit
  359.             mov         ds,ax
  360.             cCall       LocalSize <hMem>
  361. MLSExit:
  362. cEnd
  363.  
  364. ;------------------------------------------------------------------------------
  365. ; MultLocalUnlock - Unlocks an object in the designated heap
  366. ;
  367. ; Returns : Lock Count
  368. ;------------------------------------------------------------------------------
  369. cProc       MultLocalUnlock,<PUBLIC,FAR>,<es,ds>
  370.             parmW       hHeap
  371.             parmW       hMem
  372. cBegin
  373.  
  374. IFDEF DEBUG
  375.             DebugOut    MultLocalUnlock
  376.             DebugBreak
  377. ENDIF
  378.             mov         ax,hHeap
  379.             cmp         ax,0
  380.             je          MLUExit
  381.             mov         ds,ax
  382.             cCall       LocalUnlock <hMem>
  383. MLUExit:
  384. cEnd
  385.  
  386. ;------------------------------------------------------------------------------
  387. ; MultFreeHeap - Free the Local Heap
  388. ;
  389. ; Returns : NULL on success - Heap on Failure
  390. ;------------------------------------------------------------------------------
  391. cProc       MultFreeHeap,<PUBLIC,FAR>
  392.             parmW       hHeap
  393. cBegin
  394.  
  395. IFDEF DEBUG
  396.             DebugOut    MultFreeHeap
  397.             DebugBreak
  398. ENDIF
  399.             mov         ax,hHeap
  400.             cmp         ax,0
  401.             je          FLHExit
  402.             cCall       GlobalUnlock <hHeap>
  403.             cCall       GlobalFree <hHeap>
  404.  
  405. FLHExit:
  406. cEnd
  407.  
  408. ;------------------------------------------------------------------------------
  409. ; FarLocalInit - Initializes the FarLocal Heap Routines
  410. ;
  411. ; Returns : Success NonZero | Failure FALSE
  412. ;------------------------------------------------------------------------------
  413. cProc       FarLocalInit,<PUBLIC,FAR>,<di>
  414. cBegin
  415.  
  416. IFDEF DEBUG
  417.             DebugOut    FarLocalInit
  418.             DebugBreak
  419. ENDIF
  420.             mov         ax,1                    ; Assume success
  421.             cmp         FLHeap,0                ; Have we initialized before
  422.             jne         FLIExit                 ; Yes, then exit
  423.  
  424.             mov         FLSize,HSIZE            ; Start with a 8K heap
  425.             cCall       MultLocalInit <FLSize>  ; Initialize the handle table
  426.             cmp         ax,0                    ; failure?
  427.             je          FLIExit                 ; then were hosed
  428.             mov         FLHeap,ax               ; save the handle
  429.             
  430.             push        ax
  431.             push        (LMEM_MOVEABLE OR LMEM_ZEROINIT)
  432.             push        (K * 6)                 ; start with 2K entries
  433.             cCall       MultLocalAlloc 
  434.             
  435.             cmp         ax,0                    ; allocation succeed?
  436.             jne         TableOK                 ; yes
  437.  
  438. CleanUp:    cCall       MultFreeHeap <FLHeap>   ; clean up
  439.             mov         FLHeap,0
  440.             jmps        FLIExit                 ; and get out
  441.  
  442. TableOK:    mov         FLHandle,ax             ; store the handle
  443.             cCall       MultLocalLock <FLHeap,FLHandle>
  444.             cmp         dx,0                    ; if we cant lock it down
  445.             je          CleanUp                 ; then exit
  446.  
  447.             mov         FLOffset,ax             ; store offset
  448.             mov         FLSel,dx                ; store selector
  449.             add         ax,FLSize               ; add the offset with size
  450.             dec         ax                      ; 0 referenced
  451.             mov         FLEnd,ax                ; store the table end
  452.  
  453.             cCall       MultLocalInit <FLSize>  ; Initialize the first heap to 8K
  454.             les         di,dwptr FLOffset
  455.             mov         es:[di],ax              ; store the handle
  456.  
  457. FLIExit:
  458. cEnd
  459.  
  460.  
  461. ;------------------------------------------------------------------------------
  462. ; FarLocalAlloc - Allocates from the FarLocal Heap
  463. ;
  464. ; Returns : Success DD HANDLE | Failure FALSE
  465. ;------------------------------------------------------------------------------
  466. cProc       FarLocalAlloc,<PUBLIC,FAR>,<di,si>
  467.             parmW       wFlags
  468.             parmW       wSize
  469.  
  470. cBegin
  471.  
  472. IFDEF DEBUG
  473.             DebugOut    FarLocalAlloc
  474.             DebugBreak
  475. ENDIF
  476.             cCall       FarLocalInit            ; initialize arena
  477.  
  478.             mov         ax,0                    ; assume failure
  479.             mov         dx,0
  480.  
  481.  
  482. tsearch:    les         di,dwptr FLOffset       ; es:di to top of arena
  483.             mov         cx,wSize                ; cx gets desired size
  484.  
  485. search:     cmp         es:[di].full,ch         ; is this arena entry full
  486.             jbe         found_one               ; no then try the allocation
  487.  
  488. next_entry: add         di,3                    ; get next arena entry
  489.             cmp         di,FLEnd                ; are we beyond our limit
  490.             jb          search                  ; no, then continue walk
  491.                                                 ; yes then attempt to resize
  492.                                                 ; the arena
  493.             cCall       MultLocalUnlock <FLHeap,FLHandle>
  494.             add         FLSize,(K * 6)          ; add another 2K entries
  495.             mov         ax,(LMEM_MOVEABLE OR LMEM_ZEROINIT)
  496.             cCall       MultLocalReAlloc <FLHeap,FLHandle,FLSize,ax>
  497.             cmp         ax,0                    ; did realloc fail?
  498.             je          WeBeHosed               ; yes, exit
  499.             cCall       MultLocalLock <FLHeap,FLHandle>
  500.             mov         FLOffset,ax             ; store offset
  501.             mov         FLSel,dx                ; store selector
  502.             add         ax,FLSize               ; add the offset with size
  503.             dec         ax                      ; 0 referenced
  504.             mov         FLEnd,ax                ; store the table end
  505.             jmps        tsearch                 ; no, then start walk
  506.  
  507.   ;;; **** possible optimization: calulate and set di to new area
  508.  
  509. found_one:  cmp         es:[di].handle,0        ; has this heap been initialized
  510.             jne         do_alloc                ; yes, then try the allocation
  511.  
  512. alloc_new:  cCall       MultLocalInit <HSIZE>   ; Initialize the next heap
  513.             cmp         ax,0                    ; Init fail?
  514.             je          WeBeHosed               ; yes, were hosed
  515.             mov         es:[di].handle,ax       ; Store the new handle
  516.             
  517. do_alloc:   push        es:[di].handle          ; push heap handle
  518.             push        wFlags                  ; push flags
  519.             push        wSize                   ; then requested size
  520.             cCall       MultLocalAlloc          ; attempt allocation
  521.  
  522.             cmp         ax,0                    ; did the alloc fail?
  523.             jne         got_it                  ; no
  524.             mov         cx,wSize                ; cx gets desired size
  525.             cmp         ch,0                    ; is size < 255
  526.             jne         size_ok                 ; no, then size ok
  527.             inc         ch                      ; yes, then bump ch
  528.  
  529. size_ok:    mov         es:[di].full,ch         ; full here so mark it
  530.             jmp         next_entry              ; go back and search for more
  531.  
  532. got_it:     mov         dx,es:[di].handle       ; we have 4 byte handles
  533.  
  534. WeBeHosed:
  535.  
  536. cEnd
  537.  
  538. ;------------------------------------------------------------------------------
  539. ; FarLocalFree - Frees objects from the FarLocal Heap
  540. ;
  541. ; Returns : Failure DD HANDLE | Success NULL
  542. ;------------------------------------------------------------------------------
  543. cProc       FarLocalFree,<PUBLIC,FAR>,<di,si>
  544.             parmD       dwHandle
  545. cBegin
  546.  
  547. IFDEF DEBUG
  548.             DebugOut    FarLocalFree
  549.             DebugBreak
  550. ENDIF
  551.             mov         dx,1                    ; assume failure
  552.             mov         ax,wptr dwHandle + 2    ; get the heaps global handle
  553.             les         di,dwptr FLOffset       ; es:di to top of arena
  554.  
  555. tfsearch:   cmp         es:[di].handle,ax       ; is this the right arena entry
  556.             je          found_it                ; yes
  557.             add         di,3                    ; get next arena entry
  558.             cmp         di,FLEnd                ; are we beyond our limit
  559.             jb          tfsearch                ; no, then continue walk
  560.             jmps        fdone
  561.  
  562. found_it:   mov         dx,0                    ; signal success finding heap
  563.             push        ds                      ; save ds
  564.             lds         si, dwHandle            ; get the heap and handle
  565.             cCall       LocalSize <si>          ; ask for object size
  566.             push        ax                      ; save size
  567.             cCall       LocalFree <si>          ; si has object handle
  568.             pop         cx                      ; size via pop
  569.             pop         ds                      ; restore ds
  570.             cmp         ax,0                    ; success
  571.             jne         fdone                   ; no, then error
  572.             cmp         es:[di].full,0          ; is this heap marked full?
  573.             je          fdone                   ; no, then were done
  574.             add         es:[di].full,ch         ; add the freed size (256 byte granularity)
  575.             jnc         fdone                   ; overflow?
  576.             mov         es:[di].full,0          ; reset the full byte
  577. fdone:
  578.  
  579. cEnd
  580.  
  581.  
  582. ;------------------------------------------------------------------------------
  583. ; FarLocalCompact - Compacts the FarLocal Heap
  584. ;
  585. ; Returns : VOID
  586. ;------------------------------------------------------------------------------
  587. cProc       FarLocalCompact,<PUBLIC,FAR>,<di>
  588.  
  589. cBegin
  590.  
  591. IFDEF DEBUG
  592.             DebugOut    FarLocalCompact
  593.             DebugBreak
  594. ENDIF
  595.  
  596.             les         di,dwptr FLOffset       ; es:di to top of arena
  597.  
  598. tfcsearch:  cmp         es:[di].handle,0        ; arena entry?
  599.             je          fcdone                  ; no then were done
  600.             mov         ax,es:[di].handle
  601.             push        ds                      ; change ds
  602.             mov         ds,ax
  603.             mov         cx,0FFFFh               ; max compaction
  604.             cCall       LocalCompact <cx>       ; do the compaction
  605.             pop         ds                      ; restore ds
  606.             cmp         es:[di].full,ah         ; last alloc < new size
  607.             jge         noreset
  608.             mov         es:[di].handle,0        ; reset the full count
  609.  
  610. noreset:    add         di,3                    ; get next arena entry
  611.             cmp         di,FLEnd                ; are we beyond our limit
  612.             jb          tfcsearch               ; no, then continue walk
  613.             jmps        fcdone
  614.  
  615. fcdone:
  616.  
  617. cEnd
  618.  
  619.  
  620. ;------------------------------------------------------------------------------
  621. ; SetDStoHeap - Sets DS to heap
  622. ;
  623. ; Returns : Old DS
  624. ;------------------------------------------------------------------------------
  625. cProc       SetDStoHeap,<PUBLIC,FAR>
  626.             parmW       hHeap
  627. cBegin
  628.  
  629. IFDEF DEBUG
  630.             DebugOut    MultLocalUnlock
  631.             DebugBreak
  632. ENDIF
  633.             mov         ax,hHeap
  634.             cmp         ax,0
  635.             je          SDSExit
  636.             push        ds
  637.             mov         ds,ax
  638.             pop         ax
  639. SDSExit:
  640. cEnd
  641.  
  642. sEnd        CODE
  643. END
  644.