windows-nt/Source/XPSP1/NT/shell/ext/hnw/nconnnt/nconnnt.cpp
2020-09-26 16:20:57 +08:00

816 lines
17 KiB
C++

#include <windows.h>
#include "netconn.h"
#include "globals.h"
#include "localstr.h"
#include <netcfgx.h>
#include <devguid.h>
#include <shlwapi.h>
#define ARRAYSIZE(x) (sizeof((x)) / sizeof((x)[0]))
#pragma warning(disable:4100) // unreferenced formal parameter
enum NetApplyChanges
{
Apply,
Cancel,
Nothing
};
HRESULT UninitNetCfg(INetCfg* pnetcfg, INetCfgLock* pnetcfglock, NetApplyChanges applychanges)
{
HRESULT hr = S_OK;
if (Apply == applychanges)
{
hr = pnetcfg->Apply();
}
else if (Cancel == applychanges)
{
hr = pnetcfg->Cancel();
}
// Note: Don't set hr to anything after this point. We want to preserve the value from Apply
// or Cancel - especially Apply which may signal a reboot is necessary.
// Release even if this stuff above fails. Caller probably won't check return.
pnetcfg->Uninitialize();
if (pnetcfglock)
{
pnetcfglock->ReleaseWriteLock();
pnetcfglock->Release();
}
pnetcfg->Release();
CoUninitialize();
return hr;
}
HRESULT InitNetCfg(INetCfg** ppnetcfg, INetCfgLock** ppnetcfglock)
{
BOOL fLockAquired = FALSE;
*ppnetcfg = NULL;
if (ppnetcfglock)
{
*ppnetcfglock = NULL;
}
HRESULT hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance( CLSID_CNetCfg, NULL, CLSCTX_SERVER,
IID_INetCfg, (void**) ppnetcfg);
if (SUCCEEDED(hr))
{
if (ppnetcfglock)
{
hr = (*ppnetcfg)->QueryInterface(IID_INetCfgLock, (void**) ppnetcfglock);
if (SUCCEEDED(hr))
{
LPWSTR pszCurrentLockHolder;
hr = (*ppnetcfglock)->AcquireWriteLock(5, WIZARDNAME, &pszCurrentLockHolder);
if (S_OK == hr)
{
fLockAquired = TRUE;
}
else
{
hr = NETCFG_E_NO_WRITE_LOCK;
}
}
}
if (SUCCEEDED(hr))
{
hr = (*ppnetcfg)->Initialize(NULL);
}
}
// Clean up our mess if we failed
if (FAILED(hr))
{
if (ppnetcfglock)
{
if (*ppnetcfglock)
{
if (fLockAquired)
{
(*ppnetcfglock)->ReleaseWriteLock();
}
(*ppnetcfglock)->Release();
*ppnetcfglock = NULL;
}
}
if (*ppnetcfg)
{
(*ppnetcfg)->Release();
*ppnetcfg = NULL;
}
}
}
return hr;
}
LPWSTR NineXIdToComponentId(LPCWSTR psz9xid)
{
LPWSTR pszComponentId = NULL;
if (0 == StrCmpI(psz9xid, SZ_PROTOCOL_TCPIP))
{
pszComponentId = &NETCFG_TRANS_CID_MS_TCPIP;
} else if (0 == StrCmpI(psz9xid, SZ_CLIENT_MICROSOFT))
{
pszComponentId = &NETCFG_CLIENT_CID_MS_MSClient;
}
return pszComponentId;
}
// EnumComponents and TestRunDll are test-only stuff and should be removed - TODO
void EnumComponents(INetCfg* pnetcfg, const GUID* pguid)
{
IEnumNetCfgComponent* penum;
HRESULT hr = pnetcfg->EnumComponents(pguid, &penum);
if (SUCCEEDED(hr))
{
INetCfgComponent* pcomponent;
while (S_OK == (hr = penum->Next(1, &pcomponent, NULL)))
{
LPWSTR pszId;
LPWSTR pszName;
hr = pcomponent->GetId(&pszId);
if (SUCCEEDED(hr))
{
OutputDebugString(pszId);
CoTaskMemFree(pszId);
}
hr = pcomponent->GetDisplayName(&pszName);
if (SUCCEEDED(hr))
{
OutputDebugString(L" - ");
OutputDebugString(pszName);
CoTaskMemFree(pszName);
}
OutputDebugString(L"\n");
pcomponent->Release();
}
penum->Release();
}
}
void APIENTRY TestRunDll(HWND hwndStub, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow)
{
HRESULT hr = S_OK;
CoInitialize(NULL);
INetCfg *pnetcfg = NULL;
hr = CoCreateInstance( CLSID_CNetCfg, NULL, CLSCTX_SERVER,
IID_INetCfg, (LPVOID*)&pnetcfg);
if (SUCCEEDED(hr))
{
hr = pnetcfg->Initialize(NULL);
if (SUCCEEDED(hr))
{
OutputDebugString(L"GUID_DEVCLASS_NET\n");
EnumComponents(pnetcfg, &GUID_DEVCLASS_NET);
OutputDebugString(L"\nGUID_DEVCLASS_NETTRANS\n");
EnumComponents(pnetcfg, &GUID_DEVCLASS_NETTRANS);
OutputDebugString(L"\nGUID_DEVCLASS_NETCLIENT\n");
EnumComponents(pnetcfg, &GUID_DEVCLASS_NETCLIENT);
OutputDebugString(L"\nGUID_DEVCLASS_NETSERVICE\n");
EnumComponents(pnetcfg, &GUID_DEVCLASS_NETSERVICE);
pnetcfg->Uninitialize();
}
pnetcfg->Release();
}
CoUninitialize();
}
BOOL IsComponentInstalled(LPCWSTR pszId)
{
BOOL fInstalled = FALSE;
INetCfg* pnetcfg;
HRESULT hr = InitNetCfg(&pnetcfg, NULL);
if (SUCCEEDED(hr))
{
INetCfgComponent* pcomponent;
HRESULT hr = pnetcfg->FindComponent(pszId, &pcomponent);
if (S_OK == hr)
{
// Component found
pcomponent->Release();
fInstalled = TRUE;
}
hr = UninitNetCfg(pnetcfg, NULL, Nothing);
}
return fInstalled;
}
HRESULT InstallComponent(const GUID* pguidType, LPCWSTR pszId)
{
INetCfg* pnetcfg;
INetCfgLock* pnetcfglock;
// Init & aquire a write lock
HRESULT hr = InitNetCfg(&pnetcfg, &pnetcfglock);
if (SUCCEEDED(hr))
{
INetCfgClassSetup* pnetcfgclasssetup;
hr = pnetcfg->QueryNetCfgClass(pguidType, IID_INetCfgClassSetup, (void**) &pnetcfgclasssetup);
if (SUCCEEDED(hr))
{
INetCfgComponent* pNewComp;
OBO_TOKEN obotoken;
ZeroMemory(&obotoken, sizeof(OBO_TOKEN));
obotoken.Type = OBO_USER;
hr = pnetcfgclasssetup->Install(
pszId,
&obotoken,
0, /* NSF_POSTSYSINSTALL ? */
0,
NULL,
NULL,
&pNewComp);
if (SUCCEEDED(hr))
{
pNewComp->Release();
}
pnetcfgclasssetup->Release();
}
// Free our mess and apply changes if we succeeded in installing our component
hr = UninitNetCfg(pnetcfg, pnetcfglock, (SUCCEEDED(hr)) ? Apply : Cancel);
}
return hr;
}
// NOT USED. But keep around since NetConnFree is used.
//
LPVOID WINAPI NetConnAlloc(DWORD cbAlloc)
{
return LocalAlloc(LMEM_FIXED, cbAlloc);
}
// USED.
//
VOID WINAPI NetConnFree(LPVOID pMem)
{
if (pMem)
LocalFree(pMem);
}
// USED. Only one call with (SZ_PROTOCOL_TCPIP, TRUE).
//
BOOL WINAPI IsProtocolInstalled(LPCWSTR pszProtocolDeviceID, BOOL bExhaustive)
{
BOOL fSuccess = FALSE;
LPCWSTR pszTransportId = NineXIdToComponentId(pszProtocolDeviceID);
if (pszTransportId)
{
fSuccess = IsComponentInstalled(pszTransportId);
}
return fSuccess;
}
// USED. Called once with (FALSE)
//
BOOL WINAPI IsMSClientInstalled(BOOL bExhaustive)
{
return IsComponentInstalled(NETCFG_CLIENT_CID_MS_MSClient);
}
// USED. Only one call with (hwnd, NULL, NULL)
//
HRESULT WINAPI InstallTCPIP(HWND hwndParent, PROGRESS_CALLBACK pfnProgress, LPVOID pvProgressParam)
{
HRESULT hr = InstallComponent(&GUID_DEVCLASS_NETTRANS, NETCFG_TRANS_CID_MS_TCPIP);
// Map the reboot result code
if (NETCFG_S_REBOOT == hr)
{
hr = NETCONN_NEED_RESTART;
}
return hr;
}
// USED. Called once with (hwnd, NULL, NULL)
//
HRESULT WINAPI InstallMSClient(HWND hwndParent, PROGRESS_CALLBACK pfnProgress, LPVOID pvProgressParam)
{
HRESULT hr = InstallComponent(&GUID_DEVCLASS_NETCLIENT, NETCFG_CLIENT_CID_MS_MSClient);
// Map the reboot result code
if (NETCFG_S_REBOOT == hr)
{
hr = NETCONN_NEED_RESTART;
}
return hr;
}
// USED. Called once with (hwnd, NULL, NULL).
//
HRESULT WINAPI InstallSharing(HWND hwndParent, PROGRESS_CALLBACK pfnProgress, LPVOID pvProgressParam)
{
HRESULT hr = InstallComponent(&GUID_DEVCLASS_NETSERVICE, NETCFG_SERVICE_CID_MS_SERVER);
// Map the reboot result code
if (NETCFG_S_REBOOT == hr)
{
hr = NETCONN_NEED_RESTART;
}
return hr;
}
// USED. Called once with (TRUE)
//
BOOL WINAPI IsSharingInstalled(BOOL bExhaustive)
{
return IsComponentInstalled(NETCFG_SERVICE_CID_MS_SERVER);
}
// USED. Called once with (SZ_CLIENT_MICROSOFT, TRUE).
//
BOOL WINAPI IsClientInstalled(LPCWSTR pszClient, BOOL bExhaustive)
{
BOOL fSuccess = FALSE;
LPCWSTR pszClientId = NineXIdToComponentId(pszClient);
if (pszClientId)
{
fSuccess = IsComponentInstalled(pszClientId);
}
return fSuccess;
}
// USED. Called four times.
// This is always TRUE on NT?
BOOL WINAPI IsAccessControlUserLevel()
{
return TRUE;
}
// USED. Called once.
// This can't be disabled on NT
HRESULT WINAPI DisableUserLevelAccessControl()
{
return E_NOTIMPL;
}
#define CopyStrMacro(Dest) if (SUCCEEDED(hr)) {StrCpyNW((Dest), pszTemp, ARRAYSIZE((Dest))); CoTaskMemFree(pszTemp);}
HRESULT FillAdapterInfo(INetCfgComponent* pcomponent, NETADAPTER* pNetAdapter)
{
HRESULT hr = S_OK;
LPWSTR pszTemp;
DWORD dwCharacteristics;
// szDisplayName
hr = pcomponent->GetDisplayName(&pszTemp);
if (SUCCEEDED(hr))
{
OutputDebugString(L"\n\nDisplayName:");
OutputDebugString(pszTemp);
StrCpyNW(pNetAdapter->szDisplayName, pszTemp, ARRAYSIZE(pNetAdapter->szDisplayName));
CoTaskMemFree(pszTemp);
}
// szDeviceID
hr = pcomponent->GetId(&pszTemp);
if (SUCCEEDED(hr))
{
OutputDebugString(L"\nId:");
OutputDebugString(pszTemp);
StrCpyNW(pNetAdapter->szDeviceID, pszTemp, ARRAYSIZE(pNetAdapter->szDeviceID));
CoTaskMemFree(pszTemp);
}
// review - unused as of now - maybe remove
hr = pcomponent->GetPnpDevNodeId(&pszTemp);
if (SUCCEEDED(hr))
{
OutputDebugString(L"\nPnpDevNodeId:");
OutputDebugString(pszTemp);
}
// review - assuming szEnumKey is actually the BindName since it is used in EnumMatchingNetBindings.
hr = pcomponent->GetBindName(&pszTemp);
if (SUCCEEDED(hr))
{
OutputDebugString(L"\nBindName:");
OutputDebugString(pszTemp);
StrCpyNW(pNetAdapter->szEnumKey, pszTemp, ARRAYSIZE(pNetAdapter->szEnumKey));
CoTaskMemFree(pszTemp);
}
// Also usused
DWORD dwStatus;
hr = pcomponent->GetDeviceStatus(&dwStatus);
if (SUCCEEDED(hr))
{
WCHAR szTemp[20];
wnsprintf(szTemp, ARRAYSIZE(szTemp), L"%x", dwStatus);
OutputDebugString(L"\nDeviceStatus:");
OutputDebugString(szTemp);
}
hr = pcomponent->GetCharacteristics(&dwCharacteristics);
if (SUCCEEDED(hr))
{
WCHAR szTemp[20];
wnsprintf(szTemp, ARRAYSIZE(szTemp), L"%x", dwCharacteristics);
OutputDebugString(L"\nCharacteristics:");
OutputDebugString(szTemp);
}
// szClassKey ??
// szManufacturer - don't care
pNetAdapter->szManufacturer[0] = 0;
// szInfFileName - don't care
pNetAdapter->szInfFileName[0] = 0;
// bNicType - review
pNetAdapter->bNicType = (BYTE)((dwCharacteristics & NCF_VIRTUAL) ? NIC_VIRTUAL : NIC_UNKNOWN);
// bNetType - review
pNetAdapter->bNetType = (BYTE)((dwCharacteristics & NCF_PHYSICAL) ? NETTYPE_LAN : NETTYPE_PPTP);
// bNetSubType - review
pNetAdapter->bNetSubType = SUBTYPE_NONE;
// bIcsStatus (internet connection sharing??)- review
pNetAdapter->bIcsStatus = ICS_NONE;
// bError - review
pNetAdapter->bError = NICERR_NONE;
// bWarning - review
pNetAdapter->bWarning = NICWARN_NONE;
return S_OK;
}
#define ALLOCGROWBY 10
int AllocAndGetAdapterInfo(IEnumNetCfgComponent* penum, NETADAPTER** pprgNetAdapters)
{
*pprgNetAdapters = NULL;
UINT iMaxItems = 0;
UINT iCurrentItem = 0;
HRESULT hr = S_OK;
while (S_OK == hr)
{
INetCfgComponent* pnetadapter;
hr = penum->Next(1, &pnetadapter, NULL);
if (S_OK == hr)
{
if (iCurrentItem == iMaxItems)
{
// Time to allocate some memory
iMaxItems += ALLOCGROWBY;
if (*pprgNetAdapters)
{
NETADAPTER* pTemp = (NETADAPTER*) LocalReAlloc(*pprgNetAdapters, sizeof(NETADAPTER) * iMaxItems, LMEM_ZEROINIT);
if (!pTemp)
{
hr = E_OUTOFMEMORY;
LocalFree(*pprgNetAdapters);
*pprgNetAdapters = NULL;
}
else
{
*pprgNetAdapters = pTemp;
}
}
else
{
*pprgNetAdapters = (NETADAPTER*) LocalAlloc(LMEM_ZEROINIT, sizeof(NETADAPTER) * iMaxItems);
if (!*pprgNetAdapters)
{
hr = E_OUTOFMEMORY;
}
}
}
if (SUCCEEDED(hr))
{
hr = FillAdapterInfo(pnetadapter, (*pprgNetAdapters) + iCurrentItem);
}
pnetadapter->Release();
iCurrentItem ++;
}
else
{
// We've got as many as we can; we're done
}
}
return iCurrentItem;
}
// USED. Called four times - out parameter is never NULL.
//
int WINAPI EnumNetAdapters(NETADAPTER FAR** pprgNetAdapters)
{
*pprgNetAdapters = NULL;
int iAdapters = 0;
INetCfg* pnetcfg;
HRESULT hr = InitNetCfg(&pnetcfg, NULL);
if (SUCCEEDED(hr))
{
IEnumNetCfgComponent* penum;
hr = pnetcfg->EnumComponents(&GUID_DEVCLASS_NET, &penum);
if (SUCCEEDED(hr))
{
iAdapters = AllocAndGetAdapterInfo(penum, pprgNetAdapters);
}
hr = UninitNetCfg(pnetcfg, NULL, Nothing);
}
return iAdapters;
}
// USED. Called once with bAutodial TRUE or FALSE and szConnection not used.
//
void WINAPI EnableAutodial(BOOL bAutodial, LPCWSTR szConnection = NULL)
{
}
// USED. Called twice.
//
BOOL WINAPI IsAutodialEnabled()
{
return FALSE;
}
// USED. Called once.
//
void WINAPI SetDefaultDialupConnection(LPCWSTR pszConnectionName)
{
}
// Used. Called once.
//
void WINAPI GetDefaultDialupConnection(LPWSTR pszConnectionName, int cchMax)
{
}
// Used. Called four times. Second parameter is always SZ_PROTOCOL_TCPIP.
// Update: Actually only called once from SetHomeConnection. The other three are #if 0'd.
// Update2: SetHomeConnection needs to have a different implementation for NT, so this is never really called.
//
int WINAPI EnumMatchingNetBindings(LPCWSTR pszParentBinding, LPCWSTR pszDeviceID, LPWSTR** pprgBindings)
{
return 0;
}
HRESULT WINAPI RestartNetAdapter(DWORD devnode)
{
return E_NOTIMPL;
}
// NOT USED.
//
/*
HRESULT WINAPI InstallProtocol(LPCWSTR pszProtocol, HWND hwndParent, PROGRESS_CALLBACK pfnCallback, LPVOID pvCallbackParam)
{
return E_NOTIMPL;
}
*/
// NOT USED.
//
/*
HRESULT WINAPI RemoveProtocol(LPCWSTR pszProtocol)
{
return E_NOTIMPL;
}
*/
// NOT USED.
//
/*
HRESULT WINAPI EnableBrowseMaster()
{
return E_NOTIMPL;
}
*/
// NOT USED.
//
/*
BOOL WINAPI IsFileSharingEnabled()
{
return FALSE;
}
*/
// NOT USED.
//
/*
BOOL WINAPI IsPrinterSharingEnabled()
{
return FALSE;
}
*/
// NOT USED.
//
/*
BOOL WINAPI FindConflictingService(LPCWSTR pszWantService, NETSERVICE* pConflict)
{
return FALSE;
}
*/
// NOT USED.
//
/*
HRESULT WINAPI EnableSharingAppropriately()
{
return E_NOTIMPL;
}
*/
// NOT USED.
//
/*
HRESULT WINAPI InstallNetAdapter(LPCWSTR pszDeviceID, LPCWSTR pszInfPath, HWND hwndParent, PROGRESS_CALLBACK pfnProgress, LPVOID pvCallbackParam)
{
return E_NOTIMPL;
}
*/
// NOT USED.
//
/*
HRESULT WINAPI EnableQuickLogon()
{
return E_NOTIMPL;
}
*/
// NOT USED.
//
/*
HRESULT WINAPI DetectHardware(LPCWSTR pszDeviceID)
{
return E_NOTIMPL;
}
*/
// NOT USED.
//
/*
BOOL WINAPI IsProtocolBoundToAdapter(LPCWSTR pszProtocolID, const NETADAPTER* pAdapter)
{
return FALSE;
}
*/
// NOT USED.
//
/*
HRESULT WINAPI EnableNetAdapter(const NETADAPTER* pAdapter)
{
return E_NOTIMPL;
}
*/
// NOT USED.
//
/*
HRESULT WINAPI RemoveClient(LPCWSTR pszClient)
{
return E_NOTIMPL;
}
*/
// NOT USED.
//
/*
HRESULT WINAPI RemoveGhostedAdapters(LPCWSTR pszDeviceID)
{
return E_NOTIMPL;
}
*/
// NOT USED.
//
/*
HRESULT WINAPI RemoveUnknownAdapters(LPCWSTR pszDeviceID)
{
return E_NOTIMPL;
}
*/
// NOT USED.
//
/*
BOOL WINAPI DoesAdapterMatchDeviceID(const NETADAPTER* pAdapter, LPCWSTR pszDeviceID)
{
return FALSE;
}
*/
// NOT USED.
//
/*
BOOL WINAPI IsAdapterBroadband(const NETADAPTER* pAdapter)
{
return FALSE;
}
*/
// NOT USED.
//
/*
void WINAPI SaveBroadbandSettings(LPCWSTR pszBroadbandAdapterNumber)
{
}
*/
// NOT USED.
//
/*
BOOL WINAPI UpdateBroadbandSettings(LPWSTR pszEnumKeyBuf, int cchEnumKeyBuf)
{
return FALSE;
}
*/