You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
357 lines
8.4 KiB
357 lines
8.4 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dispatch.cpp
|
|
|
|
Abstract:
|
|
|
|
This module contains the implementation for the Server
|
|
Extension Object Dispatcher service.
|
|
|
|
Author:
|
|
|
|
Andy Jacobs ([email protected])
|
|
|
|
Revision History:
|
|
|
|
andyj 11/26/96 created
|
|
|
|
--*/
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "seo.h"
|
|
#include "dispatch.h"
|
|
|
|
|
|
class CDictItemNameList {
|
|
public:
|
|
CDictItemNameList(ISEODictionary *piFrom);
|
|
~CDictItemNameList();
|
|
public:
|
|
DWORD m_dwCount;
|
|
CComVariant *m_aNames;
|
|
};
|
|
|
|
|
|
static HRESULT ReallocCComVariant(CComVariant **ppBase,
|
|
DWORD dwBaseCnt,
|
|
DWORD dwNewBaseCnt) {
|
|
CComVariant *pNew = NULL;
|
|
|
|
if (dwBaseCnt == dwNewBaseCnt) {
|
|
return (S_OK);
|
|
}
|
|
if (!dwNewBaseCnt) {
|
|
delete[] *ppBase;
|
|
*ppBase = NULL;
|
|
return (S_OK);
|
|
}
|
|
ATLTRY(pNew = new CComVariant[dwNewBaseCnt];)
|
|
_ASSERTE(pNew);
|
|
if (!pNew) {
|
|
return (E_OUTOFMEMORY);
|
|
}
|
|
for (DWORD dwIdx=0;(dwIdx<dwBaseCnt)&&(dwIdx<dwNewBaseCnt);dwIdx++) {
|
|
pNew[dwIdx].Attach(&(*ppBase)[dwIdx]);
|
|
}
|
|
delete[] *ppBase;
|
|
*ppBase = pNew;
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
static HRESULT ReallocCComVariant(CComVariant **ppBase,
|
|
DWORD dwBaseCnt,
|
|
CComVariant *pAdd,
|
|
DWORD dwAddCnt) {
|
|
HRESULT hrRes;
|
|
|
|
hrRes = ReallocCComVariant(ppBase,dwBaseCnt,dwBaseCnt+dwAddCnt);
|
|
if (!SUCCEEDED(hrRes)) {
|
|
return (hrRes);
|
|
}
|
|
for (DWORD dwIdx=0;dwIdx<dwAddCnt;dwIdx++) {
|
|
(*ppBase)[dwIdx+dwBaseCnt].Attach(&pAdd[dwIdx]);
|
|
}
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
CDictItemNameList::CDictItemNameList(ISEODictionary *piFrom) {
|
|
HRESULT hrRes;
|
|
|
|
m_dwCount = 0;
|
|
m_aNames = NULL;
|
|
if (piFrom) {
|
|
CComPtr<IUnknown> pUnkEnum;
|
|
|
|
hrRes = piFrom->get__NewEnum(&pUnkEnum);
|
|
if (SUCCEEDED(hrRes)) {
|
|
CComQIPtr<IEnumVARIANT,&IID_IEnumVARIANT> pevEnum(pUnkEnum);
|
|
|
|
if (pevEnum) {
|
|
while (1) {
|
|
CComVariant aNew[20];
|
|
DWORD dwCnt;
|
|
|
|
hrRes = pevEnum->Next(sizeof(aNew)/sizeof(aNew[0]),aNew,&dwCnt);
|
|
if (!SUCCEEDED(hrRes)) {
|
|
break;
|
|
}
|
|
if (!dwCnt) {
|
|
break;
|
|
}
|
|
hrRes = ReallocCComVariant(&m_aNames,m_dwCount,aNew,dwCnt);
|
|
if (!SUCCEEDED(hrRes)) {
|
|
break;
|
|
}
|
|
for (DWORD dwIdx=0;dwIdx<dwCnt;dwIdx++) {
|
|
hrRes = m_aNames[dwIdx+m_dwCount].ChangeType(VT_BSTR);
|
|
_ASSERTE(SUCCEEDED(hrRes));
|
|
if (!SUCCEEDED(hrRes)) {
|
|
// Ack! Ok - just drop this name off the list by moving the last name
|
|
// on the list to this position, and fiddling the indexes so that we
|
|
// attemp to convert this position again.
|
|
if (dwIdx<dwCnt-1) {
|
|
m_aNames[dwIdx+m_dwCount].Attach(&m_aNames[dwCnt+m_dwCount-1]);
|
|
}
|
|
dwIdx--;
|
|
dwCnt--;
|
|
}
|
|
}
|
|
m_dwCount += dwCnt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
CDictItemNameList::~CDictItemNameList() {
|
|
|
|
delete[] m_aNames;
|
|
m_dwCount = 0;
|
|
m_aNames = NULL;
|
|
}
|
|
|
|
|
|
CSEOBaseDispatcher::CSEOBaseDispatcher() {
|
|
|
|
m_apbBindings = NULL;
|
|
m_dwBindingsCount = 0;
|
|
}
|
|
|
|
|
|
CSEOBaseDispatcher::~CSEOBaseDispatcher() {
|
|
|
|
while (m_dwBindingsCount) {
|
|
delete m_apbBindings[--m_dwBindingsCount];
|
|
}
|
|
delete[] m_apbBindings;
|
|
m_apbBindings = NULL;
|
|
}
|
|
|
|
|
|
HRESULT STDMETHODCALLTYPE CSEOBaseDispatcher::SetContext(ISEORouter *piRouter, ISEODictionary *pdictBP) {
|
|
HRESULT hrRes;
|
|
CComPtr<ISEODictionary> pdictBindings;
|
|
|
|
_ASSERT(!m_dwBindingsCount&&!m_apbBindings);
|
|
hrRes = pdictBP->GetInterfaceA(BD_BINDINGS,IID_ISEODictionary,(IUnknown **) &pdictBindings);
|
|
if (SUCCEEDED(hrRes)) {
|
|
CDictItemNameList dinlBindings(pdictBindings);
|
|
|
|
if (dinlBindings.m_dwCount) {
|
|
m_apbBindings = new CBinding *[dinlBindings.m_dwCount];
|
|
if (!m_apbBindings) {
|
|
return (E_OUTOFMEMORY);
|
|
}
|
|
memset(m_apbBindings,0,sizeof(CBinding *)*dinlBindings.m_dwCount);
|
|
for (m_dwBindingsCount=0;m_dwBindingsCount<dinlBindings.m_dwCount;m_dwBindingsCount++) {
|
|
CComPtr<ISEODictionary> pdictBinding;
|
|
|
|
pdictBinding.Release();
|
|
hrRes = pdictBindings->GetInterfaceW(dinlBindings.m_aNames[m_dwBindingsCount].bstrVal,
|
|
IID_ISEODictionary,
|
|
(IUnknown **) &pdictBinding);
|
|
_ASSERT(SUCCEEDED(hrRes));
|
|
if (SUCCEEDED(hrRes)) {
|
|
hrRes = AllocBinding(pdictBinding,&m_apbBindings[m_dwBindingsCount]);
|
|
_ASSERT(SUCCEEDED(hrRes));
|
|
}
|
|
}
|
|
qsort(m_apbBindings,m_dwBindingsCount,sizeof(m_apbBindings[0]),comp_binding);
|
|
}
|
|
}
|
|
if (SUCCEEDED(hrRes)) {
|
|
m_piRouter = piRouter;
|
|
m_pdictBP = pdictBP;
|
|
}
|
|
return (hrRes);
|
|
}
|
|
|
|
|
|
static HRESULT GetCLSIDFromBinding(LPCSTR pszCLSID,
|
|
LPCSTR pszProgID,
|
|
ISEODictionary *piBinding,
|
|
CLSID *pclsid) {
|
|
HRESULT hrRes;
|
|
CComVariant varTmp;
|
|
|
|
if (!piBinding) {
|
|
return (E_POINTER);
|
|
}
|
|
if (pszCLSID) {
|
|
hrRes = piBinding->GetVariantA(pszCLSID,&varTmp);
|
|
if (SUCCEEDED(hrRes)) {
|
|
hrRes = varTmp.ChangeType(VT_BSTR);
|
|
if (SUCCEEDED(hrRes)) {
|
|
hrRes = CLSIDFromString(varTmp.bstrVal,pclsid);
|
|
if (SUCCEEDED(hrRes)) {
|
|
return (hrRes);
|
|
}
|
|
}
|
|
}
|
|
varTmp.Clear();
|
|
}
|
|
if (!pszProgID) {
|
|
return (E_FAIL); // tbd - come up with a better error code
|
|
}
|
|
hrRes = piBinding->GetVariantA(pszProgID,&varTmp);
|
|
if (!SUCCEEDED(hrRes)) {
|
|
return (hrRes);
|
|
}
|
|
hrRes = varTmp.ChangeType(VT_BSTR);
|
|
if (!SUCCEEDED(hrRes)) {
|
|
return (hrRes);
|
|
}
|
|
hrRes = CLSIDFromProgID(varTmp.bstrVal,pclsid);
|
|
return (hrRes);
|
|
}
|
|
|
|
|
|
HRESULT CSEOBaseDispatcher::CBinding::Init(ISEODictionary *piBinding) {
|
|
HRESULT hrRes;
|
|
CComVariant varTmp;
|
|
CLSID clsidTmp;
|
|
|
|
if (!piBinding) {
|
|
return (E_POINTER);
|
|
}
|
|
// Try to get the CLSID of the object - if an error occurs,
|
|
// this binding is invalid.
|
|
hrRes = GetCLSIDFromBinding(BD_OBJECT,BD_PROGID,piBinding,&m_clsidObject);
|
|
if (!SUCCEEDED(hrRes)) {
|
|
return (S_FALSE);
|
|
}
|
|
// From this point on, all errors are silently ignored - we
|
|
// use default values if we can't get something from the binding
|
|
// database.
|
|
hrRes = piBinding->GetVariantA(BD_PRIORITY,&varTmp);
|
|
if (SUCCEEDED(hrRes)) {
|
|
hrRes = varTmp.ChangeType(VT_I4);
|
|
if (SUCCEEDED(hrRes)) {
|
|
m_dwPriority = (DWORD) varTmp.lVal;
|
|
}
|
|
}
|
|
if (!SUCCEEDED(hrRes)) {
|
|
// If the priority isn't set, default to "last".
|
|
m_dwPriority = (DWORD) -1;
|
|
}
|
|
varTmp.Clear();
|
|
m_piBinding = piBinding;
|
|
// Try to get an instance of the rule engine.
|
|
hrRes = GetCLSIDFromBinding(BD_RULEENGINE,NULL,piBinding,&clsidTmp);
|
|
if (SUCCEEDED(hrRes)) {
|
|
hrRes = CoCreateInstance(clsidTmp,
|
|
NULL,
|
|
CLSCTX_ALL,
|
|
IID_ISEOBindingRuleEngine,
|
|
(LPVOID *) &m_piRuleEngine);
|
|
}
|
|
// See if the 'exclusive' flag has been set.
|
|
m_bExclusive = FALSE;
|
|
hrRes = piBinding->GetVariantA(BD_EXCLUSIVE,&varTmp);
|
|
if (SUCCEEDED(hrRes)) {
|
|
hrRes = varTmp.ChangeType(VT_BOOL);
|
|
if (SUCCEEDED(hrRes)) {
|
|
if (varTmp.boolVal) {
|
|
m_bExclusive = TRUE;
|
|
}
|
|
} else {
|
|
hrRes = varTmp.ChangeType(VT_I4);
|
|
if (SUCCEEDED(hrRes)) {
|
|
if (varTmp.lVal) {
|
|
m_bExclusive = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
varTmp.Clear();
|
|
m_bValid = TRUE;
|
|
return (S_OK);
|
|
}
|
|
|
|
|
|
int CSEOBaseDispatcher::CBinding::Compare(const CBinding& b) const {
|
|
|
|
if (m_dwPriority == b.m_dwPriority) {
|
|
return (0);
|
|
} else {
|
|
return ((m_dwPriority>b.m_dwPriority)?1:-1);
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT CSEOBaseDispatcher::AllocBinding(ISEODictionary *pdictBinding, CBinding **ppbBinding) {
|
|
HRESULT hrRes;
|
|
|
|
if (!ppbBinding) {
|
|
return (E_POINTER);
|
|
}
|
|
*ppbBinding = new CBinding;
|
|
if (!*ppbBinding) {
|
|
return (E_OUTOFMEMORY);
|
|
}
|
|
hrRes = (*ppbBinding)->Init(pdictBinding);
|
|
if (!SUCCEEDED(hrRes)) {
|
|
delete *ppbBinding;
|
|
*ppbBinding = NULL;
|
|
}
|
|
return (hrRes);
|
|
}
|
|
|
|
|
|
static int _cdecl comp_binding(const void *pv1, const void *pv2) {
|
|
const CSEOBaseDispatcher::CBinding **ppb1 = (const CSEOBaseDispatcher::CBinding **) pv1;
|
|
const CSEOBaseDispatcher::CBinding **ppb2 = (const CSEOBaseDispatcher::CBinding **) pv2;
|
|
|
|
return ((*ppb1)->Compare(**ppb2));
|
|
}
|
|
|
|
|
|
HRESULT CSEOBaseDispatcher::Dispatch(CEventParams *pEventParams) {
|
|
BOOL bObjectCalled = FALSE;
|
|
HRESULT hrRes;
|
|
|
|
for (DWORD dwIdx=0;dwIdx<m_dwBindingsCount;dwIdx++) {
|
|
if (!m_apbBindings[dwIdx]->m_bValid) {
|
|
continue;
|
|
}
|
|
if (m_apbBindings[dwIdx]->m_bExclusive && bObjectCalled) {
|
|
continue;
|
|
}
|
|
hrRes = pEventParams->CheckRule(*m_apbBindings[dwIdx]);
|
|
if (hrRes == S_OK) {
|
|
hrRes = pEventParams->CallObject(*m_apbBindings[dwIdx]);
|
|
if ((hrRes == SEO_S_DONEPROCESSING) || m_apbBindings[dwIdx]->m_bExclusive) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return (S_OK);
|
|
}
|