Click here to Skip to main content
15,886,026 members
Please Sign up or sign in to vote.
4.50/5 (2 votes)
See more:
G'Day All,

I have been trying to get the EnableStatic function to work with Multiple IP's/Netmasks and am having trouble. At NO point do I get any errors to any of the function calls, but none of my passed IP/Netmask pairs are actually being programmed. Hoping someone on here might have an idea as to what I am possibly doing wrong or missing.

The code to do the C++ EnableStatic was based off of this article in the posts section from "Brian Clow For God's Sake 10:38 30 May '06":

Making WMI Queries In C++[^]

I have changed the function to instead take a list of IP/Netmasks and build the EnableStatic parameters from those.

Here is the code (there is still some cleanup to do in the error returns for the function calls, but I have been first trying to get it to work):

C++
typedef struct IP_INFO
{
	char ip[40];
	char netmask[40];
} IP_INFO, *PIP_INFO;

bool AddIPAddressToAdapterPersistant(PIP_INFO &ipInfo, INT count, INT fIndex)
{
	HRESULT hr;
    IWbemLocator *pLocator = NULL;
    IWbemServices *pNamespace = NULL;
	BSTR path = SysAllocString(L"ROOT\\CIMV2");

    // Initialize COM and connect to WMI.
    hr = CoInitialize(0);
	if(FAILED(hr))
	{
		return (false);
	} // if

    hr  =  CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); 
	if(FAILED(hr))
	{
		CoUninitialize();
		return(false);
	} // if

    hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLocator);
	if (FAILED(hr))
	{
		CoUninitialize();
		return (false);
	} // if

    hr = pLocator->ConnectServer(path, NULL, NULL, NULL, 0, NULL, NULL, &pNamespace);
	if(FAILED(hr))
	{
		pLocator->Release();
		CoUninitialize();
		return(false);
	} // if

	// Grab class required to work on Win32_NetworkAdapterConfiguration
	IWbemClassObject *pClass = NULL;
	BSTR ClassPath = SysAllocString(L"Win32_NetworkAdapterConfiguration");
	hr = pNamespace->GetObject(ClassPath, 0, NULL, &pClass, NULL);
	SysFreeString(ClassPath);
	if( WBEM_S_NO_ERROR == hr )
	{
		// Grab pointer to the input parameter class of the method we are going to call
		BSTR MethodName_ES = SysAllocString(L"EnableStatic");
		IWbemClassObject *pInClass_ES = NULL;
		if(WBEM_S_NO_ERROR == pClass->GetMethod(MethodName_ES, 0, &pInClass_ES, NULL))
		{
			// Spawn instance of the input parameter class, so that we can stuff our parameters in
			IWbemClassObject *pInInst_ES = NULL;
 
			if(WBEM_S_NO_ERROR == pInClass_ES->SpawnInstance(0, &pInInst_ES))
			{
				//
				// (Step 3) - Pack desired parameters into the input class instances
				//
				// Convert from multibyte strings to wide character arrays
				wchar_t tmp_ip[_countof(ipInfo->ip)];
				SAFEARRAY *ip_list = SafeArrayCreateVector(VT_BSTR, 0, count);
				// Insert into safe arrays, allocating memory as we do so (destroying the safe array will destroy the allocated memory)
				long idx[] = {0};
				for(int i = 0; i < count; i++)
				{
					mbstowcs(tmp_ip, ipInfo[i].ip, _countof(ipInfo[i].ip));
					BSTR ip = SysAllocString(tmp_ip);
					idx[0] = i;
					if(FAILED(SafeArrayPutElement(ip_list, idx, ip)))
					{
						return (false);
					} // if
					// Destroy the BSTR pointer
					SysFreeString(ip);
				} // for

				// Convert from multibyte strings to wide character arrays
				wchar_t tmp_netmask[_countof(ipInfo->netmask)];
				SAFEARRAY *netmask_list = SafeArrayCreateVector(VT_BSTR, 0, count);
				// Insert into safe arrays, allocating memory as we do so (destroying the safe array will destroy the allocated memory)
				for(int i = 0; i < count; i++)
				{
					mbstowcs(tmp_netmask, ipInfo[i].netmask, _countof(ipInfo[i].netmask));
					BSTR netmask = SysAllocString(tmp_netmask);
					idx[0] = i;
					if(FAILED(SafeArrayPutElement(netmask_list, idx, netmask)))
					{
						return (false);
					} // if
					// Destroy the BSTR pointer
					SysFreeString(netmask);
				} // for

				// Now wrap each safe array in a VARIANT so that it can be passed to COM function
				VARIANT arg1_ES;
				VariantInit(&arg1_ES);
				arg1_ES.vt = VT_ARRAY|VT_BSTR;
				arg1_ES.parray = ip_list;
 
				VARIANT arg2_ES;
				VariantInit(&arg2_ES);
				arg2_ES.vt = VT_ARRAY|VT_BSTR; 
				arg2_ES.parray = netmask_list;
  
				if((WBEM_S_NO_ERROR == pInInst_ES->Put(L"IPAddress", 0, &arg1_ES, 0)) &&
			       (WBEM_S_NO_ERROR == pInInst_ES->Put(L"SubNetMask", 0, &arg2_ES, 0)))
				{
					//
					// (Step 4) - Call the methods
					//

					// First build the object path that specifies which network adapter we are executing a method on
					char indexString[10];
					itoa(fIndex, indexString, 10);
 
					char instanceString[100];
					wchar_t w_instanceString[100];
					strcpy(instanceString, "Win32_NetworkAdapterConfiguration.Index='");
					strcat(instanceString, indexString);
					strcat(instanceString, "'");
					mbstowcs(w_instanceString, instanceString, 100);
					BSTR InstancePath = SysAllocString(w_instanceString);
 
					// Now call the method
					IWbemClassObject * pOutInst = NULL;
					hr = pNamespace->ExecMethod(InstancePath, MethodName_ES, 0, NULL, pInInst_ES, &pOutInst, NULL);
					if(FAILED(hr))
					{
						// false
						return(false);
					} // if
					SysFreeString(InstancePath);
				} // if
 
				// Clear the variants - does this actually get ride of safearrays?
				VariantClear(&arg1_ES);
				VariantClear(&arg2_ES);

				// Destroy safe arrays, which destroys the objects stored inside them
				SafeArrayDestroy(ip_list); ip_list = NULL;
				SafeArrayDestroy(netmask_list); netmask_list = NULL;
 			}
			else
			{
				 // false
			} // if
 
			// Free up the instances that we spawned
			if(pInInst_ES)
			{
				pInInst_ES->Release();
				pInInst_ES = NULL;
			} // if
		}
		else
		{
			// false
		} // if
 
		// Free up methods input parameters class pointers
		if(pInClass_ES)
		{
			pInClass_ES->Release();
			pInClass_ES = NULL;
		} // if
		SysFreeString(MethodName_ES);
	}
	else
	{
		// false
	} // if
 
	// Variable cleanup
	if (pNamespace)
	{
		pNamespace->Release();
		pNamespace = NULL;
	}
	if (pLocator)
	{
		pLocator->Release();
		pLocator = NULL;
	} // if
	if(pClass)
	{
		pClass->Release();
		pClass = NULL;
	} //if
	CoUninitialize();

	return(true);
}


