//+--------------------------------------------------------------------------- // // 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 #pragma hdrstop #include #include 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