/**********************************************************************/
/**                       Microsoft Windows/NT                       **/
/**                Copyright(c) Microsoft Corporation, 1997 - 1999 **/
/**********************************************************************/

/*
	infopriv.cpp
		
    FILE HISTORY:
        
*/

#include "stdafx.h"
#include "infoi.h"
#include "rtrstr.h"			// common router strings
#include "rtrdata.h"		// CRouterDataObject
#include "setupapi.h"		// SetupDi* functions

static const GUID GUID_DevClass_Net = {0x4D36E972,0xE325,0x11CE,{0xBF,0xC1,0x08,0x00,0x2B,0xE1,0x03,0x18}};


typedef DWORD (APIENTRY* PRASRPCCONNECTSERVER)(LPTSTR, HANDLE *);
typedef DWORD (APIENTRY* PRASRPCDISCONNECTSERVER)(HANDLE);
typedef DWORD (APIENTRY* PRASRPCREMOTEGETSYSTEMDIRECTORY)(HANDLE, LPTSTR, UINT);
typedef DWORD (APIENTRY* PRASRPCREMOTERASDELETEENTRY)(HANDLE, LPTSTR, LPTSTR);

HRESULT RasPhoneBookRemoveInterface(LPCTSTR pszMachine, LPCTSTR pszIf)
{			
	CString		stPath;
	DWORD		dwErr;
	HINSTANCE	hrpcdll = NULL;
	TCHAR		szSysDir[MAX_PATH+1];

	PRASRPCCONNECTSERVER pRasRpcConnectServer;
	PRASRPCDISCONNECTSERVER pRasRpcDisconnectServer;
	PRASRPCREMOTEGETSYSTEMDIRECTORY pRasRpcRemoteGetSystemDirectory;
	PRASRPCREMOTERASDELETEENTRY pRasRpcRemoteRasDeleteEntry;
	HANDLE hConnection = NULL;

	if (!(hrpcdll = LoadLibrary(TEXT("rasman.dll"))) ||
		!(pRasRpcConnectServer = (PRASRPCCONNECTSERVER)GetProcAddress(
											hrpcdll, "RasRpcConnectServer"
		)) ||
		!(pRasRpcDisconnectServer = (PRASRPCDISCONNECTSERVER)GetProcAddress(
											hrpcdll, "RasRpcDisconnectServer"
		)) ||
		!(pRasRpcRemoteGetSystemDirectory =
							   (PRASRPCREMOTEGETSYSTEMDIRECTORY)GetProcAddress(
									hrpcdll, "RasRpcRemoteGetSystemDirectory"
		)) ||
		!(pRasRpcRemoteRasDeleteEntry =
								(PRASRPCREMOTERASDELETEENTRY)GetProcAddress(
									hrpcdll, "RasRpcRemoteRasDeleteEntry"
		)))
		{
			
			if (hrpcdll) { FreeLibrary(hrpcdll); }
			return hrOK;
		}
				
	dwErr = pRasRpcConnectServer((LPTSTR)pszMachine, &hConnection);
	
	if (dwErr == NO_ERROR)
	{
		szSysDir[0] = TEXT('\0');

		//$ Review: kennt, are these functions WIDE or ANSI?
		// We can't just pass in TCHARs.  Since we're dynamically
		// linking to these functions we need to know.
		
		// This is bogus, if this call fails we don't know what to do
		pRasRpcRemoteGetSystemDirectory(hConnection, szSysDir, MAX_PATH);
		
		stPath.Format(TEXT("%s\\RAS\\%s"), szSysDir, c_szRouterPbk);
		
		dwErr = pRasRpcRemoteRasDeleteEntry(
		                            hConnection,
									(LPTSTR)(LPCTSTR)stPath,
									(LPTSTR)(LPCTSTR)pszIf
								   );
		pRasRpcDisconnectServer(hConnection);
	}

    if (hrpcdll)
        FreeLibrary(hrpcdll);
	
	return HRESULT_FROM_WIN32(dwErr);
}




/*---------------------------------------------------------------------------
	CNetcardRegistryHelper implemenation
 ---------------------------------------------------------------------------*/


