/*++ * * WOW v1.0 * * Copyright (c) 1994, Microsoft Corporation * * WOLE2.C * WOW32 Support for OLE2 stuff * * History: * Created 03-May-1994 by Bob Day (bobday) --*/ #include "precomp.h" #pragma hdrstop MODNAME(wole.c); /* ** Under OLE 2.0, the IMessageFilter interface passes HTASKs/THREADIDs. It ** passes HTASKs in the 16-bit world, and THREADIDs in the 32-bit world. The ** OLE 2.0 16 <-> 32 interoperability DLLs need a way of converting the ** HTASK into an appropriate THREADID and back. ** ** Really the only place the 16-bit code uses the HTASK is in ole2's BUSY.C ** module, wherein they take the HTASK and use TOOLHELP's TaskFindHandle ** to determine a HINST. Then they take the HINST and try and find its ** module name, and a top-level window handle. Using this, they bring up ** a nice dialog describing the task. ** ** In the case when a 32-bit process's THREADID needs to be given into the ** 16-bit world as an htask, we create an htask alias (a GDT selector). ** We check for it in TaskFindHandle and return an HINST of exactly the ** same value (same GDT selector). We also check for this value in ** GetModuleFileName. Then, later, we make sure that any window operated on ** with GetWindowWord( GWW_HINST, ...) maps to exactly the same value if it ** is from a 32-bit process AND from the process which we created an alias ** for. ** ** I've tried to make these routines general, so that later we might be able ** to really maintain HTASK aliases whenever we see a 32-bit THREADID, but ** it is too late before shipping to be able to test a general fix. ** ** -BobDay ** */ #define MAP_SLOT_HTASK(slot) ((HTASK16)((WORD)0xffe0 - (8 * (slot)))) #define MAP_HTASK_SLOT(htask) ((UINT)(((WORD)0xffe0 - (htask16))/8)) typedef struct tagHTASKALIAS { DWORD dwThreadID32; DWORD dwProcessID32; union { FILETIME ftCreationTime; ULONGLONG ullCreationTime; }; } HTASKALIAS; #define MAX_HTASKALIAS_SIZE 32 // 32 should be plenty HTASKALIAS *lphtaskalias = NULL; UINT cHtaskAliasCount = 0; BOOL GetThreadIDHTASKALIAS( DWORD dwThreadID32, HTASKALIAS *ha ) { OBJECT_ATTRIBUTES obja; THREAD_BASIC_INFORMATION ThreadInfo; HANDLE hThread; NTSTATUS Status; FILETIME ftDummy; CLIENT_ID cid; InitializeObjectAttributes( &obja, NULL, 0, NULL, 0 ); cid.UniqueProcess = 0; // Don't know it, 0 means any process cid.UniqueThread = (HANDLE)dwThreadID32; Status = NtOpenThread( &hThread, THREAD_QUERY_INFORMATION, &obja, &cid ); if ( !NT_SUCCESS(Status) ) { #if DBG DbgPrint("WOW32: Could not get open thread handle\n"); #endif return( FALSE ); } Status = NtQueryInformationThread( hThread, ThreadBasicInformation, (PVOID)&ThreadInfo, sizeof(THREAD_BASIC_INFORMATION), NULL ); ha->dwProcessID32 = (DWORD)ThreadInfo.ClientId.UniqueProcess; ha->dwThreadID32 = dwThreadID32; GetThreadTimes( hThread, &ha->ftCreationTime, &ftDummy, &ftDummy, &ftDummy ); Status = NtClose( hThread ); if ( !NT_SUCCESS(Status) ) { #if DBG DbgPrint("WOW32: Could not close thread handle\n"); DbgBreakPoint(); #endif return( FALSE ); } return( TRUE ); } HTASK16 AddHtaskAlias( DWORD ThreadID32 ) { UINT iSlot; UINT iUsable; HTASKALIAS ha; ULONGLONG ullOldest; if ( !GetThreadIDHTASKALIAS( ThreadID32, &ha ) ) { return( 0 ); } // // Need to allocate the alias table? // if ( lphtaskalias == NULL ) { lphtaskalias = (HTASKALIAS *) malloc_w( MAX_HTASKALIAS_SIZE * sizeof(HTASKALIAS) ); if ( lphtaskalias == NULL ) { LOGDEBUG(LOG_ALWAYS,("WOW::AddHtaskAlias : Failed to allocate memory\n")); WOW32ASSERT(FALSE); return( 0 ); } // Zero them out initially memset( lphtaskalias, 0, MAX_HTASKALIAS_SIZE * sizeof(HTASKALIAS) ); } // // Now iterate through the alias table, either finding an available slot, // or finding the oldest one there to overwrite. // iSlot = 0; iUsable = 0; ullOldest = -1; while ( iSlot < MAX_HTASKALIAS_SIZE ) { // // Did we find an available slot? // if ( lphtaskalias[iSlot].dwThreadID32 == 0 ) { cHtaskAliasCount++; // Using an available slot iUsable = iSlot; break; } // // Remember the oldest guy // if ( lphtaskalias[iSlot].ullCreationTime < ullOldest ) { ullOldest = lphtaskalias[iSlot].ullCreationTime; iUsable = iSlot; } iSlot++; } // // If the above loop is exitted due to not enough space, then // iUsable will be the oldest one. If it was exitted because we found // an empty slot, then iUsable will be the slot. // lphtaskalias[iUsable] = ha; return( MAP_SLOT_HTASK(iUsable) ); } HTASK16 FindHtaskAlias( DWORD ThreadID32 ) { UINT iSlot; if ( lphtaskalias == NULL || ThreadID32 == 0 ) { return( 0 ); } iSlot = MAX_HTASKALIAS_SIZE; while ( iSlot > 0 ) { --iSlot; // // Did we find the appropriate guy? // if ( lphtaskalias[iSlot].dwThreadID32 == ThreadID32 ) { return( MAP_SLOT_HTASK(iSlot) ); } } return( 0 ); } void RemoveHtaskAlias( HTASK16 htask16 ) { UINT iSlot; // // Get out early if we haven't any aliases // if ( lphtaskalias == NULL || (!htask16)) { return; } iSlot = MAP_HTASK_SLOT(htask16); if (iSlot >= MAX_HTASKALIAS_SIZE) { LOGDEBUG(LOG_ALWAYS, ("WOW::RemoveHtaskAlias : iSlot >= MAX_TASK_ALIAS_SIZE\n")); WOW32ASSERT(FALSE); return; } // // Zap the entry from the list // if (lphtaskalias[iSlot].dwThreadID32) { lphtaskalias[iSlot].dwThreadID32 = 0; lphtaskalias[iSlot].dwProcessID32 = 0; lphtaskalias[iSlot].ullCreationTime = 0; --cHtaskAliasCount; } } DWORD GetHtaskAlias( HTASK16 htask16, LPDWORD lpProcessID32 ) { UINT iSlot; DWORD ThreadID32; HTASKALIAS ha; ha.dwProcessID32 = 0; ThreadID32 = 0; if ( ! ISTASKALIAS(htask16) ) { goto Done; } iSlot = MAP_HTASK_SLOT(htask16); if ( iSlot >= MAX_HTASKALIAS_SIZE ) { WOW32ASSERTMSGF(FALSE, ("WOW::GetHtaskAlias : iSlot >= MAX_TASK_ALIAS_SIZE\n")); goto Done; } ThreadID32 = lphtaskalias[iSlot].dwThreadID32; // // Make sure the thread still exists in the system // if ( ! GetThreadIDHTASKALIAS( ThreadID32, &ha ) || ha.ullCreationTime != lphtaskalias[iSlot].ullCreationTime || ha.dwProcessID32 != lphtaskalias[iSlot].dwProcessID32 ) { RemoveHtaskAlias( htask16 ); ha.dwProcessID32 = 0; ThreadID32 = 0; } if ( lpProcessID32 ) { *lpProcessID32 = ha.dwProcessID32; } Done: return ThreadID32; } UINT GetHtaskAliasProcessName( HTASK16 htask16, LPSTR lpNameBuffer, UINT cNameBufferSize ) { DWORD dwThreadID32; DWORD dwProcessID32; PSYSTEM_PROCESS_INFORMATION ProcessInfo; PUCHAR pucLargeBuffer; ULONG LargeBufferSize = 32*1024; NTSTATUS status = STATUS_INFO_LENGTH_MISMATCH; ULONG TotalOffset; dwThreadID32 = GetHtaskAlias(htask16, &dwProcessID32); if ( dwThreadID32 == 0 || cNameBufferSize == 0 || lpNameBuffer == NULL ) { return 0; } while(status == STATUS_INFO_LENGTH_MISMATCH) { pucLargeBuffer = VirtualAlloc(NULL, LargeBufferSize, MEM_COMMIT, PAGE_READWRITE); if (pucLargeBuffer == NULL) { WOW32ASSERTMSGF((FALSE), ("WOW::GetHtaskAliasProcessName: VirtualAlloc(%x) failed %x.\n", LargeBufferSize)); return 0; } status = NtQuerySystemInformation(SystemProcessInformation, pucLargeBuffer, LargeBufferSize, &TotalOffset); if (NT_SUCCESS(status)) { break; } else if (status == STATUS_INFO_LENGTH_MISMATCH) { LargeBufferSize += 8192; VirtualFree (pucLargeBuffer, 0, MEM_RELEASE); pucLargeBuffer = NULL; } else { WOW32ASSERTMSGF((NT_SUCCESS(status)), ("WOW::GetHtaskAliasProcessName: NtQuerySystemInformation failed %x.\n", status)); if(pucLargeBuffer) { VirtualFree (pucLargeBuffer, 0, MEM_RELEASE); } return 0; } } // // Iterate through the returned list of process information structures, // trying to find the one with the right process id. // TotalOffset = 0; ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pucLargeBuffer; while (TRUE) { if ( (DWORD)ProcessInfo->UniqueProcessId == dwProcessID32 ) { // // Found it, return the name. // if ( ProcessInfo->ImageName.Buffer ) { cNameBufferSize = WideCharToMultiByte( CP_ACP, 0, ProcessInfo->ImageName.Buffer, // src ProcessInfo->ImageName.Length, lpNameBuffer, // dest cNameBufferSize, NULL, NULL ); lpNameBuffer[cNameBufferSize] = '\0'; return cNameBufferSize; } else { // // Don't let them get the name of a system process // return 0; } } if (ProcessInfo->NextEntryOffset == 0) { break; } TotalOffset += ProcessInfo->NextEntryOffset; ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&pucLargeBuffer[TotalOffset]; } return 0; }