ATL DCOM Object creation fails in VS 2010 Build - c++

We have a DCOM server which works fine in Win 7 64 Bit for the VS 2008 build. In the case of VS 2010 build, the client side object creation fails with "Server Creation Failed" error message. The class definition is given below.
When debugged, we have seen that a message with message id 1024, has received in the message loop, but DispatchMessage does not route the message, to create CICEConnect object. In the VS 2008 build, DispatchMessage routes the call to create CICEConnect object. I believe this creates the issue
The server application was stated when the client tries to create the object. The DCOM server is running in the local machine
How can I debug the issue further?
void RunMessageLoop() throw()
{
MSG msg;
while (GetMessage(&msg, 0, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
class ATL_NO_VTABLE CICEConnect :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CICEConnect, &CLSID_ICEConnect>,
public IDispatchImpl<IICEConnect, &IID_IICEConnect, &LIBID_ICEConnectServerLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
CICEConnect()
{
}
DECLARE_CLASSFACTORY_SINGLETON(CICEConnect)
DECLARE_REGISTRY_RESOURCEID(IDR_ICECONNECT)
BEGIN_COM_MAP(CICEConnect)
COM_INTERFACE_ENTRY(IICEConnect)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
};
If I Skip p->Release(); in the following RegisterClassObject, the COM Object creation succeeds.
struct _ATL_OBJMAP_ENTRY30
{
HRESULT WINAPI RegisterClassObject(
_In_ DWORD dwClsContext,
_In_ DWORD dwFlags)
{
IUnknown* p = NULL;
if (pfnGetClassObject == NULL)
return S_OK;
HRESULT hRes = pfnGetClassObject(pfnCreateInstance, __uuidof(IUnknown), (LPVOID*) &p);
if (SUCCEEDED(hRes))
hRes = CoRegisterClassObject(*pclsid, p, dwClsContext, dwFlags, &dwRegister);
if (p != NULL)
p->Release();
return hRes;
}
// Added in ATL 3.0
void (WINAPI *pfnObjectMain)(_In_ bool bStarting);
};
The Code used to create the COM object is given below
int _tmain(int argc, _TCHAR* argv[])
{
CoInitializeEx(NULL,COINIT_MULTITHREADED);
COSERVERINFO server;
memset(&server,0,sizeof(COSERVERINFO));
COAUTHINFO athn;
ZeroMemory(&athn, sizeof(COAUTHINFO));
athn.dwAuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
athn.dwAuthnSvc = RPC_C_AUTHN_WINNT;
athn.dwAuthzSvc = RPC_C_AUTHZ_NONE;
athn.dwCapabilities = EOAC_NONE;
athn.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
athn.pAuthIdentityData = NULL;
athn.pwszServerPrincName = NULL;
server.pAuthInfo = &athn;
server.pwszName = L"\\\\localhost";
server.dwReserved1 = 0;
server.dwReserved2 = 0;
MULTI_QI mqi = {&IID_IICEConnect, NULL, S_OK};
// Access the PMC on the given machine
HRESULT hRes = CoCreateInstanceEx(CLSID_ICEConnect,NULL,
CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,&server,1,&mqi);
return 0;
}

Don't you think that DispatchMessage is a system call and its implementation is beyond the control of VS2008 & VS2010? maybe you do not handle correct message to create the control! for example a change in the SDK may generate your error. message with ID 1024 is WM_USER and system do not handle it normally. handling this message is up to the user code

Related

Watch for new explorer windows in Win32 API

I'm currently making a program to add tabs to the Windows file explorer using the win32 API since I'm not satisfied by any of the programs that currently do that (Clover, Groupy to name a few).
To do that I obviously need to get all explorer windows that are currently opened and to make the program watch for new windows being created.
The way I currently do it is by calling EnumWindows in my messages loop, and attaching to my program's main window any explorer window that isn't attached yet.
while(GetMessage(&uMsg, NULL, 0, 0) > 0)
{
TranslateMessage(&uMsg);
DispatchMessage(&uMsg);
EnumWindows((WNDENUMPROC)findExplorerWindows, (LPARAM)mainWindow);
}
This is obviously not optimal (new windows only get attached to my program when a message is sent to my program, and overall it slows everything down quite a bit especially when there's already a lot of opened windows) and I'd like to know if there is a way to watch the opened windows list to fire an event whenever a new window is created or anything of that sort.
Here is some sample Console code (uses COM) that uses the IShellWindows interface.
First it dumps the current explorer windows ("views"), then it hooks events raised by the companion interface DShellWindowsEvents
#include <atlbase.h>
#include <atlcom.h>
#include <shobjidl_core.h>
#include <shlobj_core.h>
#include <exdispid.h>
// a COM class that handles DShellWindowsEvents
class WindowsEvents : public IDispatch
{
// poor man's COM object... we don't care, we're basically a static thing here
STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject)
{
if (IsEqualIID(riid, IID_IUnknown))
{
*ppvObject = static_cast<IUnknown*>(this);
return S_OK;
}
if (IsEqualIID(riid, IID_IDispatch))
{
*ppvObject = static_cast<IDispatch*>(this);
return S_OK;
}
*ppvObject = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() { return 1; }
STDMETHODIMP_(ULONG) Release() { return 1; }
// this is what's called by the Shell (BTW, on the same UI thread)
// there are only two events "WindowRegistered" (opened) and "WindowRevoked" (closed)
STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr)
{
// first parameter is window's registration cookie
int cookie = V_I4(&pDispParams->rgvarg[0]);
if (dispIdMember == DISPID_WINDOWREGISTERED) // needs exdispid.h
{
wprintf(L"Window registered, cookie:%u\n", cookie);
}
else if (dispIdMember == DISPID_WINDOWREVOKED)
{
wprintf(L"Window revoked, cookie:%u\n", cookie);
}
// currently the cookie is not super useful, it's supposed to be usable by FindWindowSW
CComVariant empty;
long hwnd;
CComPtr<IDispatch> window;
HRESULT hr = Windows->FindWindowSW(&pDispParams->rgvarg[0], &empty, 0, &hwnd, SWFO_COOKIEPASSED, &window);
// always returns S_FALSE... it does not seem to work
// so, you'll have to ask for all windows again...
return S_OK;
}
// the rest is left not implemented
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo) { return E_NOTIMPL; }
STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; }
STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { return E_NOTIMPL; }
public:
CComPtr<IShellWindows> Windows;
};
int main()
{
CoInitialize(NULL);
{
CComPtr<IShellWindows> windows;
if (SUCCEEDED(windows.CoCreateInstance(CLSID_ShellWindows)))
{
// dump current windows
long count = 0;
windows->get_Count(&count);
for (long i = 0; i < count; i++)
{
CComPtr<IDispatch> window;
if (SUCCEEDED(windows->Item(CComVariant(i), &window)))
{
// get the window handle
CComPtr<IWebBrowserApp> app;
if (SUCCEEDED(window->QueryInterface(&app)))
{
HWND hwnd = NULL;
app->get_HWND((SHANDLE_PTR*)&hwnd);
wprintf(L"HWND[%i]:%p\n", i, hwnd);
}
}
}
// now wait for windows to open
// get the DShellWindowsEvents dispinterface for events
CComPtr<IConnectionPointContainer> cpc;
if (SUCCEEDED(windows.QueryInterface(&cpc)))
{
// https://learn.microsoft.com/en-us/windows/win32/shell/dshellwindowsevents
CComPtr<IConnectionPoint> cp;
if (SUCCEEDED(cpc->FindConnectionPoint(DIID_DShellWindowsEvents, &cp)))
{
WindowsEvents events;
events.Windows = windows;
DWORD cookie = 0;
// hook events
if (SUCCEEDED(cp->Advise(&events, &cookie)))
{
// pump COM messages to make sure events arrive
do
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} while (TRUE);
// normally we should get here if someone sends a PostQuitMessage(0) to the current thread
// but this is a console sample...
// unhook events
cp->Unadvise(cookie);
}
}
}
}
}
CoUninitialize();
return 0;
}

