//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1994. // // File: apinot.cxx // // Contents: Implementation of non-API thunks // // History: 11-Mar-94 BobDay Created // //---------------------------------------------------------------------------- #include "headers.cxx" #pragma hdrstop #include #include #include "olethk32.hxx" #include "apinot.hxx" #include "tlsthk.hxx" // // The following is a global static used by OLE32 to call back into // this DLL. There is no static data associated with the static, so // it merely defines a virtual interface that OLE32 can use. // OleThunkWOW g_thkOleThunkWOW; // // The following API is exported from WOW32.DLL. There is no global include // file that it exists in yet. // #if defined(_CHICAGO_) /* Not supported under Chicago yet. */ /* But it's probably not important anymore. */ #define WOWFreeMetafile(x) (0) #else extern "C" BOOL WINAPI WOWFreeMetafile( HANDLE h32 ); #endif //+--------------------------------------------------------------------------- // // Function: CoInitializeNot, public // // Synopsis: Thunks for the 16-bit applications call to CoInitialize // // Arguments: [lpmalloc] - Parameter from the 16-bit world // // Returns: Appropriate status code // // History: 11-Mar-94 BobDay Created // //---------------------------------------------------------------------------- STDAPI_(DWORD) CoInitializeNot( LPMALLOC lpMalloc ) { HRESULT hresult; hresult = CoInitializeWOW( lpMalloc, &g_thkOleThunkWOW ); return (DWORD)hresult; } //+--------------------------------------------------------------------------- // // Function: OleInitializeNot, public // // Synopsis: Thunks for the 16-bit applications call to OleInitialize // // Arguments: [lpmalloc] - Parameter from the 16-bit world // // Returns: Appropriate status code // // History: 11-Mar-94 BobDay Created // //---------------------------------------------------------------------------- STDAPI_(DWORD) OleInitializeNot( LPMALLOC lpMalloc ) { HRESULT hresult; hresult = OleInitializeWOW( lpMalloc, &g_thkOleThunkWOW ); return (DWORD)hresult; } //+--------------------------------------------------------------------------- // // Function: RegisterDelayedClassFactories // // Synopsis: This function is called to actually do the registration of // the delayed class factories. // // Effects: When the application specific 'trigger' is hit // (ie OleRegGetUserType for WordPerfect), this routine is // called to actually do all of the delayed class factory // registrations. // // Arguments: (none) // // Requires: // // Returns: nothing // // History: 4-18-95 kevinro Created // //---------------------------------------------------------------------------- void RegisterDelayedClassFactories() { thkDebugOut((DEB_ITRACE, "_IN RegisterDelayedClassFactories()\n")); PThreadData pdata; IUnknown *punk; HRESULT hr; DelayedRegistrationTable *pTable = NULL; DelayRegistration *pdelayed; DWORD dwReg; int i; // // Get the thread specific data and table to determine if there are // any delayed registrations. If not, just call the real routine. // pdata = TlsThkGetData(); if (pdata == NULL) { goto exitRtn; } if ((pTable = pdata->pDelayedRegs) == NULL) { goto exitRtn; } // // // for (i = 0 ; i < MAX_DELAYED_REGISTRATIONS ; i++) { pdelayed = &(pTable->_Entries[i]); if((pdelayed->_punk != NULL) && (pdelayed->_dwRealKey == 0)) { hr = CoRegisterClassObject(pdelayed->_clsid, pdelayed->_punk, pdelayed->_dwClsContext, pdelayed->_flags, &(pdelayed->_dwRealKey)); if (FAILED(hr)) { thkDebugOut((DEB_ERROR, "RegisterDelayedClassFactory gets %x\n",hr)); } } } exitRtn: thkDebugOut((DEB_ITRACE, "OUT RegisterDelayedClassFactories()\n")); } //+--------------------------------------------------------------------------- // // Function: CoRevokeClassObjectNot // // Synopsis: Unregisters a class object that might have been delayed // // Effects: The 16-bit API CoRevokeClassObject has been directed to this // routine. This routine will check the list of interfaces that // have been registered, and will try to determine if the key // needs to be translated. // // Arguments: [dwKey] -- Key to revoke // // History: 4-18-95 kevinro Created // // Notes: // //---------------------------------------------------------------------------- HRESULT CoRevokeClassObjectNot( DWORD dwKey) { thkDebugOut((DEB_ITRACE, "_IN CoRevokeClassObjectNot(dwKey = %x)\n", dwKey)); PThreadData pdata; IUnknown *punk; HRESULT hr; DelayedRegistrationTable *pTable = NULL; DWORD dwReg = ~dwKey; // // Get the thread specific data and table to determine if there are // any delayed registrations. If not, just call the real routine. // pdata = TlsThkGetData(); if (pdata == NULL) { goto exitRtn; } if ((pTable = pdata->pDelayedRegs) == NULL) { goto exitRtn; } // // the 'fake' key is really the bitwise not of the index // if ( dwReg >= MAX_DELAYED_REGISTRATIONS) { goto exitRtn; } if(pTable->_Entries[dwReg]._punk != NULL) { punk = pTable->_Entries[dwReg]._punk; pTable->_Entries[dwReg]._punk = NULL; dwKey = pTable->_Entries[dwReg]._dwRealKey; pTable->_Entries[dwReg]._dwRealKey = 0; // // The class object table normally does an addref on the class factory. // We are also holding an addref on the punk. Release it. // if (punk != NULL) { punk->Release(); // // If the real key is zero, then we never did actually finish // the registration. In this case, we return S_OK, because we // are faking the app out anyway. This might happen if the app // decides to shutdown for some reason without triggering the // operation that causes us to register its class objects // if (dwKey == 0) { hr = S_OK; goto exitNow; } } } exitRtn: hr = CoRevokeClassObject(dwKey); exitNow: thkDebugOut((DEB_ITRACE,"OUT CoRevokeClassObjectNot():%x\n",hr)); return(hr); } //+--------------------------------------------------------------------------- // // Function: CoRegisterClassObjectDelayed // // Synopsis: Delay the registration of class objects. Some applications, // such as Word Perfect 6.1, register their class objects then // do peek message operations BEFORE they are fully initialized. // This causes problems because we can call in and do // CreateInstance calls before they are ready for them. This // wonderful hack will delay the registration of class objects // until someone calls RegisterClassObjectsNow(), which is // called when we know it is safe. // // Novell knows about this hack, and promised not to change // the 16-bit code on us. // // Effects: Store all of the registration information in an array, and // return a special key value. // // // Arguments: ( Same as CoRegisterClassObject) // // Requires: The associated routine CoUnregisterClassObjectDelayed needs // to be called in the CoRevokeClassObject path to check to see // if the key being passed in is a special key. That way we // can translate the key before calling the real routine. // // The special key value is not of the key // // Returns: S_OK or E_UNEXPECTED // // History: 4-14-95 kevinro Created // // Notes: // //---------------------------------------------------------------------------- HRESULT CoRegisterClassObjectDelayed( REFCLSID refclsid, LPUNKNOWN punk, DWORD dwClsContext, DWORD flags, DWORD *pdwReg) { thkDebugOut((DEB_ITRACE,"_IN CoRegisterClassObjectDelayed\n")); PThreadData pdata; int i; DelayedRegistrationTable *pTable = NULL; // // Assume this is going to fail // HRESULT hr = E_UNEXPECTED; *pdwReg = 0; pdata = TlsThkGetData(); if (pdata == NULL) { goto exitRtn; } if ((pTable = pdata->pDelayedRegs) == NULL) { pTable = pdata->pDelayedRegs = new DelayedRegistrationTable(); } if (pTable != NULL) { for (i = 0 ; i < MAX_DELAYED_REGISTRATIONS ; i++) { if(pTable->_Entries[i]._punk == NULL) { pTable->_Entries[i]._punk = punk; pTable->_Entries[i]._clsid = refclsid; pTable->_Entries[i]._dwClsContext = dwClsContext; pTable->_Entries[i]._flags = flags; // // The class object table normally does an // addref on the class factory. We will hang on to this // to keep the class factory and the 3216 proxy alive // punk->AddRef(); *pdwReg = ~i; hr = S_OK; break; } } } exitRtn: thkDebugOut((DEB_ITRACE,"OUT CoRegisterClassObjectDelayed() : %x\n",hr)); return(hr); } //+--------------------------------------------------------------------------- // // Function: CoRegisterClassObjectNot, public // // Synopsis: Thunks for the 16-bit applications call CoRegisterClassObject // Here we check for the registered class objects to set the // thread's compatability bits. // // Arguments: [refclsid] - CLSID for the class to register // [punk] - ClassFactory interface // [dwClsContext] - Class context // [flags] - flags // [lpdwreg] - register // // Returns: Appropriate status code // // History: 18-Jul-94 BobDay Created // //---------------------------------------------------------------------------- EXTERN_C const CLSID CDECL CLSID_EXCEL5_WORKSHEET = { 0x020810, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}}; EXTERN_C const CLSID CDECL CLSID_WORD6_DOCUMENT = { 0x020900, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}}; EXTERN_C const CLSID CDECL CLSID_WPWIN61 = { 0x89FE3FE3, 0x9FF6, 0x101B, {0xB6, 0x78, 0x04, 0x02, 0x1C, 0x00, 0x70, 0x02}}; EXTERN_C const CLSID CDECL CLSID_WPWIN61_FILE = { 0x1395F281, 0x4326, 0x101b, {0x8B, 0x9A, 0xCE, 0x29, 0x3E, 0xF3, 0x84, 0x49}}; EXTERN_C const CLSID CDECL CLSID_IKITARO_130 = { 0x02B501, 0, 0, {0xC0, 0, 0, 0, 0, 0, 0, 0x46}}; DEFINE_OLEGUID(CLSID_EXCEL5_WORKSHEET, 0x20810, 0, 0); STDAPI_(DWORD) CoRegisterClassObjectNot( REFCLSID refclsid, LPUNKNOWN punk, DWORD dwClsContext, DWORD flags, LPDWORD lpdwreg ) { // // Excel didn't AddRef the IOleObjectClientSite returned from // the IOleObject::GetClientSite method. // if ( IsEqualCLSID(refclsid,CLSID_EXCEL5_WORKSHEET) ) { DWORD dw; dw = TlsThkGetAppCompatFlags(); TlsThkSetAppCompatFlags(dw | OACF_CLIENTSITE_REF); thkDebugOut((DEB_WARN,"AppCompatFlag: OACF_CLIENTSITE_REF enabled\n")); } // // WinWord didn't call OleSetMenuDescriptor(NULL) during // IOleInPlaceFrame::RemoveMenus. We do it for them. // // Also WinWord thinks GDI objects like palettes and bitmaps can be // transferred on HGLOBALs during GetData calls. In order to thunk // them properly, we need to patch up the STGMEDIUMS given to use // by word. This is controlled by OACF_USEGDI. // // YAWC: Word chokes and dies because it fails to disconnect some of its // objects. During shutdown of a link, for example, cleaning up the stdid // table causes WORD to fault. // else if ( IsEqualCLSID(refclsid,CLSID_WORD6_DOCUMENT) ) { DWORD dw; dw = TlsThkGetAppCompatFlags(); TlsThkSetAppCompatFlags(dw | OACF_RESETMENU | OACF_USEGDI | OACF_NO_UNINIT_CLEANUP); thkDebugOut((DEB_WARN,"AppCompatFlag: OACF_RESETMENU enabled\n")); thkDebugOut((DEB_WARN,"AppCompatFlag: OACF_USEGDI enabled\n")); thkDebugOut((DEB_WARN,"AppCompatFlag: OACF_NO_UNINIT_CLEANUP enabled\n")); } else if ( IsEqualCLSID(refclsid,CLSID_WPWIN61) ) { thkDebugOut((DEB_WARN,"WordPerfect hack triggered\n")); thkDebugOut((DEB_WARN,"Intercepting CoRegisterClassObject(WPWIN61)\n")); return CoRegisterClassObjectDelayed( refclsid,punk,dwClsContext,flags,lpdwreg); } else if ( IsEqualCLSID(refclsid,CLSID_WPWIN61_FILE) ) { thkDebugOut((DEB_WARN,"WordPerfect hack triggered\n")); thkDebugOut((DEB_WARN,"Intercepting CoRegisterClassObject(WPWIN61_FILE)\n")); return CoRegisterClassObjectDelayed( refclsid,punk,dwClsContext,flags,lpdwreg); } else if ( IsEqualCLSID(refclsid,CLSID_IKITARO_130) ) { // Note: Ikitaro queries for IViewObject and uses it as IViewObject2 DWORD dw = TlsThkGetAppCompatFlags(); thkDebugOut((DEB_WARN,"Ikitaro hack triggered\n")); TlsThkSetAppCompatFlags(dw | OACF_IVIEWOBJECT2); } return (DWORD)CoRegisterClassObject( refclsid, punk, dwClsContext, flags, lpdwreg ); } //+--------------------------------------------------------------------------- // // Function: OleRegGetUserTypeNot // // Synopsis: Adds a hook for a WordPerfect hack. Check out the functions // CoRegisterClassObjectDelayed and // RegisterDelayedClassFactories for details. In essence, when // this function is called for the WPWIN61 classID, we know // that it is safe to register all of the delayed class objects. // This determination was done by debugging Wordperfect. When // they call this API, then are actually done initializing the // internals of their app. // // Effects: // // History: 4-18-95 kevinro Created // // Notes: // //---------------------------------------------------------------------------- STDAPI_(DWORD) OleRegGetUserTypeNot(REFCLSID clsid,DWORD dwFormOfType,LPOLESTR *pszUserType) { // // Wordperfect has a bug. When they call OleRegGetUserType for their // classid, we know that it is safe to register their class objects for // real. // // See CoRegisterClassObjectDelayed for details // if ( IsEqualCLSID(clsid,CLSID_WPWIN61) ) { thkDebugOut((DEB_WARN,"Registering WordPerfects class objects\n")); RegisterDelayedClassFactories(); } return OleRegGetUserType(clsid,dwFormOfType,pszUserType); } //+--------------------------------------------------------------------------- // // Member: OleThunkWOW::LoadProcDll, public // // Synopsis: Callback function for 32-bit OLE to load a 16-bit DLL // // Arguments: [pszDllName] - Name of 16-bit DLL // [lpvpfnGetClassObject] - returned 16:16 address of // "DllGetClassObject" // [lpvpfnCanUnloadNow] - returned 16:16 address of // "DllCanUnloadNow" // [lpvhmodule] - returned 16-bit hmodule // // Returns: Appropriate status code // // History: 11-Mar-94 BobDay Created // //---------------------------------------------------------------------------- STDMETHODIMP OleThunkWOW::LoadProcDll( LPCTSTR pszDllName, LPDWORD lpvpfnGetClassObject, LPDWORD lpvpfnCanUnloadNow, LPDWORD lpvhmodule ) { HRESULT hr; UINT uiSize; VPSTR vpstr16; VPVOID vplpds16; LOADPROCDLLSTRUCT UNALIGNED *lplpds16; char string[256]; // Ensure that Interop is enabled Win4Assert(gfIteropEnabled); // Ensure that callbacks are allowed on this thread Win4Assert(TlsThkGetThkMgr()->AreCallbacksAllowed()); uiSize = lstrlen(pszDllName) + 1; vpstr16 = STACKALLOC16(uiSize*sizeof(TCHAR)); if (vpstr16 == 0) { hr = E_OUTOFMEMORY; goto Exit; } #ifndef _CHICAGO_ hr = Convert_LPOLESTR_to_VPSTR(pszDllName, vpstr16, uiSize, uiSize*sizeof(TCHAR)); #else hr = Convert_LPSTR_to_VPSTR(pszDllName, vpstr16, uiSize, uiSize*sizeof(TCHAR)); #endif if (FAILED(hr)) { goto EH_vpstr16; } vplpds16 = STACKALLOC16(sizeof(LOADPROCDLLSTRUCT)); if (vplpds16 == 0) { hr = E_OUTOFMEMORY; goto EH_vpstr16; } lplpds16 = FIXVDMPTR(vplpds16, LOADPROCDLLSTRUCT); lplpds16->vpDllName = vpstr16; lplpds16->vpfnGetClassObject = 0; lplpds16->vpfnCanUnloadNow = 0; lplpds16->vhmodule = 0; RELVDMPTR(vplpds16); hr = CallbackTo16( gdata16Data.fnLoadProcDll, vplpds16 ); if (SUCCEEDED(hr)) { lplpds16 = FIXVDMPTR(vplpds16, LOADPROCDLLSTRUCT); *lpvpfnGetClassObject = lplpds16->vpfnGetClassObject; *lpvpfnCanUnloadNow = lplpds16->vpfnCanUnloadNow; *lpvhmodule = lplpds16->vhmodule; RELVDMPTR(vplpds16); #ifdef _CHICAGO_ thkDebugOut((DEB_WARN, "Loaded COM DLL: %s with HMODULE: 0x%x\n", pszDllName, *lpvhmodule)); #else thkDebugOut((DEB_WARN, "Loaded COM DLL: %ws with HMODULE: 0x%x\n", pszDllName, *lpvhmodule)); #endif } else { hr = CO_E_DLLNOTFOUND; } STACKFREE16(vplpds16, sizeof(LOADPROCDLLSTRUCT)); EH_vpstr16: STACKFREE16(vpstr16,uiSize*sizeof(TCHAR)); Exit: return hr; } //+--------------------------------------------------------------------------- // // Member: OleThunkWOW::UnloadProcDll, public // // Synopsis: Callback function for 32-bit OLE to unload a 16-bit DLL // // Arguments: [vhmodule] - 16-bit hmodule // // Returns: Appropriate status code // // History: 11-Mar-94 BobDay Created // //---------------------------------------------------------------------------- STDMETHODIMP OleThunkWOW::UnloadProcDll( HMODULE vhmodule ) { HRESULT hr = S_OK; // Ensure that Interop is enabled and callbacks are // not allowed on this thread if(gfIteropEnabled && TlsThkGetThkMgr()->AreCallbacksAllowed()) hr = CallbackTo16(gdata16Data.fnUnloadProcDll, HandleToUlong(vhmodule)); return(hr); } //+--------------------------------------------------------------------------- // // Member: OleThunkWOW::CallGetClassObject, public // // Synopsis: Callback function for 32-bit OLE to call 16-bit // DllGetClassObject // // Arguments: [vpfnGetClassObject] - 16:16 address of DllGetClassObject // [rclsid] - CLSID of object // [riid] - IID of interface on object // [ppv] - returned object interface // // Returns: Appropriate status code // // History: 11-Mar-94 BobDay Created // //---------------------------------------------------------------------------- STDMETHODIMP OleThunkWOW::CallGetClassObject( DWORD vpfnGetClassObject, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv ) { DWORD dwResult; VPVOID vpcgcos16; CALLGETCLASSOBJECTSTRUCT UNALIGNED *lpcgcos16; VPVOID iface16; IIDIDX iidx; IUnknown *punkThis32; CThkMgr *pThkMgr; ThreadData *ptd; // Ensure that Interop is enabled Win4Assert(gfIteropEnabled); // Ensure that callbacks are allowed on this thread Win4Assert(TlsThkGetThkMgr()->AreCallbacksAllowed()); ptd = TlsThkGetData(); if (ptd == NULL) { thkDebugOut((DEB_WARN, "WARNING: CallGetClassObject refused\n")); dwResult = (DWORD)E_FAIL; goto Exit; } pThkMgr = ptd->pCThkMgr; vpcgcos16 = STACKALLOC16(sizeof(CALLGETCLASSOBJECTSTRUCT)); if (vpcgcos16 == 0) { dwResult = (DWORD)E_OUTOFMEMORY; goto Exit; } lpcgcos16 = FIXVDMPTR(vpcgcos16, CALLGETCLASSOBJECTSTRUCT); lpcgcos16->vpfnGetClassObject = vpfnGetClassObject; lpcgcos16->clsid = rclsid; lpcgcos16->iid = riid; lpcgcos16->iface = 0; RELVDMPTR(vpcgcos16); dwResult = CallbackTo16( gdata16Data.fnCallGetClassObject, vpcgcos16 ); if ( SUCCEEDED(dwResult) ) { lpcgcos16 = FIXVDMPTR(vpcgcos16, CALLGETCLASSOBJECTSTRUCT); iface16 = lpcgcos16->iface; iidx = IidToIidIdx(riid); // We're on the way out creating a proxy so set the state // appropriately pThkMgr->SetThkState(THKSTATE_INVOKETHKOUT32); // Get a 32-bit proxy object for the 16-bit object punkThis32 = pThkMgr->FindProxy3216(NULL, iface16, NULL, iidx, FALSE, NULL); pThkMgr->SetThkState(THKSTATE_NOCALL); // Set the out param *(IUnknown **)ppv = punkThis32; // As this is an OUT parameter, release the actual 16-bit interface // This could be the last release on the 16-bit interface, if the // proxy was not successfully created ReleaseOnObj16(iface16); if(punkThis32 == NULL) { dwResult = (DWORD)E_OUTOFMEMORY; } RELVDMPTR(vpcgcos16); } else { // need to map dwResult only for failure cases (see hmMappings) dwResult = TransformHRESULT_1632( dwResult ); } STACKFREE16(vpcgcos16, sizeof(CALLGETCLASSOBJECTSTRUCT)); Exit: return dwResult; } //+--------------------------------------------------------------------------- // // Member: OleThunkWOW::CallCanUnloadNow, public // // Synopsis: Callback function for 32-bit OLE to call 16-bit // CanUnloadNow // // Arguments: [vpfnCanUnloadNow] - 16:16 address of DllCanUnloadNow // // Returns: Appropriate status code // // History: 11-Mar-94 BobDay Created // //---------------------------------------------------------------------------- STDMETHODIMP OleThunkWOW::CallCanUnloadNow( DWORD vpfnCanUnloadNow) { HRESULT hr = S_OK; // Ensure that Interop is enabled and callbacks are // not allowed on this thread if(gfIteropEnabled && TlsThkGetThkMgr()->AreCallbacksAllowed()) hr = CallbackTo16(gdata16Data.fnCallCanUnloadNow, vpfnCanUnloadNow); return(hr); } //+--------------------------------------------------------------------------- // // Member: OleThunkWOW::GetThunkManager, public // // Synopsis: Callback function for 32-bit OLE to retrieve the thunkmanager // // Arguments: [ppThkMgr] - Thunk manager return // // Returns: Appropriate status code // // History: 11-May-94 JohannP Created // //---------------------------------------------------------------------------- STDMETHODIMP OleThunkWOW::GetThunkManager(IThunkManager **ppThkMgr) { thkDebugOut((DEB_THUNKMGR, "%sIn OleThunkWOW::GetThunkManager\n", NestingLevelString())); thkAssert(ppThkMgr != NULL); IUnknown *pUnk = TlsThkGetThkMgr(); thkAssert(pUnk && "Invalid Thunkmanager"); *ppThkMgr = (IThunkManager *)pUnk; pUnk->AddRef(); thkDebugOut((DEB_THUNKMGR, "%sOut OleThunkWOW::GetThunkManager: (%p)\n", NestingLevelString(), pUnk)); return NOERROR; } //+--------------------------------------------------------------------------- // // Member: OleThunkWOW::WinExec16, public // // Synopsis: Callback function for 32-bit OLE to run an application // // Arguments: [pszCommandLine] - command line for WinExec // [usShow] - fShow for WinExec // // Returns: Appropriate status code // // History: 27-Jul-94 AlexT Created // //---------------------------------------------------------------------------- STDMETHODIMP OleThunkWOW::WinExec16( LPCOLESTR pszCommandLine, USHORT usShow ) { HRESULT hr; UINT uiSize; VPSTR vpstr16; VPVOID vplpds16; WINEXEC16STRUCT UNALIGNED *lpwes16; ULONG ulRet; // Ensure that Interop is enabled Win4Assert(gfIteropEnabled); // Ensure that callbacks are allowed on this thread Win4Assert(TlsThkGetThkMgr()->AreCallbacksAllowed()); uiSize = lstrlenW(pszCommandLine) + 1; vpstr16 = STACKALLOC16(uiSize*2); if (vpstr16 == 0) { hr = E_OUTOFMEMORY; goto Exit; } hr = Convert_LPOLESTR_to_VPSTR(pszCommandLine, vpstr16, uiSize, uiSize*2); if (FAILED(hr)) { goto EH_vpstr16; } vplpds16 = STACKALLOC16(sizeof(WINEXEC16STRUCT)); if (vplpds16 == 0) { hr = E_OUTOFMEMORY; goto EH_vpstr16; } lpwes16 = FIXVDMPTR(vplpds16, WINEXEC16STRUCT); lpwes16->vpCommandLine = vpstr16; lpwes16->vusShow = usShow; RELVDMPTR(vplpds16); ulRet = CallbackTo16( gdata16Data.fnWinExec16, vplpds16 ); thkDebugOut((DEB_ITRACE, "CallbackTo16(WinExec16) returned %ld\n", ulRet)); // According to the Windows spec, return values greater than 31 indicate // success. if (ulRet > 31) { hr = S_OK; } else if (0 == ulRet) { // 0 indicates lack of some kind of resource hr = E_OUTOFMEMORY; } else { hr = HRESULT_FROM_WIN32(ulRet); } STACKFREE16(vplpds16, sizeof(WINEXEC16STRUCT)); EH_vpstr16: STACKFREE16(vpstr16, uiSize*2); Exit: return hr; } //+--------------------------------------------------------------------------- // // Method: OleThunkWOW::ConvertHwndToFullHwnd // // Synopsis: Converts a 16 bit HWND into a 32-bit HWND // // Effects: Since OLE32 doesn't directly link to WOW, this function allows // the DDE layer to access the routine that maps 16 bit HWND to // full 32-bit HWND's. // // Arguments: [hwnd] -- HWND to convert // // History: 8-03-94 kevinro Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP_(HWND) OleThunkWOW::ConvertHwndToFullHwnd(HWND hwnd) { return(FULLHWND_32((USHORT)hwnd)); } //+--------------------------------------------------------------------------- // // Method: OleThunkWOW::FreeMetaFile // // Synopsis: Calls wow to delete a metafile that has memory reserved in // the 16 bit address space // // Effects: Since OLE32 doesn't directly link to WOW, this function allows // the DDE layer to access the routine in WOW // // Arguments: [hmf] -- HANDLE to delete // // History: 8-03-94 kevinro Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP_(BOOL) OleThunkWOW::FreeMetaFile(HANDLE hmf) { return(WOWFreeMetafile(hmf)); } //+--------------------------------------------------------------------------- // // Member: OleThunkWOW::YieldTask16, public // // Synopsis: Callback function for 32-bit OLE to yield // // History: 08-Aug-94 Ricksa Created // //---------------------------------------------------------------------------- STDMETHODIMP OleThunkWOW::YieldTask16(void) { WOWYield16(); return S_OK; } //+--------------------------------------------------------------------------- // // Member: OleThunkWOW::DirectedYield, public // // Synopsis: Does a directed yield in the VDM. // // History: 08-Aug-94 Rickhi Created // //---------------------------------------------------------------------------- STDMETHODIMP OleThunkWOW::DirectedYield(DWORD dwCalleeTID) { WORD hTask16 = WOWHandle16((void *)dwCalleeTID, WOW_TYPE_HTASK); thkDebugOut((DEB_ITRACE, "WOWDirectedYield16(%x)\n", hTask16)); WOWDirectedYield16(hTask16); thkDebugOut((DEB_ITRACE, "WOWDirectedYield16() returned\n")); return S_OK; } //+--------------------------------------------------------------------------- // // Method: OleThunkWOW::PrepareForCleanup // // Synopsis: Prepares OLETHK32 for OLE32.DLL's cleanup. // // Effects: It does this by taking all of the remaining 3216 proxies // and marking them such that no callbacks into the 16-bit // world are possible. // // Arguments: -none- // // History: 24-Aug-94 bobday Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP_(void) OleThunkWOW::PrepareForCleanup(void) { CThkMgr *pcthkmgr; if ( TlsThkGetData() != NULL ) { pcthkmgr = (CThkMgr*)TlsThkGetThkMgr(); // // Tell the thkmgr to prepare for cleaning itself up // pcthkmgr->PrepareForCleanup(); } } //+--------------------------------------------------------------------------- // // Method: OleThunkWOW::GetAppCompatibilityFlags // // Synopsis: Used to return the current THK app compatibility flags to // OLE32.DLL // Arguments: [void] -- // // Requires: // // Returns: Flags defined in ih\thunkapi.hxx // // History: 1-11-96 kevinro Created // //---------------------------------------------------------------------------- STDMETHODIMP_(DWORD) OleThunkWOW::GetAppCompatibilityFlags(void) { return(TlsThkGetAppCompatFlags()); }