File Isn't Deleting - windows

I have a code that finds files that are less than 20 seconds old. It's finding them, but I can't get them deleted. I am using remove(). I've tried using remove with wildcards but no luck. It has to be something with the syntax. Any help is appreciated. Thank you.
using namespace std;
typedef vector<WIN32_FIND_DATA> tFoundFilesVector;
std::wstring LastWriteTime;
int getFileList(const char * filespec, tFoundFilesVector &foundFiles)
{
WIN32_FIND_DATA findData;
HANDLE h;
int validResult=true;
int numFoundFiles = 0;
h = FindFirstFile((LPCSTR)filespec, &findData);
if (h == INVALID_HANDLE_VALUE)
return 0;
while (validResult)
{
numFoundFiles++;
foundFiles.push_back(findData);
validResult = FindNextFile(h, &findData);
}
return numFoundFiles;
}
void showFileAge(tFoundFilesVector &fileList)
{
unsigned _int64 fileTime, curTime, age;
tFoundFilesVector::iterator iter;
FILETIME ftNow;
CoFileTimeNow(&ftNow);
curTime = ((_int64) ftNow.dwHighDateTime << 32) + ftNow.dwLowDateTime;
for (iter=fileList.begin(); iter<fileList.end(); iter++)
{
fileTime = ((_int64)iter->ftLastWriteTime.dwHighDateTime << 32) + iter- >ftLastWriteTime.dwLowDateTime;
age = curTime - fileTime;
if (age <= (_int64)200000000UL)
{
wcout << " Delete: '" <<endl;
wcout << "FILE: '" << iter->cFileName << "', AGE: " << (_int64)age/10000000UL << " seconds" << endl;
remove("C:\\mapper\\iter->cFileName");
}
else
{
//wcout << " Quit: '" <<endl;
//return;
}
}
}
int main()
{
string fileSpec = "*.*";
tFoundFilesVector foundFiles;
tFoundFilesVector::iterator iter;
int foundCount = 0;
getFileList("c:\\Mapper\\*.txt", foundFiles);
getFileList("c:\\Mapper\\*.jpg", foundFiles);
foundCount = foundFiles.size();
if (foundCount)
{
wcout << "Found "<<foundCount<<" matching files.\n";
showFileAge(foundFiles);
}
system("pause");
return 0;
}

You need to concatenate the strings "C:\mapper\" with whatever is in iter->cFileName. The most simple way of doing that would be to use the std::string class.
The result would look something like this:
remove(string("c:\\mapper\\").append(string(iter->cFileName)).c_str());
This assumes you do not use unicode encoding of your strings, otherwise you need to use std::wstring. To use these classes you will also need to include
#include <string>
in the top of your file.

Related

libzip: zip_name_locate() fails on specific filename, even trying all possible encoding combinations