Moving UWP application window by native c++ code

I am trying to control the size and position of a UWP APP (Windows Mixed Reality Portal) via a sepate app. In my case, I am using a console app for simplicity. A Command script would also work for what I want to achieve.
I have tried Windows api such as MoveWindow,SetWindowPos but they do not work as expected and GetWindowRect returns a 0,0,0,0 rect. I can get the window handle but not change the size/position.
My reason for doing this is to send virtual mouse keys to the app in order to initialise the front position of the Windows Mixed Reality system. Sending the virtual keys are fine but I am having trouble automating shifting of the position of the uwp app itself.
#include <iostream>
#include <ShObjIdl.h>
#include <atlbase.h>
#include <tlhelp32.h>
BOOL CALLBACK EnumWindowsProcBack(HWND windowHandle, LPARAM lParam) {
DWORD searchedProcessId = (DWORD)lParam; // This is the process ID we search for (passed from BringToForeground as lParam)
DWORD windowProcessId = 0;
GetWindowThreadProcessId(windowHandle, &windowProcessId); // Get process ID of the window we just found
if (searchedProcessId == windowProcessId) { // Is it the process we care about?
//std::cout << "moving window..\n";
//bool s=MoveWindow(windowHandle, 0, 0, 1920, 1080, true);
SetWindowPos(
windowHandle,
HWND_TOP,
0,
0,
600,
600,
SWP_NOSIZE
);
return FALSE; // Stop enumerating windows
}
return TRUE; // Continue enumerating
}
void MoveWindowToFixedLocation(DWORD processId) {
EnumWindows(&EnumWindowsProcBack, (LPARAM)processId);
}
HRESULT LaunchApp(LPCWSTR AUMID, DWORD &pid)
{
HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
if (FAILED(hr))
{
wprintf(L"LaunchApp %s: Failed to init COM. hr = 0x%08lx \n", AUMID, hr);
}
{
CComPtr<IApplicationActivationManager> AppActivationMgr = nullptr;
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(CLSID_ApplicationActivationManager, nullptr,
CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&AppActivationMgr));
if (FAILED(hr))
{
wprintf(L"LaunchApp %s: Failed to create Application Activation Manager.hr = 0x%08lx \n", AUMID, hr);
}
}
if (SUCCEEDED(hr))
{
//DWORD pid = 0;
hr = AppActivationMgr->ActivateApplication(AUMID, nullptr, AO_NONE,
&pid);
if (FAILED(hr))
{
wprintf(L"LaunchApp %s: Failed to Activate App. hr = 0x%08lx \n", AUMID, hr);
}
}
}
CoUninitialize();
return hr;
}
int main() {
DWORD pid = 0;
LaunchApp(L"Microsoft.Windows.HolographicFirstRun_cw5n1h2txyewy!App", pid);
//cout << pid;
MoveWindowToFixedLocation(pid);
}
It's impossible. UWP app runs in own closed environment. A desktop application cannot sent it any signal.

