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.
1667 lines
49 KiB
1667 lines
49 KiB
// nwlnkipx.cpp : Implementation of CNwlnkIPX
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
#include <ncxbase.h>
|
|
#include <netconp.h>
|
|
#include "ncmisc.h"
|
|
#include "ncnetcfg.h"
|
|
#include "ncpnp.h"
|
|
#include "ncreg.h"
|
|
#include "nwlnkipx.h"
|
|
|
|
extern const WCHAR c_szAdapterSections[];
|
|
extern const WCHAR c_szAdapters[];
|
|
extern const WCHAR c_szSpecificTo[];
|
|
extern const WCHAR c_szSvcNwlnkIpx[];
|
|
extern const WCHAR c_szInfId_MS_NWNB[];
|
|
extern const WCHAR c_szInfId_MS_NWSPX[];
|
|
|
|
|
|
static const WCHAR c_szProviderOrderVal[] = L"ProviderOrder";
|
|
static const WCHAR c_szSrvProvOrderKey[] = L"System\\CurrentControlSet\\Control\\ServiceProvider\\Order";
|
|
|
|
const WCHAR c_sz0xPrefix[] = L"0x";
|
|
const WCHAR c_sz8Zeros[] = L"00000000";
|
|
const DWORD c_dwPktTypeDefault = AUTO;
|
|
const WCHAR c_szMediaType[] = L"MediaType";
|
|
|
|
static const WCHAR c_szIpxParameters[] = L"System\\CurrentControlSet\\Services\\NwlnkIpx\\Parameters";
|
|
static const WCHAR c_szPktType[] = L"PktType";
|
|
static const WCHAR c_szNetworkNumber[] = L"NetworkNumber";
|
|
static const WCHAR c_szDedicatedRouter[] = L"DedicatedRouter";
|
|
static const WCHAR c_szEnableWANRouter[] = L"EnableWANRouter";
|
|
static const WCHAR c_szInitDatagrams[] = L"InitDatagrams";
|
|
static const WCHAR c_szMaxDatagrams[] = L"MaxDatagrams";
|
|
static const WCHAR c_szReplaceConfigDialog[] = L"ReplaceConfigDialog";
|
|
static const WCHAR c_szRipCount[] = L"RipCount";
|
|
static const WCHAR c_szRipTimeout[] = L"RipTimeout";
|
|
static const WCHAR c_szRipUsageTime[] = L"RipUsageTime";
|
|
static const WCHAR c_szSocketEnd[] = L"SocketEnd";
|
|
static const WCHAR c_szSocketStart[] = L"SocketStart";
|
|
static const WCHAR c_szSocketUniqueness[] = L"SocketUniqueness";
|
|
static const WCHAR c_szSourceRouteUsageTime[]= L"SourceRouteUsageTime";
|
|
static const WCHAR c_szVirtualNetworkNumber[]= L"VirtualNetworkNumber";
|
|
|
|
static const DWORD c_dwBindSap = 0x8137;
|
|
static const DWORD c_dwEnableFuncaddr = 1;
|
|
static const DWORD c_dwMaxPktSize = 0;
|
|
static const DWORD c_dwSourceRouteBCast = 0;
|
|
static const DWORD c_dwSourceRouteMCast = 0;
|
|
static const DWORD c_dwSourceRouteDef = 0;
|
|
static const DWORD c_dwSourceRouting = 1;
|
|
|
|
static const WCHAR c_szBindSap[] = L"BindSap";
|
|
static const WCHAR c_szEnableFuncaddr[] = L"EnableFuncaddr";
|
|
static const WCHAR c_szMaxPktSize[] = L"MaxPktSize";
|
|
static const WCHAR c_szSourceRouteBCast[] = L"SourceRouteBCast";
|
|
static const WCHAR c_szSourceRouteMCast[] = L"SourceRouteMCast";
|
|
static const WCHAR c_szSourceRouteDef[] = L"SourceRouteDef";
|
|
static const WCHAR c_szSourceRouting[] = L"SourceRouting";
|
|
|
|
static const DWORD c_dwDedicatedRouter = 0;
|
|
static const DWORD c_dwEnableWANRouter = 0;
|
|
static const DWORD c_dwInitDatagrams = 0xa;
|
|
static const DWORD c_dwMaxDatagrams = 0x32;
|
|
static const DWORD c_dwReplaceConfigDialog = 0;
|
|
static const DWORD c_dwRipCount = 0x5;
|
|
static const DWORD c_dwRipTimeout = 0x1;
|
|
static const DWORD c_dwRipUsageTime = 0xf;
|
|
static const DWORD c_dwSocketEnd = 0x5fff;
|
|
static const DWORD c_dwSocketStart = 0x4000;
|
|
static const DWORD c_dwSocketUniqueness = 0x8;
|
|
static const DWORD c_dwSourceRouteUsageTime = 0xf;
|
|
static const DWORD c_dwVirtualNetworkNumber = 0;
|
|
|
|
static const REGBATCH regbatchIpx[] = {
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szDedicatedRouter, REG_DWORD,
|
|
offsetof(IpxParams,dwDedicatedRouter), (BYTE *)&c_dwDedicatedRouter},
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szEnableWANRouter, REG_DWORD,
|
|
offsetof(IpxParams,dwEnableWANRouter), (BYTE *)&c_dwEnableWANRouter},
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szInitDatagrams, REG_DWORD,
|
|
offsetof(IpxParams,dwInitDatagrams), (BYTE *)&c_dwInitDatagrams},
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szMaxDatagrams, REG_DWORD,
|
|
offsetof(IpxParams,dwMaxDatagrams), (BYTE *)&c_dwMaxDatagrams},
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szReplaceConfigDialog, REG_DWORD,
|
|
offsetof(IpxParams,dwReplaceConfigDialog), (BYTE *)&c_dwReplaceConfigDialog},
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szRipCount, REG_DWORD,
|
|
offsetof(IpxParams,dwRipCount), (BYTE *)&c_dwRipCount},
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szRipTimeout, REG_DWORD,
|
|
offsetof(IpxParams,dwRipTimeout), (BYTE *)&c_dwRipTimeout},
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szRipUsageTime, REG_DWORD,
|
|
offsetof(IpxParams,dwRipUsageTime), (BYTE *)&c_dwRipUsageTime},
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szSocketEnd, REG_DWORD,
|
|
offsetof(IpxParams,dwSocketEnd), (BYTE *)&c_dwSocketEnd},
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szSocketStart, REG_DWORD,
|
|
offsetof(IpxParams,dwSocketStart), (BYTE *)&c_dwSocketStart},
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szSocketUniqueness, REG_DWORD,
|
|
offsetof(IpxParams,dwSocketUniqueness), (BYTE *)&c_dwSocketUniqueness},
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szSourceRouteUsageTime, REG_DWORD,
|
|
offsetof(IpxParams,dwSourceRouteUsageTime), (BYTE *)&c_dwSourceRouteUsageTime},
|
|
{HKEY_LOCAL_MACHINE, c_szIpxParameters, c_szVirtualNetworkNumber, REG_DWORD,
|
|
offsetof(IpxParams,dwVirtualNetworkNumber), (BYTE *)&c_dwVirtualNetworkNumber}};
|
|
|
|
|
|
CNwlnkIPX::CNwlnkIPX() :
|
|
m_pnccMe(NULL),
|
|
m_pNetCfg(NULL),
|
|
m_fNetworkInstall(FALSE),
|
|
m_fAdapterListChanged(FALSE),
|
|
m_fPropertyChanged(FALSE),
|
|
m_eInstallAction(eActUnknown),
|
|
m_pspObj1(NULL),
|
|
m_pspObj2(NULL),
|
|
m_pIpxEnviroment(NULL),
|
|
m_pUnkPropContext(NULL)
|
|
{
|
|
}
|
|
|
|
CNwlnkIPX::~CNwlnkIPX()
|
|
{
|
|
ReleaseObj(m_pUnkPropContext);
|
|
ReleaseObj(m_pNetCfg);
|
|
ReleaseObj(m_pnccMe);
|
|
|
|
delete m_pIpxEnviroment;
|
|
|
|
CleanupPropPages();
|
|
}
|
|
|
|
|
|
// INetCfgNotify
|
|
|
|
STDMETHODIMP CNwlnkIPX::Initialize (
|
|
INetCfgComponent* pncc,
|
|
INetCfg* pNetCfg,
|
|
BOOL fInstalling)
|
|
{
|
|
HRESULT hr;
|
|
|
|
Validate_INetCfgNotify_Initialize(pncc, pNetCfg, fInstalling);
|
|
|
|
// Hold on to our the component representing us and our host
|
|
// INetCfg object.
|
|
AddRefObj (m_pnccMe = pncc);
|
|
AddRefObj (m_pNetCfg = pNetCfg);
|
|
|
|
//
|
|
// Determine if the Netware stack is installed, if so DO NOT
|
|
// install over it.
|
|
//
|
|
if (FIsNetwareIpxInstalled())
|
|
{
|
|
//TODO: EventLog(Novell Netware already installed);
|
|
//$REVIEW: Do we just want to silently proceed an do nothing?
|
|
}
|
|
|
|
// Query current settings
|
|
hr = CIpxEnviroment::HrCreate(this, &m_pIpxEnviroment);
|
|
|
|
TraceError("CNwlnkIPX::Initialize",hr);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::Upgrade(DWORD, DWORD)
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::ReadAnswerFile (
|
|
PCWSTR pszAnswerFile,
|
|
PCWSTR pszAnswerSection)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
Validate_INetCfgNotify_ReadAnswerFile(pszAnswerFile, pszAnswerSection );
|
|
|
|
// Record the fact that this is a network installation
|
|
m_fNetworkInstall = TRUE;
|
|
m_eInstallAction = eActInstall;
|
|
|
|
// Only process answer file and install sub-components if the answer file
|
|
// is present. If the answer file is not present we should already be installed.
|
|
if (NULL == pszAnswerFile)
|
|
{
|
|
goto Error; // Success case
|
|
}
|
|
|
|
// Read the Answer file contents
|
|
hr = HrProcessAnswerFile(pszAnswerFile,
|
|
pszAnswerSection);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
Error:
|
|
TraceError("CNwlnkIPX::ReadAnswerFile",hr);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Function: CNwlnkIPX::HrProcessAnswerFile
|
|
//
|
|
// Purpose: Process the answer file information, merging
|
|
// its contents into the internal information
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns: HRESULT, S_OK on success
|
|
//
|
|
HRESULT CNwlnkIPX::HrProcessAnswerFile(PCWSTR pszAnswerFile,
|
|
PCWSTR pszAnswerSection)
|
|
{
|
|
CSetupInfFile csif;
|
|
DWORD dwData;
|
|
BOOL fValue;
|
|
HRESULT hr = S_OK;
|
|
INFCONTEXT infctx;
|
|
|
|
AssertSz(pszAnswerFile, "Answer file string is NULL!");
|
|
AssertSz(pszAnswerSection, "Answer file sections string is NULL!");
|
|
|
|
// Open the answer file.
|
|
hr = csif.HrOpen(pszAnswerFile, NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
// Release all of the adapter specific info
|
|
Assert(NULL != m_pIpxEnviroment);
|
|
m_pIpxEnviroment->ReleaseAdapterInfo();
|
|
|
|
// Read the DedicatedRouter parameter
|
|
hr = csif.HrGetStringAsBool(pszAnswerSection, c_szDedicatedRouter,
|
|
&fValue);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_pIpxEnviroment->SetDedicatedRouter(fValue);
|
|
}
|
|
|
|
// Read the EnableWANRouter parameter
|
|
hr = csif.HrGetStringAsBool(pszAnswerSection, c_szEnableWANRouter,
|
|
&fValue);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_pIpxEnviroment->SetEnableWANRouter(fValue);
|
|
}
|
|
|
|
// Read the virtual network number
|
|
hr = csif.HrGetDword(pszAnswerSection, c_szVirtualNetworkNumber, &dwData);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_pIpxEnviroment->SetVirtualNetworkNumber(dwData);
|
|
}
|
|
|
|
// Read the property containing the list of adapter sections
|
|
hr = ::HrSetupFindFirstLine(csif.Hinf(), pszAnswerSection,
|
|
c_szAdapterSections, &infctx);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
DWORD dwIdx;
|
|
DWORD dwCnt = SetupGetFieldCount(&infctx);
|
|
tstring str;
|
|
|
|
// For each adapter in the list read the adapter information
|
|
for (dwIdx=1; dwIdx <= dwCnt; dwIdx++)
|
|
{
|
|
hr = ::HrSetupGetStringField(infctx, dwIdx, &str);
|
|
if (FAILED(hr))
|
|
{
|
|
TraceError("CNwlnkIPX::HrProcessAnswerFile - Failed to read adapter section name",hr);
|
|
break;
|
|
}
|
|
|
|
hr = HrReadAdapterAnswerFileSection(&csif, str.c_str());
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
Error:
|
|
TraceError("CNwlnkIpx::HrProcessAnswerFile", hr);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Function: CNwlnkIPX::HrReadAdapterAnswerFileSection
|
|
//
|
|
// Purpose: Read the adapter answer file section and create
|
|
// the adapter info section if successful
|
|
//
|
|
// Parameters:
|
|
//
|
|
// Returns:
|
|
//
|
|
HRESULT
|
|
CNwlnkIPX::HrReadAdapterAnswerFileSection(CSetupInfFile * pcsif,
|
|
PCWSTR pszSection)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CIpxAdapterInfo * pAI = NULL;
|
|
INetCfgComponent* pncc = NULL;
|
|
tstring str;
|
|
|
|
// Read the SpecificTo adapter name
|
|
hr = pcsif->HrGetString(pszSection, c_szSpecificTo, &str);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
// Search for the specified adapter in the set of existing adapters
|
|
hr = ::HrAnswerFileAdapterToPNCC(m_pNetCfg, str.c_str(), &pncc);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
// if we found the adapter component object (pncc != NULL) process
|
|
// the adapter section
|
|
if (pncc)
|
|
{
|
|
DWORD dwIdx;
|
|
DWORD dwCnt;
|
|
INFCONTEXT infctx;
|
|
|
|
pAI = new CIpxAdapterInfo;
|
|
Assert(NULL != pAI);
|
|
|
|
// Query the adapter component info
|
|
hr = ::HrQueryAdapterComponentInfo(pncc, pAI);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
// Read the PktType (Failure is usually just "not found")
|
|
hr = ::HrSetupFindFirstLine(pcsif->Hinf(), pszSection, c_szPktType,
|
|
&infctx);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
dwCnt = ::SetupGetFieldCount(&infctx);
|
|
|
|
// For each adapter in the list read the adapter information
|
|
for (dwIdx=1; dwIdx <= dwCnt; dwIdx++)
|
|
{
|
|
hr = ::HrSetupGetStringField(infctx, dwIdx, &str);
|
|
if (FAILED(hr))
|
|
{
|
|
TraceError("CNwlnkIPX::HrProcessAnswerFile - Failed to read adapter section name",hr);
|
|
goto Error;
|
|
}
|
|
|
|
Assert(!str.empty());
|
|
|
|
// Raid # 205831 - Trim any leading "0x"
|
|
//
|
|
if (0 == _wcsnicmp(str.c_str(), c_sz0xPrefix, wcslen(c_sz0xPrefix)))
|
|
{
|
|
str.erase(0, wcslen(c_sz0xPrefix));
|
|
}
|
|
|
|
pAI->PFrmTypeList()->push_back(new tstring(str));
|
|
}
|
|
}
|
|
|
|
// Default PktType?
|
|
if (0 == pAI->PFrmTypeList()->size())
|
|
{
|
|
WCHAR szBuf[10];
|
|
|
|
// If the info was not found or contained no elements, add the
|
|
// default value.
|
|
wsprintfW(szBuf,L"%X",c_dwPktTypeDefault);
|
|
pAI->PFrmTypeList()->push_back(new tstring(szBuf));
|
|
}
|
|
|
|
// Read the NetworkNumber
|
|
hr = ::HrSetupFindFirstLine(pcsif->Hinf(), pszSection, c_szNetworkNumber,
|
|
&infctx);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
dwCnt = SetupGetFieldCount(&infctx);
|
|
|
|
// For each adapter in the list read the adapter information
|
|
for (dwIdx=1; dwIdx <= dwCnt; dwIdx++)
|
|
{
|
|
hr = ::HrSetupGetStringField(infctx, dwIdx, &str);
|
|
if (FAILED(hr))
|
|
{
|
|
TraceError("CNwlnkIPX::HrProcessAnswerFile - Failed to read adapter section name",hr);
|
|
goto Error;
|
|
}
|
|
|
|
Assert(!str.empty());
|
|
pAI->PNetworkNumList()->push_back(new tstring(str));
|
|
}
|
|
}
|
|
|
|
// Default Network Number?
|
|
if (0 == pAI->PNetworkNumList()->size())
|
|
{
|
|
// If the info was not found or contained no elements, add the
|
|
// default value.
|
|
pAI->PNetworkNumList()->push_back(new tstring(c_sz8Zeros));
|
|
}
|
|
|
|
// Ensure that the network number list has the same number of
|
|
// elements as the frame type list. This can happen when the user
|
|
// configures multiple frame types on 3.51 but only one network
|
|
// number is used. We'll extend the last network number used
|
|
// and pad it to make the network number list the same size.
|
|
//
|
|
Assert (pAI->PNetworkNumList()->size());
|
|
|
|
while (pAI->PNetworkNumList()->size() < pAI->PFrmTypeList()->size())
|
|
{
|
|
pAI->PNetworkNumList()->push_back(
|
|
new tstring(*pAI->PNetworkNumList()->back()));
|
|
}
|
|
|
|
pAI->SetDirty(TRUE);
|
|
m_pIpxEnviroment->AdapterInfoList().push_back(pAI);
|
|
MarkAdapterListChanged();
|
|
}
|
|
#ifdef ENABLETRACE
|
|
else
|
|
{
|
|
TraceTag(ttidDefault, "CNwlnkIPX::HrReadAdapterAnswerFileSection - "
|
|
"Adapter \"%S\" not yet installed.",str.c_str());
|
|
}
|
|
#endif
|
|
|
|
// Normalize return
|
|
hr = S_OK;
|
|
|
|
Done:
|
|
ReleaseObj(pncc);
|
|
return hr;
|
|
|
|
Error:
|
|
delete pAI;
|
|
TraceError("CNwlnkIpx::HrReadAdapterAnswerFileSection",hr);
|
|
goto Done;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::Install (DWORD)
|
|
{
|
|
HRESULT hr;
|
|
CIpxAdapterInfo * pAI;
|
|
ADAPTER_INFO_LIST::iterator iter;
|
|
|
|
m_eInstallAction = eActInstall;
|
|
|
|
// Mark all the initially detected adapters as dirty
|
|
for (iter = m_pIpxEnviroment->AdapterInfoList().begin();
|
|
iter != m_pIpxEnviroment->AdapterInfoList().end();
|
|
iter++)
|
|
{
|
|
pAI = *iter;
|
|
pAI->SetDirty(TRUE);
|
|
}
|
|
|
|
// Install NwlnkNb.
|
|
hr = ::HrInstallComponentOboComponent (m_pNetCfg, NULL,
|
|
GUID_DEVCLASS_NETTRANS,
|
|
c_szInfId_MS_NWNB,
|
|
m_pnccMe,
|
|
NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
// Install NwlnkSpx.
|
|
hr = ::HrInstallComponentOboComponent (m_pNetCfg, NULL,
|
|
GUID_DEVCLASS_NETTRANS,
|
|
c_szInfId_MS_NWSPX,
|
|
m_pnccMe,
|
|
NULL);
|
|
|
|
Error:
|
|
TraceError("CNwlnkIPX::Install",hr);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::Removing ()
|
|
{
|
|
HRESULT hr;
|
|
|
|
m_eInstallAction = eActRemove;
|
|
|
|
// Remove NwlnkNb.
|
|
hr = ::HrRemoveComponentOboComponent(m_pNetCfg, GUID_DEVCLASS_NETTRANS,
|
|
c_szInfId_MS_NWNB, m_pnccMe);
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
// Remove NwlnkSpx.
|
|
hr = ::HrRemoveComponentOboComponent(m_pNetCfg, GUID_DEVCLASS_NETTRANS,
|
|
c_szInfId_MS_NWSPX, m_pnccMe);
|
|
|
|
Error:
|
|
TraceError("CNwlnkIPX::Removing",hr);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::Validate ( )
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::CancelChanges ()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::ApplyRegistryChanges ()
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
switch(m_eInstallAction)
|
|
{
|
|
case eActInstall:
|
|
hr = HrCommitInstall();
|
|
break;
|
|
|
|
case eActRemove:
|
|
hr = HrCommitRemove();
|
|
break;
|
|
|
|
default: // eActUnknown (Configuration)
|
|
if (m_fAdapterListChanged || m_fPropertyChanged)
|
|
{
|
|
// Update the registry if the adapter list changed
|
|
Assert(m_pIpxEnviroment);
|
|
hr = m_pIpxEnviroment->HrUpdateRegistry();
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Send change notification
|
|
hr = HrReconfigIpx();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
TraceError("CNwlnkIPX::ApplyRegistryChanges",hr);
|
|
return hr;
|
|
}
|
|
|
|
|
|
// INetCfgComponentPropertyUi
|
|
STDMETHODIMP CNwlnkIPX::SetContext(IUnknown * pUnk)
|
|
{
|
|
ReleaseObj(m_pUnkPropContext);
|
|
m_pUnkPropContext = pUnk;
|
|
if (m_pUnkPropContext)
|
|
{
|
|
AddRefObj(m_pUnkPropContext);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CNwlnkIPX::MergePropPages (
|
|
IN OUT DWORD* pdwDefPages,
|
|
OUT LPBYTE* pahpspPrivate,
|
|
OUT UINT* pcPages,
|
|
IN HWND hwndParent,
|
|
OUT PCWSTR* pszStartPage)
|
|
{
|
|
Validate_INetCfgProperties_MergePropPages (
|
|
pdwDefPages, pahpspPrivate, pcPages, hwndParent, pszStartPage);
|
|
|
|
HRESULT hr = S_OK;
|
|
HPROPSHEETPAGE * ahpsp = NULL;
|
|
PRODUCT_FLAVOR pf;
|
|
int nPages = 0;
|
|
CIpxAdapterInfo * pAI = NULL;
|
|
|
|
Assert(pahpspPrivate);
|
|
Assert(*pahpspPrivate == NULL); // Out param init done via Validate above
|
|
*pcPages = 0;
|
|
|
|
// Start with new property pages each time.
|
|
CleanupPropPages();
|
|
|
|
// Get the current Adapter
|
|
if (NULL != m_pUnkPropContext)
|
|
{
|
|
CIpxAdapterInfo * pAITmp;
|
|
INetLanConnectionUiInfo * pLanConn = NULL;
|
|
ADAPTER_INFO_LIST::iterator iter;
|
|
|
|
hr = m_pUnkPropContext->QueryInterface(IID_INetLanConnectionUiInfo,
|
|
reinterpret_cast<LPVOID *>(&pLanConn));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
GUID guid;
|
|
hr = pLanConn->GetDeviceGuid(&guid);
|
|
ReleaseObj(pLanConn);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
// Find the adapter in our adapter list
|
|
for (iter = m_pIpxEnviroment->AdapterInfoList().begin();
|
|
iter != m_pIpxEnviroment->AdapterInfoList().end();
|
|
iter++)
|
|
{
|
|
pAITmp = *iter;
|
|
|
|
if (guid == *pAITmp->PInstanceGuid())
|
|
{
|
|
pAI = pAITmp;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Assert(SUCCEEDED(hr));
|
|
|
|
// If we have an adapter but it's
|
|
// disabled/hidden/deleted we show no pages
|
|
if ((NULL != pAI) && (pAI->FDeletePending() ||
|
|
pAI->FDisabled() || pAI->FHidden()))
|
|
{
|
|
Assert(0 == *pcPages);
|
|
hr = S_FALSE;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else if (E_NOINTERFACE == hr)
|
|
{
|
|
// RAS doesn't have the notion of a current adapter
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// m_pUnkPropContext should have been set first
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
// If the product is not workstation (therefore NTAS)
|
|
GetProductFlavor(NULL, &pf);
|
|
if ((PF_WORKSTATION != pf) && (NULL != pAI))
|
|
{
|
|
// Server
|
|
#ifdef INCLUDE_RIP_ROUTING
|
|
nPages = 2;
|
|
#else
|
|
nPages = 1;
|
|
#endif
|
|
|
|
// Allocate a buffer large enough to hold the handle to the IPX config.
|
|
// property page.
|
|
ahpsp = (HPROPSHEETPAGE *)CoTaskMemAlloc(sizeof(HPROPSHEETPAGE) * nPages);
|
|
if (!ahpsp)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto cleanup; // Alloc failed to no need to free ahpsp
|
|
}
|
|
|
|
// Allocate the CPropSheetPage objects
|
|
m_pspObj1 = new CIpxASConfigDlg(this, m_pIpxEnviroment, pAI);
|
|
#ifdef INCLUDE_RIP_ROUTING
|
|
m_pspObj2 = new CIpxASInternalDlg(this, m_pIpxEnviroment, pAI);
|
|
#endif
|
|
|
|
// Create the actual PROPSHEETPAGE for each object.
|
|
// This needs to be done regardless of whether the classes existed before.
|
|
ahpsp[0] = m_pspObj1->CreatePage(DLG_IPXAS_CONFIG, 0);
|
|
#ifdef INCLUDE_RIP_ROUTING
|
|
ahpsp[1] = m_pspObj2->CreatePage(DLG_IPXAS_INTERNAL, 0);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Workstation
|
|
nPages = 1;
|
|
|
|
// Allocate a buffer large enough to hold the handle to the IPX config.
|
|
// property page.
|
|
ahpsp = (HPROPSHEETPAGE *)CoTaskMemAlloc(sizeof(HPROPSHEETPAGE) * nPages);
|
|
if (!ahpsp)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto cleanup; // Alloc failed to no need to free ahpsp
|
|
}
|
|
|
|
// Allocate the CPropSheetPage object
|
|
m_pspObj1 = new CIpxConfigDlg(this, m_pIpxEnviroment, pAI);
|
|
|
|
// Create the actual PROPSHEETPAGE for each object.
|
|
// This needs to be done regardless of whether the classes existed before.
|
|
ahpsp[0] = m_pspObj1->CreatePage(DLG_IPX_CONFIG, 0);
|
|
}
|
|
|
|
if (NULL != ahpsp[0])
|
|
{
|
|
*pahpspPrivate = (LPBYTE)ahpsp;
|
|
*pcPages = nPages;
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Error;
|
|
}
|
|
|
|
cleanup:
|
|
TraceError("CNwlnkIPX::MergePropPages", hr);
|
|
return hr;
|
|
|
|
Error:
|
|
CoTaskMemFree(ahpsp);
|
|
goto cleanup;
|
|
}
|
|
|
|
VOID CNwlnkIPX::CleanupPropPages()
|
|
{
|
|
delete m_pspObj1;
|
|
m_pspObj1 = NULL;
|
|
|
|
#ifdef INCLUDE_RIP_ROUTING
|
|
delete m_pspObj2;
|
|
m_pspObj2 = NULL;
|
|
#endif
|
|
}
|
|
STDMETHODIMP CNwlnkIPX::ValidateProperties (HWND)
|
|
{
|
|
m_fPropertyChanged = TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::CancelProperties ()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::ApplyProperties ()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// INetCfgComponentNotifyBinding
|
|
|
|
STDMETHODIMP CNwlnkIPX::QueryBindingPath ( DWORD dwChangeFlag,
|
|
INetCfgBindingPath* pncbpItem )
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::NotifyBindingPath ( DWORD dwChangeFlag,
|
|
INetCfgBindingPath* pncbpItem )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
INetCfgComponent *pnccFound = NULL;
|
|
|
|
Validate_INetCfgBindNotify_NotifyBindingPath( dwChangeFlag, pncbpItem );
|
|
|
|
Assert(NULL != m_pIpxEnviroment);
|
|
|
|
// Only Interested in lower binding Add's and Remove's
|
|
if (dwChangeFlag & (NCN_ADD | NCN_REMOVE | NCN_ENABLE | NCN_DISABLE))
|
|
{
|
|
CIterNetCfgBindingInterface ncbiIter(pncbpItem);
|
|
INetCfgBindingInterface *pncbi;
|
|
|
|
// Enumerate the binding interfaces looking for an Adapter
|
|
while (SUCCEEDED(hr) &&
|
|
(S_OK == (hr = ncbiIter.HrNext (&pncbi))))
|
|
{
|
|
INetCfgComponent *pncc;
|
|
|
|
hr = pncbi->GetLowerComponent(&pncc);
|
|
if (S_OK == hr)
|
|
{
|
|
GUID guidClass;
|
|
hr = pncc->GetClassGuid(&guidClass);
|
|
if ((S_OK == hr) && (GUID_DEVCLASS_NET == guidClass))
|
|
{
|
|
ReleaseObj(pnccFound);
|
|
pnccFound = pncc; // Transfer Ownership
|
|
pncc = NULL;
|
|
}
|
|
else
|
|
{
|
|
ReleaseObj(pncc);
|
|
}
|
|
}
|
|
|
|
ReleaseObj(pncbi);
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
// Did we find the Adapter?
|
|
if (pnccFound)
|
|
{
|
|
BOOL fFound = FALSE;
|
|
PWSTR pszBindName = NULL;
|
|
CIpxAdapterInfo * pAI;
|
|
ADAPTER_INFO_LIST::iterator iterAdapterInfo;
|
|
|
|
Assert(m_pIpxEnviroment);
|
|
|
|
hr = pnccFound->GetBindName(&pszBindName);
|
|
if (S_OK != hr)
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
// Search the adapter list
|
|
for (iterAdapterInfo = m_pIpxEnviroment->AdapterInfoList().begin();
|
|
iterAdapterInfo != m_pIpxEnviroment->AdapterInfoList().end();
|
|
iterAdapterInfo++)
|
|
{
|
|
pAI = *iterAdapterInfo;
|
|
Assert (pAI);
|
|
|
|
if (0 == lstrcmpiW(pszBindName, pAI->SzBindName()))
|
|
{
|
|
fFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Assert(pszBindName);
|
|
CoTaskMemFree(pszBindName);
|
|
|
|
// Apply the appropriate delta to the adapter list
|
|
if (fFound && (dwChangeFlag & NCN_REMOVE))
|
|
{
|
|
// Mark the adapter as Delete Pending
|
|
pAI->SetDeletePending(TRUE);
|
|
m_fAdapterListChanged = TRUE;
|
|
}
|
|
else if (!fFound && (dwChangeFlag & NCN_ADD))
|
|
{
|
|
// Add the adapter to the list
|
|
hr = m_pIpxEnviroment->HrAddAdapter(pnccFound);
|
|
m_fAdapterListChanged = TRUE;
|
|
}
|
|
else if (fFound && (dwChangeFlag & NCN_ADD))
|
|
{
|
|
// Re-enable the adapters existance
|
|
pAI->SetDeletePending(FALSE);
|
|
}
|
|
|
|
if (fFound)
|
|
{
|
|
if (dwChangeFlag & NCN_ENABLE)
|
|
{
|
|
pAI->SetDisabled(FALSE);
|
|
m_fAdapterListChanged = TRUE;
|
|
}
|
|
else if (dwChangeFlag & NCN_DISABLE)
|
|
{
|
|
pAI->SetDisabled(TRUE);
|
|
m_fAdapterListChanged = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = S_OK; // Normailze return value
|
|
}
|
|
|
|
Error:
|
|
ReleaseObj(pnccFound);
|
|
TraceError("CNwlnkIPX::NotifyBindingPath",hr);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::GetFrameTypesForAdapter(PCWSTR pszAdapterBindName,
|
|
DWORD cFrameTypesMax,
|
|
DWORD* anFrameTypes,
|
|
DWORD* pcFrameTypes)
|
|
{
|
|
Assert(pszAdapterBindName);
|
|
Assert(cFrameTypesMax);
|
|
Assert(anFrameTypes);
|
|
Assert(pcFrameTypes);
|
|
|
|
*pcFrameTypes = 0;
|
|
|
|
ADAPTER_INFO_LIST::iterator iterAI;
|
|
|
|
for (iterAI = m_pIpxEnviroment->AdapterInfoList().begin();
|
|
iterAI != m_pIpxEnviroment->AdapterInfoList().end();
|
|
iterAI++)
|
|
{
|
|
CIpxAdapterInfo *pAI = *iterAI;
|
|
if (0 == lstrcmpW(pszAdapterBindName, pAI->SzBindName()))
|
|
{
|
|
list<tstring *>::iterator iterFrmType;
|
|
for (iterFrmType = pAI->PFrmTypeList()->begin();
|
|
(iterFrmType != pAI->PFrmTypeList()->end()) &&
|
|
(*pcFrameTypes < cFrameTypesMax);
|
|
iterFrmType++)
|
|
{
|
|
// Copy the Frame Type
|
|
tstring *pstr1 = *iterFrmType;
|
|
anFrameTypes[(*pcFrameTypes)++] = DwFromSz(pstr1->c_str(), 16);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::GetVirtualNetworkNumber(DWORD* pdwVNetworkNumber)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (NULL == pdwVNetworkNumber)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
goto Error;
|
|
}
|
|
|
|
Assert(NULL != m_pIpxEnviroment);
|
|
*pdwVNetworkNumber = m_pIpxEnviroment->DwVirtualNetworkNumber();
|
|
|
|
Error:
|
|
TraceError("CNwlnkIPX::GetVirtualNetworkNumber",hr);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CNwlnkIPX::SetVirtualNetworkNumber(DWORD dwVNetworkNumber)
|
|
{
|
|
HRESULT hr;
|
|
Assert(NULL != m_pIpxEnviroment);
|
|
m_pIpxEnviroment->SetVirtualNetworkNumber(dwVNetworkNumber);
|
|
m_fPropertyChanged = TRUE;
|
|
|
|
// Tell INetCfg that our component is dirty
|
|
INetCfgComponentPrivate* pinccp = NULL;
|
|
Assert(NULL != m_pnccMe);
|
|
hr = m_pnccMe->QueryInterface(IID_INetCfgComponentPrivate,
|
|
reinterpret_cast<void**>(&pinccp));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pinccp->SetDirty();
|
|
pinccp->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Function: CNwlnkIPX::HrCommitInstall
|
|
//
|
|
// Purpose: Commit Installation registry changes to the registry
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: HRESULT, S_OK on success
|
|
//
|
|
//
|
|
STDMETHODIMP CNwlnkIPX::HrCommitInstall()
|
|
{
|
|
HRESULT hr;
|
|
|
|
Assert(m_pIpxEnviroment);
|
|
hr = m_pIpxEnviroment->HrUpdateRegistry();
|
|
|
|
TraceError("CNwlnkIPX::HrCommitInstall",hr);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Function: CNwlnkIPX::HrCommitRemove
|
|
//
|
|
// Purpose: Remove from the registry settings which were created by this
|
|
// component's installation.
|
|
//
|
|
// Parameters: None
|
|
//
|
|
// Returns: HRESULT, S_OK on success
|
|
//
|
|
//
|
|
STDMETHODIMP CNwlnkIPX::HrCommitRemove()
|
|
{
|
|
// Remove "NwlnkIpx" from the:
|
|
// System\CurrentControlSet\Control\ServiceProvider\Order\ProviderOrder value
|
|
(void) HrRegRemoveStringFromMultiSz(c_szSvcNwlnkIpx, HKEY_LOCAL_MACHINE,
|
|
c_szSrvProvOrderKey,
|
|
c_szProviderOrderVal,
|
|
STRING_FLAG_REMOVE_ALL);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
CIpxAdapterInfo::CIpxAdapterInfo() : m_dwMediaType(ETHERNET_MEDIA),
|
|
m_fDeletePending(FALSE),
|
|
m_fDisabled(FALSE),
|
|
m_fDirty(FALSE),
|
|
m_dwCharacteristics(0L)
|
|
{
|
|
ZeroMemory(&m_guidInstance, sizeof(m_guidInstance));
|
|
}
|
|
|
|
CIpxAdapterInfo::~CIpxAdapterInfo()
|
|
{
|
|
DeleteColString(&m_lstpstrFrmType);
|
|
DeleteColString(&m_lstpstrNetworkNum);
|
|
}
|
|
|
|
CIpxEnviroment::CIpxEnviroment(CNwlnkIPX *pno)
|
|
{
|
|
Assert(NULL != pno);
|
|
m_pno = pno; // Retain the Notification object
|
|
|
|
m_fRipInstalled = FALSE;
|
|
m_fEnableRip = FALSE;
|
|
m_dwRipValue = 0;
|
|
ZeroMemory(&m_IpxParams, sizeof(m_IpxParams));
|
|
}
|
|
|
|
CIpxEnviroment::~CIpxEnviroment()
|
|
{
|
|
ReleaseAdapterInfo();
|
|
|
|
// Note: Do nothing with the m_pno notification object, we just borrowed it
|
|
}
|
|
|
|
//
|
|
// Member: CIpxEnviroment::ReleaseAdapterInfo
|
|
//
|
|
// Purpose: Release the adapter info
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: nothing
|
|
//
|
|
void CIpxEnviroment::ReleaseAdapterInfo()
|
|
{
|
|
CIpxAdapterInfo *pAI;
|
|
|
|
while (!m_lstpAdapterInfo.empty())
|
|
{
|
|
pAI = m_lstpAdapterInfo.front();
|
|
m_lstpAdapterInfo.pop_front();
|
|
delete pAI;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Member: CIpxEnviroment::DwCountValidAdapters
|
|
//
|
|
// Purpose: Return the count of adapters not marked as delete pending,
|
|
// disabled, or hidden.
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: nothing
|
|
//
|
|
DWORD CIpxEnviroment::DwCountValidAdapters()
|
|
{
|
|
DWORD dwCount = 0;
|
|
ADAPTER_INFO_LIST::iterator iterAI;
|
|
|
|
for (iterAI = AdapterInfoList().begin();
|
|
iterAI != AdapterInfoList().end();
|
|
iterAI++)
|
|
{
|
|
CIpxAdapterInfo *pAI = *iterAI;
|
|
|
|
if (pAI->FDeletePending() || pAI->FDisabled() || pAI->FHidden())
|
|
continue;
|
|
|
|
dwCount++;
|
|
}
|
|
|
|
return dwCount;
|
|
}
|
|
|
|
HRESULT CIpxEnviroment::HrOpenIpxAdapterSubkey(HKEY *phkey, BOOL fCreateIfMissing)
|
|
{
|
|
DWORD dwDisposition;
|
|
HRESULT hr;
|
|
tstring str;
|
|
|
|
// Open the NetCard key
|
|
str = c_szIpxParameters;
|
|
str += L"\\";
|
|
str += c_szAdapters;
|
|
if (fCreateIfMissing)
|
|
{
|
|
hr = ::HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, str.c_str(),
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
|
|
phkey, &dwDisposition);
|
|
}
|
|
else
|
|
{
|
|
hr = ::HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, str.c_str(), KEY_READ, phkey );
|
|
}
|
|
if (S_OK != hr)
|
|
goto Error;
|
|
|
|
Error:
|
|
TraceError("CIpxEnviroment::HrOpenIpxAdapterSubkey",
|
|
HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND) == hr ? S_OK : hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CIpxEnviroment::HrOpenIpxAdapterSubkeyEx(PCWSTR pszKeyName,
|
|
DWORD dwAccess,
|
|
BOOL fCreateIfMissing,
|
|
HKEY *phkey)
|
|
{
|
|
HRESULT hr;
|
|
HKEY hkeyRoot = NULL;
|
|
|
|
Assert(pszKeyName);
|
|
Assert(0 < lstrlenW(pszKeyName));
|
|
|
|
// Open the NetCard key
|
|
hr = HrOpenIpxAdapterSubkey(&hkeyRoot, fCreateIfMissing);
|
|
if (S_OK != hr)
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
// Open the adapter specific subkey (creating if requested and required)
|
|
if (fCreateIfMissing)
|
|
{
|
|
DWORD dwDisposition;
|
|
|
|
hr = HrRegCreateKeyEx(HKEY_LOCAL_MACHINE, pszKeyName,
|
|
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
|
|
phkey, &dwDisposition);
|
|
}
|
|
else
|
|
{
|
|
// Try exact match first, it's faster
|
|
hr = HrRegOpenKeyEx( hkeyRoot, pszKeyName, dwAccess, phkey );
|
|
}
|
|
|
|
Error:
|
|
RegSafeCloseKey(hkeyRoot);
|
|
TraceError("CIpxEnviroment::HrOpenIpxAdapterSubkeyEx",
|
|
HRESULT_FROM_WIN32 (ERROR_FILE_NOT_FOUND) == hr ? S_OK : hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CIpxEnviroment::HrGetIpxParams()
|
|
{
|
|
RegReadValues(celems(regbatchIpx), regbatchIpx, (BYTE *)&m_IpxParams,
|
|
KEY_READ);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CIpxEnviroment::HrGetOneAdapterInfo(INetCfgComponent *pNCC,
|
|
CIpxAdapterInfo **ppAI)
|
|
{
|
|
HKEY hkeyCard = NULL;
|
|
HRESULT hr = S_OK;
|
|
CIpxAdapterInfo * pAI = NULL;
|
|
|
|
Assert(NULL != pNCC);
|
|
|
|
// Init the return value
|
|
*ppAI = NULL;
|
|
|
|
pAI = (CIpxAdapterInfo *)new CIpxAdapterInfo;
|
|
Assert(NULL != pAI);
|
|
|
|
if (pAI == NULL)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
// Query the adapter component info
|
|
hr = ::HrQueryAdapterComponentInfo(pNCC, pAI);
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
// Open the IPX subkey specific to this adapter
|
|
hr = HrOpenIpxAdapterSubkeyEx(pAI->SzBindName(), KEY_READ, FALSE,
|
|
&hkeyCard);
|
|
if (S_OK == hr)
|
|
{
|
|
// Get the packet types
|
|
//
|
|
hr = HrRegQueryColString(hkeyCard, c_szPktType,
|
|
&pAI->m_lstpstrFrmType);
|
|
if (S_OK != hr)
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
// Get the network numbers
|
|
//
|
|
hr = HrRegQueryColString(hkeyCard, c_szNetworkNumber,
|
|
&pAI->m_lstpstrNetworkNum);
|
|
if (S_OK != hr)
|
|
{
|
|
goto Error;
|
|
}
|
|
}
|
|
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
|
|
{
|
|
// Normalize any ERROR_FILE_NOT_FOUND errors
|
|
hr = S_OK;
|
|
}
|
|
else if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
}
|
|
|
|
// Default PktType?
|
|
if (0 == pAI->PFrmTypeList()->size())
|
|
{
|
|
WCHAR szBuf[10];
|
|
|
|
// If the info was not found or contained no elements, add the
|
|
// default value.
|
|
wsprintfW(szBuf,L"%X",c_dwPktTypeDefault);
|
|
pAI->PFrmTypeList()->push_back(new tstring(szBuf));
|
|
}
|
|
|
|
// Default Network Number?
|
|
if (0 == pAI->PNetworkNumList()->size())
|
|
{
|
|
// If the info was not found or contained no elements, add the
|
|
// default value.
|
|
pAI->PNetworkNumList()->push_back(new tstring(c_sz8Zeros));
|
|
}
|
|
|
|
// Update the return value with the new object
|
|
*ppAI = pAI;
|
|
|
|
Done:
|
|
::RegSafeCloseKey(hkeyCard);
|
|
TraceError("CIpxEnviroment::HrGetOneAdapterInfo",hr);
|
|
return hr;
|
|
|
|
Error:
|
|
delete pAI;
|
|
goto Done;
|
|
}
|
|
|
|
HRESULT CIpxEnviroment::HrGetAdapterInfo()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CIpxAdapterInfo * pAI = NULL;
|
|
INetCfgComponent* pncc = NULL;
|
|
INetCfgComponent* pnccUse = NULL;
|
|
|
|
// Find each netcard, to do so, trace the bindings to their end
|
|
// If the endpoint is a netcard then add it to the list
|
|
CIterNetCfgBindingPath ncbpIter(m_pno->m_pnccMe);
|
|
INetCfgBindingPath* pncbp;
|
|
|
|
while (SUCCEEDED(hr) && (S_OK == (hr = ncbpIter.HrNext (&pncbp))))
|
|
{
|
|
// Iterate the binding interfaces of this path.
|
|
CIterNetCfgBindingInterface ncbiIter(pncbp);
|
|
INetCfgBindingInterface* pncbi;
|
|
|
|
while (SUCCEEDED(hr) && (S_OK == (hr = ncbiIter.HrNext (&pncbi))))
|
|
{
|
|
// Retrieve the lower component
|
|
hr = pncbi->GetLowerComponent(&pncc);
|
|
if (S_OK == hr)
|
|
{
|
|
GUID guidClass;
|
|
|
|
// Is it an Adapter?
|
|
hr = pncc->GetClassGuid(&guidClass);
|
|
if ((S_OK == hr) && (guidClass == GUID_DEVCLASS_NET))
|
|
{
|
|
ReleaseObj(pnccUse);
|
|
pnccUse = pncc;
|
|
pncc = NULL;
|
|
}
|
|
else
|
|
{
|
|
// Release the lower component
|
|
ReleaseObj(pncc);
|
|
}
|
|
}
|
|
|
|
// Release the binding interface
|
|
ReleaseObj (pncbi);
|
|
}
|
|
|
|
if (NULL != pnccUse)
|
|
{
|
|
// Query the Adapter information
|
|
hr = HrGetOneAdapterInfo(pnccUse, &pAI);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (S_FALSE == pncbp->IsEnabled())
|
|
pAI->SetDisabled(TRUE);
|
|
|
|
// Add this Adapter to the list
|
|
m_lstpAdapterInfo.push_back(pAI);
|
|
}
|
|
|
|
ReleaseObj(pnccUse);
|
|
pnccUse = NULL;
|
|
}
|
|
|
|
// Release the binding path
|
|
ReleaseObj (pncbp);
|
|
}
|
|
|
|
// Normalize the HRESULT. (i.e. don't return S_FALSE)
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
|
|
TraceError("CIpxEnviroment::HrGetNetCardInfo",hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CIpxEnviroment::HrWriteOneAdapterInfo(HKEY hkeyAdapters,
|
|
CIpxAdapterInfo* pAI)
|
|
{
|
|
DWORD dwDisposition;
|
|
HRESULT hr;
|
|
HKEY hkeyCard = NULL;
|
|
PWSTR psz = NULL;
|
|
|
|
// Open the IPX subkey for this specific adapter
|
|
hr = ::HrRegCreateKeyEx(hkeyAdapters, pAI->SzBindName(), REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS, NULL, &hkeyCard, &dwDisposition);
|
|
if (S_OK != hr)
|
|
goto Error;
|
|
|
|
// Write the packet info
|
|
// Generate the data to write
|
|
AssertSz(pAI->m_lstpstrFrmType.size(),"Did not expect an empty list, default value missing");
|
|
ColStringToMultiSz(pAI->m_lstpstrFrmType, &psz);
|
|
if (psz)
|
|
{
|
|
hr = ::HrRegSetMultiSz(hkeyCard, c_szPktType, psz);
|
|
if (S_OK != hr)
|
|
goto Error;
|
|
|
|
delete [] psz;
|
|
psz = NULL;
|
|
}
|
|
#ifdef DBG
|
|
else
|
|
{
|
|
AssertSz(0,"PacketType value is NULL?");
|
|
}
|
|
#endif
|
|
|
|
// Write the network number
|
|
AssertSz(pAI->m_lstpstrNetworkNum.size(),"Did not expect an empty list, default value missing");
|
|
ColStringToMultiSz(pAI->m_lstpstrNetworkNum, &psz);
|
|
if (psz)
|
|
{
|
|
hr = ::HrRegSetMultiSz(hkeyCard, c_szNetworkNumber, psz);
|
|
if (S_OK != hr)
|
|
goto Error;
|
|
|
|
delete [] psz;
|
|
psz = NULL;
|
|
}
|
|
#ifdef DBG
|
|
else
|
|
{
|
|
AssertSz(0,"NetworkNumber value is NULL?");
|
|
}
|
|
#endif
|
|
|
|
// If the key for this adapter didn't exist previously
|
|
// write the base set of values
|
|
if (REG_CREATED_NEW_KEY == dwDisposition)
|
|
{
|
|
struct
|
|
{
|
|
PCWSTR pszProp;
|
|
DWORD dwValue;
|
|
} rgAdapterSettings[] = {{c_szBindSap,c_dwBindSap},
|
|
{c_szEnableFuncaddr,c_dwEnableFuncaddr},
|
|
{c_szMaxPktSize,c_dwMaxPktSize},
|
|
{c_szSourceRouteBCast,c_dwSourceRouteBCast},
|
|
{c_szSourceRouteMCast,c_dwSourceRouteMCast},
|
|
{c_szSourceRouteDef,c_dwSourceRouteDef},
|
|
{c_szSourceRouting,c_dwSourceRouting}};
|
|
|
|
for (int nIdx=0; nIdx<celems(rgAdapterSettings); nIdx++)
|
|
{
|
|
hr = ::HrRegSetDword(hkeyCard, rgAdapterSettings[nIdx].pszProp,
|
|
rgAdapterSettings[nIdx].dwValue);
|
|
if (FAILED(hr))
|
|
{
|
|
goto Error;
|
|
}
|
|
}
|
|
}
|
|
|
|
Error:
|
|
delete [] psz;
|
|
::RegSafeCloseKey(hkeyCard);
|
|
TraceError("CIpxEnviroment::HrWriteOneAdapterInfo",hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CIpxEnviroment::HrWriteAdapterInfo()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HKEY hkeyAdapters = NULL;
|
|
ADAPTER_INFO_LIST::iterator iterAdapterInfo;
|
|
CIpxAdapterInfo * pAI;
|
|
|
|
// Create the IPX Adapter Subkey
|
|
hr = HrOpenIpxAdapterSubkey(&hkeyAdapters, TRUE);
|
|
if (S_OK != hr)
|
|
goto Error;
|
|
|
|
// Now commit the contents of the adapter list to the registry
|
|
for (iterAdapterInfo = m_lstpAdapterInfo.begin();
|
|
iterAdapterInfo != m_lstpAdapterInfo.end();
|
|
iterAdapterInfo++)
|
|
{
|
|
pAI = *iterAdapterInfo;
|
|
|
|
// Write out all adapter's not marked with delete pending
|
|
if (pAI->FDeletePending())
|
|
{
|
|
// Remove the NwlnkIpx\Adapter\{bindname} tree
|
|
(VOID)::HrRegDeleteKeyTree(hkeyAdapters, pAI->SzBindName());
|
|
}
|
|
else if (pAI->IsDirty())
|
|
{
|
|
hr = HrWriteOneAdapterInfo(hkeyAdapters, pAI);
|
|
if (S_OK != hr)
|
|
goto Error;
|
|
}
|
|
}
|
|
|
|
Error:
|
|
::RegSafeCloseKey(hkeyAdapters);
|
|
TraceError("CIpxEnviroment::HrWriteAdapterInfo",hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CIpxEnviroment::HrCreate(CNwlnkIPX *pno, CIpxEnviroment ** ppIpxEnviroment)
|
|
{
|
|
HRESULT hr;
|
|
CIpxEnviroment * pIpxEnviroment = (CIpxEnviroment *)new CIpxEnviroment(pno);
|
|
|
|
if (pIpxEnviroment == NULL)
|
|
{
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
*ppIpxEnviroment = NULL;
|
|
|
|
// Get the Ipx Parameter Key info
|
|
hr = pIpxEnviroment->HrGetIpxParams();
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
// Collect the Adapter Info for all cards installed
|
|
hr = pIpxEnviroment->HrGetAdapterInfo();
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
*ppIpxEnviroment = pIpxEnviroment;
|
|
|
|
Complete:
|
|
TraceError("CIpxEnviroment::HrCreate",hr);
|
|
return hr;
|
|
|
|
Error:
|
|
delete pIpxEnviroment;
|
|
goto Complete;
|
|
}
|
|
|
|
HRESULT CIpxEnviroment::HrUpdateRegistry()
|
|
{
|
|
HRESULT hr;
|
|
|
|
// Commit the registry changes
|
|
hr = ::HrRegWriteValues(celems(regbatchIpx), regbatchIpx,
|
|
(BYTE *)&m_IpxParams, REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS);
|
|
if (S_OK != hr)
|
|
goto Error;
|
|
|
|
// Write adapter info to registry
|
|
hr = HrWriteAdapterInfo();
|
|
|
|
Error:
|
|
TraceError("CIpxEnviroment::HrUpdateRegistry",hr);
|
|
return hr;
|
|
}
|
|
|
|
VOID CIpxEnviroment::RemoveAdapter(CIpxAdapterInfo * pAI)
|
|
{
|
|
Assert(NULL != pAI);
|
|
m_lstpAdapterInfo.remove(pAI);
|
|
delete pAI;
|
|
}
|
|
|
|
HRESULT CIpxEnviroment::HrAddAdapter(INetCfgComponent * pncc)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
CIpxAdapterInfo * pAI = NULL;
|
|
|
|
hr = HrGetOneAdapterInfo(pncc, &pAI);
|
|
if (FAILED(hr))
|
|
goto Error;
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = S_OK; // Normalize return
|
|
|
|
// Add the Adapter to the list
|
|
pAI->SetDirty(TRUE);
|
|
m_lstpAdapterInfo.push_back(pAI);
|
|
|
|
Error:
|
|
TraceError("CIpxEnviroment::HrAddAdapter",hr);
|
|
return hr;
|
|
}
|
|
|
|
//$ REVIEW - Start - This is moving to windows\inc\ipxpnp.h
|
|
#define IPX_RECONFIG_VERSION 0x1
|
|
|
|
#define RECONFIG_AUTO_DETECT 1
|
|
#define RECONFIG_MANUAL 2
|
|
#define RECONFIG_PREFERENCE_1 3
|
|
#define RECONFIG_NETWORK_NUMBER_1 4
|
|
#define RECONFIG_PREFERENCE_2 5
|
|
#define RECONFIG_NETWORK_NUMBER_2 6
|
|
#define RECONFIG_PREFERENCE_3 7
|
|
#define RECONFIG_NETWORK_NUMBER_3 8
|
|
#define RECONFIG_PREFERENCE_4 9
|
|
#define RECONFIG_NETWORK_NUMBER_4 10
|
|
|
|
#define RECONFIG_PARAMETERS 10
|
|
|
|
//
|
|
// Main configuration structure.
|
|
//
|
|
|
|
struct RECONFIG
|
|
{
|
|
ULONG ulVersion;
|
|
BOOLEAN InternalNetworkNumber;
|
|
BOOLEAN AdapterParameters[RECONFIG_PARAMETERS];
|
|
};
|
|
|
|
//$ REVIEW - End - This is moving to windows\inc\ipxpnp.h
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CNwlnkIPX::HrReconfigIpx
|
|
//
|
|
// Purpose: Notify Ipx of configuration changes
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: HRESULT, S_OK on success, NETCFG_S_REBOOT on failure
|
|
//
|
|
HRESULT CNwlnkIPX::HrReconfigIpx()
|
|
{
|
|
HRESULT hrRet;
|
|
HRESULT hr = S_OK;
|
|
INT nIdx;
|
|
RECONFIG Config;
|
|
CIpxAdapterInfo * pAI;
|
|
PRODUCT_FLAVOR pf;
|
|
ADAPTER_INFO_LIST::iterator iter;
|
|
ULONG ulConfigSize;
|
|
|
|
if (0 == m_pIpxEnviroment->DwCountValidAdapters())
|
|
{
|
|
return S_OK; // Nothing to configure
|
|
}
|
|
|
|
ZeroMemory(&Config, sizeof(Config));
|
|
Config.ulVersion = IPX_RECONFIG_VERSION;
|
|
|
|
// Workstation or server?
|
|
GetProductFlavor(NULL, &pf);
|
|
if (PF_WORKSTATION != pf)
|
|
{
|
|
Config.InternalNetworkNumber = TRUE;
|
|
// Now submit the global reconfig notification
|
|
hrRet = HrSendNdisPnpReconfig(NDIS, c_szSvcNwlnkIpx, c_szEmpty,
|
|
&Config, sizeof(RECONFIG));
|
|
if (FAILED(hrRet) &&
|
|
(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hrRet))
|
|
{
|
|
hr = NETCFG_S_REBOOT;
|
|
}
|
|
}
|
|
|
|
Config.InternalNetworkNumber = FALSE;
|
|
|
|
// For each adapter...
|
|
for (nIdx=0, iter = m_pIpxEnviroment->AdapterInfoList().begin();
|
|
iter != m_pIpxEnviroment->AdapterInfoList().end();
|
|
nIdx++, iter++)
|
|
{
|
|
pAI = *iter;
|
|
|
|
if (pAI->FDeletePending() || pAI->FDisabled() || !pAI->IsDirty())
|
|
continue;
|
|
|
|
ZeroMemory(&Config.AdapterParameters, sizeof(Config.AdapterParameters));
|
|
|
|
if (AUTO == pAI->DwFrameType())
|
|
Config.AdapterParameters[RECONFIG_AUTO_DETECT] = TRUE;
|
|
else
|
|
Config.AdapterParameters[RECONFIG_MANUAL] = TRUE;
|
|
|
|
// We are performing a shortcut here by setting a range to TRUE
|
|
// based on the number of frames in use. For example if there is
|
|
// only one frame in use we need to set both:
|
|
// RECONFIG_PREFERENCE_1 and RECONFIG_NETWORK_NUMBER_1 to TRUE
|
|
Assert(RECONFIG_PREFERENCE_1 + 1 == RECONFIG_NETWORK_NUMBER_1);
|
|
Assert(RECONFIG_NETWORK_NUMBER_1 + 1 == RECONFIG_PREFERENCE_2);
|
|
Assert(RECONFIG_PREFERENCE_2 + 1 == RECONFIG_NETWORK_NUMBER_2);
|
|
Assert(RECONFIG_NETWORK_NUMBER_2 + 1 == RECONFIG_PREFERENCE_3);
|
|
Assert(RECONFIG_PREFERENCE_3 + 1 == RECONFIG_NETWORK_NUMBER_3);
|
|
Assert(RECONFIG_NETWORK_NUMBER_3 + 1 == RECONFIG_PREFERENCE_4);
|
|
Assert(RECONFIG_PREFERENCE_4 + 1 == RECONFIG_NETWORK_NUMBER_4);
|
|
|
|
INT nCntFrms = pAI->PFrmTypeList()->size();
|
|
if ((0 < nCntFrms) && (4 >= nCntFrms))
|
|
{
|
|
memset(&Config.AdapterParameters[RECONFIG_PREFERENCE_1],
|
|
TRUE, sizeof(BOOLEAN) * nCntFrms * 2);
|
|
}
|
|
|
|
Assert(lstrlenW(pAI->SzBindName()));
|
|
|
|
// Now submit the reconfig notification
|
|
hrRet = HrSendNdisPnpReconfig(NDIS, c_szSvcNwlnkIpx, pAI->SzBindName(),
|
|
&Config, sizeof(RECONFIG));
|
|
if (FAILED(hrRet) &&
|
|
(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hrRet))
|
|
{
|
|
hr = NETCFG_S_REBOOT;
|
|
}
|
|
}
|
|
|
|
TraceError("CNwlnkIPX::HrReconfigIpx",hr);
|
|
return hr;
|
|
}
|
|
|