blob: 61548983662d021cdbf5c032453e4e977108a8ba [file] [log] [blame]
Alexandre Julliard329f0681996-04-14 13:21:20 +00001/*
2 * Win32 heap functions
3 *
4 * Copyright 1996 Alexandre Julliard
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00005 * Copyright 1998 Ulrich Weigand
Alexandre Julliard329f0681996-04-14 13:21:20 +00006 */
7
Francois Gougete5ddd262001-10-14 16:18:52 +00008#include "config.h"
9
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000010#include <assert.h>
Alexandre Julliard329f0681996-04-14 13:21:20 +000011#include <stdlib.h>
Alexandre Julliard383da682000-02-10 22:15:21 +000012#include <stdio.h>
Alexandre Julliard329f0681996-04-14 13:21:20 +000013#include <string.h>
Francois Gougete5ddd262001-10-14 16:18:52 +000014
Alexandre Julliardb0f58612001-12-19 19:16:27 +000015#include "winbase.h"
Marcus Meissner04c3e1d1999-02-19 10:37:02 +000016#include "wine/winbase16.h"
Alexandre Julliardb0f58612001-12-19 19:16:27 +000017#include "winerror.h"
18#include "winnt.h"
19#include "ntddk.h"
Alexandre Julliardc7e7df82000-08-14 14:41:19 +000020#include "wine/unicode.h"
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +000021#include "selectors.h"
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000022#include "global.h"
Alexandre Julliardb0f58612001-12-19 19:16:27 +000023#include "thread.h"
Ulrich Weigand416d39e1998-12-01 14:45:37 +000024#include "toolhelp.h"
Alexandre Julliard15657091999-05-23 10:25:25 +000025#include "debugtools.h"
Alexandre Julliard329f0681996-04-14 13:21:20 +000026
Alexandre Julliard383da682000-02-10 22:15:21 +000027DEFAULT_DEBUG_CHANNEL(heap);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000028
Alexandre Julliard079fd722000-01-25 01:41:35 +000029/* address where we try to map the system heap */
30#define SYSTEM_HEAP_BASE ((void*)0x65430000)
Alexandre Julliardb0f58612001-12-19 19:16:27 +000031#define SYSTEM_HEAP_SIZE 0x100000 /* Default heap size = 1Mb */
Alexandre Julliard079fd722000-01-25 01:41:35 +000032
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000033
34#define HTABLE_SIZE 0x10000
35#define HTABLE_PAGESIZE 0x1000
36#define HTABLE_NPAGES (HTABLE_SIZE / HTABLE_PAGESIZE)
37
Patrik Stridvallc7a8dde1999-04-25 12:36:53 +000038#include "pshpack1.h"
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000039typedef struct _LOCAL32HEADER
40{
41 WORD freeListFirst[HTABLE_NPAGES];
42 WORD freeListSize[HTABLE_NPAGES];
43 WORD freeListLast[HTABLE_NPAGES];
44
45 DWORD selectorTableOffset;
46 WORD selectorTableSize;
47 WORD selectorDelta;
48
49 DWORD segment;
50 LPBYTE base;
51
52 DWORD limit;
53 DWORD flags;
54
55 DWORD magic;
Alexandre Julliarda3960291999-02-26 11:11:13 +000056 HANDLE heap;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000057
58} LOCAL32HEADER;
Patrik Stridvallc7a8dde1999-04-25 12:36:53 +000059#include "poppack.h"
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000060
61#define LOCAL32_MAGIC ((DWORD)('L' | ('H'<<8) | ('3'<<16) | ('2'<<24)))
62
Alexandre Julliardb0f58612001-12-19 19:16:27 +000063static HANDLE systemHeap; /* globally shared heap */
64
65/***********************************************************************
66 * HEAP_CreateSystemHeap
67 *
68 * Create the system heap.
69 */
70inline static HANDLE HEAP_CreateSystemHeap(void)
71{
72 int created;
73 void *base;
74 HANDLE map, event;
75 UNICODE_STRING event_name;
76 OBJECT_ATTRIBUTES event_attr;
77
78 if (!(map = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE,
79 0, SYSTEM_HEAP_SIZE, "__SystemHeap" ))) return 0;
80 created = (GetLastError() != ERROR_ALREADY_EXISTS);
81
82 if (!(base = MapViewOfFileEx( map, FILE_MAP_ALL_ACCESS, 0, 0, 0, SYSTEM_HEAP_BASE )))
83 {
84 /* pre-defined address not available */
85 ERR( "system heap base address %p not available\n", SYSTEM_HEAP_BASE );
86 return 0;
87 }
88
89 /* create the system heap event */
90 RtlCreateUnicodeStringFromAsciiz( &event_name, "__SystemHeapEvent" );
91 event_attr.Length = sizeof(event_attr);
92 event_attr.RootDirectory = 0;
93 event_attr.ObjectName = &event_name;
94 event_attr.Attributes = 0;
95 event_attr.SecurityDescriptor = NULL;
96 event_attr.SecurityQualityOfService = NULL;
97 NtCreateEvent( &event, EVENT_ALL_ACCESS, &event_attr, TRUE, FALSE );
98
99 if (created) /* newly created heap */
100 {
101 systemHeap = RtlCreateHeap( HEAP_SHARED, base, SYSTEM_HEAP_SIZE,
102 SYSTEM_HEAP_SIZE, NULL, NULL );
103 NtSetEvent( event, NULL );
104 }
105 else
106 {
107 /* wait for the heap to be initialized */
108 WaitForSingleObject( event, INFINITE );
Alexandre Julliard77dc0092001-12-26 20:38:53 +0000109 systemHeap = (HANDLE)base;
Alexandre Julliardb0f58612001-12-19 19:16:27 +0000110 }
111 CloseHandle( map );
112 return systemHeap;
113}
114
115
116/***********************************************************************
117 * HeapCreate (KERNEL32.@)
118 * RETURNS
119 * Handle of heap: Success
120 * NULL: Failure
121 */
122HANDLE WINAPI HeapCreate(
123 DWORD flags, /* [in] Heap allocation flag */
124 DWORD initialSize, /* [in] Initial heap size */
125 DWORD maxSize /* [in] Maximum heap size */
126) {
127 HANDLE ret;
128
129 if ( flags & HEAP_SHARED )
130 {
131 if (!systemHeap) HEAP_CreateSystemHeap();
132 else WARN( "Shared Heap requested, returning system heap.\n" );
133 ret = systemHeap;
134 }
135 else
136 {
137 ret = RtlCreateHeap( flags, NULL, maxSize, initialSize, NULL, NULL );
138 if (!ret) SetLastError( ERROR_NOT_ENOUGH_MEMORY );
139 }
140 return ret;
141}
142
143/***********************************************************************
144 * HeapDestroy (KERNEL32.@)
145 * RETURNS
146 * TRUE: Success
147 * FALSE: Failure
148 */
149BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ )
150{
151 if (heap == systemHeap)
152 {
153 WARN( "attempt to destroy system heap, returning TRUE!\n" );
154 return TRUE;
155 }
156 if (!RtlDestroyHeap( heap )) return TRUE;
157 SetLastError( ERROR_INVALID_HANDLE );
158 return FALSE;
159}
160
161
162/***********************************************************************
163 * HeapCompact (KERNEL32.@)
164 */
165DWORD WINAPI HeapCompact( HANDLE heap, DWORD flags )
166{
167 return RtlCompactHeap( heap, flags );
168}
169
170
171/***********************************************************************
172 * HeapLock (KERNEL32.@)
173 * Attempts to acquire the critical section object for a specified heap.
174 *
175 * RETURNS
176 * TRUE: Success
177 * FALSE: Failure
178 */
179BOOL WINAPI HeapLock(
180 HANDLE heap /* [in] Handle of heap to lock for exclusive access */
181) {
182 return RtlLockHeap( heap );
183}
184
185
186/***********************************************************************
187 * HeapUnlock (KERNEL32.@)
188 * Releases ownership of the critical section object.
189 *
190 * RETURNS
191 * TRUE: Success
192 * FALSE: Failure
193 */
194BOOL WINAPI HeapUnlock(
195 HANDLE heap /* [in] Handle to the heap to unlock */
196) {
197 return RtlUnlockHeap( heap );
198}
199
200
201/***********************************************************************
202 * HeapValidate (KERNEL32.@)
203 * Validates a specified heap.
204 *
205 * NOTES
206 * Flags is ignored.
207 *
208 * RETURNS
209 * TRUE: Success
210 * FALSE: Failure
211 */
212BOOL WINAPI HeapValidate(
213 HANDLE heap, /* [in] Handle to the heap */
214 DWORD flags, /* [in] Bit flags that control access during operation */
215 LPCVOID block /* [in] Optional pointer to memory block to validate */
216) {
217 return RtlValidateHeap( heap, flags, block );
218}
219
220
221/***********************************************************************
222 * HeapWalk (KERNEL32.@)
223 * Enumerates the memory blocks in a specified heap.
224 *
225 * TODO
226 * - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
227 * PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support)
228 *
229 * RETURNS
230 * TRUE: Success
231 * FALSE: Failure
232 */
233BOOL WINAPI HeapWalk(
234 HANDLE heap, /* [in] Handle to heap to enumerate */
235 LPPROCESS_HEAP_ENTRY entry /* [out] Pointer to structure of enumeration info */
236) {
237 NTSTATUS ret = RtlWalkHeap( heap, entry );
238 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
239 return !ret;
240}
241
242
243/***********************************************************************
244 * GetProcessHeap (KERNEL32.@)
245 */
246HANDLE WINAPI GetProcessHeap(void)
247{
248 HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process;
249 return pdb[0x18 / sizeof(HANDLE)]; /* get dword at offset 0x18 in pdb */
250}
251
252
253/***********************************************************************
254 * GetProcessHeaps (KERNEL32.@)
255 */
256DWORD WINAPI GetProcessHeaps( DWORD count, HANDLE *heaps )
257{
258 return RtlGetProcessHeaps( count, heaps );
259}
260
261
262/***********************************************************************
263 * 32-bit local heap functions (Win95; undocumented)
264 */
265
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000266/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000267 * K208 (KERNEL.208)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000268 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000269HANDLE WINAPI Local32Init16( WORD segment, DWORD tableSize,
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000270 DWORD heapSize, DWORD flags )
271{
272 DWORD totSize, segSize = 0;
273 LPBYTE base;
274 LOCAL32HEADER *header;
Alexandre Julliardb0f58612001-12-19 19:16:27 +0000275 HANDLE heap;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000276 WORD *selectorTable;
277 WORD selectorEven, selectorOdd;
278 int i, nrBlocks;
279
280 /* Determine new heap size */
281
282 if ( segment )
Jesper Skov5c3e4571998-11-01 19:27:22 +0000283 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000284 if ( (segSize = GetSelectorLimit16( segment )) == 0 )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000285 return 0;
286 else
287 segSize++;
Jesper Skov5c3e4571998-11-01 19:27:22 +0000288 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000289
290 if ( heapSize == -1L )
291 heapSize = 1024L*1024L; /* FIXME */
292
293 heapSize = (heapSize + 0xffff) & 0xffff0000;
294 segSize = (segSize + 0x0fff) & 0xfffff000;
295 totSize = segSize + HTABLE_SIZE + heapSize;
296
297
298 /* Allocate memory and initialize heap */
299
300 if ( !(base = VirtualAlloc( NULL, totSize, MEM_RESERVE, PAGE_READWRITE )) )
301 return 0;
302
303 if ( !VirtualAlloc( base, segSize + HTABLE_PAGESIZE,
304 MEM_COMMIT, PAGE_READWRITE ) )
305 {
306 VirtualFree( base, 0, MEM_RELEASE );
307 return 0;
308 }
309
Alexandre Julliardb0f58612001-12-19 19:16:27 +0000310 if (!(heap = RtlCreateHeap( 0, base + segSize + HTABLE_SIZE, heapSize, 0x10000, NULL, NULL )))
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000311 {
312 VirtualFree( base, 0, MEM_RELEASE );
313 return 0;
314 }
315
316
317 /* Set up header and handle table */
318
319 header = (LOCAL32HEADER *)(base + segSize);
320 header->base = base;
321 header->limit = HTABLE_PAGESIZE-1;
322 header->flags = 0;
323 header->magic = LOCAL32_MAGIC;
Alexandre Julliardb0f58612001-12-19 19:16:27 +0000324 header->heap = heap;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000325
326 header->freeListFirst[0] = sizeof(LOCAL32HEADER);
327 header->freeListLast[0] = HTABLE_PAGESIZE - 4;
328 header->freeListSize[0] = (HTABLE_PAGESIZE - sizeof(LOCAL32HEADER)) / 4;
329
330 for (i = header->freeListFirst[0]; i < header->freeListLast[0]; i += 4)
331 *(DWORD *)((LPBYTE)header + i) = i+4;
332
333 header->freeListFirst[1] = 0xffff;
334
335
336 /* Set up selector table */
337
338 nrBlocks = (totSize + 0x7fff) >> 15;
339 selectorTable = (LPWORD) HeapAlloc( header->heap, 0, nrBlocks * 2 );
Alexandre Julliard914406f2000-11-14 01:54:49 +0000340 selectorEven = SELECTOR_AllocBlock( base, totSize, WINE_LDT_FLAGS_DATA );
341 selectorOdd = SELECTOR_AllocBlock( base + 0x8000, totSize - 0x8000, WINE_LDT_FLAGS_DATA );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000342 if ( !selectorTable || !selectorEven || !selectorOdd )
343 {
344 if ( selectorTable ) HeapFree( header->heap, 0, selectorTable );
Alexandre Julliard914406f2000-11-14 01:54:49 +0000345 if ( selectorEven ) SELECTOR_FreeBlock( selectorEven );
346 if ( selectorOdd ) SELECTOR_FreeBlock( selectorOdd );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000347 HeapDestroy( header->heap );
348 VirtualFree( base, 0, MEM_RELEASE );
349 return 0;
350 }
351
352 header->selectorTableOffset = (LPBYTE)selectorTable - header->base;
353 header->selectorTableSize = nrBlocks * 4; /* ??? Win95 does it this way! */
354 header->selectorDelta = selectorEven - selectorOdd;
355 header->segment = segment? segment : selectorEven;
356
357 for (i = 0; i < nrBlocks; i++)
358 selectorTable[i] = (i & 1)? selectorOdd + ((i >> 1) << __AHSHIFT)
359 : selectorEven + ((i >> 1) << __AHSHIFT);
360
361 /* Move old segment */
362
363 if ( segment )
364 {
365 /* FIXME: This is somewhat ugly and relies on implementation
366 details about 16-bit global memory handles ... */
367
368 LPBYTE oldBase = (LPBYTE)GetSelectorBase( segment );
369 memcpy( base, oldBase, segSize );
370 GLOBAL_MoveBlock( segment, base, totSize );
Alexandre Julliard7f187e52001-02-23 01:37:05 +0000371 HeapFree( GetProcessHeap(), 0, oldBase );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000372 }
373
Alexandre Julliarda3960291999-02-26 11:11:13 +0000374 return (HANDLE)header;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000375}
376
377/***********************************************************************
378 * Local32_SearchHandle
379 */
380static LPDWORD Local32_SearchHandle( LOCAL32HEADER *header, DWORD addr )
381{
382 LPDWORD handle;
383
384 for ( handle = (LPDWORD)((LPBYTE)header + sizeof(LOCAL32HEADER));
385 handle < (LPDWORD)((LPBYTE)header + header->limit);
386 handle++)
387 {
388 if (*handle == addr)
389 return handle;
390 }
391
392 return NULL;
393}
394
395/***********************************************************************
396 * Local32_ToHandle
397 */
398static VOID Local32_ToHandle( LOCAL32HEADER *header, INT16 type,
399 DWORD addr, LPDWORD *handle, LPBYTE *ptr )
400{
401 *handle = NULL;
402 *ptr = NULL;
403
404 switch (type)
405 {
406 case -2: /* 16:16 pointer, no handles */
Alexandre Julliard982a2232000-12-13 20:20:09 +0000407 *ptr = MapSL( addr );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000408 *handle = (LPDWORD)*ptr;
409 break;
410
411 case -1: /* 32-bit offset, no handles */
412 *ptr = header->base + addr;
413 *handle = (LPDWORD)*ptr;
414 break;
415
416 case 0: /* handle */
417 if ( addr >= sizeof(LOCAL32HEADER)
418 && addr < header->limit && !(addr & 3)
419 && *(LPDWORD)((LPBYTE)header + addr) >= HTABLE_SIZE )
420 {
421 *handle = (LPDWORD)((LPBYTE)header + addr);
422 *ptr = header->base + **handle;
423 }
424 break;
425
426 case 1: /* 16:16 pointer */
Alexandre Julliard982a2232000-12-13 20:20:09 +0000427 *ptr = MapSL( addr );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000428 *handle = Local32_SearchHandle( header, *ptr - header->base );
429 break;
430
431 case 2: /* 32-bit offset */
432 *ptr = header->base + addr;
433 *handle = Local32_SearchHandle( header, *ptr - header->base );
434 break;
435 }
436}
437
438/***********************************************************************
439 * Local32_FromHandle
440 */
441static VOID Local32_FromHandle( LOCAL32HEADER *header, INT16 type,
442 DWORD *addr, LPDWORD handle, LPBYTE ptr )
443{
444 switch (type)
445 {
446 case -2: /* 16:16 pointer */
447 case 1:
448 {
449 WORD *selTable = (LPWORD)(header->base + header->selectorTableOffset);
450 DWORD offset = (LPBYTE)ptr - header->base;
451 *addr = MAKELONG( offset & 0x7fff, selTable[offset >> 15] );
452 }
453 break;
454
455 case -1: /* 32-bit offset */
456 case 2:
457 *addr = ptr - header->base;
458 break;
459
460 case 0: /* handle */
461 *addr = (LPBYTE)handle - (LPBYTE)header;
462 break;
463 }
464}
465
466/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000467 * K209 (KERNEL.209)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000468 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000469DWORD WINAPI Local32Alloc16( HANDLE heap, DWORD size, INT16 type, DWORD flags )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000470{
471 LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
472 LPDWORD handle;
473 LPBYTE ptr;
474 DWORD addr;
475
476 /* Allocate memory */
477 ptr = HeapAlloc( header->heap,
478 (flags & LMEM_MOVEABLE)? HEAP_ZERO_MEMORY : 0, size );
479 if (!ptr) return 0;
480
481
482 /* Allocate handle if requested */
483 if (type >= 0)
484 {
485 int page, i;
486
487 /* Find first page of handle table with free slots */
488 for (page = 0; page < HTABLE_NPAGES; page++)
489 if (header->freeListFirst[page] != 0)
490 break;
491 if (page == HTABLE_NPAGES)
492 {
Alexandre Julliard15657091999-05-23 10:25:25 +0000493 WARN("Out of handles!\n" );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000494 HeapFree( header->heap, 0, ptr );
495 return 0;
496 }
497
498 /* If virgin page, initialize it */
499 if (header->freeListFirst[page] == 0xffff)
500 {
501 if ( !VirtualAlloc( (LPBYTE)header + (page << 12),
502 0x1000, MEM_COMMIT, PAGE_READWRITE ) )
503 {
Alexandre Julliard15657091999-05-23 10:25:25 +0000504 WARN("Cannot grow handle table!\n" );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000505 HeapFree( header->heap, 0, ptr );
506 return 0;
507 }
508
509 header->limit += HTABLE_PAGESIZE;
510
511 header->freeListFirst[page] = 0;
512 header->freeListLast[page] = HTABLE_PAGESIZE - 4;
513 header->freeListSize[page] = HTABLE_PAGESIZE / 4;
514
515 for (i = 0; i < HTABLE_PAGESIZE; i += 4)
516 *(DWORD *)((LPBYTE)header + i) = i+4;
517
Ulrich Weigand38882461998-10-14 18:00:23 +0000518 if (page < HTABLE_NPAGES-1)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000519 header->freeListFirst[page+1] = 0xffff;
520 }
521
522 /* Allocate handle slot from page */
523 handle = (LPDWORD)((LPBYTE)header + header->freeListFirst[page]);
524 if (--header->freeListSize[page] == 0)
525 header->freeListFirst[page] = header->freeListLast[page] = 0;
526 else
527 header->freeListFirst[page] = *handle;
528
529 /* Store 32-bit offset in handle slot */
530 *handle = ptr - header->base;
531 }
532 else
533 {
534 handle = (LPDWORD)ptr;
535 header->flags |= 1;
536 }
537
538
539 /* Convert handle to requested output type */
540 Local32_FromHandle( header, type, &addr, handle, ptr );
541 return addr;
542}
543
544/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000545 * K210 (KERNEL.210)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000546 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000547DWORD WINAPI Local32ReAlloc16( HANDLE heap, DWORD addr, INT16 type,
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000548 DWORD size, DWORD flags )
549{
550 LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
551 LPDWORD handle;
552 LPBYTE ptr;
553
554 if (!addr)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000555 return Local32Alloc16( heap, size, type, flags );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000556
557 /* Retrieve handle and pointer */
558 Local32_ToHandle( header, type, addr, &handle, &ptr );
559 if (!handle) return FALSE;
560
561 /* Reallocate memory block */
562 ptr = HeapReAlloc( header->heap,
563 (flags & LMEM_MOVEABLE)? HEAP_ZERO_MEMORY : 0,
564 ptr, size );
565 if (!ptr) return 0;
566
567 /* Modify handle */
568 if (type >= 0)
569 *handle = ptr - header->base;
570 else
571 handle = (LPDWORD)ptr;
572
573 /* Convert handle to requested output type */
574 Local32_FromHandle( header, type, &addr, handle, ptr );
575 return addr;
576}
577
578/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000579 * K211 (KERNEL.211)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000580 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000581BOOL WINAPI Local32Free16( HANDLE heap, DWORD addr, INT16 type )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000582{
583 LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
584 LPDWORD handle;
585 LPBYTE ptr;
586
587 /* Retrieve handle and pointer */
588 Local32_ToHandle( header, type, addr, &handle, &ptr );
589 if (!handle) return FALSE;
590
591 /* Free handle if necessary */
592 if (type >= 0)
593 {
594 int offset = (LPBYTE)handle - (LPBYTE)header;
595 int page = offset >> 12;
596
597 /* Return handle slot to page free list */
598 if (header->freeListSize[page]++ == 0)
599 header->freeListFirst[page] = header->freeListLast[page] = offset;
600 else
601 *(LPDWORD)((LPBYTE)header + header->freeListLast[page]) = offset,
Ulrich Weigand38882461998-10-14 18:00:23 +0000602 header->freeListLast[page] = offset;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000603
604 *handle = 0;
605
606 /* Shrink handle table when possible */
607 while (page > 0 && header->freeListSize[page] == HTABLE_PAGESIZE / 4)
608 {
609 if ( VirtualFree( (LPBYTE)header +
610 (header->limit & ~(HTABLE_PAGESIZE-1)),
611 HTABLE_PAGESIZE, MEM_DECOMMIT ) )
612 break;
613
614 header->limit -= HTABLE_PAGESIZE;
Ulrich Weigand38882461998-10-14 18:00:23 +0000615 header->freeListFirst[page] = 0xffff;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000616 page--;
617 }
618 }
619
620 /* Free memory */
621 return HeapFree( header->heap, 0, ptr );
622}
623
624/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000625 * K213 (KERNEL.213)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000626 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000627DWORD WINAPI Local32Translate16( HANDLE heap, DWORD addr, INT16 type1, INT16 type2 )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000628{
629 LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
630 LPDWORD handle;
631 LPBYTE ptr;
632
633 Local32_ToHandle( header, type1, addr, &handle, &ptr );
634 if (!handle) return 0;
635
636 Local32_FromHandle( header, type2, &addr, handle, ptr );
637 return addr;
638}
639
640/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000641 * K214 (KERNEL.214)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000642 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000643DWORD WINAPI Local32Size16( HANDLE heap, DWORD addr, INT16 type )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000644{
645 LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
646 LPDWORD handle;
647 LPBYTE ptr;
648
649 Local32_ToHandle( header, type, addr, &handle, &ptr );
650 if (!handle) return 0;
651
652 return HeapSize( header->heap, 0, ptr );
653}
654
655/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000656 * K215 (KERNEL.215)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000657 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000658BOOL WINAPI Local32ValidHandle16( HANDLE heap, WORD addr )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000659{
660 LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
661 LPDWORD handle;
662 LPBYTE ptr;
663
664 Local32_ToHandle( header, 0, addr, &handle, &ptr );
665 return handle != NULL;
666}
667
668/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000669 * K229 (KERNEL.229)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000670 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000671WORD WINAPI Local32GetSegment16( HANDLE heap )
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000672{
673 LOCAL32HEADER *header = (LOCAL32HEADER *)heap;
674 return header->segment;
675}
676
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000677/***********************************************************************
678 * Local32_GetHeap
679 */
680static LOCAL32HEADER *Local32_GetHeap( HGLOBAL16 handle )
681{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000682 WORD selector = GlobalHandleToSel16( handle );
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000683 DWORD base = GetSelectorBase( selector );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000684 DWORD limit = GetSelectorLimit16( selector );
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000685
686 /* Hmmm. This is a somewhat stupid heuristic, but Windows 95 does
687 it this way ... */
688
689 if ( limit > 0x10000 && ((LOCAL32HEADER *)base)->magic == LOCAL32_MAGIC )
690 return (LOCAL32HEADER *)base;
691
692 base += 0x10000;
693 limit -= 0x10000;
694
695 if ( limit > 0x10000 && ((LOCAL32HEADER *)base)->magic == LOCAL32_MAGIC )
696 return (LOCAL32HEADER *)base;
697
698 return NULL;
699}
700
701/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000702 * Local32Info (KERNEL.444)
703 * Local32Info (TOOLHELP.84)
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000704 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000705BOOL16 WINAPI Local32Info16( LOCAL32INFO *pLocal32Info, HGLOBAL16 handle )
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000706{
Alexandre Julliardb0f58612001-12-19 19:16:27 +0000707 PROCESS_HEAP_ENTRY entry;
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000708 int i;
709
710 LOCAL32HEADER *header = Local32_GetHeap( handle );
711 if ( !header ) return FALSE;
712
713 if ( !pLocal32Info || pLocal32Info->dwSize < sizeof(LOCAL32INFO) )
714 return FALSE;
715
Alexandre Julliardb0f58612001-12-19 19:16:27 +0000716 pLocal32Info->dwMemReserved = 0;
717 pLocal32Info->dwMemCommitted = 0;
718 pLocal32Info->dwTotalFree = 0;
719 pLocal32Info->dwLargestFreeBlock = 0;
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000720
Alexandre Julliardb0f58612001-12-19 19:16:27 +0000721 while (HeapWalk( header->heap, &entry ))
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000722 {
Alexandre Julliardb0f58612001-12-19 19:16:27 +0000723 if (entry.wFlags & PROCESS_HEAP_REGION)
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000724 {
Alexandre Julliardb0f58612001-12-19 19:16:27 +0000725 pLocal32Info->dwMemReserved += entry.u.Region.dwCommittedSize
726 + entry.u.Region.dwUnCommittedSize;
727 pLocal32Info->dwMemCommitted = entry.u.Region.dwCommittedSize;
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000728 }
Alexandre Julliardb0f58612001-12-19 19:16:27 +0000729 else if (!(entry.wFlags & PROCESS_HEAP_ENTRY_BUSY))
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000730 {
Alexandre Julliardb0f58612001-12-19 19:16:27 +0000731 DWORD size = entry.cbData + entry.cbOverhead;
732 pLocal32Info->dwTotalFree += size;
733 if (size > pLocal32Info->dwLargestFreeBlock) pLocal32Info->dwLargestFreeBlock = size;
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000734 }
735 }
736
737 pLocal32Info->dwcFreeHandles = 0;
738 for ( i = 0; i < HTABLE_NPAGES; i++ )
739 {
740 if ( header->freeListFirst[i] == 0xffff ) break;
741 pLocal32Info->dwcFreeHandles += header->freeListSize[i];
742 }
743 pLocal32Info->dwcFreeHandles += (HTABLE_NPAGES - i) * HTABLE_PAGESIZE/4;
744
745 return TRUE;
746}
747
748/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000749 * Local32First (KERNEL.445)
750 * Local32First (TOOLHELP.85)
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000751 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000752BOOL16 WINAPI Local32First16( LOCAL32ENTRY *pLocal32Entry, HGLOBAL16 handle )
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000753{
Alexandre Julliard15657091999-05-23 10:25:25 +0000754 FIXME("(%p, %04X): stub!\n", pLocal32Entry, handle );
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000755 return FALSE;
756}
757
758/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000759 * Local32Next (KERNEL.446)
760 * Local32Next (TOOLHELP.86)
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000761 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000762BOOL16 WINAPI Local32Next16( LOCAL32ENTRY *pLocal32Entry )
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000763{
Alexandre Julliard15657091999-05-23 10:25:25 +0000764 FIXME("(%p): stub!\n", pLocal32Entry );
Ulrich Weigand416d39e1998-12-01 14:45:37 +0000765 return FALSE;
766}
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000767