How can DOM elements be retrieved from a C++ program?

I would need to get all elements of webpage displayed in IE from a c++ program.
I tried to see with spy++ but there's only the IEFrame.
So I'm thinking about using the developement tool (F12 in IE), I heard there's a way to automat it, a good idea ?
Thanks
You can get an IHtmlDocument2 reference from an IE's window handle, even out-of-process. This is documented here https://support.microsoft.com/en-us/help/249232/how-to-get-ihtmldocument2-from-a-hwnd, but not really supported by Microsoft.
However it looks like it still works today, I've tested it with a Windows 10 box, and IE is now a frozen app, so not going to change any time soon.
Once you have the proper HWND for Internet Explorer, than you can get the DOM with a code like this. Make sure IE and your program run at the same security level
The DOM is the same as when you're coding IE inprocess (host, activex, etc.), however for security reasons, some things may not work :
void DoSomeDomOperations(HWND hwnd)
{
UINT msg = RegisterWindowMessage(L"WM_HTML_GETOBJECT");
LRESULT result = 0;
SendMessageTimeout(hwnd, msg, NULL, NULL, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&result);
if (!result)
return;
// get main document object
IHTMLDocument2 *doc = NULL;
ObjectFromLresult(result, IID_IHTMLDocument2, NULL, (void**)&doc);
if (!doc)
return;
// get document's url
BSTR url = NULL;
doc->get_URL(&url);
wprintf(L"url:%s\n", url);
SysFreeString(url);
// get body element
IHTMLElement *element = NULL;
doc->get_body(&element);
if (element)
{
BSTR text = NULL;
element->get_innerText(&text);
wprintf(L"text:%s\n", text);
SysFreeString(text);
element->Release();
}
// etc.
// etc.
doc->Release();
}
And here is a full sample console app that scans all current IE processes running:
BOOL CALLBACK GetIEServerWindowProc(HWND hwnd, LPARAM lParam)
{
// enumerate all child windows to find IE's COM server
wchar_t className[100];
GetClassName(hwnd, className, 100);
if (!wcscmp(className, L"Internet Explorer_Server"))
{
*((HWND*)lParam) = hwnd;
return FALSE;
}
return TRUE;
}
HWND GetIEServerWindow(HWND hwnd)
{
HWND serverHwnd = NULL;
EnumChildWindows(hwnd, GetIEServerWindowProc, (LPARAM)&serverHwnd);
return serverHwnd;
}
struct IEServer
{
DWORD processId;
HWND serverHwnd;
};
BOOL CALLBACK GetIEProcessServerWindowProc(HWND hwnd, LPARAM lParam)
{
DWORD processId = ((IEServer*)lParam)->processId;
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
if (pid == processId)
{
HWND serverHwnd = GetIEServerWindow(hwnd);
if (serverHwnd)
{
((IEServer*)lParam)->serverHwnd = serverHwnd;
return FALSE;
}
}
return TRUE;
}
HWND GetIEProcessServerWindow(DWORD processId)
{
IEServer ie = { processId, NULL };
EnumWindows(GetIEProcessServerWindowProc, (LPARAM)&ie);
return ie.serverHwnd;
}
void EnumerateIEProcesses()
{
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (h == INVALID_HANDLE_VALUE)
return;
PROCESSENTRY32 process;
process.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(h, &process))
{
do
{
// we only consider IE processes
if (!wcscmp(process.szExeFile, L"iexplore.exe"))
{
HWND serverHwnd = GetIEProcessServerWindow(process.th32ProcessID);
if (serverHwnd)
{
DoSomeDomOperations(serverHwnd);
}
}
} while (Process32Next(h, &process));
}
CloseHandle(h);
}
int main()
{
CoInitialize(NULL);
EnumerateIEProcesses();
CoUninitialize();
return 0;
}

