C++ 通过WMI接口设置/获取网卡信息(DHCP、IP、MASK、GW)

#include <iostream>
#include <vector>
#include <locale>
#include <codecvt>

#include <comdef.h>
#include <comutil.h>
#include <Wbemidl.h>

#pragma comment(lib, "wbemuuid.lib")

using namespace std;

typedef struct
{
	std::string					Driver;				// 驱动
	std::string					Guid;				// GUID
	std::string					MacAddress;			// MAC地址
	int							Index;				// 索引
	int							InterfaceIndex;		// 网卡索引
	std::vector<std::string>	IPSubnet;	        // 子网	
	std::vector<std::string>	DnsAddresses;		// DNS服务器
	std::vector<std::string>	IPAddresses;		// IP地址
	std::vector<std::string>	DefaultIPGateway;	// 默认网关服务器
	bool						DhcpEnabled;		// 启用DHCP
	int							Metric;				// 跃点
	bool						IPEnabled;			// IP启用
	std::string					ConnectionId;		// 链接ID
	std::string					ScopeId;			// 域ID
	std::string					Caption;			// 标题
	std::string					Description;		// 描述信息
} NetworkInterface;

typedef std::shared_ptr<NetworkInterface> NetworkInterfacePtr;

struct SYSTEM_WINDOWS_COM_INITIALIZED
{
	SYSTEM_WINDOWS_COM_INITIALIZED()
	{
		char messages[1000];
		HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
		if (FAILED(hr))
		{
			sprintf(messages, "Failed to initialize COM library. Error code = 0x%08x", hr);
			throw std::runtime_error(messages);
		}

		hr = CoInitializeSecurity(
			NULL,
			-1,
			NULL,
			NULL,
			RPC_C_AUTHN_LEVEL_DEFAULT,
			RPC_C_IMP_LEVEL_IMPERSONATE,
			NULL,
			EOAC_NONE,
			NULL);
		if (FAILED(hr))
		{
			sprintf(messages, "Failed to initialize security. Error code = 0x%08x", hr);
			throw std::runtime_error(messages);
		}
	}
	~SYSTEM_WINDOWS_COM_INITIALIZED() noexcept
	{
		CoUninitialize();
	}
};

static std::string VARIANT_string(BSTR& bstrVal)
{
	std::string result;
	LPSTR str = _com_util::ConvertBSTRToString(bstrVal);
	if (NULL != str)
	{
		result = str;
		delete[] str;
	}

	SysFreeString(bstrVal);
	return result;
}

static std::string VARIANT_string(VARIANT& vt) noexcept
{
	std::string result;
	if (vt.vt & VT_BSTR)
	{
		result = VARIANT_string(vt.bstrVal);
	}

	if (vt.vt != VT_EMPTY)
	{
		VariantClear(&vt);
	}

	return std::move(result);
}

static std::string VARIANT_string(IWbemClassObject* obj, LPCWSTR name) noexcept
{
	VARIANT vt;
	VariantInit(&vt);

	HRESULT hr = obj->Get(name, 0, &vt, 0, 0);
	if (SUCCEEDED(hr))
	{
		std::string result = VARIANT_string(vt);
		VariantClear(&vt);
		return std::move(result);
	}
	else
	{
		VariantClear(&vt);
		return std::string();
	}
}

template<typename T>
static T VARIANT_value(VARIANT& vt, T defaultValue) noexcept
{
	if (vt.vt == VT_I1)
	{
		return vt.cVal;
	}

	if (vt.vt == VT_I2)
	{
		return vt.iVal;
	}

	if (vt.vt == VT_I4)
	{
		return vt.intVal;
	}

	if (vt.vt == VT_I8)
	{
		return vt.llVal;
	}

	if (vt.vt == VT_UI1)
	{
		return vt.bVal;
	}

	if (vt.vt == VT_UI2)
	{
		return vt.uiVal;
	}

	if (vt.vt == VT_UI4)
	{
		return vt.uintVal;
	}

	if (vt.vt == VT_UI8)
	{
		return vt.ullVal;
	}

	if (vt.vt == VT_BOOL)
	{
		return vt.boolVal != VARIANT_FALSE ? 1 : 0;
	}

	if (vt.vt == VT_R4)
	{
		return vt.fltVal;
	}

	if (vt.vt == VT_R8)
	{
		return vt.dblVal;
	}

	if (vt.vt == VT_PTR)
	{
		return (int64_t)vt.punkVal;
	}

	if (vt.vt == VT_INT_PTR)
	{
		return vt.intVal;
	}

	if (vt.vt == VT_INT_PTR)
	{
		return vt.uintVal;
	}

	return defaultValue;
}

