[NETCFGX] Implement ITcpipProperties_fnUnknown2 partially

- Update internal IpAddress, Gateway and NameServer information
- Mark modified component
This commit is contained in:
Eric Kohl
2026-06-23 17:27:22 +02:00
parent 57a7c56d51
commit 72c5ab502b
4 changed files with 304 additions and 71 deletions

View File

@@ -1,15 +1,5 @@
#include "precomp.h"
typedef struct
{
const INetCfgComponent *lpVtbl;
const INetCfgComponentBindings *lpVtblBindings;
const INetCfgComponentPrivate *lpVtblPrivate;
LONG ref;
NetCfgComponentItem * pItem;
INetCfg * pNCfg;
} INetCfgComponentImpl;
typedef struct
{
const IEnumNetCfgComponent * lpVtbl;

View File

@@ -705,7 +705,7 @@ ApplyOrCancelChanges(
WCHAR szName[200];
LPOLESTR pszGuid;
while(pHead)
while (pHead)
{
if (pHead->bChanged)
{
@@ -738,6 +738,8 @@ ApplyOrCancelChanges(
INetCfgComponentControl_CancelChanges(pHead->pControl);
}
}
pHead->bChanged = FALSE;
}
pHead = pHead->pNext;
}

View File

@@ -78,6 +78,16 @@ typedef struct
NetCfgComponentItem * pProtocol;
} INetCfgImpl;
typedef struct
{
const INetCfgComponent *lpVtbl;
const INetCfgComponentBindings *lpVtblBindings;
const INetCfgComponentPrivate *lpVtblPrivate;
LONG ref;
NetCfgComponentItem * pItem;
INetCfg * pNCfg;
} INetCfgComponentImpl;
/* netcfg_iface.c */
HRESULT WINAPI INetCfg_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv);

View File

