windows-nt/Source/XPSP1/NT/com/ole32/olethunk/olethk32/olethk32.cxx

626 lines
17 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1994.
//
// File: olethk32.cxx
//
// Contents: Main routines for olethk32.dll
//
// History: 22-Feb-94 DrewB Created
//
//----------------------------------------------------------------------------
#include "headers.cxx"
#include <userapis.h>
#pragma hdrstop
#include <thkmgr.hxx>
#include <stdio.h>
DECLARE_INFOLEVEL(thk);
DECLARE_INFOLEVEL(Stack);
// Interop is disabled at load time
DATA16 gdata16Data;
BOOL gfIteropEnabled;
#if DBG == 1
BOOL fSaveProxy = FALSE; // Used to find apps who call dead proxies
BOOL fStabilizeProxies = TRUE; // Used to easily disable stabilization
BOOL fZapProxy = FALSE; // Used to zap entries in freelist
#ifdef _CHICAGO_
BOOL fSSOn = TRUE;
#endif // _CHICAGO_
#if defined(__cplusplus)
extern "C"
{
#endif
void CallOutputFunctions(const char *buffer);
#if defined(__cplusplus)
}
#endif
#endif
CLIPFORMAT g_cfLinkSourceDescriptor, g_cfObjectDescriptor;
BYTE g_abLeadTable[256];
//+---------------------------------------------------------------------------
//
// Function: DoThreadDetach
//
// Synopsis: When a thread is detaching, cleanup for it.
//
// Effects: This is called during both DLL_THREAD_DETACH, and
// DLL_PROCESS_DETACH.
//
// Arguments: (none)
//
// History: 3-18-95 kevinro Created
//
// Notes:
//
//----------------------------------------------------------------------------
void
DoThreadDetach()
{
thkDebugOut((DEB_DLL,"_IN DoThreadDetach\n"));
//
// If there is thunk data, clean it up now.
//
if (TlsGetValue(dwTlsThkIndex) != NULL)
{
thkDebugOut((DEB_DLL,"DoThreadDetach calling ThkMgrUninitialize\n"));
ThkMgrUninitialize(0, 0, 0);
}
thkDebugOut((DEB_DLL,"OUT DoThreadDetach\n"));
}
//+---------------------------------------------------------------------------
//
// Function: LibMain, public
//
// Synopsis: DLL initialization entry point
//
// History: 23-Feb-94 DrewB Created
//
// Notes:
//
// (KevinRo 19-Mar-95)
//
// Caution needs to be exercised during cleanup. OLE32.DLL has
// a pointer that we pass in during CoInitializeWOW. This pointer
// is used to call back into OLETHK32 for cleanup purposes, as well as
// accessing functions exposed by the 16-bit side. It is important that
// when OLETHK32 unloads, the pointer in OLE32 is marked as invalid.
// There is a call during the DLL_PROCESS_DETACH below that causes
// OLE32 to invalidate its pointer.
//
// In addition, the last thread attached to a DLL will not generate
// a DLL_THREAD_DETACH. Instead, it generates a DLL_PROCESS_DETACH. This
// means that DLL_PROCESS_DETACH should perform all the steps that
// DLL_THREAD_DETACH does in addition to whatever DLL_PROCESS_DETACH work
// that needs to be done.
//
// Lastly, OLETHK32.DLL is statically linked to OLE32.DLL. This means
// that OLETHK32.DLL's DLL_PROCESS_DETACH will be called before OLE32's.
// That is why it is safe for us to call the OLE32 entry point during
// DLL_PROCESS_DETACH
//----------------------------------------------------------------------------
extern "C" BOOL __cdecl LibMain(HANDLE hDll,
DWORD dwReason,
LPVOID lpReserved)
{
switch( dwReason )
{
case DLL_PROCESS_ATTACH:
#if DBG == 1
char achInfoLevel[80];
if(thkInfoLevel == (DEB_ERROR | DEB_WARN) &&
GetProfileStringA("olethk32", "InfoLevel", "3", achInfoLevel,
sizeof(achInfoLevel)) > 0)
{
thkInfoLevel = strtol (achInfoLevel, NULL, 0);
}
#endif
thkDebugOut((DEB_DLL,"_IN DLL_PROCESS_ATTACH\n"));
//
// Save a slot in the thread local storage for our PSTACK (pseudo-
// stack) pointer.
//
if (!TlsThkAlloc())
{
thkDebugOut((DEB_WARN, "TlsThkAlloc failed\n"));
return FALSE;
}
thkDebugOut((DEB_DLL,"OUT DLL_PROCESS_ATTACH\n"));
break;
case DLL_THREAD_ATTACH:
thkDebugOut((DEB_DLL,"_IN DLL_THREAD_ATTACH\n"));
TlsSetValue(dwTlsThkIndex, NULL);
thkDebugOut((DEB_DLL,"OUT DLL_THREAD_ATTACH\n"));
break;
case DLL_THREAD_DETACH:
thkDebugOut((DEB_DLL,"_IN DLL_THREAD_DETACH\n"));
//
// Call OLE32.DLL and tell it to cleanup for this thread. This will
// not mark OLE32's ptr invalid since this is only a thread detach
// and not a process detach. This is a private API between OLE32 and
// OLETHK32.
//
thkDebugOut((DEB_DLL,"Calling Unload WOW for Thread Detach\n"));
CoUnloadingWOW(FALSE);
//
// When the thread for this task goes away, we need to clean out
// the thunk manager.
//
DoThreadDetach();
thkDebugOut((DEB_DLL,"OUT DLL_THREAD_DETACH\n"));
break;
case DLL_PROCESS_DETACH:
thkDebugOut((DEB_DLL,
"IN DLL_PROCESS_DETACH: %s\n",
lpReserved?"Process Exit":"Dll Unload"));
//
// The last threads cleanup needs to be done here.
//
if (lpReserved == NULL)
{
//
// Call OLE32.DLL and tell it to cleanup for this thread, and to
// never call us again, since we are going away. This is a private
// API between OLE32 and OLETHK32. This call will mark OLE32's
// private pointer to us as invalid.
//
thkDebugOut((DEB_DLL,"Calling Unload WOW\n"));
CoUnloadingWOW(TRUE);
//
// lpReserved being NULL means this cleanup is due to
// a FreeLibrary. If it was due to process exit, there
// is no way for us to determine the state of the data
// structures in the system. Other threads may have been
// right smack in the middle of taking apart data structures.
//
//
// Chicago unloads DLL's differently than NT. On Chicago, the
// 32-bit side cleans up first, plus resources allocated on
// the 32-bit side are released when the 16-bit process goes
// away. On NT, the 16-bit process is treated like a thread,
// so we have to cleanup.
//
#ifndef _CHICAGO_
DoThreadDetach();
#endif
//
// Only cleanup the memory if the process is not going away.
// On Windows NT, there are cases when the NTVDM needs to be
// blown away. We shouldn't be calling back to the 16-bit
// side in this case. Therefore, we explicitly call free here
// instead of putting it in the destructor.
//
flFreeList32.FreeMemoryBlocks();
flHolderFreeList.FreeMemoryBlocks();
flRequestFreeList.FreeMemoryBlocks();
}
TlsThkFree();
//
// Call to cleanup 16-bit memory if we are running on Win95.
// This should free up the 16-bit memory associated with this
// process. This is called in IntOpUninitialize on NT, since it
// needs to be called before the 16-bit side goes away.
//
#ifdef _CHICAGO_
flFreeList16.FreeMemoryBlocks();
#endif
thkDebugOut((DEB_DLL,"OUT DLL_PROCESS_DETACH\n"));
break;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: IntOpInitialize, public
//
// Synopsis: Initializes the 32-bit interoperability code
//
// Arguments: [lpdata16] - 16-bit call data
// [dw1] - Ignored
// [dw2] - Ignored
//
// Returns: Appropriate status code
//
// History: 22-Feb-94 JohannP Created
//
//----------------------------------------------------------------------------
STDAPI IntOpInitialize(LPDATA16 lpdata16, DWORD dw1, DWORD dw2)
{
int i;
thkDebugOut((DEB_ITRACE | DEB_THUNKMGR, "_IN IntOpInitialize (%08lX)\n",
lpdata16));
thkAssert((THOP_LASTOP & ~THOP_OPMASK) == 0);
#if DBG == 1
char achInfoLevel[80];
#ifdef _CHICAGO_
if (GetProfileStringA("CairOLE InfoLevels",
"Stack", "3", achInfoLevel,
sizeof(achInfoLevel)) > 0)
{
StackInfoLevel = strtol (achInfoLevel, NULL, 0);
}
#endif // _CHICAGO_
if (GetProfileIntA("olethk32", "BreakOnInit", FALSE))
{
// DebugBreak's in WOW are fatal unless the exception
// is handled somehow. If a debugger is hooked up,
// it'll get first crack at the break exception
// If not, our handler will ignore the exception so
// execution can continue
__try
{
DebugBreak();
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
fSaveProxy = GetProfileIntA("olethk32", "SaveProxy", FALSE);
fZapProxy = GetProfileIntA("olethk32", "ZapProxy", FALSE);
fStabilizeProxies = GetProfileIntA("olethk32", "Stabilize", TRUE);
#endif
// Copy passed parameter from 16-bit world...
memcpy( (LPVOID)&gdata16Data, (LPVOID)lpdata16, sizeof( DATA16 ) );
// Enable interop
gfIteropEnabled = TRUE;
#if defined(_CHICAGO_)
g_cfObjectDescriptor =
RegisterClipboardFormatA("Object Descriptor");
g_cfLinkSourceDescriptor =
RegisterClipboardFormatA("Link Source Descriptor");
#else
g_cfObjectDescriptor =
(CLIPFORMAT) RegisterClipboardFormat(__TEXT("Object Descriptor"));
g_cfLinkSourceDescriptor =
(CLIPFORMAT) RegisterClipboardFormat(__TEXT("Link Source Descriptor"));
#endif
if (g_cfObjectDescriptor == 0 || g_cfLinkSourceDescriptor == 0)
{
thkDebugOut((DEB_WARN, "IntOpInitialize: "
"Unable to register clipboard formats\n"));
return E_UNEXPECTED;
}
// Create a lookup table for lead-byte-ness
// so we can avoid calling IsDBCSLeadByte on every character
// during string validation
for (i = 0; i < 256; i++)
{
g_abLeadTable[i] = (BYTE)IsDBCSLeadByte((BYTE)i);
}
thkDebugOut((DEB_THUNKMGR | DEB_ITRACE, "OUT IntOpInitialize (%08lX)\n",
lpdata16));
return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Function: IntOpUninitialize, public
//
// Synopsis: Cleanup initiated by 16-bit DLL unload
//
// Arguments: [dw1]
// [dw2]
// [dw3]
//
// History: 29-Nov-94 DrewB Created
// 10-20-97 Gopalk Disabled interop as CompObj is no
// longer present after this point
//
// Notes: (KevinRo) This routine is only called by compobj.dll. To make
// things even more interesting, it is only called on Windows/NT. Win95
// does the flFreeList16.FreeMemoryBlocks during PROCESS_DETACH. Cleanup
// of the proxies is not neccessary on Win95, since the 16-bit process will
// clean them up for us.
//
//----------------------------------------------------------------------------
STDAPI IntOpUninitialize(DWORD dw1, DWORD dw2, DWORD dw3)
{
thkDebugOut((DEB_THUNKMGR | DEB_ITRACE, "_IN IntOpUninitialize\n"));
#ifndef _CHICAGO_
// Remove all existing proxies since we're going to free the
// proxy memory in the next step
if (TlsThkGetData() != NULL)
{
CThkMgr *ptm = TlsThkGetThkMgr();
if (ptm)
{
ptm->RemoveAllProxies();
}
}
// Clean up the 16-bit freelist at this time because we know
// that 16-bit code is still active and available for callback
// If we waited for the freelist destructor to be called, 16-bit
// code would already be cleaned up and the WOWGlobalFree calls
// would fail
flFreeList16.FreeMemoryBlocks();
// Disable interop
gfIteropEnabled = FALSE;
#if DBG==1
// In debug builds zero out 16-bit callback function pointer so that
// we fault in the 32-bit code if we call them hereafter
memset( (LPVOID)&gdata16Data, 0, sizeof( DATA16 ) );
#endif
WgtDump();
#else
thkAssert(!"IntOpUninitialize called on Win95");
#endif
thkDebugOut((DEB_THUNKMGR | DEB_ITRACE, "OUT IntOpUninitialize\n"));
return 0;
}
//+---------------------------------------------------------------------------
//
// Function: ConvertHr1632Thunk, public
//
// Synopsis: Trivial function to allow calling HRESULT conversion
// functions from 16-bit
//
// Arguments: [hr] - HRESULT to convert
// [dw1]
// [dw2]
//
// Returns: Appropriate status code
//
// History: 26-Sep-94 DrewB Created
//
// Notes: Required because 16-bit calls to CallProc32W use three
// arguments
//
//----------------------------------------------------------------------------
STDAPI ConvertHr1632Thunk(HRESULT hr, DWORD dw1, DWORD dw2)
{
return TransformHRESULT_1632(hr);
}
//+---------------------------------------------------------------------------
//
// Function: ConvertHr3216Thunk, public
//
// Synopsis: Trivial function to allow calling HRESULT conversion
// functions from 16-bit
//
// Arguments: [hr] - HRESULT to convert
// [dw1]
// [dw2]
//
// Returns: Appropriate status code
//
// History: 26-Sep-94 DrewB Created
//
// Notes: Required because 16-bit calls to CallProc32W use three
// arguments
//
//----------------------------------------------------------------------------
STDAPI ConvertHr3216Thunk(HRESULT hr, DWORD dw1, DWORD dw2)
{
return TransformHRESULT_3216(hr);
}
//+-------------------------------------------------------------------------
//
// Function: ThkAddAppCompatFlag
//
// Synopsis: Takes the given flag and ORs it into the current app
// compatibility flag set
//
// Effects:
//
// Arguments: [dwFlag] -- flag to set
//
// Requires:
//
// Returns: void
//
// Signals:
//
// Modifies:
//
// Algorithm:
//
// History: dd-mmm-yy Author Comment
// 15-Mar-95 alexgo author
//
// Notes: This function exists so that 16bit thunk dll's may
// also set app compatibility flags. olethk32 code typically
// sets the flags directly via TlsThkSetAppCompatFlags
//
//--------------------------------------------------------------------------
STDAPI_(void) ThkAddAppCompatFlag( DWORD dwFlag )
{
DWORD dw;
dw = TlsThkGetAppCompatFlags();
dw |= dwFlag;
TlsThkSetAppCompatFlags(dw);
}
#if DBG == 1
static LONG _wgtAllocated = 0;
//+---------------------------------------------------------------------------
//
// Function: WgtAllocLock, public debug
//
// Synopsis: Tracking for WOWGlobalAllocLock16
//
// History: 29-Nov-94 DrewB Created
//
//----------------------------------------------------------------------------
VPVOID WgtAllocLock(WORD wFlags, DWORD cb, HMEM16 *ph)
{
HMEM16 h;
VPVOID vpv;
vpv = WOWGlobalAllocLock16(wFlags, cb, &h);
if (vpv != 0)
{
#ifdef WGT_TRACK
if (WOWGlobalLockSize16(h, &cb) != 0)
{
_wgtAllocated += cb;
WOWGlobalUnlock16(h);
}
else
{
thkDebugOut((DEB_WARN,
"Unable to get size of allocated block 0x%04lX\n",
h));
// This is a guess at how big a block Win16 will allocate
_wgtAllocated += (cb+31) & 31;
}
#endif
if (ph != NULL)
{
*ph = h;
}
}
else
{
thkDebugOut((DEB_WARN,
"Unable to allocate %d bytes of 16-bit memory\n",
cb));
}
return vpv;
}
//+---------------------------------------------------------------------------
//
// Function: WgtUnlockFree, public
//
// Synopsis: Tracking for WOWGlobalUnlockFree16
//
// History: 29-Nov-94 DrewB Created
//
//----------------------------------------------------------------------------
void WgtUnlockFree(VPVOID vpv)
{
HMEM16 h;
DWORD cb;
if (vpv == 0)
{
thkDebugOut((DEB_WARN, "Attempt to free NULL\n"));
}
else
{
#ifdef WGT_TRACK
// Total hack, incorrect
h = (HMEM16)(vpv >> 16);
if (WOWGlobalLockSize16(h, &cb) != 0)
{
_wgtAllocated -= cb;
WOWGlobalUnlock16(h);
}
else
{
thkDebugOut((DEB_WARN,
"Unable to get size of allocated block 0x%04lX\n",
h));
}
#endif
WOWGlobalUnlockFree16(vpv);
}
}
//+---------------------------------------------------------------------------
//
// Function: WgtDump, public
//
// Synopsis: Dumps global tracking information
//
// History: 29-Nov-94 DrewB Created
//
//----------------------------------------------------------------------------
void WgtDump(void)
{
if (_wgtAllocated != 0)
{
thkDebugOut((DEB_WARN,
"%d bytes of 16-bit memory currently allocated\n",
_wgtAllocated));
}
}
//+---------------------------------------------------------------------------
//
// Function: ThkCallOutputFunctions, public
//
// Synopsis: thunked pass-thru to Ole32 CallOutputFunctions for 16-bit land
//
// History: 23-Jan-95 murthys Created
//
//----------------------------------------------------------------------------
void ThkCallOutputFunctions(const char * buffer, PVOID dummy1, PVOID dummy2)
{
CallOutputFunctions(buffer);
}
#endif // DBG == 1