template<typename T>
T VARIANT_value(IWbemClassObject* obj, LPCWSTR name, T defaultValue) noexcept
{
	VARIANT vt;
	VariantInit(&vt);

	HRESULT hr = obj->Get(name, 0, &vt, 0, 0);
	if (SUCCEEDED(hr))
	{
		T result = VARIANT_value<T>(vt, defaultValue);
		VariantClear(&vt);
		return result;
	}
	else
	{
		VariantClear(&vt);
		return defaultValue;
	}
}

template<>
bool VARIANT_value<bool>(IWbemClassObject* obj, LPCWSTR name, bool defaultValue) noexcept
{
	int intValue = VARIANT_value<int>(obj, name, 0);
	return intValue != 0;
}

static bool VARIANT_strings(VARIANT& vt, std::vector<std::string>& strings) noexcept
{
	bool b = false;
	if (vt.vt & VT_ARRAY) /* SafeArrayDestroy */
	{
		SAFEARRAY* parray = vt.parray;
		if (vt.vt & VT_BSTR)
		{
			LONG lBound = 0;
			LONG uBound = 0;

			SafeArrayGetLBound(parray, 1, &lBound);
			SafeArrayGetUBound(parray, 1, &uBound);

			for (LONG i = lBound; i <= uBound; i++)
			{
				BSTR bstrIP;
				HRESULT hr = SafeArrayGetElement(parray, &i, &bstrIP);
				if (SUCCEEDED(hr))
				{
					std::string str = VARIANT_string(bstrIP);
					if (!str.empty())
					{
						b |= true;
						strings.push_back(str);
					}
				}
			}
		}
	}

	VariantClear(&vt);
	return b;
}

static bool VARIANT_strings(IWbemClassObject* obj, LPCWSTR name, std::vector<std::string>& strings) noexcept
{
	VARIANT vt;
	VariantInit(&vt);

	HRESULT hr = obj->Get(name, 0, &vt, 0, 0);
	if (SUCCEEDED(hr))
	{
		bool b = VARIANT_strings(vt, strings);
		VariantClear(&vt);
		return b;
	}

	VariantClear(&vt);
	return false;
}

static bool GetAllNetworkInterfacesInternal(std::vector<NetworkInterfacePtr>& interfaces) noexcept
{
	// 创建WMI服务
	IWbemLocator* pLoc = NULL;
	HRESULT hr = CoCreateInstance(
		CLSID_WbemLocator,
		0,
		CLSCTX_INPROC_SERVER,
		IID_IWbemLocator,
		(LPVOID*)&pLoc);
	if (FAILED(hr))
	{
		return false;
	}

	IWbemServices* pSvc = NULL;
	hr = pLoc->ConnectServer(
		_bstr_t(L"ROOT\\CIMV2"),
		NULL,
		NULL,
		0,
		NULL,
		0,
		0,
		&pSvc);
	if (FAILED(hr))
	{
		pLoc->Release();
		return false;
	}

	// 设置WMI服务安全级别
	hr = CoSetProxyBlanket(
		pSvc,
		RPC_C_AUTHN_WINNT,
		RPC_C_AUTHZ_NONE,
		NULL,
		RPC_C_AUTHN_LEVEL_CALL,
		RPC_C_IMP_LEVEL_IMPERSONATE,
		NULL,
		EOAC_NONE);
	if (FAILED(hr))
	{
		pSvc->Release();
		pLoc->Release();
		return false;
	}

	// 查询网卡信息
	IEnumWbemClassObject* pEnumerator = NULL;
	hr = pSvc->ExecQuery(
		_bstr_t(L"WQL"),
		_bstr_t(L"SELECT * FROM Win32_NetworkAdapterConfiguration"), /*  WHERE IPEnabled = TRUE */
		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
		NULL,
		&pEnumerator);
	if (FAILED(hr))
	{
		pSvc->Release();
		pLoc->Release();
		return false;
	}

	// 遍历网卡信息
	bool ok = false;
	while (pEnumerator)
	{
		IWbemClassObject* pclsObj = NULL;
		ULONG uReturn = 0;
		hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
		if (FAILED(hr) || 0 == uReturn)
		{
			break;
		}
		else
		{
			NetworkInterfacePtr networkInterface = std::make_shared<NetworkInterface>();
			networkInterface->Description = VARIANT_string(pclsObj, L"Description");
			networkInterface->Driver = VARIANT_string(pclsObj, L"ServiceName");
			networkInterface->Guid = VARIANT_string(pclsObj, L"SettingID");
			networkInterface->Index = VARIANT_value(pclsObj, L"Index", -1);
			networkInterface->InterfaceIndex = VARIANT_value(pclsObj, L"InterfaceIndex", -1);
			networkInterface->Metric = VARIANT_value(pclsObj, L"IPConnectionMetric", -1);
			networkInterface->MacAddress = VARIANT_string(pclsObj, L"MacAddress");
			networkInterface->IPEnabled = VARIANT_value(pclsObj, L"IPEnabled", false);
			networkInterface->DhcpEnabled = VARIANT_value(pclsObj, L"DhcpEnabled", false);
			networkInterface->Caption = VARIANT_string(pclsObj, L"Caption");
			networkInterface->ScopeId = VARIANT_string(pclsObj, L"WINSScopeID");
			networkInterface->ConnectionId = VARIANT_string(pclsObj, L"NetConnectionID");

			VARIANT_strings(pclsObj, L"IPAddress", networkInterface->IPAddresses);
			VARIANT_strings(pclsObj, L"IPSubnet", networkInterface->IPSubnet);
			VARIANT_strings(pclsObj, L"DefaultIPGateway", networkInterface->DefaultIPGateway);

			ok |= true;
			interfaces.push_back(networkInterface);
		}

		pclsObj->Release();
	}

	// 释放COM对象
	pEnumerator->Release();
	pSvc->Release();
	pLoc->Release();

	return ok;
}

