I am writing a VC++ program which needs to change Network Connection name (eg. "Local Connection").
The Windows's IPHELPER provides API to get network connection, but it doesn't provide write method.
And I know I can use "netsh" to change this network connection name, yes, in English Windows, this method works properly, but in Japanese or Chinese Windows this method can't work properly.
After read some documents in MSDN, I found WMI Win32_NetworkAdapter class has a property "NetConnectionID". This property contains the adapter's network connection name, and its read/write perperty.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa394216(v=vs.85).aspx
NetConnectionID
Data type: string
Access type: Read/write
So, I wrote a WMI code to change this property value.
int RasWmiAdapterSetInfo(void *pWmiAdapterCfg)
{
if(pWmiAdapterCfg)
{
int retVal = -1;
HRESULT hres;
VARIANT varWrite;
RAS_WMI_W32_ADAPTER_PTR *pRasWmiAdapterCfg = (RAS_WMI_W32_ADAPTER_PTR*)pWmiAdapterCfg;
VariantInit(&varWrite);
V_VT(&varWrite) = VT_BSTR;
V_BSTR(&varWrite) = SysAllocString(L"My New Connection 1");
hres = pRasWmiAdapterCfg->pclsObj->Put(L"NetConnectionID", 0, &varWrite, 0);
if(FAILED(hres))
{
printf("RasWmiAdapterSetInfo Failed HR=%08x\n", hres);
goto CLEARUP;
}
retVal = 0;
CLEARUP:
VariantClear(&varWrite);
return retVal;
}
return -1;
}
The return value hres was OK, but this property value was not changed.
IWbemLocator *pLoc;
IWbemServices *pSvc;
IEnumWbemClassObject *pEnumerator;
...
... (ignore some code to init pLoc, pSvc, pEnumerator)
...
IWbemClassObject *pclsObj;
IWbemClassObject *pClass;
pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
pSvc->GetObject( bstr_t(adapterClsName), 0, NULL, &pClass, NULL );
Is anyone can tell me why the pclsObj->Put method did not take effect?
Thanks.
As far as I understand, IWbemClassObject::Put() only updates a class instance's property value in memory. To commit changes to WMI repository, you need to call IWbemServices::PutInstance() to update entire class instance.
So adding something like this to your code should get it to work:
IWbemCallResult* callResult = nullptr;
HRESULT hr = wbemSvc_->PutInstance(pClass, WBEM_FLAG_UPDATE_ONLY,
nullptr, &callResult);
if (SUCCEEDED(hr) && callResult)
callResult->Release();
Hope that helps!
Related
I'm trying to learn how the WMI works, but the default examples given have so far been atrocious.
Here's the example for calling the Create method of the Win32_Process class:
https://learn.microsoft.com/en-us/windows/win32/wmisdk/example--calling-a-provider-method
I have added proper error handling to this, we store the HRESULT of each call in a variable hres and check if the calls failed. As such:
hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);
if (FAILED(hres))
{
wprintf("Failed to get class. Error code = 0x%lx\n", hres);
return hres;
}
The code executes correctly right up until here:
// Create the values for the in parameters
VARIANT varCommand;
varCommand.vt = VT_BSTR;
varCommand.bstrVal = _bstr_t(L"notepad.exe");
// Store the value for the in parameters
hres = pClassInstance->Put(L"CommandLine", 0,
&varCommand, 0);
wprintf(L"The command is: %s\n", V_BSTR(&varCommand));
Where the pClassInstance->Put throws 'ol c5.
At this point, hres is S_OK for the call to SpawnInstance but these are the pointers we have for the class instances:
+pClass 0x000001c04e73fca0 IWbemClassObject *
- pClassInstance 0x000001c04e749d60 IWbemClassObject *
- IUnknown {...} IUnknown
- __vfptr 0x00007ff9f8d0ee98 {fastprox.dll!const CWbemInstance::`vftable'{for `_IWmiObject'}} {0x00007ff9f8c6f450 {fastprox.dll!CWbemObject::QueryInterface(void)}, ...} void * *
[0x00000000] 0x00007ff9f8c6f450 {fastprox.dll!CWbemObject::QueryInterface(void)} void *
[0x00000001] 0x00007ff9f8c907d0 {fastprox.dll!CWbemObject::AddRef(void)} void *
[0x00000002] 0x00007ff9f8c8ffd0 {fastprox.dll!CWbemObject::Release(void)} void *
+pInParamsDefinition 0x000001c04e743ca0 IWbemClassObject *
And varCommand:
+varCommand BSTR = 0x000001c04e74ffe8 tagVARIANT
The call stack:
oleaut32.dll!SysAllocString()
vfbasics.dll!AVrfpSysAllocString()
wbemcomn.dll!CVar::SetVariant()
fastprox.dll!CWbemInstance::Put()
> Ele.exe!WMIConnection::InvokeMethod()
So it appears that bstrVal isn't being properly set, I think? I tried initializing it first with VariantInit, and I also tried dynamically allocating it on the heap instead. Neither resolved the issue:
VARIANT varCommand;
VariantInit(&varCommand);
varCommand.vt = VT_BSTR;
varCommand.bstrVal = _bstr_t(L"notepad.exe");
I also tried manually zeroing out the Variant buffer, to no effect. This is what we have for bstrVal in the memory dump when the access violation occurs:
bstrVal 0x000001c04e74ffe8 <Error reading characters of string.> wchar_t *
<Unable to read memory> wchar_t
On this line:
varCommand.bstrVal = _bstr_t(L"notepad.exe");
The code creates a temporary _bstr_t object that goes out of scope, destroying the allocated BSTR memory, immediately after varCommand.bstrVal has been assigned to. Thus, varCommand.bstrVal is left dangling, pointing at invalid memory, when varCommand is passed to pClassInstance->Put(). That is undefined behavior.
Use this instead to keep the BSTR alive until you are actually done using it:
_bstr_t str(L"notepad.exe");
VARIANT varCommand;
varCommand.vt = VT_BSTR;
varCommand.bstrVal = str;
// use varCommand as needed...
// DO NOT call VarClear() or SysFreeString()!
// You don't own the BSTR memory...
//VarClear(&varCommand);
Alternatively:
VARIANT varCommand;
varCommand.vt = VT_BSTR;
varCommand.bstrVal = SysAllocString(L"notepad.exe");
// use varCommand as needed...
// You DO own the BSTR memory, so free it!
VarClear(&varCommand);
Otherwise, consider using _variant_t instead, let it manage the memory for you:
_variant_t varCommand(L"notepad.exe");
hres = pClassInstance->Put(L"CommandLine", 0, &varCommand, 0);
wprintf(L"The command is: %s\n", V_BSTR(&varCommand));
I figured it out. There are several forum posts on the internet asking about this example, with no solutions given, so I am very happy to provide this now.
The Microsoft example is using the incorrect classes.
In the Microsoft example, they attempt to call the Put method on a class instance of Win32_Process to set the parameters.
This is incorrect. We need to set the parameters via first getting the class method definition for Win32_Process::Create and then setting its parameters inside a new instance of Win32_Process::Create.
We additionally need to construct an instance of the Win32_ProcessStartup class object as it's a required input parameter for Win32_Process::Create.
In the example below I will populate one field of the Win32_ProcessStartup class instance, you can figure out the rest.
So this code from the Microsoft example:
IWbemClassObject* pClass = NULL;
hres = pSvc->GetObject(ClassName, 0, NULL, &pClass, NULL);
IWbemClassObject* pInParamsDefinition = NULL;
hres = pClass->GetMethod(MethodName, 0,
&pInParamsDefinition, NULL);
IWbemClassObject* pClassInstance = NULL;
hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);
// Create the values for the in parameters
VARIANT varCommand;
varCommand.vt = VT_BSTR;
varCommand.bstrVal = _bstr_t(L"notepad.exe");
// Store the value for the in parameters
hres = pClassInstance->Put(L"CommandLine", 0,
&varCommand, 0);
wprintf(L"The command is: %s\n", V_BSTR(&varCommand));
Becomes (sans error handling for readability):
// Get the class object
hres = pClass->GetMethod(lpwMethodName, 0,
&pInParamsDefinition, NULL);
hres = pInParamsDefinition->SpawnInstance(0, &pClassInstance);
// Get the Win32_ProcessStartup class object
IWbemClassObject* pStartupObject = NULL;
hres = pSvc->GetObject(_bstr_t(L"Win32_ProcessStartup"), 0, NULL, &pStartupObject, NULL);
// Create an instance of the Win32_ProcessStartup class object
IWbemClassObject* pStartupInstance = NULL;
hres = pStartupObject->SpawnInstance(0, &pStartupInstance);
// Create the value for the ShowWindow variable of the Win32_ProcessStartup class
VARIANT varParams;
VariantInit(&varParams);
varParams.vt = VT_I2;
varParams.intVal = SW_SHOW;
// And populate it
hres = pStartupInstance->Put(_bstr_t(L"ShowWindow"), 0, &varParams, 0);
// Get the method definition for Win32_Process::Create and store it in pInParamsDefinition
hres = pClass->GetMethod(_bstr_t(lpwMethodName), 0, &pInParamsDefinition, NULL);
// Spawn an instance of the Create method and store it in pParamsInstance
IWbemClassObject* pParamsInstance = NULL;
hres = pInParamsDefinition->SpawnInstance(0, &pParamsInstance);
// Now we can set the parameters without error
hres = pParamsInstance->Put(_bstr_t(L"CurrentDirectory"), 0, pvCurrentDirectory, 0);
Please note that all of these hres returns should be checked for failure.
The definition for Win32_ProcessStartup is provided here:
https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-processstartup
And the definition for the Create method of Win32_Process:
https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/create-method-in-class-win32-process
I am trying to save a shortcut to my application in the startup folder. It all compiles, but it fails to actually save the game. The error seems to occur at hres = ppf->Save(wsz, TRUE);, where hres is set to -2147024891. If that means something specific, I haven't discovered what yet. My code is copied almost verbatim from MSDN, so I'm pretty confused why it isn't working. Perhaps I don't have permission to save a shortcut to the startup folder? Then again, I am also fairly new to all this, so it might be some basic error I am making. I am copying in all my #includes as well in case that is the problem.
Edit:
First, to avoid confusion, this is CLI based C++.
Checking hres for errors is just part of the MDSN code. This is really almost the exact same code from the website example. I have put in breakpoints, which is how I know that hres becomes -2147024891 right after the line hres = ppf->Save(wsz, TRUE); is run.
In case these are wrong, mediaMaestroLocation is set to "C:\Users\Keith\Documents\Visual Studio 2012\Projects\MediaMaestro\Debug\MediaMaestro.exe" and startupDestination is "C:\Users\Keith\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup". While the exe location looks great, I wonder if it matters that there isn't a \ after the destination folder path. I would have checked it already, but I need to spend a couple minutes figure out how to do it first.
#include <windows.h>
#include <string>
#include <stdio.h>
#include <shobjidl.h>
#include <shlobj.h>
#include "objbase.h"
#include <objidl.h>
#include <shlguid.h>
#include <winnls.h>
#using <System.dll>
#using <System.Windows.Forms.dll>
using namespace System;
using namespace System::Windows::Forms;
char startupDestination[MAX_PATH];
char mediaMaestroLocation[MAX_PATH];
DWORD nChars = 0;
BOOL yChars = 0;
HRESULT CreateLink()
{
CoInitializeEx( NULL, 0 );
HRESULT hres = 0;
IShellLink* psl;
if (SUCCEEDED(hres))
{
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(mediaMaestroLocation);
psl->SetDescription("Media Maestro");
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Ensure that the string is Unicode.
MultiByteToWideChar(CP_ACP, 0, startupDestination, -1, wsz, MAX_PATH);
// Add code here to check return value from MultiByteWideChar
// for success.
// Save the link by calling IPersistFile::Save.
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
}
CoUninitialize();
return hres;
}
Here is the click event in the UI that calls the function:
void settingsLaunchOnStart_Click( Object^ Sender, EventArgs^ e )
{
if (settingsLaunchOnStart->Checked == false)
{
HRESULT r;
nChars = GetModuleFileName( NULL, mediaMaestroLocation, sizeof(mediaMaestroLocation) );
yChars = SHGetFolderPath( NULL, CSIDL_STARTUP, NULL, SHGFP_TYPE_CURRENT, startupDestination);
r = CreateLink();
}
else if (settingsLaunchOnStart->Checked == true)
{
//code to remove the shortcut
}
}
Is there something I am missing?
It turns out that it wasn't enough to name the output folder path, I had to name the file and extension as well. It seems strange to me, considering I don't think I have seen a single other example doing this. Anyway, here is my updated working code:
HRESULT CreateLink()
{
CoInitializeEx( NULL, 0 );
HRESULT hres = 0;
IShellLink* psl;
if (SUCCEEDED(hres))
{
// Get a pointer to the IShellLink interface. It is assumed that CoInitialize
// has already been called.
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLink, (LPVOID*)&psl); //CLSCTX_ALL CLSCTX_INPROC_SERVER (void**)&psl (LPVOID*)&psl
if (SUCCEEDED(hres))
{
IPersistFile* ppf;
// Set the path to the shortcut target and add the description.
psl->SetPath(mediaMaestroLocation);
psl->SetDescription(L"Media Maestro");
psl->SetIconLocation(mediaMaestroLocation, 0);
// Query IShellLink for the IPersistFile interface, used for saving the
// shortcut in persistent storage.
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); //(void**)&psl (LPVOID*)&ppf
if (SUCCEEDED(hres))
{
WCHAR wsz[MAX_PATH];
// Save the link by calling IPersistFile::Save.
hres = _wmakepath_s( wsz, _MAX_PATH, NULL, startupDestination,
L"MediaMaestro", L"lnk" );
hres = ppf->Save(wsz, TRUE);
ppf->Release();
}
psl->Release();
}
}
CoUninitialize();
return hres;
}
The addition of _wmakepath_s lets me append the name of my program and its extension onto the filepath I got from SHGetFolderPath. Once I feed that into the IPersistFile interface it saves as it should.
you have only initialized hres to 0 and then ur checking if it succeded ? u are never realling declaring it somewhere, and -2147024891 probably means that the variable is not initialized yet.
a wild guess is that it never even reahes the: hres = ppf->Save(wsz, TRUE); line and therefore it is not initialized :P try putting out some breakpoints when debugging and maybe use some watches to peek into variables :)
Best regards.
I've been trying to follow the following MSDN tutorial to query the 64 bit registry provider from a 32 bit application.
Sadly, the examples are all written in VB, and I'm stuck with something.
For C++ developers, the article mentions that...
C++ applications can use the IWbemContext interface with IWbemServices::ExecMethod to communicate the use of a nondefault provider to WMI.
...although, when you look at the sample VB code, the context object is also used in the ConnectServer method:
Set objCtx = CreateObject("WbemScripting.SWbemNamedValueSet")
objCtx.Add "__ProviderArchitecture", 32
Set objLocator = CreateObject("Wbemscripting.SWbemLocator")
Set objServices = objLocator.ConnectServer("","root\default","","",,,,objCtx)
Set objStdRegProv = objServices.Get("StdRegProv")
I've tried reproducing this in VC++:
HRESULT res;
CComPtr<IWbemContext> ctx;
if (!create_registry_redirection_context_(hive, ctx)) {
return false;
}
res = locator_->ConnectServer(CComBSTR(namespace_.c_str()), // Namespace to use
0, // Current security context (username)
0, // Current security context (password)
0, // Use current locale
WBEM_FLAG_CONNECT_USE_MAX_WAIT, // Return if connexion is unsuccessful after 2 minutes
0, // Name of the domain of the user to authenticate
ctx, // Optional context
&service_); // Fill this pointer
The create_registry_redirection_context_ method uses CoCreateInstance to instantiate my context, and I use the following lines to set the architecture:
CComVariant value_arch(64, VT_I4);
ctx->SetValue(L"__ProviderArchitecture", 0, &value_arch);
Now the problem is, the ConnectServer method returns an error (0x80041008 - WMI Invalid Parameter). If I comment out the ctx->SetValue(L"__ProviderArchitecture", 0, &value_arch); line, everything works properly, but of course, I end up querying the 32 bit registry provider.
I've also tried not setting any context during the ConnectServer call, but only during the ExecMethod call (as specified in the MSDN article), but although I don't get any error, I'm still querying the 32 bit provider, and not seeing my 64bit registry keys.
What am I doing wrong?
Thanks in advance for your time.
I know, it's a little bit late, but for archive (and because MS is unable to provide such a sample):
HRESULT hres;
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
m_nExitCode = TCP1;
return FALSE;
}
IWbemContext *pContext = NULL;
hres = CoCreateInstance(CLSID_WbemContext, 0, CLSCTX_INPROC_SERVER, IID_IWbemContext, (LPVOID *) &pContext);
if (FAILED(hres))
{
m_nExitCode = TCP1_2;
return FALSE;
}
VARIANT vArchitecture;
VariantInit(&vArchitecture);
V_VT(&vArchitecture) = VT_I4;
V_INT(&vArchitecture) = 64;
hres = pContext->SetValue(_bstr_t(L"__ProviderArchitecture"), 0, &vArchitecture);
VariantClear(&vArchitecture);
//VARIANT vRequiredArchicture;
//VariantInit(&vRequiredArchicture);
//V_VT(&vRequiredArchicture) = VT_BOOL;
//V_BOOL(&vRequiredArchicture) = VARIANT_TRUE;
//hres = pContext->SetValue(_bstr_t(L"__RequiredArchitecture"), 0, &vRequiredArchicture);
//VariantClear(&vRequiredArchicture);
IWbemServices *pSvc = NULL;
hres = pLoc->ConnectServer(
_bstr_t(L"root\\Microsoft\\SqlServer\\ComputerManagement10"), // Object path of WMI namespace
NULL, // User name. NULL = current user
NULL, // User password. NULL = current
0, // Locale. NULL indicates current
NULL, // Security flags.
0, // Authority (for example, Kerberos)
pContext, // Context object
&pSvc // pointer to IWbemServices proxy
);
The block with RequiredArchitecture is untested and seems to be unnecessary.
PS: Error-handling needs to be improved!
have you looked at
http://msdn.microsoft.com/en-us/library/windows/desktop/aa393067(v=vs.85).aspx
and tried setting "__RequiredArchitecture" = TRUE as well?
Also have to tried to get it to work in the way that the same code shows ( ie 64 bit to 32 bit) first?
I would like to know when a interface has been disabled.
If I go into the windows manager and disable one of the 2 enabled connections, GetIfTable() only returns status about 1 interface, it no longer sees the disconnected one.
(Returns 1 table)
How can I get something to return that the disabled interface still exists but is currently disabled?
Thanks.
http://msdn.microsoft.com/en-us/library/aa365943%28VS.85%29.aspx
I think you would just need to read the registry.
For example, this is a snippet found on the web of what things should look like:
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\{1E6AF554-25FF-40FC-9CEE-EB899472C5A3}\Connection]
"PnpInstanceID"="PCI\\VEN_14E4&DEV_1696&SUBSYS_12BC103C&REV_03\\4&3A321F38&0&10F0"
"MediaSubType"=dword:00000001
"Name"="Lan Name"
"ShowIcon"=dword:00000000
"IpCheckingEnabled"=dword:00000001
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Network\{4D36E972-E325-11CE-BFC1-08002BE10318}\{1E6AF554-25FF-40FC-9CEE-EB899472C5A3}\Connection]
"PnpInstanceID"="PCI\\VEN_14E4&DEV_1696&SUBSYS_12BC103C&REV_03\\4&3A321F38&0&10F0"
"MediaSubType"=dword:00000001
"Name"="Lan Name"
"ShowIcon"=dword:00000000
"IpCheckingEnabled"=dword:00000001
How about using the interfaces from netcon.h as illustrated in this example? The code in that example enables and disables the interface programmatically, but I've made some modifications so that you could query the status instead:
#include <netcon.h>
// wszName is the name of the connection as appears in Network Connections folder
// set bEnable to true to enable and to false to disable
bool GetConnectionStatus(LPCWSTR wszName, bool *status)
{
bool result = false;
if (!status)
return false;
typedef void (__stdcall * LPNcFreeNetconProperties)(NETCON_PROPERTIES* pProps);
HMODULE hmod = LoadLibrary("netshell.dll");
if (!hmod)
return false;
LPNcFreeNetconProperties NcFreeNetconProperties =
(LPNcFreeNetconProperties)GetProcAddress(hmod, "NcFreeNetconProperties");
if (!NcFreeNetconProperties )
return false;
INetConnectionManager * pMan = 0;
HRESULT hres = CoCreateInstance(CLSID_ConnectionManager,
0,
CLSCTX_ALL,
__uuidof(INetConnectionManager),
(void**)&pMan);
if (SUCCEEDED(hres))
{
IEnumNetConnection * pEnum = 0;
hres = pMan->EnumConnections(NCME_DEFAULT, &pEnum);
if (SUCCEEDED(hres))
{
INetConnection * pCon = 0;
ULONG count;
while (pEnum->Next(1, &pCon, &count) == S_OK && !done)
{
NETCON_PROPERTIES * pProps = 0;
hres = pCon->GetProperties(&pProps);
if (SUCCEEDED(hres))
{
if (wcscmp(pProps->pszwName,wszName) == 0)
{
*status = pProps->Status == NCS_CONNECTED;
}
NcFreeNetconProperties(pProps);
}
pCon->Release();
}
pEnum->Release();
}
pMan->Release();
}
FreeLibrary(hmod);
return result;
}
Another option is use the Win32_NetworkAdapter WMI Class , check the NetConnectionStatus and NetEnabled properties.
The IP_ADAPTER_ADDRESSES structure hold an OperStatus member.
See MSDN documentation
I think it can be used to detect disabled NICs. I didn't try.
Here is a test code:
ULONG nFlags= 0;
if (WINVER>=0x0600) // flag supported in Vista and later
nFlags= 0x0100; // GAA_FLAG_INCLUDE_ALL_INTERFACES
// during system initialization, GetAdaptersAddresses may return ERROR_BUFFER_OVERFLOW and supply nLen,
// but in a subsequent call it may return ERROR_BUFFER_OVERFLOW and supply greater nLen !
ULONG nLen= sizeof (IP_ADAPTER_ADDRESSES);
BYTE* pBuf= NULL;
DWORD nErr= 0 ;
do
{
delete[] pBuf;
pBuf= new BYTE[nLen];
nErr= ::GetAdaptersAddresses(AF_INET, nFlags, NULL, (IP_ADAPTER_ADDRESSES*&)pBuf, &nLen);
}
while (ERROR_BUFFER_OVERFLOW == nErr);
if (NO_ERROR != nErr)
{
delete[] pBuf;
TCHAR czErr[300]= _T("GetAdaptersAddresses failed. ");
REPORT(REP_ERROR, _T("GetAdapterInfo"), GetSysErrStr(nErr, czErr, 300));
return false;
}
const IP_ADAPTER_ADDRESSES* pAdaptersAddresses= (IP_ADAPTER_ADDRESSES*&)pBuf;
while (pAdaptersAddresses) // for each adapter
{
TCHAR czAdapterName [500]; str_cpy(czAdapterName , 500, pAdaptersAddresses->AdapterName );
TCHAR czDesc [500]; str_cpy(czDesc , 500, pAdaptersAddresses->Description );
TCHAR czFriendlyName[500]; str_cpy(czFriendlyName, 500, pAdaptersAddresses->FriendlyName);
const IF_OPER_STATUS& Stat= pAdaptersAddresses->OperStatus; // 1:up, 2:down...
...
pAdaptersAddresses= pAdaptersAddresses->Next;
}
According to this CodeGuru forum message, you can query WMI for this information (A C# code is provided there).
To query WMI using C++, see these two links:
MSDN
CodeProject
command-line:
wmic NIC where(ConfigManagerErrorCode=22)get Description,Index,NetConnectionID,PNPDeviceID
Output:
Description Index NetConnectionID PNPDeviceID
Broadcom 802.11g Network Adapter 8 WiFi PCI\VEN_14E4&DEV_4320&SUBSYS_041814E4&REV_03\4&31B6CD7&0&00F0
1394 Net Adapter 13 1394 V1394\NIC1394\1B9E0F31E8C00
TAP-Win32 Adapter V9 14 Steganos Internet Anonym 2012 VPN Adapter ROOT\NET\0000
VirtualBox Host-Only Ethernet Adapter 24 VirtualBox Host-Only Network ROOT\NET\0001
I am developing an application for Windows Vista and 7 in Visual Studio C++, in which I have to assign static IP address to a network card and establish a connection. For this, I am entering the Ip values in registry along with setting the Enable DHCP value to 0. Then I need to disable and then enable the network card for these values to take effect. For this, I am using "INetConnectionManager" in the following code:
CoInitialize(0);
typedef void (__stdcall * PNcFreeNetconProperties)(NETCON_PROPERTIES* pProps);
HMODULE hmod = LoadLibrary(L"netshell.dll");
if (!hmod)
return false;
LPNcFreeNetconProperties NcFreeNetconProperties =
(LPNcFreeNetconProperties)GetProcAddress(hmod, "NcFreeNetconProperties");
if (!NcFreeNetconProperties )
return false;
INetConnectionManager * pMan = 0;
HRESULT hres = CoCreateInstance(CLSID_ConnectionManager,
0,
CLSCTX_ALL,
__uuidof(INetConnectionManager),
(void**)&pMan);
if (SUCCEEDED(hres))
{
IEnumNetConnection * pEnum = 0;
hres = pMan->EnumConnections(NCME_DEFAULT, &pEnum);
if (SUCCEEDED(hres))
{
INetConnection * pCon = 0;
ULONG count;
bool done = false;
while (pEnum->Next(1, &pCon, &count) == S_OK && !done)
{
NETCON_PROPERTIES * pProps = 0;
hres = pCon->GetProperties(&pProps);
if (SUCCEEDED(hres))
{
if (wcscmp(pProps-pszwDeviceName, AdapterName) == 0)
{
if (bEnable)
result = (pCon->Connect() == S_OK);
else
result = (pCon->Disconnect() == S_OK);
done = true;
}
NcFreeNetconProperties(pProps);
}
pCon->Release();
}
pEnum->Release();
}
pMan->Release();
}
FreeLibrary(hmod);
CoUninitialize();
It's disabling and enabling the network card very well, BUT the autoconfiguration IPv4 values are getting set instead of the static values in the registry. This strangely works properly for DHCP connection but not for static connection.
NOTE: I even tried SetIfEntry for it, but it fails to disable or enable Network Card.
Please suggest where I am doing wrong or anything I am missing.
You can use AddIPAddress:
http://msdn.microsoft.com/en-us/library/aa365801%28v=vs.85%29.aspx
Does INetConnectionManager supported on Windows VISTA and Win7? I have implemented the same code what you have written here but I get access denied for pCon->Connect when application runs on non admin login. Therefore, it looks like that we need to elevate the com object using COM Moniker.
Regards
IP_Telephony