Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1734 lines
56 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: D I A L U P . C P P
//
// Contents: Implements the dial up connection object.
//
// Notes:
//
// Author: shaunco 23 Sep 1997
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "dialup.h"
#include "nccom.h"
#include "ncnetcon.h"
#include "ncras.h"
#include "ncreg.h"
#include "userenv.h"
#include "cmutil.h"
#include "cobase.h"
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::CreateInstanceUninitialized
//
// Purpose: Create an uninitialized instance of
// CComObject <CDialupConnection> and return an interface
// pointer as well as a pointer to the CDialupConnection.
//
// Arguments:
// riid [in] IID of desired interface.
// ppv [out] Returned interface pointer.
// ppObj [out] Returned object pointer.
//
// Returns: S_OK or E_OUTOFMEMORY.
//
// Author: shaunco 20 Apr 1998
//
// Notes:
//
//static
HRESULT
CDialupConnection::CreateInstanceUninitialized (
REFIID riid,
VOID** ppv,
CDialupConnection** ppObj)
{
Assert (ppObj);
Assert (ppv);
*ppv = NULL;
*ppObj = NULL;
HRESULT hr = E_OUTOFMEMORY;
CDialupConnection* pObj;
pObj = new CComObject <CDialupConnection>;
if (pObj)
{
// Do the standard CComCreator::CreateInstance stuff.
//
pObj->SetVoid (NULL);
pObj->InternalFinalConstructAddRef ();
hr = pObj->FinalConstruct ();
pObj->InternalFinalConstructRelease ();
if (SUCCEEDED(hr))
{
INetConnection* pCon = static_cast<INetConnection*>(pObj);
hr = pCon->QueryInterface (riid, ppv);
if (SUCCEEDED(hr))
{
*ppObj = pObj;
}
}
if (FAILED(hr))
{
delete pObj;
}
}
TraceError ("CDialupConnection::CreateInstanceFromDetails", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::CreateInstanceFromDetails
//
// Purpose: Create an initialized instance of
// CComObject <CDialupConnection> given RASENUMENTRYDETAILS and
// return an interface pointer on that object.
//
// Arguments:
// pszwPbkFile [in] Path to the phonebook file.
// pszwEntryName [in] Name of the entry in the phonebook.
// fForAllUsers [in] TRUE if this entry is for all users.
// riid [in] IID of desired interface.
// ppv [out] Returned interface pointer.
//
// Returns: S_OK or E_OUTOFMEMORY.
//
// Author: shaunco 23 Sep 1997
//
// Notes:
//
// static
HRESULT
CDialupConnection::CreateInstanceFromDetails (
const RASENUMENTRYDETAILS* pEntryDetails,
REFIID riid,
VOID** ppv)
{
Assert(pEntryDetails);
Assert(pEntryDetails->szPhonebookPath);
CDialupConnection* pObj;
HRESULT hr = CreateInstanceUninitialized (riid, ppv, &pObj);
if (SUCCEEDED(hr))
{
pObj->SetPbkFile (pEntryDetails->szPhonebookPath);
pObj->CacheProperties (pEntryDetails);
// We are now a full-fledged object.
//
pObj->m_fInitialized = TRUE;
}
TraceError ("CDialupConnection::CreateInstanceFromDetails", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::CreateInstanceFromPbkFileAndEntryName
//
// Purpose: Create an initialized instance of
// CComObject <CDialupConnection> given only a phonebook path,
// entry name, and weather it is for all users or not and
// return an interface pointer on that object.
//
// Arguments:
// pszPbkFile [in] Phonebook path.
// pszEntryName [in] Entry name.
// riid [in] IID of desired interface.
// ppv [out] Returned interface pointer.
//
// Returns: S_OK or E_OUTOFMEMORY.
//
// Author: shaunco 20 Apr 1998
//
// Notes: This is called from Duplicate.
//
//static
HRESULT
CDialupConnection::CreateInstanceFromPbkFileAndEntryName (
PCWSTR pszPbkFile,
PCWSTR pszEntryName,
REFIID riid,
VOID** ppv)
{
TraceTag (ttidWanCon,
"CDialupConnection::CreateInstanceFromPbkFileAndEntryName called");
CDialupConnection* pObj;
HRESULT hr = CreateInstanceUninitialized (riid, ppv, &pObj);
if (SUCCEEDED(hr))
{
pObj->SetPbkFile (pszPbkFile);
pObj->SetEntryName (pszEntryName);
pObj->m_guidId = GUID_NULL;
// We are now a full-fledged object.
//
pObj->m_fInitialized = TRUE;
}
TraceError ("CDialupConnection::CreateInstanceFromPbkFileAndEntryName", hr);
return hr;
}
//+---------------------------------------------------------------------------
// INetConnection
//
STDMETHODIMP
CDialupConnection::GetUiObjectClassId (
CLSID* pclsid)
{
HRESULT hr = S_OK;
// Validate parameters.
//
if (!pclsid)
{
hr = E_POINTER;
}
else if (!m_fInitialized)
{
hr = E_UNEXPECTED;
}
else
{
static const CLSID CLSID_DialupConnectionUi =
{0x7007ACC1,0x3202,0x11D1,{0xAA,0xD2,0x00,0x80,0x5F,0xC1,0x27,0x0E}};
static const CLSID CLSID_DirectConnectionUi =
{0x7007ACC2,0x3202,0x11D1,{0xAA,0xD2,0x00,0x80,0x5F,0xC1,0x27,0x0E}};
static const CLSID CLSID_VpnConnectionUi =
{0x7007ACC6,0x3202,0x11D1,{0xAA,0xD2,0x00,0x80,0x5F,0xC1,0x27,0x0E}};
static const CLSID CLSID_PPPoEUi =
{0x7007ACD4,0x3202,0x11D1,{0xAA,0xD2,0x00,0x80,0x5F,0xC1,0x27,0x0E}};
hr = HrEnsureEntryPropertiesCached ();
if (SUCCEEDED(hr))
{
switch (MediaType ())
{
case NCM_DIRECT:
*pclsid = CLSID_DirectConnectionUi;
break;
case NCM_ISDN:
case NCM_PHONE:
*pclsid = CLSID_DialupConnectionUi;
break;
case NCM_TUNNEL:
*pclsid = CLSID_VpnConnectionUi;
break;
case NCM_PPPOE:
*pclsid = CLSID_PPPoEUi;
break;
default:
*pclsid = CLSID_DialupConnectionUi;
TraceTag (ttidWanCon, "GetUiObjectClassId: Unknown media type "
"(%d) treating as CLSID_DialupConnectionUi", MediaType());
}
}
}
TraceError ("CDialupConnection::GetUiObjectClassId", hr);
return hr;
}
STDMETHODIMP
CDialupConnection::Connect ()
{
return E_NOTIMPL;
}
STDMETHODIMP
CDialupConnection::Disconnect ()
{
HRESULT hr;
if (!m_fInitialized)
{
hr = E_UNEXPECTED;
}
else
{
HRASCONN hRasConn;
hr = HrFindRasConn (&hRasConn, NULL);
if (S_OK == hr)
{
// Because RasHangup could call RasCustomHangup
// we need to impersonate the client to allow the correct
// per-user information to be used.
//
// Impersonate the client.
//
HRESULT hrT = CoImpersonateClient ();
TraceErrorOptional ("CDialupConnection::Disconnect -- CoImpersonateClient", hrT, RPC_E_CALL_COMPLETE == hrT);
// We need to continue if we're called in-proc (ie. if RPC_E_CALL_COMPLETE is returned).
if (SUCCEEDED(hrT) || (RPC_E_CALL_COMPLETE == hrT))
{
hr = HrRasHangupUntilDisconnected (hRasConn);
}
if (SUCCEEDED(hrT))
{
hrT = CoRevertToSelf ();
TraceError ("CDialupConnection::Disconnect -- CoRevertToSelf", hrT);
}
}
else if (S_FALSE == hr)
{
hr = S_OK;
}
}
TraceError ("CDialupConnection::Disconnect", hr);
return hr;
}
STDMETHODIMP
CDialupConnection::Delete ()
{
HRESULT hr = E_UNEXPECTED;
if (!m_fInitialized)
{
hr = E_UNEXPECTED;
}
else
{
hr = HrEnsureEntryPropertiesCached ();
if (SUCCEEDED(hr))
{
// If we allow removal (a decision which is based on the
// whether the user is an admin, whether the connection is
// 'for all users', and the connection's current state) then
// proceed. If FAllowRemoval fails, it's output parameter
// is the "reason" in the form of an HRESULT. We can use
// this as our return value in that case.
//
HRESULT hrReason;
if (FAllowRemoval (&hrReason))
{
// If we're active in any way, we can't be removed.
//
NETCON_STATUS status;
hr = HrGetStatus(&status);
if (SUCCEEDED(hr) &&
((NCS_CONNECTING != status) &&
(NCS_CONNECTED != status) &&
(NCS_DISCONNECTING != status)))
{
// We do an impersonation here in case the connection has a RAS custom delete notification
// setup (CM connections do, for instance). This allows the RasCustomDeleteEntryNotify
// function to interact with the system as the user.
//
HRESULT hrT = CoImpersonateClient ();
TraceError ("HrRemoveCmProfile -- CoImpersonateClient", hrT);
// We need to continue if we're called in-proc (ie. if RPC_E_CALL_COMPLETE is returned).
if (SUCCEEDED(hrT) || (RPC_E_CALL_COMPLETE == hrT))
{
// Delete the RAS entry, note that for branded connections, RAS
// will call RasCustomDeleteEntryNotify after deletion.
//
DWORD dwErr = RasDeleteEntry (PszwPbkFile (), PszwEntryName ());
hr = HRESULT_FROM_WIN32 (dwErr);
TraceError ("RasDeleteEntry", hr);
}
// Revert to ourselves
//
if (SUCCEEDED(hrT))
{
CoRevertToSelf ();
}
}
else
{
// Don't allow deletion unless disconnected
//
TraceTag (ttidWanCon, "Disallowing delete while in connected or"
"partially connected state");
hr = E_UNEXPECTED;
}
}
else
{
hr = hrReason;
}
}
}
TraceError ("CDialupConnection::Delete", hr);
return hr;
}
STDMETHODIMP
CDialupConnection::Duplicate (
PCWSTR pszDuplicateName,
INetConnection** ppCon)
{
HRESULT hr = S_OK;
// Validate parameters.
//
if (!pszDuplicateName || !ppCon)
{
hr = E_POINTER;
}
else if (!m_fInitialized)
{
hr = E_UNEXPECTED;
}
else
{
*ppCon = NULL;
hr = HrEnsureEntryPropertiesCached ();
if (SUCCEEDED(hr))
{
// Make sure the name is valid in the same phone book.
//
DWORD dwErr = RasValidateEntryName (
PszwPbkFile (), pszDuplicateName);
hr = HRESULT_FROM_WIN32 (dwErr);
TraceError ("RasValidateEntryName", hr);
if (SUCCEEDED(hr))
{
dwErr = DwCloneEntry (
PszwPbkFile(),
PszwEntryName(),
pszDuplicateName);
hr = HRESULT_FROM_WIN32 (dwErr);
TraceError ("DwCloneEntry", hr);
if (SUCCEEDED(hr))
{
hr = CreateInstanceFromPbkFileAndEntryName (
PszwPbkFile (),
pszDuplicateName,
IID_INetConnection, (VOID**)ppCon);
if (SUCCEEDED(hr))
{
hr = HrEnsureHNetPropertiesCached();
}
if (SUCCEEDED(hr))
{
if (m_HNetProperties.fFirewalled || m_HNetProperties.fIcsPublic) // lazy eval the hnetcfg stuff
{
IHNetCfgMgr* pHomenetConfigManager;
hr = HrGetHNetCfgMgr(&pHomenetConfigManager);
if(SUCCEEDED(hr))
{
IHNetConnection* pNewHomenetConnection;
hr = pHomenetConfigManager->GetIHNetConnectionForINetConnection(*ppCon, &pNewHomenetConnection);
if(SUCCEEDED(hr))
{
IHNetConnection* pHomenetConnection;
hr = HrGetIHNetConnection(&pHomenetConnection);
if(SUCCEEDED(hr))
{
// copy port bindings
// REVIEW if somethings fails here to we need to nuke the new connection?
IEnumHNetPortMappingBindings* pEnumPortMappingBindings;
hr = pNewHomenetConnection->EnumPortMappings(FALSE, &pEnumPortMappingBindings);
if(SUCCEEDED(hr))
{
ULONG ulFetched;
IHNetPortMappingBinding* pNewPortMappingBinding;
while(S_OK == pEnumPortMappingBindings->Next(1, &pNewPortMappingBinding, &ulFetched))
{
Assert(1 == ulFetched);
IHNetPortMappingProtocol* pPortMappingProtocol;
hr = pNewPortMappingBinding->GetProtocol(&pPortMappingProtocol);
if(SUCCEEDED(hr))
{
// find the original binding by using the protocol field
IHNetPortMappingBinding* pPortMappingBinding;
hr = pHomenetConnection->GetBindingForPortMappingProtocol(pPortMappingProtocol, &pPortMappingBinding);
if(SUCCEEDED(hr))
{
BOOLEAN bEnabled;
hr = pPortMappingBinding->GetEnabled(&bEnabled);
if(SUCCEEDED(hr))
{
if(TRUE == bEnabled)
{
hr = pNewPortMappingBinding->SetEnabled(bEnabled);
}
}
// always set the computer address
if(SUCCEEDED(hr))
{
ULONG ulAddress;
hr = pPortMappingBinding->GetTargetComputerAddress(&ulAddress);
if(SUCCEEDED(hr))
{
if(0 != ulAddress)
{
hr = pNewPortMappingBinding->SetTargetComputerAddress(ulAddress);
}
}
}
// only set the computer name if it is used
if(SUCCEEDED(hr))
{
BOOLEAN bUseName;
hr = pPortMappingBinding->GetCurrentMethod(&bUseName);
if(SUCCEEDED(hr) && TRUE == bUseName)
{
OLECHAR* pszTargetComputerName;
hr = pPortMappingBinding->GetTargetComputerName(&pszTargetComputerName);
if(SUCCEEDED(hr))
{
if(L'\0' != *pszTargetComputerName)
{
hr = pNewPortMappingBinding->SetTargetComputerName(pszTargetComputerName);
}
CoTaskMemFree(pszTargetComputerName);
}
}
}
ReleaseObj(pPortMappingBinding);
}
ReleaseObj(pPortMappingProtocol);
}
ReleaseObj(pNewPortMappingBinding);
}
ReleaseObj(pEnumPortMappingBindings);
}
if(m_HNetProperties.fFirewalled) // copy firewall yes/no and ICMP settings
{
IHNetFirewalledConnection* pFirewalledConnection;
hr = pNewHomenetConnection->Firewall(&pFirewalledConnection);
if(SUCCEEDED(hr))
{
HNET_FW_ICMP_SETTINGS* pICMPSettings;
hr = pHomenetConnection->GetIcmpSettings(&pICMPSettings);
if(SUCCEEDED(hr))
{
hr = pNewHomenetConnection->SetIcmpSettings(pICMPSettings);
CoTaskMemFree(pICMPSettings);
}
ReleaseObj(pFirewalledConnection);
}
}
ReleaseObj(pHomenetConnection);
}
ReleaseObj(pNewHomenetConnection);
}
ReleaseObj(pHomenetConfigManager);
}
}
}
}
}
}
}
TraceError ("CDialupConnection::Duplicate", hr);
return hr;
}
STDMETHODIMP
CDialupConnection::GetProperties (
NETCON_PROPERTIES** ppProps)
{
HRESULT hr = S_OK;
HRESULT hrHiddenCM = S_OK;
CMEntry cm;
// Validate parameters.
//
if (!ppProps)
{
hr = E_POINTER;
}
else if (!m_fInitialized)
{
hr = E_UNEXPECTED;
}
else
{
// Initialize the output parameter.
//
*ppProps = NULL;
hr = HrEnsureEntryPropertiesCached ();
if (SUCCEEDED(hr))
{
NETCON_PROPERTIES* pProps;
hr = HrCoTaskMemAlloc (sizeof (NETCON_PROPERTIES),
reinterpret_cast<VOID**>(&pProps));
if (SUCCEEDED(hr))
{
HRESULT hrT;
ZeroMemory (pProps, sizeof (NETCON_PROPERTIES));
// guidId
//
pProps->guidId = GuidId ();
// pszwName
//
hrT = HrCoTaskMemAllocAndDupSz (
PszwEntryName(),
&pProps->pszwName);
if (FAILED(hrT))
{
hr = hrT;
}
hrT = HrCoTaskMemAllocAndDupSz (
PszwDeviceName(),
&pProps->pszwDeviceName);
if (FAILED(hrT))
{
hr = hrT;
}
// Status
//
hrT = HrGetStatus (&pProps->Status);
if (FAILED(hrT))
{
hr = hrT;
}
// Verify that the status return is accurate. HrGetStatus returns NCS_DISCONNECTED
// if the connectoid is NCS_CONNECTING, which is wrong!!!!.
//
if( pProps->Status == NCS_DISCONNECTED )
{
// CMUtil remebers the Hidden connection (Connection Manager) and the status of
// any ras events (i.e. Connecting, Disconnecting etc). The Data is filled in
// in function RasEventNotify.
//
hrHiddenCM = CCMUtil::Instance().HrGetEntry(pProps->guidId,cm);
if ( S_OK == hrHiddenCM )
{
// Use CCMUtil's status, its more accurate.
//
pProps->Status = cm.m_ncs;
}
}
// Check if this connection has a child connection
//
hrHiddenCM = CCMUtil::Instance().HrGetEntry(PszwEntryName(),cm);
if( hrHiddenCM == S_OK )
{
// It has a child connectoid
// Now we have to determine which one describes the overall status of the connection
//
if( cm.m_ncs == NCS_CONNECTING || cm.m_ncs == NCS_DISCONNECTING ||
cm.m_ncs == NCS_CONNECTED)
{
if( pProps->Status == NCS_DISCONNECTING )
{
// This case happens if the parent is disconnecting
// The parent is disconnecting, so the child will be disconnecting.
// Change the status of the child to disconnecting so that we do not
// get confused later on when the child is connected at the parent is
// disconnected. i.e. are we overall connecting or disconnecting!!!!
//
CCMUtil::Instance().SetEntry(GuidId (), PszwEntryName(),pProps->Status);
}
else
if( cm.m_ncs == NCS_CONNECTED && pProps->Status == NCS_DISCONNECTED )
{
// This case will only happen if the child is connected and the parent is still
// disconnected.
//
pProps->Status = NCS_CONNECTING;
}
else if (!IsEqualGUID(pProps->guidId, cm.m_guid))
{
TraceTag(ttidWanCon, "Overwriting parent connection status: %s with child status: %s", DbgNcs(pProps->Status), DbgNcs(cm.m_ncs));
// When in doubt and the GUID's are different (ie. not a BAP/Multilink connection) take the childs status =)
//
pProps->Status = cm.m_ncs;
}
}
}
// Type
//
pProps->MediaType = MediaType ();
// dwCharacter
//
hrT = HrGetCharacteristics (&pProps->dwCharacter);
if (FAILED(hrT))
{
hr = hrT;
}
// clsidThisObject
//
pProps->clsidThisObject = CLSID_DialupConnection;
// clsidUiObject
//
hrT = GetUiObjectClassId (&pProps->clsidUiObject);
if (FAILED(hrT))
{
hr = hrT;
}
// Assign the output parameter or cleanup if we had any failures.
//
if (SUCCEEDED(hr))
{
*ppProps = pProps;
}
else
{
Assert (NULL == *ppProps);
FreeNetconProperties (pProps);
}
}
}
}
TraceError ("CDialupConnection::GetProperties", hr);
return hr;
}
STDMETHODIMP
CDialupConnection::Rename (
PCWSTR pszNewName)
{
HRESULT hr;
// Validate parameters.
//
if (!pszNewName)
{
hr = E_POINTER;
}
else if (!m_fInitialized)
{
hr = E_UNEXPECTED;
}
else
{
hr = HrLockAndRenameEntry (pszNewName, this);
}
TraceError ("CDialupConnection::Rename", hr);
return hr;
}
//+---------------------------------------------------------------------------
// INetRasConnection
//
STDMETHODIMP
CDialupConnection::GetRasConnectionInfo (
RASCON_INFO* pRasConInfo)
{
HRESULT hr = HrGetRasConnectionInfo (pRasConInfo);
TraceError ("CDialupConnection::GetRasConnectionInfo", hr);
return hr;
}
STDMETHODIMP
CDialupConnection::SetRasConnectionInfo (
const RASCON_INFO* pRasConInfo)
{
HRESULT hr = HrSetRasConnectionInfo (pRasConInfo);
TraceError ("CDialupConnection::SetRasConnectionInfo", hr);
return hr;
}
STDMETHODIMP
CDialupConnection::GetRasConnectionHandle (
ULONG_PTR* phRasConn)
{
HRESULT hr = HrGetRasConnectionHandle (
reinterpret_cast<HRASCONN*>(phRasConn));
TraceError ("CDialupConnection::GetRasConnectionHandle",
(S_FALSE == hr) ? S_OK : hr);
return hr;
}
//+---------------------------------------------------------------------------
// IPersistNetConnection
//
STDMETHODIMP
CDialupConnection::GetClassID (
CLSID* pclsid)
{
HRESULT hr = S_OK;
// Validate parameters.
//
if (!pclsid)
{
hr = E_POINTER;
}
else
{
*pclsid = CLSID_DialupConnection;
}
TraceError ("CDialupConnection::GetClassID", hr);
return hr;
}
STDMETHODIMP
CDialupConnection::GetSizeMax (
ULONG* pcbSize)
{
HRESULT hr = HrPersistGetSizeMax (pcbSize);
TraceError ("CDialupConnection::GetSizeMax", hr);
return hr;
}
STDMETHODIMP
CDialupConnection::Load (
const BYTE* pbBuf,
ULONG cbSize)
{
HRESULT hr = HrPersistLoad (pbBuf, cbSize);
TraceError ("CDialupConnection::Load", hr);
return hr;
}
STDMETHODIMP
CDialupConnection::Save (
BYTE* pbBuf,
ULONG cbSize)
{
HRESULT hr = HrPersistSave (pbBuf, cbSize);
TraceError ("CDialupConnection::Save", hr);
return hr;
}
//+---------------------------------------------------------------------------
// INetConnectionBrandingInfo
//
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::GetBrandingIconPaths
//
// Purpose: Returns the full paths to three icons.
//
// Arguments: pConBrandInfo - pointer to an Icon branding structure
//
// Returns: S_OK or an error code
//
STDMETHODIMP
CDialupConnection::GetBrandingIconPaths(
CON_BRANDING_INFO ** ppConBrandInfo)
{
HRESULT hr = HrEnsureEntryPropertiesCached ();
CON_BRANDING_INFO * pConBrandInfo = NULL;
Assert(ppConBrandInfo);
if (SUCCEEDED(hr))
{
if (!FIsBranded ())
{
hr = E_NOTIMPL;
}
else
{
WCHAR szTemp[MAX_PATH+1];
WCHAR szIconName[MAX_PATH+1];
const WCHAR* const CMSECTION = L"Connection Manager";
HICON hIcon;
hr = HrCoTaskMemAlloc(sizeof(CON_BRANDING_INFO), (LPVOID*)&pConBrandInfo);
if (SUCCEEDED(hr))
{
ZeroMemory(pConBrandInfo, sizeof(CON_BRANDING_INFO));
// Get the path to the cms file to get the Icon entries from.
//
hr = HrEnsureCmStringsLoaded();
if (SUCCEEDED(hr))
{
// Get the Large Icon path
//
if (0 != GetPrivateProfileStringW(CMSECTION, L"Icon", L"",
szIconName, celems(szIconName), PszwCmsFile ()))
{
lstrcpynW(szTemp, PszwCmDir (), celems(szTemp));
lstrcatW(szTemp, szIconName);
if (NULL != (hIcon = (HICON)LoadImage(NULL, szTemp, IMAGE_ICON, 32, 32, LR_LOADFROMFILE)))
{
DestroyIcon(hIcon);
hr = HrCoTaskMemAllocAndDupSz (szTemp, &(pConBrandInfo->szwLargeIconPath));
}
}
// See if the CM icon is hidden
WCHAR szHideTrayIcon[MAX_PATH+1];
DWORD dwHideTrayIcon = 1; // default is to hide the CM icon
if (SUCCEEDED(hr) &&
(0 != GetPrivateProfileStringW(CMSECTION, L"HideTrayIcon", L"1",
szHideTrayIcon, celems(szHideTrayIcon), PszwCmsFile ())))
{
dwHideTrayIcon = _ttoi(szHideTrayIcon);
}
if (dwHideTrayIcon) // If the CM icon is not hidden, we don't want another branded icon. We'll use blinky lights instead
{
// Get the Tray Icon path
//
if (SUCCEEDED(hr) &&
(0 != GetPrivateProfileStringW(CMSECTION, L"TrayIcon", L"",
szIconName, celems(szIconName), PszwCmsFile ())))
{
lstrcpynW(szTemp, PszwCmDir (), celems(szTemp));
lstrcatW(szTemp, szIconName);
if (NULL != (hIcon = (HICON)LoadImage(NULL, szTemp, IMAGE_ICON, 16, 16, LR_LOADFROMFILE)))
{
DestroyIcon(hIcon);
hr = HrCoTaskMemAllocAndDupSz (szTemp, &(pConBrandInfo->szwTrayIconPath));
}
}
}
}
}
}
}
// Fill in the out param struct if we succeeded, otherwise leave it alone so it will still
// marshall.
//
if (SUCCEEDED(hr))
{
*ppConBrandInfo = pConBrandInfo;
}
TraceError ("CDialupConnection::GetBrandingIconPaths", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::GetTrayMenuEntries
//
// Purpose: Returns any branded menu items to be added to the tray menu.
//
// Arguments: pMenuData -- Pointer to a Tray Menu Data struct
//
// Returns: S_OK or an error code
//
STDMETHODIMP
CDialupConnection::GetTrayMenuEntries(
CON_TRAY_MENU_DATA** ppMenuData)
{
// initialize output
Assert(ppMenuData);
*ppMenuData = NULL;
CON_TRAY_MENU_DATA * pMenuData = NULL;
HRESULT hr = HrEnsureEntryPropertiesCached ();
if (SUCCEEDED(hr))
{
if (!FIsBranded ())
{
hr = E_NOTIMPL;
}
else
{
hr = HrEnsureCmStringsLoaded();
if (SUCCEEDED(hr))
{
//
// Get the menu item section
//
WCHAR* pszMenuItemsSection = NULL;
int nSize;
hr = HrGetPrivateProfileSectionWithAlloc(&pszMenuItemsSection, &nSize);
// Process the menu items
//
if (SUCCEEDED(hr) && (nSize>0))
{
// We have menu items to process. First make a copy of the data
// and figure out a line count.
//
hr = HrCoTaskMemAlloc(sizeof(CON_TRAY_MENU_DATA), (LPVOID*)&pMenuData);
if (SUCCEEDED(hr))
{
DWORD dwCount = 0;
WCHAR*pszLine = NULL;
WCHAR szName[MAX_PATH+1];
WCHAR szCmdLine[MAX_PATH+1];
WCHAR szParams[MAX_PATH+1];
pszLine = pszMenuItemsSection;
while ((NULL != pszLine) && (0 != *pszLine))
{
if (SUCCEEDED(HrGetMenuNameAndCmdLine(pszLine, szName,
szCmdLine, szParams)))
{
dwCount++;
}
pszLine = pszLine + lstrlenW(pszLine) + 1;
}
ASSERT(0 != dwCount);
// Now that we have an accurate count, lets
// allocate the memory for the marshalling and
// reparse the items.
//
hr = HrCoTaskMemAlloc(dwCount*sizeof(CON_TRAY_MENU_ENTRY),
(LPVOID*)&pMenuData->pctme);
if (SUCCEEDED(hr))
{
pMenuData->dwCount = dwCount;
DWORD dwNumAdded = 0;
pszLine = pszMenuItemsSection;
while ((NULL != pszLine) && (0 != *pszLine) && SUCCEEDED(hr))
{
if (SUCCEEDED(HrGetMenuNameAndCmdLine(pszLine,
szName, szCmdLine, szParams)) && (dwNumAdded <= dwCount))
{
hr = HrFillInConTrayMenuEntry(szName, szCmdLine, szParams,
&(pMenuData->pctme[dwNumAdded]));
if (FAILED(hr))
{
CoTaskMemFree(&pMenuData->pctme);
}
dwNumAdded++;
}
pszLine = pszLine + lstrlenW(pszLine) + 1;
}
}
else
{
delete pMenuData;
}
}
delete (pszMenuItemsSection);
}
}
}
}
// Fill in the out param struct if we succeeded, otherwise leave it alone so it will still
// marshall.
//
if (SUCCEEDED(hr))
{
*ppMenuData = pMenuData;
}
TraceError ("CDialupConnection::GetTrayMenuEntries", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::HrGetPrivateProfileSectionWithAlloc
//
// Purpose: This function ensures that the CM specific member vars for dialup
// are loaded and usable by CM specific functions.
//
// Arguments: none
//
// Returns: S_OK or an error code
//
HRESULT
CDialupConnection::HrGetPrivateProfileSectionWithAlloc (
WCHAR** pszSection,
int* pnSize)
{
Assert(pszSection);
Assert(pnSize);
HRESULT hr = HrEnsureCmStringsLoaded();
if (!pszSection)
{
return E_POINTER;
}
if (!pnSize)
{
return E_POINTER;
}
if (SUCCEEDED(hr))
{
const int c_64K= 64*1024;
int nAllocated = 1024;
*pnSize = nAllocated - 2;
while ((nAllocated <= c_64K) && ((*pnSize) == (nAllocated - 2)))
{
// Should never need more than the 4-5 lines we already allocated
// but someone might want lots of menu options.
//
if (NULL != *pszSection)
{
delete (*pszSection);
}
*pszSection = new WCHAR[nAllocated];
if (*pszSection)
{
*pnSize = GetPrivateProfileSectionW(L"Menu Options",
*pszSection, nAllocated,
PszwCmsFile ());
}
else
{
hr = E_OUTOFMEMORY;
break;
}
nAllocated = 2*nAllocated;
}
if (nAllocated > c_64K)
{
hr = E_UNEXPECTED;
}
if (nAllocated > c_64K || 0 == *pnSize)
{
// We need to free this in both cases, because if the size is 0, then the callers don't free this.
delete *pszSection;
}
}
TraceError ("CDialupConnection::HrGetPrivateProfileSectionWithAlloc", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::HrGetMenuNameAndCmdLine
//
// Purpose: Given a menu item line from a CMS file parses out the Menu item name,
// Menu executable, and Menu item parameters.
//
// Arguments: pMenuData -- Pointer to a Tray Menu Data struct
//
// Returns: S_OK or an error code
//
HRESULT
CDialupConnection::HrGetMenuNameAndCmdLine(
PWSTR pszString,
PWSTR szName,
PWSTR szProgram,
PWSTR szParams)
{
WCHAR* pszPtr1;
WCHAR* pszPtr2;
WCHAR szLine[MAX_PATH+1];
BOOL fLong = FALSE;
HRESULT hr;
Assert(NULL != pszString);
Assert(NULL != szName);
Assert(NULL != szProgram);
Assert(NULL != szParams);
ZeroMemory(szName, celems(szName));
ZeroMemory(szProgram, celems(szProgram));
ZeroMemory(szParams, celems(szParams));
lstrcpynW(szLine, pszString, celems(szLine));
// Process the first portion, the "Name=" part
//
pszPtr1 = wcsstr(szLine, L"=");
if (pszPtr1)
{
*pszPtr1 = 0;
lstrcpynW(szName, szLine, MAX_PATH);
// Process next portion, the program name
//
pszPtr1++;
if (pszPtr1)
{
// Look for "+" or " " marking end of program portion
//
if (*pszPtr1 == L'+')
{
pszPtr1++;
pszPtr2 = wcsstr(pszPtr1, L"+");
fLong = TRUE;
}
else
{
// If not a long filename then we have two choices,
// either a short program name and params or just a
// short program name.
//
pszPtr2 = wcsstr(pszPtr1, L" ");
fLong = FALSE;
}
// Terminate program name and copy
//
if (pszPtr2)
{
if (*pszPtr2 != 0)
{
*pszPtr2 = 0;
pszPtr2++;
}
lstrcpynW(szProgram, pszPtr1, MAX_PATH);
// Process final portion, the params
//
if (fLong)
{
pszPtr2++; // skip blank
}
// Now we are have the param string
//
if (pszPtr2)
{
lstrcpynW(szParams, pszPtr2, MAX_PATH);
}
}
else
{
// Just a program with no params and no space seperator
// (this happens on memphis)
//
lstrcpynW(szProgram, pszPtr1, MAX_PATH);
}
}
hr = S_OK;
}
else
{
// No entries
//
hr = E_UNEXPECTED;
}
TraceError ("CDialupConnection::HrGetMenuNameAndCmdLine", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::HrFillInConTrayMenuEntry
//
// Purpose: Given the elements of a ConTrayMenuEntry struct, the function
// allocs the memory necessary and copies of the given elements.
//
// Arguments: szwName - Display name of the command to show in the tray context menu
// szwCmdLine - actual command to run for this menu entry
// szwParams - command params for this command
// pMenuEntry - pointer to the struct to fill in and execute
//
// Returns: S_OK or an error code
//
HRESULT
CDialupConnection::HrFillInConTrayMenuEntry (
PCWSTR szName,
PCWSTR szCmdLine,
PCWSTR szParams,
CON_TRAY_MENU_ENTRY* pMenuEntry)
{
HRESULT hr;
ZeroMemory(pMenuEntry, sizeof(CON_TRAY_MENU_ENTRY));
hr = HrCoTaskMemAlloc ((lstrlenW(szName)+1)*sizeof(WCHAR),
(LPVOID*)&(pMenuEntry->szwMenuText));
if (SUCCEEDED(hr))
{
lstrcpyW(pMenuEntry->szwMenuText, szName);
hr = HrCoTaskMemAlloc ((lstrlenW(szParams)+1)*sizeof(WCHAR),
(LPVOID*)&(pMenuEntry->szwMenuParams));
if (S_OK == hr)
{
lstrcpyW(pMenuEntry->szwMenuParams, szParams);
if (0 == wcsncmp(PszwShortServiceName (), szCmdLine,
lstrlenW(PszwShortServiceName ())))
{
//
// Then we have an included file. Add the profile dir path
//
// Take out the "short service name" because it's already included in the path
PCWSTR pszFileName = szCmdLine + lstrlenW(PszwShortServiceName()) + 1;
hr = HrCoTaskMemAlloc ((lstrlenW(pszFileName)+lstrlenW(PszwProfileDir())+1)*sizeof(WCHAR),
(LPVOID*)&(pMenuEntry->szwMenuCmdLine));
if (S_OK == hr)
{
lstrcpyW(pMenuEntry->szwMenuCmdLine, PszwProfileDir ());
lstrcatW(pMenuEntry->szwMenuCmdLine, pszFileName);
}
}
else
{
hr = HrCoTaskMemAlloc ((lstrlenW(szCmdLine)+1)*sizeof(WCHAR),
(LPVOID*)&(pMenuEntry->szwMenuCmdLine));
if (S_OK == hr)
{
lstrcpyW(pMenuEntry->szwMenuCmdLine, szCmdLine);
}
}
}
}
if (FAILED(hr))
{
//
// We Failed so free the memory
//
CoTaskMemFree(pMenuEntry->szwMenuText);
CoTaskMemFree(pMenuEntry->szwMenuCmdLine);
CoTaskMemFree(pMenuEntry->szwMenuParams);
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::HrGetCmpFileLocation
//
// Purpose: Compares the phonebook file path to path of the current user's
// application data dir. If the initial paths are the same we have
// a private profile. Please NOTE that calling this function
// requires the calling client to properly setup CoSetProxyBlanket for
// a private user profile (matches the call to CoImpersonateClient)
//
// Arguments: szwPhonebook -- path to the phonebook the CM connectoid lives in
//
// Returns: S_OK or an error code
//
HRESULT
CDialupConnection::HrGetCmpFileLocation(
PCWSTR szPhonebook,
PCWSTR szEntryName,
PWSTR szCmpFilePath)
{
DWORD dwSize = MAX_PATH;
HKEY hKey;
HANDLE hBaseKey = NULL;
HANDLE hFile;
HRESULT hr;
HRESULT hrImpersonate = E_FAIL;
static const WCHAR c_mappingsRegKey[] = L"Software\\Microsoft\\Connection Manager\\Mappings";
HANDLE hImpersonationToken = NULL; // The token of the thread
HANDLE hPrimaryToken = NULL; // The primary token for the new process
if ((NULL == szCmpFilePath) || (NULL == szPhonebook))
{
hr = E_POINTER;
}
else
{
hr = HrEnsureEntryPropertiesCached ();
if (SUCCEEDED(hr))
{
if (m_fForAllUsers)
{
// We have an all users key so get the information from HKLM
//
hBaseKey = HKEY_LOCAL_MACHINE;
}
else
{
// Then we have a private profile. Since netman runs as a system account,
// we must impersonate the client and then make an RTL call to get
// the current users HKCU hive before querying the registry for the
// cmp path. We also need to get the user token so that we can expand the
// cmp string in the single user case.
//
hrImpersonate = CoImpersonateClient ();
TraceError ("HrGetCmpFileLocation -- CoImpersonateClient", hr);
if (SUCCEEDED(hrImpersonate))
{
NTSTATUS ntstat = RtlOpenCurrentUser(KEY_READ | KEY_WRITE, &hBaseKey);
hr = HRESULT_FROM_NT(ntstat);
TraceError ("RtlOpenCurrentUser", hr);
if (SUCCEEDED(hr))
{
// Create a primary token
//
if (!OpenThreadToken(
GetCurrentThread(),
TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
TRUE,
&hImpersonationToken))
{
hr = HrFromLastWin32Error();
TraceError ("HrGetCmpFileLocation -- OpenThreadToken", hr);
}
else
{
if(!DuplicateTokenEx(hImpersonationToken,
TOKEN_IMPERSONATE | TOKEN_READ | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE,
NULL,
SecurityImpersonation,
TokenPrimary,
&hPrimaryToken
))
{
hr = HrFromLastWin32Error();
TraceError ("HrGetCmpFileLocation -- DuplicateTokenEx", hr);
}
}
}
}
}
// Now Open the mappings key and get the cmp file path
//
if (SUCCEEDED(hr))
{
hr = HrRegOpenKeyEx((HKEY)hBaseKey,
c_mappingsRegKey,
KEY_READ, &hKey);
if (SUCCEEDED(hr))
{
dwSize = MAX_PATH;
WCHAR szTemp[MAX_PATH+1];
hr = HrRegQuerySzBuffer(hKey, szEntryName, szTemp, &dwSize);
if (SUCCEEDED (hr))
{
// Check to see if the file exists
//
if (!m_fForAllUsers)
{
ExpandEnvironmentStringsForUserW(hPrimaryToken, szTemp,
szCmpFilePath, MAX_PATH);
}
else
{
lstrcpyW(szCmpFilePath, szTemp);
}
hFile = CreateFile(szCmpFilePath, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
else
{
CloseHandle(hFile);
hr = S_OK;
}
}
RegCloseKey(hKey);
}
}
}
if (!m_fForAllUsers)
{
if (hImpersonationToken)
{
CloseHandle(hImpersonationToken);
}
if (hPrimaryToken)
{
CloseHandle(hPrimaryToken);
}
// Close the handle opened by RtlOpenCurrentUser
//
NtClose(hBaseKey);
}
if (SUCCEEDED(hrImpersonate))
{
hr = CoRevertToSelf ();
TraceError ("HrGetCmpFileLocation -- CoRevertToSelf", hr);
}
}
TraceError ("CDialupConnection::HrGetCmpFileLocation", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::HrEnsureCmStringsLoaded
//
// Purpose: This function ensures that the CM specific member vars for dialup
// are loaded and usable by CM specific functions. Please NOTE that
// calling EnsureCmStringsAreLoaded requires the calling client to
// properly setup CoSetProxyBlanket for a private user profile.
//
// Arguments: none
//
// Returns: S_OK or an error code
//
HRESULT
CDialupConnection::HrEnsureCmStringsLoaded()
{
HRESULT hr = S_OK;
if (!m_fCmPathsLoaded)
{
WCHAR szwCmpFile[MAX_PATH];
WCHAR szwCmsFile[MAX_PATH];
WCHAR szwDrive[MAX_PATH];
WCHAR szwDir[MAX_PATH];
WCHAR szwFileName[MAX_PATH];
WCHAR szwExtension[MAX_PATH];
WCHAR szwProfileDir[MAX_PATH];
WCHAR szwCmDir[MAX_PATH];
int nNumChars;
hr = HrGetCmpFileLocation(PszwPbkFile (), PszwEntryName (), szwCmpFile);
if (SUCCEEDED(hr))
{
// Now split the path
//
_wsplitpath(szwCmpFile, szwDrive, szwDir, szwFileName, szwExtension);
// Now construct the path to the cms file
//
nNumChars = wsprintfW(szwCmsFile, L"%s%s%s\\%s%s", szwDrive, szwDir, szwFileName, szwFileName, L".cms");
ASSERT(nNumChars < celems(szwCmsFile));
// Now construct the profile dir path
//
nNumChars = wsprintfW(szwProfileDir, L"%s%s%s\\", szwDrive, szwDir, szwFileName);
ASSERT(nNumChars < celems(szwProfileDir));
// Now construct the CM dir path
//
nNumChars = wsprintfW(szwCmDir, L"%s%s", szwDrive, szwDir);
ASSERT(nNumChars < celems(szwCmDir));
// Now transfer to the member variables
//
m_strCmsFile = szwCmsFile;
m_strProfileDir = szwProfileDir; // remember this already has the trailing slash
m_strCmDir = szwCmDir; // remember this already has the trailing slash
m_strShortServiceName = szwFileName;
m_fCmPathsLoaded = TRUE;
}
}
TraceError ("CDialupConnection::HrEnsureCmStringsLoaded", hr);
return hr;
}
// INetDefaultConnection
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::SetDefault
//
// Purpose: Set the default RAS connection
//
// Arguments: TRUE to set as default connection. FALSE to unset it
//
// Returns: S_OK or an error code
//
HRESULT
CDialupConnection::SetDefault(BOOL bDefault)
{
HRESULT hr = S_OK;
HRESULT hrT = S_OK;
if (!m_fInitialized)
{
hr = E_UNEXPECTED;
}
else
{
hr = HrEnsureEntryPropertiesCached ();
if (SUCCEEDED(hr))
{
RASAUTODIALENTRY adEntry;
ZeroMemory(&adEntry, sizeof(adEntry));
adEntry.dwSize = sizeof(adEntry);
if (bDefault)
{
wcsncpy(adEntry.szEntry, PszwEntryName(), sizeof(adEntry.szEntry) / sizeof(TCHAR));
}
hrT = CoImpersonateClient();
if (SUCCEEDED(hrT))
{
DWORD dwErr = RasSetAutodialAddress(
NULL,
NULL,
&adEntry,
sizeof(adEntry),
1);
if (dwErr != NO_ERROR)
{
hr = HRESULT_FROM_WIN32(dwErr);
}
hrT = CoRevertToSelf();
}
}
}
TraceError ("CDialupConnection::SetDefault", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::GetDefault
//
// Purpose: Get the default RAS connection
//
// Arguments: pbDefault - Is this the default connection
//
// Returns: S_OK or an error code
//
HRESULT
CDialupConnection::GetDefault (BOOL* pbDefault)
{
HRESULT hr = S_OK;
if (!m_fInitialized)
{
hr = E_UNEXPECTED;
}
else
{
hr = HrEnsureEntryPropertiesCached ();
if (SUCCEEDED(hr))
{
if (m_dwFlagsPriv & REED_F_Default)
{
*pbDefault = TRUE;
}
else
{
*pbDefault = FALSE;
}
}
}
TraceError ("CDialupConnection::GetDefault", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CDialupConnection::GetDefault
//
// Purpose: Get the default RAS connection
//
// Arguments: pbDefault - Is this the default connection
//
// Returns: S_OK or an error code
//
HRESULT
CDialupConnection::GetPropertiesEx(NETCON_PROPERTIES_EX** ppConnectionPropertiesEx)
{
HRESULT hr = S_OK;
*ppConnectionPropertiesEx = NULL;
if (!m_fInitialized)
{
hr = E_UNEXPECTED;
}
else
{
NETCON_PROPERTIES* pProps;
NETCON_PROPERTIES_EX* pPropsEx = reinterpret_cast<NETCON_PROPERTIES_EX*>(CoTaskMemAlloc(sizeof(NETCON_PROPERTIES_EX)));
if (pPropsEx)
{
ZeroMemory(pPropsEx, sizeof(NETCON_PROPERTIES_EX));
hr = GetProperties(&pProps);
if (SUCCEEDED(hr))
{
hr = HrBuildPropertiesExFromProperties(pProps, pPropsEx, dynamic_cast<IPersistNetConnection *>(this));
if (SUCCEEDED(hr))
{
pPropsEx->bstrPhoneOrHostAddress = SysAllocString(m_strPhoneNumber.c_str());
*ppConnectionPropertiesEx = pPropsEx;
}
FreeNetconProperties(pProps);
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
TraceError ("CDialupConnection::GetPropertiesEx", hr);
return hr;
}