409 lines
10 KiB
C
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;
|
||
|
}
|
||
|
|