xref: /reactos/dll/win32/kernel32/client/heapmem.c (revision 1734f297)
1 /*
2  * PROJECT:         ReactOS Win32 Base API
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            dll/win32/kernel32/client/heapmem.c
5  * PURPOSE:         Heap Memory APIs (wrappers for RtlHeap*)
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <k32.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS ********************************************************************/
17 
18 RTL_HANDLE_TABLE BaseHeapHandleTable;
19 HANDLE BaseHeap;
20 ULONG_PTR SystemRangeStart;
21 
22 /* PRIVATE FUNCTIONS **********************************************************/
23 
24 VOID
25 NTAPI
26 BaseDllInitializeMemoryManager(VOID)
27 {
28     BaseHeap = RtlGetProcessHeap();
29     RtlInitializeHandleTable(0xFFFF,
30                              sizeof(BASE_HEAP_HANDLE_ENTRY),
31                              &BaseHeapHandleTable);
32     NtQuerySystemInformation(SystemRangeStartInformation,
33                              &SystemRangeStart,
34                              sizeof(SystemRangeStart),
35                              NULL);
36 }
37 
38 /* PUBLIC FUNCTIONS ***********************************************************/
39 
40 /*
41  * @implemented
42  */
43 HANDLE
44 WINAPI
45 HeapCreate(DWORD flOptions,
46            SIZE_T dwInitialSize,
47            SIZE_T dwMaximumSize)
48 {
49     HANDLE hRet;
50     ULONG Flags;
51 
52     /* Remove non-Win32 flags and tag this allocation */
53     Flags = (flOptions & (HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE)) |
54             HEAP_CLASS_1;
55 
56     /* Check if heap is growable and ensure max size is correct */
57     if (dwMaximumSize == 0)
58         Flags |= HEAP_GROWABLE;
59     else if (dwMaximumSize < BaseStaticServerData->SysInfo.PageSize &&
60             dwInitialSize > dwMaximumSize)
61     {
62         /* Max size is non-zero but less than page size which can't be correct.
63            Fix it up by bumping it to the initial size whatever it is. */
64         dwMaximumSize = dwInitialSize;
65     }
66 
67     /* Call RTL Heap */
68     hRet = RtlCreateHeap(Flags,
69                          NULL,
70                          dwMaximumSize,
71                          dwInitialSize,
72                          NULL,
73                          NULL);
74 
75     /* Set the last error if we failed, and return the pointer */
76     if (!hRet) SetLastError(ERROR_NOT_ENOUGH_MEMORY);
77     return hRet;
78 }
79 
80 /*
81  * @implemented
82  */
83 BOOL
84 WINAPI
85 HeapDestroy(HANDLE hHeap)
86 {
87     /* Return TRUE if the heap was destroyed */
88    if (!RtlDestroyHeap(hHeap)) return TRUE;
89 
90     /* Otherwise, we got the handle back, so fail */
91     SetLastError(ERROR_INVALID_HANDLE);
92     return FALSE;
93 }
94 
95 /*
96  * @implemented
97  */
98 HANDLE
99 WINAPI
100 GetProcessHeap(VOID)
101 {
102     /* Call the RTL API */
103     return RtlGetProcessHeap();
104 }
105 
106 /*
107  * @implemented
108  */
109 DWORD
110 WINAPI
111 GetProcessHeaps(DWORD NumberOfHeaps,
112                 PHANDLE ProcessHeaps)
113 {
114     /* Call the RTL API */
115     return RtlGetProcessHeaps(NumberOfHeaps, ProcessHeaps);
116 }
117 
118 /*
119  * @implemented
120  */
121 BOOL
122 WINAPI
123 HeapLock(HANDLE hHeap)
124 {
125     /* Call the RTL API */
126     return RtlLockHeap(hHeap);
127 }
128 
129 /*
130  * @implemented
131  */
132 BOOL
133 WINAPI
134 HeapUnlock(HANDLE hHeap)
135 {
136     /* Call the RTL API */
137     return RtlUnlockHeap(hHeap);
138 }
139 
140 /*
141  * @implemented
142  */
143 SIZE_T
144 WINAPI
145 HeapCompact(HANDLE hHeap, DWORD dwFlags)
146 {
147     /* Call the RTL API */
148     return RtlCompactHeap(hHeap, dwFlags);
149 }
150 
151 /*
152  * @implemented
153  */
154 BOOL
155 WINAPI
156 HeapValidate(HANDLE hHeap,
157              DWORD dwFlags,
158              LPCVOID lpMem)
159 {
160     /* Call the RTL API */
161     return RtlValidateHeap(hHeap, dwFlags, (PVOID)lpMem);
162 }
163 
164 /*
165  * @implemented
166  */
167 DWORD
168 WINAPI
169 HeapCreateTagsW(_In_ HANDLE hHeap,
170                 _In_ DWORD dwFlags,
171                 _In_opt_ PWSTR lpTagName,
172                 _In_ PWSTR lpTagSubName)
173 {
174     /* Call the RTL API */
175     return RtlCreateTagHeap(hHeap,
176                             dwFlags,
177                             lpTagName,
178                             lpTagSubName);
179 }
180 
181 /*
182  * @implemented
183  */
184 DWORD
185 WINAPI
186 HeapExtend(HANDLE hHeap,
187            DWORD dwFlags,
188            PVOID BaseAddress,
189            DWORD dwBytes)
190 {
191     NTSTATUS Status;
192 
193     /* Call the RTL API. Gone in Vista, so commented out. */
194     Status = STATUS_NOT_IMPLEMENTED; //RtlExtendHeap(hHeap, dwFlags, BaseAddress, dwBytes);
195     if (!NT_SUCCESS(Status))
196     {
197         /* We failed */
198         BaseSetLastNTError(Status);
199         return FALSE;
200     }
201 
202     /* Return success */
203     return TRUE;
204 }
205 
206 /*
207  * @implemented
208  */
209 PWSTR
210 WINAPI
211 HeapQueryTagW(HANDLE hHeap,
212               DWORD dwFlags,
213               WORD wTagIndex,
214               BOOL bResetCounters,
215               PVOID lpTagInfo)
216 {
217     /* Call the RTL API */
218     return RtlQueryTagHeap(hHeap,
219                            dwFlags,
220                            wTagIndex,
221                            (BOOLEAN)bResetCounters,
222                            lpTagInfo);
223 }
224 
225 /*
226  * @implemented
227  */
228 BOOL
229 WINAPI
230 HeapSummary(HANDLE hHeap,
231             DWORD dwFlags,
232             PVOID Summary)
233 {
234     NTSTATUS Status;
235     RTL_HEAP_USAGE Usage;
236 
237     /* Fill in the length information */
238     Usage.Length = sizeof(Usage);
239 
240     /* Call RTL. Gone in Vista, so commented out */
241     Status = STATUS_NOT_IMPLEMENTED; //RtlUsageHeap(hHeap, dwFlags, &Usage);
242     if (!NT_SUCCESS(Status))
243     {
244         /* We failed */
245         BaseSetLastNTError(Status);
246         return FALSE;
247     }
248 
249     /* FIXME: Summary == Usage?! */
250     RtlCopyMemory(Summary, &Usage, sizeof(Usage));
251     return TRUE;
252 }
253 
254 /*
255  * @implemented
256  */
257 BOOL
258 WINAPI
259 HeapUsage(HANDLE hHeap,
260           DWORD dwFlags,
261           DWORD Unknown,
262           DWORD Unknown2,
263           IN PVOID Usage)
264 {
265     NTSTATUS Status;
266 
267     /* Call RTL. Gone in Vista, so commented out */
268     Status = STATUS_NOT_IMPLEMENTED; //RtlUsageHeap(hHeap, dwFlags, &Usage);
269     if (!NT_SUCCESS(Status))
270     {
271         /* We failed */
272         BaseSetLastNTError(Status);
273         return FALSE;
274     }
275     else if (Status == STATUS_MORE_ENTRIES)
276     {
277         /* There are still more entries to parse */
278         return TRUE;
279     }
280 
281     /* Otherwise, we're completely done, so we return FALSE, but NO_ERROR */
282     SetLastError(NO_ERROR);
283     return FALSE;
284 }
285 
286 /*
287  * @implemented
288  */
289 BOOL
290 WINAPI
291 HeapWalk(HANDLE	hHeap,
292          LPPROCESS_HEAP_ENTRY lpEntry)
293 {
294     NTSTATUS Status;
295 
296     DPRINT1("Warning, HeapWalk is calling RtlWalkHeap with Win32 parameters\n");
297 
298     Status = RtlWalkHeap(hHeap, lpEntry);
299 
300     if (!NT_SUCCESS(Status))
301     {
302         SetLastError(RtlNtStatusToDosError(Status));
303         return FALSE;
304     }
305 
306     return TRUE;
307 }
308 
309 /*
310  * @implemented
311  */
312 BOOL
313 WINAPI
314 HeapQueryInformation(HANDLE HeapHandle,
315                      HEAP_INFORMATION_CLASS HeapInformationClass,
316                      PVOID HeapInformation OPTIONAL,
317                      SIZE_T HeapInformationLength OPTIONAL,
318                      PSIZE_T ReturnLength OPTIONAL)
319 {
320     NTSTATUS Status;
321 
322     Status = RtlQueryHeapInformation(HeapHandle,
323                                      HeapInformationClass,
324                                      HeapInformation,
325                                      HeapInformationLength,
326                                      ReturnLength);
327 
328     if (!NT_SUCCESS(Status))
329     {
330         BaseSetLastNTError(Status);
331         return FALSE;
332     }
333 
334     return TRUE;
335 }
336 
337 /*
338  * @implemented
339  */
340 BOOL
341 WINAPI
342 HeapSetInformation(HANDLE HeapHandle,
343                    HEAP_INFORMATION_CLASS HeapInformationClass,
344                    PVOID HeapInformation OPTIONAL,
345                    SIZE_T HeapInformationLength OPTIONAL)
346 {
347     NTSTATUS Status;
348 
349     Status = RtlSetHeapInformation(HeapHandle,
350                                    HeapInformationClass,
351                                    HeapInformation,
352                                    HeapInformationLength);
353 
354     if (!NT_SUCCESS(Status))
355     {
356         BaseSetLastNTError(Status);
357         return FALSE;
358     }
359 
360     return TRUE;
361 }
362 
363 /*
364  * @implemented
365  */
366 HGLOBAL
367 NTAPI
368 GlobalAlloc(UINT uFlags,
369             SIZE_T dwBytes)
370 {
371     ULONG Flags = 0;
372     PVOID Ptr = NULL;
373     HANDLE hMemory;
374     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
375     BASE_TRACE_ALLOC(dwBytes, uFlags);
376     ASSERT(BaseHeap);
377 
378     /* Make sure the flags are valid */
379     if (uFlags & ~GMEM_VALID_FLAGS)
380     {
381         /* They aren't, fail */
382         BASE_TRACE_FAILURE();
383         SetLastError(ERROR_INVALID_PARAMETER);
384         return NULL;
385     }
386 
387     /* Convert ZEROINIT */
388     if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
389 
390     /* Check if we're not movable, which means pointer-based heap */
391     if (!(uFlags & GMEM_MOVEABLE))
392     {
393         /* Check if this is DDESHARE (deprecated) */
394         if (uFlags & GMEM_DDESHARE) Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE;
395 
396         /* Allocate heap for it */
397         Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes ? dwBytes : 1);
398         if (!Ptr) SetLastError(ERROR_NOT_ENOUGH_MEMORY);
399         BASE_TRACE_ALLOC2(Ptr);
400         return Ptr;
401     }
402 
403     /* This is heap based, so lock it in first */
404     RtlLockHeap(BaseHeap);
405 
406     /*
407      * Disable locking, enable custom flags, and write the
408      * movable flag (deprecated)
409      */
410     Flags |= HEAP_NO_SERIALIZE |
411              HEAP_SETTABLE_USER_VALUE |
412              BASE_HEAP_FLAG_MOVABLE;
413 
414     /* Allocate the handle */
415     HandleEntry = BaseHeapAllocEntry();
416     if (!HandleEntry)
417     {
418         /* Fail */
419         hMemory = NULL;
420         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
421         BASE_TRACE_FAILURE();
422     }
423     else
424     {
425         /* Get the object and make sure we have size */
426         hMemory = &HandleEntry->Object;
427         if (dwBytes)
428         {
429             /* Allocate the actual memory for it */
430             Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
431             BASE_TRACE_PTR(HandleEntry, Ptr);
432             if (!Ptr)
433             {
434                 /* We failed, manually set the allocate flag and free the handle */
435                 HandleEntry->Flags = RTL_HANDLE_VALID;
436                 BaseHeapFreeEntry(HandleEntry);
437 
438                 /* For the cleanup case */
439                 HandleEntry = NULL;
440             }
441             else
442             {
443                 /* All worked well, save our heap entry */
444                 RtlSetUserValueHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr, hMemory);
445             }
446         }
447     }
448 
449     /* Cleanup! First unlock the heap */
450     RtlUnlockHeap(BaseHeap);
451 
452     /* Check if a handle was allocated */
453     if (HandleEntry)
454     {
455         /* Set the pointer and allocated flag */
456         HandleEntry->Object = Ptr;
457         HandleEntry->Flags = RTL_HANDLE_VALID;
458         if (!Ptr)
459         {
460             /* We don't have a valid pointer, but so reuse this handle */
461             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
462         }
463 
464         /* Check if the handle is discardable */
465         if (uFlags & GMEM_DISCARDABLE)
466         {
467             /* Save it in the handle entry */
468             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
469         }
470 
471         /* Check if the handle is moveable */
472         if (uFlags & GMEM_MOVEABLE)
473         {
474             /* Save it in the handle entry */
475             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_MOVABLE;
476         }
477 
478         /* Check if the handle is DDE Shared */
479         if (uFlags & GMEM_DDESHARE)
480         {
481             /* Save it in the handle entry */
482             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE;
483         }
484 
485         /* Set the pointer */
486         Ptr = hMemory;
487     }
488 
489     /* Return the pointer */
490     return Ptr;
491 }
492 
493 /*
494  * @implemented
495  */
496 SIZE_T
497 NTAPI
498 GlobalCompact(DWORD dwMinFree)
499 {
500     /* Call the RTL Heap Manager */
501     return RtlCompactHeap(BaseHeap, 0);
502 }
503 
504 /*
505  * @implemented
506  */
507 VOID
508 NTAPI
509 GlobalFix(HGLOBAL hMem)
510 {
511     /* Lock the memory if it the handle is valid */
512     if (INVALID_HANDLE_VALUE != hMem) GlobalLock(hMem);
513 }
514 
515 /*
516  * @implemented
517  */
518 UINT
519 NTAPI
520 GlobalFlags(HGLOBAL hMem)
521 {
522     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
523     HANDLE Handle = NULL;
524     ULONG Flags = 0;
525     UINT uFlags = GMEM_INVALID_HANDLE;
526 
527     /* Start by locking the heap */
528     RtlLockHeap(BaseHeap);
529     _SEH2_TRY
530     {
531         /* Check if this is a simple RTL Heap Managed block */
532         if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
533         {
534             /* Then we'll query RTL Heap */
535             RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags);
536             BASE_TRACE_PTR(Handle, hMem);
537 
538             /*
539              * Check if RTL Heap didn't find a handle associated with us or
540              * said that this heap isn't movable, which means something we're
541              * really not a handle-based heap.
542              */
543             if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
544             {
545                 /* Then set the flags to 0 */
546                 uFlags = 0;
547             }
548             else
549             {
550                 /* Otherwise we're handle-based, so get the internal handle */
551                 hMem = Handle;
552             }
553         }
554 
555         /* Check if the handle is actually an entry in our table */
556         if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
557         {
558             /* Then get the entry */
559             HandleEntry = BaseHeapGetEntry(hMem);
560             BASE_TRACE_HANDLE(HandleEntry, hMem);
561 
562             /* Make sure it's a valid handle */
563             if (BaseHeapValidateEntry(HandleEntry))
564             {
565                 /* Get the lock count first */
566                 uFlags = HandleEntry->LockCount & GMEM_LOCKCOUNT;
567 
568                 /* Now check if it's discardable */
569                 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSABLE)
570                 {
571                     /* Set the Win32 Flag */
572                     uFlags |= GMEM_DISCARDABLE;
573                 }
574 
575                 /* Check if it's DDE Shared */
576                 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_DDESHARE)
577                 {
578                     /* Set the Win32 Flag */
579                     uFlags |= GMEM_DDESHARE;
580                 }
581 
582                 /* Now check if it's discarded */
583                 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
584                 {
585                    /* Set the Win32 Flag */
586                    uFlags |= GMEM_DISCARDED;
587                }
588             }
589         }
590 
591         /* Check if by now, we still haven't gotten any useful flags */
592         if (uFlags == GMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE);
593     }
594     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
595     {
596         /* Set the exception code */
597         BaseSetLastNTError(_SEH2_GetExceptionCode());
598     }
599     _SEH2_END;
600 
601     /* All done! Unlock heap and return Win32 Flags */
602     RtlUnlockHeap(BaseHeap);
603     return uFlags;
604 }
605 
606 /*
607  * @implemented
608  */
609 HGLOBAL
610 NTAPI
611 GlobalFree(HGLOBAL hMem)
612 {
613     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
614     LPVOID Ptr;
615     BASE_TRACE_DEALLOC(hMem);
616 
617     /* Check if this was a simple allocated heap entry */
618     if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
619     {
620         /* Free it with the RTL Heap Manager */
621         if (RtlFreeHeap(BaseHeap, 0, hMem))
622         {
623             /* Return NULL since there's no handle */
624             return NULL;
625         }
626         else
627         {
628             /* Otherwise fail */
629             BASE_TRACE_FAILURE();
630             SetLastError(ERROR_INVALID_HANDLE);
631             return hMem;
632         }
633     }
634 
635     /* It's a handle probably, so lock the heap */
636     RtlLockHeap(BaseHeap);
637     _SEH2_TRY
638     {
639         /* Make sure that this is an entry in our handle database */
640         if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
641         {
642             /* Get the entry */
643             HandleEntry = BaseHeapGetEntry(hMem);
644             BASE_TRACE_HANDLE(HandleEntry, hMem);
645 
646             /* Make sure the handle is valid */
647             if (!BaseHeapValidateEntry(HandleEntry))
648             {
649                 /* It's not, fail */
650                 SetLastError(ERROR_INVALID_HANDLE);
651                 Ptr = NULL;
652             }
653             else
654             {
655                 /* It's valid, so get the pointer */
656                 Ptr = HandleEntry->Object;
657 
658                 /* Free this handle */
659                 BaseHeapFreeEntry(HandleEntry);
660 
661                 /* If the pointer is 0, then we don't have a handle either */
662                 if (!Ptr) hMem = NULL;
663             }
664         }
665         else
666         {
667             /* Otherwise, reuse the handle as a pointer */
668             BASE_TRACE_FAILURE();
669             Ptr = hMem;
670         }
671 
672         /* Check if we got here with a valid heap pointer */
673         if (Ptr)
674         {
675             /* Free it with the RTL Heap Manager */
676             if (RtlFreeHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr))
677             {
678                 /* Everything worked */
679                 hMem = NULL;
680             }
681             else
682             {
683                 /* This wasn't a real heap handle */
684                 SetLastError(ERROR_INVALID_HANDLE);
685             }
686         }
687     }
688     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
689     {
690         /* Set the exception code */
691         BaseSetLastNTError(_SEH2_GetExceptionCode());
692     }
693     _SEH2_END;
694 
695     /* We're done, so unlock the heap and return the handle */
696     RtlUnlockHeap(BaseHeap);
697     return hMem;
698 }
699 
700 /*
701  * @implemented
702  */
703 HGLOBAL
704 NTAPI
705 GlobalHandle(LPCVOID pMem)
706 {
707     HANDLE Handle = NULL;
708     ULONG Flags;
709 
710     /* Lock the heap */
711     RtlLockHeap(BaseHeap);
712     _SEH2_TRY
713     {
714         /* Query RTL Heap */
715         if (!RtlGetUserInfoHeap(BaseHeap,
716                                 HEAP_NO_SERIALIZE,
717                                 (PVOID)pMem,
718                                 &Handle,
719                                 &Flags))
720         {
721             /* RTL Heap Manager does not know about this heap */
722             SetLastError(ERROR_INVALID_HANDLE);
723         }
724         else
725         {
726             /*
727              * Check if RTL Heap didn't find a handle for us or said that
728              * this heap isn't movable.
729              */
730             BASE_TRACE_PTR(Handle, pMem);
731             if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
732             {
733                 /* We're actually handle-based, so the pointer is a handle */
734                 Handle = (HANDLE)pMem;
735             }
736         }
737     }
738     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
739     {
740         /* Set the exception code */
741         BaseSetLastNTError(_SEH2_GetExceptionCode());
742     }
743     _SEH2_END;
744 
745     /* All done, unlock the heap and return the handle */
746     RtlUnlockHeap(BaseHeap);
747     return Handle;
748 }
749 
750 /*
751  * @implemented
752  */
753 LPVOID
754 NTAPI
755 GlobalLock(HGLOBAL hMem)
756 {
757     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
758     LPVOID Ptr;
759 
760     /* Check if this was a simple allocated heap entry */
761     if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
762     {
763         /* Make sure it's not a kernel or invalid address */
764         if ((hMem >= (HGLOBAL)SystemRangeStart) || (IsBadReadPtr(hMem, 1)))
765         {
766             /* Signal an error */
767             SetLastError(ERROR_INVALID_HANDLE);
768             return NULL;
769         }
770 
771         /* It's all good */
772         return hMem;
773     }
774 
775     /* Otherwise, lock the heap */
776     RtlLockHeap(BaseHeap);
777     _SEH2_TRY
778     {
779         /* Get the handle entry */
780         HandleEntry = BaseHeapGetEntry(hMem);
781         BASE_TRACE_HANDLE(HandleEntry, hMem);
782 
783         /* Make sure it's valid */
784         if (!BaseHeapValidateEntry(HandleEntry))
785         {
786             /* It's not, fail */
787             BASE_TRACE_FAILURE();
788             SetLastError(ERROR_INVALID_HANDLE);
789             Ptr = NULL;
790         }
791         else
792         {
793             /* Otherwise, get the pointer */
794             Ptr = HandleEntry->Object;
795             if (Ptr)
796             {
797                 /* Increase the lock count, unless we've went too far */
798                 if (HandleEntry->LockCount++ == GMEM_LOCKCOUNT)
799                 {
800                     /* In which case we simply unlock once */
801                     HandleEntry->LockCount--;
802                 }
803             }
804             else
805             {
806                 /* The handle is still there but the memory was already freed */
807                 SetLastError(ERROR_DISCARDED);
808             }
809         }
810     }
811     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
812     {
813         SetLastError(ERROR_INVALID_HANDLE);
814         Ptr = NULL;
815     }
816     _SEH2_END;
817 
818     /* All done. Unlock the heap and return the pointer */
819     RtlUnlockHeap(BaseHeap);
820     return Ptr;
821 }
822 
823 HGLOBAL
824 NTAPI
825 GlobalReAlloc(HGLOBAL hMem,
826               SIZE_T dwBytes,
827               UINT uFlags)
828 {
829     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
830     HANDLE Handle;
831     LPVOID Ptr;
832     ULONG Flags = 0;
833 
834     /* Throw out invalid flags */
835     if (uFlags & ~(GMEM_VALID_FLAGS | GMEM_MODIFY))
836     {
837         SetLastError(ERROR_INVALID_PARAMETER);
838         return NULL;
839     }
840 
841     /* Throw out invalid combo */
842     if ((uFlags & GMEM_DISCARDABLE) && !(uFlags & GMEM_MODIFY))
843     {
844         SetLastError(ERROR_INVALID_PARAMETER);
845         return NULL;
846     }
847 
848     /* Convert ZEROINIT */
849     if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
850 
851     /* If this wasn't a movable heap, then we MUST re-alloc in place */
852     if (!(uFlags & GMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
853 
854     /* Lock the heap and disable built-in locking in the RTL Heap functions */
855     RtlLockHeap(BaseHeap);
856     Flags |= HEAP_NO_SERIALIZE;
857 
858     /* Check if this is a simple handle-based block */
859     if (((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
860     {
861         /* Get the entry */
862         HandleEntry = BaseHeapGetEntry(hMem);
863         BASE_TRACE_HANDLE(HandleEntry, hMem);
864 
865         /* Make sure the handle is valid */
866         if (!BaseHeapValidateEntry(HandleEntry))
867         {
868             /* Fail */
869             BASE_TRACE_FAILURE();
870             SetLastError(ERROR_INVALID_HANDLE);
871             hMem = NULL;
872         }
873         else if (uFlags & GMEM_MODIFY)
874         {
875             /* User is changing flags... check if the memory was discardable */
876             if (uFlags & GMEM_DISCARDABLE)
877             {
878                 /* Then set the flag */
879                 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
880             }
881             else
882             {
883                 /* Otherwise, remove the flag */
884                 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSABLE;
885             }
886         }
887         else
888         {
889             /* Otherwise, get the object and check if we have no size */
890             Ptr = HandleEntry->Object;
891             if (!dwBytes)
892             {
893                 /* Clear the handle and check for a pointer */
894                 hMem = NULL;
895                 if (Ptr)
896                 {
897                     /* Make sure the handle isn't locked */
898                     if ((uFlags & GMEM_MOVEABLE) && !(HandleEntry->LockCount))
899                     {
900                         /* Free the current heap */
901                         if (RtlFreeHeap(BaseHeap, Flags, Ptr))
902                         {
903                             /* Free the handle */
904                             HandleEntry->Object = NULL;
905                             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
906 
907                             /* Get the object pointer */
908                             hMem = &HandleEntry->Object;
909                         }
910                     }
911                 }
912                 else
913                 {
914                     /* Otherwise just return the object pointer */
915                     hMem = &HandleEntry->Object;
916                 }
917             }
918             else
919             {
920                 /* Otherwise, we're allocating, so set the new flags needed */
921                 Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
922                 if (!Ptr)
923                 {
924                     /* We don't have a base, so allocate one */
925                     Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
926                     BASE_TRACE_ALLOC2(Ptr);
927                     if (Ptr)
928                     {
929                         /* Allocation succeeded, so save our entry */
930                         RtlSetUserValueHeap(BaseHeap,
931                                             HEAP_NO_SERIALIZE,
932                                             Ptr,
933                                             hMem);
934                     }
935                 }
936                 else
937                 {
938                     /*
939                      * If it's not movable or currently locked, we MUST allocate
940                      * in-place!
941                      */
942                     if (!(uFlags & GMEM_MOVEABLE) && (HandleEntry->LockCount))
943                     {
944                         /* Set the flag */
945                         Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
946                     }
947                     else
948                     {
949                         /* Otherwise clear the flag if we set it previously */
950                         Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
951                     }
952 
953                     /* Do the re-allocation. No need to save the entry again */
954                     Ptr = RtlReAllocateHeap(BaseHeap, Flags, Ptr, dwBytes);
955                 }
956 
957                 /* Make sure we have a pointer by now */
958                 if (Ptr)
959                 {
960                     /* Write it in the handle entry and mark it in use */
961                     HandleEntry->Object = Ptr;
962                     HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSE;
963                 }
964                 else
965                 {
966                     /* Otherwise we failed */
967                     hMem = NULL;
968                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
969                 }
970             }
971         }
972     }
973     else if (uFlags & GMEM_MODIFY)
974     {
975         /* This is not a handle-based heap and the caller wants it to be one */
976         if (uFlags & GMEM_MOVEABLE)
977         {
978             /* Get information on its current state */
979             Handle = hMem;
980             if (RtlGetUserInfoHeap(BaseHeap,
981                                    HEAP_NO_SERIALIZE,
982                                    hMem,
983                                    &Handle,
984                                    NULL))
985             {
986                 /*
987                  * Check if the handle matches the pointer or the moveable flag
988                  * isn't there, which is what we expect since it currently isn't.
989                  */
990                 if ((Handle == hMem) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
991                 {
992                     /* Allocate a handle for it */
993                     HandleEntry = BaseHeapAllocEntry();
994                     if (!HandleEntry)
995                     {
996                         /* No entry could be allocated */
997                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
998                         RtlUnlockHeap(BaseHeap);
999                         return NULL;
1000                     }
1001 
1002                     /* Calculate the size of the current heap */
1003                     dwBytes = RtlSizeHeap(BaseHeap, HEAP_NO_SERIALIZE, hMem);
1004 
1005                     /* Set the movable flag */
1006                     Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
1007 
1008                     /* Now allocate the actual heap for it */
1009                     HandleEntry->Object = RtlAllocateHeap(BaseHeap,
1010                                                           Flags,
1011                                                           dwBytes);
1012                     BASE_TRACE_PTR(HandleEntry->Object, HandleEntry);
1013                     if (!HandleEntry->Object)
1014                     {
1015                         /*
1016                          * We failed, manually set the allocate flag and
1017                          * free the handle
1018                          */
1019                         HandleEntry->Flags = RTL_HANDLE_VALID;
1020                         BaseHeapFreeEntry(HandleEntry);
1021 
1022                         /* For the cleanup case */
1023                         BASE_TRACE_FAILURE();
1024                         HandleEntry = NULL;
1025                         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1026                     }
1027                     else
1028                     {
1029                         /* Otherwise, copy the new heap and free the old one */
1030                         RtlMoveMemory(HandleEntry->Object, hMem, dwBytes);
1031                         RtlFreeHeap(BaseHeap, HEAP_NO_SERIALIZE, hMem);
1032 
1033                         /* Select the heap pointer */
1034                         hMem = (HANDLE)&HandleEntry->Object;
1035 
1036                         /* Initialize the count and default flags */
1037                         HandleEntry->LockCount = 0;
1038                         HandleEntry->Flags = RTL_HANDLE_VALID |
1039                                              BASE_HEAP_ENTRY_FLAG_MOVABLE;
1040 
1041                         /* Check if it's also discardable */
1042                         if (uFlags & GMEM_DISCARDABLE)
1043                         {
1044                             /* Set the internal flag */
1045                             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
1046                         }
1047 
1048                         /* Check if it's also DDE Shared */
1049                         if (uFlags & GMEM_DDESHARE)
1050                         {
1051                             /* Set the internal flag */
1052                             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE;
1053                         }
1054 
1055                         /* Allocation succeeded, so save our entry */
1056                         RtlSetUserValueHeap(BaseHeap,
1057                                             HEAP_NO_SERIALIZE,
1058                                             HandleEntry->Object,
1059                                             hMem);
1060                     }
1061                 }
1062             }
1063         }
1064     }
1065     else
1066     {
1067         /* Otherwise, this is a simple RTL Managed Heap, so just call it */
1068         hMem = RtlReAllocateHeap(BaseHeap,
1069                                  Flags | HEAP_NO_SERIALIZE,
1070                                  hMem,
1071                                  dwBytes);
1072         if (!hMem)
1073         {
1074             /* Fail */
1075             BASE_TRACE_FAILURE();
1076             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1077         }
1078     }
1079 
1080     /* All done, unlock the heap and return the pointer */
1081     RtlUnlockHeap(BaseHeap);
1082     return hMem;
1083 }
1084 
1085 /*
1086  * @implemented
1087  */
1088 SIZE_T
1089 NTAPI
1090 GlobalSize(HGLOBAL hMem)
1091 {
1092     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1093     PVOID Handle = NULL;
1094     ULONG Flags = 0;
1095     SIZE_T dwSize = MAXULONG_PTR;
1096 
1097     /* Lock the heap */
1098     RtlLockHeap(BaseHeap);
1099     _SEH2_TRY
1100     {
1101         /* Check if this is a simple RTL Heap Managed block */
1102         if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
1103         {
1104             /* Then we'll query RTL Heap */
1105             if (RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags))
1106             {
1107                 BASE_TRACE_PTR(Handle, hMem);
1108                 /*
1109                  * Check if RTL Heap didn't give us a handle or said that this
1110                  * heap isn't movable.
1111                  */
1112                 if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
1113                 {
1114                     /* We're not a handle heap, so use the generic call */
1115                     dwSize = RtlSizeHeap(BaseHeap, HEAP_NO_SERIALIZE, hMem);
1116                 }
1117                 else
1118                 {
1119                     /* We're a handle heap so get the internal handle */
1120                     hMem = Handle;
1121                 }
1122             }
1123         }
1124 
1125         /* Make sure that this is an entry in our handle database */
1126         if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
1127         {
1128             /* Get the entry */
1129             HandleEntry = BaseHeapGetEntry(hMem);
1130             BASE_TRACE_HANDLE(HandleEntry, hMem);
1131 
1132             /* Make sure the handle is valid */
1133             if (!BaseHeapValidateEntry(HandleEntry))
1134             {
1135                 /* Fail */
1136                 BASE_TRACE_FAILURE();
1137                 SetLastError(ERROR_INVALID_HANDLE);
1138             }
1139             else if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
1140             {
1141                 /* We've reused this block, but we've saved the size for you */
1142                 dwSize = HandleEntry->OldSize;
1143             }
1144             else
1145             {
1146                 /* Otherwise, query RTL about it */
1147                 dwSize = RtlSizeHeap(BaseHeap,
1148                                      HEAP_NO_SERIALIZE,
1149                                      HandleEntry->Object);
1150             }
1151         }
1152     }
1153     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1154     {
1155         /* Set failure for later */
1156         dwSize = MAXULONG_PTR;
1157     }
1158     _SEH2_END;
1159 
1160     /* Check if by now, we still haven't gotten any useful size */
1161     if (dwSize == MAXULONG_PTR)
1162     {
1163         /* Fail */
1164         BASE_TRACE_FAILURE();
1165         SetLastError(ERROR_INVALID_HANDLE);
1166         dwSize = 0;
1167     }
1168 
1169     /* All done! Unlock heap and return the size */
1170     RtlUnlockHeap(BaseHeap);
1171     return dwSize;
1172 }
1173 
1174 /*
1175  * @implemented
1176  */
1177 VOID
1178 NTAPI
1179 GlobalUnfix(HGLOBAL hMem)
1180 {
1181     /* If the handle is valid, unlock it */
1182     if (hMem != INVALID_HANDLE_VALUE) GlobalUnlock(hMem);
1183 }
1184 
1185 /*
1186  * @implemented
1187  */
1188 BOOL
1189 NTAPI
1190 GlobalUnlock(HGLOBAL hMem)
1191 {
1192     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1193     BOOL RetVal = TRUE;
1194 
1195     /* Check if this was a simple allocated heap entry */
1196     if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) return RetVal;
1197 
1198     /* Otherwise, lock the heap */
1199     RtlLockHeap(BaseHeap);
1200 
1201     /* Get the handle entry */
1202     HandleEntry = BaseHeapGetEntry(hMem);
1203     BASE_TRACE_HANDLE(HandleEntry, hMem);
1204 
1205     _SEH2_TRY
1206     {
1207         /* Make sure it's valid */
1208         if (!BaseHeapValidateEntry(HandleEntry))
1209         {
1210             /* It's not, fail */
1211             BASE_TRACE_FAILURE();
1212             SetLastError(ERROR_INVALID_HANDLE);
1213             RetVal = FALSE;
1214         }
1215         else
1216         {
1217             /* Otherwise, decrement lock count, unless we're already at 0*/
1218             if (!HandleEntry->LockCount--)
1219             {
1220                 /* In which case we simply lock it back and fail */
1221                 HandleEntry->LockCount++;
1222                 SetLastError(ERROR_NOT_LOCKED);
1223                 RetVal = FALSE;
1224             }
1225             else if (!HandleEntry->LockCount)
1226             {
1227                 /* Nothing to unlock */
1228                 SetLastError(NO_ERROR);
1229                 RetVal = FALSE;
1230             }
1231         }
1232     }
1233     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1234     {
1235         SetLastError(ERROR_INVALID_PARAMETER);
1236         RetVal = FALSE;
1237     }
1238     _SEH2_END;
1239 
1240     /* All done. Unlock the heap and return the pointer */
1241     RtlUnlockHeap(BaseHeap);
1242     return RetVal;
1243 }
1244 
1245 /*
1246  * @implemented
1247  */
1248 BOOL
1249 NTAPI
1250 GlobalUnWire(HGLOBAL hMem)
1251 {
1252     /* This is simply an unlock */
1253     return GlobalUnlock(hMem);
1254 }
1255 
1256 /*
1257  * @implemented
1258  */
1259 LPVOID
1260 NTAPI
1261 GlobalWire(HGLOBAL hMem)
1262 {
1263     /* This is just a lock */
1264     return GlobalLock(hMem);
1265 }
1266 
1267 /*
1268  * @implemented
1269  */
1270 BOOL
1271 NTAPI
1272 GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer)
1273 {
1274     SYSTEM_PERFORMANCE_INFORMATION PerformanceInfo;
1275     VM_COUNTERS VmCounters;
1276     QUOTA_LIMITS QuotaLimits;
1277     ULONGLONG PageFile, PhysicalMemory;
1278 
1279     if (lpBuffer->dwLength != sizeof(*lpBuffer))
1280     {
1281         SetLastError(ERROR_INVALID_PARAMETER);
1282         return FALSE;
1283     }
1284 
1285     /* Query performance information */
1286     NtQuerySystemInformation(SystemPerformanceInformation,
1287                              &PerformanceInfo,
1288                              sizeof(PerformanceInfo),
1289                              NULL);
1290 
1291     /* Calculate memory load */
1292     lpBuffer->dwMemoryLoad = ((DWORD)(BaseStaticServerData->SysInfo.NumberOfPhysicalPages -
1293                                       PerformanceInfo.AvailablePages) * 100) /
1294                                       BaseStaticServerData->SysInfo.NumberOfPhysicalPages;
1295 
1296     /* Save physical memory */
1297     PhysicalMemory = BaseStaticServerData->SysInfo.NumberOfPhysicalPages *
1298                      BaseStaticServerData->SysInfo.PageSize;
1299     lpBuffer->ullTotalPhys = PhysicalMemory;
1300 
1301     /* Now save available physical memory */
1302     PhysicalMemory = PerformanceInfo.AvailablePages *
1303                      BaseStaticServerData->SysInfo.PageSize;
1304     lpBuffer->ullAvailPhys = PhysicalMemory;
1305 
1306     /* Query VM and Quota Limits */
1307     NtQueryInformationProcess(NtCurrentProcess(),
1308                               ProcessQuotaLimits,
1309                               &QuotaLimits,
1310                               sizeof(QUOTA_LIMITS),
1311                               NULL);
1312     NtQueryInformationProcess(NtCurrentProcess(),
1313                               ProcessVmCounters,
1314                               &VmCounters,
1315                               sizeof(VM_COUNTERS),
1316                               NULL);
1317 
1318     /* Save the commit limit */
1319     lpBuffer->ullTotalPageFile = min(QuotaLimits.PagefileLimit,
1320                                      PerformanceInfo.CommitLimit);
1321     lpBuffer->ullTotalPageFile *= BaseStaticServerData->SysInfo.PageSize;
1322 
1323     /* Calculate how many pages are left */
1324     PageFile = PerformanceInfo.CommitLimit - PerformanceInfo.CommittedPages;
1325 
1326     /* Save the total */
1327     lpBuffer->ullAvailPageFile = min(PageFile,
1328                                      QuotaLimits.PagefileLimit -
1329                                      VmCounters.PagefileUsage);
1330     lpBuffer->ullAvailPageFile *= BaseStaticServerData->SysInfo.PageSize;
1331 
1332     /* Now calculate the total virtual space */
1333     lpBuffer->ullTotalVirtual = (BaseStaticServerData->SysInfo.MaximumUserModeAddress -
1334                                  BaseStaticServerData->SysInfo.MinimumUserModeAddress) + 1;
1335 
1336     /* And finally the available virtual space */
1337     lpBuffer->ullAvailVirtual = lpBuffer->ullTotalVirtual - VmCounters.VirtualSize;
1338     lpBuffer->ullAvailExtendedVirtual = 0;
1339 
1340     return TRUE;
1341 }
1342 
1343 /*
1344  * @implemented
1345  */
1346 VOID
1347 NTAPI
1348 GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
1349 {
1350     MEMORYSTATUSEX lpBufferEx;
1351 
1352     /* Call the extended function */
1353     lpBufferEx.dwLength = sizeof(MEMORYSTATUSEX);
1354     if (GlobalMemoryStatusEx(&lpBufferEx))
1355     {
1356         /* Reset the right size and fill out the information */
1357         lpBuffer->dwLength = sizeof(MEMORYSTATUS);
1358         lpBuffer->dwMemoryLoad = lpBufferEx.dwMemoryLoad;
1359         lpBuffer->dwTotalPhys = (SIZE_T)min(lpBufferEx.ullTotalPhys, MAXULONG_PTR);
1360         lpBuffer->dwAvailPhys = (SIZE_T)min(lpBufferEx.ullAvailPhys, MAXULONG_PTR);
1361         lpBuffer->dwTotalPageFile = (SIZE_T)min(lpBufferEx.ullTotalPageFile, MAXULONG_PTR);
1362         lpBuffer->dwAvailPageFile = (SIZE_T)min(lpBufferEx.ullAvailPageFile, MAXULONG_PTR);
1363         lpBuffer->dwTotalVirtual = (SIZE_T)min(lpBufferEx.ullTotalVirtual, MAXULONG_PTR);
1364         lpBuffer->dwAvailVirtual = (SIZE_T)min(lpBufferEx.ullAvailVirtual, MAXULONG_PTR);
1365     }
1366 }
1367 
1368 /*
1369  * @implemented
1370  */
1371 HLOCAL
1372 NTAPI
1373 LocalAlloc(UINT uFlags,
1374            SIZE_T dwBytes)
1375 {
1376     ULONG Flags = 0;
1377     PVOID Ptr = NULL;
1378     HANDLE hMemory;
1379     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1380     BASE_TRACE_ALLOC(dwBytes, uFlags);
1381     ASSERT(BaseHeap);
1382 
1383     /* Make sure the flags are valid */
1384     if (uFlags & ~LMEM_VALID_FLAGS)
1385     {
1386         /* They aren't, fail */
1387         BASE_TRACE_FAILURE();
1388         SetLastError(ERROR_INVALID_PARAMETER);
1389         return NULL;
1390     }
1391 
1392     /* Convert ZEROINIT */
1393     if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
1394 
1395     /* Check if we're not movable, which means pointer-based heap */
1396     if (!(uFlags & LMEM_MOVEABLE))
1397     {
1398         /* Allocate heap for it */
1399         Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
1400         BASE_TRACE_ALLOC2(Ptr);
1401         return Ptr;
1402     }
1403 
1404     /* This is heap based, so lock it in first */
1405     RtlLockHeap(BaseHeap);
1406 
1407     /*
1408      * Disable locking, enable custom flags, and write the
1409      * movable flag (deprecated)
1410      */
1411     Flags |= HEAP_NO_SERIALIZE |
1412              HEAP_SETTABLE_USER_VALUE |
1413              BASE_HEAP_FLAG_MOVABLE;
1414 
1415     /* Allocate the handle */
1416     HandleEntry = BaseHeapAllocEntry();
1417     if (!HandleEntry)
1418     {
1419         /* Fail */
1420         hMemory = NULL;
1421         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1422         BASE_TRACE_FAILURE();
1423         goto Quickie;
1424     }
1425 
1426     /* Get the object and make sure we have size */
1427     hMemory = &HandleEntry->Object;
1428     if (dwBytes)
1429     {
1430         /* Allocate the actual memory for it */
1431         Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
1432         BASE_TRACE_PTR(HandleEntry, Ptr);
1433         if (!Ptr)
1434         {
1435             /* We failed, manually set the allocate flag and free the handle */
1436             HandleEntry->Flags = RTL_HANDLE_VALID;
1437             BaseHeapFreeEntry(HandleEntry);
1438 
1439             /* For the cleanup case */
1440             HandleEntry = NULL;
1441         }
1442         else
1443         {
1444             /* All worked well, save our heap entry */
1445             RtlSetUserValueHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr, hMemory);
1446         }
1447     }
1448 
1449 Quickie:
1450     /* Cleanup! First unlock the heap */
1451     RtlUnlockHeap(BaseHeap);
1452 
1453     /* Check if a handle was allocated */
1454     if (HandleEntry)
1455     {
1456         /* Set the pointer and allocated flag */
1457         HandleEntry->Object = Ptr;
1458         HandleEntry->Flags = RTL_HANDLE_VALID;
1459         if (!Ptr)
1460         {
1461             /* We don't have a valid pointer, but so reuse this handle */
1462             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
1463         }
1464 
1465         /* Check if the handle is discardable */
1466         if (uFlags & GMEM_DISCARDABLE)
1467         {
1468             /* Save it in the handle entry */
1469             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
1470         }
1471 
1472         /* Check if the handle is moveable */
1473         if (uFlags & GMEM_MOVEABLE)
1474         {
1475             /* Save it in the handle entry */
1476             HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_MOVABLE;
1477         }
1478 
1479         /* Set the pointer */
1480         Ptr = hMemory;
1481     }
1482 
1483     /* Return the pointer */
1484     return Ptr;
1485 }
1486 
1487 /*
1488  * @implemented
1489  */
1490 SIZE_T
1491 NTAPI
1492 LocalCompact(UINT dwMinFree)
1493 {
1494     /* Call the RTL Heap Manager */
1495     return RtlCompactHeap(BaseHeap, 0);
1496 }
1497 
1498 /*
1499  * @implemented
1500  */
1501 UINT
1502 NTAPI
1503 LocalFlags(HLOCAL hMem)
1504 {
1505     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1506     HANDLE Handle = NULL;
1507     ULONG Flags = 0;
1508     UINT uFlags = LMEM_INVALID_HANDLE;
1509 
1510     /* Start by locking the heap */
1511     RtlLockHeap(BaseHeap);
1512 
1513     /* Check if this is a simple RTL Heap Managed block */
1514     if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
1515     {
1516         /* Then we'll query RTL Heap */
1517         RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags);
1518         BASE_TRACE_PTR(Handle, hMem);
1519 
1520         /*
1521          * Check if RTL Heap didn't find a handle associated with us or
1522          * said that this heap isn't movable, which means something we're
1523          * really not a handle-based heap.
1524          */
1525         if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
1526         {
1527             /* Then set the flags to 0 */
1528             uFlags = 0;
1529         }
1530         else
1531         {
1532             /* Otherwise we're handle-based, so get the internal handle */
1533             hMem = Handle;
1534         }
1535     }
1536 
1537     /* Check if the handle is actually an entry in our table */
1538     if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
1539     {
1540         /* Then get the entry */
1541         HandleEntry = BaseHeapGetEntry(hMem);
1542         BASE_TRACE_HANDLE(HandleEntry, hMem);
1543 
1544         /* Make sure it's a valid handle */
1545         if (BaseHeapValidateEntry(HandleEntry))
1546         {
1547             /* Get the lock count first */
1548             uFlags = HandleEntry->LockCount & LMEM_LOCKCOUNT;
1549 
1550             /* Now check if it's discardable */
1551             if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSABLE)
1552             {
1553                 /* Set the Win32 Flag */
1554                 uFlags |= LMEM_DISCARDABLE;
1555             }
1556 
1557             /* Now check if it's discarded */
1558             if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
1559                /* Set the Win32 Flag */
1560                uFlags |= LMEM_DISCARDED;
1561         }
1562     }
1563 
1564     /* Check if by now, we still haven't gotten any useful flags */
1565     if (uFlags == LMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE);
1566 
1567     /* All done! Unlock heap and return Win32 Flags */
1568     RtlUnlockHeap(BaseHeap);
1569     return uFlags;
1570 }
1571 
1572 /*
1573  * @implemented
1574  */
1575 HLOCAL
1576 NTAPI
1577 LocalFree(HLOCAL hMem)
1578 {
1579     /* This is identical to a Global Free */
1580     return GlobalFree(hMem);
1581 }
1582 
1583 /*
1584  * @implemented
1585  */
1586 HLOCAL
1587 NTAPI
1588 LocalHandle(LPCVOID pMem)
1589 {
1590     /* This is identical to a Global Handle */
1591     return GlobalHandle(pMem);
1592 }
1593 
1594 /*
1595  * @implemented
1596  */
1597 LPVOID
1598 NTAPI
1599 LocalLock(HLOCAL hMem)
1600 {
1601     /* This is the same as a GlobalLock, assuming these never change */
1602     C_ASSERT(LMEM_LOCKCOUNT == GMEM_LOCKCOUNT);
1603     return GlobalLock(hMem);
1604 }
1605 
1606 HLOCAL
1607 NTAPI
1608 LocalReAlloc(HLOCAL hMem,
1609              SIZE_T dwBytes,
1610              UINT uFlags)
1611 {
1612     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1613     LPVOID Ptr;
1614     ULONG Flags = 0;
1615 
1616     /* Convert ZEROINIT */
1617     if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
1618 
1619     /* If this wasn't a movable heap, then we MUST re-alloc in place */
1620     if (!(uFlags & LMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
1621 
1622     /* Lock the heap and disable built-in locking in the RTL Heap functions */
1623     RtlLockHeap(BaseHeap);
1624     Flags |= HEAP_NO_SERIALIZE;
1625 
1626     /* Check if this is a simple handle-based block */
1627     if (((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
1628     {
1629         /* Get the entry */
1630         HandleEntry = BaseHeapGetEntry(hMem);
1631         BASE_TRACE_HANDLE(HandleEntry, hMem);
1632 
1633         /* Make sure the handle is valid */
1634         if (!BaseHeapValidateEntry(HandleEntry))
1635         {
1636             /* Fail */
1637             BASE_TRACE_FAILURE();
1638             SetLastError(ERROR_INVALID_HANDLE);
1639             hMem = NULL;
1640         }
1641         else if (uFlags & LMEM_MODIFY)
1642         {
1643             /* User is changing flags... check if the memory was discardable */
1644             if (uFlags & LMEM_DISCARDABLE)
1645             {
1646                 /* Then set the flag */
1647                 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
1648             }
1649             else
1650             {
1651                 /* Otherwise, remove the flag */
1652                 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSABLE;
1653             }
1654         }
1655         else
1656         {
1657             /* Otherwise, get the object and check if we have no size */
1658             Ptr = HandleEntry->Object;
1659             if (!dwBytes)
1660             {
1661                 /* Clear the handle and check for a pointer */
1662                 hMem = NULL;
1663                 if (Ptr)
1664                 {
1665                     /* Make sure the handle isn't locked */
1666                     if ((uFlags & LMEM_MOVEABLE) && !(HandleEntry->LockCount))
1667                     {
1668                         /* Free the current heap */
1669                         RtlFreeHeap(BaseHeap, Flags, Ptr);
1670 
1671                         /* Free the handle */
1672                         HandleEntry->Object = NULL;
1673                         HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
1674 
1675                         /* Get the object pointer */
1676                         hMem = &HandleEntry->Object;
1677                     }
1678                 }
1679                 else
1680                 {
1681                     /* Otherwise just return the object pointer */
1682                     hMem = &HandleEntry->Object;
1683                 }
1684             }
1685             else
1686             {
1687                 /* Otherwise, we're allocating, so set the new flags needed */
1688                 Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
1689                 if (!Ptr)
1690                 {
1691                     /* We don't have a base, so allocate one */
1692                     Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
1693                     BASE_TRACE_ALLOC2(Ptr);
1694                     if (Ptr)
1695                     {
1696                         /* Allocation succeeded, so save our entry */
1697                         RtlSetUserValueHeap(BaseHeap,
1698                                             HEAP_NO_SERIALIZE,
1699                                             Ptr,
1700                                             hMem);
1701                     }
1702                 }
1703                 else
1704                 {
1705                     /*
1706                      * If it's not movable or currently locked, we MUST allocate
1707                      * in-place!
1708                      */
1709                     if (!(uFlags & LMEM_MOVEABLE) && (HandleEntry->LockCount))
1710                     {
1711                         /* Set the flag */
1712                         Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
1713                     }
1714                     else
1715                     {
1716                         /* Otherwise clear the flag if we set it previously */
1717                         Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
1718                     }
1719 
1720                     /* And do the re-allocation */
1721                     Ptr = RtlReAllocateHeap(BaseHeap, Flags, Ptr, dwBytes);
1722                 }
1723 
1724                 /* Make sure we have a pointer by now */
1725                 if (Ptr)
1726                 {
1727                     /* Write it in the handle entry and mark it in use */
1728                     HandleEntry->Object = Ptr;
1729                     HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSE;
1730                 }
1731                 else
1732                 {
1733                     /* Otherwise we failed */
1734                     hMem = NULL;
1735                     SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1736                 }
1737             }
1738         }
1739     }
1740     else if (!(uFlags & LMEM_MODIFY))
1741     {
1742         /* Otherwise, this is a simple RTL Managed Heap, so just call it */
1743         hMem = RtlReAllocateHeap(BaseHeap,
1744                                  Flags | HEAP_NO_SERIALIZE,
1745                                  hMem,
1746                                  dwBytes);
1747         if (!hMem)
1748         {
1749             /* Fail */
1750             BASE_TRACE_FAILURE();
1751             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1752         }
1753     }
1754 
1755     /* All done, unlock the heap and return the pointer */
1756     RtlUnlockHeap(BaseHeap);
1757     return hMem;
1758 }
1759 
1760 /*
1761  * @implemented
1762  */
1763 SIZE_T
1764 WINAPI
1765 LocalShrink(HLOCAL hMem,
1766             UINT cbNewSize)
1767 {
1768     /* Call RTL */
1769     return RtlCompactHeap(BaseHeap, 0);
1770 }
1771 
1772 /*
1773  * @implemented
1774  */
1775 SIZE_T
1776 NTAPI
1777 LocalSize(HLOCAL hMem)
1778 {
1779     /* This is the same as a Global Size */
1780     return GlobalSize(hMem);
1781 }
1782 
1783 /*
1784  * @implemented
1785  */
1786 BOOL
1787 NTAPI
1788 LocalUnlock(HLOCAL hMem)
1789 {
1790     PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1791     BOOL RetVal = TRUE;
1792 
1793     /* Check if this was a simple allocated heap entry */
1794     if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
1795     {
1796        /* Fail, because LocalUnlock is not supported on LMEM_FIXED allocations */
1797        SetLastError(ERROR_NOT_LOCKED);
1798        return FALSE;
1799     }
1800 
1801     /* Otherwise, lock the heap */
1802     RtlLockHeap(BaseHeap);
1803 
1804     /* Get the handle entry */
1805     HandleEntry = BaseHeapGetEntry(hMem);
1806     BASE_TRACE_HANDLE(HandleEntry, hMem);
1807     _SEH2_TRY
1808     {
1809         /* Make sure it's valid */
1810         if (!BaseHeapValidateEntry(HandleEntry))
1811         {
1812             /* It's not, fail */
1813             BASE_TRACE_FAILURE();
1814             SetLastError(ERROR_INVALID_HANDLE);
1815             RetVal = FALSE;
1816         }
1817         else
1818         {
1819             /* Otherwise, decrement lock count, unless we're already at 0*/
1820             if (!HandleEntry->LockCount--)
1821             {
1822                 /* In which case we simply lock it back and fail */
1823                 HandleEntry->LockCount++;
1824                 SetLastError(ERROR_NOT_LOCKED);
1825                 RetVal = FALSE;
1826             }
1827             else if (!HandleEntry->LockCount)
1828             {
1829                 /* Nothing to unlock */
1830                 SetLastError(NO_ERROR);
1831                 RetVal = FALSE;
1832             }
1833         }
1834     }
1835     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1836     {
1837         SetLastError(ERROR_INVALID_PARAMETER);
1838         RetVal = FALSE;
1839     }
1840     _SEH2_END;
1841 
1842     /* All done. Unlock the heap and return the pointer */
1843     RtlUnlockHeap(BaseHeap);
1844     return RetVal;
1845 }
1846 
1847 /* EOF */
1848