/*!--------------------------------------------------------------------------
	CNetcardRegistryHelper::CNetcardRegistryHelper
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
CNetcardRegistryHelper::CNetcardRegistryHelper()
	: m_hkeyBase(NULL),
	m_hkeyService(NULL),
	m_hkeyTitle(NULL),
    m_hkeyConnection(NULL),
	m_fInit(FALSE),
	m_fNt4(FALSE),
	m_hDevInfo(INVALID_HANDLE_VALUE)
{
}

/*!--------------------------------------------------------------------------
	CNetcardRegistryHelper::~CNetcardRegistryHelper
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
CNetcardRegistryHelper::~CNetcardRegistryHelper()
{
    FreeDevInfo();

 	if (m_hkeyTitle && (m_hkeyTitle != m_hkeyBase))
		::RegCloseKey(m_hkeyTitle);

    if (m_hkeyService && (m_hkeyService != m_hkeyBase))
		::RegCloseKey(m_hkeyService);

    if (m_hkeyConnection)
        ::RegCloseKey(m_hkeyConnection);
}

void CNetcardRegistryHelper::FreeDevInfo()
{
	if (m_hDevInfo != INVALID_HANDLE_VALUE)
	{
		SetupDiDestroyDeviceInfoList(m_hDevInfo);
		m_hDevInfo = INVALID_HANDLE_VALUE;
	}
}

/*!--------------------------------------------------------------------------
	CNetcardRegistryHelper::Initialize
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
void CNetcardRegistryHelper::Initialize(BOOL fNt4, HKEY hkeyBase, LPCTSTR pszKeyBase, LPCTSTR pszMachineName)
{
	m_fNt4 = fNt4;
	m_hkeyBase = hkeyBase;
	m_hkeyService = NULL;
	m_hkeyTitle = NULL;
	m_fInit = FALSE;
	m_stService.Empty();
	m_stTitle.Empty();
	m_stKeyBase = pszKeyBase;
	m_stMachineName.Empty();

    
    // Get the connection registry key
    if (!m_fNt4 && hkeyBase)
    {
        if (m_hkeyConnection != NULL)
        {
            RegCloseKey(m_hkeyConnection);
            m_hkeyConnection = NULL;
        }
        
        if (RegOpenKey(hkeyBase, c_szRegKeyConnection, &m_hkeyConnection)
                != ERROR_SUCCESS)
        {
            m_hkeyConnection = NULL;
        }
    }

    // Get up the setup api info
	if (!m_fNt4)
	{
        FreeDevInfo();

        if (IsLocalMachine(pszMachineName))
		{
			m_hDevInfo = SetupDiCreateDeviceInfoList((LPGUID) &GUID_DevClass_Net, NULL);
		}
		else
		{
			if (StrniCmp(pszMachineName, _T("\\\\"), 2) != 0)
			{
				m_stMachineName = _T("\\\\");
				m_stMachineName += pszMachineName;
			}
			else
				m_stMachineName = pszMachineName;
			
			m_hDevInfo = SetupDiCreateDeviceInfoListEx(
				(LPGUID) &GUID_DevClass_Net,
				NULL,
				(LPCTSTR) m_stMachineName,
				0);
		}
	}
		
}

/*!--------------------------------------------------------------------------
	CNetcardRegistryHelper::ReadServiceName
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
DWORD CNetcardRegistryHelper::ReadServiceName()
{
	DWORD	dwErr = ERROR_SUCCESS;
	LPCTSTR	pszService;

	dwErr = PrivateInit();
	if (dwErr != ERROR_SUCCESS)
		return dwErr;

	Assert(m_fNt4);

	pszService = m_fNt4 ? c_szServiceName : c_szService;

	dwErr = ReadRegistryCString(_T(""), pszService,
								m_hkeyService, &m_stService);
	return dwErr;
}

/*!--------------------------------------------------------------------------
	CNetcardRegistryHelper::GetServiceName
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
LPCTSTR CNetcardRegistryHelper::GetServiceName()
{
	ASSERT(m_fInit);
	return m_stService;
}

/*!--------------------------------------------------------------------------
	CNetcardRegistryHelper::ReadTitle
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
DWORD CNetcardRegistryHelper::ReadTitle()
{
	DWORD	dwErr = ERROR_SUCCESS;
	CString	stTemp;
	TCHAR		szDesc[1024];
	
	dwErr = PrivateInit();
	if (dwErr != ERROR_SUCCESS)
		return dwErr;

	if (m_fNt4)
	{
		dwErr = ReadRegistryCString(_T(""), c_szTitle,
									m_hkeyTitle, &stTemp);
		if (dwErr == ERROR_SUCCESS)
			m_stTitle = stTemp;
	}
	else
	{
		
		//$NT5
		SPMprConfigHandle	sphConfig;
		LPWSTR				pswz;
		
		if (m_stMachineName.IsEmpty())
			pswz = NULL;
		else
			pswz = (LPTSTR) (LPCTSTR) m_stMachineName;

		dwErr = ::MprConfigServerConnect(pswz,
										 &sphConfig);

		if (dwErr == ERROR_SUCCESS)
			dwErr = ::MprConfigGetFriendlyName(sphConfig,
											   T2W((LPTSTR)(LPCTSTR)m_stKeyBase),
											   szDesc,
											   sizeof(szDesc));

		m_stTitle = szDesc;
	}
//Error:	
	return dwErr;
}

/*!--------------------------------------------------------------------------
	CNetcardRegistryHelper::GetTitle
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
LPCTSTR CNetcardRegistryHelper::GetTitle()
{
	Assert(m_fInit);
 	return m_stTitle;
}


/*!--------------------------------------------------------------------------
	CNetcardRegistryHelper::ReadDeviceName
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
DWORD CNetcardRegistryHelper::ReadDeviceName()
{
	SP_DEVINFO_DATA	DevInfo;
	CString	stPnpInstanceID;
	DWORD		dwType = REG_SZ;
	TCHAR		szDesc[1024];
	DWORD	dwErr = ERROR_SUCCESS;
	

	if (m_fNt4)
	{
		if (m_stTitle.IsEmpty())
			dwErr = ReadTitle();
		m_stDeviceName = m_stTitle;
	}
	else
	{
		//$NT5
		// For NT5, we have a much harder time, since this involves
		// multiple lookups

        // Windows NT Bug : ?
        // The New Binding Engine changed some of the keys around,
        // We neet do look at the
		// HKLM\SYSTEM\CCS\Control\Network\{GUID_DEVCLASS_NET}\{netcard guid}\Connection
		// From this subkey get the PnpInstanceID

        if (m_hkeyConnection)
            dwErr = ReadRegistryCString(_T("HKLM\\SYSTEM\\CCS\\Control\\Network\\{GID_DEVCLASS_NET}\\{netcard guid}\\Connection"),
                                        c_szPnpInstanceID,
                                        m_hkeyConnection,
                                        &stPnpInstanceID);

		// ok, the base key is
		// HKLM\SYSTEM\CCS\Control\Network\{GUID_DEVCLASS_NET}\{netcard guid}
		// From this subkey get the PnpInstanceID

        if (dwErr != ERROR_SUCCESS)
            dwErr = ReadRegistryCString(_T("HKLM\\SYSTEM\\CCS\\Control\\Network\\{GID_DEVCLASS_NET}\\{netcard guid}"),
                                        c_szPnpInstanceID,
                                        m_hkeyBase,
                                        &stPnpInstanceID);
		if (dwErr != ERROR_SUCCESS)			
			goto Error;


		// Initialize the structure
		::ZeroMemory(&DevInfo, sizeof(DevInfo));
		DevInfo.cbSize = sizeof(DevInfo);
		
		if (!SetupDiOpenDeviceInfo(m_hDevInfo,
								   (LPCTSTR) stPnpInstanceID,
								   NULL,
								   0,
								   &DevInfo
								  ))
		{
			dwErr = GetLastError();
			goto Error;
		}

		// Try to get the friendly name first
		if (!SetupDiGetDeviceRegistryProperty(m_hDevInfo,
											  &DevInfo,
											  SPDRP_FRIENDLYNAME,
											  &dwType,
											  (LPBYTE) szDesc,
											  sizeof(szDesc),
											  NULL
											 ))
		{
			// If we fail to get the friendly name, try to
			// get the device description instead.
			if (!SetupDiGetDeviceRegistryProperty(m_hDevInfo,
				&DevInfo,
				SPDRP_DEVICEDESC,
				&dwType,
				(LPBYTE) szDesc,
				sizeof(szDesc),
				NULL
				))
			{
				dwErr = GetLastError();
				goto Error;
			}
		}

		m_stDeviceName = szDesc;
	}

Error:
	return dwErr;
}

/*!--------------------------------------------------------------------------
	CNetcardRegistryHelper::GetDeviceName
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
LPCTSTR CNetcardRegistryHelper::GetDeviceName()
{
	Assert(m_fInit);
	return m_stDeviceName;
}

/*!--------------------------------------------------------------------------
	CNetcardRegistryHelper::PrivateInit
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
DWORD CNetcardRegistryHelper::PrivateInit()
{
	DWORD	dwErr = ERROR_SUCCESS;
	
	if (m_fInit)
		return ERROR_SUCCESS;

	m_fInit = TRUE;

	if (m_fNt4)
	{
		// For NT4, we don't need to do anything, we are at the
		// place where we want to read the data
		m_hkeyService = m_hkeyBase;
		m_hkeyTitle = m_hkeyBase;
	}
	else
	{
		// We don't need m_hkeyService for NT5
		m_hkeyService = NULL;
		m_hkeyTitle = NULL;
	}
		

//Error:

	if (dwErr != ERROR_SUCCESS)
	{
		if (m_hkeyService)
			::RegCloseKey(m_hkeyService);
		m_hkeyService = NULL;
		
		if (m_hkeyTitle)
			::RegCloseKey(m_hkeyTitle);
		m_hkeyTitle = NULL;

		m_fInit = FALSE;
	}
	
	return dwErr;
}

/*!--------------------------------------------------------------------------
	CNetcardRegistryHelper::ReadRegistryCString
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
DWORD CNetcardRegistryHelper::ReadRegistryCString(
									LPCTSTR pszKey,
									LPCTSTR pszValue,
									HKEY	hkey,
									CString *pstDest)
{
	DWORD	dwSize, dwType;
	DWORD	dwErr = ERROR_SUCCESS;

	ASSERT(pstDest);
	
	dwSize = 0;
	dwErr = ::RegQueryValueEx(hkey,
							  pszValue,
							  NULL,
							  &dwType,
							  NULL,
							  &dwSize);
	CheckRegQueryValueError(dwErr, pszKey, pszValue, TEXT("CNetcardRegistryHelper::ReadRegistryCString"));
	if (dwErr != ERROR_SUCCESS)
		goto Error;
	ASSERT(dwType == REG_SZ);

	// Increase size to handle terminating NULL
	dwSize ++;
	
	dwErr = ::RegQueryValueEx(hkey,
							  pszValue,
							  NULL,
							  &dwType,
							  (LPBYTE) pstDest->GetBuffer(dwSize),
							  &dwSize);
	pstDest->ReleaseBuffer();
	
	CheckRegQueryValueError(dwErr, pszKey, pszValue, _T("CNetcardRegistryHelper::ReadRegistryCString"));
	if (dwErr != ERROR_SUCCESS)
		goto Error;

Error:
	return dwErr;
}

CWeakRef::CWeakRef()
	: m_cRef(1),
	m_cRefWeak(0),
	m_fStrongRef(TRUE),
	m_fDestruct(FALSE),
	m_fInShutdown(FALSE)
{
}

STDMETHODIMP_(ULONG) CWeakRef::AddRef()
{
	ULONG	ulReturn;
	Assert(m_cRef >= m_cRefWeak);
	ulReturn = InterlockedIncrement(&m_cRef);
	if (!m_fStrongRef)
	{
		m_fStrongRef = TRUE;
		ReviveStrongRef();
	}
	return ulReturn;	
}

STDMETHODIMP_(ULONG) CWeakRef::Release()
{
	ULONG	ulReturn;
	BOOL	fShutdown = m_fInShutdown;
	
	Assert(m_cRef >= m_cRefWeak);
	
	ulReturn = InterlockedDecrement(&m_cRef);
	if (ulReturn == 0)
		m_fInShutdown = TRUE;
	
	if ((m_cRef == m_cRefWeak) && m_fStrongRef)
	{
		m_fStrongRef = FALSE;

		AddWeakRef();
		
		OnLastStrongRef();

		ReleaseWeakRef();

	}

	if (ulReturn == 0 && (m_fInShutdown != fShutdown) && m_fInShutdown)
		delete this;
	return ulReturn;
}

STDMETHODIMP CWeakRef::AddWeakRef()
{
	Assert(m_cRef >= m_cRefWeak);
	InterlockedIncrement(&m_cRef);
	InterlockedIncrement(&m_cRefWeak);
	return hrOK;
}

STDMETHODIMP CWeakRef::ReleaseWeakRef()
{
	Assert(m_cRef >= m_cRefWeak);
	InterlockedDecrement(&m_cRefWeak);
	Release();
	return hrOK;
}


void SRouterCB::LoadFrom(const RouterCB *pcb)
{
	dwLANOnlyMode = pcb->dwLANOnlyMode;
}

void SRouterCB::SaveTo(RouterCB *pcb)
{
	pcb->dwLANOnlyMode = dwLANOnlyMode;
}


void SRtrMgrCB::LoadFrom(const RtrMgrCB *pcb)
{
	dwTransportId = pcb->dwTransportId;
	stId = pcb->szId;
	stTitle = pcb->szTitle;
	stDLLPath = pcb->szDLLPath;
//	stConfigDLL = pcb->szConfigDLL;			
}

void SRtrMgrCB::SaveTo(RtrMgrCB *pcb)
{
	pcb->dwTransportId = dwTransportId;
	StrnCpyOleFromT(pcb->szId, (LPCTSTR) stId, RTR_ID_MAX);
	StrnCpyOleFromT(pcb->szTitle, (LPCTSTR) stTitle, RTR_TITLE_MAX);
	StrnCpyOleFromT(pcb->szDLLPath, (LPCTSTR) stDLLPath, RTR_PATH_MAX);
//	StrnCpyOleFromT(pcb->szConfigDLL, (LPCTSTR) stConfigDLL, RTR_PATH_MAX);
}


void SRtrMgrProtocolCB::LoadFrom(const RtrMgrProtocolCB *pcb)
{
	dwProtocolId = pcb->dwProtocolId;
	stId = pcb->szId;
    dwFlags = pcb->dwFlags;
	dwTransportId = pcb->dwTransportId;
	stRtrMgrId = pcb->szRtrMgrId;
	stTitle = pcb->szTitle;
	stDLLName = pcb->szDLLName;
//	stConfigDLL = pcb->szConfigDLL;
	guidAdminUI = pcb->guidAdminUI;
	guidConfig = pcb->guidConfig;
	stVendorName = pcb->szVendorName;
}

void SRtrMgrProtocolCB::SaveTo(RtrMgrProtocolCB *pcb)
{
	pcb->dwProtocolId = dwProtocolId;
	StrnCpyOleFromT(pcb->szId, (LPCTSTR) stId, RTR_ID_MAX);
    pcb->dwFlags = dwFlags;
	pcb->dwTransportId = dwTransportId;
	StrnCpyOleFromT(pcb->szRtrMgrId, (LPCTSTR) stRtrMgrId, RTR_ID_MAX);
	StrnCpyOleFromT(pcb->szTitle, (LPCTSTR) stTitle, RTR_TITLE_MAX);
	StrnCpyOleFromT(pcb->szDLLName, (LPCTSTR) stDLLName, RTR_PATH_MAX);
//	StrnCpyOleFromT(pcb->szConfigDLL, (LPCTSTR) stConfigDLL, RTR_PATH_MAX);
	pcb->guidAdminUI = guidAdminUI;
	pcb->guidConfig = guidConfig;
	StrnCpyOleFromT(pcb->szVendorName, (LPCTSTR) stVendorName, VENDOR_NAME_MAX);
}


void SInterfaceCB::LoadFrom(const InterfaceCB *pcb)
{
	stId = pcb->szId;
	stDeviceName = pcb->szDevice;
	dwIfType = pcb->dwIfType;
	bEnable = pcb->bEnable;
	stTitle = pcb->szTitle;
    dwBindFlags = pcb->dwBindFlags;
}

void SInterfaceCB::SaveTo(InterfaceCB *pcb)
{
	StrnCpyOleFromT(pcb->szId, (LPCTSTR) stId, RTR_ID_MAX);
	StrnCpyOleFromT(pcb->szDevice, (LPCTSTR) stDeviceName, RTR_DEVICE_MAX);
	pcb->dwIfType = dwIfType;
	pcb->bEnable = bEnable;
	StrnCpyOleFromT(pcb->szTitle, (LPCTSTR) stTitle, RTR_TITLE_MAX);
    pcb->dwBindFlags = dwBindFlags;
}


void SRtrMgrInterfaceCB::LoadFrom(const RtrMgrInterfaceCB *pcb)
{
	dwTransportId = pcb->dwTransportId;
	stId = pcb->szId;
	stInterfaceId = pcb->szInterfaceId;
	dwIfType = pcb->dwIfType;
	stTitle = pcb->szTitle;
}

void SRtrMgrInterfaceCB::SaveTo(RtrMgrInterfaceCB *pcb)
{
	pcb->dwTransportId = dwTransportId;
	StrnCpyOleFromT(pcb->szId, (LPCTSTR) stId, RTR_ID_MAX);
	StrnCpyOleFromT(pcb->szInterfaceId, (LPCTSTR) stInterfaceId, RTR_ID_MAX);
	pcb->dwIfType = dwIfType;
	StrnCpyOleFromT(pcb->szTitle, (LPCTSTR) stTitle, RTR_TITLE_MAX);
}


void SRtrMgrProtocolInterfaceCB::LoadFrom(const RtrMgrProtocolInterfaceCB *pcb)
{
	dwProtocolId = pcb->dwProtocolId;
	stId = pcb->szId;
	dwTransportId = pcb->dwTransportId;
	stRtrMgrId = pcb->szRtrMgrId;
	stInterfaceId = pcb->szInterfaceId;
	dwIfType = pcb->dwIfType;
	stTitle = pcb->szTitle;
}

void SRtrMgrProtocolInterfaceCB::SaveTo(RtrMgrProtocolInterfaceCB *pcb)
{
	pcb->dwProtocolId = dwProtocolId;
	StrnCpyOleFromT(pcb->szId, (LPCTSTR) stId, RTR_ID_MAX);
	pcb->dwTransportId = dwTransportId;
	StrnCpyOleFromT(pcb->szRtrMgrId, (LPCTSTR) stRtrMgrId, RTR_ID_MAX);
	StrnCpyOleFromT(pcb->szInterfaceId, (LPCTSTR) stInterfaceId, RTR_TITLE_MAX);
	pcb->dwIfType = dwIfType;
	StrnCpyOleFromT(pcb->szTitle, (LPCTSTR) stTitle, RTR_PATH_MAX);
}



/*!--------------------------------------------------------------------------
	CreateDataObjectFromRouterInfo
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
HRESULT CreateDataObjectFromRouterInfo(IRouterInfo *pInfo,
									   LPCTSTR pszMachineName,
									   DATA_OBJECT_TYPES type,
									   MMC_COOKIE cookie,
									   ITFSComponentData *pTFSCompData,
									   IDataObject **ppDataObject,
                                       CDynamicExtensions * pDynExt,
                                       BOOL fAddedAsLocal)
{
	Assert(ppDataObject);
	CRouterDataObject	*	pdo = NULL;
	HRESULT			hr = hrOK;

	SPIUnknown	spunk;
	SPIDataObject	spDataObject;

	pdo = new CRouterDataObject;
	spDataObject = pdo;

	pdo->SetComputerName(pszMachineName);
    pdo->SetComputerAddedAsLocal(fAddedAsLocal);
	
	CORg( CreateRouterInfoAggregation(pInfo, pdo, &spunk) );
	
	pdo->SetInnerIUnknown(spunk);
		
	// Save cookie and type for delayed rendering
	pdo->SetType(type);
	pdo->SetCookie(cookie);
	
	// Store the coclasscls with the data object
	pdo->SetClsid(*(pTFSCompData->GetCoClassID()));
			
	pdo->SetTFSComponentData(pTFSCompData);

    pdo->SetDynExt(pDynExt);

	*ppDataObject = spDataObject.Transfer();

Error:
	return hr;
}


/*!--------------------------------------------------------------------------
	AdviseDataList::AddConnection
		Adds a connection to the list.
	Author: KennT
 ---------------------------------------------------------------------------*/