Problems accessing a COM interface in C++

What I want to do is access a COM interface and then call the "Open" method of that interface.
I have a sample code in Visual Basic which works fine, but I need to write it in C++ and I can't seem to get it to work.
First of all, this is the working VB code:
Dim CANapeApplication As CANAPELib.Application
CANapeApplication = CreateObject("CANape.Application")
Call CANapeApplication.Open("C:\Users\Public\Documents\Vector\CANape\12\Project", 0)
CANape.Application is the ProgID which selects the interface I need.
After reading some docs at msdn.microsoft.com and this question, I wrote this code:
void ErrorDescription(HRESULT hr); //Function to output a readable hr error
int InitCOM();
int OpenCANape();
// Declarations of variables used.
HRESULT hresult;
void **canApeAppPtr;
IDispatch *pdisp;
CLSID ClassID;
DISPID FAR dispid;
UINT nArgErr;
OLECHAR FAR* canApeWorkingDirectory = L"C:\\Users\\Public\\Documents\\Vector\\CANape\\12\\Project";
int main(){
// Instantiate CANape COM interface
if (InitCOM() != 0) {
std::cout << "init error";
return 1;
}
// Open CANape
if (OpenCANape() != 0) {
std::cout << "Failed to open CANape Project" << std::endl;
return 1;
}
CoUninitialize();
return 0;
}
void ErrorDescription(HRESULT hr) {
if(FACILITY_WINDOWS == HRESULT_FACILITY(hr))
hr = HRESULT_CODE(hr);
TCHAR* szErrMsg;
if(FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&szErrMsg, 0, NULL) != 0)
{
_tprintf(TEXT("%s"), szErrMsg);
LocalFree(szErrMsg);
} else
_tprintf( TEXT("[Could not find a description for error # %#x.]\n"), hr);
}
int InitCOM() {
// Initialize OLE DLLs.
hresult = OleInitialize(NULL);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
// Get CLSID from ProgID
//hresult = CLSIDFromProgID(OLESTR("CANape.Application"), &ClassID);
hresult = CLSIDFromProgID(OLESTR("CanapeCom.CanapeCom"), &ClassID);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
// OLE function CoCreateInstance starts application using GUID/CLSID
hresult = CoCreateInstance(ClassID, NULL, CLSCTX_LOCAL_SERVER,
IID_IDispatch, (void **)&pdisp);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
// Call QueryInterface to see if object supports IDispatch
hresult = pdisp->QueryInterface(IID_IDispatch, (void **)&pdisp);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
std::cout << "success" << std::endl;
return 0;
}
int OpenCANape() {
//Method name
OLECHAR *szMember = L"Open";
// Retrieve the dispatch identifier for the Open method
// Use defaults where possible
DISPID idFileExists;
hresult = pdisp->GetIDsOfNames(
IID_NULL,
&szMember,
1,
LOCALE_SYSTEM_DEFAULT,
&idFileExists);
if (!SUCCEEDED(hresult)) {
std::cout << "GetIDsOfNames: ";
ErrorDescription(hresult);
return 1;
}
unsigned int puArgErr = 0;
VARIANT VarResult;
VariantInit(&VarResult);
DISPPARAMS pParams;
memset(&pParams, 0, sizeof(DISPPARAMS));
pParams.cArgs = 2;
VARIANT Arguments[2];
VariantInit(&Arguments[0]);
pParams.rgvarg = Arguments;
pParams.cNamedArgs = 0;
pParams.rgvarg[0].vt = VT_BSTR;
pParams.rgvarg[0].bstrVal = SysAllocString(canApeWorkingDirectory);
pParams.rgvarg[1].vt = VT_INT;
pParams.rgvarg[1].intVal = 0; // debug mode
// Invoke the method. Use defaults where possible.
hresult = pdisp->Invoke(
dispid,
IID_NULL,
LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD,
&pParams,
&VarResult,
NULL,
&puArgErr
);
SysFreeString(pParams.rgvarg[0].bstrVal);
if (!SUCCEEDED(hresult)) {
ErrorDescription(hresult);
return 1;
}
return 0;
}
There are several problems with this.
Using the ClassID received from CLSIDFromProgID as the first parameter of CoCreateInstance does not work, it returns the error: class not registered
If i use the ProgID CanapeCom.CanapeCom (I found it by looking in the Registry), CoCreateInstance works. However, when I use pdisp->GetIDsOfNames I get the error message: Unkown name. Which I think means that the method was not found. That seems logical because I've used a different ProgID, but I just can't figure out how to get to the interface I'm looking for.
I have also tried to use the resulting CLSID from CLSIDFromProgID(OLESTR("CANape.Application"), &ClassID); as the 4th argument of CoCreateInstance but that resulted in a "No such interface supported" error.
Do I need the dll file of the software? In the VB example the dll file is used to get the interface and then create a new object using the ProgID. I'm not sure if I need to do the same in C++ or how this should work.
I'm really stuck here and hope that someone can help me.
Thanks for your comments.
I've fixed the problem, although the solution is kind of embarrassing...
In my defense, I'm still a student and new to this kind of stuff.
I've used the Process Monitor to check what happens when I execute the VB script.
I saw that the CLSID used there is the ID returned by CLSIDFromProgID(OLESTR("CANape.Application"), &ClassID);, which meant that this had to be the right one and the problem had to be somewhere else. I've looked again at the CoCreateInstance and then took a look at the other parameters. Turns out that the context CLSCTX_LOCAL_SERVER was wrong, it has to be CLSCTX_INPROC_SERVER. I don't know why I've set it to local_server in the first place or why I've never questioned it. I wrote that part of the code a few days ago and then focused too much on the CLSID and IID rather than on the other parameters.
I've also taken the first comment from Alex into account and created a tlb file.
This is a simplified version of the code that works:
#import "CANape.tlb"
int _tmain(int argc, _TCHAR* argv[])
{
_bstr_t path = "C:\\Users\\Public\\Documents\\Vector\\CANape\\12\\Project";
CLSID idbpnt;
CoInitialize(NULL);
HRESULT hr = CLSIDFromProgID (L"CANape.Application", &idbpnt);
CANAPELib::IApplication *app;
hr = CoCreateInstance(idbpnt,NULL,CLSCTX_INPROC_SERVER,__uuidof(CANAPELib::IApplication),(LPVOID*)&app );
app->Open(path,0);
CoUninitialize();
return 0;
}

How do I detect a disabled Network Interface Connection from a Windows application?

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