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