I am trying to build a "failsafe" layer on top of libzip but libzip is giving me some trouble here.
First I add a file to my (empty) archive with zip_file_add(...). This has 3 possible user-defined encodings available. Then I try to locate the name with zip_name_locate(...) which also has 3 possible user-defined encodings available.
This mcve checks all possible encoding combinations and all of them fail for the specific filename x%²»Ã-ØÑ–6¨wx.txt. When using a more conventional file.txt filename, zip_name_locate() succeeds every time.
#include <zip.h>
#include <include/libzip.h>//<.pragmas to include the .lib's...
#include <iostream>
#include <vector>
#include <utility>
/*
'zip_file_add' possible encodings:
ZIP_FL_ENC_GUESS
ZIP_FL_ENC_UTF_8
ZIP_FL_ENC_CP437
'zip_name_locate' possible encodings:
ZIP_FL_ENC_RAW
ZIP_FL_ENC_GUESS
ZIP_FL_ENC_STRICT
*/
/*
build encoding pairs (trying all possibilities)
*/
std::vector<std::pair<unsigned, unsigned>>
encoding_pairs{
{ ZIP_FL_ENC_GUESS, ZIP_FL_ENC_RAW },
{ ZIP_FL_ENC_UTF_8, ZIP_FL_ENC_RAW },
{ ZIP_FL_ENC_CP437, ZIP_FL_ENC_RAW },
{ ZIP_FL_ENC_GUESS, ZIP_FL_ENC_GUESS },
{ ZIP_FL_ENC_UTF_8, ZIP_FL_ENC_GUESS },
{ ZIP_FL_ENC_CP437, ZIP_FL_ENC_GUESS },
{ ZIP_FL_ENC_GUESS, ZIP_FL_ENC_STRICT },
{ ZIP_FL_ENC_UTF_8, ZIP_FL_ENC_STRICT },
{ ZIP_FL_ENC_CP437, ZIP_FL_ENC_STRICT },
};
int main(int argc, char** argv) {
const char* file_buf = "hello world";
#if 0
const char* file_name = "file.txt";
#else
const char* file_name = "x%²»Ã-ØÑ–6¨wx.txt";
#endif
zip_error_t ze;
zip_error_init(&ze);
{
zip_source_t* zs = zip_source_buffer_create(nullptr, 0, 1, &ze);
if (zs == NULL)
return -1;
zip_t* z = zip_open_from_source(zs, ZIP_CHECKCONS, &ze);
if (z == NULL)
return -1;
{
zip_source_t* s = zip_source_buffer(z, file_buf, strlen(file_buf), 0);//0 = don't let libzip auto-free the const char* buffer on the stack
if (s == NULL)
return -1;
for (size_t ep = 0; ep < encoding_pairs.size(); ep++) {
std::cout << "ep = " << ep << std::endl;
zip_uint64_t index;
if ((index = zip_file_add(z, file_name, s, encoding_pairs[ep].first)) == -1) {
std::cout << "could not zip_file_add() with encoding " << encoding_pairs[ep].first << std::endl;
continue;
}
if (zip_name_locate(z, file_name, encoding_pairs[ep].second) == -1) {
std::cout << "the name '" << file_name << "' could not be located." << std::endl;
std::cout << " encoding pair: " << encoding_pairs[ep].first << " <-> " << encoding_pairs[ep].second << std::endl;
}
else {
std::cout << "the name was located." << std::endl;
}
if (zip_delete(z, index) == -1)
return -1;
}
}
zip_close(z);
}
zip_error_fini(&ze);
return 0;
}
I don't understand what I might be doing wrong here or if libzip just can't even resolve such a name.
If it can't then what would be the criteria on names to avoid ?
It turns out the problem was the encoding of my source file itself. It was ANSI - So I converted it to UTF8 and it solved the issue.
What I still don't understand is why libzip can't zip_name_locate() a name from an input c-string that is exactly the same as the input c-string used in zip_file_add() (whatever the source file encoding might be). "Lost in translation" perhaps ?
(Special thanks to Thomas Klausner for helping me find the issue).

How to get source location of #includes using clang libtooling?

Is there any way to get clang::SourceLocation for every #include in file by its clang::FileID or clang::FileEntry or something?
What about using source manager's GetIncludedLoc function which takes fileid as parameter.
SourceManager.GetIncludedLoc(fileid)
Thank's #Hemant for your answer, you're right
I Already found that by myself (in clang 3.8 it is called getIncludeLoc)
but forgot to write here.
I used this to find the location after all #includes where i can put my own.
Here's the function (For sure not the best way) I wrote for this, hope it helps someone
SourceLocation getIncludeLocation(FileID fileID, SourceManager &sm, unsigned carriages) {
return SourceLocation();
set<unsigned> lines;
if (fileID.isInvalid())
for (auto it = sm.fileinfo_begin(); it != sm.fileinfo_end(); it++) {
SourceLocation includeLoc = sm.getIncludeLoc(sm.translateFile(it->first));
if (includeLoc.isValid() && sm.isInFileID(includeLoc, fileID)) {
lines.insert(sm.getSpellingLineNumber(includeLoc));
}
}
unsigned pos(0);
if (!lines.empty()) {
bool first = true;
for (unsigned line :lines) {
if (first)
first = false;
else if ((line - pos) > carriages)
break;
pos = line;
//cout << "Include line:" << pos << endl;
}
//cout << console_hline('-') << endl;
}
cout << sm.getFileEntryForID(fileID)->getName() << endl;
return sm.translateFileLineCol(sm.getFileEntryForID(fileID), ++pos, 1);
}
Also some information about includes can be get by
Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, StringRef &Buffer)
and
Lexer::ComputePreamble(StringRef Buffer, const LangOptions &LangOpts, unsigned MaxLines = 0)

What Time Is This Returning

