windows-nt/Source/XPSP1/NT/sdktools/mtscript/localobj/object.cxx
2020-09-26 16:20:57 +08:00

867 lines
22 KiB
C++

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