Framework for the doppler effect.
[wine] / memory / heap.c
1 /*
2  * Win32 heap functions
3  *
4  * Copyright 1996 Alexandre Julliard
5  * Copyright 1998 Ulrich Weigand
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
31 #include "winbase.h"
32 #include "wine/winbase16.h"
33 #include "winerror.h"
34 #include "winnt.h"
35 #include "winternl.h"
36 #include "wine/unicode.h"
37 #include "selectors.h"
38 #include "global.h"
39 #include "thread.h"
40 #include "toolhelp.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(heap);
44
45 /* address where we try to map the system heap */
46 #define SYSTEM_HEAP_BASE  ((void*)0x65430000)
47 #define SYSTEM_HEAP_SIZE  0x100000   /* Default heap size = 1Mb */
48
49
50 #define HTABLE_SIZE      0x10000
51 #define HTABLE_PAGESIZE  0x1000
52 #define HTABLE_NPAGES    (HTABLE_SIZE / HTABLE_PAGESIZE)
53
54 #include "pshpack1.h"
55 typedef struct _LOCAL32HEADER
56 {
57     WORD     freeListFirst[HTABLE_NPAGES];
58     WORD     freeListSize[HTABLE_NPAGES];
59     WORD     freeListLast[HTABLE_NPAGES];
60
61     DWORD    selectorTableOffset;
62     WORD     selectorTableSize;
63     WORD     selectorDelta;
64
65     DWORD    segment;
66     LPBYTE   base;
67
68     DWORD    limit;
69     DWORD    flags;
70
71     DWORD    magic;
72     HANDLE heap;
73
74 } LOCAL32HEADER;
75 #include "poppack.h"
76
77 #define LOCAL32_MAGIC    ((DWORD)('L' | ('H'<<8) | ('3'<<16) | ('2'<<24)))
78
79 static HANDLE systemHeap;   /* globally shared heap */
80
81 /***********************************************************************
82  *           HEAP_CreateSystemHeap
83  *
84  * Create the system heap.
85  */
86 inline static HANDLE HEAP_CreateSystemHeap(void)
87 {
88     int created;
89     void *base;
90     HANDLE map, event;
91     UNICODE_STRING event_name;
92     OBJECT_ATTRIBUTES event_attr;
93
94     if (!(map = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE,
95                                     0, SYSTEM_HEAP_SIZE, "__SystemHeap" ))) return 0;
96     created = (GetLastError() != ERROR_ALREADY_EXISTS);
97
98     if (!(base = MapViewOfFileEx( map, FILE_MAP_ALL_ACCESS, 0, 0, 0, SYSTEM_HEAP_BASE )))
99     {
100         /* pre-defined address not available */
101         ERR( "system heap base address %p not available\n", SYSTEM_HEAP_BASE );
102         return 0;
103     }
104
105     /* create the system heap event */
106     RtlCreateUnicodeStringFromAsciiz( &event_name, "__SystemHeapEvent" );
107     event_attr.Length = sizeof(event_attr);
108     event_attr.RootDirectory = 0;
109     event_attr.ObjectName = &event_name;
110     event_attr.Attributes = 0;
111     event_attr.SecurityDescriptor = NULL;
112     event_attr.SecurityQualityOfService = NULL;
113     NtCreateEvent( &event, EVENT_ALL_ACCESS, &event_attr, TRUE, FALSE );
114
115     if (created)  /* newly created heap */
116     {
117         systemHeap = RtlCreateHeap( HEAP_SHARED, base, SYSTEM_HEAP_SIZE,
118                                     SYSTEM_HEAP_SIZE, NULL, NULL );
119         NtSetEvent( event, NULL );
120     }
121     else
122     {
123         /* wait for the heap to be initialized */
124         WaitForSingleObject( event, INFINITE );
125         systemHeap = (HANDLE)base;
126     }
127     CloseHandle( map );
128     return systemHeap;
129 }
130
131
132 /***********************************************************************
133  *           HeapCreate   (KERNEL32.@)
134  * RETURNS
135  *      Handle of heap: Success
136  *      NULL: Failure
137  */
138 HANDLE WINAPI HeapCreate(
139                 DWORD flags,       /* [in] Heap allocation flag */
140                 SIZE_T initialSize, /* [in] Initial heap size */
141                 SIZE_T maxSize      /* [in] Maximum heap size */
142 ) {
143     HANDLE ret;
144
145     if ( flags & HEAP_SHARED )
146     {
147         if (!systemHeap) HEAP_CreateSystemHeap();
148         else WARN( "Shared Heap requested, returning system heap.\n" );
149         ret = systemHeap;
150     }
151     else
152     {
153         ret = RtlCreateHeap( flags, NULL, maxSize, initialSize, NULL, NULL );
154         if (!ret) SetLastError( ERROR_NOT_ENOUGH_MEMORY );
155     }
156     return ret;
157 }
158
159 /***********************************************************************
160  *           HeapDestroy   (KERNEL32.@)
161  * RETURNS
162  *      TRUE: Success
163  *      FALSE: Failure
164  */
165 BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ )
166 {
167     if (heap == systemHeap)
168     {
169         WARN( "attempt to destroy system heap, returning TRUE!\n" );
170         return TRUE;
171     }
172     if (!RtlDestroyHeap( heap )) return TRUE;
173     SetLastError( ERROR_INVALID_HANDLE );
174     return FALSE;
175 }
176
177
178 /***********************************************************************
179  *           HeapCompact   (KERNEL32.@)
180  */
181 SIZE_T WINAPI HeapCompact( HANDLE heap, DWORD flags )
182 {
183     return RtlCompactHeap( heap, flags );
184 }
185
186
187 /***********************************************************************
188  *           HeapLock   (KERNEL32.@)
189  * Attempts to acquire the critical section object for a specified heap.
190  *
191  * RETURNS
192  *      TRUE: Success
193  *      FALSE: Failure
194  */
195 BOOL WINAPI HeapLock(
196               HANDLE heap /* [in] Handle of heap to lock for exclusive access */
197 ) {
198     return RtlLockHeap( heap );
199 }
200
201
202 /***********************************************************************
203  *           HeapUnlock   (KERNEL32.@)
204  * Releases ownership of the critical section object.
205  *
206  * RETURNS
207  *      TRUE: Success
208  *      FALSE: Failure
209  */
210 BOOL WINAPI HeapUnlock(
211               HANDLE heap /* [in] Handle to the heap to unlock */
212 ) {
213     return RtlUnlockHeap( heap );
214 }
215
216
217 /***********************************************************************
218  *           HeapValidate   (KERNEL32.@)
219  * Validates a specified heap.
220  *
221  * NOTES
222  *      Flags is ignored.
223  *
224  * RETURNS
225  *      TRUE: Success
226  *      FALSE: Failure
227  */
228 BOOL WINAPI HeapValidate(
229               HANDLE heap, /* [in] Handle to the heap */
230               DWORD flags,   /* [in] Bit flags that control access during operation */
231               LPCVOID block  /* [in] Optional pointer to memory block to validate */
232 ) {
233     return RtlValidateHeap( heap, flags, block );
234 }
235
236
237 /***********************************************************************
238  *           HeapWalk   (KERNEL32.@)
239  * Enumerates the memory blocks in a specified heap.
240  *
241  * TODO
242  *   - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
243  *     PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support)
244  *
245  * RETURNS
246  *      TRUE: Success
247  *      FALSE: Failure
248  */
249 BOOL WINAPI HeapWalk(
250               HANDLE heap,               /* [in]  Handle to heap to enumerate */
251               LPPROCESS_HEAP_ENTRY entry /* [out] Pointer to structure of enumeration info */
252 ) {
253     NTSTATUS ret = RtlWalkHeap( heap, entry );
254     if (ret) SetLastError( RtlNtStatusToDosError(ret) );
255     return !ret;
256 }
257
258
259 /***********************************************************************
260  *           GetProcessHeap    (KERNEL32.@)
261  */
262 HANDLE WINAPI GetProcessHeap(void)
263 {
264     HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process;
265     return pdb[0x18 / sizeof(HANDLE)];  /* get dword at offset 0x18 in pdb */
266 }
267
268
269 /***********************************************************************
270  *           GetProcessHeaps    (KERNEL32.@)
271  */
272 DWORD WINAPI GetProcessHeaps( DWORD count, HANDLE *heaps )
273 {
274     return RtlGetProcessHeaps( count, heaps );
275 }
276
277
278 /***********************************************************************
279  * 32-bit local heap functions (Win95; undocumented)
280  */
281
282 /***********************************************************************
283  *           K208   (KERNEL.208)
284  */
285 HANDLE WINAPI Local32Init16( WORD segment, DWORD tableSize,
286                              DWORD heapSize, DWORD flags )
287 {
288     DWORD totSize, segSize = 0;
289     LPBYTE base;
290     LOCAL32HEADER *header;
291     HANDLE heap;
292     WORD *selectorTable;
293     WORD selectorEven, selectorOdd;
294     int i, nrBlocks;
295
296     /* Determine new heap size */
297
298     if ( segment )
299     {
300         if ( (segSize = GetSelectorLimit16( segment )) == 0 )
301             return 0;
302         else
303             segSize++;
304     }
305
306     if ( heapSize == -1L )
307         heapSize = 1024L*1024L;   /* FIXME */
308
309     heapSize = (heapSize + 0xffff) & 0xffff0000;
310     segSize  = (segSize  + 0x0fff) & 0xfffff000;
311     totSize  = segSize + HTABLE_SIZE + heapSize;
312
313
314     /* Allocate memory and initialize heap */
315
316     if ( !(base = VirtualAlloc( NULL, totSize, MEM_RESERVE, PAGE_READWRITE )) )
317         return 0;
318
319     if ( !VirtualAlloc( base, segSize + HTABLE_PAGESIZE,
320                         MEM_COMMIT, PAGE_READWRITE ) )
321     {
322         VirtualFree( base, 0, MEM_RELEASE );
323         return 0;
324     }
325
326     if (!(heap = RtlCreateHeap( 0, base + segSize + HTABLE_SIZE, heapSize, 0x10000, NULL, NULL )))
327     {
328         VirtualFree( base, 0, MEM_RELEASE );
329         return 0;
330     }
331
332
333     /* Set up header and handle table */
334
335     header = (LOCAL32HEADER *)(base + segSize);
336     header->base    = base;
337     header->limit   = HTABLE_PAGESIZE-1;
338     header->flags   = 0;
339     header->magic   = LOCAL32_MAGIC;
340     header->heap    = heap;
341
342     header->freeListFirst[0] = sizeof(LOCAL32HEADER);
343     header->freeListLast[0]  = HTABLE_PAGESIZE - 4;
344     header->freeListSize[0]  = (HTABLE_PAGESIZE - sizeof(LOCAL32HEADER)) / 4;
345
346     for (i = header->freeListFirst[0]; i < header->freeListLast[0]; i += 4)
347         *(DWORD *)((LPBYTE)header + i) = i+4;
348
349     header->freeListFirst[1] = 0xffff;
350
351
352     /* Set up selector table */
353
354     nrBlocks      = (totSize + 0x7fff) >> 15;
355     selectorTable = (LPWORD) HeapAlloc( header->heap,  0, nrBlocks * 2 );
356     selectorEven  = SELECTOR_AllocBlock( base, totSize, WINE_LDT_FLAGS_DATA );
357     selectorOdd   = SELECTOR_AllocBlock( base + 0x8000, totSize - 0x8000, WINE_LDT_FLAGS_DATA );
358     if ( !selectorTable || !selectorEven || !selectorOdd )
359     {
360         if ( selectorTable ) HeapFree( header->heap, 0, selectorTable );
361         if ( selectorEven  ) SELECTOR_FreeBlock( selectorEven );
362         if ( selectorOdd   ) SELECTOR_FreeBlock( selectorOdd );
363         HeapDestroy( header->heap );
364         VirtualFree( base, 0, MEM_RELEASE );
365         return 0;
366     }
367
368     header->selectorTableOffset = (LPBYTE)selectorTable - header->base;
369     header->selectorTableSize   = nrBlocks * 4;  /* ??? Win95 does it this way! */
370     header->selectorDelta       = selectorEven - selectorOdd;
371     header->segment             = segment? segment : selectorEven;
372
373     for (i = 0; i < nrBlocks; i++)
374         selectorTable[i] = (i & 1)? selectorOdd  + ((i >> 1) << __AHSHIFT)
375                                   : selectorEven + ((i >> 1) << __AHSHIFT);
376
377     /* Move old segment */
378
379     if ( segment )
380     {
381         /* FIXME: This is somewhat ugly and relies on implementation
382                   details about 16-bit global memory handles ... */
383
384         LPBYTE oldBase = (LPBYTE)GetSelectorBase( segment );
385         memcpy( base, oldBase, segSize );
386         GLOBAL_MoveBlock( segment, base, totSize );
387         HeapFree( GetProcessHeap(), 0, oldBase );
388     }
389
390     return (HANDLE)header;
391 }
392
393 /***********************************************************************
394  *           Local32_SearchHandle
395  */
396 static LPDWORD Local32_SearchHandle( LOCAL32HEADER *header, DWORD addr )
397 {
398     LPDWORD handle;
399
400     for ( handle = (LPDWORD)((LPBYTE)header + sizeof(LOCAL32HEADER));
401           handle < (LPDWORD)((LPBYTE)header + header->limit);
402           handle++)
403     {
404         if (*handle == addr)
405             return handle;
406     }
407
408     return NULL;
409 }
410
411 /***********************************************************************
412  *           Local32_ToHandle
413  */
414 static VOID Local32_ToHandle( LOCAL32HEADER *header, INT16 type,
415                               DWORD addr, LPDWORD *handle, LPBYTE *ptr )
416 {
417     *handle = NULL;
418     *ptr    = NULL;
419
420     switch (type)
421     {
422         case -2:    /* 16:16 pointer, no handles */
423             *ptr    = MapSL( addr );
424             *handle = (LPDWORD)*ptr;
425             break;
426
427         case -1:    /* 32-bit offset, no handles */
428             *ptr    = header->base + addr;
429             *handle = (LPDWORD)*ptr;
430             break;
431
432         case 0:     /* handle */
433             if (    addr >= sizeof(LOCAL32HEADER)
434                  && addr <  header->limit && !(addr & 3)
435                  && *(LPDWORD)((LPBYTE)header + addr) >= HTABLE_SIZE )
436             {
437                 *handle = (LPDWORD)((LPBYTE)header + addr);
438                 *ptr    = header->base + **handle;
439             }
440             break;
441
442         case 1:     /* 16:16 pointer */
443             *ptr    = MapSL( addr );
444             *handle = Local32_SearchHandle( header, *ptr - header->base );
445             break;
446
447         case 2:     /* 32-bit offset */
448             *ptr    = header->base + addr;
449             *handle = Local32_SearchHandle( header, *ptr - header->base );
450             break;
451     }
452 }
453
454 /***********************************************************************
455  *           Local32_FromHandle
456  */
457 static VOID Local32_FromHandle( LOCAL32HEADER *header, INT16 type,
458                                 DWORD *addr, LPDWORD handle, LPBYTE ptr )
459 {
460     switch (type)
461     {
462         case -2:    /* 16:16 pointer */
463         case  1:
464         {
465             WORD *selTable = (LPWORD)(header->base + header->selectorTableOffset);
466             DWORD offset   = (LPBYTE)ptr - header->base;
467             *addr = MAKELONG( offset & 0x7fff, selTable[offset >> 15] );
468         }
469         break;
470
471         case -1:    /* 32-bit offset */
472         case  2:
473             *addr = ptr - header->base;
474             break;
475
476         case  0:    /* handle */
477             *addr = (LPBYTE)handle - (LPBYTE)header;
478             break;
479     }
480 }
481
482 /***********************************************************************
483  *           K209   (KERNEL.209)
484  */
485 DWORD WINAPI Local32Alloc16( HANDLE heap, DWORD size, INT16 type, DWORD flags )
486 {
487     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
488     LPDWORD handle;
489     LPBYTE ptr;
490     DWORD addr;
491
492     /* Allocate memory */
493     ptr = HeapAlloc( header->heap,
494                      (flags & LMEM_MOVEABLE)? HEAP_ZERO_MEMORY : 0, size );
495     if (!ptr) return 0;
496
497
498     /* Allocate handle if requested */
499     if (type >= 0)
500     {
501         int page, i;
502
503         /* Find first page of handle table with free slots */
504         for (page = 0; page < HTABLE_NPAGES; page++)
505             if (header->freeListFirst[page] != 0)
506                 break;
507         if (page == HTABLE_NPAGES)
508         {
509             WARN("Out of handles!\n" );
510             HeapFree( header->heap, 0, ptr );
511             return 0;
512         }
513
514         /* If virgin page, initialize it */
515         if (header->freeListFirst[page] == 0xffff)
516         {
517             if ( !VirtualAlloc( (LPBYTE)header + (page << 12),
518                                 0x1000, MEM_COMMIT, PAGE_READWRITE ) )
519             {
520                 WARN("Cannot grow handle table!\n" );
521                 HeapFree( header->heap, 0, ptr );
522                 return 0;
523             }
524
525             header->limit += HTABLE_PAGESIZE;
526
527             header->freeListFirst[page] = 0;
528             header->freeListLast[page]  = HTABLE_PAGESIZE - 4;
529             header->freeListSize[page]  = HTABLE_PAGESIZE / 4;
530
531             for (i = 0; i < HTABLE_PAGESIZE; i += 4)
532                 *(DWORD *)((LPBYTE)header + i) = i+4;
533
534             if (page < HTABLE_NPAGES-1)
535                 header->freeListFirst[page+1] = 0xffff;
536         }
537
538         /* Allocate handle slot from page */
539         handle = (LPDWORD)((LPBYTE)header + header->freeListFirst[page]);
540         if (--header->freeListSize[page] == 0)
541             header->freeListFirst[page] = header->freeListLast[page] = 0;
542         else
543             header->freeListFirst[page] = *handle;
544
545         /* Store 32-bit offset in handle slot */
546         *handle = ptr - header->base;
547     }
548     else
549     {
550         handle = (LPDWORD)ptr;
551         header->flags |= 1;
552     }
553
554
555     /* Convert handle to requested output type */
556     Local32_FromHandle( header, type, &addr, handle, ptr );
557     return addr;
558 }
559
560 /***********************************************************************
561  *           K210   (KERNEL.210)
562  */
563 DWORD WINAPI Local32ReAlloc16( HANDLE heap, DWORD addr, INT16 type,
564                              DWORD size, DWORD flags )
565 {
566     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
567     LPDWORD handle;
568     LPBYTE ptr;
569
570     if (!addr)
571         return Local32Alloc16( heap, size, type, flags );
572
573     /* Retrieve handle and pointer */
574     Local32_ToHandle( header, type, addr, &handle, &ptr );
575     if (!handle) return FALSE;
576
577     /* Reallocate memory block */
578     ptr = HeapReAlloc( header->heap,
579                        (flags & LMEM_MOVEABLE)? HEAP_ZERO_MEMORY : 0,
580                        ptr, size );
581     if (!ptr) return 0;
582
583     /* Modify handle */
584     if (type >= 0)
585         *handle = ptr - header->base;
586     else
587         handle = (LPDWORD)ptr;
588
589     /* Convert handle to requested output type */
590     Local32_FromHandle( header, type, &addr, handle, ptr );
591     return addr;
592 }
593
594 /***********************************************************************
595  *           K211   (KERNEL.211)
596  */
597 BOOL WINAPI Local32Free16( HANDLE heap, DWORD addr, INT16 type )
598 {
599     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
600     LPDWORD handle;
601     LPBYTE ptr;
602
603     /* Retrieve handle and pointer */
604     Local32_ToHandle( header, type, addr, &handle, &ptr );
605     if (!handle) return FALSE;
606
607     /* Free handle if necessary */
608     if (type >= 0)
609     {
610         int offset = (LPBYTE)handle - (LPBYTE)header;
611         int page   = offset >> 12;
612
613         /* Return handle slot to page free list */
614         if (header->freeListSize[page]++ == 0)
615             header->freeListFirst[page] = header->freeListLast[page]  = offset;
616         else
617             *(LPDWORD)((LPBYTE)header + header->freeListLast[page]) = offset,
618             header->freeListLast[page] = offset;
619
620         *handle = 0;
621
622         /* Shrink handle table when possible */
623         while (page > 0 && header->freeListSize[page] == HTABLE_PAGESIZE / 4)
624         {
625             if ( VirtualFree( (LPBYTE)header +
626                               (header->limit & ~(HTABLE_PAGESIZE-1)),
627                               HTABLE_PAGESIZE, MEM_DECOMMIT ) )
628                 break;
629
630             header->limit -= HTABLE_PAGESIZE;
631             header->freeListFirst[page] = 0xffff;
632             page--;
633         }
634     }
635
636     /* Free memory */
637     return HeapFree( header->heap, 0, ptr );
638 }
639
640 /***********************************************************************
641  *           K213   (KERNEL.213)
642  */
643 DWORD WINAPI Local32Translate16( HANDLE heap, DWORD addr, INT16 type1, INT16 type2 )
644 {
645     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
646     LPDWORD handle;
647     LPBYTE ptr;
648
649     Local32_ToHandle( header, type1, addr, &handle, &ptr );
650     if (!handle) return 0;
651
652     Local32_FromHandle( header, type2, &addr, handle, ptr );
653     return addr;
654 }
655
656 /***********************************************************************
657  *           K214   (KERNEL.214)
658  */
659 DWORD WINAPI Local32Size16( HANDLE heap, DWORD addr, INT16 type )
660 {
661     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
662     LPDWORD handle;
663     LPBYTE ptr;
664
665     Local32_ToHandle( header, type, addr, &handle, &ptr );
666     if (!handle) return 0;
667
668     return HeapSize( header->heap, 0, ptr );
669 }
670
671 /***********************************************************************
672  *           K215   (KERNEL.215)
673  */
674 BOOL WINAPI Local32ValidHandle16( HANDLE heap, WORD addr )
675 {
676     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
677     LPDWORD handle;
678     LPBYTE ptr;
679
680     Local32_ToHandle( header, 0, addr, &handle, &ptr );
681     return handle != NULL;
682 }
683
684 /***********************************************************************
685  *           K229   (KERNEL.229)
686  */
687 WORD WINAPI Local32GetSegment16( HANDLE heap )
688 {
689     LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
690     return header->segment;
691 }
692
693 /***********************************************************************
694  *           Local32_GetHeap
695  */
696 static LOCAL32HEADER *Local32_GetHeap( HGLOBAL16 handle )
697 {
698     WORD selector = GlobalHandleToSel16( handle );
699     DWORD base  = GetSelectorBase( selector );
700     DWORD limit = GetSelectorLimit16( selector );
701
702     /* Hmmm. This is a somewhat stupid heuristic, but Windows 95 does
703        it this way ... */
704
705     if ( limit > 0x10000 && ((LOCAL32HEADER *)base)->magic == LOCAL32_MAGIC )
706         return (LOCAL32HEADER *)base;
707
708     base  += 0x10000;
709     limit -= 0x10000;
710
711     if ( limit > 0x10000 && ((LOCAL32HEADER *)base)->magic == LOCAL32_MAGIC )
712         return (LOCAL32HEADER *)base;
713
714     return NULL;
715 }
716
717 /***********************************************************************
718  *           Local32Info   (KERNEL.444)
719  *           Local32Info   (TOOLHELP.84)
720  */
721 BOOL16 WINAPI Local32Info16( LOCAL32INFO *pLocal32Info, HGLOBAL16 handle )
722 {
723     PROCESS_HEAP_ENTRY entry;
724     int i;
725
726     LOCAL32HEADER *header = Local32_GetHeap( handle );
727     if ( !header ) return FALSE;
728
729     if ( !pLocal32Info || pLocal32Info->dwSize < sizeof(LOCAL32INFO) )
730         return FALSE;
731
732     pLocal32Info->dwMemReserved = 0;
733     pLocal32Info->dwMemCommitted = 0;
734     pLocal32Info->dwTotalFree = 0;
735     pLocal32Info->dwLargestFreeBlock = 0;
736
737     while (HeapWalk( header->heap, &entry ))
738     {
739         if (entry.wFlags & PROCESS_HEAP_REGION)
740         {
741             pLocal32Info->dwMemReserved += entry.u.Region.dwCommittedSize
742                                            + entry.u.Region.dwUnCommittedSize;
743             pLocal32Info->dwMemCommitted = entry.u.Region.dwCommittedSize;
744         }
745         else if (!(entry.wFlags & PROCESS_HEAP_ENTRY_BUSY))
746         {
747             DWORD size = entry.cbData + entry.cbOverhead;
748             pLocal32Info->dwTotalFree += size;
749             if (size > pLocal32Info->dwLargestFreeBlock) pLocal32Info->dwLargestFreeBlock = size;
750         }
751     }
752
753     pLocal32Info->dwcFreeHandles = 0;
754     for ( i = 0; i < HTABLE_NPAGES; i++ )
755     {
756         if ( header->freeListFirst[i] == 0xffff ) break;
757         pLocal32Info->dwcFreeHandles += header->freeListSize[i];
758     }
759     pLocal32Info->dwcFreeHandles += (HTABLE_NPAGES - i) * HTABLE_PAGESIZE/4;
760
761     return TRUE;
762 }
763
764 /***********************************************************************
765  *           Local32First   (KERNEL.445)
766  *           Local32First   (TOOLHELP.85)
767  */
768 BOOL16 WINAPI Local32First16( LOCAL32ENTRY *pLocal32Entry, HGLOBAL16 handle )
769 {
770     FIXME("(%p, %04X): stub!\n", pLocal32Entry, handle );
771     return FALSE;
772 }
773
774 /***********************************************************************
775  *           Local32Next   (KERNEL.446)
776  *           Local32Next   (TOOLHELP.86)
777  */
778 BOOL16 WINAPI Local32Next16( LOCAL32ENTRY *pLocal32Entry )
779 {
780     FIXME("(%p): stub!\n", pLocal32Entry );
781     return FALSE;
782 }
783
784
785 /* FIXME: these functions are needed for dlls that aren't properly separated yet */
786
787 LPVOID WINAPI HeapAlloc( HANDLE heap, DWORD flags, SIZE_T size )
788 {
789     return RtlAllocateHeap( heap, flags, size );
790 }
791
792 BOOL WINAPI HeapFree( HANDLE heap, DWORD flags, LPVOID ptr )
793 {
794     return RtlFreeHeap( heap, flags, ptr );
795 }
796
797 LPVOID WINAPI HeapReAlloc( HANDLE heap, DWORD flags, LPVOID ptr, SIZE_T size )
798 {
799     return RtlReAllocateHeap( heap, flags, ptr, size );
800 }
801
802 SIZE_T WINAPI HeapSize( HANDLE heap, DWORD flags, LPVOID ptr )
803 {
804     return RtlSizeHeap( heap, flags, ptr );
805 }
806
807 void WINAPI EnterCriticalSection( CRITICAL_SECTION *crit )
808 {
809     RtlEnterCriticalSection( crit );
810 }
811
812 BOOL WINAPI TryEnterCriticalSection( CRITICAL_SECTION *crit )
813 {
814     return RtlTryEnterCriticalSection( crit );
815 }
816
817 void WINAPI DeleteCriticalSection( CRITICAL_SECTION *crit )
818 {
819     RtlDeleteCriticalSection( crit );
820 }
821
822 void WINAPI LeaveCriticalSection( CRITICAL_SECTION *crit )
823 {
824     RtlLeaveCriticalSection( crit );
825 }