@@ -357,6 +357,11 @@ BuildParametersString(
/* Format: "DefGw=;GwMetric=;IfMetric=0;DNS=;WINS=;DynamicUpdate=1;NameRegistration=0;" */
if (ppszParameters == NULL)
return E_FAIL;
*ppszParameters = NULL;
/* Count Gateway entries */
dwCount = 0;
pAddr = pAdapter->NewGw;
@@ -366,58 +371,66 @@ BuildParametersString(
pAddr = pAddr->Next;
}
TRACE("Gateway count: %lu\n", dwCount);
/* Build Default Gateway string */
pszDefGateway = CoTaskMemAlloc(dwCount * IP_STRING_MAX_LENGTH * sizeof(WCHAR));
if (pszDefGateway == NULL)
if (dwCount > 0)
{
hr = E_OUTOFMEMORY;
goto done;
}
ZeroMemory(pszDefGateway, dwCount * IP_STRING_MAX_LENGTH * sizeof(WCHAR));
pString = pszDefGateway;
pAddr = pAdapter->NewGw;
while (pAddr != NULL)
{
if (pString != pszDefGateway)
pszDefGateway = CoTaskMemAlloc(dwCount * IP_STRING_MAX_LENGTH * sizeof(WCHAR));
if (pszDefGateway == NULL)
{
*pString = L',';
pString++;
hr = E_OUTOFMEMORY;
goto done;
}
Address.S_un.S_addr = htonl(pAddr->u.SubnetMask);
pString = RtlIpv4AddressToStringW(&Address, pString);
ZeroMemory(pszDefGateway, dwCount * IP_STRING_MAX_LENGTH * sizeof(WCHAR));
pAddr = pAddr->Next;
pString = pszDefGateway;
pAddr = pAdapter->NewGw;
while (pAddr != NULL)
{
if (pString != pszDefGateway)
{
*pString = L',';
pString++;
}
Address.S_un.S_addr = htonl(pAddr->IpAddress);
pString = RtlIpv4AddressToStringW(&Address, pString);
pAddr = pAddr->Next;
}
}
TRACE("DefaultGateway %S\n", pszDefGateway);
/* Build Gateway Metric string */
pszGatewayMetric = CoTaskMemAlloc(dwCount * 5 * sizeof(WCHAR));
if (pszGatewayMetric == NULL)
if (dwCount > 0)
{
hr = E_OUTOFMEMORY;
goto done;
}
ZeroMemory(pszGatewayMetric, dwCount * 5 * sizeof(WCHAR));
pString = pszGatewayMetric;
pAddr = pAdapter->NewGw;
while (pAddr != NULL)
{
if (pString != pszGatewayMetric)
pszGatewayMetric = CoTaskMemAlloc(dwCount * 5 * sizeof(WCHAR));
if (pszGatewayMetric == NULL)
{
*pString = L',';
pString++;
hr = E_OUTOFMEMORY;
goto done;
}
nLength = _swprintf(pString, L"%hu", pAddr->u.Metric);
pString += nLength;
ZeroMemory(pszGatewayMetric, dwCount * 5 * sizeof(WCHAR));
pAddr = pAddr->Next;
pString = pszGatewayMetric;
pAddr = pAdapter->NewGw;
while (pAddr != NULL)
{
if (pString != pszGatewayMetric)
{
*pString = L',';
pString++;
}
nLength = _swprintf(pString, L"%hu", pAddr->u.Metric);
pString += nLength;
pAddr = pAddr->Next;
}
}
TRACE("Gateway Metric %S\n", pszGatewayMetric);
@@ -431,39 +444,44 @@ BuildParametersString(
pAddr = pAddr->Next;
}
pszNameServers = CoTaskMemAlloc(dwCount * IP_STRING_MAX_LENGTH * sizeof(WCHAR));
if (pszNameServers == NULL)
{
hr = E_OUTOFMEMORY;
goto done;
}
TRACE("DNS count: %lu\n", dwCount);
ZeroMemory(pszNameServers, dwCount * IP_STRING_MAX_LENGTH * sizeof(WCHAR));
pString = pszNameServers;
pAddr = pAdapter->NewNs;
while (pAddr != NULL)
if (dwCount > 0)
{
if (pString != pszNameServers)
pszNameServers = CoTaskMemAlloc(dwCount * IP_STRING_MAX_LENGTH * sizeof(WCHAR));
if (pszNameServers == NULL)
{
*pString = L',';
pString++;
hr = E_OUTOFMEMORY;
goto done;
}
Address.S_un.S_addr = htonl(pAddr->IpAddress);
pString = RtlIpv4AddressToStringW(&Address, pString);
ZeroMemory(pszNameServers, dwCount * IP_STRING_MAX_LENGTH * sizeof(WCHAR));
pAddr = pAddr->Next;
pString = pszNameServers;
pAddr = pAdapter->NewNs;
while (pAddr != NULL)
{
if (pString != pszNameServers)
{
*pString = L',';
pString++;
}
Address.S_un.S_addr = htonl(pAddr->IpAddress);
pString = RtlIpv4AddressToStringW(&Address, pString);
pAddr = pAddr->Next;
}
}
TRACE("Name Servers %S\n", pszNameServers);
/* Get the Parameters string length */
nLength = _scwprintf(L"DefGw=%s;GwMetric=%s;IfMetric=%lu;DNS=%s;",
pszDefGateway,
pszGatewayMetric,
pszDefGateway ? pszDefGateway : L"",
pszGatewayMetric ? pszGatewayMetric : L"",
pAdapter->NewMetric,
pszNameServers);
pszNameServers ? pszNameServers : L"");
TRACE("Param string length %d\n", nLength);
if (nLength == -1)
@@ -482,10 +500,10 @@ BuildParametersString(
/* Fill the Parameters buffer */
_swprintf(pszParameters,
L"DefGw=%s;GwMetric=%s;IfMetric=%lu;DNS=%s;",
pszDefGateway,
pszGatewayMetric,
pszDefGateway ? pszDefGateway : L"",
pszGatewayMetric ? pszGatewayMetric : L"",
pAdapter->NewMetric,
pszNameServers);
pszNameServers ? pszNameServers : L"");
TRACE("Parameters %S\n", pszParameters);
@@ -504,6 +522,48 @@ done:
return hr;
}
static
PWSTR
ExtractParameterValue(
PWSTR pszParameters,
PWSTR pszParameter)
{
PWSTR pToken, pStart, pEnd, pBuffer;
INT length = 0;
ERR("ExtractParameterValue(%S, %S)\n", pszParameters, pszParameter);
pToken = wcsstr(pszParameters, pszParameter);
if (pToken == NULL)
return NULL;
pStart = wcschr(pToken, L'=');
if (pStart == NULL)
return NULL;
pStart++;
pEnd = wcschr(pStart, L';');
if (pEnd == NULL)
length = wcslen(pStart);
else
length = pEnd - pStart;
TRACE("length %d\n", length);
if (length == 0)
return NULL;
pBuffer = (PWSTR)CoTaskMemAlloc((length + 1) * sizeof(WCHAR));
if (pBuffer)
{
CopyMemory(pBuffer, pStart, length * sizeof(WCHAR));
pBuffer[length] = UNICODE_NULL;
}
return pBuffer;
}
/***************************************************************
* TCP/IP Filter Dialog
*
@@ -4642,9 +4702,15 @@ ITcpipProperties_fnUnknown2(
GUID *pAdapterName,
PTCPIP_PROPERTIES pProperties)
{
AdapterSettings *pAdapter;
IN_ADDR IpAddress, SubnetMask, Gateway, Dns;
PWSTR pszGateway = NULL, pszMetric = NULL, pszDns = NULL;
DWORD dwMetric;
LPCWSTR Term;
NTSTATUS Status;
HRESULT hr = S_OK;
ERR("ITcpipProperties_fnUnknown2(%s %p)\n", wine_dbgstr_guid(pAdapterName), pProperties);
TRACE("ITcpipProperties_fnUnknown2(%s %p)\n", wine_dbgstr_guid(pAdapterName), pProperties);
if (pProperties)
{
@@ -4654,6 +4720,171 @@ ITcpipProperties_fnUnknown2(
ERR("pProperties->pszParameters %S\n", pProperties->pszParameters);
}
TcpipConfNotifyImpl *This = impl_from_ITcpipProperties(iface);
pAdapter = GetAdapterByGuid(This, pAdapterName);
if (pAdapter == NULL)
return E_FAIL;
pAdapter->NewDhcpEnabled = (pProperties->dwDhcp != 0);
if (pAdapter->NewDhcpEnabled)
{
TRACE("DHCP\n");
pAdapter->NewIp->IpAddress = 0;
pAdapter->NewIp->u.SubnetMask = 0;
}
else
{
TRACE("STATIC\n");
Status = RtlIpv4StringToAddressW((PCWSTR)pProperties->pszIpAddress,
TRUE,
&Term,
&IpAddress);
if (Status != 0 /*STATUS_SUCCESS*/)
{
hr = E_FAIL;
goto done;
}
TRACE("IP Address: %u.%u.%u.%u\n",
IpAddress.S_un.S_un_b.s_b1, IpAddress.S_un.S_un_b.s_b2, IpAddress.S_un.S_un_b.s_b3, IpAddress.S_un.S_un_b.s_b4);
Status = RtlIpv4StringToAddressW((PCWSTR)pProperties->pszSubnetMask,
TRUE,
&Term,
&SubnetMask);
if (Status != 0 /*STATUS_SUCCESS*/)
{
hr = E_FAIL;
goto done;
}
TRACE("Subnet Mask: %u.%u.%u.%u\n",
SubnetMask.S_un.S_un_b.s_b1, SubnetMask.S_un.S_un_b.s_b2, SubnetMask.S_un.S_un_b.s_b3, SubnetMask.S_un.S_un_b.s_b4);
TRACE("pAdapter->NewIp %p\n", pAdapter->NewIp);
if (pAdapter->NewIp == NULL)
{
pAdapter->NewIp = CoTaskMemAlloc(sizeof(IP_ADDR));
if (pAdapter->NewIp == NULL)
{
hr = E_OUTOFMEMORY;
goto done;
}
ZeroMemory(pAdapter->NewIp, sizeof(IP_ADDR));
}
pAdapter->NewIp->IpAddress = ntohl(IpAddress.S_un.S_addr);
pAdapter->NewIp->u.SubnetMask = ntohl(SubnetMask.S_un.S_addr);
}
/* Parse pszParameters */
pszGateway = ExtractParameterValue(pProperties->pszParameters, L"DefGw");
pszMetric = ExtractParameterValue(pProperties->pszParameters, L"GwMetric");
if (pszGateway != NULL && pszMetric != NULL)
{
TRACE("Gateway: %S\n", pszGateway);
TRACE("Metric: %S\n", pszMetric);
if ((wcslen(pszGateway) == 0) && (wcslen(pszMetric) == 0))
{
FIXME("Delete Gateway and Metric!\n");
}
else
{
Status = RtlIpv4StringToAddressW((PCWSTR)pszGateway,
TRUE,
&Term,
&Gateway);
if (Status != 0 /*STATUS_SUCCESS*/)
{
hr = E_FAIL;
goto done;
}
TRACE("Gateway: %u.%u.%u.%u\n",
Gateway.S_un.S_un_b.s_b1, Gateway.S_un.S_un_b.s_b2, Gateway.S_un.S_un_b.s_b3, Gateway.S_un.S_un_b.s_b4);
TRACE("pAdapter->NewGw %p\n", pAdapter->NewGw);
if (pAdapter->NewGw == NULL)
{
pAdapter->NewGw = CoTaskMemAlloc(sizeof(IP_ADDR));
if (pAdapter->NewGw == NULL)
{
hr = E_OUTOFMEMORY;
goto done;
}
ZeroMemory(pAdapter->NewGw, sizeof(IP_ADDR));
}
pAdapter->NewGw->IpAddress = ntohl(Gateway.S_un.S_addr);
dwMetric = wcstoul(pszMetric, (PWSTR*)&Term, 10);
if (dwMetric > 9999)
dwMetric = 9999;
pAdapter->NewGw->u.Metric = (USHORT)dwMetric;
}
}
pszDns = ExtractParameterValue(pProperties->pszParameters, L"DNS");
if (pszDns)
{
TRACE("DNS: %S\n", pszDns);
if (wcslen(pszDns) == 0)
{
FIXME("Delete DNS!\n");
}
else
{
Status = RtlIpv4StringToAddressW((PCWSTR)pszDns,
TRUE,
&Term,
&Dns);
if (Status != 0 /*STATUS_SUCCESS*/)
{
hr = E_FAIL;
goto done;
}
TRACE("Dns: %u.%u.%u.%u\n",
Dns.S_un.S_un_b.s_b1, Dns.S_un.S_un_b.s_b2, Dns.S_un.S_un_b.s_b3, Dns.S_un.S_un_b.s_b4);
TRACE("pAdapter->NewNs %p\n", pAdapter->NewNs);
if (pAdapter->NewNs == NULL)
{
pAdapter->NewNs = CoTaskMemAlloc(sizeof(IP_ADDR));
if (pAdapter->NewNs == NULL)
{
hr = E_OUTOFMEMORY;
goto done;
}
ZeroMemory(pAdapter->NewNs, sizeof(IP_ADDR));
}
pAdapter->NewNs->IpAddress = ntohl(Dns.S_un.S_addr);
}
}
/*
TODO:
IfMetric
DynamicUpdate
NameRegistration
*/
if (This->pNComp)
((INetCfgComponentImpl *)(This->pNComp))->pItem->bChanged = TRUE;
done:
if (pszGateway)
CoTaskMemFree(pszGateway);
if (pszMetric)
CoTaskMemFree(pszMetric);
if (pszDns)
CoTaskMemFree(pszDns);
return hr;
}