HRESULT AdviseDataList::AddConnection(IRtrAdviseSink *pAdvise,
									  LONG_PTR ulConnId,
									  LPARAM lUserParam)
{
	Assert(pAdvise);
	
	HRESULT	hr = hrOK;
	SAdviseData	adviseData;
	
	COM_PROTECT_TRY
	{
		adviseData.m_ulConnection = ulConnId;
		adviseData.m_pAdvise = pAdvise;
		adviseData.m_lUserParam = lUserParam;

		AddTail(adviseData);
		
		pAdvise->AddRef();
	}
	COM_PROTECT_CATCH;
	return hr;
}

/*!--------------------------------------------------------------------------
	AdviseDataList::RemoveConnection
		Removes the connection from the list.
	Author: KennT
 ---------------------------------------------------------------------------*/
HRESULT AdviseDataList::RemoveConnection(LONG_PTR ulConnection)
{
	HRESULT		hr = E_INVALIDARG;
	POSITION	pos, posTemp;
    POSITION    posNotify;
	SAdviseData	adviseData;
	
	COM_PROTECT_TRY
	{
		pos = GetHeadPosition();
		while (pos)
		{
			posTemp = pos;
			adviseData = GetNext(pos);
			if (adviseData.m_ulConnection == ulConnection)
			{
				hr = hrOK;
				SAdviseData::Destroy(&adviseData);
				RemoveAt(posTemp);

                // Remove this connection from the list
                if (!m_listNotify.IsEmpty())
                {
                    posNotify = m_listNotify.GetHeadPosition();
                    while (posNotify)
                    {
                        posTemp = posNotify;
                        adviseData = m_listNotify.GetNext(posNotify);
                        if (adviseData.m_ulConnection == ulConnection)
                        {
                            adviseData.m_ulFlags |= ADVISEDATA_DELETED;
                            m_listNotify.SetAt(posTemp, adviseData);
                            break;
                        }
                    }
                }
				break;
			}
		}
	}
	COM_PROTECT_CATCH;
	return hr;
}


