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