|
|
//+---------------------------------------------------------------------------
//
// 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"<local>"));
// 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; }
|