/*!--------------------------------------------------------------------------
	AdviseDataList::NotifyChange
		Enumerates through the list of advise sinks and sends this
		notification to each one.		
	Author: KennT
 ---------------------------------------------------------------------------*/
HRESULT AdviseDataList::NotifyChange(DWORD dwChangeType,
									 DWORD dwObjectType,
									 LPARAM lParam)
{
	POSITION	pos;
	SAdviseData	adviseData;
	HRESULT		hr = hrOK;

    // This requires a two-step process.  (this is necessary since
    // a callback here, may change the items in the list).

    // First, gather a list of all the advise sinks (place them
    // in a list).
    //
    // Secondly, go through the list calling the OnChange()
    // notifications.  THIS LIST MAY BE MODIFIED BY A CALL TO
    // THE UNADVISE FUNCTIONS.  This means that the unadvise must
    // traverse this list.


    // Remove all entries in m_listNotify
    m_listNotify.RemoveAll();

    
    // Do the first step and build up the list
	pos = GetHeadPosition();

	while (pos)
	{
		adviseData = GetNext(pos);
        adviseData.m_ulFlags = 0;

        m_listNotify.AddTail(adviseData);
    }

    // Now go through the notify list and send out the notifies
    pos = m_listNotify.GetHeadPosition();
    while (pos)
    {
        adviseData = m_listNotify.GetNext(pos);

        if ((adviseData.m_ulFlags & ADVISEDATA_DELETED) == 0)
        {
            // Ignore the return value
            adviseData.m_pAdvise->OnChange(adviseData.m_ulConnection,
                                           dwChangeType,
                                           dwObjectType,
                                           adviseData.m_lUserParam,
                                           lParam);
        }
	}

    // Clear out the list again
    m_listNotify.RemoveAll();
	return hr;
}


