|
|
//+---------------------------------------------------------------------------
//
// 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
|