static HRESULT VARIANT_create_safe_array(VARIANT& vt, const std::vector<std::string>& list) noexcept
{
	LONG length = list.size();
	if (length < 0)
	{
		length = 0;
	}

	SAFEARRAY* sa = SafeArrayCreateVector(VT_BSTR, 0, length);
	vt.vt = VT_ARRAY | VT_BSTR;
	vt.parray = sa;

	HRESULT hr = ERROR_SUCCESS;
	for (LONG i = 0; i < length; i++)
	{
		_bstr_t bstr(list[i].data());
		hr = SafeArrayPutElement(sa, &i, bstr.GetBSTR());
		if (FAILED(hr))
		{
			break;
		}
	}
	return hr;
}

template<typename InternalCall>
static bool CoCallFunctionInternal(IWbemServices* services, IWbemClassObject* obj, const _bstr_t& clazz, const _bstr_t& method, InternalCall&& internal_call) noexcept
{
	IWbemClassObject* pClass = NULL;
	IWbemClassObject* pInParamsDefinition = NULL;
	IWbemClassObject* pClassInstance = NULL;
	IWbemClassObject* pOutParams = NULL;

	VARIANT vtPATH;
	VariantInit(&vtPATH);

	VARIANT vtRET;
	VariantInit(&vtRET);

	bool ok = false;
	for (;;)
	{
		HRESULT hr = services->GetObject(clazz, 0, NULL, &pClass, NULL);
		if (FAILED(hr))
		{
			break;
		}

		hr = pClass->GetMethod(method, 0, &pInParamsDefinition, NULL);
		if (FAILED(hr))
		{
			break;
		}

		hr = pInParamsDefinition->SpawnInstance(0, &pClassInstance);
		if (FAILED(hr))
		{
			break;
		}

		hr = internal_call(pClassInstance);
		if (FAILED(hr))
		{
			break;
		}

		hr = obj->Get(L"__PATH", 0, &vtPATH, NULL, NULL);
		if (FAILED(hr))
		{
			break;
		}

		hr = services->ExecMethod(
			vtPATH.bstrVal,
			method, /* BSTR(L"SetDNSServerSearchOrder") */
			0,
			NULL,
			pClassInstance,
			&pOutParams,
			NULL);
		if (FAILED(hr))
		{
			break; /* SUCCEEDED */
		}

		hr = pOutParams->Get(_bstr_t(L"ReturnValue"), 0, &vtRET, NULL, 0);
		if (FAILED(hr))
		{
			break;
		}

		int err = VARIANT_value(vtRET, 0);
		if (err)
		{
			break;
		}

		ok = true;
		break;
	}

	if (vtPATH.vt & VT_BSTR)
	{
		SysFreeString(vtPATH.bstrVal);
	}

	if (pOutParams)
	{
		pOutParams->Release();
	}

	if (pClassInstance)
	{
		pClassInstance->Release();
	}

	if (pInParamsDefinition)
	{
		pInParamsDefinition->Release();
	}

	if (pClass)
	{
		pClass->Release();
	}

	VariantClear(&vtRET);
	VariantClear(&vtPATH);
	return ok;
}