void SAdviseData::Destroy(SAdviseData *pAdviseData)
{
	if (pAdviseData && pAdviseData->m_pAdvise)
	{
		pAdviseData->m_pAdvise->Release();
		pAdviseData->m_pAdvise = NULL;
		pAdviseData->m_ulConnection = NULL;
		pAdviseData->m_lUserParam = 0;
	}
#ifdef DEBUG
	else if (pAdviseData)
		Assert(pAdviseData->m_ulConnection == 0);
#endif
}

void SRmData::Destroy(SRmData *pRmData)
{
	if (pRmData && pRmData->m_pRmInfo)
	{
        // This destruct should only get called if this RtrMgr is
        // a child of this node.
		pRmData->m_pRmInfo->Destruct();
		pRmData->m_pRmInfo->ReleaseWeakRef();

		pRmData->m_pRmInfo = NULL;
	}
}



/*!--------------------------------------------------------------------------
	CreateDataObjectFromInterfaceInfo
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
HRESULT CreateDataObjectFromInterfaceInfo(IInterfaceInfo *pInfo,
									   DATA_OBJECT_TYPES type,
									   MMC_COOKIE cookie,
									   ITFSComponentData *pTFSCompData,
									   IDataObject **ppDataObject)
{
	Assert(ppDataObject);

	HRESULT			hr = hrOK;
	CRouterDataObject *	pdo = NULL;
	SPIDataObject	spDataObject;
	SPIUnknown		spunk;

	pdo = new CRouterDataObject;
	spDataObject = pdo;

	pdo->SetComputerName(pInfo->GetMachineName());

	CORg( CreateInterfaceInfoAggregation(pInfo, pdo, &spunk) );

	pdo->SetInnerIUnknown(spunk);
	
	// Save cookie and type for delayed rendering
	pdo->SetType(type);
	pdo->SetCookie(cookie);
	
	// Store the coclass with the data object
	pdo->SetClsid(*(pTFSCompData->GetCoClassID()));
			
	pdo->SetTFSComponentData(pTFSCompData);
						
	*ppDataObject = spDataObject.Transfer();

Error:
	return hr;
}


/*!--------------------------------------------------------------------------
	LookupRtrMgr
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
TFSCORE_API(HRESULT) LookupRtrMgr(IRouterInfo *pRouter,
								  DWORD dwTransportId,
								  IRtrMgrInfo **ppRm)
{
	Assert(pRouter);
	Assert(ppRm);
	return pRouter->FindRtrMgr(dwTransportId, ppRm);
}

/*!--------------------------------------------------------------------------
	LookupRtrMgrProtocol
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
TFSCORE_API(HRESULT) LookupRtrMgrProtocol(IRouterInfo *pRouter,
										  DWORD dwTransportId,
										  DWORD dwProtocolId,
										  IRtrMgrProtocolInfo **ppRmProt)
{
	Assert(pRouter);
	Assert(ppRmProt);

	SPIRtrMgrInfo	spRm;
	HRESULT			hr = hrOK;
	
	CORg( LookupRtrMgr(pRouter, dwTransportId, &spRm) );

	if (FHrOK(hr))
		CORg( spRm->FindRtrMgrProtocol(dwProtocolId, ppRmProt) );

Error:
	return hr;
}


TFSCORE_API(HRESULT) LookupRtrMgrInterface(IRouterInfo *pRouter,
										   LPCOLESTR pszInterfaceId,
										   DWORD dwTransportId,
										   IRtrMgrInterfaceInfo **ppRmIf)
{
	Assert(pRouter);
	SPIInterfaceInfo	spIf;
	HRESULT				hr = hrFalse;

	CORg( pRouter->FindInterface(pszInterfaceId, &spIf) );
	if (FHrOK(hr))
	{
		hr = spIf->FindRtrMgrInterface(dwTransportId, ppRmIf);
	}

Error:
	return hr;
}

TFSCORE_API(HRESULT) LookupRtrMgrProtocolInterface(
	IInterfaceInfo *pIf, DWORD dwTransportId, DWORD dwProtocolId,
	IRtrMgrProtocolInterfaceInfo **ppRmProtIf)
{
	Assert(pIf);
	SPIRtrMgrInterfaceInfo	spRmIf;
	HRESULT				hr = hrFalse;

	hr = pIf->FindRtrMgrInterface(dwTransportId, &spRmIf);
	if (FHrOK(hr))
		CORg( spRmIf->FindRtrMgrProtocolInterface(dwProtocolId, ppRmProtIf) );

Error:
	return hr;
}

/*!--------------------------------------------------------------------------
	CreateRouterDataObject
		-
	Author: KennT
 ---------------------------------------------------------------------------*/
HRESULT CreateRouterDataObject(LPCTSTR pszMachineName,
							   DATA_OBJECT_TYPES type,
							   MMC_COOKIE cookie,
							   ITFSComponentData *pTFSCompData,
							   IDataObject **ppDataObject,
                               CDynamicExtensions * pDynExt,
                               BOOL fAddedAsLocal)
{
	Assert(ppDataObject);
	CRouterDataObject	*	pdo = NULL;
	HRESULT			hr = hrOK;

	SPIUnknown	spunk;
	SPIDataObject	spDataObject;

	pdo = new CRouterDataObject;
	spDataObject = pdo;

	pdo->SetComputerName(pszMachineName);
    pdo->SetComputerAddedAsLocal(fAddedAsLocal);
	
	// Save cookie and type for delayed rendering
	pdo->SetType(type);
	pdo->SetCookie(cookie);
	
	// Store the coclasscls with the data object
	pdo->SetClsid(*(pTFSCompData->GetCoClassID()));
			
	pdo->SetTFSComponentData(pTFSCompData);

    pdo->SetDynExt(pDynExt);

	*ppDataObject = spDataObject.Transfer();

//Error:
	return hr;
}