[SHELL32] SHChangeNotify: Use tree for CDirectoryList (#6784)
[reactos.git] / win32ss / user / ntuser / object.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: User handle manager
5 * FILE: win32ss/user/ntuser/object.c
6 * PROGRAMER: Copyright (C) 2001 Alexandre Julliard
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserObj);
11
12 //int usedHandles=0;
13 PUSER_HANDLE_TABLE gHandleTable = NULL;
14
15 /* Forward declarations */
16 _Success_(return!=NULL)
17 static PVOID AllocThreadObject(
18 _In_ PDESKTOP pDesk,
19 _In_ PTHREADINFO pti,
20 _In_ SIZE_T Size,
21 _Out_ PVOID* HandleOwner)
22 {
23 PTHROBJHEAD ObjHead;
24
25 UNREFERENCED_PARAMETER(pDesk);
26
27 ASSERT(Size > sizeof(*ObjHead));
28 ASSERT(pti != NULL);
29
30 ObjHead = UserHeapAlloc(Size);
31 if (!ObjHead)
32 return NULL;
33
34 RtlZeroMemory(ObjHead, Size);
35
36 ObjHead->pti = pti;
37 IntReferenceThreadInfo(pti);
38 *HandleOwner = pti;
39 /* It's a thread object, but it still count as one for the process */
40 pti->ppi->UserHandleCount++;
41
42 return ObjHead;
43 }
44
45 static void FreeThreadObject(
46 _In_ PVOID Object)
47 {
48 PTHROBJHEAD ObjHead = (PTHROBJHEAD)Object;
49 PTHREADINFO pti = ObjHead->pti;
50
51 UserHeapFree(ObjHead);
52
53 pti->ppi->UserHandleCount--;
54 IntDereferenceThreadInfo(pti);
55 }
56
57 _Success_(return!=NULL)
58 static PVOID AllocDeskThreadObject(
59 _In_ PDESKTOP pDesk,
60 _In_ PTHREADINFO pti,
61 _In_ SIZE_T Size,
62 _Out_ PVOID* HandleOwner)
63 {
64 PTHRDESKHEAD ObjHead;
65
66 ASSERT(Size > sizeof(*ObjHead));
67 ASSERT(pti != NULL);
68
69 if (!pDesk)
70 pDesk = pti->rpdesk;
71
72 ObjHead = DesktopHeapAlloc(pDesk, Size);
73 if (!ObjHead)
74 return NULL;
75
76 RtlZeroMemory(ObjHead, Size);
77
78 ObjHead->pSelf = ObjHead;
79 ObjHead->rpdesk = pDesk;
80 ObjHead->pti = pti;
81 IntReferenceThreadInfo(pti);
82 *HandleOwner = pti;
83 /* It's a thread object, but it still count as one for the process */
84 pti->ppi->UserHandleCount++;
85
86 return ObjHead;
87 }
88
89 static void FreeDeskThreadObject(
90 _In_ PVOID Object)
91 {
92 PTHRDESKHEAD ObjHead = (PTHRDESKHEAD)Object;
93 PDESKTOP pDesk = ObjHead->rpdesk;
94 PTHREADINFO pti = ObjHead->pti;
95
96 DesktopHeapFree(pDesk, Object);
97
98 pti->ppi->UserHandleCount--;
99 IntDereferenceThreadInfo(pti);
100 }
101
102 _Success_(return!=NULL)
103 static PVOID AllocDeskProcObject(
104 _In_ PDESKTOP pDesk,
105 _In_ PTHREADINFO pti,
106 _In_ SIZE_T Size,
107 _Out_ PVOID* HandleOwner)
108 {
109 PPROCDESKHEAD ObjHead;
110 PPROCESSINFO ppi;
111
112 ASSERT(Size > sizeof(*ObjHead));
113 ASSERT(pDesk != NULL);
114 ASSERT(pti != NULL);
115
116 ObjHead = DesktopHeapAlloc(pDesk, Size);
117 if (!ObjHead)
118 return NULL;
119
120 RtlZeroMemory(ObjHead, Size);
121
122 ppi = pti->ppi;
123
124 ObjHead->pSelf = ObjHead;
125 ObjHead->rpdesk = pDesk;
126 ObjHead->hTaskWow = (DWORD_PTR)ppi;
127 ppi->UserHandleCount++;
128 IntReferenceProcessInfo(ppi);
129 *HandleOwner = ppi;
130
131 return ObjHead;
132 }
133
134 static void FreeDeskProcObject(
135 _In_ PVOID Object)
136 {
137 PPROCDESKHEAD ObjHead = (PPROCDESKHEAD)Object;
138 PDESKTOP pDesk = ObjHead->rpdesk;
139 PPROCESSINFO ppi = (PPROCESSINFO)ObjHead->hTaskWow;
140
141 ppi->UserHandleCount--;
142 IntDereferenceProcessInfo(ppi);
143
144 DesktopHeapFree(pDesk, Object);
145 }
146
147 _Success_(return!=NULL)
148 static PVOID AllocProcMarkObject(
149 _In_ PDESKTOP pDesk,
150 _In_ PTHREADINFO pti,
151 _In_ SIZE_T Size,
152 _Out_ PVOID* HandleOwner)
153 {
154 PPROCMARKHEAD ObjHead;
155 PPROCESSINFO ppi = pti->ppi;
156
157 UNREFERENCED_PARAMETER(pDesk);
158
159 ASSERT(Size > sizeof(*ObjHead));
160
161 ObjHead = UserHeapAlloc(Size);
162 if (!ObjHead)
163 return NULL;
164
165 RtlZeroMemory(ObjHead, Size);
166
167 ObjHead->ppi = ppi;
168 IntReferenceProcessInfo(ppi);
169 *HandleOwner = ppi;
170 ppi->UserHandleCount++;
171
172 return ObjHead;
173 }
174
175 void FreeProcMarkObject(
176 _In_ PVOID Object)
177 {
178 PPROCESSINFO ppi = ((PPROCMARKHEAD)Object)->ppi;
179
180 UserHeapFree(Object);
181
182 ppi->UserHandleCount--;
183 IntDereferenceProcessInfo(ppi);
184 }
185
186 _Success_(return!=NULL)
187 static PVOID AllocSysObject(
188 _In_ PDESKTOP pDesk,
189 _In_ PTHREADINFO pti,
190 _In_ SIZE_T Size,
191 _Out_ PVOID* ObjectOwner)
192 {
193 PVOID Object;
194
195 UNREFERENCED_PARAMETER(pDesk);
196 UNREFERENCED_PARAMETER(pti);
197
198 ASSERT(Size > sizeof(HEAD));
199
200 Object = UserHeapAlloc(Size);
201 if (!Object)
202 return NULL;
203
204 *ObjectOwner = NULL;
205
206 RtlZeroMemory(Object, Size);
207 return Object;
208 }
209
210 _Success_(return!=NULL)
211 static PVOID AllocSysObjectCB(
212 _In_ PDESKTOP pDesk,
213 _In_ PTHREADINFO pti,
214 _In_ SIZE_T Size,
215 _Out_ PVOID* ObjectOwner)
216 {
217 PVOID Object;
218
219 UNREFERENCED_PARAMETER(pDesk);
220 UNREFERENCED_PARAMETER(pti);
221 ASSERT(Size > sizeof(HEAD));
222
223 /* Allocate the clipboard data */
224 // FIXME: This allocation should be done on the current session pool;
225 // however ReactOS' MM doesn't support session pool yet.
226 Object = ExAllocatePoolZero(/* SESSION_POOL_MASK | */ PagedPool, Size, USERTAG_CLIPBOARD);
227 if (!Object)
228 {
229 ERR("ExAllocatePoolZero failed. No object created.\n");
230 return NULL;
231 }
232
233 *ObjectOwner = NULL;
234 return Object;
235 }
236
237 static void FreeSysObject(
238 _In_ PVOID Object)
239 {
240 UserHeapFree(Object);
241 }
242
243 static void FreeSysObjectCB(
244 _In_ PVOID Object)
245 {
246 ExFreePoolWithTag(Object, USERTAG_CLIPBOARD);
247 }
248
249 static const struct
250 {
251 PVOID (*ObjectAlloc)(PDESKTOP, PTHREADINFO, SIZE_T, PVOID*);
252 BOOLEAN (*ObjectDestroy)(PVOID);
253 void (*ObjectFree)(PVOID);
254 } ObjectCallbacks[TYPE_CTYPES] =
255 {
256 { NULL, NULL, NULL }, /* TYPE_FREE */
257 { AllocDeskThreadObject, co_UserDestroyWindow, FreeDeskThreadObject }, /* TYPE_WINDOW */
258 { AllocDeskProcObject, UserDestroyMenuObject, FreeDeskProcObject }, /* TYPE_MENU */
259 { AllocProcMarkObject, IntDestroyCurIconObject, FreeCurIconObject }, /* TYPE_CURSOR */
260 { AllocSysObject, /*UserSetWindowPosCleanup*/NULL, FreeSysObject }, /* TYPE_SETWINDOWPOS */
261 { AllocDeskThreadObject, IntRemoveHook, FreeDeskThreadObject }, /* TYPE_HOOK */
262 { AllocSysObjectCB, /*UserClipDataCleanup*/NULL,FreeSysObjectCB }, /* TYPE_CLIPDATA */
263 { AllocDeskProcObject, DestroyCallProc, FreeDeskProcObject }, /* TYPE_CALLPROC */
264 { AllocProcMarkObject, UserDestroyAccelTable, FreeProcMarkObject }, /* TYPE_ACCELTABLE */
265 { NULL, NULL, NULL }, /* TYPE_DDEACCESS */
266 { NULL, NULL, NULL }, /* TYPE_DDECONV */
267 { NULL, NULL, NULL }, /* TYPE_DDEXACT */
268 { AllocSysObject, /*UserMonitorCleanup*/NULL, FreeSysObject }, /* TYPE_MONITOR */
269 { AllocSysObject, /*UserKbdLayoutCleanup*/NULL,FreeSysObject }, /* TYPE_KBDLAYOUT */
270 { AllocSysObject, /*UserKbdFileCleanup*/NULL, FreeSysObject }, /* TYPE_KBDFILE */
271 { AllocThreadObject, IntRemoveEvent, FreeThreadObject }, /* TYPE_WINEVENTHOOK */
272 { AllocSysObject, /*UserTimerCleanup*/NULL, FreeSysObject }, /* TYPE_TIMER */
273 { AllocInputContextObject, UserDestroyInputContext, UserFreeInputContext }, /* TYPE_INPUTCONTEXT */
274 { NULL, NULL, NULL }, /* TYPE_HIDDATA */
275 { NULL, NULL, NULL }, /* TYPE_DEVICEINFO */
276 { NULL, NULL, NULL }, /* TYPE_TOUCHINPUTINFO */
277 { NULL, NULL, NULL }, /* TYPE_GESTUREINFOOBJ */
278 };
279
280 #if DBG
281
282 void DbgUserDumpHandleTable(VOID)
283 {
284 int HandleCounts[TYPE_CTYPES];
285 PPROCESSINFO ppiList;
286 int i;
287 PWCHAR TypeNames[] = {L"Free",L"Window",L"Menu", L"CursorIcon", L"SMWP", L"Hook", L"ClipBoardData", L"CallProc",
288 L"Accel", L"DDEaccess", L"DDEconv", L"DDExact", L"Monitor", L"KBDlayout", L"KBDfile",
289 L"Event", L"Timer", L"InputContext", L"HidData", L"DeviceInfo", L"TouchInput",L"GestureInfo"};
290
291 ERR("Total handles count: %lu\n", gpsi->cHandleEntries);
292
293 memset(HandleCounts, 0, sizeof(HandleCounts));
294
295 /* First of all count the number of handles per type */
296 ppiList = gppiList;
297 while (ppiList)
298 {
299 ERR("Process %s (%p) handles count: %d\n\t", ppiList->peProcess->ImageFileName, ppiList->peProcess->UniqueProcessId, ppiList->UserHandleCount);
300
301 for (i = 1 ;i < TYPE_CTYPES; i++)
302 {
303 HandleCounts[i] += ppiList->DbgHandleCount[i];
304
305 DbgPrint("%S: %lu, ", TypeNames[i], ppiList->DbgHandleCount[i]);
306 if (i % 6 == 0)
307 DbgPrint("\n\t");
308 }
309 DbgPrint("\n");
310
311 ppiList = ppiList->ppiNext;
312 }
313
314 /* Print total type counts */
315 ERR("Total handles of the running processes: \n\t");
316 for (i = 1 ;i < TYPE_CTYPES; i++)
317 {
318 DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]);
319 if (i % 6 == 0)
320 DbgPrint("\n\t");
321 }
322 DbgPrint("\n");
323
324 /* Now count the handle counts that are allocated from the handle table */
325 memset(HandleCounts, 0, sizeof(HandleCounts));
326 for (i = 0; i < gHandleTable->nb_handles; i++)
327 HandleCounts[gHandleTable->handles[i].type]++;
328
329 ERR("Total handles count allocated: \n\t");
330 for (i = 1 ;i < TYPE_CTYPES; i++)
331 {
332 DbgPrint("%S: %d, ", TypeNames[i], HandleCounts[i]);
333 if (i % 6 == 0)
334 DbgPrint("\n\t");
335 }
336 DbgPrint("\n");
337 }
338
339 #endif
340
341 PUSER_HANDLE_ENTRY handle_to_entry(PUSER_HANDLE_TABLE ht, HANDLE handle )
342 {
343 unsigned short generation;
344 int index = (LOWORD(handle) - FIRST_USER_HANDLE) >> 1;
345 if (index < 0 || index >= ht->nb_handles)
346 return NULL;
347 if (!ht->handles[index].type)
348 return NULL;
349 generation = HIWORD(handle);
350 if (generation == ht->handles[index].generation || !generation || generation == 0xffff)
351 return &ht->handles[index];
352 return NULL;
353 }
354
355 __inline static HANDLE entry_to_handle(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY ptr )
356 {
357 int index = ptr - ht->handles;
358 return (HANDLE)((((INT_PTR)index << 1) + FIRST_USER_HANDLE) + (ptr->generation << 16));
359 }
360
361 __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
362 {
363 PUSER_HANDLE_ENTRY entry;
364 TRACE("handles used %lu\n", gpsi->cHandleEntries);
365
366 if (ht->freelist)
367 {
368 entry = ht->freelist;
369 ht->freelist = entry->ptr;
370
371 gpsi->cHandleEntries++;
372 return entry;
373 }
374
375 if (ht->nb_handles >= ht->allocated_handles) /* Need to grow the array */
376 {
377 ERR("Out of user handles! Used -> %lu, NM_Handle -> %d\n", gpsi->cHandleEntries, ht->nb_handles);
378
379 #if DBG
380 DbgUserDumpHandleTable();
381 #endif
382
383 return NULL;
384 #if 0
385 PUSER_HANDLE_ENTRY new_handles;
386 /* Grow array by 50% (but at minimum 32 entries) */
387 int growth = max( 32, ht->allocated_handles / 2 );
388 int new_size = min( ht->allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 );
389 if (new_size <= ht->allocated_handles)
390 return NULL;
391 if (!(new_handles = UserHeapReAlloc( ht->handles, new_size * sizeof(*ht->handles) )))
392 return NULL;
393 ht->handles = new_handles;
394 ht->allocated_handles = new_size;
395 #endif
396 }
397
398 entry = &ht->handles[ht->nb_handles++];
399
400 entry->generation = 1;
401
402 gpsi->cHandleEntries++;
403
404 return entry;
405 }
406
407 VOID UserInitHandleTable(PUSER_HANDLE_TABLE ht, PVOID mem, ULONG bytes)
408 {
409 ht->freelist = NULL;
410 ht->handles = mem;
411
412 ht->nb_handles = 0;
413 ht->allocated_handles = bytes / sizeof(USER_HANDLE_ENTRY);
414 }
415
416
417 __inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY entry)
418 {
419 void *ret;
420
421 #if DBG
422 {
423 PPROCESSINFO ppi;
424 switch (entry->type)
425 {
426 case TYPE_WINDOW:
427 case TYPE_HOOK:
428 case TYPE_WINEVENTHOOK:
429 ppi = ((PTHREADINFO)entry->pi)->ppi;
430 break;
431 case TYPE_MENU:
432 case TYPE_CURSOR:
433 case TYPE_CALLPROC:
434 case TYPE_ACCELTABLE:
435 ppi = entry->pi;
436 break;
437 default:
438 ppi = NULL;
439 }
440 if (ppi)
441 ppi->DbgHandleCount[entry->type]--;
442 }
443 #endif
444
445 ret = entry->ptr;
446 entry->ptr = ht->freelist;
447 entry->type = 0;
448 entry->flags = 0;
449 entry->pi = NULL;
450 ht->freelist = entry;
451
452 gpsi->cHandleEntries--;
453
454 return ret;
455 }
456
457 /* allocate a user handle for a given object */
458 HANDLE UserAllocHandle(
459 _Inout_ PUSER_HANDLE_TABLE ht,
460 _In_ PVOID object,
461 _In_ HANDLE_TYPE type,
462 _In_ PVOID HandleOwner)
463 {
464 PUSER_HANDLE_ENTRY entry = alloc_user_entry(ht);
465 if (!entry)
466 return 0;
467 entry->ptr = object;
468 entry->type = type;
469 entry->flags = 0;
470 entry->pi = HandleOwner;
471 if (++entry->generation >= 0xffff)
472 entry->generation = 1;
473
474 /* We have created a handle, which is a reference! */
475 UserReferenceObject(object);
476
477 return entry_to_handle(ht, entry );
478 }
479
480 /* return a pointer to a user object from its handle without setting an error */
481 PVOID UserGetObjectNoErr(PUSER_HANDLE_TABLE ht, HANDLE handle, HANDLE_TYPE type )
482 {
483 PUSER_HANDLE_ENTRY entry;
484
485 ASSERT(ht);
486
487 if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
488 {
489 return NULL;
490 }
491 return entry->ptr;
492 }
493
494 /* return a pointer to a user object from its handle */
495 PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, HANDLE_TYPE type )
496 {
497 PUSER_HANDLE_ENTRY entry;
498
499 ASSERT(ht);
500
501 if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
502 {
503 EngSetLastError(ERROR_INVALID_HANDLE);
504 return NULL;
505 }
506 return entry->ptr;
507 }
508
509
510 /* Get the full handle (32bit) for a possibly truncated (16bit) handle */
511 HANDLE get_user_full_handle(PUSER_HANDLE_TABLE ht, HANDLE handle )
512 {
513 PUSER_HANDLE_ENTRY entry;
514
515 if ((ULONG_PTR)handle >> 16)
516 return handle;
517 if (!(entry = handle_to_entry(ht, handle )))
518 return handle;
519 return entry_to_handle( ht, entry );
520 }
521
522
523 /* Same as get_user_object plus set the handle to the full 32-bit value */
524 void *get_user_object_handle(PUSER_HANDLE_TABLE ht, HANDLE* handle, HANDLE_TYPE type )
525 {
526 PUSER_HANDLE_ENTRY entry;
527
528 if (!(entry = handle_to_entry(ht, *handle )) || entry->type != type)
529 return NULL;
530 *handle = entry_to_handle( ht, entry );
531 return entry->ptr;
532 }
533
534
535
536 BOOL FASTCALL UserCreateHandleTable(VOID)
537 {
538 PVOID mem;
539 INT HandleCount = 1024 * 4;
540
541 // FIXME: Don't alloc all at once! Must be mapped into umode also...
542 mem = UserHeapAlloc(sizeof(USER_HANDLE_ENTRY) * HandleCount);
543 if (!mem)
544 {
545 ERR("Failed creating handle table\n");
546 return FALSE;
547 }
548
549 gHandleTable = UserHeapAlloc(sizeof(USER_HANDLE_TABLE));
550 if (gHandleTable == NULL)
551 {
552 UserHeapFree(mem);
553 ERR("Failed creating handle table\n");
554 return FALSE;
555 }
556
557 // FIXME: Make auto growable
558 UserInitHandleTable(gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * HandleCount);
559
560 return TRUE;
561 }
562
563 //
564 // New
565 //
566 PVOID
567 FASTCALL
568 UserCreateObject( PUSER_HANDLE_TABLE ht,
569 PDESKTOP pDesktop,
570 PTHREADINFO pti,
571 HANDLE* h,
572 HANDLE_TYPE type,
573 ULONG size)
574 {
575 HANDLE hi;
576 PVOID Object;
577 PVOID ObjectOwner;
578
579 /* Some sanity checks. Other checks will be made in the allocator */
580 ASSERT(type < TYPE_CTYPES);
581 ASSERT(type != TYPE_FREE);
582 ASSERT(ht != NULL);
583
584 /* Allocate the object */
585 ASSERT(ObjectCallbacks[type].ObjectAlloc != NULL);
586 Object = ObjectCallbacks[type].ObjectAlloc(pDesktop, pti, size, &ObjectOwner);
587 if (!Object)
588 {
589 ERR("User object allocation failed. Out of memory!\n");
590 return NULL;
591 }
592
593 hi = UserAllocHandle(ht, Object, type, ObjectOwner);
594 if (hi == NULL)
595 {
596 ERR("Out of user handles!\n");
597 ObjectCallbacks[type].ObjectFree(Object);
598 return NULL;
599 }
600
601 #if DBG
602 if (pti)
603 pti->ppi->DbgHandleCount[type]++;
604 #endif
605
606 /* Give this object its identity. */
607 ((PHEAD)Object)->h = hi;
608
609 /* The caller will get a locked object.
610 * Note: with the reference from the handle, that makes two */
611 UserReferenceObject(Object);
612
613 if (h)
614 *h = hi;
615 return Object;
616 }
617
618 // Win: HMMarkObjectDestroy
619 BOOL
620 FASTCALL
621 UserMarkObjectDestroy(PVOID Object)
622 {
623 PUSER_HANDLE_ENTRY entry;
624 PHEAD ObjHead = Object;
625
626 entry = handle_to_entry(gHandleTable, ObjHead->h);
627
628 ASSERT(entry != NULL);
629
630 entry->flags |= HANDLEENTRY_DESTROY;
631
632 if (ObjHead->cLockObj > 1)
633 {
634 entry->flags &= ~HANDLEENTRY_INDESTROY;
635 TRACE("Count %d\n",ObjHead->cLockObj);
636 return FALSE;
637 }
638
639 return TRUE;
640 }
641
642 BOOL
643 FASTCALL
644 UserDereferenceObject(PVOID Object)
645 {
646 PHEAD ObjHead = Object;
647
648 ASSERT(ObjHead->cLockObj >= 1);
649 ASSERT(ObjHead->cLockObj < 0x10000);
650
651 if (--ObjHead->cLockObj == 0)
652 {
653 PUSER_HANDLE_ENTRY entry;
654 HANDLE_TYPE type;
655
656 entry = handle_to_entry(gHandleTable, ObjHead->h);
657
658 ASSERT(entry != NULL);
659 /* The entry should be marked as in deletion */
660 ASSERT(entry->flags & HANDLEENTRY_INDESTROY);
661
662 type = entry->type;
663 ASSERT(type != TYPE_FREE);
664 ASSERT(type < TYPE_CTYPES);
665
666 /* We can now get rid of everything */
667 free_user_entry(gHandleTable, entry );
668
669 #if 0
670 /* Call the object destructor */
671 ASSERT(ObjectCallbacks[type].ObjectCleanup != NULL);
672 ObjectCallbacks[type].ObjectCleanup(Object);
673 #endif
674
675 /* And free it */
676 ASSERT(ObjectCallbacks[type].ObjectFree != NULL);
677 ObjectCallbacks[type].ObjectFree(Object);
678
679 return TRUE;
680 }
681 return FALSE;
682 }
683
684 BOOL
685 FASTCALL
686 UserFreeHandle(PUSER_HANDLE_TABLE ht, HANDLE handle )
687 {
688 PUSER_HANDLE_ENTRY entry;
689
690 if (!(entry = handle_to_entry( ht, handle )))
691 {
692 SetLastNtError( STATUS_INVALID_HANDLE );
693 return FALSE;
694 }
695
696 entry->flags = HANDLEENTRY_INDESTROY;
697
698 return UserDereferenceObject(entry->ptr);
699 }
700
701 BOOL
702 FASTCALL
703 UserObjectInDestroy(HANDLE h)
704 {
705 PUSER_HANDLE_ENTRY entry;
706
707 if (!(entry = handle_to_entry( gHandleTable, h )))
708 {
709 SetLastNtError( STATUS_INVALID_HANDLE );
710 return TRUE;
711 }
712 return (entry->flags & HANDLEENTRY_INDESTROY);
713 }
714
715 BOOL
716 FASTCALL
717 UserDeleteObject(HANDLE h, HANDLE_TYPE type )
718 {
719 PVOID body = UserGetObject(gHandleTable, h, type);
720
721 if (!body) return FALSE;
722
723 ASSERT( ((PHEAD)body)->cLockObj >= 1);
724 ASSERT( ((PHEAD)body)->cLockObj < 0x10000);
725
726 return UserFreeHandle(gHandleTable, h);
727 }
728
729 VOID
730 FASTCALL
731 UserReferenceObject(PVOID obj)
732 {
733 PHEAD ObjHead = obj;
734 ASSERT(ObjHead->cLockObj < 0x10000);
735
736 ObjHead->cLockObj++;
737 }
738
739 PVOID
740 FASTCALL
741 UserReferenceObjectByHandle(HANDLE handle, HANDLE_TYPE type)
742 {
743 PVOID object;
744
745 object = UserGetObject(gHandleTable, handle, type);
746 if (object)
747 {
748 UserReferenceObject(object);
749 }
750 return object;
751 }
752
753 BOOLEAN
754 UserDestroyObjectsForOwner(PUSER_HANDLE_TABLE Table, PVOID Owner)
755 {
756 int i;
757 PUSER_HANDLE_ENTRY Entry;
758 BOOLEAN Ret = TRUE;
759
760 /* Sweep the whole handle table */
761 for (i = 0; i < Table->allocated_handles; i++)
762 {
763 Entry = &Table->handles[i];
764
765 if (Entry->pi != Owner)
766 continue;
767
768 /* Do not destroy if it's already been done */
769 if (Entry->flags & HANDLEENTRY_INDESTROY)
770 continue;
771
772 /* Call destructor */
773 if (!ObjectCallbacks[Entry->type].ObjectDestroy(Entry->ptr))
774 {
775 ERR("Failed destructing object %p, type %u.\n", Entry->ptr, Entry->type);
776 /* Don't return immediately, we must continue destroying the other objects */
777 Ret = FALSE;
778 }
779 }
780
781 return Ret;
782 }
783
784 /*
785 *
786 * Status
787 * @implemented
788 */
789
790 BOOL
791 APIENTRY
792 NtUserValidateHandleSecure(
793 HANDLE handle)
794 {
795 UINT uType;
796 PPROCESSINFO ppi;
797 PUSER_HANDLE_ENTRY entry;
798 BOOL Ret = FALSE;
799
800 UserEnterExclusive();
801
802 if (!(entry = handle_to_entry(gHandleTable, handle )))
803 {
804 EngSetLastError(ERROR_INVALID_HANDLE);
805 goto Exit; // Return FALSE
806 }
807 uType = entry->type;
808 switch (uType)
809 {
810 case TYPE_WINDOW:
811 case TYPE_INPUTCONTEXT:
812 ppi = ((PTHREADINFO)entry->pi)->ppi;
813 break;
814 case TYPE_MENU:
815 case TYPE_ACCELTABLE:
816 case TYPE_CURSOR:
817 case TYPE_HOOK:
818 case TYPE_CALLPROC:
819 case TYPE_SETWINDOWPOS:
820 ppi = entry->pi;
821 break;
822 default:
823 ppi = NULL;
824 break;
825 }
826
827 if (!ppi)
828 goto Exit; // Return FALSE
829
830 // Same process job returns TRUE.
831 if (gptiCurrent->ppi->pW32Job == ppi->pW32Job) Ret = TRUE;
832
833 Exit:
834 UserLeave();
835 return Ret;
836 }
837
838 // Win: HMAssignmentLock
839 PVOID FASTCALL UserAssignmentLock(PVOID *ppvObj, PVOID pvNew)
840 {
841 PVOID pvOld = *ppvObj;
842 *ppvObj = pvNew;
843
844 if (pvOld && pvOld == pvNew)
845 return pvOld;
846
847 if (pvNew)
848 UserReferenceObject(pvNew);
849
850 if (pvOld)
851 {
852 if (UserDereferenceObject(pvOld))
853 pvOld = NULL;
854 }
855
856 return pvOld;
857 }
858
859 // Win: HMAssignmentUnlock
860 PVOID FASTCALL UserAssignmentUnlock(PVOID *ppvObj)
861 {
862 PVOID pvOld = *ppvObj;
863 *ppvObj = NULL;
864
865 if (pvOld)
866 {
867 if (UserDereferenceObject(pvOld))
868 pvOld = NULL;
869 }
870
871 return pvOld;
872 }