// https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/setdnsserversearchorder-method-in-class-win32-networkadapterconfiguration
// https://learn.microsoft.com/zh-cn/windows/win32/wmisdk/example--calling-a-provider-method?source=recommendations
static bool SetNetifAddressesInternal(IWbemServices* services, IWbemClassObject* obj, const _bstr_t& method, LPCWSTR parameter, const std::vector<std::string>& addresses) noexcept
{
	const _bstr_t Win32_NetworkAdapterConfiguration(L"Win32_NetworkAdapterConfiguration");

	return CoCallFunctionInternal(services, obj, Win32_NetworkAdapterConfiguration, method,
		[&addresses, parameter](IWbemClassObject* pClassInstance) noexcept
		{
			VARIANT vt;
			VariantInit(&vt);

			HRESULT hr = VARIANT_create_safe_array(vt, addresses);
			if (SUCCEEDED(hr))
			{
				hr = pClassInstance->Put(parameter, 0, &vt, 0);
			}

			VariantClear(&vt);
			return hr;
		});
}

static bool SetDnsAddressesInternal(IWbemServices* services, IWbemClassObject* obj, const std::vector<std::string>& servers) noexcept
{
	const _bstr_t SetDNSServerSearchOrder(L"SetDNSServerSearchOrder");

	return SetNetifAddressesInternal(services, obj, SetDNSServerSearchOrder, L"DNSServerSearchOrder", servers);
}

template<typename InternalCall>
static bool SetNetifAddressesInternal(int interface_index, InternalCall&& internal_call) noexcept
{
	// 创建WMI服务
	IWbemLocator* pLoc = NULL;
	HRESULT hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLoc);
	if (FAILED(hr))
	{
		return false;
	}

	IWbemServices* pSvc = NULL;
	hr = pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &pSvc);
	if (FAILED(hr))
	{
		pLoc->Release();
		return false;
	}

	// 设置WMI服务安全级别
	hr = CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE);
	if (FAILED(hr))
	{
		pSvc->Release();
		pLoc->Release();
		return false;
	}

	WCHAR wsql[256];
	if (_snwprintf(wsql, sizeof(wsql), L"SELECT * FROM Win32_NetworkAdapterConfiguration WHERE InterfaceIndex = '%d'", interface_index) < 1)
	{
		pSvc->Release();
		pLoc->Release();
		return false;
	}

	// 查询网卡信息
	IEnumWbemClassObject* pEnumerator = NULL;
	hr = pSvc->ExecQuery(
		_bstr_t(L"WQL"),
		_bstr_t(wsql),
		WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
		NULL,
		&pEnumerator);
	if (FAILED(hr))
	{
		pSvc->Release();
		pLoc->Release();
		return false;
	}

	// 遍历网卡信息
	bool ok = false;
	while (pEnumerator)
	{
		IWbemClassObject* pclsObj = NULL;
		ULONG uReturn = 0;
		hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
		if (FAILED(hr) || 0 == uReturn)
		{
			break;
		}

		ok |= internal_call(pSvc, pclsObj);
		pclsObj->Release();
		break;
	}

	pEnumerator->Release();
	pSvc->Release();
	pLoc->Release();

	return ok;
}

static bool SetNetifIPAddressInternal(IWbemServices* services, IWbemClassObject* obj, const std::vector<std::string>& ips, const std::vector<std::string>& masks) noexcept
{
	const _bstr_t Win32_NetworkAdapterConfiguration(L"Win32_NetworkAdapterConfiguration");
	const _bstr_t EnableStatic(L"EnableStatic");

	return CoCallFunctionInternal(services, obj, Win32_NetworkAdapterConfiguration, EnableStatic,
		[&ips, &masks](IWbemClassObject* pClassInstance) noexcept
		{
			VARIANT vtIPAddress;
			VARIANT vtSubnetMask;

			VariantInit(&vtIPAddress);
			VariantInit(&vtSubnetMask);

			HRESULT hr = VARIANT_create_safe_array(vtIPAddress, ips);
			if (SUCCEEDED(hr))
			{
				hr = pClassInstance->Put(L"IPAddress", 0, &vtIPAddress, 0);
				if (SUCCEEDED(hr))
				{
					hr = VARIANT_create_safe_array(vtSubnetMask, masks);
					if (SUCCEEDED(hr))
					{
						hr = pClassInstance->Put(L"SubnetMask", 0, &vtSubnetMask, 0);
					}
				}
			}

			VariantClear(&vtIPAddress);
			VariantClear(&vtSubnetMask);
			return hr;
		});
	return false;
}

