//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1995 // // File: object.cxx // // Contents: Implementation of the CLocalMTProxy class and // associated objects. // //---------------------------------------------------------------------------- #include "headers.hxx" #include "mtscript.h" // MIDL generated file #include "localobj.h" long g_lObjectCount = 0; // *********************************************************************** // // CLocalProxyCP // // ConnectionPoint for CLocalMTProxy // // *********************************************************************** CLocalProxyCP::CLocalProxyCP(CLocalMTProxy *pMach) { _ulRefs = 1; _pMTProxy = pMach; _pMTProxy->AddRef(); } CLocalProxyCP::~CLocalProxyCP() { _pMTProxy->Release(); } HRESULT CLocalProxyCP::QueryInterface(REFIID iid, void **ppv) { if (iid == IID_IUnknown || iid == IID_IConnectionPoint) { *ppv = (IConnectionPoint *)this; } else { *ppv = NULL; return E_NOINTERFACE; } ((IUnknown *)*ppv)->AddRef(); return S_OK; } HRESULT CLocalProxyCP::GetConnectionInterface(IID * pIID) { *pIID = DIID_DRemoteMTScriptEvents; return S_OK; } HRESULT CLocalProxyCP::GetConnectionPointContainer(IConnectionPointContainer ** ppCPC) { *ppCPC = _pMTProxy; (*ppCPC)->AddRef(); return S_OK; } //+--------------------------------------------------------------------------- // // Member: CLocalProxyCP::Advise, public // // Synopsis: Remembers interface pointers that we want to fire events // through. // // Arguments: [pUnkSink] -- Pointer to remember // [pdwCookie] -- Place to put cookie for Unadvise // // Returns: HRESULT // //---------------------------------------------------------------------------- HRESULT CLocalProxyCP::Advise(IUnknown *pUnkSink, DWORD *pdwCookie) { IDispatch *pDisp; HRESULT hr; TraceTag((tagError, "CLocalProxyCP::Advise: Advising %p", pUnkSink)); hr = pUnkSink->QueryInterface(IID_IDispatch, (LPVOID*)&pDisp); if (hr) { return hr; } // We can only keep one sink at a time. ReleaseInterface(_pMTProxy->_pDispSink); _pMTProxy->_pDispSink = pDisp; *pdwCookie = (DWORD)pDisp; return S_OK; } //+--------------------------------------------------------------------------- // // Member: CLocalProxyCP::Unadvise, public // // Synopsis: Forgets a pointer we remembered during Advise. // // Arguments: [dwCookie] -- Cookie returned from Advise // // Returns: HRESULT // //---------------------------------------------------------------------------- HRESULT CLocalProxyCP::Unadvise(DWORD dwCookie) { TraceTag((tagError, "CLocalProxyCP::Unadvise: Unadvising %p", dwCookie)); if (dwCookie == (DWORD)_pMTProxy->_pDispSink) { ClearInterface(&_pMTProxy->_pDispSink); } else return E_INVALIDARG; return S_OK; } HRESULT CLocalProxyCP::EnumConnections(LPENUMCONNECTIONS * ppEnum) { *ppEnum = NULL; RRETURN(E_NOTIMPL); } // *********************************************************************** // // CLocalMTProxy // // *********************************************************************** CLocalMTProxy::CLocalMTProxy() { _ulRefs = 1; _ulAllRefs = 1; InterlockedIncrement(&g_lObjectCount); Assert(_pTypeInfoInterface == NULL); Assert(_pTypeLibDLL == NULL); } CLocalMTProxy::~CLocalMTProxy() { ReleaseInterface(_pTypeInfoInterface); ReleaseInterface(_pTypeInfoCM); ReleaseInterface(_pTypeLibDLL); InterlockedDecrement(&g_lObjectCount); } //+--------------------------------------------------------------------------- // // Member: CLocalMTProxy::Passivate, public // // Synopsis: Called when the refcount for CLocalMTProxy goes to zero. This // will cause us to let go of all the objects we hold onto, which // in turn should cause everyone else to let go of our subobjects. // When that happens we can finally delete ourselves. // //---------------------------------------------------------------------------- void CLocalMTProxy::Passivate() { Disconnect(); ClearInterface(&_pDispSink); } //+--------------------------------------------------------------------------- // // Member: CLocalMTProxy::QueryInterface, public // // Synopsis: Standard IUnknown::QueryInterface // //---------------------------------------------------------------------------- HRESULT CLocalMTProxy::QueryInterface(REFIID iid, void **ppvObj) { if (iid == IID_IRemoteMTScriptProxy || iid == IID_IUnknown || iid == IID_IDispatch) { *ppvObj = (IRemoteMTScriptProxy *)this; } else if (iid == IID_IConnectionPointContainer) { *ppvObj = (IConnectionPointContainer *)this; } else if (iid == IID_IProvideClassInfo) { *ppvObj = (IProvideClassInfo *)this; } else { *ppvObj = NULL; return E_NOINTERFACE; } ((IUnknown *)*ppvObj)->AddRef(); return S_OK; } //+--------------------------------------------------------------------------- // // Member: CLocalMTProxy::AddRef, public // // Synopsis: Standard IUnknown::AddRef. Increments the refcount on the // CLocalMTProxy object. // //---------------------------------------------------------------------------- ULONG CLocalMTProxy::AddRef() { return ++_ulRefs; } //+--------------------------------------------------------------------------- // // Member: CLocalMTProxy::Release, public // // Synopsis: IUnknown::Release. // // Notes: If the refcount on CLocalMTProxy goes to zero, we know our // owner is done with us and we can clean up. So, we release // all our interface pointers and etc. However, someone may still // be holding on to our event sink subobject, so we can't // delete ourselves yet. // //---------------------------------------------------------------------------- ULONG CLocalMTProxy::Release() { ULONG ulRefs = --_ulRefs; if (ulRefs == 0) { _ulRefs = ULREF_IN_DESTRUCTOR; Passivate(); AssertSz(_ulRefs == ULREF_IN_DESTRUCTOR, "NONFATAL: Invalid refcount during passivate!"); _ulRefs = 0; SubRelease(); } return ulRefs; } //+--------------------------------------------------------------------------- // // Member: CLocalMTProxy::SubAddRef, public // // Synopsis: Called when the event sink gets addref'd. Increments an overall // refcount. // //---------------------------------------------------------------------------- ULONG CLocalMTProxy::SubAddRef() { return ++_ulAllRefs; } //+--------------------------------------------------------------------------- // // Member: CLocalMTProxy::SubRelease, public // // Synopsis: Called when the event sink gets released and when // CLocalMTProxy passivates. If the overall refcount is zero, // we know no-one is using us and we can go away. // //---------------------------------------------------------------------------- ULONG CLocalMTProxy::SubRelease() { if (--_ulAllRefs == 0) { _ulAllRefs = ULREF_IN_DESTRUCTOR; _ulRefs = ULREF_IN_DESTRUCTOR; delete this; } return 0; } //--------------------------------------------------------------------------- // // Member: CLocalMTProxy::EnumConnectionPoints, IConnectionPointContainer // //--------------------------------------------------------------------------- HRESULT CLocalMTProxy::EnumConnectionPoints(LPENUMCONNECTIONPOINTS *) { return E_NOTIMPL; } //--------------------------------------------------------------------------- // // Member: CLocalMTProxy::FindConnectionPoint, IConnectionPointContainer // //--------------------------------------------------------------------------- HRESULT CLocalMTProxy::FindConnectionPoint(REFIID iid, LPCONNECTIONPOINT* ppCpOut) { HRESULT hr; TraceTag((tagError, "CLocalMTProxy::FindConnectionPoint called.")); if (iid == DIID_DRemoteMTScriptEvents || iid == IID_IDispatch) { TraceTag((tagError, "CLocalMTProxy::FindConnectionPoint: Returning event source.")); *ppCpOut = new CLocalProxyCP(this); hr = *ppCpOut ? S_OK : E_OUTOFMEMORY; } else { hr = E_NOINTERFACE; } RRETURN(hr); } //+--------------------------------------------------------------------------- // // Member: CLocalMTProxy::GetClassInfo, public // // Synopsis: Implementation of IProvideClassInfo // // Arguments: [pTI] -- Return type info interface here // // Notes: This returns the typeinfo for the RemoteMTScriptProxy coclass // //---------------------------------------------------------------------------- HRESULT CLocalMTProxy::GetClassInfo(ITypeInfo **pTI) { HRESULT hr; TraceTag((tagError, "CLocalMTProxy::GetClassInfo called")); hr = LoadTypeLibs(); if (hr) return hr; hr = _pTypeLibDLL->GetTypeInfoOfGuid(CLSID_RemoteMTScriptProxy, pTI); return hr; } //--------------------------------------------------------------------------- // // Member: CLocalMTProxy::GetTypeInfo, IDispatch // // Notes: This returns the typeinfo for the IRemoteMTScriptProxy dual // interface. // //--------------------------------------------------------------------------- HRESULT CLocalMTProxy::GetTypeInfo(UINT itinfo, ULONG lcid, ITypeInfo ** pptinfo) { HRESULT hr; TraceTag((tagError, "CLocalMTProxy::GetTypeInfo called")); hr = LoadTypeLibs(); if (hr) return hr; *pptinfo = _pTypeInfoInterface; (*pptinfo)->AddRef(); return S_OK; } //--------------------------------------------------------------------------- // // Member: CLocalMTProxy::GetTypeInfoCount, IDispatch // //--------------------------------------------------------------------------- HRESULT CLocalMTProxy::GetTypeInfoCount(UINT * pctinfo) { *pctinfo = 1; return S_OK; } //--------------------------------------------------------------------------- // // Member: CLocalMTProxy::GetIDsOfNames, IDispatch // //--------------------------------------------------------------------------- HRESULT CLocalMTProxy::GetIDsOfNames(REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid) { HRESULT hr; hr = LoadTypeLibs(); if (hr) return hr; hr = _pTypeInfoInterface->GetIDsOfNames(rgszNames, cNames, rgdispid); if (hr && _pDispRemote) { hr = _pTypeInfoCM->GetIDsOfNames(rgszNames, cNames, rgdispid); } return hr; } //--------------------------------------------------------------------------- // // Member: CLocalMTProxy::Invoke, IDispatch // //--------------------------------------------------------------------------- HRESULT CLocalMTProxy::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr) { HRESULT hr; hr = LoadTypeLibs(); if (hr) return hr; hr = _pTypeInfoInterface->Invoke((IRemoteMTScriptProxy *)this, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); // // If we're connected to the remote object, then we forward any calls // we don't know how to handle on to that object. This is not aggregation, // since we have not set up object identity in this relationship. // if (hr && _pDispRemote) { hr = _pDispRemote->Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); } return hr; } //+--------------------------------------------------------------------------- // // Member: CLocalMTProxy::LoadTypeLibs, public // // Synopsis: Ensures that we have loaded our typelibrary // //---------------------------------------------------------------------------- HRESULT CLocalMTProxy::LoadTypeLibs() { HRESULT hr = S_OK; TCHAR achDll[MAX_PATH]; if (!_pTypeLibDLL) { GetModuleFileName(g_hInstDll, achDll, MAX_PATH); hr = THR(LoadTypeLib(achDll, &_pTypeLibDLL)); if (hr) goto Cleanup; } if (!_pTypeInfoInterface) { hr = THR(_pTypeLibDLL->GetTypeInfoOfGuid(IID_IRemoteMTScriptProxy, &_pTypeInfoInterface)); if (hr) goto Cleanup; } if (!_pTypeInfoCM) { hr = THR(_pTypeLibDLL->GetTypeInfoOfGuid(IID_IConnectedMachine, &_pTypeInfoCM)); if (hr) goto Cleanup; } Cleanup: if (hr) { TraceTag((tagError, "CLocalMTProxy::LoadTypeLibs returning %x", hr)); } return hr; } // ************************************************************************* //+--------------------------------------------------------------------------- // // Member: CLocalMTProxy::Connect, public // // Synopsis: Connects to the RemoteMTScript object on the given remote // (or local) machine. // // Arguments: [bstrMachine] -- Machine to connect to. If NULL or empty, // use the local machine. // // Returns: HRESULT // // Notes: This also sets up the event sink for handling events. // //---------------------------------------------------------------------------- STDMETHODIMP CLocalMTProxy::Connect(BSTR bstrMachine) { HRESULT hr = S_OK; COSERVERINFO csi = { 0 }; MULTI_QI mqi[2] = { 0 }; BOOL fRemote = TRUE; // IConnectionPointContainer *pCPC; // IConnectionPoint *pCP; if (!bstrMachine || SysStringLen(bstrMachine) == 0) { fRemote = FALSE; } TraceTag((tagError, "CLocalMTProxy::Connect called. Machine=%ls", (fRemote) ? bstrMachine : L"")); // The following code will remove all security from the connection. This // will need to be enabled if the corresponding call to CoInitializeSecurity // is turned on in mtscript.exe. // Remove security for the connection. csi.pAuthInfo = NULL; csi.pwszName = bstrMachine; mqi[0].pIID = &IID_IDispatch; // mqi[1].pIID = &IID_IConnectionPointContainer; hr = CoCreateInstanceEx(CLSID_RemoteMTScript, NULL, CLSCTX_SERVER, (fRemote) ? &csi : NULL, 1, mqi); if (FAILED(hr)) { TraceTag((tagError, "CLocalMTProxy::Connect: CoCreateInstanceEx returned=%x", hr)); return hr; } if (mqi[0].hr) return mqi[0].hr; _pDispRemote = (IDispatch *)mqi[0].pItf; /* // Security problems make it difficult to impossible to make a // reverse COM event interface connect successfully. if (!mqi[1].hr) { pCPC = (IConnectionPointContainer *)mqi[1].pItf; hr = pCPC->FindConnectionPoint(DIID_DRemoteMTScriptEvents, &pCP); if (!hr) { hr = pCP->Advise(&_cesSink, &_dwSinkCookie); ReleaseInterface(pCP); } ReleaseInterface(pCPC); #if DBG == 1 if (hr) TraceTag((tagError, "Hookup to event sink returned %x", hr)); #endif // If the advise failed for some reason, just don't sink events. } else { TraceTag((tagError, "CLocalMTProxy::Connect: ICPC QI returned=%x", mqi[1].hr)); } */ return S_OK; } //+--------------------------------------------------------------------------- // // Member: CLocalMTProxy::Disconnect, public // // Synopsis: Disconnects from a machine we connected to via Connect(). // // Arguments: (none) // //---------------------------------------------------------------------------- STDMETHODIMP CLocalMTProxy::Disconnect() { HRESULT hr = S_OK; TraceTag((tagError, "CLocalMTProxy::Disconnect called")); if (_dwSinkCookie) { IConnectionPointContainer *pCPC; IConnectionPoint *pCP; hr = _pDispRemote->QueryInterface(IID_IConnectionPointContainer, (LPVOID*)&pCPC); if (!hr) { hr = pCPC->FindConnectionPoint(DIID_DRemoteMTScriptEvents, &pCP); if (!hr) { pCP->Unadvise(_dwSinkCookie); ReleaseInterface(pCP); } ReleaseInterface(pCPC); #if DBG == 1 if (hr) TraceTag((tagError, "Unadvise from event sink returned %x", hr)); #endif } _dwSinkCookie = 0; } ClearInterface(&_pDispRemote); return S_OK; } //+--------------------------------------------------------------------------- // // Member: CLocalMTProxy::DownloadFile, public // // Synopsis: Downloads a file from the given URL and stores it locally. // // Arguments: [bstrURL] -- URL to download // [bstrFile] -- Path of where the file was saved by urlmon // // Returns: HRESULT // //---------------------------------------------------------------------------- STDMETHODIMP CLocalMTProxy::DownloadFile(BSTR bstrURL, BSTR *bstrFile) { HRESULT hr; TCHAR achBuf[MAX_PATH * 2]; hr = URLDownloadToCacheFile((IRemoteMTScriptProxy*)this, bstrURL, achBuf, MAX_PATH * 2, 0, NULL); if (hr) { int cChar; HINSTANCE hModURLMON = LoadLibraryA("urlmon.dll"); cChar = wsprintf(achBuf, L"Error: (%x) ", hr); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS, hModURLMON, hr, 0, achBuf + cChar, MAX_PATH * 2 - cChar, NULL); FreeLibrary(hModURLMON); } *bstrFile = SysAllocString(achBuf); return S_OK; } // ************************************************************************* // // CMTEventSink // // Class which implements the event sink for the remote object. This just // forwards all calls to the event sink registered with us by the web page, // if any. // // ************************************************************************* HRESULT CMTEventSink::QueryInterface(REFIID iid, void **ppv) { if (iid == IID_IUnknown || iid == IID_IDispatch) { *ppv = (IDispatch *)this; } else { *ppv = NULL; return E_NOINTERFACE; } ((IUnknown *)*ppv)->AddRef(); return S_OK; } //--------------------------------------------------------------------------- // // Member: CMTEventSink::GetTypeInfo, IDispatch // //--------------------------------------------------------------------------- HRESULT CMTEventSink::GetTypeInfo(UINT itinfo, ULONG lcid, ITypeInfo ** pptinfo) { if (Proxy()->_pDispSink) { return Proxy()->_pDispSink->GetTypeInfo(itinfo, lcid, pptinfo); } return S_OK; } //--------------------------------------------------------------------------- // // Member: CMTEventSink::GetTypeInfoCount, IDispatch // //--------------------------------------------------------------------------- HRESULT CMTEventSink::GetTypeInfoCount(UINT * pctinfo) { if (Proxy()->_pDispSink) { return Proxy()->_pDispSink->GetTypeInfoCount(pctinfo); } return S_OK; } //--------------------------------------------------------------------------- // // Member: CMTEventSink::GetIDsOfNames, IDispatch // //--------------------------------------------------------------------------- HRESULT CMTEventSink::GetIDsOfNames(REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgdispid) { if (Proxy()->_pDispSink) { return Proxy()->_pDispSink->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); } return S_OK; } //--------------------------------------------------------------------------- // // Member: CMTEventSink::Invoke, IDispatch // //--------------------------------------------------------------------------- HRESULT CMTEventSink::Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, UINT * puArgErr) { TraceTag((tagError, "CMTEventSink::Invoke called")); if (Proxy()->_pDispSink) { HRESULT hr; hr = Proxy()->_pDispSink->Invoke(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); if (hr) { TraceTag((tagError, "CMTEventSink::Invoke: Sink call returned %x!", hr)); } } TraceTag((tagError, "CMTEventSink::Invoke returning")); return S_OK; }