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