static bool SetDefaultIPGatewayInternal(IWbemServices* services, IWbemClassObject* obj, const std::vector<std::string>& gateways) noexcept
{
	const _bstr_t SetGateways(L"SetGateways");

	return SetNetifAddressesInternal(services, obj, SetGateways, L"DefaultIPGateway", gateways);
}

static bool DhcpEnabledInternal(IWbemServices* services, IWbemClassObject* obj) noexcept
{
	const _bstr_t Win32_NetworkAdapterConfiguration(L"Win32_NetworkAdapterConfiguration");
	const _bstr_t EnableDHCP(L"EnableDHCP");

	VARIANT vtDHCPEnabled;
	VariantInit(&vtDHCPEnabled);

	VARIANT vtPATH;
	VariantInit(&vtPATH);

	vtDHCPEnabled.vt = VT_BOOL;
	vtDHCPEnabled.boolVal = VARIANT_TRUE;

	HRESULT hr = obj->Put(L"DHCPEnabled", 0, &vtDHCPEnabled, 0);
	if (SUCCEEDED(hr))
	{
		hr = obj->Get(L"__PATH", 0, &vtPATH, NULL, NULL);
		if (SUCCEEDED(hr))
		{
			hr = services->ExecMethod(vtPATH.bstrVal, EnableDHCP, 0, NULL, obj, NULL, NULL);
		}
	}

	if (vtPATH.vt & VT_BSTR)
	{
		SysFreeString(vtPATH.bstrVal);
	}

	VariantClear(&vtPATH);
	VariantClear(&vtDHCPEnabled);
	return SUCCEEDED(hr);
}

bool GetAllNetworkInterfaces(std::vector<NetworkInterfacePtr>& interfaces) noexcept
{
	SYSTEM_WINDOWS_COM_INITIALIZED WINDOWS_COM_INITIALIZED;
	return GetAllNetworkInterfacesInternal(interfaces);
}

bool SetDnsAddresses(int interface_index, const std::vector<std::string>& servers) noexcept
{
	SYSTEM_WINDOWS_COM_INITIALIZED WINDOWS_COM_INITIALIZED;
	return SetNetifAddressesInternal(interface_index,
		[&servers](IWbemServices* pSvc, IWbemClassObject* pclsObj) noexcept
		{
			return SetDnsAddressesInternal(pSvc, pclsObj, servers);
		});
}

bool SetDefaultIPGateway(int interface_index, const std::vector<std::string>& servers) noexcept
{
	SYSTEM_WINDOWS_COM_INITIALIZED WINDOWS_COM_INITIALIZED;
	return SetNetifAddressesInternal(interface_index,
		[&servers](IWbemServices* pSvc, IWbemClassObject* pclsObj) noexcept
		{
			return SetDefaultIPGatewayInternal(pSvc, pclsObj, servers);
		});
}

bool SetIPAddresses(int interface_index, const std::vector<std::string>& ips, const std::vector<std::string>& masks) noexcept
{
	SYSTEM_WINDOWS_COM_INITIALIZED WINDOWS_COM_INITIALIZED;
	return SetNetifAddressesInternal(interface_index,
		[&ips, &masks](IWbemServices* pSvc, IWbemClassObject* pclsObj) noexcept
		{
			return SetNetifIPAddressInternal(pSvc, pclsObj, ips, masks);
		});
}

bool DhcpEnabled(int interface_index) noexcept
{
	SYSTEM_WINDOWS_COM_INITIALIZED WINDOWS_COM_INITIALIZED;
	return SetNetifAddressesInternal(interface_index,
		[](IWbemServices* pSvc, IWbemClassObject* pclsObj) noexcept
		{
			return DhcpEnabledInternal(pSvc, pclsObj);
		});
}

int main()
{
	std::vector<NetworkInterfacePtr> interfaces;
	GetAllNetworkInterfaces(interfaces);

	std::vector<std::string> servers = { "1.1.1.1", "8.8.8.8" };
	SetIPAddresses(18, { "10.0.0.2" }, { "255.255.255.0" });
	SetDefaultIPGateway(18, { "10.0.0.1" });
	SetDnsAddresses(18, servers);
	DhcpEnabled(18);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值