📄 conpoint.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include "common.h"
#include "cobex.h"
#include "conpoint.h"
#include <olectl.h>
CEnumConnectionPoints::CEnumConnectionPoints(IConnectionPoint *pcnpInit)
{
_ulRefs = 1;
_ulIndex = 0;
_pcnp = pcnpInit;
if (_pcnp)
_pcnp->AddRef();
}
CEnumConnectionPoints::~CEnumConnectionPoints()
{
SVSUTIL_ASSERT(_ulRefs == 0);
if (_pcnp)
_pcnp->Release();
}
HRESULT STDMETHODCALLTYPE
CEnumConnectionPoints::Next(ULONG cConnections, LPCONNECTIONPOINT *ppCP, ULONG *pcFetched)
{
if (!ppCP)
return E_POINTER;
*ppCP = NULL;
if ((cConnections == 0) || ((cConnections > 1) && (pcFetched == NULL)))
return E_INVALIDARG;
ULONG cCopied = 0;
if (pcFetched)
*pcFetched = 0;
if (_pcnp != NULL && _ulIndex == 0)
{
*ppCP = _pcnp;
_pcnp->AddRef();
if (pcFetched)
*pcFetched = 1;
_ulIndex = 1;
cCopied = 1;
}
return (cConnections == cCopied) ? S_OK : S_FALSE;
}
HRESULT STDMETHODCALLTYPE
CEnumConnectionPoints::Skip(ULONG cConnections)
{
if (cConnections == 0)
return E_INVALIDARG;
if (_ulIndex > 0 || !_pcnp)
return S_FALSE;
_ulIndex++;
return (cConnections == 1) ? S_OK : S_FALSE;
}
HRESULT STDMETHODCALLTYPE
CEnumConnectionPoints::Reset(void)
{
_ulIndex = 0;
return S_OK;
}
ULONG STDMETHODCALLTYPE
CEnumConnectionPoints::AddRef()
{
return InterlockedIncrement((LONG*)&_ulRefs);
}
ULONG STDMETHODCALLTYPE
CEnumConnectionPoints::Release()
{
ULONG ulRefs;
InterlockedExchange((LONG *)&ulRefs, _ulRefs);
SVSUTIL_ASSERT(ulRefs != 0xffffffff);
if (InterlockedDecrement((LONG*)&_ulRefs) == 0)
{
delete this;
return 0;
}
return ulRefs - 1;
}
HRESULT STDMETHODCALLTYPE
CEnumConnectionPoints::QueryInterface(REFIID riid, void** ppv)
{
if ((riid == IID_IEnumConnectionPoints) || (riid == IID_IUnknown))
{
*ppv = (IEnumConnectionPoints *) this;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
CConnectionPoint::CConnectionPoint(IConnectionPointContainer *pCPC)
{
_ulRefs = 1;
_ulNextCookie = 1;
_pSinkList = NULL;
_ulConns = 0;
_pCPC = pCPC;
if (_pCPC)
_pCPC->AddRef();
}
CConnectionPoint::~CConnectionPoint()
{
SVSUTIL_ASSERT(_ulRefs == 0);
if (_pCPC)
_pCPC->Release();
PSINKNODE pNode = _pSinkList;
while(pNode)
{
SVSUTIL_ASSERT(pNode->pObSink);
PSINKNODE pNode1 = pNode->pNext;
PREFAST_ASSERT(pNode);
PREFAST_ASSERT(pNode->pObSink);
pNode->pObSink->Release();
delete pNode;
pNode = pNode1;
}
}
void
CConnectionPoint::ContainerReleased()
{
SVSUTIL_ASSERT(gpSynch->IsLocked());
PREFAST_ASSERT(_pCPC);
_pCPC->Release();
_pCPC = NULL;
}
//NOTE: the *ONLY* way for this to fail is if it cant get the lock
HRESULT
CConnectionPoint::Notify(OBEX_EVENT evt, IUnknown *pOBEXDevice, IUnknown *pUnk2)
{
SVSUTIL_ASSERT(gpSynch->IsLocked() && pOBEXDevice);
DEBUGMSG(OBEX_COBEX_ZONE,(L"CConnectionPoint::Notify()\n"));
PSINKNODE pSinkNode = _pSinkList;
PSINKNODE pPrev = NULL;
while (pSinkNode)
{
IObexSink *pSink = pSinkNode->pObSink;
pSinkNode->ulFlags |= SN_LOCKED;
PREFAST_ASSERT(pSink);
DEBUGMSG(OBEX_COBEX_ZONE,(L"CConnectionPoint::Notify- Unlocking, going out to notify(event=%d, pSink=0x%08x)\n", evt, pSink));
ReleaseLock();
//run the sinks Notify
HRESULT hr = pSink->Notify(evt, pOBEXDevice, pUnk2);
if(!GetLock())
return E_FAIL;
//Notify is always called on the EnumThread, and hence is assured that g_pObex will remain initialized
DEBUGMSG(OBEX_COBEX_ZONE,(L"CConnectionPoint::Notify- Got lock. Notify returned 0x%08x\n", hr));
pSinkNode->ulFlags &= ~SN_LOCKED;
//if the sink node was marked for removal when we unlocked and went out to
// notify, remove it now
if (pSinkNode->ulFlags & SN_REMOVED)
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CConnectionPoint::Notify - Node 0x%08x marked for removal during Notify.Removing it now.\n", pSinkNode));
if (!pPrev)
_pSinkList = pSinkNode->pNext;
else
pPrev->pNext = pSinkNode->pNext;
PSINKNODE pCurrent = pSinkNode->pNext;
PREFAST_ASSERT(pSinkNode);
PREFAST_ASSERT(pSinkNode->pObSink);
pSinkNode->pObSink->Release();
delete pSinkNode;
_ulConns--;
pSinkNode = pCurrent;
}
else
{
pPrev = pSinkNode;
pSinkNode = pSinkNode->pNext;
}
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE
CConnectionPoint::GetConnectionInterface(IID *pIID)
{
if (!pIID)
return E_POINTER;
*pIID = IID_IObexSink;
return S_OK;
}
HRESULT STDMETHODCALLTYPE
CConnectionPoint::GetConnectionPointContainer(IConnectionPointContainer **ppCPC)
{
if (!ppCPC)
return E_POINTER;
*ppCPC = NULL;
if (!GetLock())
return E_FAIL;
HRESULT hr = E_FAIL;
*ppCPC = _pCPC;
if (_pCPC)
{
_pCPC->AddRef();
hr = S_OK;
}
ReleaseLock();
return hr;
}
HRESULT STDMETHODCALLTYPE
CConnectionPoint::Advise(IUnknown *pUnkSink, DWORD *pdwCookie)
{
if ((!pUnkSink) || (!pdwCookie))
return E_POINTER;
*pdwCookie = 0;
//make sure this IUnknown pointer supports IObexSink
IObexSink *pObSink = NULL;
HRESULT hr = pUnkSink->QueryInterface(IID_IObexSink, (LPVOID *)&pObSink);
if ((FAILED(hr)) || (!pObSink) )
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CConnectionPoint::Advise - Interface does not support IObexSink()\n"));
return CONNECT_E_CANNOTCONNECT;
}
hr = E_FAIL;
SINKNODE *pSink = NULL;
if (!GetLock())
return hr;
SVSUTIL_ASSERT(pObSink);
//chain in the Sink
pSink = new SINKNODE;
if (pSink)
{
pSink->ulFlags = 0;
//ref the sink and put it in the linked list
pObSink->AddRef();
pSink->pObSink = pObSink;
pSink->ulCookie = _ulNextCookie++;
pSink->pNext = _pSinkList;
*pdwCookie = pSink->ulCookie;
_pSinkList = pSink;
_ulConns++;
hr = S_OK;
DEBUGMSG(OBEX_COBEX_ZONE,(L"CConnectionPoint::Advise - pUnkSink=0x%08x, Cookie=%d\n", pUnkSink, _pSinkList->ulCookie));
}
else
{
hr = E_OUTOFMEMORY;
DEBUGMSG(OBEX_COBEX_ZONE, (L"CConnectionPoint::Advise(pUnkSink=0x%08x) fails. E_OUTOFMEMORY\n", pUnkSink));
}
if(pObSink)
pObSink->Release();
ReleaseLock();
return hr;
}
HRESULT STDMETHODCALLTYPE
CConnectionPoint::Unadvise(DWORD dwCookie)
{
DEBUGMSG(OBEX_COBEX_ZONE,(L"CConnectionPoint::Unadvise - Cookie=%d\n", dwCookie));
if (!dwCookie)
return E_INVALIDARG;
HRESULT hr = E_FAIL;
if (!GetLock())
return hr;
PSINKNODE pSinkNode = _pSinkList;
PSINKNODE pPrev = NULL;
while(pSinkNode)
{
if (pSinkNode->ulCookie == dwCookie)
{
pSinkNode->ulFlags |= SN_REMOVED;
if (!(pSinkNode->ulFlags & SN_LOCKED))
{
if (!pPrev)
_pSinkList = pSinkNode->pNext;
else
pPrev->pNext = pSinkNode->pNext;
PREFAST_ASSERT(pSinkNode->pObSink);
pSinkNode->pObSink->Release();
delete pSinkNode;
_ulConns--;
}
DEBUGMSG(OBEX_COBEX_ZONE,(L"CConnectionPoint::Unadvise : Removed Cookie=%d\n", dwCookie));
ReleaseLock();
return S_OK;
};
pPrev = pSinkNode;
pSinkNode = pSinkNode->pNext;
}
SVSUTIL_ASSERT(pSinkNode == NULL);
DEBUGMSG(OBEX_COBEX_ZONE,(L"CConnectionPoint::Unadvise : Missing Cookie=%d\n", dwCookie));
ReleaseLock();
return CONNECT_E_CANNOTCONNECT;
}
HRESULT STDMETHODCALLTYPE
CConnectionPoint::EnumConnections(IEnumConnections **ppEnum)
{
if (!ppEnum)
return E_POINTER;
*ppEnum = NULL;
HRESULT hr = E_FAIL;
if (!GetLock())
return hr;
CEnumConnections *pEnum = new CEnumConnections();
if (pEnum)
{
hr = pEnum->Init(_pSinkList, _ulConns);
if (SUCCEEDED(hr))
{
*ppEnum = (IEnumConnections *)pEnum;
(*ppEnum)->AddRef();
hr = S_OK;
}
pEnum->Release();
}
else
hr = E_OUTOFMEMORY;
ReleaseLock();
return hr;
}
ULONG STDMETHODCALLTYPE
CConnectionPoint::AddRef()
{
return InterlockedIncrement((LONG*)&_ulRefs);
}
ULONG STDMETHODCALLTYPE
CConnectionPoint::Release()
{
ULONG ulRefs;
InterlockedExchange((LONG *)&ulRefs, _ulRefs);
SVSUTIL_ASSERT(ulRefs != 0xffffffff);
if (InterlockedDecrement((LONG*)&_ulRefs) == 0)
{
delete this;
return 0;
}
return ulRefs - 1;
}
HRESULT STDMETHODCALLTYPE
CConnectionPoint::QueryInterface(REFIID riid, void** ppv)
{
if ((riid == IID_IConnectionPoint) || (riid == IID_IUnknown))
{
*ppv = (IConnectionPoint *) this;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////
CEnumConnections::CEnumConnections()
{
_ulRefs = 1;
_ulIndex = 0;
_ulConns = 0;
_pConnData = NULL;
}
CEnumConnections::~CEnumConnections()
{
SVSUTIL_ASSERT(_ulRefs == 0);
if (_pConnData)
{
for (ULONG i=0; i<_ulConns; i++)
{
PREFAST_ASSERT(_pConnData[i].pUnk);
_pConnData[i].pUnk->Release();
}
}
delete[] _pConnData;
_pConnData = NULL;
}
HRESULT
CEnumConnections::Init(SINKNODE *pSinkList, ULONG ulConns)
{
//
// 100 is arbituary, it should be safe this big but realistically
// never get there
if (!ulConns || ulConns > 100)
{
SVSUTIL_ASSERT(!pSinkList);
return S_FALSE;
}
if (!pSinkList)
return E_INVALIDARG;
SVSUTIL_ASSERT(gpSynch->IsLocked());
_pConnData = new CONNECTDATA[ulConns];
if (!_pConnData)
return E_OUTOFMEMORY;
for (ULONG i=0; (pSinkList) && (i<ulConns); i++)
{
_pConnData[i].pUnk = (IUnknown *)pSinkList->pObSink;
_pConnData[i].pUnk->AddRef();
_pConnData[i].dwCookie = pSinkList->ulCookie;
pSinkList = pSinkList->pNext;
}
if (i==ulConns && pSinkList == NULL)
{
_ulConns = ulConns;
return S_OK;
}
delete[] _pConnData;
_ulConns = 0;
return E_FAIL;
}
HRESULT STDMETHODCALLTYPE
CEnumConnections::Next(ULONG cConnections, CONNECTDATA *pCD, ULONG *pcFetched)
{
if (!pCD)
return E_POINTER;
if ((cConnections == 0) || ((cConnections > 1) && (pcFetched == NULL)))
return E_INVALIDARG;
ULONG cCopied = 0;
if (pcFetched)
*pcFetched = 0;
if (_pConnData != NULL && _ulIndex < _ulConns)
{
while(_ulIndex < _ulConns)
{
pCD[cCopied].pUnk = _pConnData[_ulIndex].pUnk;
pCD[cCopied].pUnk->AddRef();
pCD[cCopied].dwCookie = _pConnData[_ulIndex].dwCookie;
cCopied++;
_ulIndex++;
}
if (pcFetched)
*pcFetched = cCopied;
}
return (cConnections == cCopied) ? S_OK : S_FALSE;
}
HRESULT STDMETHODCALLTYPE
CEnumConnections::Skip(ULONG cConnections)
{
if (cConnections == 0)
return E_INVALIDARG;
if (_ulIndex + cConnections >= _ulConns)
{
_ulIndex = _ulConns;
return S_FALSE;
}
else
{
_ulIndex += cConnections;
return S_OK;
}
}
HRESULT STDMETHODCALLTYPE
CEnumConnections::Reset(void)
{
_ulIndex = 0;
return S_OK;
}
ULONG STDMETHODCALLTYPE
CEnumConnections::AddRef()
{
return InterlockedIncrement((LONG*)&_ulRefs);
}
ULONG STDMETHODCALLTYPE
CEnumConnections::Release()
{
ULONG ulRefs;
InterlockedExchange((LONG *)&ulRefs, _ulRefs);
SVSUTIL_ASSERT(ulRefs != 0xffffffff);
if (InterlockedDecrement((LONG*)&_ulRefs) == 0)
{
delete this;
return 0;
}
return ulRefs - 1;
}
HRESULT STDMETHODCALLTYPE
CEnumConnections::QueryInterface(REFIID riid, void** ppv)
{
if ((riid == IID_IEnumConnections) || (riid == IID_IUnknown))
{
*ppv = (IEnumConnections *) this;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -