How to use the GetLastError function in a Win32 Console Application? - winapi

I am trying to open a Registry Key using the RegOpenKeyEx function from the Windows API, and have this code:
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int wmain(int argc, wchar_t*argv [])
{
HKEY hKey = HKEY_CURRENT_USER;
LPCTSTR lpSubKey = L"Demo";
DWORD ulOptions = 0;
REGSAM samDesired = KEY_ALL_ACCESS;
HKEY phkResult;
long R = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &phkResult);
if (R == ERROR_SUCCESS)
{
cout << "The registry key has been opened." << endl;
}
else //How can I retrieve the standard error message using GetLastError() here?
{
}
}
How do I use the GetLastError() function to show a generic error message instead of valid any Error Message ID into the else?
Edit: I know there is a FormatMessage function but have the same problem, I don't know how to use it on my code.

The Registry functions do not use GetLastError(). They return the actual error codes directly:
long R = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &phkResult);
if (R == ERROR_SUCCESS)
{
cout << "The registry key has been created." << endl;
}
else
{
cout << "The registry key has not been created. Error: " << R << endl;
}
If you want to display a system error message, use FormatMessage() for that:
long R = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &phkResult);
if (R == ERROR_SUCCESS)
{
cout << "The registry key has been created." << endl;
}
else
{
char *pMsg = NULL;
FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL,
R,
0,
(LPSTR)&pMsg,
0,
NULL
);
cout << "The registry key has not been created. Error: (" << R << ") " << pMsg << endl;
LocalFree(pMsg);
}

Try this
HKEY hKey = HKEY_CURRENT_USER;
LPCTSTR lpSubKey = L"Demo";
DWORD ulOptions = 0;
REGSAM samDesired = KEY_ALL_ACCESS;
HKEY phkResult;
char *ErrorMsg= NULL;
long R = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &phkResult);
if (R == ERROR_SUCCESS)
{
printf("The registry key has been opened.");
}
else //How can I retrieve the standard error message using GetLastError() here?
{
FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL,
R,
0,
(LPSTR)&ErrorMsg,
0,
NULL
);
printf("Error while creating Reg key.");
}

Related

Exact way to get permissions of a file in windows using C++ and api

