NT4/private/ole32/com/remote/callcont.cxx
2020-09-30 17:12:29 +02:00

507 lines
15 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1993.
//
// File: CallCont.cxx (32 bit target)
//
// Contents: Contains the CallControl interface
//
// Functions:
//
// History: 23-Dec-93 Johann Posch (johannp) Created
//
// CODEWORK: probably does not need to be an OLE-style interface
//
//--------------------------------------------------------------------------
#include <ole2int.h>
#include "callcont.hxx"
#include "callmain.hxx"
#include <olespy.hxx>
COleStaticMutexSem sgmxs; // protects CoRegisterMessageFilter & CoGetCallControll
//+-------------------------------------------------------------------------
//
// Class: CCallControl
//
// Synopsis: interface between channels and call main control
//
// History: 27-Dec-93 Johann Posch (johannp) Created
//
//--------------------------------------------------------------------------
class CCallControl : public ICallControl
{
public:
// *** IUnknown methods ***
STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR* ppvObj) ;
STDMETHOD_(ULONG,AddRef) (THIS) ;
STDMETHOD_(ULONG,Release) (THIS) ;
// *** ICallControl methods ***
STDMETHOD (CallRunModalLoop) (THIS_ PCALLDATA pCalldata) ;
STDMETHOD (SetCallState) (THIS_ PCALLDATA pCalldata,
SERVERCALLEX ServerCall,
SCODE scode);
STDMETHOD (HandleDispatchCall) (THIS_ DWORD TIDCaller, REFLID lid,
PINTERFACEINFO32 pIfInfo,
PDISPATCHDATA pDispatchData) ;
STDMETHOD (ModalLoopBlockFunction) (THIS_ );
CCallControl(PORIGINDATA pOrigindata, CCallMainControl &rCMC, HRESULT *phr);
~CCallControl();
private:
ULONG _refs; // reference count
BOOL _fReg; // TRUE if we registered OD with CMC.
CCallMainControl &_CMC; // pointer to call main controller
ORIGINDATA _OD; // origin data
};
#ifdef _CHICAGO_
HRESULT StackSwitch (CCallMainControl *pCMC, CCallInfo *pCallInfo);
HRESULT StackSwitch(CCallMainControl *pCMC, CCallInfo *pCallInfo)
{
HRESULT hres;
StackDebugOut((DEB_STCKSWTCH, "SSCallRunModalLoop 32->16 : CMC(%x), pCallInfo(%x)\n", pCMC,pCallInfo));
hres = pCMC->TransmitAndRunModalLoop(pCallInfo);
StackDebugOut((DEB_STCKSWTCH, "SSCallRunModalLoop 32<-16 back; hres:%ld\n", hres));
return hres;
}
#endif // _CHICAGO_
//+-------------------------------------------------------------------------
//
// Method: CCallControl::QueryInterface
//
// Synopsis: query for a new interface
//
// History: 27-Dec-93 Johann Posch (johannp) Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CCallControl::QueryInterface (REFIID riid, LPVOID FAR* ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = (ICallControl *) this;
AddRef();
return S_OK;
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
}
//+-------------------------------------------------------------------------
//
// Method: CCallControl::AddRef
//
// Synopsis: increments reference count
//
// History: 27-Dec-93 Johann Posch (johannp) Created
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CCallControl::AddRef ()
{
InterlockedIncrement( (long *) &_refs );
return _refs;
}
//+-------------------------------------------------------------------------
//
// Method: CCallControl::Release
//
// Synopsis: decrements reference count
//
// History: 27-Dec-93 Johann Posch (johannp) Created
//
//--------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CCallControl::Release ()
{
ULONG refs = _refs - 1;
if (InterlockedDecrement( (long*) &_refs ) == 0)
{
delete this;
return 0;
}
return refs;
}
//+-------------------------------------------------------------------------
//
// Method: CCallControl::CallRunModalLoop
//
// Synopsis: dispatch an outgoing call and enter the modal loop
//
// Arguments: [pCalldata] - call info
//
// Returns:
//
// History: 27-Dec-93 Johann Posch (johannp) Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CCallControl::CallRunModalLoop (PCALLDATA pCalldata)
{
TRACECALL(TRACE_CALLCONT, "CCallControl::CallRunModalLoop");
CairoleDebugOut((DEB_CALLCONT, "CCallControl::CallRunModalLoop"));
Win4Assert(pCalldata && pCalldata->id == CALLDATAID_UNUSED &&
"CallRunModalLoop - Invalid pCalldata.");
RpcSpy((CALLOUT_BEGIN, NULL, pCalldata->iid, pCalldata->iMethod, 0));
// check if we can call out
HRESULT hres = _CMC.CanMakeOutCall(pCalldata->CallCat, pCalldata->iid);
// CODEWORK: below, we transform CALLCAT_INTERNALSYNC calls into
// CALLCAT_INTERNALINPUTSYNC calls when processing an CALLCAT_INPUTSYNC
// call. The above routine takes that transformation into account. We
// should address the BUGBUG below and then if we keep the transformation,
// move it above the call to CanMakeOutCall and change CanMakeOutCall
// to not compensate for the transformation.
if (hres == S_OK)
{
// create callinfo
CCallInfo CallInfo(pCalldata, &_OD);
CALLTYPE ctSaved = _CMC.GetCallType();
// BUGBUG: RICKHI: do we really want to do this?
if ((_CMC.GetCallCatOfInCall() == CALLCAT_INPUTSYNC
|| InSendMessage())
&& pCalldata->CallCat == CALLCAT_INTERNALSYNC)
{
pCalldata->CallCat = CALLCAT_INTERNALINPUTSYNC;
}
#ifdef _CHICAGO_
// Note: Switch to the 16 bit stack under WIN95.
if (SSONBIGSTACK())
{
CairoleDebugOut((DEB_CALLCONT, "In CallRunModalLoop: CMC(%x), pCallInfo(%x)\n", &_CMC,&CallInfo));
hres = SSCall(8, SSF_SmallStack, (LPVOID)StackSwitch, (DWORD)&_CMC, (DWORD) &CallInfo);
}
else
hres = _CMC.TransmitAndRunModalLoop(&CallInfo);
#else
// call the modal loop
hres = _CMC.TransmitAndRunModalLoop(&CallInfo);
#endif // _CHICAGO_
// reset the main call type
_CMC.SetCallType(ctSaved);
}
RpcSpy((CALLOUT_END, NULL, pCalldata->iid, pCalldata->iMethod, 0));
CairoleDebugOut((DEB_CALLCONT, "CallRunModalLoop returned: %ld\n", hres));
return hres;
}
//+-------------------------------------------------------------------------
//
// Method: CCallControl::SetCallState
//
// Synopsis: sets the state of the given call
//
// Arguments: [pCalldata] - call info
// [ServerCall] - call state
// [scode] - return code
//
// Returns: S_OK
//
// History: 27-Dec-93 Johann Posch (johannp) Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CCallControl::SetCallState (PCALLDATA pCalldata,
SERVERCALLEX ServerCall,
SCODE scode)
{
TRACECALL(TRACE_CALLCONT, "CCallControl::SetCallState\n");
Win4Assert(pCalldata && "SetCallState - Invalid calldata.");
Win4Assert(ServerCall <= SERVERCALLEX_CANCELED && "SetCallState - Invalid SERVERCALLEX.");
PCALLINFO pCallInfo = _CMC.GetCIfromCallID(pCalldata->id);
Win4Assert(pCallInfo && "SetCallState - Invalid pCalldata->id");
pCallInfo->SetCallState((CallState) ServerCall, scode);
return S_OK;
}
//+-------------------------------------------------------------------------
//
// Method: CCallControl::HandleDispatchCall
//
// Synopsis: determine if the app can handle an incoming call, and if
// so, dispatch the call
//
// Arguments: [TIDCaller] - threadid of the calling app
// [lid] - logical threadid the call was made on
// [pIfInfo] - call interface info
// [pChannelData] - channel specific data
//
// Returns: RPC_E_SERVERCALL_REJECTED - call was rejected
// RPC_E_SERVERCALL_RETRYLATER - call was rejected, retry later
// S_OK - call succeeded
// other - error from app
//
// History: 27-Dec-93 Johann Posch (johannp) Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CCallControl::HandleDispatchCall (DWORD TIDCaller,
REFLID lid,
PINTERFACEINFO32 pIfInfo,
PDISPATCHDATA pChannelData)
{
TRACECALL(TRACE_CALLCONT, "CCallControl::HandleDispatchCall");
Win4Assert(pIfInfo && "HandleDispatchCall - Invalid pIfInfo.");
CairoleDebugOut((DEB_CALLCONT, "CCallControl::HandleDispatchCall TIDCaller:%x CallCat:%x\n",
TIDCaller, pIfInfo->callcat));
RpcSpy((CALLIN_BEGIN, NULL, pIfInfo->iid, pIfInfo->wMethod, 0));
// HandleDispatchCall is only called from ComInvoke. Internal calls are
// dispatched directly to their worker functions.
Win4Assert(!(pIfInfo->callcat == CALLCAT_INTERNALSYNC ||
pIfInfo->callcat == CALLCAT_INTERNALINPUTSYNC) &&
"HandleDispatchCall called on Internal Call");
Win4Assert(TIDCaller);
//
// BUGBUG #27041 <RickHi>
//
// Stabilize this object to correct a problem of exiting Word 2.0c while
// a Media Player object is open. The below ->DispatchCall() would
// cause this object to be deleted, thus a crash in the following
// statement.
//
{
AddRef();
}
// ask the App's message filter (if there is one) what to do
CALLTYPE ctSaved = _CMC.GetCallType();
HRESULT hres = _CMC.CanHandleIncomingCall(TIDCaller, lid, pIfInfo);
if (hres == S_OK)
{
// app will allow the call, dispatch it
CALLCATEGORY CallCat = _CMC.SetCallCatOfInCall(pIfInfo->callcat);
hres = _OD.pChCont->DispatchCall(pChannelData);
_CMC.SetCallCatOfInCall(CallCat);
}
// reset the main call state
_CMC.SetCallType(ctSaved);
//
// End of stabilization section.
//
{
Release();
}
RpcSpy((CALLIN_END, NULL, pIfInfo->iid, pIfInfo->wMethod, hres));
CairoleDebugOut((DEB_CALLCONT, "CCallControl::HandleDispatchCall hres = %ld \n", hres));
return hres;
}
STDMETHODIMP CCallControl::ModalLoopBlockFunction()
{
return _CMC.BlockFn();
}
//+-------------------------------------------------------------------------
//
// Method: CCallControl::CCallControl
//
// Synopsis: constructs a new call control
//
// Arguments: [pOrigindata] - call origin info
// [rCMC] - callmain control
// [phr] - where to return the result code
//
// Returns: S_OK - created OK
// RPC_E_UNEXPECTED - duplicate origin data
//
// History: 27-Dec-93 Johann Posch (johannp) Created
//
//--------------------------------------------------------------------------
CCallControl::CCallControl(PORIGINDATA pOrigindata, CCallMainControl &rCMC, HRESULT *phr) :
_CMC(rCMC),
_refs(1)
{
Win4Assert(pOrigindata && "Invalid parameter to constructor");
_OD = *pOrigindata;
// addref the channelcontrol interface
_OD.pChCont->AddRef();
// try to register this origin data with the Main Call Control. We
// cant do this earlier due to threading issues.
_fReg = _CMC.Register(&_OD);
*phr = (_fReg) ? S_OK : RPC_E_UNEXPECTED;
}
//+-------------------------------------------------------------------------
//
// Method: CCallControl::~CCallControl
//
// Synopsis: destructor for call control
//
// Arguments: none
//
// History: 27-Dec-93 Johann Posch (johannp) Created
//
//--------------------------------------------------------------------------
CCallControl::~CCallControl()
{
if (_fReg)
{
// only if we successfully registered do we unregister. this
// avoids deregistering a valid OD if registration failed due
// to duplicates.
_CMC.Unregister(&_OD);
}
_OD.pChCont->Release();
}
//+-------------------------------------------------------------------------
//
// Function: CoGetCallControl, private
//
// Synopsis: Returns a pointer to CCallControl
//
// Arguments: Pointer to OriginData
//
// Returns: CCallControl
//
// Algorithm:
//
// History: 27-Dec-93 Johann Posch (johannp) Created
//
//--------------------------------------------------------------------------
STDAPI CoGetCallControl(PORIGINDATA pOrigindata, PCALLCONTROL FAR* ppCallControl)
{
TRACECALL(TRACE_CALLCONT, "CCallControl::CoGetCallControl");
Win4Assert((pOrigindata && pOrigindata->CallOrigin < CALLORIGIN_LAST)
&& L"CoGetCallControl: Invalid CallOrigin specified" );
HRESULT hr = RPC_E_UNEXPECTED;
// only one thread should enter here
COleStaticLock lck(sgmxs);
CCallMainControl *pcmc = GetCallMainControlForThread();
if (pcmc)
{
// create a new callcontrol with the same callmaincontrol
*ppCallControl = new CCallControl(pOrigindata, *pcmc, &hr);
if (FAILED(hr))
{
// registration failed.
delete *ppCallControl;
*ppCallControl = NULL;
}
}
else
{
CairoleDebugOut((DEB_ERROR, "CoGetCallControl: GetCallMainControl Failed\n"));
*ppCallControl = NULL;
}
return hr;
}
//+-------------------------------------------------------------------------
//
// Function: CoRegisterMessageFilter, public
//
// Synopsis: registers an applications message filter with the call control
//
// Arguments: [pMsgFilter] - message filter to register
// [ppMsgFilter] - optional, where to return previous IMF
//
// Returns: S_OK - registered successfully
//
// History: 27-Dec-93 Johann Posch (johannp) Created
//
//--------------------------------------------------------------------------
STDAPI CoRegisterMessageFilter(LPMESSAGEFILTER pMsgFilter,
LPMESSAGEFILTER *ppMsgFilter)
{
OLETRACEIN((API_CoRegisterMessageFilter, PARAMFMT("pMsgFilter= %p, ppMsgFilter= %p"), pMsgFilter, ppMsgFilter));
HRESULT hr;
hr = CoRegisterMessageFilterEx(
(LPMESSAGEFILTER32) ((void *)pMsgFilter),
(LPMESSAGEFILTER32 *) ((void **)ppMsgFilter)
);
OLETRACEOUT((API_CoRegisterMessageFilter, hr));
return hr;
}
STDAPI CoRegisterMessageFilterEx(LPMESSAGEFILTER32 pMsgFilter,
LPMESSAGEFILTER32 * ppMsgFilter)
{
TRACECALL(TRACE_CALLCONT, "CoRegisterMessageFilter");
CALLHOOKOBJECT(S_OK,CLSID_NULL,IID_IMessageFilter,
(IUnknown **)&pMsgFilter);
HRESULT hr = S_OK;
CCallMainControl *pcmc = NULL;
{
// only one thread should enter here
COleStaticLock lck(sgmxs);
if ((pcmc = GetCallMainControlForThread()))
{
LPMESSAGEFILTER32 pMF = pcmc->SetMessageFilter(pMsgFilter);
if (ppMsgFilter)
{
// return the old one.
*ppMsgFilter = pMF;
}
else if (pMF)
{
// release the old one.
pMF->Release();
}
}
else
{
// error here
Win4Assert(FALSE && "CoRegisterMessageFilter invalid call.");
hr = E_FAIL;
}
}
return hr;
}