Thanks!
Posted
Updated 7-Aug-18 3:03am
v2
Comments
Member 10557037 21-Jan-16 4:16am    
Tipp: For better overview it may be a good idea to create a seaparate function that build the SAFEARRAY from an array of strings.
Member 13339507 1-Aug-17 9:34am    
Can you share the source code?
I'm trying to do something like that, but can't.
kj_easy_DN 3-Aug-18 10:57am    
Does this still work in Windows 10?

I copied the source code without any modifications, and just added a main function like this:

IP_INFO ipData[1];
strcpy_s (ipData[0].ip, sizeof(ipData[0].ip), "10.0.2.15");
strcpy_s (ipData[0].netmask, sizeof(ipData[0].netmask), "255.255.255.0");

PIP_INFO pipData = &(ipData[0]);
bool ret = AddIPAddressToAdapterPersistant(pipData, 1, 1);

I single stepped through the whole procedure, every call return OK, but in the end the one and only network adapter config was NOT changed.
I checked this with ipconfig/all and by opening the control panel/network card/properties page, TCP/IPv4.
Everything still DHCP, nothing changed.
kj_easy_DN 7-Aug-18 4:36am    
Well, I had to run the developer studio as admin. Then things worked fine.
Please see my post below, how to improve the sample a bit, to get some hints about the reason for a call, which returns hr=S_OK, but seems to have "no effect".

