windows-nt/Source/XPSP1/NT/base/mvdm/wow32/wole2.c
2020-09-26 16:20:57 +08:00

409 lines
10 KiB
C

/*++
*
* 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;
}