#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;
}
C++ 通过WMI接口设置/获取网卡信息(DHCP、IP、MASK、GW)
最新推荐文章于 2024-04-15 14:08:13 发布