Well, found the problem. *sigh*

My ip/netmask list that I was passing to the function contained a first IP of 10.0.1.0 ... oversight on my part since it's an invalid IP. BUT the EnableStatic() call took the parameters and returned an HRESULT of OK. It doesn't seem like the EnableStatic() will return an error if you pass it an invalid IP/NETMASK pair.

Code and learn I guess.
 
Share this answer
 
C#
VariantClear(&arg1_ES);
VariantClear(&arg2_ES);


This two line is not needed because SafeArrayDestroy will have the VariantClear function called on each member and safe arrays of BSTR will have the SysFreeString function called on each element.
 
Share this answer
 
Good to know:
a) run this code as administrator, otherwise hRes returns OK, but the "retValue" (pOutInst in the example above) returned as output parameter will indicate an error.

b) to get retValue, use these additional lines of code can help:

C++
// existing code from above
IWbemClassObject * pOutInst = NULL;
hr = pNamespace->ExecMethod(InstancePath, MethodName_ES, 0, NULL, pInInst_ES, &pOutInst, NULL);
if(FAILED(hr))
{
	// false
	return(false);
} // if FAILED

// added ---------------------------
// From the point of view of WMI, the function succeeded, but the 
// operating system might have some objections.
// The operating system return code is stored in the property 
// "ReturnValue" of the result parameter. 

else  
{  
	VARIANT vtRet;  
	VariantInit(&vtRet);
  
	hr = pOutInst->Get(L"ReturnValue", 0, &vtRet, NULL, 0);
	if (FAILED(hr)) 
		return (false); 
	else  
	{
		if (vtRet.intVal == 0 || vtRet.intVal == 1)
		{
			// no error: 0=OK, 1=OK, but reboot required
		}
		else
		{
			// if (vtRet.intVal == 0x80070005 || vtRet.intVal == 81)
			// 0x80070005=E_ACCESS_DENIED: Access denied by DCOM security.
			// 81=no access rights
			return (false);
	}

	VariantClear(&vtRet);  
	pOutInst->Release();  
}  
// ----------------------------------
SysFreeString(InstancePath);


Finally, if you want to get some readable error message back, you can use FormatMessage and tell this function to look into the WMI DLL "wbem\wmiutils.dll", and use vtRet.intVal as input, like this:

C++
<pre>#include "Shlobj.h"
PWCHAR WMI_GetErrorString(DWORD err)                                        
{
	static WCHAR szErrorString[1024]; // returned data buffer
	szErrorString[0] = '\0';

	WCHAR path[MAX_PATH];
	PWSTR pDllPath=NULL;
	HMODULE hDllModule=NULL;

	// get path to Windows\system32
	HRESULT hr = ::SHGetKnownFolderPath(FOLDERID_System, 0, NULL, &pDllPath);

	if(SUCCEEDED(hr))                                                
	{ /* succeeded */
		// append path to wmiutils.dll, and attempt to load the DLL
		wcscpy_s (path, pDllPath);
		wcscat_s (path, L"\\wbem\\wmiutils.dll");

		hDllModule = ::LoadLibrary(path);                                   
		if(hDllModule != NULL) 
		{/* DLL load succeeded */

			// use FormatMessage to get the error text for the current error code
			// from wmiutils.dll

			if(::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE,
				(LPCVOID)hDllModule,                                 
				err,                                          
				0,						// language ID
				szErrorString,
				sizeof(szErrorString),
				NULL)
				== 0)
			{ /* not found */
				;
			} /* not found */

			PWCHAR eol = wcschr(szErrorString, L'\r');                            
			if(eol != NULL)
				*eol = L'\0';// remove trailing \r\n, if necessary                                              


		} /* succeeded */
	} /* succeeded */


	// housekeeping
	if (pDllPath != NULL)
		 CoTaskMemFree(pDllPath);
	if (hDllModule != NULL)
		::FreeLibrary(hDllModule); 

	return szErrorString;
} // ErrorString
 
Share this answer
 
Comments
Richard Deeming 7-Aug-18 13:25pm    
Asked, answered, and solved SIX YEARS AGO.

Stick to answering recent questions.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900