Deep in the sauce here. I haven't worked with time to much so I'm a little confused here. I know there is FILETIME and SYSTEMTIME. What I am trying to get at this point (because it might change) are file that are less than a 20 seconds old. This returning the files and their size and something in seconds, What I'd like to know is where it is filtering by time if it is, and how can I adjust it to suit my needs. Thank you.
using namespace std;
typedef vector<WIN32_FIND_DATA> tFoundFilesVector;
std::wstring LastWriteTime;
int getFileList(wstring filespec, tFoundFilesVector &foundFiles)
{
WIN32_FIND_DATA findData;
HANDLE h;
int validResult=true;
int numFoundFiles = 0;
h = FindFirstFile(filespec.c_str(), &findData);
if (h == INVALID_HANDLE_VALUE)
return 0;
while (validResult)
{
numFoundFiles++;
foundFiles.push_back(findData);
validResult = FindNextFile(h, &findData);
}
return numFoundFiles;
}
void showFileAge(tFoundFilesVector &fileList)
{
unsigned _int64 fileTime, curTime, age;
tFoundFilesVector::iterator iter;
FILETIME ftNow;
//__int64 nFileSize;
//LARGE_INTEGER li;
//li.LowPart = ftNow.dwLowDateTime;
//li.HighPart = ftNow.dwHighDateTime;
CoFileTimeNow(&ftNow);
curTime = ((_int64) ftNow.dwHighDateTime << 32) + ftNow.dwLowDateTime;
for (iter=fileList.begin(); iter<fileList.end(); iter++)
{
fileTime = ((_int64)iter->ftLastWriteTime.dwHighDateTime << 32) + iter->ftLastWriteTime.dwLowDateTime;
age = curTime - fileTime;
cout << "FILE: '" << iter->cFileName << "', AGE: " << (_int64)age/10000000UL << " seconds" << endl;
}
}
int main()
{
string fileSpec = "*.*";
tFoundFilesVector foundFiles;
tFoundFilesVector::iterator iter;
int foundCount = 0;
getFileList(L"c:\\Mapper\\*.txt", foundFiles);
getFileList(L"c:\\Mapper\\*.jpg", foundFiles);
foundCount = foundFiles.size();
if (foundCount)
{
cout << "Found "<<foundCount<<" matching files.\n";
showFileAge(foundFiles);
}
system("pause");
return 0;
}
I don't know what you've done to try to debug this but your code doesn't work at all. The reason is you're passing getFileList() a wstring but then passing that to the ANSI version of FindFirstFile(). Unless you #define UNICODE or use the appropriate compiler option, all system calls will expect char *, not UNICODE.
The easiest fix is to simply change the declaration of getFileList() to this:
int getFileList(const char * filespec, tFoundFilesVector &foundFiles)
Change the call to FindFirstFile() to this:
h = FindFirstFile((LPCSTR)filespec, &findData);
And then change the calls to it to this:
getFileList("c:\\Mapper\\*.txt", foundFiles);
getFileList("c:\\Mapper\\*.jpg", foundFiles);
Your other option is to switch all char strings to wide chars, but either way you need to be consistent throughout. Once you do that the program works as expected.
As for your final question, your program is not filtering by time at all.
Not quite an answer, but you might want to read about file system tunneling.
It may prevent you from what you're trying to do in some situations.

how to customize "TimeStamp" format of Boost.Log