My project is like i need to modify the file permissions from a web application. I'm using java for backend and emberjs for client side. To get the file permissions I'm using C++ native code with windows api with JNI. Here is my problem,
I need to get the permissions of the files in a directory in windows using api. I'm new to windows api so I've googled and got the below code and modified it to my needs. Now the problem is when i run this, it gives me the results when the file has "Full Control" as permission otherwise the permissions are not showing. Please help me with this. What need to be modified in here or if there are any other possible solutions, please suggest me that too. Thanks in advance.
Here is my code,
#include <Windows.h>
#include <vector>
#include <map>
#include <iostream>
#include <aclapi.h>
#include <windows.h>
#include <string>
#include <memory>
#include <tchar.h>
using namespace std;
bool CanAccessFolder(LPCTSTR folderName, DWORD genericAccessRights,DWORD& grantedRights)
{
bool bRet = false;
DWORD length = 0;
if (!::GetFileSecurity(folderName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION, NULL, NULL, &length) &&
ERROR_INSUFFICIENT_BUFFER == ::GetLastError()) {
PSECURITY_DESCRIPTOR security = static_cast< PSECURITY_DESCRIPTOR >(::malloc(length));
if (security && ::GetFileSecurity(folderName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION, security, length, &length)) {
HANDLE hToken = NULL;
if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_IMPERSONATE | TOKEN_QUERY |
TOKEN_DUPLICATE | STANDARD_RIGHTS_READ, &hToken)) {
HANDLE hImpersonatedToken = NULL;
if (::DuplicateToken(hToken, SecurityImpersonation, &hImpersonatedToken)) {
GENERIC_MAPPING mapping = { 0xFFFFFFFF };
PRIVILEGE_SET privileges = { 0 };
DWORD grantedAccess = 0, privilegesLength = sizeof(privileges);
BOOL result = FALSE;
mapping.GenericRead = FILE_GENERIC_READ;
mapping.GenericWrite = FILE_GENERIC_WRITE;
mapping.GenericExecute = FILE_GENERIC_EXECUTE;
mapping.GenericAll = FILE_ALL_ACCESS;
::MapGenericMask(&genericAccessRights, &mapping);
if (::AccessCheck(security, hImpersonatedToken, genericAccessRights,
&mapping, &privileges, &privilegesLength, &grantedAccess, &result))
{
bRet = (result == TRUE);
grantedRights = grantedAccess;
}
::CloseHandle(hImpersonatedToken);
}
::CloseHandle(hToken);
}
::free(security);
}
}
return bRet;
}
vector<string> printMasks(DWORD Mask)
{
// This evaluation of the ACCESS_MASK is an example.
// Applications should evaluate the ACCESS_MASK as necessary.
vector<string> access;
std::wcout << "Effective Allowed Access Mask : "<< Mask << std::hex << std::endl;
if (((Mask & GENERIC_ALL) == GENERIC_ALL)
|| ((Mask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS))
{
// wprintf_s(L"Full Control\n");
access.push_back("Full Control");
// return access;
}
if (((Mask & GENERIC_READ) == GENERIC_READ)
|| ((Mask & FILE_GENERIC_READ) == FILE_GENERIC_READ))
// wprintf_s(L"Read\n");
access.push_back("Read");
if (((Mask & GENERIC_WRITE) == GENERIC_WRITE)
|| ((Mask & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE))
// wprintf_s(L"Write\n");
access.push_back("Write");
if (((Mask & GENERIC_EXECUTE) == GENERIC_EXECUTE)
|| ((Mask & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE))
// wprintf_s(L"Execute\n");
access.push_back("Execute");
return access;
}
std::map<std::string, std::vector<std::string>>
list_directory(const std::string &directory)
{
DWORD access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | FILE_ALL_ACCESS;
std::map<std::string, std::vector<std::string>> files;
WIN32_FIND_DATAA findData;
HANDLE hFind = INVALID_HANDLE_VALUE;
std::string full_path = directory + "\\*";
hFind = FindFirstFileA(full_path.c_str(), &findData);
if (hFind == INVALID_HANDLE_VALUE)
throw std::runtime_error("Invalid handle value! Please check your path...");
while (FindNextFileA(hFind, &findData) != 0)
{
std::string file = findData.cFileName;
std::string filepath = directory + "/" + file;
DWORD grant = 0;
bool b = CanAccessFolder(filepath.c_str(), access_mask, grant);
files[file] = printMasks(grant);
}
FindClose(hFind);
return files;
}
int main() {
std::map<std::string, std::vector<std::string>> files;
files = list_directory("C:/Users/Vicky/Desktop/samples");
int i = 1;
map<string, vector<string>> :: iterator it=files.begin();
//iteration using traditional for loop
for(it=files.begin();it!=files.end();it++)
{
//accessing keys
cout << it->first << " : \t";
//accessing values (vectors)
for (auto &&i : it->second)
{
cout << i << "\t";
}
cout << endl;
}
}
Here are the results,
sample1.txt permissions
sample2.txt permissions
When you are performing the access check the line
DWORD access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | FILE_ALL_ACCESS;
Is specifying that you are checking that the if you have read/write/execute/full control access to each item you are checking.
As a result when you call AccessCheck on sample2.txt where you don't have all those permissions AccessCheck reports in its last parameter that you don't have access. In that case MSDN for the GrantedAccess parameter states
[out] GrantedAccess
A pointer to an access mask that receives the granted access rights. If >AccessStatus is set to FALSE, the function sets the access mask to zero. If
the function fails, it does not set the access mask.
That access mask of all zero's is what you are printing out for sample2.txt
If you want to see what you can actually do for each file change the line above to
DWORD access_mask = MAXIMUM_ALLOWED;
This causes the file to be checked for whatever access it can get hold of rather than full control which it does not have.

PRINTER_INFO_6 not available using WIn32 api

I have been trying to get printer status from a DNP rx1 printer, but the status of the printer does not change when I open the tray of the printer. Here is an example using py32win library to access the status and it always return status = 0 event when the tray is open.
device_name = win32print.GetDefaultPrinter()
handle = win32print.OpenPrinter(device_name)
# Get the default properties for the printer
properties = win32print.GetPrinter(handle, 2)
When I try win32print.GetPrinter(handle, 6) # 6 = print_info_6 I get the some NotImplementedException. So my guess is that the firmware of the printer have not implemented print_info_6. So I can't get the status from the printer
I have also tried using powershell with:
Get-Printer | Select Name, PrinterStatus
Also no change in status when I open the tray or if there is a paper jam.
Is there anything that I'm overlooking? Is there anything else I can try to get the status of the printer?
PRINTER_INFO_6 works for me in C++ on Windows 10 1903 with OneNote printer.
And when I pause the printer I get status 0x00000001 (PRINTER_STATUS_PAUSED).
The C++ code I used for testing.
#pragma comment(lib, "Winspool")
int main()
{
DWORD bufSize;
WCHAR* buf = NULL;
HANDLE hPrinter = NULL;
PRINTER_INFO_6 info = {};
DWORD needed;
BOOL result = FALSE;
DWORD err;
// Get required buffer size
result = GetDefaultPrinter(NULL, &bufSize);
if(!result)
{
err = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER != err)
{
std::cout << "GetDefaultPrinter failed with error: \n" << GetLastError();
return 0;
}
}
buf = (WCHAR*)calloc(bufSize, sizeof(WCHAR));
result = GetDefaultPrinter(buf, &bufSize);
if (!result)
{
std::cout << "GetDefaultPrinter failed with error: \n" << GetLastError();
return 0;
}
std::wcout << "Printer name: " << buf << "\n";
result = OpenPrinter(buf, &hPrinter, NULL);
if (!result)
{
std::cout << "OpenPrinter failed with error: \n" << GetLastError();
return 0;
}
result = GetPrinter(hPrinter, 6, (LPBYTE)&info, sizeof(PRINTER_INFO_6), &needed);
if (!result)
{
err = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER != err)
{
std::cout << "GetPrinter failed with error: \n" << GetLastError();
return 0;
}
}
BYTE* statBuf = (BYTE*)calloc(needed, sizeof(BYTE));
result = GetPrinter(hPrinter, 6, statBuf, needed, &needed);
if (!result)
{
std::cout << "GetPrinter failed with error: \n" << GetLastError();
return 0;
}
std::cout << "Printer status (low 32bit): " << *((DWORD*)statBuf) << "\n";
statBuf += sizeof(DWORD);
std::cout << "Printer status (high 32bit): " << *((DWORD*)statBuf) << "\n";
getchar();
}
Some issues I found in testing:
Pinter status defined as a DWORD (4 bytes) in PRINTER_INFO_6 structure but GetPrinter requries 8 bytes for it (needed == 8). So you will get ERROR_INSUFFICIENT_BUFFER error when you pass a PRINTER_INFO_6 structure as pPrinter parameter.
There is only PRINTER_INFO_6 defined but no _PRINTER_INFO_6W (Unicode) and _PRINTER_INFO_6A (ANSI) mentioned in the document.

NTFS ACL Inheritance is not correctly retrieved for some files

I noticed that my application is not retrieving correctly the NTFS ACL
inheritance of certain files. The files are located in subfolders of my
profiles. When using ICACLS.EXE it correctly outputs (I) for those files. But
when retrieving ACCESS_ALLOWED_ACE->Header.AceFlags using GetFileSecurity() this is always zero for those files. However, this is working for many other
files on my system. Also folders are not affected, but all files in my profile
directory and its subfolders.
Here is sample C++ code that allows to reproduce the problem:
#include <windows.h>
#include <iostream>
#include <comdef.h>
using namespace std;
int main(int argc, TCHAR** argv)
{
// Check Input Arguments
if (2 != argc)
{
// Output usage information in case of wrong arguments
cout << "Usage: ACLInfo.exe <path to file or directory>" << endl;
return 0;
}
// Get the path from supplied arguments
_bstr_t strPath = argv[1];
// Find out size of needed buffer for security descriptor with DACL
// DACL = Discretionary Access Control List
DWORD dwSizeNeeded = 0;
BOOL bSuccess = GetFileSecurityW(strPath,
DACL_SECURITY_INFORMATION,
NULL,
0,
&dwSizeNeeded);
if (0 == dwSizeNeeded)
{
return E_FAIL;
}
BYTE* pSecDescriptorBuf = new BYTE[dwSizeNeeded];
// Retrieve security descriptor with DACL information
bSuccess = GetFileSecurityW((BSTR)strPath,
DACL_SECURITY_INFORMATION,
pSecDescriptorBuf,
dwSizeNeeded,
&dwSizeNeeded);
// Check if we successfully retrieved security descriptor with DACL
information
if (!bSuccess)
{
DWORD dwError = GetLastError();
cout << "Failed to get file security information (" << dwError << ")\n";
return E_FAIL;
}
// Getting DACL from Security Descriptor
PACL pacl;
BOOL bDaclPresent, bDaclDefaulted;
bSuccess =
GetSecurityDescriptorDacl((SECURITY_DESCRIPTOR*)pSecDescriptorBuf,
&bDaclPresent, &pacl, &bDaclDefaulted);
// Check if we successfully retrieved DACL
if (!bSuccess)
{
DWORD dwError = GetLastError();
cout << "Failed to retrieve DACL from security descriptor (" << dwError
<< ")\n";
return E_FAIL;
}
// Check if DACL present in security descriptor
if (!bDaclPresent)
{
cout << "DACL was not found.\n";
return E_FAIL;
}
// DACL for specified file was retrieved successfully
// Now, we should fill in the linked list of ACEs
// Iterate through ACEs (Access Control Entries) of DACL
for (USHORT i = 0; i < pacl->AceCount; i++)
{
LPVOID pAce;
bSuccess = GetAce(pacl, i, &pAce);
if (!bSuccess)
{
DWORD dwError = GetLastError();
cout << "Failed to get ace " << i << " (" << dwError << ")\n";
continue;
}
BYTE AceFlags = ((ACCESS_ALLOWED_ACE*)pAce)->Header.AceFlags;
BOOL Inherited = (AceFlags && (INHERITED_ACE || OBJECT_INHERIT_ACE || CONTAINER_INHERIT_ACE)) != 0;
if (!Inherited)
cout << "not ";
cout << "Inherited";
}
return 0;
}
AceFlags is always 0 for the affected files. So what is the correct way to determine that these ACLs are inherited?

ATA command device IDENTIFY

I am trying to identify a device using ATA_PASS_THROUGH_EX.
When I see the output buffer, it has all invalid data. Can someone help me what I am doing wrong?
#include <Windows.h>
#include <ntddscsi.h>
#include <iostream>
void main() {
WCHAR *fileName = (WCHAR * ) "\\.\PhysicalDrive0";
HANDLE handle = CreateFile(
fileName,
GENERIC_READ | GENERIC_WRITE, //IOCTL_ATA_PASS_THROUGH requires read-write
FILE_SHARE_READ,
NULL, //no security attributes
OPEN_EXISTING,
0, //flags and attributes
NULL //no template file
);
ATA_PASS_THROUGH_EX inputBuffer;
inputBuffer.Length = sizeof(ATA_PASS_THROUGH_EX);
inputBuffer.AtaFlags = ATA_FLAGS_DATA_IN;
inputBuffer.DataTransferLength = 0;
inputBuffer.DataBufferOffset = 0;
IDEREGS *ir = (IDEREGS *) inputBuffer.CurrentTaskFile;
ir->bCommandReg = 0xEC; //identify device
ir->bSectorCountReg = 1;
unsigned int inputBufferSize = sizeof(ATA_PASS_THROUGH_EX);
UINT8 outputBuffer[512];
UINT32 outputBufferSize = 512;
LPDWORD bytesReturned = 0;
DeviceIoControl( handle, IOCTL_ATA_PASS_THROUGH_DIRECT, &inputBuffer, inputBufferSize, &outputBuffer, outputBufferSize, bytesReturned, NULL);
DWORD error = GetLastError();
std::cout << outputBuffer << std::endl;
system("pause");
}
update:
When I check the error value, it is 5, which means it is an access violation. I am running in admin mode. Am I doing something wrong?
-Nick
I've done this using code that looks like this:
int foo()
{
int iRet( 0 );
// Open handle to disk.
HANDLE hDevice( ::CreateFileW( L"\\\\.\\PhysicalDrive0", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ) );
if( hDevice == INVALID_HANDLE_VALUE )
{
std::wcout << L"CreateFileW( " << sPath << L" ) failed. LastError: " << GetLastError() << std::endl;
return -1;
}
//
// Use IOCTL_ATA_PASS_THROUGH
//
std::vector< UCHAR > vBuffer( sizeof( ATA_PASS_THROUGH_EX ) + sizeof( IDENTIFY_DEVICE_DATA ), 0 );
PATA_PASS_THROUGH_EX pATARequest( reinterpret_cast< PATA_PASS_THROUGH_EX >( &vBuffer[0] ) );
pATARequest->AtaFlags = ATA_FLAGS_DATA_IN | ATA_FLAGS_DRDY_REQUIRED;
pATARequest->Length = sizeof( ATA_PASS_THROUGH_EX );
pATARequest->DataBufferOffset = sizeof( ATA_PASS_THROUGH_EX );
pATARequest->DataTransferLength = sizeof( IDENTIFY_DEVICE_DATA );
pATARequest->TimeOutValue = 2;
pATARequest->CurrentTaskFile[6] = ID_CMD;
ULONG ulBytesRead;
if( DeviceIoControl( hDevice, IOCTL_ATA_PASS_THROUGH,
&vBuffer[0], ULONG( vBuffer.size() ),
&vBuffer[0], ULONG( vBuffer.size() ),
&ulBytesRead, NULL ) == FALSE )
{
std::cout << "DeviceIoControl(IOCTL_ATA_PASS_THROUGH) failed. LastError: " << GetLastError() << std::endl;
iRet = -1;
}
else
{
// Fetch identity blob from output buffer.
PIDENTIFY_DEVICE_DATA pIdentityBlob( reinterpret_cast< PIDENTIFY_DEVICE_DATA >( &vBuffer[ sizeof( ATA_PASS_THROUGH_EX ) ] ) );
}
CloseHandle( hDevice );
return iRet;
}
Note that this must be run from an administrator account or elevated context.

How could I get or change the IP address of a disconnected NIC in Windows?

I have configured the IP address for a NIC successfully in Windows7. But after pulling out the net cable, I can't get the IP address from API and ipconfig, but I can view it in "Network Connections". And if I insert the cable again, then I can get the address once more.
How could I get or change the IP address of a NIC, when the NIC is disconnected? I have used "GetAdaptersInfo" "GetIpAddrTable" or WMI class. All above method return 0.0.0.0 ipaddress for such NIC.
My platform is Windows7, and I wish the method can work for other Windows platforms.
Thanks!
The IP address isn't a property inherent to the NIC. The instant it becomes disconnected, it loses its IP. The IP is assigned by either a DHCP server or statically by your OS when there is actually a connection.
To get the IP from a disconnected NIC, try using netsh interface dump, for example:
netsh interface ipv4 dump name="Wireless Network Connection"
The ouput is like:
#----------------------------------
# IPv4 Configuration
# ----------------------------------
pushd interface ipv4
reset
set global icmpredirects=enabled
add address name="Wireless Network Connection" address=192.168.229.2 mask=255.255.255.0
popd
# End of IPv4 configuration
Some people suggested me to change a registry key, which will turn off media detection.
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters\DisableDHCPMediaSense
Type: REG_DWORD
Value: 1
I have tested this method but it still returns 0.0.0.0, but I can read unpluged NIC's IP address from reg:
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\[NIC_GUID]}\Parameters\Tcpip]
EnableDHCP
IPAddress
SubnetMask
DefaultGateway
As sshannin noted, the IP is only assigned, if the interface is connected. If you don't want to parse the output of netsh (as dmitry noted), you could check for settings in the registry in
HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\<GUID>
The IP address(es) which will get assigned to the interface are in the IPaddress REG_MULTI_SZ value, which is string list for several IPs.
Also the information about DHCP may be invalid if no cable is connected, so check the DisableDhcpOnConnect.
The following code outputs the first IP address of each network adapter found (no complete error handling):
#define WINNT 0x501
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <sstream>
#include <list>
#include <map>
#include <algorithm>
#include <iomanip>
#include <ws2ipdef.h>
#include <iphlpapi.h>
#undef __IPHLPAPI_H__
#include <winternl.h>
#include <netioapi.h> // In my SDK iphlpapi.h does not include netioapi.h !!!
#pragma comment (lib, "ws2_32")
#pragma comment (lib, "iphlpapi")
using namespace std;
class IP
{
public:
IP(unsigned long _ip = 0) : ip(ntohl(_ip)) {}
unsigned long ip;
};
wostream &operator<<(wostream &str, IP ip)
{
wostringstream o; o << ((ip.ip&0xff000000)>>24) << L"." << ((ip.ip&0xff0000)>>16) << L"." << ((ip.ip&0xff00)>>8) << L"." << (ip.ip&0xff);
return str << o.str();
}
typedef DWORD (__stdcall *fnGetIfTable2)(PMIB_IF_TABLE2*);
struct AdapterInfo
{
enum eCable {
connected,
disconnected,
unknown
} cable;
wstring FriendlyName;
wstring Description;
IP IpAddr;
IP Subnet;
bool dhcp;
unsigned char MAC[MAX_ADAPTER_ADDRESS_LENGTH];
ULONG64 speed;
AdapterInfo() : speed(0), cable(unknown) { memset(MAC, 0, sizeof(MAC)); };
};
map<unsigned long, AdapterInfo> Adapters;
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD( 2, 2 ), &wsaData);
// 1. Gather the relevant interfaces (no loopback or IPv6)
// -------------------------------------------------------
list<unsigned long> Indices;
PIP_INTERFACE_INFO pIfTable = 0;
ULONG dwIfTableSize = 0;
while (GetInterfaceInfo(pIfTable, &dwIfTableSize) == ERROR_INSUFFICIENT_BUFFER) {
if (pIfTable)
free(pIfTable);
pIfTable = (PIP_INTERFACE_INFO)malloc(dwIfTableSize);
}
for (int i= 0; i < pIfTable->NumAdapters; ++i)
Indices.push_back(pIfTable->Adapter[i].Index);
free(pIfTable);
// 2. Get the IP address (only one per adapter)
// --------------------------------------------
PMIB_IPADDRTABLE pIPAddrTable = 0;
DWORD dwSize = 0;
while (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) {
if (pIPAddrTable)
free( pIPAddrTable );
pIPAddrTable = (PMIB_IPADDRTABLE) malloc( dwSize );
}
for (unsigned i = 0; i<pIPAddrTable->dwNumEntries; ++i)
{
if (find(Indices.begin(), Indices.end(), pIPAddrTable->table[i].dwIndex) == Indices.end())
continue; // Any interface which is not relevant (probably loopback)
Adapters[pIPAddrTable->table[i].dwIndex].IpAddr = pIPAddrTable->table[i].dwAddr;
Adapters[pIPAddrTable->table[i].dwIndex].Subnet = pIPAddrTable->table[i].dwMask;
}
// 3. Get the name of the interface
// --------------------------------
IP_ADAPTER_ADDRESSES *AdapterAddresses = 0;
ULONG OutBufferLength = 0;
while (GetAdaptersAddresses(AF_INET, 0,NULL, AdapterAddresses, &OutBufferLength) == ERROR_BUFFER_OVERFLOW) {
if (AdapterAddresses)
free(AdapterAddresses);
AdapterAddresses = (PIP_ADAPTER_ADDRESSES) malloc(OutBufferLength);
}
PIP_ADAPTER_ADDRESSES AdapterList = AdapterAddresses;
while (AdapterList) {
if (find(Indices.begin(), Indices.end(), AdapterList->IfIndex) != Indices.end())
{
Adapters[AdapterList->IfIndex].FriendlyName = AdapterList->FriendlyName;
Adapters[AdapterList->IfIndex].Description = AdapterList->Description;
Adapters[AdapterList->IfIndex].dhcp = ((AdapterList->Flags&IP_ADAPTER_DHCP_ENABLED)!=0);
Adapters[AdapterList->IfIndex].speed = min(AdapterList->TransmitLinkSpeed, AdapterList->ReceiveLinkSpeed);
if (Adapters[AdapterList->IfIndex].speed == -1)
Adapters[AdapterList->IfIndex].speed = 0;
memcpy(Adapters[AdapterList->IfIndex].MAC, AdapterList->PhysicalAddress, min(AdapterList->PhysicalAddressLength, MAX_ADAPTER_ADDRESS_LENGTH));
}
AdapterList = AdapterList->Next;
}
// 4. Check if cable connected
fnGetIfTable2 pGetIfTable2 = 0;
HMODULE hModule = LoadLibraryA("Iphlpapi");
if (hModule)
{
pGetIfTable2 = (fnGetIfTable2)GetProcAddress(hModule,"GetIfTable2");
FreeLibrary(hModule);
}
if (pGetIfTable2)
{
PMIB_IF_TABLE2 table;
if (pGetIfTable2(&table) == NO_ERROR)
{
for (ULONG i = 0; i < table->NumEntries; ++i)
{
if (Adapters.find(table->Table[i].InterfaceIndex) != Adapters.end())
{
switch(table->Table[i].MediaConnectState)
{
case MediaConnectStateUnknown: Adapters[table->Table[i].InterfaceIndex].cable = AdapterInfo::unknown; break;
case MediaConnectStateConnected: Adapters[table->Table[i].InterfaceIndex].cable = AdapterInfo::connected; break;
case MediaConnectStateDisconnected: Adapters[table->Table[i].InterfaceIndex].cable = AdapterInfo::disconnected;
if (Adapters[table->Table[i].InterfaceIndex].IpAddr.ip == 0 &&
!Adapters[table->Table[i].InterfaceIndex].dhcp)
{
// Check Registry for the IP of the unconnected NIC
GUID *pGuid = &table->Table[i].InterfaceGuid;
char sKey[256];
sprintf(sKey, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
pGuid->Data1, pGuid->Data2, pGuid->Data3,
pGuid->Data4[0], pGuid->Data4[1], pGuid->Data4[2], pGuid->Data4[3], pGuid->Data4[4], pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7]);
HKEY hKey;
LONG res = RegOpenKeyExA(HKEY_LOCAL_MACHINE, sKey, 0, KEY_QUERY_VALUE|KEY_WOW64_64KEY, &hKey);
if (res == ERROR_SUCCESS)
{
if (Adapters[table->Table[i].InterfaceIndex].dhcp)
{
DWORD type, disableDHCP, size = sizeof(disableDHCP);
DWORD res = RegGetValueA(hKey,"", "DisableDhcpOnConnect", RRF_RT_REG_DWORD, &type, &disableDHCP, &size);
if (res == ERROR_SUCCESS && type == REG_DWORD)
Adapters[table->Table[i].InterfaceIndex].dhcp = disableDHCP == 0;
}
if (!Adapters[table->Table[i].InterfaceIndex].dhcp)
{
char IPAddress[512], SubnetMask[512];
DWORD type, size1 = sizeof(IPAddress), size2 = sizeof(SubnetMask);
DWORD res = RegGetValueA(hKey,"", "IPAddress", RRF_RT_REG_MULTI_SZ, &type, IPAddress, &size1);
if (res == ERROR_SUCCESS && type == REG_MULTI_SZ)
{
res = RegGetValueA(hKey,"", "SubnetMask", RRF_RT_REG_MULTI_SZ, &type, SubnetMask, &size2);
if (res == ERROR_SUCCESS && type == REG_MULTI_SZ)
{
Adapters[table->Table[i].InterfaceIndex].IpAddr = IP(inet_addr(IPAddress)); // String list, taking first element
Adapters[table->Table[i].InterfaceIndex].Subnet = IP(inet_addr(SubnetMask)); // String list, taking first element
}
}
}
RegCloseKey(hKey);
}
}
break;
}
}
}
}
}
// Output everything...
// --------------------
map<unsigned long, AdapterInfo>::iterator it = Adapters.begin(), end = Adapters.end();
while (it != end)
{
wcout << L"Adapter \"" << it->second.FriendlyName << L"\"\n";
wcout << L" DHCP: " << (it->second.dhcp?L"yes":L"no") << endl;
if (it->second.IpAddr.ip)
wcout << L" IP : " << it->second.IpAddr << endl;
if (it->second.Subnet.ip)
wcout << L" Subnet: " << it->second.Subnet << endl;
if (it->second.MAC[0] || it->second.MAC[1] || it->second.MAC[2] || it->second.MAC[3] || it->second.MAC[4] || it->second.MAC[5])
wcout << L" MAC: " << hex << setfill(L'0') << setw(2) << (unsigned)it->second.MAC[0] << L"-" << setw(2) << (unsigned)it->second.MAC[1] << L"-" << setw(2) << (unsigned)it->second.MAC[2] << L"-" << setw(2) << (unsigned)it->second.MAC[3] << L"-" << setw(2) << (unsigned)it->second.MAC[4] << L"-" << setw(2) << (unsigned)it->second.MAC[5] << dec << endl;
if (it->second.speed)
wcout << L" Speed: " << it->second.speed << endl;
if (!it->second.Description.empty())
wcout << L" Descr. \"" << it->second.Description << L"\"" << endl;
if (it->second.cable != AdapterInfo::unknown)
{
switch(it->second.cable)
{
case AdapterInfo::connected: wcout << " Cable: connected"; break;
case AdapterInfo::disconnected: wcout << " Cable: disconnected"; break;
}
}
wcout << endl;
++it;
}
}

Resources