a0449e36fca1e2bad10623e218b71c5322eaf5a2
[reactos.git] / dll / win32 / kernel32 / mem / global.c
1 /*
2 * PROJECT: ReactOS Win32 Base API
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/kernel32/mem/global.c
5 * PURPOSE: Global Memory APIs (sits on top of Heap*)
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 extern SYSTEM_BASIC_INFORMATION BaseCachedSysInfo;
19 RTL_HANDLE_TABLE BaseHeapHandleTable;
20
21 /* FUNCTIONS ***************************************************************/
22
23 /*
24 * @implemented
25 */
26 HGLOBAL
27 NTAPI
28 GlobalAlloc(UINT uFlags,
29 DWORD dwBytes)
30 {
31 ULONG Flags = 0;
32 PVOID Ptr = NULL;
33 HANDLE hMemory;
34 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
35 BASE_TRACE_ALLOC(dwBytes, uFlags);
36 ASSERT(hProcessHeap);
37
38 /* Make sure the flags are valid */
39 if (uFlags & ~GMEM_VALID_FLAGS)
40 {
41 /* They aren't, fail */
42 BASE_TRACE_FAILURE();
43 SetLastError(ERROR_INVALID_PARAMETER);
44 return NULL;
45 }
46
47 /* Convert ZEROINIT */
48 if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
49
50 /* Check if we're not movable, which means pointer-based heap */
51 if (!(uFlags & GMEM_MOVEABLE))
52 {
53 /* Check if this is DDESHARE (deprecated) */
54 if (uFlags & GMEM_DDESHARE) Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE;
55
56 /* Allocate heap for it */
57 Ptr = RtlAllocateHeap(hProcessHeap, Flags, dwBytes);
58 BASE_TRACE_ALLOC2(Ptr);
59 return Ptr;
60 }
61
62 /* This is heap based, so lock it in first */
63 RtlLockHeap(hProcessHeap);
64
65 /*
66 * Disable locking, enable custom flags, and write the
67 * movable flag (deprecated)
68 */
69 Flags |= HEAP_NO_SERIALIZE |
70 HEAP_SETTABLE_USER_VALUE |
71 BASE_HEAP_FLAG_MOVABLE;
72
73 /* Allocate the handle */
74 HandleEntry = BaseHeapAllocEntry();
75 if (!HandleEntry)
76 {
77 /* Fail */
78 hMemory = NULL;
79 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
80 BASE_TRACE_FAILURE();
81 goto Quickie;
82 }
83
84 /* Get the object and make sure we have size */
85 hMemory = &HandleEntry->Object;
86 if (dwBytes)
87 {
88 /* Allocate the actual memory for it */
89 Ptr = RtlAllocateHeap(hProcessHeap, Flags, dwBytes);
90 BASE_TRACE_PTR(HandleEntry, Ptr);
91 if (!Ptr)
92 {
93 /* We failed, manually set the allocate flag and free the handle */
94 HandleEntry->Flags = RTL_HANDLE_VALID;
95 BaseHeapFreeEntry(HandleEntry);
96
97 /* For the cleanup case */
98 HandleEntry = NULL;
99 }
100 else
101 {
102 /* All worked well, save our heap entry */
103 RtlSetUserValueHeap(hProcessHeap, HEAP_NO_SERIALIZE, Ptr, hMemory);
104 }
105 }
106
107 Quickie:
108 /* Cleanup! First unlock the heap */
109 RtlUnlockHeap(hProcessHeap);
110
111 /* Check if a handle was allocated */
112 if (HandleEntry)
113 {
114 /* Set the pointer and allocated flag */
115 HandleEntry->Object = Ptr;
116 HandleEntry->Flags = RTL_HANDLE_VALID;
117 if (!Ptr)
118 {
119 /* We don't have a valid pointer, but so reuse this handle */
120 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
121 }
122
123 /* Check if the handle is discardable */
124 if (uFlags & GMEM_DISCARDABLE)
125 {
126 /* Save it in the handle entry */
127 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
128 }
129
130 /* Check if the handle is moveable */
131 if (uFlags & GMEM_MOVEABLE)
132 {
133 /* Save it in the handle entry */
134 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_MOVABLE;
135 }
136
137 /* Check if the handle is DDE Shared */
138 if (uFlags & GMEM_DDESHARE)
139 {
140 /* Save it in the handle entry */
141 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE;
142 }
143
144 /* Set the pointer */
145 Ptr = hMemory;
146 }
147
148 /* Return the pointer */
149 return Ptr;
150 }
151
152 /*
153 * @implemented
154 */
155 SIZE_T
156 NTAPI
157 GlobalCompact(DWORD dwMinFree)
158 {
159 /* Call the RTL Heap Manager */
160 return RtlCompactHeap(hProcessHeap, 0);
161 }
162
163 /*
164 * @implemented
165 */
166 VOID
167 NTAPI
168 GlobalFix(HGLOBAL hMem)
169 {
170 /* Lock the memory if it the handle is valid */
171 if (INVALID_HANDLE_VALUE != hMem) GlobalLock(hMem);
172 }
173
174 /*
175 * @implemented
176 */
177 UINT
178 NTAPI
179 GlobalFlags(HGLOBAL hMem)
180 {
181 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
182 HANDLE Handle = NULL;
183 ULONG Flags = 0;
184 UINT uFlags = GMEM_INVALID_HANDLE;
185
186 /* Start by locking the heap */
187 RtlLockHeap(hProcessHeap);
188
189 /* Check if this is a simple RTL Heap Managed block */
190 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
191 {
192 /* Then we'll query RTL Heap */
193 RtlGetUserInfoHeap(hProcessHeap, Flags, hMem, &Handle, &Flags);
194 BASE_TRACE_PTR(Handle, hMem);
195
196 /*
197 * Check if RTL Heap didn't find a handle associated with us or
198 * said that this heap isn't movable, which means something we're
199 * really not a handle-based heap.
200 */
201 if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
202 {
203 /* Then set the flags to 0 */
204 uFlags = 0;
205 }
206 else
207 {
208 /* Otherwise we're handle-based, so get the internal handle */
209 hMem = Handle;
210 }
211 }
212
213 /* Check if the handle is actually an entry in our table */
214 if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
215 {
216 /* Then get the entry */
217 HandleEntry = BaseHeapGetEntry(hMem);
218 BASE_TRACE_HANDLE(HandleEntry, hMem);
219
220 /* Make sure it's a valid handle */
221 if (BaseHeapValidateEntry(HandleEntry))
222 {
223 /* Get the lock count first */
224 uFlags = HandleEntry->LockCount & GMEM_LOCKCOUNT;
225
226 /* Now check if it's discardable */
227 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSABLE)
228 {
229 /* Set the Win32 Flag */
230 uFlags |= GMEM_DISCARDABLE;
231 }
232
233 /* Check if it's DDE Shared */
234 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_DDESHARE)
235 {
236 /* Set the Win32 Flag */
237 uFlags |= GMEM_DDESHARE;
238 }
239
240 /* Now check if it's discarded */
241 if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
242 /* Set the Win32 Flag */
243 uFlags |= GMEM_DISCARDED;
244 }
245 }
246
247 /* Check if by now, we still haven't gotten any useful flags */
248 if (uFlags == GMEM_INVALID_HANDLE) SetLastError(ERROR_INVALID_HANDLE);
249
250 /* All done! Unlock heap and return Win32 Flags */
251 RtlUnlockHeap(hProcessHeap);
252 return uFlags;
253 }
254
255 /*
256 * @implemented
257 */
258 HGLOBAL
259 NTAPI
260 GlobalFree(HGLOBAL hMem)
261 {
262 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
263 LPVOID Ptr;
264 BASE_TRACE_DEALLOC(hMem);
265
266 /* Check if this was a simple allocated heap entry */
267 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
268 {
269 /* Free it with the RTL Heap Manager */
270 if (RtlFreeHeap(hProcessHeap, 0, hMem))
271 {
272 /* Return NULL since there's no handle */
273 return NULL;
274 }
275 else
276 {
277 /* Otherwise fail */
278 BASE_TRACE_FAILURE();
279 SetLastError(ERROR_INVALID_HANDLE);
280 return hMem;
281 }
282 }
283
284 /* It's a handle probably, so lock the heap */
285 RtlLockHeap(hProcessHeap);
286
287 /* Make sure that this is an entry in our handle database */
288 if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
289 {
290 /* Get the entry */
291 HandleEntry = BaseHeapGetEntry(hMem);
292 BASE_TRACE_HANDLE(HandleEntry, hMem);
293
294 /* Make sure the handle is valid */
295 if (!BaseHeapValidateEntry(HandleEntry))
296 {
297 /* It's not, fail */
298 SetLastError(ERROR_INVALID_HANDLE);
299 Ptr = NULL;
300 }
301 else
302 {
303 /* It's valid, so get the pointer */
304 Ptr = HandleEntry->Object;
305
306 /* Free this handle */
307 BaseHeapFreeEntry(HandleEntry);
308
309 /* If the pointer is 0, then we don't have a handle either */
310 if (!Ptr) hMem = NULL;
311 }
312 }
313 else
314 {
315 /* Otherwise, reuse the handle as a pointer */
316 BASE_TRACE_FAILURE();
317 Ptr = hMem;
318 }
319
320 /* Check if we got here with a valid heap pointer */
321 if (Ptr)
322 {
323 /* Free it */
324 RtlFreeHeap(hProcessHeap, HEAP_NO_SERIALIZE, Ptr);
325 hMem = NULL;
326 }
327
328 /* We're done, so unlock the heap and return the handle */
329 RtlUnlockHeap(hProcessHeap);
330 return hMem;
331 }
332
333 /*
334 * @implemented
335 */
336 HGLOBAL
337 NTAPI
338 GlobalHandle(LPCVOID pMem)
339 {
340 HANDLE Handle = NULL;
341 ULONG Flags;
342
343 /* Lock the heap */
344 RtlLockHeap(hProcessHeap);
345
346 /* Query RTL Heap */
347 RtlGetUserInfoHeap(hProcessHeap,
348 HEAP_NO_SERIALIZE,
349 (PVOID)pMem,
350 &Handle,
351 &Flags);
352 BASE_TRACE_PTR(Handle, pMem);
353
354 /*
355 * Check if RTL Heap didn't find a handle for us or said that
356 * this heap isn't movable.
357 */
358 if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
359 {
360 /* We're actually handle-based, so the pointer is a handle */
361 Handle = (HANDLE)pMem;
362 }
363
364 /* All done, unlock the heap and return the handle */
365 RtlUnlockHeap(hProcessHeap);
366 return Handle;
367 }
368
369 /*
370 * @implemented
371 */
372 LPVOID
373 NTAPI
374 GlobalLock(HGLOBAL hMem)
375 {
376 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
377 LPVOID Ptr;
378
379 /* Check if this was a simple allocated heap entry */
380 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
381 {
382 /* Verify and return the pointer */
383 return IsBadReadPtr(hMem, 1) ? NULL : hMem;
384 }
385
386 /* Otherwise, lock the heap */
387 RtlLockHeap(hProcessHeap);
388
389 _SEH2_TRY
390 {
391 /* Get the handle entry */
392 HandleEntry = BaseHeapGetEntry(hMem);
393 BASE_TRACE_HANDLE(HandleEntry, hMem);
394
395 /* Make sure it's valid */
396 if (!BaseHeapValidateEntry(HandleEntry))
397 {
398 /* It's not, fail */
399 BASE_TRACE_FAILURE();
400 SetLastError(ERROR_INVALID_HANDLE);
401 Ptr = NULL;
402 }
403 else
404 {
405 /* Otherwise, get the pointer */
406 Ptr = HandleEntry->Object;
407 if (Ptr)
408 {
409 /* Increase the lock count, unless we've went too far */
410 if (HandleEntry->LockCount++ == GMEM_LOCKCOUNT)
411 {
412 /* In which case we simply unlock once */
413 HandleEntry->LockCount--;
414 }
415 }
416 else
417 {
418 /* The handle is still there but the memory was already freed */
419 SetLastError(ERROR_DISCARDED);
420 }
421 }
422 }
423 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
424 {
425 SetLastError(ERROR_INVALID_HANDLE);
426 Ptr = NULL;
427 }
428 _SEH2_END
429
430 /* All done. Unlock the heap and return the pointer */
431 RtlUnlockHeap(hProcessHeap);
432 return Ptr;
433 }
434
435 HGLOBAL
436 NTAPI
437 GlobalReAlloc(HGLOBAL hMem,
438 DWORD dwBytes,
439 UINT uFlags)
440 {
441 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
442 HANDLE Handle;
443 LPVOID Ptr;
444 ULONG Flags = 0;
445
446 /* Convert ZEROINIT */
447 if (uFlags & GMEM_ZEROINIT) Flags |= HEAP_ZERO_MEMORY;
448
449 /* If this wasn't a movable heap, then we MUST re-alloc in place */
450 if (!(uFlags & GMEM_MOVEABLE)) Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
451
452 /* Lock the heap and disable built-in locking in the RTL Heap funcitons */
453 RtlLockHeap(hProcessHeap);
454 Flags |= HEAP_NO_SERIALIZE;
455
456 /* Check if this is a simple handle-based block */
457 if (((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
458 {
459 /* Get the entry */
460 HandleEntry = BaseHeapGetEntry(hMem);
461 BASE_TRACE_HANDLE(HandleEntry, hMem);
462
463 /* Make sure the handle is valid */
464 if (!BaseHeapValidateEntry(HandleEntry))
465 {
466 /* Fail */
467 BASE_TRACE_FAILURE();
468 SetLastError(ERROR_INVALID_HANDLE);
469 hMem = NULL;
470 }
471 else if (uFlags & GMEM_MODIFY)
472 {
473 /* User is changing flags... check if the memory was discardable */
474 if (uFlags & GMEM_DISCARDABLE)
475 {
476 /* Then set the flag */
477 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
478 }
479 else
480 {
481 /* Otherwise, remove the flag */
482 HandleEntry->Flags &= BASE_HEAP_ENTRY_FLAG_REUSABLE;
483 }
484 }
485 else
486 {
487 /* Otherwise, get the object and check if we have no size */
488 Ptr = HandleEntry->Object;
489 if (!dwBytes)
490 {
491 /* Clear the handle and check for a pointer */
492 hMem = NULL;
493 if (Ptr)
494 {
495 /* Make sure the handle isn't locked */
496 if ((uFlags & GMEM_MOVEABLE) && !(HandleEntry->LockCount))
497 {
498 /* Free the current heap */
499 RtlFreeHeap(hProcessHeap, Flags, Ptr);
500
501 /* Free the handle */
502 HandleEntry->Object = NULL;
503 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSE;
504
505 /* Get the object pointer */
506 hMem = &HandleEntry->Object;
507 }
508 }
509 else
510 {
511 /* Otherwise just return the object pointer */
512 hMem = &HandleEntry->Object;
513 }
514 }
515 else
516 {
517 /* Otherwise, we're allocating, so set the new flags needed */
518 Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
519 if (!Ptr)
520 {
521 /* We don't have a base, so allocate one */
522 Ptr = RtlAllocateHeap(hProcessHeap, Flags, dwBytes);
523 BASE_TRACE_ALLOC2(Ptr);
524 if (Ptr)
525 {
526 /* Allocation succeeded, so save our entry */
527 RtlSetUserValueHeap(hProcessHeap,
528 HEAP_NO_SERIALIZE,
529 Ptr,
530 hMem);
531 }
532 }
533 else
534 {
535 /*
536 * If it's not movable or currently locked, we MUST allocate
537 * in-place!
538 */
539 if (!(uFlags & GMEM_MOVEABLE) && (HandleEntry->LockCount))
540 {
541 /* Set the flag */
542 Flags |= HEAP_REALLOC_IN_PLACE_ONLY;
543 }
544 else
545 {
546 /* Otherwise clear the flag if we set it previously */
547 Flags &= ~HEAP_REALLOC_IN_PLACE_ONLY;
548 }
549
550 /* And do the re-allocation */
551 Ptr = RtlReAllocateHeap(hProcessHeap, Flags, Ptr, dwBytes);
552
553 if (Ptr)
554 {
555 /* Allocation succeeded, so save our entry */
556 RtlSetUserValueHeap(hProcessHeap,
557 HEAP_NO_SERIALIZE,
558 Ptr,
559 hMem);
560 }
561
562 }
563
564 /* Make sure we have a pointer by now */
565 if (Ptr)
566 {
567 /* Write it in the handle entry and mark it in use */
568 HandleEntry->Object = Ptr;
569 HandleEntry->Flags &= ~BASE_HEAP_ENTRY_FLAG_REUSE;
570 }
571 else
572 {
573 /* Otherwise we failed */
574 hMem = NULL;
575 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
576 }
577 }
578 }
579 }
580 else if (uFlags & GMEM_MODIFY)
581 {
582 /* This is not a handle-based heap and the caller wants it to be one */
583 if (uFlags & GMEM_MOVEABLE)
584 {
585 /* Get information on its current state */
586 Handle = hMem;
587 DPRINT1("h h %lx %lx\n", Handle, hMem);
588 RtlGetUserInfoHeap(hProcessHeap,
589 HEAP_NO_SERIALIZE,
590 hMem,
591 &Handle,
592 &Flags);
593 DPRINT1("h h %lx %lx\n", Handle, hMem);
594
595 /*
596 * Check if the handle matches the pointer or if the moveable flag
597 * isn't there, which is what we expect since it currenly isn't.
598 */
599 if (Handle == hMem || !(Flags & BASE_HEAP_FLAG_MOVABLE))
600 {
601 /* Allocate a handle for it */
602 HandleEntry = BaseHeapAllocEntry();
603
604 /* Calculate the size of the current heap */
605 dwBytes = RtlSizeHeap(hProcessHeap, HEAP_NO_SERIALIZE, hMem);
606
607 /* Set the movable flag */
608 Flags |= HEAP_SETTABLE_USER_VALUE | BASE_HEAP_FLAG_MOVABLE;
609
610 /* Now allocate the actual heap for it */
611 HandleEntry->Object = RtlAllocateHeap(hProcessHeap,
612 Flags,
613 dwBytes);
614 BASE_TRACE_PTR(HandleEntry->Object, HandleEntry);
615 if (!HandleEntry->Object)
616 {
617 /*
618 * We failed, manually set the allocate flag and
619 * free the handle
620 */
621 HandleEntry->Flags = RTL_HANDLE_VALID;
622 BaseHeapFreeEntry(HandleEntry);
623
624 /* For the cleanup case */
625 BASE_TRACE_FAILURE();
626 HandleEntry = NULL;
627 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
628 }
629 else
630 {
631 /* Otherwise, copy the current heap and free the old one */
632 RtlMoveMemory(HandleEntry->Object, hMem, dwBytes);
633 RtlFreeHeap(hProcessHeap, HEAP_NO_SERIALIZE, hMem);
634
635 /* Select the heap pointer */
636 hMem = (HANDLE)&HandleEntry->Object;
637
638 /* Initialize the count and default flags */
639 HandleEntry->LockCount = 0;
640 HandleEntry->Flags = RTL_HANDLE_VALID |
641 BASE_HEAP_ENTRY_FLAG_MOVABLE;
642
643 /* Check if it's also discardable */
644 if (uFlags & GMEM_DISCARDABLE)
645 {
646 /* Set the internal flag */
647 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_REUSABLE;
648 }
649
650 /* Check if it's also DDE Shared */
651 if (uFlags & GMEM_DDESHARE)
652 {
653 /* Set the internal flag */
654 HandleEntry->Flags |= BASE_HEAP_ENTRY_FLAG_DDESHARE;
655 }
656
657 /* Allocation succeeded, so save our entry */
658 RtlSetUserValueHeap(hProcessHeap,
659 HEAP_NO_SERIALIZE,
660 HandleEntry->Object,
661 hMem);
662 }
663 }
664 }
665 }
666 else
667 {
668 /* Otherwise, this is a simple RTL Managed Heap, so just call it */
669 hMem = RtlReAllocateHeap(hProcessHeap,
670 Flags | HEAP_NO_SERIALIZE,
671 hMem,
672 dwBytes);
673 if (!hMem)
674 {
675 /* Fail */
676 BASE_TRACE_FAILURE();
677 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
678 }
679 }
680
681 /* All done, unlock the heap and return the pointer */
682 RtlUnlockHeap(hProcessHeap);
683 return hMem;
684 }
685
686 /*
687 * @implemented
688 */
689 DWORD
690 NTAPI
691 GlobalSize(HGLOBAL hMem)
692 {
693 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
694 PVOID Handle = NULL;
695 ULONG Flags = 0;
696 SIZE_T dwSize = MAXULONG_PTR;
697
698 /* Lock the heap */
699 RtlLockHeap(hProcessHeap);
700
701 _SEH2_TRY
702 {
703 /* Check if this is a simple RTL Heap Managed block */
704 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY))
705 {
706 /* Then we'll query RTL Heap */
707 RtlGetUserInfoHeap(hProcessHeap, Flags, hMem, &Handle, &Flags);
708 BASE_TRACE_PTR(Handle, hMem);
709
710 /*
711 * Check if RTL Heap didn't give us a handle or said that this heap
712 * isn't movable.
713 */
714 if (!(Handle) || !(Flags & BASE_HEAP_FLAG_MOVABLE))
715 {
716 /* This implies we're not a handle heap, so use the generic call */
717 dwSize = RtlSizeHeap(hProcessHeap, HEAP_NO_SERIALIZE, hMem);
718 }
719 else
720 {
721 /* Otherwise we're a handle heap, so get the internal handle */
722 hMem = Handle;
723 }
724 }
725
726 /* Make sure that this is an entry in our handle database */
727 if ((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)
728 {
729 /* Get the entry */
730 HandleEntry = BaseHeapGetEntry(hMem);
731 BASE_TRACE_HANDLE(HandleEntry, hMem);
732
733 /* Make sure the handle is valid */
734 if (!BaseHeapValidateEntry(HandleEntry))
735 {
736 /* Fail */
737 BASE_TRACE_FAILURE();
738 SetLastError(ERROR_INVALID_HANDLE);
739 }
740 else if (HandleEntry->Flags & BASE_HEAP_ENTRY_FLAG_REUSE)
741 {
742 /* We've reused this block, but we've saved the size for you */
743 dwSize = HandleEntry->OldSize;
744 }
745 else
746 {
747 /* Otherwise, query RTL about it */
748 dwSize = RtlSizeHeap(hProcessHeap,
749 HEAP_NO_SERIALIZE,
750 HandleEntry->Object);
751 }
752 }
753
754 /* Check if by now, we still haven't gotten any useful size */
755 if (dwSize == MAXULONG_PTR)
756 {
757 /* Fail */
758 BASE_TRACE_FAILURE();
759 SetLastError(ERROR_INVALID_HANDLE);
760 dwSize = 0;
761 }
762 }
763 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
764 {
765 SetLastError(ERROR_INVALID_HANDLE);
766 dwSize = 0;
767 }
768 _SEH2_END
769
770 /* All done! Unlock heap and return the size */
771 RtlUnlockHeap(hProcessHeap);
772 return dwSize;
773 }
774
775 /*
776 * @implemented
777 */
778 VOID
779 NTAPI
780 GlobalUnfix(HGLOBAL hMem)
781 {
782 /* If the handle is valid, unlock it */
783 if (hMem != INVALID_HANDLE_VALUE) GlobalUnlock(hMem);
784 }
785
786 /*
787 * @implemented
788 */
789 BOOL
790 NTAPI
791 GlobalUnlock(HGLOBAL hMem)
792 {
793 PBASE_HEAP_HANDLE_ENTRY HandleEntry;
794 BOOL RetVal = TRUE;
795
796 /* Check if this was a simple allocated heap entry */
797 if (!((ULONG_PTR)hMem & BASE_HEAP_IS_HANDLE_ENTRY)) return RetVal;
798
799 /* Otherwise, lock the heap */
800 RtlLockHeap(hProcessHeap);
801
802 /* Get the handle entry */
803 HandleEntry = BaseHeapGetEntry(hMem);
804 BASE_TRACE_HANDLE(HandleEntry, hMem);
805
806 _SEH2_TRY
807 {
808 /* Make sure it's valid */
809 if (!BaseHeapValidateEntry(HandleEntry))
810 {
811 /* It's not, fail */
812 BASE_TRACE_FAILURE();
813 SetLastError(ERROR_INVALID_HANDLE);
814 RetVal = FALSE;
815 }
816 else
817 {
818 /* Otherwise, decrement lock count, unless we're already at 0*/
819 if (!HandleEntry->LockCount--)
820 {
821 /* In which case we simply lock it back and fail */
822 HandleEntry->LockCount++;
823 SetLastError(ERROR_NOT_LOCKED);
824 RetVal = FALSE;
825 }
826 else if (!HandleEntry->LockCount)
827 {
828 /* Nothing to unlock */
829 SetLastError(NO_ERROR);
830 RetVal = FALSE;
831 }
832 }
833 }
834 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
835 {
836 SetLastError(ERROR_INVALID_PARAMETER);
837 RetVal = FALSE;
838 }
839 _SEH2_END
840
841 /* All done. Unlock the heap and return the pointer */
842 RtlUnlockHeap(hProcessHeap);
843 return RetVal;
844 }
845
846 /*
847 * @implemented
848 */
849 BOOL
850 NTAPI
851 GlobalUnWire(HGLOBAL hMem)
852 {
853 /* This is simply an unlock */
854 return GlobalUnlock(hMem);
855 }
856
857 /*
858 * @implemented
859 */
860 LPVOID
861 NTAPI
862 GlobalWire(HGLOBAL hMem)
863 {
864 /* This is just a lock */
865 return GlobalLock(hMem);
866 }
867
868 /*
869 * @implemented
870 */
871 BOOL
872 NTAPI
873 GlobalMemoryStatusEx(LPMEMORYSTATUSEX lpBuffer)
874 {
875 SYSTEM_PERFORMANCE_INFORMATION PerformanceInfo;
876 VM_COUNTERS VmCounters;
877 QUOTA_LIMITS QuotaLimits;
878 ULONGLONG PageFile, PhysicalMemory;
879
880 /* Query performance information */
881 NtQuerySystemInformation(SystemPerformanceInformation,
882 &PerformanceInfo,
883 sizeof(PerformanceInfo),
884 NULL);
885
886 /* Calculate memory load */
887 lpBuffer->dwMemoryLoad = ((DWORD)(BaseCachedSysInfo.NumberOfPhysicalPages -
888 PerformanceInfo.AvailablePages) * 100) /
889 BaseCachedSysInfo.NumberOfPhysicalPages;
890
891 /* Save physical memory */
892 PhysicalMemory = BaseCachedSysInfo.NumberOfPhysicalPages *
893 BaseCachedSysInfo.PageSize;
894 lpBuffer->ullTotalPhys = PhysicalMemory;
895
896 /* Now save available physical memory */
897 PhysicalMemory = PerformanceInfo.AvailablePages *
898 BaseCachedSysInfo.PageSize;
899 lpBuffer->ullAvailPhys = PhysicalMemory;
900
901 /* Query VM and Quota Limits */
902 NtQueryInformationProcess(NtCurrentProcess(),
903 ProcessQuotaLimits,
904 &QuotaLimits,
905 sizeof(QUOTA_LIMITS),
906 NULL);
907 NtQueryInformationProcess(NtCurrentProcess(),
908 ProcessVmCounters,
909 &VmCounters,
910 sizeof(VM_COUNTERS),
911 NULL);
912
913 /* Save the commit limit */
914 lpBuffer->ullTotalPageFile = min(QuotaLimits.PagefileLimit,
915 PerformanceInfo.CommitLimit);
916
917 /* Calculate how many pages are left */
918 PageFile = PerformanceInfo.CommitLimit - PerformanceInfo.CommittedPages;
919
920 /* Save the total */
921 lpBuffer->ullAvailPageFile = min(PageFile,
922 QuotaLimits.PagefileLimit -
923 VmCounters.PagefileUsage);
924 lpBuffer->ullAvailPageFile *= BaseCachedSysInfo.PageSize;
925
926 /* Now calculate the total virtual space */
927 lpBuffer->ullTotalVirtual = (BaseCachedSysInfo.MaximumUserModeAddress -
928 BaseCachedSysInfo.MinimumUserModeAddress) + 1;
929
930 /* And finally the avilable virtual space */
931 lpBuffer->ullAvailVirtual = lpBuffer->ullTotalVirtual -
932 VmCounters.VirtualSize;
933 lpBuffer->ullAvailExtendedVirtual = 0;
934 return TRUE;
935 }
936
937 /*
938 * @implemented
939 */
940 VOID
941 NTAPI
942 GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer)
943 {
944 MEMORYSTATUSEX lpBufferEx;
945
946 /* Call the extended function */
947 lpBufferEx.dwLength = sizeof(MEMORYSTATUSEX);
948 if (GlobalMemoryStatusEx(&lpBufferEx))
949 {
950 /* Reset the right size and fill out the information */
951 lpBuffer->dwLength = sizeof(MEMORYSTATUS);
952 lpBuffer->dwMemoryLoad = lpBufferEx.dwMemoryLoad;
953 lpBuffer->dwTotalPhys = (SIZE_T)lpBufferEx.ullTotalPhys;
954 lpBuffer->dwAvailPhys = (SIZE_T)lpBufferEx.ullAvailPhys;
955 lpBuffer->dwTotalPageFile = (SIZE_T)lpBufferEx.ullTotalPageFile;
956 lpBuffer->dwAvailPageFile = (SIZE_T)lpBufferEx.ullAvailPageFile;
957 lpBuffer->dwTotalVirtual = (SIZE_T)lpBufferEx.ullTotalVirtual;
958 lpBuffer->dwAvailVirtual = (SIZE_T)lpBufferEx.ullAvailVirtual;
959 }
960 }
961
962 /* EOF */