I want to get year-month-day hour:minute:second.fraction(2 digits), if I use "%Y-%m-%d %H:%M:%S.%f", I got almost what I want exception for the fraction( last part ) of seconds, it's showing 6 digits on my Windows XP, I don't know how to get 2 digits only, any idea?
I'm using this
namespace boost
{
BOOST_LOG_OPEN_NAMESPACE
namespace attributes
{
template <typename date_time_type>
void format_time_ms( std::ostringstream& formatter, const date_time_type& date_time)
{
auto time = date_time.time_of_day();
using namespace std;
formatter
<< setfill( '0') << setw( 2) << time.hours() << ':'
<< setfill( '0') << setw( 2) << time.minutes() << ':'
<< setfill( '0') << setw( 2) << time.seconds() << ','
<< setfill( '0') << setw( 3) << time.fractional_seconds() / 1000;
}
template <typename date_time_type>
std::string format_time_ms( const date_time_type& date_time)
{
std::ostringstream formatter;
format_time_ms( formatter, date_time);
auto time = date_time.time_of_day();
return formatter.str();
}
template <typename date_time_type>
std::string format_date_time_ms( const date_time_type& date_time, const char date_time_sep = ' ')
{
using namespace std;
ostringstream formatter;
auto date = date_time.date();
formatter
<< date.year() << '-'
<< setfill( '0') << setw( 2) << int( date.month()) << '-'
<< setfill( '0') << setw( 2) << date.day() << date_time_sep;
format_time_ms( formatter, date_time);
return formatter.str();
}
template <typename date_time_type, const char date_time_sep = ' '>
struct date_time_ms_formatter
{
std::string operator () ( const date_time_type& date_time) { return format_date_time_ms( date_time, date_time_sep); }
};
struct time_ms_formatter
{
template <typename date_time_type>
std::string operator () ( const date_time_type& date_time) { return format_time_ms( date_time); }
};
template <typename time_type>
struct local_clock_source
{
time_type operator () () const
{
return date_time::microsec_clock<time_type>::local_time();
}
};
template <typename time_type>
struct universal_clock_source
{
time_type operator () () const
{
return date_time::microsec_clock<time_type>::universal_time();
}
};
template <typename time_type, typename clock_source_type, typename formater_type>
class custom_clock: public attribute
{
public:
class impl: public attribute::impl
{
public:
attribute_value get_value()
{
auto str = formater_type()( clock_source_type()());
return make_attribute_value( str);
}
};
custom_clock(): attribute( new impl()) {}
explicit custom_clock( const cast_source& source): attribute( source.as<impl>()) {}
};
typedef custom_clock<boost::posix_time::ptime, local_clock_source<boost::posix_time::ptime>, date_time_ms_formatter<boost::posix_time::ptime, '\t'> > local_date_time_ms_clock;
typedef custom_clock<boost::posix_time::ptime, universal_clock_source<boost::posix_time::ptime>, date_time_ms_formatter<boost::posix_time::ptime, '\t'> > universal_date_time_ms_clock;
typedef custom_clock<boost::posix_time::ptime, local_clock_source<boost::posix_time::ptime>, time_ms_formatter> local_time_ms_clock;
typedef custom_clock<boost::posix_time::ptime, universal_clock_source<boost::posix_time::ptime>, time_ms_formatter> universal_time_ms_clock;
}
BOOST_LOG_CLOSE_NAMESPACE // namespace log
}
initialized as
BOOST_LOG_ATTRIBUTE_KEYWORD( dateTimeStamp, "DateTime", boost::posix_time::ptime)
BOOST_LOG_ATTRIBUTE_KEYWORD( timeStamp, "Time", boost::posix_time::ptime)
core->add_global_attribute( dateTimeStamp.get_name(), attrs::local_date_time_ms_clock());
core->add_global_attribute( timeStamp.get_name(), attrs::local_time_ms_clock());
and used as
expr::stream << expr::attr<std::string>( dateTimeStamp.get_name())
expr::stream << expr::attr<std::string>( timeStamp.get_name())
Boost.DateTime (upon which Boost.Log relies) doesn't seem to support specialized fractional seconds formatting, so the only way to do that would be to write your own custom attribute formatter, or (the easier, but less nice way) to slightly modify your formatting code.
Instead of something like this:
backend->set_formatter
(
fmt::stream <<
fmt::date_time<boost::posix_time::ptime>
("TimeStamp", keywords::format = "%Y-%m-%d %H:%M:%S.%f"));
backend->set_formatter
(
fmt::stream <<
fmt::date_time<boost::posix_time::ptime>
("TimeStamp", keywords::format = %Y-%m-%d %H:%M:%S.") <<
(fmt::format("%.2s") % fmt::date_time<boost::posix_time::ptime>("%f"))
);
I haven't tested it myself, but I believe it should work: the first fmt::date_time() will return the timestamp without the fractional seconds, while the second fmt::date_time() will return just the fractional seconds, which will be cut to two digits by the fmt::format().
We addressed it with this class:
class TimeStamp : public boost::log::attributes::local_clock {
public:
typedef boost::log::attribute_value attribute_type;
typedef boost::log::attributes::local_time_traits TimeTraitsT;
typedef TimeTraitsT::time_type time_type;
typedef boost::log::attributes::basic_attribute_value< std::string > result_value;
public:
boost::shared_ptr< attribute_type > get_value() {
time_type posix_time = boost::date_time::microsec_clock< time_type >::universal_time();
time_type::time_duration_type time = posix_time.time_of_day();
time_type::date_type date = posix_time.date();
std::stringstream formatter;
formatter
<< date.year() << "-"
<< std::setfill('0') << std::setw(2) << int(date.month()) << "-"
<< std::setfill('0') << std::setw(2) << date.day() << " "
<< std::setfill('0') << std::setw(2) << boost::date_time::absolute_value(time.hours()) << ":"
<< std::setfill('0') << std::setw(2) << boost::date_time::absolute_value(time.minutes()) << ":"
<< std::setfill('0') << std::setw(2) << boost::date_time::absolute_value(time.seconds()) << ","
<< std::setfill('0') << std::setw(2) << boost::date_time::absolute_value(time.fractional_seconds()) / 1000
;
return boost::make_shared< result_value >(formatter.str());
}
};
Initialized like this:
boost::log::core::get()->add_global_attribute("TimeStamp", boost::make_shared< TimeStamp >());
And used like this:
backend_ptr->set_formatter(
boost::log::formatters::stream
<< boost::log::formatters::attr< std::string >("TimeStamp")
<< boost::log::formatters::message();
The class, obviously, lets us access or format any portion of the date we wish
Try this one. It works for me under Linux.
sink->set_formatter(log_expr::format("%1%") % log_expr::max_size_decor<char>(22)[log_expr::stream << log_expr::format_date_time<boost::posix_time::ptime>("Timestamp", "%Y-%m-%d %H:%M:%S.%f")]);

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