- Introduce the base of what should become a proper user object manager, with proper refcounting, handle management, cleanup callbacks and inter-object referencing.
Approved by Jim and Giannis.
CORE-8539 #resolve

svn path=/trunk/; revision=64219
This commit is contained in:
Jérôme Gardou 2014-09-21 17:44:40 +00:00
parent c2068d9c05
commit 01da3a14ed
21 changed files with 751 additions and 656 deletions

View file

@ -172,7 +172,7 @@ typedef struct _THRDESKHEAD
typedef struct _PROCDESKHEAD
{
HEAD;
DWORD hTaskWow;
DWORD_PTR hTaskWow;
struct _DESKTOP *rpdesk;
PVOID pSelf;
} PROCDESKHEAD, *PPROCDESKHEAD;

View file

@ -235,6 +235,7 @@ NtUserCreateAcceleratorTable(
ULONG Index;
NTSTATUS Status = STATUS_SUCCESS;
DECLARE_RETURN(HACCEL);
PTHREADINFO pti;
TRACE("Enter NtUserCreateAcceleratorTable(Entries %p, EntriesCount %u)\n",
Entries, EntriesCount);
@ -246,7 +247,14 @@ NtUserCreateAcceleratorTable(
RETURN( (HACCEL) NULL );
}
Accel = UserCreateObject(gHandleTable, NULL, NULL, (PHANDLE)&hAccel, TYPE_ACCELTABLE, sizeof(ACCELERATOR_TABLE));
pti = PsGetCurrentThreadWin32Thread();
Accel = UserCreateObject(gHandleTable,
pti->rpdesk,
pti,
(PHANDLE)&hAccel,
TYPE_ACCELTABLE,
sizeof(ACCELERATOR_TABLE));
if (Accel == NULL)
{
@ -313,6 +321,21 @@ CLEANUP:
END_CLEANUP;
}
BOOLEAN
UserDestroyAccelTable(PVOID Object)
{
PACCELERATOR_TABLE Accel = Object;
if (Accel->Table != NULL)
{
ExFreePoolWithTag(Accel->Table, USERTAG_ACCEL);
Accel->Table = NULL;
}
UserDeleteObject(Accel->head.h, TYPE_ACCELTABLE);
return TRUE;
}
BOOLEAN
APIENTRY
NtUserDestroyAcceleratorTable(
@ -334,13 +357,7 @@ NtUserDestroyAcceleratorTable(
RETURN( FALSE);
}
if (Accel->Table != NULL)
{
ExFreePoolWithTag(Accel->Table, USERTAG_ACCEL);
Accel->Table = NULL;
}
UserDeleteObject(hAccel, TYPE_ACCELTABLE);
UserDestroyAccelTable(Accel);
RETURN( TRUE);

View file

@ -2,9 +2,11 @@
typedef struct _ACCELERATOR_TABLE
{
HEAD head;
PROCMARKHEAD head;
ULONG Count;
LPACCEL Table;
} ACCELERATOR_TABLE, *PACCELERATOR_TABLE;
PACCELERATOR_TABLE FASTCALL UserGetAccelObject(HACCEL);
BOOLEAN
UserDestroyAccelTable(PVOID Object);

View file

@ -17,11 +17,11 @@ GetCallProcHandle(IN PCALLPROCDATA CallProc)
return (WNDPROC)((ULONG_PTR)UserHMGetHandle(CallProc) | 0xFFFF0000);
}
VOID
DestroyCallProc(IN PDESKTOPINFO Desktop,
IN OUT PCALLPROCDATA CallProc)
BOOLEAN
DestroyCallProc(_Inout_ PVOID Object)
{
UserDeleteObject(UserHMGetHandle(CallProc), TYPE_CALLPROC);
UserDeleteObject(UserHMGetHandle((PCALLPROCDATA)Object), TYPE_CALLPROC);
return TRUE;
}
PCALLPROCDATA
@ -33,9 +33,11 @@ CreateCallProc(IN PDESKTOP Desktop,
PCALLPROCDATA NewCallProc;
HANDLE Handle;
/* We can send any thread pointer to the object manager here,
* What's important is the process info */
NewCallProc = (PCALLPROCDATA)UserCreateObject(gHandleTable,
Desktop,
NULL,
pi->ptiList,
&Handle,
TYPE_CALLPROC,
sizeof(CALLPROCDATA));
@ -129,7 +131,7 @@ UserGetCPD(
// No luck, create a new one for the requested proc.
if (!CallProc)
{
CallProc = CreateCallProc( NULL,
CallProc = CreateCallProc( pCls->rpdeskParent,
(WNDPROC)ProcIn,
!!(Flags & UserGetCPDA2U),
pti->ppi);

View file

@ -224,8 +224,7 @@ IntDestroyClass(IN OUT PCLS Class)
NextCallProc = CallProc->spcpdNext;
CallProc->spcpdNext = NULL;
DestroyCallProc(NULL,
CallProc);
DestroyCallProc(CallProc);
CallProc = NextCallProc;
}

View file

@ -16,9 +16,8 @@ IsCallProcHandle(IN WNDPROC lpWndProc)
return ((ULONG_PTR)lpWndProc & 0xFFFF0000) == 0xFFFF0000;
}
VOID
DestroyCallProc(IN PDESKTOPINFO Desktop,
IN OUT PCALLPROCDATA CallProc);
BOOLEAN
DestroyCallProc(_Inout_ PVOID Object);
PCALLPROCDATA
CreateCallProc(IN PDESKTOP Desktop,

View file

@ -209,7 +209,13 @@ IntCreateCurIconHandle(BOOLEAN Anim)
PCURICON_OBJECT CurIcon;
HANDLE hCurIcon;
CurIcon = UserCreateObject(gHandleTable, NULL, NULL, &hCurIcon, TYPE_CURSOR, sizeof(CURICON_OBJECT));
CurIcon = UserCreateObject(
gHandleTable,
NULL,
GetW32ThreadInfo(),
&hCurIcon,
TYPE_CURSOR,
sizeof(CURICON_OBJECT));
if (!CurIcon)
{
@ -317,19 +323,6 @@ emptyList:
return Ret;
}
VOID FASTCALL
IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
{
PCURICON_OBJECT CurIcon, tmp;
/* Run through the list of icon objects */
LIST_FOR_EACH_SAFE(CurIcon, tmp, &gCurIconList, CURICON_OBJECT, ListEntry)
{
UserReferenceObject(CurIcon);
IntDestroyCurIconObject(CurIcon, Win32Process);
}
}
HCURSOR FASTCALL
IntSetCursor(
HCURSOR hCursor)

View file

@ -105,7 +105,6 @@ typedef struct _SYSTEM_CURSORINFO
BOOL InitCursorImpl(VOID);
HANDLE IntCreateCurIconHandle(BOOLEAN Anim);
VOID FASTCALL IntCleanupCurIcons(struct _EPROCESS *Process, PPROCESSINFO Win32Process);
BOOL UserDrawIconEx(HDC hDc, INT xLeft, INT yTop, PCURICON_OBJECT pIcon, INT cxWidth,
INT cyHeight, UINT istepIfAniCur, HBRUSH hbrFlickerFreeDraw, UINT diFlags);
@ -115,6 +114,7 @@ BOOL APIENTRY UserClipCursor(RECTL *prcl);
PSYSTEM_CURSORINFO IntGetSysCursorInfo(VOID);
HCURSOR FASTCALL IntSetCursor(HCURSOR hCursor);
BOOL FASTCALL IntDestroyCursor(HANDLE hCurIcon, BOOL bForce);
BOOLEAN FASTCALL IntDestroyCurIconObject(PCURICON_OBJECT CurIcon, PPROCESSINFO ppi);
#define IntReleaseCurIconObject(CurIconObj) \
UserDereferenceObject(CurIconObj)

View file

@ -129,11 +129,10 @@ IntCallLowLevelEvent( PEVENTHOOK pEH,
return NT_SUCCESS(Status) ? uResult : 0;
}
static
BOOL
FASTCALL
IntRemoveEvent(PEVENTHOOK pEH)
BOOLEAN
IntRemoveEvent(PVOID Object)
{
PEVENTHOOK pEH = Object;
if (pEH)
{
TRACE("IntRemoveEvent pEH %p\n", pEH);
@ -148,38 +147,6 @@ IntRemoveEvent(PEVENTHOOK pEH)
return FALSE;
}
VOID
FASTCALL
EVENT_DestroyThreadEvents(PETHREAD Thread)
{
PTHREADINFO pti;
PEVENTHOOK pEH;
PLIST_ENTRY pLE;
pti = Thread->Tcb.Win32Thread;
if (!pti) return;
if (!GlobalEvents || !GlobalEvents->Counts) return;
pLE = GlobalEvents->Events.Flink;
if (IsListEmpty(pLE)) return;
pEH = CONTAINING_RECORD(pLE, EVENTHOOK, Chain);
do
{
if (IsListEmpty(pLE)) break;
if (!pEH) break;
pLE = pEH->Chain.Flink;
if (pEH->head.pti == pti)
{
IntRemoveEvent(pEH);
}
pEH = CONTAINING_RECORD(pLE, EVENTHOOK, Chain);
} while (pLE != &GlobalEvents->Events);
return;
}
/* FUNCTIONS *****************************************************************/
//
@ -332,7 +299,7 @@ NtUserSetWinEventHook(
HWINEVENTHOOK Ret = NULL;
NTSTATUS Status;
HANDLE Handle;
PETHREAD Thread = NULL;
PTHREADINFO pti;
TRACE("NtUserSetWinEventHook hmod %p, pfn %p\n", hmodWinEventProc, lpfnWinEventProc);
@ -370,15 +337,22 @@ NtUserSetWinEventHook(
if (idThread)
{
PETHREAD Thread;
Status = PsLookupThreadByThreadId((HANDLE)(DWORD_PTR)idThread, &Thread);
if (!NT_SUCCESS(Status))
{
EngSetLastError(ERROR_INVALID_THREAD_ID);
goto SetEventExit;
}
pti = PsGetThreadWin32Thread(Thread);
ObDereferenceObject(Thread);
}
else
{
pti = PsGetCurrentThreadWin32Thread();
}
// Creator, pti is set here.
pEH = UserCreateObject(gHandleTable, NULL, NULL, &Handle, TYPE_WINEVENTHOOK, sizeof(EVENTHOOK));
pEH = UserCreateObject(gHandleTable, NULL, pti, &Handle, TYPE_WINEVENTHOOK, sizeof(EVENTHOOK));
if (pEH)
{
InsertTailList(&GlobalEvents->Events, &pEH->Chain);
@ -413,7 +387,6 @@ NtUserSetWinEventHook(
}
SetEventExit:
if (Thread) ObDereferenceObject(Thread);
UserLeave();
return Ret;
}

View file

@ -1028,14 +1028,13 @@ IntFreeHook(PHOOK Hook)
}
/* Remove a hook, freeing it from the chain */
static
VOID
FASTCALL
IntRemoveHook(PHOOK Hook)
BOOLEAN
IntRemoveHook(PVOID Object)
{
INT HookId;
PTHREADINFO pti;
PDESKTOP pdo;
PHOOK Hook = Object;
HookId = Hook->HookId;
@ -1073,65 +1072,8 @@ IntRemoveHook(PHOOK Hook)
pdo->pDeskInfo->fsHooks &= ~HOOKID_TO_FLAG(HookId);
}
}
}
VOID
FASTCALL
HOOK_DestroyThreadHooks(PETHREAD Thread)
{
PTHREADINFO pti;
PDESKTOP pdo;
int HookId;
PHOOK HookObj;
PLIST_ENTRY pElem;
pti = Thread->Tcb.Win32Thread;
pdo = IntGetActiveDesktop();
if (!pti || !pdo)
{
ERR("Kill Thread Hooks pti %p pdo %p\n", pti, pdo);
return;
}
// Local Thread cleanup.
if (pti->fsHooks)
{
for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
{
PLIST_ENTRY pLastHead = &pti->aphkStart[HOOKID_TO_INDEX(HookId)];
pElem = pLastHead->Flink;
while (pElem != pLastHead)
{
HookObj = CONTAINING_RECORD(pElem, HOOK, Chain);
pElem = HookObj->Chain.Flink; // get next element before hook is destroyed
IntRemoveHook(HookObj);
}
}
pti->fsHooks = 0;
pti->pClientInfo->fsHooks = 0;
}
// Global search based on Thread and cleanup.
if (pdo->pDeskInfo->fsHooks)
{
for (HookId = WH_MINHOOK; HookId <= WH_MAXHOOK; HookId++)
{
PLIST_ENTRY pGLE = &pdo->pDeskInfo->aphkStart[HOOKID_TO_INDEX(HookId)];
pElem = pGLE->Flink;
while (pElem != pGLE)
{
HookObj = CONTAINING_RECORD(pElem, HOOK, Chain);
pElem = HookObj->Chain.Flink; // Get next element before hook is destroyed
if (HookObj->head.pti == pti)
{
IntRemoveHook(HookObj);
}
}
}
}
return;
return TRUE;
}
/*
@ -1576,7 +1518,7 @@ NtUserSetWindowsHookEx( HINSTANCE Mod,
}
ObDereferenceObject(WinStaObj);
Hook = UserCreateObject(gHandleTable, NULL, NULL, (PHANDLE)&Handle, TYPE_HOOK, sizeof(HOOK));
Hook = UserCreateObject(gHandleTable, NULL, ptiHook, (PHANDLE)&Handle, TYPE_HOOK, sizeof(HOOK));
if (!Hook)
{

View file

@ -43,12 +43,12 @@ typedef struct _NOTIFYEVENT
LRESULT FASTCALL co_CallHook(INT HookId, INT Code, WPARAM wParam, LPARAM lParam);
LRESULT FASTCALL co_HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam);
LRESULT FASTCALL co_EVENT_CallEvents(DWORD, HWND, UINT_PTR, LONG_PTR);
VOID FASTCALL HOOK_DestroyThreadHooks(PETHREAD Thread);
VOID FASTCALL EVENT_DestroyThreadEvents(PETHREAD Thread);
PHOOK FASTCALL IntGetHookObject(HHOOK);
PHOOK FASTCALL IntGetNextHook(PHOOK Hook);
LRESULT FASTCALL UserCallNextHookEx( PHOOK pHook, int Code, WPARAM wParam, LPARAM lParam, BOOL Ansi);
BOOL FASTCALL IntUnhookWindowsHook(int,HOOKPROC);
BOOLEAN IntRemoveHook(PVOID Object);
BOOLEAN IntRemoveEvent(PVOID Object);
BOOL FASTCALL UserLoadApiHook(VOID);
BOOL IntLoadHookModule(int iHookID, HHOOK hHook, BOOL Unload);

View file

@ -51,12 +51,232 @@ DbgPostServiceHook(ULONG ulSyscallId, ULONG_PTR ulResult)
}
#endif
static
NTSTATUS
CreateProcessInfo(PEPROCESS Process)
{
PPROCESSINFO ppiCurrent;
NTSTATUS Status;
SIZE_T ViewSize = 0;
LARGE_INTEGER Offset;
PVOID UserBase = NULL;
PRTL_USER_PROCESS_PARAMETERS pParams = Process->Peb->ProcessParameters;
/* We might be called with an already allocated win32 process */
ppiCurrent = PsGetProcessWin32Process(Process);
if (ppiCurrent != NULL)
{
/* There is no more to do for us (this is a success code!) */
return STATUS_ALREADY_WIN32;
}
/* Allocate a new win32 process */
ppiCurrent = ExAllocatePoolWithTag(NonPagedPool,
sizeof(PROCESSINFO),
USERTAG_PROCESSINFO);
if (ppiCurrent == NULL)
{
ERR_CH(UserProcess, "Failed to allocate ppi for PID:0x%lx\n",
HandleToUlong(Process->UniqueProcessId));
return STATUS_NO_MEMORY;
}
RtlZeroMemory(ppiCurrent, sizeof(PROCESSINFO));
PsSetProcessWin32Process(Process, ppiCurrent, NULL);
#if DBG
DbgInitDebugChannels();
#if KDBG
KdRosRegisterCliCallback(DbgGdiKdbgCliCallback);
#endif
#endif
TRACE_CH(UserProcess,"Allocated ppi 0x%p for PID:0x%lx\n", ppiCurrent, HandleToUlong(Process->UniqueProcessId));
/* map the global heap into the process */
Offset.QuadPart = 0;
Status = MmMapViewOfSection(GlobalUserHeapSection,
PsGetCurrentProcess(),
&UserBase,
0,
0,
&Offset,
&ViewSize,
ViewUnmap,
SEC_NO_CHANGE,
PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
if (!NT_SUCCESS(Status))
{
TRACE_CH(UserProcess,"Failed to map the global heap! 0x%x\n", Status);
return Status;
}
ppiCurrent->HeapMappings.Next = NULL;
ppiCurrent->HeapMappings.KernelMapping = (PVOID)GlobalUserHeap;
ppiCurrent->HeapMappings.UserMapping = UserBase;
ppiCurrent->HeapMappings.Count = 1;
InitializeListHead(&ppiCurrent->GDIBrushAttrFreeList);
InitializeListHead(&ppiCurrent->GDIDcAttrFreeList);
InitializeListHead(&ppiCurrent->PrivateFontListHead);
ExInitializeFastMutex(&ppiCurrent->PrivateFontListLock);
InitializeListHead(&ppiCurrent->DriverObjListHead);
ExInitializeFastMutex(&ppiCurrent->DriverObjListLock);
ppiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
if (!EngCreateEvent((PEVENT *)&ppiCurrent->InputIdleEvent))
{
KeBugCheck(0);
}
KeInitializeEvent(ppiCurrent->InputIdleEvent, NotificationEvent, FALSE);
/* map the gdi handle table to user land */
Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(Process);
Process->Peb->GdiDCAttributeList = GDI_BATCH_LIMIT;
pParams = Process->Peb->ProcessParameters;
ppiCurrent->peProcess = Process;
/* setup process flags */
ppiCurrent->W32PF_flags = W32PF_THREADCONNECTED;
if ( pParams &&
pParams->WindowFlags & STARTF_SCRNSAVER )
{
ppiScrnSaver = ppiCurrent;
ppiCurrent->W32PF_flags |= W32PF_SCREENSAVER;
}
// Fixme check if this process is allowed.
ppiCurrent->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE; // Starting application it will get toggled off.
/* Create pools for GDI object attributes */
ppiCurrent->pPoolDcAttr = GdiPoolCreate(sizeof(DC_ATTR), 'acdG');
ppiCurrent->pPoolBrushAttr = GdiPoolCreate(sizeof(BRUSH_ATTR), 'arbG');
ppiCurrent->pPoolRgnAttr = GdiPoolCreate(sizeof(RGN_ATTR), 'agrG');
ASSERT(ppiCurrent->pPoolDcAttr);
ASSERT(ppiCurrent->pPoolBrushAttr);
ASSERT(ppiCurrent->pPoolRgnAttr);
/* Add the process to the global list */
ppiCurrent->ppiNext = gppiList;
gppiList = ppiCurrent;
IntReferenceProcessInfo(ppiCurrent);
return STATUS_SUCCESS;
}
static
NTSTATUS
DestroyProcessInfo(PEPROCESS Process)
{
PPROCESSINFO ppiCurrent, *pppi;
/* Get the Win32 Process */
ppiCurrent = PsGetProcessWin32Process(Process);
ASSERT(ppiCurrent);
TRACE_CH(UserProcess, "Destroying ppi 0x%p\n", ppiCurrent);
ppiCurrent->W32PF_flags |= W32PF_TERMINATED;
if (ppiScrnSaver == ppiCurrent)
ppiScrnSaver = NULL;
/* Destroy user objects */
UserDestroyObjectsForOwner(gHandleTable, ppiCurrent);
TRACE_CH(UserProcess,"Freeing ppi 0x%p\n", ppiCurrent);
#if DBG
if (DBG_IS_CHANNEL_ENABLED(ppiCurrent, DbgChUserObj, WARN_LEVEL))
{
TRACE_CH(UserObj, "Dumping user handles at the end of the process %s (Info %p).\n",
ppiCurrent->peProcess->ImageFileName, ppiCurrent);
DbgUserDumpHandleTable();
}
#endif
/* And GDI ones too */
GDI_CleanupForProcess(Process);
/* So we can now free the pools */
GdiPoolDestroy(ppiCurrent->pPoolDcAttr);
GdiPoolDestroy(ppiCurrent->pPoolBrushAttr);
GdiPoolDestroy(ppiCurrent->pPoolRgnAttr);
/* Remove it from the list of GUI apps */
co_IntGraphicsCheck(FALSE);
/*
* Deregister logon application automatically
*/
if(LogonProcess == ppiCurrent)
{
LogonProcess = NULL;
}
/* Close the current window station */
UserSetProcessWindowStation(NULL);
if (gppiInputProvider == ppiCurrent) gppiInputProvider = NULL;
/* Remove it from the list */
pppi = &gppiList;
while (*pppi != NULL && *pppi != ppiCurrent)
pppi = &(*pppi)->ppiNext;
ASSERT(*pppi == ppiCurrent);
*pppi = ppiCurrent->ppiNext;
if(ppiCurrent->hdeskStartup)
{
ZwClose(ppiCurrent->hdeskStartup);
ppiCurrent->hdeskStartup = NULL;
}
/* The process is dying */
PsSetProcessWin32Process(Process, NULL, ppiCurrent);
ppiCurrent->peProcess = NULL;
/* At last, dereference */
IntDereferenceProcessInfo(ppiCurrent);
return STATUS_SUCCESS;
}
VOID
UserDeleteW32Process(PPROCESSINFO ppiCurrent)
{
if (ppiCurrent->InputIdleEvent)
{
EngDeleteEvent((PEVENT)ppiCurrent->InputIdleEvent);
}
/* Close the startup desktop */
if(ppiCurrent->rpdeskStartup)
ObDereferenceObject(ppiCurrent->rpdeskStartup);
#if DBG
if (DBG_IS_CHANNEL_ENABLED(ppiCurrent, DbgChUserObj, WARN_LEVEL))
{
TRACE_PPI(ppiCurrent, UserObj, "Dumping user handles now that process info %p is gets freed.\n", ppiCurrent);
DbgUserDumpHandleTable();
}
#endif
/* Free the PROCESSINFO */
ExFreePoolWithTag(ppiCurrent, USERTAG_PROCESSINFO);
}
NTSTATUS
APIENTRY
Win32kProcessCallback(struct _EPROCESS *Process,
BOOLEAN Create)
{
PPROCESSINFO ppiCurrent, *pppi;
NTSTATUS Status;
ASSERT(Process->Peb);
@ -65,193 +285,13 @@ Win32kProcessCallback(struct _EPROCESS *Process,
if (Create)
{
SIZE_T ViewSize = 0;
LARGE_INTEGER Offset;
PVOID UserBase = NULL;
PRTL_USER_PROCESS_PARAMETERS pParams = Process->Peb->ProcessParameters;
/* We might be called with an already allocated win32 process */
ppiCurrent = PsGetProcessWin32Process(Process);
if (ppiCurrent != NULL)
{
/* There is no more to do for us (this is a success code!) */
Status = STATUS_ALREADY_WIN32;
goto Leave;
}
/* Allocate a new win32 process */
ppiCurrent = ExAllocatePoolWithTag(NonPagedPool,
sizeof(PROCESSINFO),
USERTAG_PROCESSINFO);
if (ppiCurrent == NULL)
{
ERR_CH(UserProcess, "Failed to allocate ppi for PID:0x%lx\n",
HandleToUlong(Process->UniqueProcessId));
Status = STATUS_NO_MEMORY;
goto Leave;
}
RtlZeroMemory(ppiCurrent, sizeof(PROCESSINFO));
PsSetProcessWin32Process(Process, ppiCurrent, NULL);
#if DBG
DbgInitDebugChannels();
#if KDBG
KdRosRegisterCliCallback(DbgGdiKdbgCliCallback);
#endif
#endif
TRACE_CH(UserProcess,"Allocated ppi 0x%p for PID:0x%lx\n", ppiCurrent, HandleToUlong(Process->UniqueProcessId));
/* map the global heap into the process */
Offset.QuadPart = 0;
Status = MmMapViewOfSection(GlobalUserHeapSection,
PsGetCurrentProcess(),
&UserBase,
0,
0,
&Offset,
&ViewSize,
ViewUnmap,
SEC_NO_CHANGE,
PAGE_EXECUTE_READ); /* would prefer PAGE_READONLY, but thanks to RTL heaps... */
if (!NT_SUCCESS(Status))
{
TRACE_CH(UserProcess,"Failed to map the global heap! 0x%x\n", Status);
goto Leave;
}
ppiCurrent->HeapMappings.Next = NULL;
ppiCurrent->HeapMappings.KernelMapping = (PVOID)GlobalUserHeap;
ppiCurrent->HeapMappings.UserMapping = UserBase;
ppiCurrent->HeapMappings.Count = 1;
InitializeListHead(&ppiCurrent->MenuListHead);
InitializeListHead(&ppiCurrent->GDIBrushAttrFreeList);
InitializeListHead(&ppiCurrent->GDIDcAttrFreeList);
InitializeListHead(&ppiCurrent->PrivateFontListHead);
ExInitializeFastMutex(&ppiCurrent->PrivateFontListLock);
InitializeListHead(&ppiCurrent->DriverObjListHead);
ExInitializeFastMutex(&ppiCurrent->DriverObjListLock);
ppiCurrent->KeyboardLayout = W32kGetDefaultKeyLayout();
if (!EngCreateEvent((PEVENT *)&ppiCurrent->InputIdleEvent))
{
KeBugCheck(0);
}
KeInitializeEvent(ppiCurrent->InputIdleEvent, NotificationEvent, FALSE);
/* map the gdi handle table to user land */
Process->Peb->GdiSharedHandleTable = GDI_MapHandleTable(Process);
Process->Peb->GdiDCAttributeList = GDI_BATCH_LIMIT;
pParams = Process->Peb->ProcessParameters;
ppiCurrent->peProcess = Process;
/* setup process flags */
ppiCurrent->W32PF_flags = W32PF_THREADCONNECTED;
if ( pParams &&
pParams->WindowFlags & STARTF_SCRNSAVER )
{
ppiScrnSaver = ppiCurrent;
ppiCurrent->W32PF_flags |= W32PF_SCREENSAVER;
}
// Fixme check if this process is allowed.
ppiCurrent->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE; // Starting application it will get toggled off.
/* Create pools for GDI object attributes */
ppiCurrent->pPoolDcAttr = GdiPoolCreate(sizeof(DC_ATTR), 'acdG');
ppiCurrent->pPoolBrushAttr = GdiPoolCreate(sizeof(BRUSH_ATTR), 'arbG');
ppiCurrent->pPoolRgnAttr = GdiPoolCreate(sizeof(RGN_ATTR), 'agrG');
ASSERT(ppiCurrent->pPoolDcAttr);
ASSERT(ppiCurrent->pPoolBrushAttr);
ASSERT(ppiCurrent->pPoolRgnAttr);
/* Add the process to the global list */
ppiCurrent->ppiNext = gppiList;
gppiList = ppiCurrent;
Status = CreateProcessInfo(Process);
}
else
{
/* Get the Win32 Process */
ppiCurrent = PsGetProcessWin32Process(Process);
ASSERT(ppiCurrent);
TRACE_CH(UserProcess, "Destroying ppi 0x%p\n", ppiCurrent);
ppiCurrent->W32PF_flags |= W32PF_TERMINATED;
if (ppiScrnSaver == ppiCurrent)
ppiScrnSaver = NULL;
if (ppiCurrent->InputIdleEvent)
{
EngFreeMem(ppiCurrent->InputIdleEvent);
ppiCurrent->InputIdleEvent = NULL;
}
IntCleanupMenus(Process, ppiCurrent);
IntCleanupCurIcons(Process, ppiCurrent);
GDI_CleanupForProcess(Process);
co_IntGraphicsCheck(FALSE);
/*
* Deregister logon application automatically
*/
if(LogonProcess == ppiCurrent)
{
LogonProcess = NULL;
}
/* Close the startup desktop */
if(ppiCurrent->rpdeskStartup)
ObDereferenceObject(ppiCurrent->rpdeskStartup);
if(ppiCurrent->hdeskStartup)
ZwClose(ppiCurrent->hdeskStartup);
/* Close the current window station */
UserSetProcessWindowStation(NULL);
/* Destroy GDI pools */
GdiPoolDestroy(ppiCurrent->pPoolDcAttr);
GdiPoolDestroy(ppiCurrent->pPoolBrushAttr);
GdiPoolDestroy(ppiCurrent->pPoolRgnAttr);
if (gppiInputProvider == ppiCurrent) gppiInputProvider = NULL;
pppi = &gppiList;
while (*pppi != NULL && *pppi != ppiCurrent)
pppi = &(*pppi)->ppiNext;
ASSERT(*pppi == ppiCurrent);
*pppi = ppiCurrent->ppiNext;
TRACE_CH(UserProcess,"Freeing ppi 0x%p\n", ppiCurrent);
#if DBG
if (DBG_IS_CHANNEL_ENABLED(ppiCurrent, DbgChUserObj, WARN_LEVEL))
{
DbgUserDumpHandleTable();
}
#endif
/* Free the PROCESSINFO */
PsSetProcessWin32Process(Process, NULL, ppiCurrent);
ExFreePoolWithTag(ppiCurrent, USERTAG_PROCESSINFO);
Status = DestroyProcessInfo(Process);
}
Status = STATUS_SUCCESS;
Leave:
UserLeave();
return Status;
}
@ -291,7 +331,8 @@ UserCreateThreadInfo(struct _ETHREAD *Thread)
PsSetThreadWin32Thread(Thread, ptiCurrent, NULL);
IntReferenceThreadInfo(ptiCurrent);
ptiCurrent->pEThread = Thread;
ptiCurrent->ppi = PsGetCurrentProcessWin32Process();
ptiCurrent->ppi = PsGetProcessWin32Process(Process);
IntReferenceProcessInfo(ptiCurrent->ppi);
pTeb->Win32ThreadInfo = ptiCurrent;
ptiCurrent->pClientInfo = (PCLIENTINFO)pTeb->Win32ClientInfo;
@ -317,6 +358,7 @@ UserCreateThreadInfo(struct _ETHREAD *Thread)
NULL, SynchronizationEvent, FALSE);
if (!NT_SUCCESS(Status))
{
ERR_CH(UserThread, "Event creation failed, Status 0x%08x.\n", Status);
goto error;
}
Status = ObReferenceObjectByHandle(ptiCurrent->hEventQueueClient, 0,
@ -324,6 +366,7 @@ UserCreateThreadInfo(struct _ETHREAD *Thread)
(PVOID*)&ptiCurrent->pEventQueueServer, NULL);
if (!NT_SUCCESS(Status))
{
ERR_CH(UserThread, "Failed referencing the event object, Status 0x%08x.\n", Status);
ZwClose(ptiCurrent->hEventQueueClient);
ptiCurrent->hEventQueueClient = NULL;
goto error;
@ -451,29 +494,23 @@ error:
Called from IntDereferenceThreadInfo.
*/
VOID
FASTCALL
UserDeleteW32Thread(PTHREADINFO pti)
{
if (!pti->RefCount)
{
TRACE_CH(UserThread,"UserDeleteW32Thread pti 0x%p\n",pti);
if (pti->hEventQueueClient != NULL)
ZwClose(pti->hEventQueueClient);
pti->hEventQueueClient = NULL;
PPROCESSINFO ppi = pti->ppi;
/* Free the message queue */
if (pti->MessageQueue)
{
MsqDestroyMessageQueue(pti);
}
TRACE_CH(UserThread,"UserDeleteW32Thread pti 0x%p\n",pti);
MsqCleanupThreadMsgs(pti);
/* Free the message queue */
if (pti->MessageQueue)
{
MsqDestroyMessageQueue(pti);
}
IntSetThreadDesktop(NULL, TRUE);
MsqCleanupThreadMsgs(pti);
PsSetThreadWin32Thread(pti->pEThread, NULL, pti);
ExFreePoolWithTag(pti, USERTAG_THREADINFO);
}
ExFreePoolWithTag(pti, USERTAG_THREADINFO);
IntDereferenceProcessInfo(ppi);
}
NTSTATUS
@ -541,18 +578,16 @@ UserDestroyThreadInfo(struct _ETHREAD *Thread)
}
DceFreeThreadDCE(ptiCurrent);
HOOK_DestroyThreadHooks(Thread);
EVENT_DestroyThreadEvents(Thread);
DestroyTimersForThread(ptiCurrent);
KeSetEvent(ptiCurrent->pEventQueueServer, IO_NO_INCREMENT, FALSE);
UnregisterThreadHotKeys(ptiCurrent);
/*
if (IsListEmpty(&ptiCurrent->WindowListHead))
if (!UserDestroyObjectsForOwner(gHandleTable, ptiCurrent))
{
ERR_CH(UserThread,"Thread Window List is Empty!\n");
DPRINT1("Failed to delete objects belonging to thread %p. This is VERY BAD!.\n", ptiCurrent);
ASSERT(FALSE);
return STATUS_UNSUCCESSFUL;
}
*/
co_DestroyThreadWindows(Thread);
if (ppiCurrent && ppiCurrent->ptiList == ptiCurrent && !ptiCurrent->ptiSibling &&
ppiCurrent->W32PF_flags & W32PF_CLASSESREGISTERED)
@ -614,6 +649,19 @@ UserDestroyThreadInfo(struct _ETHREAD *Thread)
*/
TRACE_CH(UserThread,"Freeing pti 0x%p\n", ptiCurrent);
IntSetThreadDesktop(NULL, TRUE);
if (ptiCurrent->hEventQueueClient != NULL)
{
ZwClose(ptiCurrent->hEventQueueClient);
ObDereferenceObject(ptiCurrent->pEventQueueServer);
}
ptiCurrent->hEventQueueClient = NULL;
/* The thread is dying */
PsSetThreadWin32Thread(ptiCurrent->pEThread, NULL, ptiCurrent);
ptiCurrent->pEThread = NULL;
/* Free the THREADINFO */
IntDereferenceThreadInfo(ptiCurrent);

View file

@ -176,7 +176,7 @@ PMENU FASTCALL VerifyMenu(PMENU pMenu)
return pMenu;
}
BOOL IntDestroyMenu( PMENU pMenu, BOOL bRecurse, BOOL RemoveFromProcess)
BOOL IntDestroyMenu( PMENU pMenu, BOOL bRecurse)
{
PMENU SubMenu;
@ -204,7 +204,7 @@ BOOL IntDestroyMenu( PMENU pMenu, BOOL bRecurse, BOOL RemoveFromProcess)
{
/* Release submenu since it was referenced when inserted */
IntReleaseMenuObject(SubMenu);
IntDestroyMenuObject(SubMenu, bRecurse, RemoveFromProcess);
IntDestroyMenuObject(SubMenu, bRecurse);
}
}
/* Free the Item */
@ -215,20 +215,22 @@ BOOL IntDestroyMenu( PMENU pMenu, BOOL bRecurse, BOOL RemoveFromProcess)
return TRUE;
}
/* Callback for the object manager */
BOOLEAN
UserDestroyMenuObject(PVOID Object)
{
return IntDestroyMenuObject(Object, TRUE);
}
BOOL FASTCALL
IntDestroyMenuObject(PMENU Menu, BOOL bRecurse, BOOL RemoveFromProcess)
IntDestroyMenuObject(PMENU Menu, BOOL bRecurse)
{
if(Menu)
{
PWND Window;
/* Remove all menu items */
IntDestroyMenu( Menu, bRecurse, RemoveFromProcess);
if (RemoveFromProcess)
{
RemoveEntryList(&Menu->ListEntry);
}
IntDestroyMenu( Menu, bRecurse);
if (PsGetCurrentProcessSessionId() == Menu->head.rpdesk->rpwinstaParent->dwSessionId)
{
@ -361,7 +363,7 @@ IntRemoveMenuItem( PMENU pMenu, UINT nPos, UINT wFlags, BOOL bRecurse )
FreeMenuText(pMenu,item);
if (bRecurse && item->spSubMenu)
{
IntDestroyMenuObject(item->spSubMenu, bRecurse, TRUE);
IntDestroyMenuObject(item->spSubMenu, bRecurse);
}
////// Use cAlloced with inc's of 8's....
if (--pMenu->cItems == 0)
@ -477,14 +479,17 @@ IntInsertMenuItem(
}
PMENU FASTCALL
IntCreateMenu(PHANDLE Handle, BOOL IsMenuBar)
IntCreateMenu(
_Out_ PHANDLE Handle,
_In_ BOOL IsMenuBar,
_In_ PDESKTOP Desktop,
_In_ PPROCESSINFO ppi)
{
PMENU Menu;
PPROCESSINFO CurrentWin32Process;
Menu = (PMENU)UserCreateObject( gHandleTable,
NULL,
NULL,
Desktop,
ppi->ptiList,
Handle,
TYPE_MENU,
sizeof(MENU));
@ -512,10 +517,6 @@ IntCreateMenu(PHANDLE Handle, BOOL IsMenuBar)
Menu->hWnd = NULL;
Menu->TimeToHide = FALSE;
/* Insert menu item into process menu handle list */
CurrentWin32Process = PsGetCurrentProcessWin32Process();
InsertTailList(&CurrentWin32Process->MenuListHead, &Menu->ListEntry);
return Menu;
}
@ -572,19 +573,19 @@ IntCloneMenuItems(PMENU Destination, PMENU Source)
PMENU FASTCALL
IntCloneMenu(PMENU Source)
{
PPROCESSINFO CurrentWin32Process;
HANDLE hMenu;
PMENU Menu;
if(!Source)
return NULL;
/* A menu is valid process wide. We can pass to the object manager any thread ptr */
Menu = (PMENU)UserCreateObject( gHandleTable,
NULL,
NULL,
&hMenu,
TYPE_MENU,
sizeof(MENU));
Source->head.rpdesk,
((PPROCESSINFO)Source->head.hTaskWow)->ptiList,
&hMenu,
TYPE_MENU,
sizeof(MENU));
if(!Menu)
return NULL;
@ -606,10 +607,6 @@ IntCloneMenu(PMENU Source)
Menu->hWnd = NULL;
Menu->TimeToHide = FALSE;
/* Insert menu item into process menu handle list */
CurrentWin32Process = PsGetCurrentProcessWin32Process();
InsertTailList(&CurrentWin32Process->MenuListHead, &Menu->ListEntry);
IntCloneMenuItems(Menu, Source);
return Menu;
@ -870,7 +867,10 @@ IntSetMenuItemInfo(PMENU MenuObject, PITEM MenuItem, PROSMENUITEMINFO lpmii, PUN
{
HANDLE hMenu;
ERR("Pop Up Menu Double Trouble!\n");
SubMenuObject = IntCreateMenu(&hMenu, FALSE); // It will be marked.
SubMenuObject = IntCreateMenu(&hMenu,
FALSE,
MenuObject->head.rpdesk,
(PPROCESSINFO)MenuObject->head.hTaskWow); // It will be marked.
if (!SubMenuObject) return FALSE;
IntReleaseMenuObject(SubMenuObject); // This will be referenced again after insertion.
circref = TRUE;
@ -878,7 +878,7 @@ IntSetMenuItemInfo(PMENU MenuObject, PITEM MenuItem, PROSMENUITEMINFO lpmii, PUN
if ( MENU_depth( SubMenuObject, 0) > MAXMENUDEPTH )
{
ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
if (circref) IntDestroyMenuObject(SubMenuObject, FALSE, TRUE);
if (circref) IntDestroyMenuObject(SubMenuObject, FALSE);
return FALSE;
}
/* Make sure the submenu is marked as a popup menu */
@ -1135,36 +1135,6 @@ co_IntTrackPopupMenu(PMENU Menu, PWND Window,
return FALSE;
}
/*!
* Internal function. Called when the process is destroyed to free the remaining menu handles.
*/
BOOL FASTCALL
IntCleanupMenus(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
{
PEPROCESS CurrentProcess;
PMENU MenuObject;
CurrentProcess = PsGetCurrentProcess();
if (CurrentProcess != Process)
{
KeAttachProcess(&Process->Pcb);
}
while (!IsListEmpty(&Win32Process->MenuListHead))
{
MenuObject = CONTAINING_RECORD(Win32Process->MenuListHead.Flink, MENU, ListEntry);
TRACE("Menus are stuck on the process list!\n");
IntDestroyMenuObject(MenuObject, FALSE, TRUE);
}
if (CurrentProcess != Process)
{
KeDetachProcess();
}
return TRUE;
}
BOOLEAN APIENTRY
intGetTitleBarInfo(PWND pWindowObject, PTITLEBARINFO bti)
{
@ -1415,7 +1385,7 @@ UINT FASTCALL IntFindSubMenu(HMENU *hMenu, HMENU hSubTarget )
}
HMENU FASTCALL UserCreateMenu(BOOL PopupMenu)
HMENU FASTCALL UserCreateMenu(PDESKTOP Desktop, BOOL PopupMenu)
{
PWINSTATION_OBJECT WinStaObject;
HANDLE Handle;
@ -1441,7 +1411,7 @@ HMENU FASTCALL UserCreateMenu(BOOL PopupMenu)
SetLastNtError(Status);
return (HMENU)0;
}
Menu = IntCreateMenu(&Handle, !PopupMenu);
Menu = IntCreateMenu(&Handle, !PopupMenu, Desktop, GetW32ProcessInfo());
if (Menu && Menu->head.rpdesk->rpwinstaParent != WinStaObject)
{
ERR("Desktop Window Station does not match Process one!\n");
@ -1450,7 +1420,7 @@ HMENU FASTCALL UserCreateMenu(BOOL PopupMenu)
}
else
{
Menu = IntCreateMenu(&Handle, !PopupMenu);
Menu = IntCreateMenu(&Handle, !PopupMenu, GetW32ThreadInfo()->rpdesk, GetW32ProcessInfo());
}
if (Menu) UserDereferenceObject(Menu);
@ -1678,7 +1648,7 @@ PMENU FASTCALL MENU_GetSystemMenu(PWND Window, PMENU Popup)
ROSMENUITEMINFO ItemInfo = {0};
UNICODE_STRING MenuName;
hSysMenu = UserCreateMenu(FALSE);
hSysMenu = UserCreateMenu(Window->head.rpdesk, FALSE);
if (NULL == hSysMenu)
{
return NULL;
@ -1742,7 +1712,7 @@ PMENU FASTCALL MENU_GetSystemMenu(PWND Window, PMENU Popup)
IntReleaseMenuObject(NewMenu);
UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
IntDestroyMenuObject(Menu, FALSE, TRUE);
IntDestroyMenuObject(Menu, FALSE);
}
else
{
@ -1782,7 +1752,7 @@ IntGetSystemMenu(PWND Window, BOOL bRevert)
Menu = UserGetMenuObject(Window->SystemMenu);
if (Menu && !(Menu->fFlags & MNF_SYSDESKMN))
{
IntDestroyMenuObject(Menu, TRUE, TRUE);
IntDestroyMenuObject(Menu, TRUE);
Window->SystemMenu = NULL;
}
}
@ -1826,7 +1796,7 @@ IntSetSystemMenu(PWND Window, PMENU Menu)
if (OldMenu)
{
OldMenu->fFlags &= ~MNF_SYSMENU;
IntDestroyMenuObject(OldMenu, TRUE, TRUE);
IntDestroyMenuObject(OldMenu, TRUE);
}
}
@ -2091,7 +2061,7 @@ BOOL FASTCALL UserDestroyMenu(HMENU hMenu)
EngSetLastError(ERROR_ACCESS_DENIED);
return FALSE;
}
return IntDestroyMenuObject(Menu, FALSE, TRUE);
return IntDestroyMenuObject(Menu, FALSE);
}
/*
@ -2116,7 +2086,7 @@ NtUserDestroyMenu(
EngSetLastError(ERROR_ACCESS_DENIED);
RETURN( FALSE);
}
RETURN( IntDestroyMenuObject(Menu, TRUE, TRUE));
RETURN( IntDestroyMenuObject(Menu, TRUE));
CLEANUP:
TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_);

View file

@ -23,8 +23,11 @@ IntGetMenuObject(HMENU hMenu);
#define IntReleaseMenuObject(MenuObj) \
UserDereferenceObject(MenuObj)
BOOLEAN
UserDestroyMenuObject(PVOID Object);
BOOL FASTCALL
IntDestroyMenuObject(PMENU MenuObject, BOOL bRecurse, BOOL RemoveFromProcess);
IntDestroyMenuObject(PMENU MenuObject, BOOL bRecurse);
PMENU FASTCALL
IntCloneMenu(PMENU Source);

View file

@ -12,6 +12,233 @@ DBG_DEFAULT_CHANNEL(UserObj);
//int usedHandles=0;
PUSER_HANDLE_TABLE gHandleTable = NULL;
/* Forward declarations */
static PVOID AllocThreadObject(
_In_ PDESKTOP pDesk,
_In_ PTHREADINFO pti,
_In_ SIZE_T Size,
_Out_ PVOID* HandleOwner)
{
PTHROBJHEAD ObjHead;
UNREFERENCED_PARAMETER(pDesk);
ASSERT(Size > sizeof(*ObjHead));
ASSERT(pti != NULL);
ObjHead = UserHeapAlloc(Size);
if (!ObjHead)
return NULL;
RtlZeroMemory(ObjHead, Size);
ObjHead->pti = pti;
IntReferenceThreadInfo(pti);
*HandleOwner = pti;
/* It's a thread object, but it still count as one for the process */
pti->ppi->UserHandleCount++;
return ObjHead;
}
static void FreeThreadObject(
_In_ PVOID Object)
{
PTHROBJHEAD ObjHead = (PTHROBJHEAD)Object;
PTHREADINFO pti = ObjHead->pti;
UserHeapFree(ObjHead);
pti->ppi->UserHandleCount--;
IntDereferenceThreadInfo(pti);
}
static PVOID AllocDeskThreadObject(
_In_ PDESKTOP pDesk,
_In_ PTHREADINFO pti,
_In_ SIZE_T Size,
_Out_ PVOID* HandleOwner)
{
PTHRDESKHEAD ObjHead;
ASSERT(Size > sizeof(*ObjHead));
ASSERT(pti != NULL);
if (!pDesk)
pDesk = pti->rpdesk;
ObjHead = DesktopHeapAlloc(pDesk, Size);
if (!ObjHead)
return NULL;
RtlZeroMemory(ObjHead, Size);
ObjHead->pSelf = ObjHead;
ObjHead->rpdesk = pDesk;
ObjHead->pti = pti;
IntReferenceThreadInfo(pti);
*HandleOwner = pti;
/* It's a thread object, but it still count as one for the process */
pti->ppi->UserHandleCount++;
return ObjHead;
}
static void FreeDeskThreadObject(
_In_ PVOID Object)
{
PTHRDESKHEAD ObjHead = (PTHRDESKHEAD)Object;
PDESKTOP pDesk = ObjHead->rpdesk;
PTHREADINFO pti = ObjHead->pti;
DesktopHeapFree(pDesk, Object);
pti->ppi->UserHandleCount--;
IntDereferenceThreadInfo(pti);
}
static PVOID AllocDeskProcObject(
_In_ PDESKTOP pDesk,
_In_ PTHREADINFO pti,
_In_ SIZE_T Size,
_Out_ PVOID* HandleOwner)
{
PPROCDESKHEAD ObjHead;
PPROCESSINFO ppi;
ASSERT(Size > sizeof(*ObjHead));
ASSERT(pDesk != NULL);
ASSERT(pti != NULL);
ObjHead = DesktopHeapAlloc(pDesk, Size);
if (!ObjHead)
return NULL;
RtlZeroMemory(ObjHead, Size);
ppi = pti->ppi;
ObjHead->pSelf = ObjHead;
ObjHead->rpdesk = pDesk;
ObjHead->hTaskWow = (DWORD_PTR)ppi;
ppi->UserHandleCount++;
IntReferenceProcessInfo(ppi);
*HandleOwner = ppi;
return ObjHead;
}
static void FreeDeskProcObject(
_In_ PVOID Object)
{
PPROCDESKHEAD ObjHead = (PPROCDESKHEAD)Object;
PDESKTOP pDesk = ObjHead->rpdesk;
PPROCESSINFO ppi = (PPROCESSINFO)ObjHead->hTaskWow;
ppi->UserHandleCount--;
IntDereferenceProcessInfo(ppi);
DesktopHeapFree(pDesk, Object);
}
static PVOID AllocProcMarkObject(
_In_ PDESKTOP pDesk,
_In_ PTHREADINFO pti,
_In_ SIZE_T Size,
_Out_ PVOID* HandleOwner)
{
PPROCMARKHEAD ObjHead;
PPROCESSINFO ppi = pti->ppi;
UNREFERENCED_PARAMETER(pDesk);
ASSERT(Size > sizeof(*ObjHead));
ObjHead = UserHeapAlloc(Size);
if (!ObjHead)
return NULL;
RtlZeroMemory(ObjHead, Size);
ObjHead->ppi = ppi;
IntReferenceProcessInfo(ppi);
*HandleOwner = ppi;
ppi->UserHandleCount++;
return ObjHead;
}
static void FreeProcMarkObject(
_In_ PVOID Object)
{
PPROCESSINFO ppi = ((PPROCMARKHEAD)Object)->ppi;
UserHeapFree(Object);
ppi->UserHandleCount--;
IntDereferenceProcessInfo(ppi);
}
static PVOID AllocSysObject(
_In_ PDESKTOP pDesk,
_In_ PTHREADINFO pti,
_In_ SIZE_T Size,
_Out_ PVOID* ObjectOwner)
{
PVOID Object;
UNREFERENCED_PARAMETER(pDesk);
UNREFERENCED_PARAMETER(pti);
ASSERT(Size > sizeof(HEAD));
Object = UserHeapAlloc(Size);
if (!Object)
return NULL;
*ObjectOwner = NULL;
RtlZeroMemory(Object, Size);
return Object;
}
static void FreeSysObject(
_In_ PVOID Object)
{
UserHeapFree(Object);
}
static const struct
{
PVOID (*ObjectAlloc)(PDESKTOP, PTHREADINFO, SIZE_T, PVOID*);
BOOLEAN (*ObjectDestroy)(PVOID);
void (*ObjectFree)(PVOID);
} ObjectCallbacks[TYPE_CTYPES] =
{
{ NULL, NULL, NULL }, /* TYPE_FREE */
{ AllocDeskThreadObject, co_UserDestroyWindow, FreeDeskThreadObject }, /* TYPE_WINDOW */
{ AllocDeskProcObject, UserDestroyMenuObject, FreeDeskProcObject }, /* TYPE_MENU */
{ AllocProcMarkObject, /*UserCursorCleanup*/NULL, FreeProcMarkObject }, /* TYPE_CURSOR */
{ AllocSysObject, /*UserSetWindowPosCleanup*/NULL, FreeSysObject }, /* TYPE_SETWINDOWPOS */
{ AllocDeskThreadObject, IntRemoveHook, FreeDeskThreadObject }, /* TYPE_HOOK */
{ AllocSysObject, /*UserClipDataCleanup*/NULL,FreeSysObject }, /* TYPE_CLIPDATA */
{ AllocDeskProcObject, DestroyCallProc, FreeDeskProcObject }, /* TYPE_CALLPROC */
{ AllocProcMarkObject, UserDestroyAccelTable, FreeProcMarkObject }, /* TYPE_ACCELTABLE */
{ NULL, NULL, NULL }, /* TYPE_DDEACCESS */
{ NULL, NULL, NULL }, /* TYPE_DDECONV */
{ NULL, NULL, NULL }, /* TYPE_DDEXACT */
{ AllocSysObject, /*UserMonitorCleanup*/NULL, FreeSysObject }, /* TYPE_MONITOR */
{ AllocSysObject, /*UserKbdLayoutCleanup*/NULL,FreeSysObject }, /* TYPE_KBDLAYOUT */
{ AllocSysObject, /*UserKbdFileCleanup*/NULL, FreeSysObject }, /* TYPE_KBDFILE */
{ AllocThreadObject, IntRemoveEvent, FreeThreadObject }, /* TYPE_WINEVENTHOOK */
{ AllocSysObject, /*UserTimerCleanup*/NULL, FreeSysObject }, /* TYPE_TIMER */
{ NULL, NULL, NULL }, /* TYPE_INPUTCONTEXT */
{ NULL, NULL, NULL }, /* TYPE_HIDDATA */
{ NULL, NULL, NULL }, /* TYPE_DEVICEINFO */
{ NULL, NULL, NULL }, /* TYPE_TOUCHINPUTINFO */
{ NULL, NULL, NULL }, /* TYPE_GESTUREINFOOBJ */
};
#if DBG
void DbgUserDumpHandleTable()
@ -27,7 +254,7 @@ void DbgUserDumpHandleTable()
memset(HandleCounts, 0, sizeof(HandleCounts));
/* First of all count the number of handles per tpe */
/* First of all count the number of handles per type */
ppiList = gppiList;
while (ppiList)
{
@ -96,7 +323,6 @@ __inline static HANDLE entry_to_handle(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY
__inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
{
PUSER_HANDLE_ENTRY entry;
PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
TRACE("handles used %lu\n", gpsi->cHandleEntries);
if (ht->freelist)
@ -105,7 +331,6 @@ __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
ht->freelist = entry->ptr;
gpsi->cHandleEntries++;
ppi->UserHandleCount++;
return entry;
}
@ -137,7 +362,6 @@ __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
entry->generation = 1;
gpsi->cHandleEntries++;
ppi->UserHandleCount++;
return entry;
}
@ -151,13 +375,33 @@ VOID UserInitHandleTable(PUSER_HANDLE_TABLE ht, PVOID mem, ULONG bytes)
ht->allocated_handles = bytes / sizeof(USER_HANDLE_ENTRY);
}
__inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY entry)
{
PPROCESSINFO ppi = PsGetCurrentProcessWin32Process();
void *ret;
#if DBG
ppi->DbgHandleCount[entry->type]--;
{
PPROCESSINFO ppi;
switch (entry->type)
{
case TYPE_WINDOW:
case TYPE_HOOK:
case TYPE_WINEVENTHOOK:
ppi = ((PTHREADINFO)entry->pi)->ppi;
break;
case TYPE_MENU:
case TYPE_CURSOR:
case TYPE_CALLPROC:
case TYPE_ACCELTABLE:
ppi = entry->pi;
break;
default:
ppi = NULL;
}
if (ppi)
ppi->DbgHandleCount[entry->type]--;
}
#endif
ret = entry->ptr;
@ -168,46 +412,16 @@ __inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY
ht->freelist = entry;
gpsi->cHandleEntries--;
ppi->UserHandleCount--;
return ret;
}
static __inline PVOID
UserHandleOwnerByType(HANDLE_TYPE type)
{
PVOID pi;
switch (type)
{
case TYPE_WINDOW:
case TYPE_INPUTCONTEXT:
pi = GetW32ThreadInfo();
break;
case TYPE_MENU:
case TYPE_CURSOR:
case TYPE_HOOK:
case TYPE_CALLPROC:
case TYPE_ACCELTABLE:
case TYPE_SETWINDOWPOS:
pi = GetW32ProcessInfo();
break;
case TYPE_MONITOR:
pi = NULL; /* System */
break;
default:
pi = NULL;
break;
}
return pi;
}
/* allocate a user handle for a given object */
HANDLE UserAllocHandle(PUSER_HANDLE_TABLE ht, PVOID object, HANDLE_TYPE type )
HANDLE UserAllocHandle(
_Inout_ PUSER_HANDLE_TABLE ht,
_In_ PVOID object,
_In_ HANDLE_TYPE type,
_In_ PVOID HandleOwner)
{
PUSER_HANDLE_ENTRY entry = alloc_user_entry(ht);
if (!entry)
@ -215,7 +429,7 @@ HANDLE UserAllocHandle(PUSER_HANDLE_TABLE ht, PVOID object, HANDLE_TYPE type )
entry->ptr = object;
entry->type = type;
entry->flags = 0;
entry->pi = UserHandleOwnerByType(type);
entry->pi = HandleOwner;
if (++entry->generation >= 0xffff)
entry->generation = 1;
@ -322,82 +536,41 @@ UserCreateObject( PUSER_HANDLE_TABLE ht,
{
HANDLE hi;
PVOID Object;
PPROCESSINFO ppi;
BOOL dt;
PDESKTOP rpdesk = pDesktop;
PVOID ObjectOwner;
/* We could get the desktop for the new object from the pti however this is
* not always the case for example when creating a new desktop window for
* the desktop thread*/
/* Some sanity checks. Other checks will be made in the allocator */
ASSERT(type < TYPE_CTYPES);
ASSERT(type != TYPE_FREE);
ASSERT(ht != NULL);
if (!pti) pti = GetW32ThreadInfo();
if (!pDesktop) rpdesk = pti->rpdesk;
ppi = pti->ppi;
switch (type)
/* Allocate the object */
ASSERT(ObjectCallbacks[type].ObjectAlloc != NULL);
Object = ObjectCallbacks[type].ObjectAlloc(pDesktop, pti, size, &ObjectOwner);
if (!Object)
{
case TYPE_WINDOW:
case TYPE_MENU:
case TYPE_HOOK:
case TYPE_CALLPROC:
case TYPE_INPUTCONTEXT:
Object = DesktopHeapAlloc(rpdesk, size);
dt = TRUE;
break;
default:
Object = UserHeapAlloc(size);
dt = FALSE;
break;
ERR("User object allocation failed. Out of memory!\n");
return NULL;
}
if (!Object)
return NULL;
hi = UserAllocHandle(ht, Object, type );
if (!hi)
hi = UserAllocHandle(ht, Object, type, ObjectOwner);
if (hi == NULL)
{
if (dt)
DesktopHeapFree(rpdesk, Object);
else
UserHeapFree(Object);
return NULL;
ERR("Out of user handles!\n");
ObjectCallbacks[type].ObjectFree(Object);
return NULL;
}
#if DBG
ppi->DbgHandleCount[type]++;
if (pti)
pti->ppi->DbgHandleCount[type]++;
#endif
RtlZeroMemory(Object, size);
switch (type)
{
case TYPE_WINDOW:
case TYPE_HOOK:
case TYPE_INPUTCONTEXT:
((PTHRDESKHEAD)Object)->rpdesk = rpdesk;
((PTHRDESKHEAD)Object)->pSelf = Object;
case TYPE_WINEVENTHOOK:
((PTHROBJHEAD)Object)->pti = pti;
break;
case TYPE_MENU:
case TYPE_CALLPROC:
((PPROCDESKHEAD)Object)->rpdesk = rpdesk;
((PPROCDESKHEAD)Object)->pSelf = Object;
break;
case TYPE_CURSOR:
((PPROCMARKHEAD)Object)->ppi = ppi;
break;
default:
break;
}
/* Now set default headers. */
/* Give this object its identity. */
((PHEAD)Object)->h = hi;
((PHEAD)Object)->cLockObj = 2; // We need this, because we create 2 refs: handle and pointer!
/* The caller will get a locked object.
* Note: with the reference from the handle, that makes two */
UserReferenceObject(Object);
if (h)
*h = hi;
@ -407,46 +580,43 @@ UserCreateObject( PUSER_HANDLE_TABLE ht,
BOOL
FASTCALL
UserDereferenceObject(PVOID object)
UserDereferenceObject(PVOID Object)
{
PUSER_HANDLE_ENTRY entry;
HANDLE_TYPE type;
PHEAD ObjHead = (PHEAD)Object;
ASSERT(((PHEAD)object)->cLockObj >= 1);
ASSERT(ObjHead->cLockObj >= 1);
if ((INT)--((PHEAD)object)->cLockObj <= 0)
{
entry = handle_to_entry(gHandleTable, ((PHEAD)object)->h );
if (--ObjHead->cLockObj == 0)
{
PUSER_HANDLE_ENTRY entry;
HANDLE_TYPE type;
if (!entry)
{
ERR("Warning! Dereference Object without ENTRY! Obj -> %p\n", object);
return FALSE;
}
TRACE("Warning! Dereference to zero! Obj -> %p\n", object);
entry = handle_to_entry(gHandleTable, ObjHead->h);
((PHEAD)object)->cLockObj = 0;
ASSERT(entry != NULL);
/* The entry should be marked as in deletion */
ASSERT(entry->flags & HANDLEENTRY_INDESTROY);
type = entry->type;
ASSERT(type != TYPE_FREE);
ASSERT(type < TYPE_CTYPES);
/* We can now get rid of everything */
free_user_entry(gHandleTable, entry );
#if 0
/* Call the object destructor */
ASSERT(ObjectCallbacks[type].ObjectCleanup != NULL);
ObjectCallbacks[type].ObjectCleanup(Object);
#endif
/* And free it */
ASSERT(ObjectCallbacks[type].ObjectFree != NULL);
ObjectCallbacks[type].ObjectFree(Object);
if (!(entry->flags & HANDLEENTRY_INDESTROY))
return TRUE;
type = entry->type;
free_user_entry(gHandleTable, entry );
switch (type)
{
case TYPE_WINDOW:
case TYPE_MENU:
case TYPE_HOOK:
case TYPE_CALLPROC:
case TYPE_INPUTCONTEXT:
return DesktopHeapFree(((PTHRDESKHEAD)object)->rpdesk, object);
default:
return UserHeapFree(object);
}
}
return FALSE;
}
return FALSE;
}
BOOL
@ -522,10 +692,10 @@ UserSetObjectOwner(PVOID obj, HANDLE_TYPE type, PVOID owner)
{
PUSER_HANDLE_ENTRY entry = handle_to_entry(gHandleTable, ((PHEAD)obj)->h );
PPROCESSINFO ppi, oldppi;
/* This must be called with a valid object */
ASSERT(entry);
/* For now, only supported for CursorIcon object */
switch(type)
{
@ -541,59 +711,55 @@ UserSetObjectOwner(PVOID obj, HANDLE_TYPE type, PVOID owner)
}
oldppi->UserHandleCount--;
IntDereferenceProcessInfo(oldppi);
ppi->UserHandleCount++;
IntReferenceProcessInfo(ppi);
#if DBG
oldppi->DbgHandleCount[type]--;
ppi->DbgHandleCount[type]++;
#endif
}
HANDLE FASTCALL ValidateHandleNoErr(HANDLE handle, HANDLE_TYPE type)
BOOLEAN
UserDestroyObjectsForOwner(PUSER_HANDLE_TABLE Table, PVOID Owner)
{
if (handle) return (PWND)UserGetObjectNoErr(gHandleTable, handle, type);
return NULL;
}
int i;
PUSER_HANDLE_ENTRY Entry;
BOOLEAN Ret = TRUE;
PVOID FASTCALL ValidateHandle(HANDLE handle, HANDLE_TYPE type)
{
PVOID pObj;
DWORD dwError = 0;
if (handle)
{
pObj = UserGetObjectNoErr(gHandleTable, handle, type);
if (!pObj)
{
switch (type)
{
case TYPE_WINDOW:
dwError = ERROR_INVALID_WINDOW_HANDLE;
break;
case TYPE_MENU:
dwError = ERROR_INVALID_MENU_HANDLE;
break;
case TYPE_CURSOR:
dwError = ERROR_INVALID_CURSOR_HANDLE;
break;
case TYPE_SETWINDOWPOS:
dwError = ERROR_INVALID_DWP_HANDLE;
break;
case TYPE_HOOK:
dwError = ERROR_INVALID_HOOK_HANDLE;
break;
case TYPE_ACCELTABLE:
dwError = ERROR_INVALID_ACCEL_HANDLE;
break;
default:
dwError = ERROR_INVALID_HANDLE;
break;
}
EngSetLastError(dwError);
return NULL;
}
return pObj;
}
return NULL;
/* Sweep the whole handle table */
for (i = 0; i < Table->allocated_handles; i++)
{
Entry = &Table->handles[i];
if (Entry->pi != Owner)
continue;
/* Do not destroy if it's already been done */
if (Entry->flags & HANDLEENTRY_INDESTROY)
continue;
/* Spcial case for cursors until cursoricon_new is there */
if (Entry->type == TYPE_CURSOR)
{
UserReferenceObject(Entry->ptr);
if (!IntDestroyCurIconObject(Entry->ptr, Owner))
{
Ret = FALSE;
}
continue;
}
/* Call destructor */
if (!ObjectCallbacks[Entry->type].ObjectDestroy(Entry->ptr))
{
ERR("Failed destructing object %p, type %u.\n", Entry->ptr, Entry->type);
/* Don't return immediately, we must continue destroying the other objects */
Ret = FALSE;
}
}
return Ret;
}
/*

View file

@ -18,8 +18,8 @@ BOOL FASTCALL UserCreateHandleTable(VOID);
BOOL FASTCALL UserObjectInDestroy(HANDLE);
void DbgUserDumpHandleTable();
VOID FASTCALL UserSetObjectOwner(PVOID obj, HANDLE_TYPE type, PVOID owner);
HANDLE FASTCALL ValidateHandleNoErr(HANDLE handle, HANDLE_TYPE type);
PVOID FASTCALL ValidateHandle(HANDLE handle, HANDLE_TYPE type);
BOOLEAN UserDestroyObjectsForOwner(PUSER_HANDLE_TABLE Table, PVOID Owner);
static __inline VOID
UserRefObjectCo(PVOID obj, PUSER_REFERENCE_ENTRY UserReferenceEntry)

View file

@ -73,11 +73,11 @@ NtUserCallNoParam(DWORD Routine)
switch(Routine)
{
case NOPARAM_ROUTINE_CREATEMENU:
Result = (DWORD_PTR)UserCreateMenu(FALSE);
Result = (DWORD_PTR)UserCreateMenu(GetW32ThreadInfo()->rpdesk, FALSE);
break;
case NOPARAM_ROUTINE_CREATEMENUPOPUP:
Result = (DWORD_PTR)UserCreateMenu(TRUE);
Result = (DWORD_PTR)UserCreateMenu(GetW32ThreadInfo()->rpdesk, TRUE);
break;
case NOPARAM_ROUTINE_DESTROY_CARET:

View file

@ -2,7 +2,7 @@
FORCEINLINE PMENU UserGetMenuObject(HMENU hMenu)
{
return ValidateHandle(hMenu, TYPE_MENU);
return UserGetObject(gHandleTable, hMenu, TYPE_MENU);
}
#define ASSERT_REFS_CO(_obj_) \
@ -106,12 +106,12 @@ PWND FASTCALL UserGetWindowObject(HWND hWnd);
VOID FASTCALL co_DestroyThreadWindows(struct _ETHREAD *Thread);
HWND FASTCALL UserGetShellWindow(VOID);
HDC FASTCALL UserGetDCEx(PWND Window OPTIONAL, HANDLE ClipRegion, ULONG Flags);
BOOLEAN FASTCALL co_UserDestroyWindow(PWND Wnd);
BOOLEAN co_UserDestroyWindow(PVOID Object);
PWND FASTCALL UserGetAncestor(PWND Wnd, UINT Type);
/*************** MENU.C ***************/
HMENU FASTCALL UserCreateMenu(BOOL PopupMenu);
HMENU FASTCALL UserCreateMenu(PDESKTOP Desktop, BOOL PopupMenu);
BOOL FASTCALL UserSetMenuDefaultItem(PMENU Menu, UINT uItem, UINT fByPos);
BOOL FASTCALL UserDestroyMenu(HMENU hMenu);

View file

@ -158,17 +158,31 @@ typedef struct _THREADINFO
#define IntReferenceThreadInfo(pti) \
InterlockedIncrement(&(pti)->RefCount)
VOID FASTCALL UserDeleteW32Thread(PTHREADINFO);
VOID UserDeleteW32Thread(PTHREADINFO);
#define IntDereferenceThreadInfo(pti) \
do { \
if(InterlockedDecrement(&(pti)->RefCount) == 0) \
{ \
ASSERT(pti->TIF_flags &= (TIF_INCLEANUP|TIF_DONTATTACHQUEUE) == (TIF_INCLEANUP|TIF_DONTATTACHQUEUE)); \
ASSERT(((pti)->TIF_flags & (TIF_INCLEANUP|TIF_DONTATTACHQUEUE)) == (TIF_INCLEANUP|TIF_DONTATTACHQUEUE)); \
UserDeleteW32Thread(pti); \
} \
} while(0)
#define IntReferenceProcessInfo(ppi) \
InterlockedIncrement((volatile LONG*)(&(ppi)->RefCount))
VOID UserDeleteW32Process(PPROCESSINFO);
#define IntDereferenceProcessInfo(ppi) \
do { \
if(InterlockedDecrement((volatile LONG*)(&(ppi)->RefCount)) == 0) \
{ \
ASSERT(((ppi)->W32PF_flags & W32PF_TERMINATED) != 0); \
UserDeleteW32Process(ppi); \
} \
} while(0)
typedef struct _W32HEAP_USER_MAPPING
{
@ -242,7 +256,6 @@ typedef struct _PROCESSINFO
DWORD dwLayout;
DWORD dwRegisteredClasses;
/* ReactOS */
LIST_ENTRY MenuListHead;
FAST_MUTEX PrivateFontListLock;
LIST_ENTRY PrivateFontListHead;
FAST_MUTEX DriverObjListLock;

View file

@ -587,14 +587,14 @@ static LRESULT co_UserFreeWindow(PWND Window,
Window->IDMenu &&
(Menu = UserGetMenuObject((HMENU)Window->IDMenu)))
{
IntDestroyMenuObject(Menu, TRUE, TRUE);
IntDestroyMenuObject(Menu, TRUE);
Window->IDMenu = 0;
}
if(Window->SystemMenu
&& (Menu = UserGetMenuObject(Window->SystemMenu)))
{
IntDestroyMenuObject(Menu, TRUE, TRUE);
IntDestroyMenuObject(Menu, TRUE);
Window->SystemMenu = (HMENU)0;
}
@ -861,40 +861,6 @@ IntSetMenu(
/* INTERNAL ******************************************************************/
VOID FASTCALL
co_DestroyThreadWindows(struct _ETHREAD *Thread)
{
PTHREADINFO WThread;
PLIST_ENTRY Current;
PWND Wnd;
USER_REFERENCE_ENTRY Ref;
WThread = (PTHREADINFO)Thread->Tcb.Win32Thread;
while (!IsListEmpty(&WThread->WindowListHead))
{
Current = WThread->WindowListHead.Flink;
Wnd = CONTAINING_RECORD(Current, WND, ThreadListEntry);
TRACE("thread cleanup: while destroy wnds, wnd=%p\n", Wnd);
/* Window removes itself from the list */
/*
* FIXME: It is critical that the window removes itself! If now, we will loop
* here forever...
*/
//ASSERT(co_UserDestroyWindow(Wnd));
UserRefObjectCo(Wnd, &Ref); // FIXME: Temp HACK??
if (!co_UserDestroyWindow(Wnd))
{
ERR("Unable to destroy window %p at thread cleanup... This is _VERY_ bad!\n", Wnd);
}
UserDerefObjectCo(Wnd); // FIXME: Temp HACK??
}
}
BOOL FASTCALL
IntIsChildWindow(PWND Parent, PWND BaseWindow)
{
@ -1788,7 +1754,7 @@ PWND FASTCALL IntCreateWindow(CREATESTRUCTW* Cs,
if (Class->atomClassName == gpsi->atomSysClass[ICLS_EDIT])
{
PCALLPROCDATA CallProc;
CallProc = CreateCallProc(NULL, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
CallProc = CreateCallProc(pWnd->head.rpdesk, pWnd->lpfnWndProc, pWnd->Unicode , pWnd->head.pti->ppi);
if (!CallProc)
{
@ -2431,9 +2397,10 @@ NtUserCreateWindowEx(
if ( (dwStyle & (WS_POPUP|WS_CHILD)) != WS_CHILD)
{
/* check hMenu is valid handle */
if (hMenu && !ValidateHandle(hMenu, TYPE_MENU))
if (hMenu && !UserGetMenuObject(hMenu))
{
/* error is set in ValidateHandle */
ERR("NtUserCreateWindowEx: Got an invalid menu handle!\n");
EngSetLastError(ERROR_INVALID_MENU_HANDLE);
return NULL;
}
}
@ -2520,12 +2487,13 @@ cleanup:
}
BOOLEAN FASTCALL co_UserDestroyWindow(PWND Window)
BOOLEAN co_UserDestroyWindow(PVOID Object)
{
HWND hWnd;
PWND pwndTemp;
PTHREADINFO ti;
MSG msg;
PWND Window = Object;
ASSERT_REFS_CO(Window); // FIXME: Temp HACK?

View file

@ -315,17 +315,17 @@ static const BOOL g_ObjectHeapTypeShared[TYPE_CTYPES] =
TRUE, /* TYPE_CURSOR */
TRUE, /* TYPE_SETWINDOWPOS */
FALSE, /* TYPE_HOOK */
FALSE, /* TYPE_CLIPDATA */
TRUE, /* TYPE_CLIPDATA */
FALSE, /* TYPE_CALLPROC */
TRUE, /* TYPE_ACCELTABLE */
FALSE, /* TYPE_DDEACCESS */
FALSE, /* TYPE_DDECONV */
FALSE, /* TYPE_DDEXACT */
TRUE, /* TYPE_MONITOR */
FALSE, /* TYPE_KBDLAYOUT */
FALSE, /* TYPE_KBDFILE */
TRUE, /* TYPE_KBDLAYOUT */
TRUE, /* TYPE_KBDFILE */
TRUE, /* TYPE_WINEVENTHOOK */
FALSE, /* TYPE_TIMER */
TRUE, /* TYPE_TIMER */
FALSE, /* TYPE_INPUTCONTEXT */
FALSE, /* TYPE_HIDDATA */
FALSE, /* TYPE_DEVICEINFO */