//**************************************************************************** // // Module: ULS.DLL // File: connpt.cpp // Content: This file contains the conection point object. // History: // Wed 17-Apr-1996 11:13:54 -by- Viroon Touranachun [viroont] // // Copyright (c) Microsoft Corporation 1995-1996 // //**************************************************************************** #include "ulsp.h" #include "connpt.h" //**************************************************************************** // CEnumConnectionPoints::CEnumConnectionPoints (void) // // History: // Wed 17-Apr-1996 11:15:18 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** CEnumConnectionPoints::CEnumConnectionPoints (void) { cRef = 0; iIndex = 0; pcnp = NULL; return; } //**************************************************************************** // CEnumConnectionPoints::~CEnumConnectionPoints (void) // // History: // Wed 17-Apr-1996 11:15:18 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** CEnumConnectionPoints::~CEnumConnectionPoints (void) { if (pcnp != NULL) { pcnp->Release(); }; return; } //**************************************************************************** // STDMETHODIMP // CEnumConnectionPoints::Init (IConnectionPoint *pcnpInit) // // History: // Wed 17-Apr-1996 11:15:25 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CEnumConnectionPoints::Init (IConnectionPoint *pcnpInit) { iIndex = 0; pcnp = pcnpInit; if (pcnp != NULL) { pcnp->AddRef(); }; return S_OK; } //**************************************************************************** // STDMETHODIMP // CEnumConnectionPoints::QueryInterface (REFIID riid, void **ppv) // // History: // Wed 17-Apr-1996 11:15:31 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CEnumConnectionPoints::QueryInterface (REFIID riid, void **ppv) { if (riid == IID_IEnumConnectionPoints || riid == IID_IUnknown) { *ppv = (IEnumConnectionPoints *) this; AddRef(); return S_OK; } else { *ppv = NULL; return ILS_E_NO_INTERFACE; }; } //**************************************************************************** // STDMETHODIMP_(ULONG) // CEnumConnectionPoints::AddRef (void) // // History: // Wed 17-Apr-1996 11:15:37 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP_(ULONG) CEnumConnectionPoints::AddRef (void) { DllLock(); MyDebugMsg ((DM_REFCOUNT, "CEnumConnectionPoints::AddRef: ref=%ld\r\n", cRef)); ::InterlockedIncrement ((LONG *) &cRef); return cRef; } //**************************************************************************** // STDMETHODIMP_(ULONG) // CEnumConnectionPoints::Release (void) // // History: // Wed 17-Apr-1996 11:15:43 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP_(ULONG) CEnumConnectionPoints::Release (void) { DllRelease(); ASSERT (cRef > 0); MyDebugMsg ((DM_REFCOUNT, "CEnumConnectionPoints::Release: ref=%ld\r\n", cRef)); if (::InterlockedDecrement ((LONG *) &cRef) == 0) { delete this; return 0; } return cRef; } //**************************************************************************** // STDMETHODIMP // CEnumConnectionPoints::Next (ULONG cConnections, // IConnectionPoint **rgpcn, // ULONG *pcFetched) // // History: // Wed 17-Apr-1996 11:15:49 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CEnumConnectionPoints::Next (ULONG cConnections, IConnectionPoint **rgpcn, ULONG *pcFetched) { ULONG cCopied; // Validate the pointer // if (rgpcn == NULL) return ILS_E_POINTER; // Validate the parameters // if ((cConnections == 0) || ((cConnections > 1) && (pcFetched == NULL))) return ILS_E_PARAMETER; // Check the enumeration index // cCopied = 0; if ((pcnp != NULL) && (iIndex == 0)) { // Return the only connection point // *rgpcn = pcnp; (*rgpcn)->AddRef(); iIndex++; cCopied++; }; // Determine the returned information based on other parameters // if (pcFetched != NULL) { *pcFetched = cCopied; }; return (cConnections == cCopied ? S_OK : S_FALSE); } //**************************************************************************** // STDMETHODIMP // CEnumConnectionPoints::Skip (ULONG cConnections) // // History: // Wed 17-Apr-1996 11:15:56 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CEnumConnectionPoints::Skip (ULONG cConnections) { // Validate the parameters // if (cConnections == 0) return ILS_E_PARAMETER; // Check the enumeration index limit // if ((pcnp == NULL) || (iIndex > 0)) { return S_FALSE; } else { // Skip the only elelment // iIndex++; return (cConnections == 1 ? S_OK : S_FALSE); }; } //**************************************************************************** // STDMETHODIMP // CEnumConnectionPoints::Reset (void) // // History: // Wed 17-Apr-1996 11:16:02 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CEnumConnectionPoints::Reset (void) { iIndex = 0; return S_OK; } //**************************************************************************** // STDMETHODIMP // CEnumConnectionPoints::Clone(IEnumConnectionPoints **ppEnum) // // History: // Wed 17-Apr-1996 11:16:11 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CEnumConnectionPoints::Clone(IEnumConnectionPoints **ppEnum) { CEnumConnectionPoints *pecp; // Validate parameters // if (ppEnum == NULL) { return ILS_E_POINTER; }; *ppEnum = NULL; // Create an enumerator // pecp = new CEnumConnectionPoints; if (pecp == NULL) return ILS_E_MEMORY; // Clone the information // pecp->iIndex = iIndex; pecp->pcnp = pcnp; if (pcnp != NULL) { pcnp->AddRef(); }; // Return the cloned enumerator // pecp->AddRef(); *ppEnum = pecp; return S_OK; } //**************************************************************************** // CConnectionPoint::CConnectionPoint (const IID *pIID, // IConnectionPointContainer *pCPCInit) // // History: // Wed 17-Apr-1996 11:16:17 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** CConnectionPoint::CConnectionPoint (const IID *pIID, IConnectionPointContainer *pCPCInit) { cRef = 0; riid = *pIID; pCPC = pCPCInit; dwNextCookie = COOKIE_INIT_VALUE; cSinkNodes = 0; pSinkList = NULL; return; } //**************************************************************************** // CConnectionPoint::~CConnectionPoint (void) // // History: // Wed 17-Apr-1996 11:16:17 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** CConnectionPoint::~CConnectionPoint (void) { PSINKNODE pSinkNode; // Traverse the sink list and free each one of them // while (pSinkList != NULL) { pSinkNode = pSinkList; pSinkList = pSinkNode->pNext; pSinkNode->pUnk->Release(); delete pSinkNode; }; return; } //**************************************************************************** // STDMETHODIMP // CConnectionPoint::QueryInterface (REFIID riid, void **ppv) // // History: // Wed 17-Apr-1996 11:16:23 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CConnectionPoint::QueryInterface (REFIID riid, void **ppv) { if (riid == IID_IConnectionPoint || riid == IID_IUnknown) { *ppv = (IConnectionPoint *) this; AddRef(); return S_OK; } else { *ppv = NULL; return ILS_E_NO_INTERFACE; }; } //**************************************************************************** // STDMETHODIMP_(ULONG) // CConnectionPoint::AddRef (void) // // History: // Wed 17-Apr-1996 11:16:30 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP_(ULONG) CConnectionPoint::AddRef (void) { DllLock(); MyDebugMsg ((DM_REFCOUNT, "CConnectionPoint::AddRef: ref=%ld\r\n", cRef)); ::InterlockedIncrement ((LONG *) &cRef); return cRef; } //**************************************************************************** // STDMETHODIMP_(ULONG) // CConnectionPoint::Release (void) // // History: // Wed 17-Apr-1996 11:16:36 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP_(ULONG) CConnectionPoint::Release (void) { DllRelease(); ASSERT (cRef > 0); MyDebugMsg ((DM_REFCOUNT, "CConnectionPoint::Release: ref=%ld\r\n", cRef)); if (::InterlockedDecrement ((LONG *) &cRef) == 0) { delete this; return 0; } return cRef; } //**************************************************************************** // STDMETHODIMP // CConnectionPoint::Notify(void *pv, CONN_NOTIFYPROC pfn) // // History: // Wed 17-Apr-1996 11:16:43 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CConnectionPoint::Notify(void *pv, CONN_NOTIFYPROC pfn) { PSINKNODE pSinkNode, pPrev; IUnknown *pUnk; BOOL fNeedClear; HRESULT hr; // Enumerate each connection // pSinkNode = pSinkList; hr = S_OK; fNeedClear = FALSE; while((pSinkNode != NULL) && (SUCCEEDED(hr))) { // Important!! Important!! // Lock the sink object here. Need to do this in case that the sink // object calls back to Unadvise and we remove this sink node during // callback. // pSinkNode->uFlags |= SN_LOCKED; pUnk = pSinkNode->pUnk; // Calls the sink object // Note: Do not need to reference the sink object again. // We already did when Advise was called. // hr = (*pfn)(pUnk, pv); pSinkNode->uFlags &= ~SN_LOCKED; if (pSinkNode->uFlags & SN_REMOVED) { fNeedClear = TRUE; }; pSinkNode = pSinkNode->pNext; }; // If there is at least one node to free // if (fNeedClear) { // Traverse the list for nodes to remove // pSinkNode = pSinkList; pPrev = NULL; while (pSinkNode != NULL) { // Release the sink object, if unadvise // if (pSinkNode->uFlags & SN_REMOVED) { PSINKNODE pNext; pNext = pSinkNode->pNext; if (pPrev == NULL) { // This is the head of the list // pSinkList = pNext; } else { pPrev->pNext = pNext; }; pSinkNode->pUnk->Release(); cSinkNodes--; delete pSinkNode; pSinkNode = pNext; } else { pPrev = pSinkNode; pSinkNode = pSinkNode->pNext; }; }; }; return hr; } //**************************************************************************** // STDMETHODIMP // CConnectionPoint::GetConnectionInterface(IID *pIID) // // History: // Wed 17-Apr-1996 11:16:43 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CConnectionPoint::GetConnectionInterface(IID *pIID) { // Validate the parameter // if (pIID == NULL) return ILS_E_POINTER; // Support only one connection interface // *pIID = riid; return S_OK; } //**************************************************************************** // STDMETHODIMP // CConnectionPoint::GetConnectionPointContainer(IConnectionPointContainer **ppCPC) // // History: // Wed 17-Apr-1996 11:16:49 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CConnectionPoint::GetConnectionPointContainer(IConnectionPointContainer **ppCPC) { // Validate the parameter // if (ppCPC == NULL) return ILS_E_POINTER; // Return the container and add its reference count // *ppCPC = pCPC; if (pCPC != NULL) { // The container is still alive // pCPC->AddRef(); return S_OK; } else { // The container no longer exists // return ILS_E_FAIL; }; } //**************************************************************************** // STDMETHODIMP // CConnectionPoint::Advise(IUnknown *pUnk, DWORD *pdwCookie) // // History: // Wed 17-Apr-1996 11:17:01 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CConnectionPoint::Advise(IUnknown *pUnk, DWORD *pdwCookie) { PSINKNODE pSinkNode; IUnknown *pSinkInterface; // Validate the parameter // if ((pUnk == NULL) || (pdwCookie == NULL)) return ILS_E_PARAMETER; // Get the sink interface // if (FAILED(pUnk->QueryInterface(riid, (void **)&pSinkInterface))) return CONNECT_E_CANNOTCONNECT; // Create the sink node // pSinkNode = new SINKNODE; pSinkNode->pNext = pSinkList; pSinkNode->pUnk = pSinkInterface; pSinkNode->dwCookie = dwNextCookie; pSinkNode->uFlags = 0; *pdwCookie = dwNextCookie; // Put it in the sink list // pSinkList = pSinkNode; dwNextCookie++; cSinkNodes++; return S_OK; } //**************************************************************************** // STDMETHODIMP // CConnectionPoint::Unadvise(DWORD dwCookie) // // History: // Wed 17-Apr-1996 11:17:09 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CConnectionPoint::Unadvise(DWORD dwCookie) { PSINKNODE pSinkNode, pPrev; // Search for the matching sink object // pPrev = NULL; pSinkNode = pSinkList; // Traverse the sink list to find the specified sink object // while (pSinkNode != NULL) { if (pSinkNode->dwCookie == dwCookie) { // Flag to remove // pSinkNode->uFlags |= SN_REMOVED; break; }; pPrev = pSinkNode; pSinkNode = pSinkNode->pNext; }; // Have we found the specified sink object? // if (pSinkNode == NULL) { // No, return failure // return CONNECT_E_NOCONNECTION; }; // Release the sink object, if not locked // if ((pSinkNode->uFlags & SN_REMOVED) && !(pSinkNode->uFlags & SN_LOCKED)) { // Is there a previous node? // if (pPrev == NULL) { // This is the head of the list // pSinkList = pSinkNode->pNext; } else { pPrev->pNext = pSinkNode->pNext; }; pSinkNode->pUnk->Release(); cSinkNodes--; delete pSinkNode; }; return S_OK; } //**************************************************************************** // STDMETHODIMP // CConnectionPoint::EnumConnections(IEnumConnections **ppEnum) // // History: // Wed 17-Apr-1996 11:17:18 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CConnectionPoint::EnumConnections(IEnumConnections **ppEnum) { CEnumConnections *pecn; HRESULT hr; // Validate parameters // if (ppEnum == NULL) { return ILS_E_POINTER; }; // Assume failure // *ppEnum = NULL; // Create an enumerator // pecn = new CEnumConnections; if (pecn == NULL) return ILS_E_MEMORY; // Initialize the enumerator // hr = pecn->Init(pSinkList, cSinkNodes); if (FAILED(hr)) { delete pecn; return hr; }; pecn->AddRef(); *ppEnum = pecn; return S_OK; } //**************************************************************************** // CEnumConnections::CEnumConnections(void) // // History: // Wed 17-Apr-1996 11:17:25 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** CEnumConnections::CEnumConnections(void) { cRef = 0; iIndex = 0; cConnections = 0; pConnectData = NULL; return; } //**************************************************************************** // CEnumConnections::~CEnumConnections(void) // // History: // Wed 17-Apr-1996 11:17:25 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** CEnumConnections::~CEnumConnections(void) { if (pConnectData != NULL) { UINT i; for (i = 0; i < cConnections; i++) { pConnectData[i].pUnk->Release(); }; delete [] pConnectData; }; return; } //**************************************************************************** // STDMETHODIMP // CEnumConnections::Init(PSINKNODE pSinkList, ULONG cSinkNodes) // // History: // Wed 17-Apr-1996 11:17:34 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CEnumConnections::Init(PSINKNODE pSinkList, ULONG cSinkNodes) { HRESULT hr = S_OK; iIndex = 0; cConnections = 0; pConnectData = NULL; // Snapshot the connection list // if (cSinkNodes > 0) { UINT i; pConnectData = new CONNECTDATA[cSinkNodes]; if (pConnectData != NULL) { for (i = 0; i < cSinkNodes && pSinkList != NULL; i++) { if (!(pSinkList->uFlags & SN_REMOVED)) { pConnectData[cConnections].pUnk = pSinkList->pUnk; pConnectData[cConnections].pUnk->AddRef(); pConnectData[cConnections].dwCookie = pSinkList->dwCookie; cConnections++; }; pSinkList = pSinkList->pNext; }; } else { hr = ILS_E_MEMORY; }; }; return hr; } //**************************************************************************** // STDMETHODIMP // CEnumConnections::QueryInterface (REFIID riid, void **ppv) // // History: // Wed 17-Apr-1996 11:17:40 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CEnumConnections::QueryInterface (REFIID riid, void **ppv) { if (riid == IID_IEnumConnections || riid == IID_IUnknown) { *ppv = (IEnumConnections *) this; AddRef(); return S_OK; } else { *ppv = NULL; return ILS_E_NO_INTERFACE; }; } //**************************************************************************** // STDMETHODIMP_(ULONG) // CEnumConnections::AddRef (void) // // History: // Wed 17-Apr-1996 11:17:49 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP_(ULONG) CEnumConnections::AddRef (void) { DllLock(); MyDebugMsg ((DM_REFCOUNT, "CEnumConnections::AddRef: ref=%ld\r\n", cRef)); ::InterlockedIncrement ((LONG *) &cRef); return cRef; } //**************************************************************************** // STDMETHODIMP_(ULONG) // CEnumConnections::Release (void) // // History: // Wed 17-Apr-1996 11:17:59 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP_(ULONG) CEnumConnections::Release (void) { DllRelease(); ASSERT (cRef > 0); MyDebugMsg ((DM_REFCOUNT, "CEnumConnections::Release: ref=%ld\r\n", cRef)); if (::InterlockedDecrement ((LONG *) &cRef) == 0) { delete this; return 0; } return cRef; } //**************************************************************************** // STDMETHODIMP // CEnumConnections::Next (ULONG cConnectionDatas, CONNECTDATA *rgpcd, // ULONG *pcFetched) // // History: // Wed 17-Apr-1996 11:18:07 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CEnumConnections::Next (ULONG cConnectDatas, CONNECTDATA *rgpcd, ULONG *pcFetched) { CONNECTDATA *pConnect; ULONG cCopied; // Validate the pointer // if (rgpcd == NULL) return ILS_E_POINTER; // Validate the parameters // if ((cConnectDatas == 0) || ((cConnectDatas > 1) && (pcFetched == NULL))) return ILS_E_PARAMETER; // Check the enumeration index // pConnect = &pConnectData[iIndex]; for (cCopied = 0; iIndex < cConnections && cCopied < cConnectDatas; cCopied++) { rgpcd[cCopied] = *pConnect; rgpcd[cCopied].pUnk->AddRef(); iIndex++; pConnect++; }; // Determine the returned information based on other parameters // if (pcFetched != NULL) { *pcFetched = cCopied; }; return (cConnectDatas == cCopied ? S_OK : S_FALSE); } //**************************************************************************** // STDMETHODIMP // CEnumConnections::Skip (ULONG cConnectDatas) // // History: // Wed 17-Apr-1996 11:18:15 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CEnumConnections::Skip (ULONG cConnectDatas) { // Validate the parameters // if (cConnectDatas == 0) return ILS_E_PARAMETER; // Check the enumeration index limit // if ((iIndex+cConnectDatas) >= cConnections) { iIndex = cConnections; return S_FALSE; } else { // Skip as requested // iIndex += cConnectDatas; return S_OK; }; } //**************************************************************************** // STDMETHODIMP // CEnumConnections::Reset (void) // // History: // Wed 17-Apr-1996 11:18:22 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CEnumConnections::Reset (void) { iIndex = 0; return S_OK; } //**************************************************************************** // STDMETHODIMP // CEnumConnections::Clone(IEnumConnections **ppEnum) // // History: // Wed 17-Apr-1996 11:18:29 -by- Viroon Touranachun [viroont] // Created. //**************************************************************************** STDMETHODIMP CEnumConnections::Clone(IEnumConnections **ppEnum) { CEnumConnections *pecn; CONNECTDATA *pConnectDataClone; UINT i; // Validate parameters // if (ppEnum == NULL) { return ILS_E_POINTER; }; *ppEnum = NULL; // Create an enumerator // pecn = new CEnumConnections; if (pecn == NULL) return ILS_E_MEMORY; // Clone the information // pConnectDataClone = new CONNECTDATA[cConnections]; if (pConnectDataClone == NULL) { delete pecn; return ILS_E_MEMORY; }; // Clone the connect data list // for (i = 0; i < cConnections; i++) { pConnectDataClone[i] = pConnectData[i]; pConnectDataClone[i].pUnk->AddRef(); }; pecn->iIndex = iIndex; pecn->cConnections = cConnections; // Return the cloned enumerator // pecn->AddRef(); *ppEnum = pecn; return S_OK; }