- Fix the stupid mess we created when making this from the cmake branch
[reactos.git] / dll / win32 / kernel32 / client / heapmem.c
1 /*
2 * PROJECT: ReactOS Win32 Base API
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/kernel32/mem/heap.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 DWORD dwInitialSize,
47 DWORD 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(HANDLE hHeap,
170 DWORD dwFlags,
171 PWSTR lpTagName,
172 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 DWORD 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 DWORD 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 funcitons */
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 currenly 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 DWORD
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 /* Query performance information */
1280 NtQuerySystemInformation(SystemPerformanceInformation,
1281 &PerformanceInfo,
1282 sizeof(PerformanceInfo),
1283 NULL);
1284
1285 /* Calculate memory load */
1286 lpBuffer->dwMemoryLoad = ((DWORD)(BaseStaticServerData->SysInfo.NumberOfPhysicalPages -
1287 PerformanceInfo.AvailablePages) * 100) /
1288 BaseStaticServerData->SysInfo.NumberOfPhysicalPages;
1289
1290 /* Save physical memory */
1291 PhysicalMemory = BaseStaticServerData->SysInfo.NumberOfPhysicalPages *
1292 BaseStaticServerData->SysInfo.PageSize;
1293 lpBuffer->ullTotalPhys = PhysicalMemory;
1294
1295 /* Now save available physical memory */
1296 PhysicalMemory = PerformanceInfo.AvailablePages *
1297 BaseStaticServerData->SysInfo.PageSize;
1298 lpBuffer->ullAvailPhys = PhysicalMemory;
1299
1300 /* Query VM and Quota Limits */
1301 NtQueryInformationProcess(NtCurrentProcess(),
1302 ProcessQuotaLimits,
1303 &QuotaLimits,
1304 sizeof(QUOTA_LIMITS),
1305 NULL);
1306 NtQueryInformationProcess(NtCurrentProcess(),
1307 ProcessVmCounters,
1308 &VmCounters,
1309 sizeof(VM_COUNTERS),
1310 NULL);
1311
1312 /* Save the commit limit */
1313 lpBuffer->ullTotalPageFile = min(QuotaLimits.PagefileLimit,
1314 PerformanceInfo.CommitLimit);
1315
1316 /* Calculate how many pages are left */
1317 PageFile = PerformanceInfo.CommitLimit - PerformanceInfo.CommittedPages;
1318
1319 /* Save the total */
1320 lpBuffer->ullAvailPageFile = min(PageFile,
1321 QuotaLimits.PagefileLimit -
1322 VmCounters.PagefileUsage);
1323 lpBuffer->ullAvailPageFile *= BaseStaticServerData->SysInfo.PageSize;
1324
1325 /* Now calculate the total virtual space */
1326 lpBuffer->ullTotalVirtual = (BaseStaticServerData->SysInfo.MaximumUserModeAddress -
1327 BaseStaticServerData->SysInfo.MinimumUserModeAddress) + 1;
1328
1329 /* And finally the avilable virtual space */
1330 lpBuffer->ullAvailVirtual = lpBuffer->ullTotalVirtual -
1331 VmCounters.VirtualSize;
1332 lpBuffer->ullAvailExtendedVirtual = 0;
1333 return TRUE;
1334 }
1335
1336 /*
1337 * @implemented
1338 */
1339 VOID
1340 NTAPI
1341 GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
1342 {
1343 MEMORYSTATUSEX lpBufferEx;
1344
1345 /* Call the extended function */
1346 lpBufferEx.dwLength = sizeof(MEMORYSTATUSEX);
1347 if (GlobalMemoryStatusEx(&lpBufferEx))
1348 {
1349 /* Reset the right size and fill out the information */
1350 lpBuffer->dwLength = sizeof(MEMORYSTATUS);
1351 lpBuffer->dwMemoryLoad = lpBufferEx.dwMemoryLoad;
1352 lpBuffer->dwTotalPhys = (SIZE_T)lpBufferEx.ullTotalPhys;
1353 lpBuffer->dwAvailPhys = (SIZE_T)lpBufferEx.ullAvailPhys;
1354 lpBuffer->dwTotalPageFile = (SIZE_T)lpBufferEx.ullTotalPageFile;
1355 lpBuffer->dwAvailPageFile = (SIZE_T)lpBufferEx.ullAvailPageFile;
1356 lpBuffer->dwTotalVirtual = (SIZE_T)lpBufferEx.ullTotalVirtual;
1357 lpBuffer->dwAvailVirtual = (SIZE_T)lpBufferEx.ullAvailVirtual;
1358 }
1359 }
1360
1361 /*
1362 * @implemented
1363 */
1364 HLOCAL
1365 NTAPI
1366 LocalAlloc(UINT uFlags,
1367 SIZE_T dwBytes)
1368 {
1369 ULONG Flags = 0;
1370 PVOID Ptr = NULL;
1371 HANDLE hMemory;
1372 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1373 BASE_TRACE_ALLOC(dwBytes, uFlags);
1374 ASSERT(BaseHeap);
1375
1376 /* Make sure the flags are valid */
1377 if (uFlags & ~LMEM_VALID_FLAGS)
1378 {
1379 /* They aren't, fail */
1380 BASE_TRACE_FAILURE();
1381 SetLastError(ERROR_INVALID_PARAMETER);
1382 return NULL;
1383 }
1384
1385 /* Convert ZEROINIT */
1386 if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
1387
1388 /* Check if we're not movable, which means pointer-based heap */
1389 if (!(uFlags & LMEM_MOVEABLE))
1390 {
1391 /* Allocate heap for it */
1392 Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
1393 BASE_TRACE_ALLOC2(Ptr);
1394 return Ptr;
1395 }
1396
1397 /* This is heap based, so lock it in first */
1398 RtlLockHeap(BaseHeap);
1399
1400 /*
1401 * Disable locking, enable custom flags, and write the
1402 * movable flag (deprecated)
1403 */
1404 Flags |= HEAP_NO_SERIALIZE |
1405 HEAP_SETTABLE_USER_VALUE |
1406 BASE_HEAP_FLAG_MOVABLE;
1407
1408 /* Allocate the handle */
1409 HandleEntry = BaseHeapAllocEntry();
1410 if (!HandleEntry)
1411 {
1412 /* Fail */
1413 hMemory = NULL;
1414 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1415 BASE_TRACE_FAILURE();
1416 goto Quickie;
1417 }
1418
1419 /* Get the object and make sure we have size */
1420 hMemory = &HandleEntry->Object;
1421 if (dwBytes)
1422 {
1423 /* Allocate the actual memory for it */
1424 Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
1425 BASE_TRACE_PTR(HandleEntry, Ptr);
1426 if (!Ptr)
1427 {
1428 /* We failed, manually set the allocate flag and free the handle */
1429 HandleEntry->Flags = RTL_HANDLE_VALID;
1430 BaseHeapFreeEntry(HandleEntry);
1431
1432 /* For the cleanup case */
1433 HandleEntry = NULL;
1434 }
1435 else
1436 {
1437 /* All worked well, save our heap entry */
1438 RtlSetUserValueHeap(BaseHeap, HEAP_NO_SERIALIZE, Ptr, hMemory);
1439 }
1440 }
1441
1442 Quickie:
1443 /* Cleanup! First unlock the heap */
1444 RtlUnlockHeap(BaseHeap);
1445
1446 /* Check if a handle was allocated */
1447 if (HandleEntry)
1448 {
1449 /* Set the pointer and allocated flag */
1450 HandleEntry->Object = Ptr;
1451 HandleEntry->Flags = RTL_HANDLE_VALID;
1452 if (!Ptr)
1453 {
1454 /* We don't have a valid pointer, but so reuse this handle */
1455 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
1456 }
1457
1458 /* Check if the handle is discardable */
1459 if (uFlags & GMEM_DISCARDABLE)
1460 {
1461 /* Save it in the handle entry */
1462 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
1463 }
1464
1465 /* Check if the handle is moveable */
1466 if (uFlags & GMEM_MOVEABLE)
1467 {
1468 /* Save it in the handle entry */
1469 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_MOVABLE;
1470 }
1471
1472 /* Set the pointer */
1473 Ptr = hMemory;
1474 }
1475
1476 /* Return the pointer */
1477 return Ptr;
1478 }
1479
1480 /*
1481 * @implemented
1482 */
1483 SIZE_T
1484 NTAPI
1485 LocalCompact(UINT dwMinFree)
1486 {
1487 /* Call the RTL Heap Manager */
1488 return RtlCompactHeap(BaseHeap, 0);
1489 }
1490
1491 /*
1492 * @implemented
1493 */
1494 UINT
1495 NTAPI
1496 LocalFlags(HLOCAL hMem)
1497 {
1498 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1499 HANDLE Handle = NULL;
1500 ULONG Flags = 0;
1501 UINT uFlags = LMEM_INVALID_HANDLE;
1502
1503 /* Start by locking the heap */
1504 RtlLockHeap(BaseHeap);
1505
1506 /* Check if this is a simple RTL Heap Managed block */
1507 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
1508 {
1509 /* Then we'll query RTL Heap */
1510 RtlGetUserInfoHeap(BaseHeap, Flags, hMem, &Handle, &Flags);
1511 BASE_TRACE_PTR(Handle, hMem);
1512
1513 /*
1514 * Check if RTL Heap didn't find a handle associated with us or
1515 * said that this heap isn't movable, which means something we're
1516 * really not a handle-based heap.
1517 */
1518 if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
1519 {
1520 /* Then set the flags to 0 */
1521 uFlags = 0;
1522 }
1523 else
1524 {
1525 /* Otherwise we're handle-based, so get the internal handle */
1526 hMem = Handle;
1527 }
1528 }
1529
1530 /* Check if the handle is actually an entry in our table */
1531 if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
1532 {
1533 /* Then get the entry */
1534 HandleEntry = BaseHeapGetEntry(hMem);
1535 BASE_TRACE_HANDLE(HandleEntry, hMem);
1536
1537 /* Make sure it's a valid handle */
1538 if (BaseHeapValidateEntry(HandleEntry))
1539 {
1540 /* Get the lock count first */
1541 uFlags = HandleEntry->LockCount & LMEM_LOCKCOUNT;
1542
1543 /* Now check if it's discardable */
1544 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSABLE)
1545 {
1546 /* Set the Win32 Flag */
1547 uFlags |= LMEM_DISCARDABLE;
1548 }
1549
1550 /* Now check if it's discarded */
1551 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
1552 /* Set the Win32 Flag */
1553 uFlags |= LMEM_DISCARDED;
1554 }
1555 }
1556
1557 /* Check if by now, we still haven't gotten any useful flags */
1558 if (uFlags == LMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE);
1559
1560 /* All done! Unlock heap and return Win32 Flags */
1561 RtlUnlockHeap(BaseHeap);
1562 return uFlags;
1563 }
1564
1565 /*
1566 * @implemented
1567 */
1568 HLOCAL
1569 NTAPI
1570 LocalFree(HLOCAL hMem)
1571 {
1572 /* This is identical to a Global Free */
1573 return GlobalFree(hMem);
1574 }
1575
1576 /*
1577 * @implemented
1578 */
1579 HLOCAL
1580 NTAPI
1581 LocalHandle(LPCVOID pMem)
1582 {
1583 /* This is identical to a Global Handle */
1584 return GlobalHandle(pMem);
1585 }
1586
1587 /*
1588 * @implemented
1589 */
1590 LPVOID
1591 NTAPI
1592 LocalLock(HLOCAL hMem)
1593 {
1594 /* This is the same as a GlobalLock, assuming these never change */
1595 C_ASSERT(LMEM_LOCKCOUNT == GMEM_LOCKCOUNT);
1596 return GlobalLock(hMem);
1597 }
1598
1599 HLOCAL
1600 NTAPI
1601 LocalReAlloc(HLOCAL hMem,
1602 SIZE_T dwBytes,
1603 UINT uFlags)
1604 {
1605 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1606 LPVOID Ptr;
1607 ULONG Flags = 0;
1608
1609 /* Convert ZEROINIT */
1610 if (uFlags & LMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
1611
1612 /* If this wasn't a movable heap, then we MUST re-alloc in place */
1613 if (!(uFlags & LMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
1614
1615 /* Lock the heap and disable built-in locking in the RTL Heap funcitons */
1616 RtlLockHeap(BaseHeap);
1617 Flags |= HEAP_NO_SERIALIZE;
1618
1619 /* Check if this is a simple handle-based block */
1620 if (((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
1621 {
1622 /* Get the entry */
1623 HandleEntry = BaseHeapGetEntry(hMem);
1624 BASE_TRACE_HANDLE(HandleEntry, hMem);
1625
1626 /* Make sure the handle is valid */
1627 if (!BaseHeapValidateEntry(HandleEntry))
1628 {
1629 /* Fail */
1630 BASE_TRACE_FAILURE();
1631 SetLastError(ERROR_INVALID_HANDLE);
1632 hMem = NULL;
1633 }
1634 else if (uFlags & LMEM_MODIFY)
1635 {
1636 /* User is changing flags... check if the memory was discardable */
1637 if (uFlags & LMEM_DISCARDABLE)
1638 {
1639 /* Then set the flag */
1640 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
1641 }
1642 else
1643 {
1644 /* Otherwise, remove the flag */
1645 HandleEntry->Flags &= BASE_HEAP_ENTRY_FLAG_REUSABLE;
1646 }
1647 }
1648 else
1649 {
1650 /* Otherwise, get the object and check if we have no size */
1651 Ptr = HandleEntry->Object;
1652 if (!dwBytes)
1653 {
1654 /* Clear the handle and check for a pointer */
1655 hMem = NULL;
1656 if (Ptr)
1657 {
1658 /* Make sure the handle isn't locked */
1659 if ((uFlags & LMEM_MOVEABLE) && !(HandleEntry->LockCount))
1660 {
1661 /* Free the current heap */
1662 RtlFreeHeap(BaseHeap, Flags, Ptr);
1663
1664 /* Free the handle */
1665 HandleEntry->Object = NULL;
1666 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
1667
1668 /* Get the object pointer */
1669 hMem = &HandleEntry->Object;
1670 }
1671 }
1672 else
1673 {
1674 /* Otherwise just return the object pointer */
1675 hMem = &HandleEntry->Object;
1676 }
1677 }
1678 else
1679 {
1680 /* Otherwise, we're allocating, so set the new flags needed */
1681 Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
1682 if (!Ptr)
1683 {
1684 /* We don't have a base, so allocate one */
1685 Ptr = RtlAllocateHeap(BaseHeap, Flags, dwBytes);
1686 BASE_TRACE_ALLOC2(Ptr);
1687 if (Ptr)
1688 {
1689 /* Allocation succeeded, so save our entry */
1690 RtlSetUserValueHeap(BaseHeap,
1691 HEAP_NO_SERIALIZE,
1692 Ptr,
1693 hMem);
1694 }
1695 }
1696 else
1697 {
1698 /*
1699 * If it's not movable or currently locked, we MUST allocate
1700 * in-place!
1701 */
1702 if (!(uFlags & LMEM_MOVEABLE) && (HandleEntry->LockCount))
1703 {
1704 /* Set the flag */
1705 Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
1706 }
1707 else
1708 {
1709 /* Otherwise clear the flag if we set it previously */
1710 Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
1711 }
1712
1713 /* And do the re-allocation */
1714 Ptr = RtlReAllocateHeap(BaseHeap, Flags, Ptr, dwBytes);
1715 }
1716
1717 /* Make sure we have a pointer by now */
1718 if (Ptr)
1719 {
1720 /* Write it in the handle entry and mark it in use */
1721 HandleEntry->Object = Ptr;
1722 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSE;
1723 }
1724 else
1725 {
1726 /* Otherwise we failed */
1727 hMem = NULL;
1728 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1729 }
1730 }
1731 }
1732 }
1733 else if (!(uFlags & LMEM_MODIFY))
1734 {
1735 /* Otherwise, this is a simple RTL Managed Heap, so just call it */
1736 hMem = RtlReAllocateHeap(BaseHeap,
1737 Flags | HEAP_NO_SERIALIZE,
1738 hMem,
1739 dwBytes);
1740 if (!hMem)
1741 {
1742 /* Fail */
1743 BASE_TRACE_FAILURE();
1744 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1745 }
1746 }
1747
1748 /* All done, unlock the heap and return the pointer */
1749 RtlUnlockHeap(BaseHeap);
1750 return hMem;
1751 }
1752
1753 /*
1754 * @implemented
1755 */
1756 SIZE_T
1757 WINAPI
1758 LocalShrink(HLOCAL hMem,
1759 UINT cbNewSize)
1760 {
1761 /* Call RTL */
1762 return RtlCompactHeap(BaseHeap, 0);
1763 }
1764
1765 /*
1766 * @implemented
1767 */
1768 SIZE_T
1769 NTAPI
1770 LocalSize(HLOCAL hMem)
1771 {
1772 /* This is the same as a Global Size */
1773 return GlobalSize(hMem);
1774 }
1775
1776 /*
1777 * @implemented
1778 */
1779 BOOL
1780 NTAPI
1781 LocalUnlock(HLOCAL hMem)
1782 {
1783 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
1784 BOOL RetVal = TRUE;
1785
1786 /* Check if this was a simple allocated heap entry */
1787 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
1788 {
1789 /* Fail, because LocalUnlock is not supported on LMEM_FIXED allocations */
1790 SetLastError(ERROR_NOT_LOCKED);
1791 return FALSE;
1792 }
1793
1794 /* Otherwise, lock the heap */
1795 RtlLockHeap(BaseHeap);
1796
1797 /* Get the handle entry */
1798 HandleEntry = BaseHeapGetEntry(hMem);
1799 BASE_TRACE_HANDLE(HandleEntry, hMem);
1800 _SEH2_TRY
1801 {
1802 /* Make sure it's valid */
1803 if (!BaseHeapValidateEntry(HandleEntry))
1804 {
1805 /* It's not, fail */
1806 BASE_TRACE_FAILURE();
1807 SetLastError(ERROR_INVALID_HANDLE);
1808 RetVal = FALSE;
1809 }
1810 else
1811 {
1812 /* Otherwise, decrement lock count, unless we're already at 0*/
1813 if (!HandleEntry->LockCount--)
1814 {
1815 /* In which case we simply lock it back and fail */
1816 HandleEntry->LockCount++;
1817 SetLastError(ERROR_NOT_LOCKED);
1818 RetVal = FALSE;
1819 }
1820 else if (!HandleEntry->LockCount)
1821 {
1822 /* Nothing to unlock */
1823 SetLastError(NO_ERROR);
1824 RetVal = FALSE;
1825 }
1826 }
1827 }
1828 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1829 {
1830 SetLastError(ERROR_INVALID_PARAMETER);
1831 RetVal = FALSE;
1832 }
1833 _SEH2_END;
1834
1835 /* All done. Unlock the heap and return the pointer */
1836 RtlUnlockHeap(BaseHeap);
1837 return RetVal;
1838 }
1839
1840 /* EOF */