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