/************************************************************************/
/*      Copyright (C) Alexey Kazakovsky 2002.  All rights reserved.     */
/*      Written by Alexey Kazakovsky (alex@lastbit.com)                 */
/*                                                                      */
/*      Free software: no warranty; use anywhere is ok; spread the      */
/*      sources; note any modifications; share variations and           */
/*      derivatives (including sending to alex@lastbit.com).            */
/*                                                                      */
/*                                                                      */
/*      This class CSysInfo makes easy to get a various system info:    */
/*      - OS version (e.g. Windows 2000 Terminal Server)                */
/*      - CPU type                                                      */
/*      - Total amount of physical memory and memory usage              */
/*      - IE version                                                    */
/*      - ADO version                                                   */
/*      - Does the current user have administrator rights ?             */
/*      - Network interface (NIC) list with their IP addresses          */
/*      - etc...                                                        */
/*                                                                      */
/*      Last Modified:           December, 19  2000                     */
/*      Unicode supported:       yes                                    */
/*      Target:                  Microsoft Visual C++ 6.0/7.0           */
/*                                                                      */
/************************************************************************/

//////////////////////////////////////////////////////////////////////////
//Updated:	28.02.2007 by WiZaRd
//
//- many codeparts rewritten and optimized, including some memleak fixes
//- added SYSINFO_USE_MIB switch to enable/disable MIB info in the sysinfo class
//- removed obsolete definitions (included in VS defines)

#include "stdafx.h"
#include "SysInfo.h"
#include <process.h>
#include "emule.h"
#include "Log.h" //>>> taz::VistaFix [pP]

#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Version.lib")

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#define CSYSINFO_VERSION "2.0"

#define W95_s L"Windows 95"
#define W98_s L"Windows 98"
#define WME_s L"Windows ME"
#define NT4_s L"Windows NT 4.0"
#define WKS_s L" Workstation"
#define WXP_s L"Windows XP"
#define XHE_s L" Home Edition"
#define XPR_s L" Professional Edition"
#define WVI_s L"Windows Vista"
#define W2K_s L"Windows 2000"
#define PRO_s L" Professional"
#define DOM_s L" Domain Controller"
#define SER_s L" Server"
#define ADV_s L" Advanced"
#define DTC_s L" DataCenter"
#define TER_s L" Terminal"
#define BOF_s L" BackOffice"

#define IE_CONFIGURATION_KEY	L"SOFTWARE\\Microsoft\\Internet Explorer"
#define CPU_CONFIGURATION_KEY	L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"
#define ADO_CONFIGURATION_KEY	L"SOFTWARE\\Microsoft\\DataAccess"

#define MAX_IPADDRESSES 100

#ifdef SYSINFO_USE_MIB
#define MIB_IFOPERSTATUS_UP 1
#define MIB_IFOPERSTATUS_DOWN 2
#define MIB_IFOPERSTATUS_TESTING 3

#define MIB_IFTYPE_ETHERNET_CSMACD 6
#define MIB_IFTYPE_PPP 23
#define MIB_IFTYPE_LOOPBACK 24
#endif

/*
typedef struct _OSVERSIONINFOEXW {
	DWORD dwOSVersionInfoSize;
	DWORD dwMajorVersion;
	DWORD dwMinorVersion;
	DWORD dwBuildNumber;
	DWORD dwPlatformId;
	TCHAR szCSDVersion[128];
	WORD  wServicePackMajor;
	WORD  wServicePackMinor;
	WORD  wSuiteMask;
	BYTE  wProductType;
	BYTE  wReserved;
} OSVERSIONINFOEX, *POSVERSIONINFOEX, *LPOSVERSIONINFOEX;
#endif
typedef OSVERSIONINFOEXA	OSVERSIONINFOEX;
typedef POSVERSIONINFOEXA	POSVERSIONINFOEX;
typedef LPOSVERSIONINFOEXA	LPOSVERSIONINFOEX;
*/

//>>> taz::VistaFix [pP]
CString GetRegKeyVista(const CString& sKey, const bool bLog = false)
{
	// get the WinVer from registry
	HKEY hKey = NULL;
#define VISTA_KEY	L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
	if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, VISTA_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
	{
		DWORD dwType;
		TCHAR szValue[100];
		DWORD dwSize = sizeof(szValue)*sizeof(TCHAR);
		if (RegQueryValueEx(hKey, sKey, NULL, &dwType, (LPBYTE)szValue, &dwSize) == ERROR_SUCCESS)
		{
			 if(dwType == REG_SZ || dwType == REG_EXPAND_SZ)
			 {
#ifdef _DEBUG
				if(bLog)
					theApp.QueueDebugLogLineEx(LOG_INFO, L"GetRegKeyVista: RegQueryValueEx (%s) returned '%s'", sKey, szValue);
#endif
				return (CString)szValue;
			}
			 if(bLog)
				 theApp.QueueDebugLogLineEx(LOG_ERROR, L"GetRegKeyVista: RegQueryValueEx (%s) returned wrong type %u", sKey, dwType);
		}
		else if(bLog)
			theApp.QueueDebugLogLineEx(LOG_ERROR, L"GetRegKeyVista: RegQueryValueEx (%s) failed to query key", sKey);
		RegCloseKey(hKey);
	}
#ifdef _DEBUG
	if(bLog)
		theApp.QueueDebugLogLineEx(LOG_ERROR, L"GetRegKeyVista: RegOpenKeyEx (%s) failed", VISTA_KEY);
#endif
	return L"";
}
//<<< taz::VistaFix [pP]

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSysInfo::CSysInfo()
{
	m_bWindowsNT = GetVersion() < 0x80000000;
	m_dwWinMajor=0;
	m_dwWinMinor=0;
	m_dwBuildNumber=0;
	m_dwServicePack=0;
	m_dwNumProcessors=0;
	m_dwCPUSpeed=0;

	m_dwMemoryLoad=0;
	m_dwAvailVirtual=0;
	m_dwTotalVirtual=0;
	m_dwAvailPageFile=0;
	m_dwTotalPageFile=0;
	m_dwAvailPhys=0;
	m_dwTotalPhys=0;

#ifdef SYSINFO_USE_MIB
	m_dwIESomething=0;
	m_dwIEBuild=0;
	m_dwIEMinor=0;
	m_dwIEMajor=0;

	m_dwADOMajor=0;
	m_dwADOMinor=0;
	m_dwADOBuild=0;
	m_dwADOSomething=0;

	m_bIphlpapiAllocated=FALSE;
	m_bIphlpapiObtained=FALSE;
	m_nNumAdaptersIphlpapi=0;

	m_GetAdaptersInfo=NULL;
	m_GetIfEntry=NULL;
	m_bIphlpapiDll=FALSE;
	m_bIphlpapiCompat=FALSE;
	m_bMibDll=FALSE;
	m_bMIBShowLoopback=FALSE;

	for (int i = 0; i < MAX_IPADDRESSES; ++i)
	{
		m_dwMIBIPArray[0]=0;
		m_dwMIBIPArray_tmp[0]=0;
	}

	m_nMIBAddresses=0;
	m_bMIBAllocated=FALSE;
#endif
	m_bUserAdmin=FALSE;

	m_GetProcessMemoryInfo=NULL;
	m_bPsapiDll=FALSE;
	time(&m_StartupTime);

	Init();
}

CSysInfo::~CSysInfo()
{
#ifdef SYSINFO_USE_MIB
	if (m_bIphlpapiAllocated) free(m_pai);
	if (m_bMIBAllocated) free(m_pMIBAdapters);
#endif
	if (m_bPsapiDll) FreeModule(m_hmPsapiDll);
#ifdef SYSINFO_USE_MIB
	if (m_bIphlpapiDll) FreeModule(m_hmIphlpapiDll);
#endif
}

void CSysInfo::Init()
{
	// Init routines. It must be called before getting system information.
#ifdef SYSINFO_USE_MIB
	m_hmIphlpapiDll = NULL;
	m_nNumAdaptersIphlpapi=0;
	if((m_hmIphlpapiDll=::LoadLibrary(L"iphlpapi.dll"))!=NULL)
	{
		// FARPROC GetProcAddress(
		//		HMODULE hModule,    // handle to DLL module
		//		LPCSTR lpProcName   // function name
		// );
		m_bIphlpapiDll=TRUE;
		m_GetAdaptersInfo=(pGetAdaptersInfo)::GetProcAddress(m_hmIphlpapiDll, "GetAdaptersInfo");
		m_GetIfEntry=(pGetIfEntry)::GetProcAddress(m_hmIphlpapiDll, "GetIfEntry");
	}
	m_bMibDll=m_mib.Init();
#endif

	m_hmPsapiDll = NULL;
	if (IsWindowsNT())
	{
		if((m_hmPsapiDll=::LoadLibrary(L"psapi.dll"))!=NULL)
		{
			m_bPsapiDll=TRUE;
			m_GetProcessMemoryInfo=(pGetProcessMemoryInfo)::GetProcAddress(m_hmPsapiDll, "GetProcessMemoryInfo");
		}
	}	

	DetectOSType();
	DetectNumProcessors();
	DetectCPUType();
	DetectMemory();
#ifdef SYSINFO_USE_MIB
	DetectIEVersion();
	DetectADOVersion();
	DetectAdaptersIphlpapi();
	MIBRefreshAddresses();
	DetectAdaptersMIB();
#endif
	DetectUserAdmin();
	DetectLoginUserName();
	DetectWorkingDir();
}

//
//  Detect a type of operation system
//
void CSysInfo::DetectOSType()
{
	BOOL bOSINFOEXWorking=FALSE;

	OSVERSIONINFO v;
	ZeroMemory(&v, sizeof(OSVERSIONINFO));
	v.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
	GetVersionEx((LPOSVERSIONINFO)&v);

	m_dwWinMajor=v.dwMajorVersion;
	m_dwWinMinor=v.dwMinorVersion;
	m_dwBuildNumber=v.dwBuildNumber;

	if (!IsWindowsNT())
	{
		// Windows 9x/ME.
		if (m_dwWinMinor==0)  { m_sOSType=W95_s; };
		if (m_dwWinMinor==10) { m_sOSType=W98_s; };
		if (m_dwWinMinor==90) { m_sOSType=WME_s; };
		m_sOSType+=v.szCSDVersion;
		return;
	};

	// Get Service Pack number
	int n=0, j=-1; CString sSvcPack; TCHAR szNum[10];
	sSvcPack=v.szCSDVersion;
	for (n=1;n<=9;n++) {
		_stprintf(szNum, L"%d", n);
		j=sSvcPack.Find(szNum);
		if (j>=0) break;
	};
	if (j>=0) m_dwServicePack=n;

	// Check for OSVERSIONINFOEX-compatibility
	// It works only on Windows NT 4.0 Service Pack 6 or better
	if ((m_dwWinMajor>=5) || (m_dwServicePack>=6))
	{ bOSINFOEXWorking=TRUE; };

	if (m_dwWinMajor==4)
	{
		// Windows NT 4.0
		m_sOSType=NT4_s;
	}
//>>> taz::VistaFix [pP]
/*
	else
	{
		if (m_dwWinMajor>=5)
		{
			if (m_dwWinMinor==0)
				m_sOSType=W2K_s;  // Windows 2000
			else if (m_dwWinMinor==1)
				m_sOSType=WXP_s;  // Windows XP
			else if (m_dwWinMinor==1)
				m_sOSType=WVI_s;  // Windows Vista+Longhorn Server
		};
	};
*/
	else if (m_dwWinMajor==5)
	{
		if (m_dwWinMinor==0)
			m_sOSType=W2K_s;  // Windows 2000
		else if (m_dwWinMinor==1)
			m_sOSType=WXP_s; // Windows XP
	}
	// pp // Windows Vista
	else if (m_dwWinMajor>=6)
	{
		bOSINFOEXWorking = false; // skip extended info, not supported for Vista anyways 
		//WiZaRd: this statement ^^ is WRONG though the needed defines may be missing... they are supplied with V$2005 and higher
		//one could use "GetProductInfo" to get the missing data but for now I leave the code that taz added but with little fixes
		CString sProduct = GetRegKeyVista(L"ProductName");
		CString sService = GetRegKeyVista(L"CSDVersion");
		if (!sProduct.IsEmpty())
		{
			m_sOSType = sProduct;
			if(!sService.IsEmpty())
				m_sOSType.AppendFormat(L" %s", sService);
		}
		else
			m_sOSType.Format(L"Microsoft Windows %u.%u, unknown version", m_dwWinMajor, m_dwWinMinor);
	}
//<<< taz::VistaFix [pP]

	if (bOSINFOEXWorking)
	{
		OSVERSIONINFOEX osvi;
		BOOL bOsVersionInfoEx;
		ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
		osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
		bOsVersionInfoEx=GetVersionEx((LPOSVERSIONINFO)&osvi);

		if (bOsVersionInfoEx)
		{
			if (osvi.wProductType==VER_NT_WORKSTATION)
			{
				if ((osvi.dwMajorVersion==5) && (osvi.dwMinorVersion>=1))
				{
					// Windows XP
					if (osvi.wSuiteMask & VER_SUITE_PERSONAL)
					{ m_sOSType+=XHE_s; }
					else
					{ m_sOSType+=XPR_s; };
				};

				if ((osvi.dwMajorVersion==5) && (osvi.dwMinorVersion==0))
				{
					// Windows 2000 Professional
					m_sOSType+=PRO_s;
				};

				if (osvi.dwMajorVersion==4)
				{
					// Windows NT 4.0 Workstation
					m_sOSType+=WKS_s;
				};
			};

			if ((osvi.wProductType==VER_NT_SERVER) || (osvi.wProductType==VER_NT_DOMAIN_CONTROLLER))
			{
				if (osvi.dwMajorVersion==5)
				{
					if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) { m_sOSType+=ADV_s; };
					if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { m_sOSType+=DTC_s; };
					if (osvi.wSuiteMask & VER_SUITE_TERMINAL) { m_sOSType+=TER_s; };
					if (osvi.wSuiteMask & VER_SUITE_BACKOFFICE) { m_sOSType+=BOF_s; };
					m_sOSType+=SER_s;
				};
				if (osvi.dwMajorVersion==4 && osvi.dwMinorVersion==0) { m_sOSType+=SER_s; };
			};

			if (osvi.wProductType==VER_NT_DOMAIN_CONTROLLER)
			{ m_sOSType+=DOM_s; };
		};
	};

	if (m_dwServicePack>0)
	{
		m_sOSType += L" ";
		m_sOSType+=v.szCSDVersion;
	}
}

//
// Detect a number of processors
//
void CSysInfo::DetectNumProcessors()
{
	SYSTEM_INFO sinfo;
	GetSystemInfo(&sinfo);
	m_dwNumProcessors=sinfo.dwNumberOfProcessors;
}

#ifdef SYSINFO_USE_MIB
//
// Detect Internet Explorer version
//
void CSysInfo::DetectIEVersion()
{
	HKEY	NewKey;
	LONG	lresult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, IE_CONFIGURATION_KEY, 
		0, KEY_EXECUTE, &NewKey);

	if (lresult != ERROR_SUCCESS) 
		return;		// key not found

	TCHAR szKeyValue[100]; 
	memset(szKeyValue, 0, sizeof(szKeyValue));
	DWORD dwType = REG_SZ; 
	DWORD dwSize = 100;

	lresult = RegQueryValueEx(NewKey, L"Version", NULL, &dwType, 
		(LPBYTE)szKeyValue, &dwSize);

	RegCloseKey(NewKey);

	if (lresult == ERROR_SUCCESS && dwSize != 0)
		_stscanf(szKeyValue, L"%d.%d.%d.%d", &m_dwIEMajor, &m_dwIEMinor, &m_dwIEBuild, &m_dwIESomething);
}
#endif

//
// Detect CPU type
//
void CSysInfo::DetectCPUType()
{
	HKEY	NewKey;

	LONG	lresult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, CPU_CONFIGURATION_KEY, 
		0, KEY_EXECUTE, &NewKey);

	if (lresult != ERROR_SUCCESS) 
		return;		// key not found


	TCHAR szKeyValue[100]; 
	memset(szKeyValue, 0, sizeof(szKeyValue));
	DWORD dwType = REG_SZ; 
	DWORD dwSize = 100;

	lresult = RegQueryValueEx(NewKey, L"Identifier", NULL, 
		&dwType, (LPBYTE)szKeyValue, &dwSize);

	if (lresult == ERROR_SUCCESS && dwSize != 0)
		m_sCPUIdentifier = szKeyValue; 

	memset(szKeyValue, 0, sizeof(szKeyValue));
	dwType = REG_SZ; 
	dwSize = 100;

	lresult = RegQueryValueEx(NewKey, L"VendorIdentifier", NULL, 
		&dwType, (LPBYTE)szKeyValue, &dwSize);

	if (lresult == ERROR_SUCCESS && dwSize != 0)
		m_sCPUVendorIdentifier = szKeyValue; 

	memset(szKeyValue, 0, sizeof(szKeyValue));
	dwType = REG_SZ; 
	dwSize = 100;

	lresult = RegQueryValueEx(NewKey, L"ProcessorNameString", 
		NULL, &dwType, (LPBYTE)szKeyValue, &dwSize);

	if (lresult == ERROR_SUCCESS && dwSize != 0)
		m_sCPUNameString = szKeyValue;

	DWORD dwData = 0; 
	dwType = REG_DWORD; 
	dwSize = sizeof(dwData);
	lresult = RegQueryValueEx(NewKey, L"~MHz", NULL, 
		&dwType, (LPBYTE)(&dwData), &dwSize);

	if (lresult == ERROR_SUCCESS && dwSize != 0)
		m_dwCPUSpeed = dwData;

	RegCloseKey(NewKey);
}

#ifdef SYSINFO_USE_MIB
//
// Detect ADO version
//
void CSysInfo::DetectADOVersion()
{
	HKEY	NewKey;
	LONG	lresult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, ADO_CONFIGURATION_KEY, 
		0, KEY_EXECUTE, &NewKey);

	if (lresult != ERROR_SUCCESS) 
		return;		// key not found

	TCHAR szKeyValue[100]; 
	memset(szKeyValue, 0, sizeof(szKeyValue));
	DWORD dwType = REG_SZ; 
	DWORD dwSize = 100;

	lresult = RegQueryValueEx(NewKey, L"FullInstallVer", 
		NULL, &dwType, (LPBYTE)szKeyValue, &dwSize);

	if (lresult != ERROR_SUCCESS)
	{
		memset(szKeyValue, 0, sizeof(szKeyValue));
		DWORD dwType = REG_SZ; 
		DWORD dwSize = 100;

		lresult = RegQueryValueEx(NewKey, L"Version", 
			NULL, &dwType, (LPBYTE)szKeyValue, &dwSize);
	}

	if (lresult == ERROR_SUCCESS && dwSize != 0)
		_stscanf(szKeyValue, L"%d.%d.%d.%d", &m_dwADOMajor, &m_dwADOMinor, &m_dwADOBuild, &m_dwADOSomething);

	RegCloseKey(NewKey);
}
#endif

//
// Does the current user have administrator rights ?
//
void CSysInfo::DetectUserAdmin()
{
	if (!IsWindowsNT())
	{
		m_bUserAdmin=TRUE;
		return;
	}

	HANDLE hAccessToken       = NULL;
	PBYTE  pInfoBuffer        = NULL;
	DWORD  dwInfoBufferSize   = 1024;
	PTOKEN_GROUPS ptgGroups   = NULL;
	PSID   psidAdministrators = NULL;
	SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
	//BOOL   bResult = FALSE;

	__try
	{
		// init security token
		if( !AllocateAndInitializeSid( 
			&siaNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, 
			DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdministrators ) )
			__leave;

		// for Windows NT 4.0 only
		if( !OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hAccessToken ) )
			__leave;

		do
		{
			if( pInfoBuffer )
				delete[] pInfoBuffer; //>>> WiZaRd::Memleak FiX
			pInfoBuffer = new BYTE[dwInfoBufferSize];
			if( !pInfoBuffer )
				__leave;
			SetLastError( 0 );
			if( !GetTokenInformation( 
				hAccessToken, 
				TokenGroups, pInfoBuffer, 
				dwInfoBufferSize, &dwInfoBufferSize ) &&
				( ERROR_INSUFFICIENT_BUFFER != GetLastError() )
				)
				__leave;
			else
				ptgGroups = (PTOKEN_GROUPS)pInfoBuffer;
		}
		while( GetLastError() );

		for(UINT i = 0; i < ptgGroups->GroupCount; ++i)
		{
			if( EqualSid(psidAdministrators, ptgGroups->Groups[i].Sid) )
			{
				m_bUserAdmin=TRUE;
				__leave;
			}
		} 
	}

	__finally
	{
		if( hAccessToken )
			CloseHandle( hAccessToken );
		if( pInfoBuffer )
			delete[] pInfoBuffer; //>>> WiZaRd::Memleak FiX
		if( psidAdministrators )
			FreeSid( psidAdministrators );
	}
}

BOOL CSysInfo::GetFileInfo(LPCTSTR lpszFileName, DWORD *v_major, DWORD *v_minor, 
						   DWORD *v_build, DWORD *v_something, DWORD *size)
{
	*v_major=0; *v_minor=0; *v_build=0; *v_something=0; *size=0;
	if (lpszFileName==NULL) return FALSE;

	DWORD InfoSize;
	VS_FIXEDFILEINFO  fileinfo;
	VS_FIXEDFILEINFO  *fi;
	fi=&fileinfo;
	UINT size_fileinfo; size_fileinfo=sizeof(fileinfo);

	LPTSTR lpFileName; int i=0; i=_tcslen(lpszFileName);
	if (i>0)
	{
		// Convert LPCTSTR to LPTSTR
		lpFileName=new TCHAR[i+1];
		memset(lpFileName, 0, i+1);
		_tcscpy(lpFileName, lpszFileName);
	}
	else
		return FALSE;

	InfoSize=GetFileVersionInfoSize(lpFileName, 0);
	if (InfoSize>0)
	{
		LPVOID lpVoid;
		lpVoid=malloc(InfoSize);
		memset(lpVoid, 0, InfoSize);
		if (GetFileVersionInfo(lpFileName, NULL, InfoSize, lpVoid))
		{
			if (VerQueryValue(lpVoid, L"\\", (LPVOID *)&fi, &size_fileinfo))
			{	
				*v_major=((fi->dwFileVersionMS>>16) & 0x0000FFFF);
				*v_minor=(fi->dwFileVersionMS & 0x0000FFFF);
				*v_build=((fi->dwFileVersionLS>>16) & 0x0000FFFF);
				*v_something=(fi->dwFileVersionLS & 0x0000FFFF);
			}
		}
		free(lpVoid);
		delete[] lpFileName; //>>> WiZaRd::Memleak FiX
	}
	else
	{
		delete[] lpFileName; //>>> WiZaRd::Memleak FiX
		return FALSE;
	}

	// Get file size
	WIN32_FIND_DATA fdata; HANDLE hFile;

	hFile=FindFirstFile(lpszFileName, &fdata);
	if (hFile!=INVALID_HANDLE_VALUE)
	{
		*size=fdata.nFileSizeLow;
		FindClose(hFile);
		return TRUE;
	}
	else
		return FALSE;
}

//
// Get file information in the explicit system directory (e.g. c:\winnt\system32)
//
BOOL CSysInfo::GetSystemFileInfo(LPCTSTR lpszFileName, DWORD *v_major, DWORD *v_minor, 
								 DWORD *v_build, DWORD *v_something, DWORD *size)
{
	*v_major=0; *v_minor=0; *v_build=0; *v_something=0; *size=0;

	CString str;
	TCHAR	szSysDirectory[100];
	int i=GetSystemDirectory(szSysDirectory, 50);
	if (i==0) return FALSE;
	str.Format(L"%s\\%s", szSysDirectory, lpszFileName);
	if (GetFileInfo((LPCTSTR)str, v_major, v_minor, v_build, v_something, size)) return TRUE;
	return FALSE;
}

void CSysInfo::DetectLoginUserName()
{
	DWORD dwSize = 100;
	LPTSTR pStr = m_sUserName.GetBuffer(150);
	GetUserName(pStr, &dwSize);
	m_sUserName.ReleaseBuffer();
}

void CSysInfo::DetectWorkingDir()
{
	LPTSTR pStr = m_sWorkingDir.GetBuffer(250);
	DWORD dwRes=::GetModuleFileName(NULL, pStr, 200);
	m_sWorkingDir.ReleaseBuffer();
	if (dwRes != 0)
	{
		int i=m_sWorkingDir.ReverseFind('\\');
		if (i != -1) 
			m_sWorkingDir = m_sWorkingDir.Left(i+1);
	}
}

//
// Detect the size of the current process
//
DWORD CSysInfo::GetProcessMemoryUsage()
{
	if (m_GetProcessMemoryInfo!=NULL)
	{
		// Get a handle to the process.
		HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, _getpid());
		if (hProcess)
		{
			m_GetProcessMemoryInfo(hProcess, &m_ProcMemCounters, sizeof(m_ProcMemCounters));
			CloseHandle(hProcess);
			DWORD f = (DWORD)((m_ProcMemCounters.WorkingSetSize)/1024);
			return f;
		}
		else
			return 0;
	}
	else
		return 0;
}

//
// Detect memory sizes
//
void CSysInfo::DetectMemory()
{
	if (IsWindowsNT() && m_dwWinMajor > 4)
	{
		// Windows 2000+. Use GlobalMemoryStatusEx to detect memory size more than 4GB
		MEMORYSTATUSEX MemStatEx;
		memset(&MemStatEx, 0, sizeof(MemStatEx));
		MemStatEx.dwLength = sizeof(MemStatEx);

		HMODULE hmKernelDll;
		m_pGlobalMemoryStatusEx = NULL;
		BOOL bSuccess = FALSE;
		if((hmKernelDll=::LoadLibrary(L"kernel32.dll"))!=NULL)
		{
			m_pGlobalMemoryStatusEx=(pGlobalMemoryStatusEx)::GetProcAddress(hmKernelDll, "GlobalMemoryStatusEx");
			if (m_pGlobalMemoryStatusEx!=NULL)
			{
				if ((*m_pGlobalMemoryStatusEx)(&MemStatEx))
				{
					m_dwMemoryLoad=MemStatEx.dwMemoryLoad;
					m_dwTotalPhys=MemStatEx.ullTotalPhys;
					m_dwAvailPhys=MemStatEx.ullAvailPhys;
					m_dwTotalPageFile=MemStatEx.ullTotalPageFile;
					m_dwAvailPageFile=MemStatEx.ullAvailPageFile;
					m_dwTotalVirtual=MemStatEx.ullTotalVirtual;
					m_dwAvailVirtual=MemStatEx.ullAvailVirtual;
					bSuccess=TRUE;
				};
			};
			::FreeLibrary(hmKernelDll);
		};
		if (bSuccess) 
			return;
	}

	MEMORYSTATUS MemStat;
	memset(&MemStat, 0, sizeof(MemStat));
	MemStat.dwLength=sizeof(MemStat);

	GlobalMemoryStatus(&MemStat);
	m_dwMemoryLoad=MemStat.dwMemoryLoad;
	m_dwTotalPhys=MemStat.dwTotalPhys;
	m_dwAvailPhys=MemStat.dwAvailPhys;
	m_dwTotalPageFile=MemStat.dwTotalPageFile;
	m_dwAvailPageFile=MemStat.dwAvailPageFile;
	m_dwTotalVirtual=MemStat.dwTotalVirtual;
	m_dwAvailVirtual=MemStat.dwAvailVirtual;
}

time_t CSysInfo::GetUpTime()
{
	time_t now;
	time(&now);
	return (now-m_StartupTime);
}

#ifdef SYSINFO_USE_MIB
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
//
// Get Network Adapters Info with iphlpapi
//     (only for Windows 2000+ or Windows 98+)
//
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
void CSysInfo::DetectAdaptersIphlpapi()
{
	if (m_GetAdaptersInfo==NULL) return;

	// GetAdaptersInfo works only in Windows 2000+ or in Windows 98+
	if (IsWindowsNT())
	{ if (m_dwWinMajor<5) { m_bIphlpapiCompat=FALSE; return; } }
	else
	{ if (m_dwWinMinor<10) { m_bIphlpapiCompat=FALSE; return; } }

	m_bIphlpapiCompat=TRUE;

	if (m_bIphlpapiAllocated)
	{
		free(m_pai); m_bIphlpapiAllocated=FALSE;
	}

	ULONG t=0; m_pai=NULL;
	// Get memory size before calling GetAdaptersInfo()
	(*m_GetAdaptersInfo)(m_pai, &t);

	// Allocate memory for GetAdaptersInfo()
	m_pai=(PIP_ADAPTER_INFO)malloc(t+1);

	if (m_pai!=NULL)
	{
		m_bIphlpapiAllocated=TRUE;
		memset(m_pai, 0, t+1);
		// Call GetAdaptersInfo to obtain list of NICs
		DWORD r=(*m_GetAdaptersInfo)(m_pai, &t);
		if (r==ERROR_SUCCESS)
		{
			m_bIphlpapiObtained=TRUE;
			PIP_ADAPTER_INFO tmp_pai = m_pai;

			// Get number of NICs installed
			++m_nNumAdaptersIphlpapi;
			while (tmp_pai->Next!=NULL)
			{
				++m_nNumAdaptersIphlpapi;
				tmp_pai=tmp_pai->Next;
			}
		}
	}
}

LPCSTR CSysInfo::GetAPIAdapterDescr(int i)
{
	if (m_nNumAdaptersIphlpapi>0 && m_nNumAdaptersIphlpapi>i)
	{
		// Get pointer to the IP_ADDR_STRING structure of requested adapter
		int j = 0; 
		PIP_ADAPTER_INFO tmp_pai = m_pai;
		while (j!=i && tmp_pai != NULL)
		{
			++j; 
			tmp_pai = tmp_pai->Next;
		}

		// return pointer to the adapter description
		if (tmp_pai==NULL)
			return NULL;
		else
			return (LPCSTR)tmp_pai->Description;
	}
	else
		return NULL;
}

LPCSTR CSysInfo::GetAPIAdapterName(int i)
{
	if (m_nNumAdaptersIphlpapi>0 && m_nNumAdaptersIphlpapi>i)
	{
		// Get pointer to the IP_ADDR_STRING structure of requested adapter
		int j = 0; 
		PIP_ADAPTER_INFO tmp_pai = m_pai;
		while (j!=i && tmp_pai != NULL)
		{
			++j; 
			tmp_pai = tmp_pai->Next;
		}

		// return pointer to the adapter name
		if (tmp_pai==NULL)
			return NULL;
		else
			return (LPCSTR)tmp_pai->AdapterName;
	}
	else
		return NULL;
}

int CSysInfo::GetAPINumAddresses(int i)
{
	if ((m_nNumAdaptersIphlpapi>0) && (m_nNumAdaptersIphlpapi>i))
	{
		// Get pointer to the IP_ADDR_STRING structure of requested adapter
		int j = 0; 
		PIP_ADAPTER_INFO tmp_pai = m_pai;
		while (j!=i && tmp_pai != NULL)
		{
			++j; 
			tmp_pai = tmp_pai->Next;
		}

		if (tmp_pai!=NULL)
		{
			// walk to the ip address list to count all ip addresses of given adapter
			j=1; 
			PIP_ADDR_STRING pip = &(tmp_pai->IpAddressList);
			while (pip->Next!=NULL)
			{
				++j; 
				pip=pip->Next;
			}
			return j;
		}
		else
			return 0;
	}
	else
		return 0;
}

// This function returns the IP address of given adapter
// Incoming parameters:		index - zero-based index of network adapter
//							indexIP - zero-based index of IP address of network adapter
//
LPCSTR CSysInfo::GetAPIAdapterIPStr(int i, int indexIP)
{
	if (m_nNumAdaptersIphlpapi>0 && m_nNumAdaptersIphlpapi>i)
	{
		// Get pointer to the IP_ADDR_STRING structure of requested adapter
		int j = 0; 
		PIP_ADAPTER_INFO tmp_pai = m_pai;
		while (j!=i && tmp_pai != NULL)
		{
			++j; 
			tmp_pai = tmp_pai->Next;
		}

		if (tmp_pai!=NULL)
		{
			// tmp_pai contains pointer to the IP_ADAPTER_INFO structure
			j=0; 
			PIP_ADDR_STRING pip = &(tmp_pai->IpAddressList);
			int a=GetAPINumAddresses(i);
			if (a>0 && a>indexIP)
			{
				while (j!=indexIP && pip != NULL)
				{
					++j; 
					pip = pip->Next;
				}

				if (pip!=NULL)
					return (LPCSTR)pip->IpAddress.String;
			}
		}
	}
	return NULL;
}

// This function returns the network mask of given adapter and IP address
// Incoming parameters:		index - zero-based index of network adapter
//							indexIP - zero-based index of IP address of network adapter
//
LPCSTR CSysInfo::GetAPIAdapterMaskStr(int i, int indexIP)
{
	if (m_nNumAdaptersIphlpapi>0 && m_nNumAdaptersIphlpapi>i)
	{
		// Get pointer to the IP_ADDR_STRING structure of requested adapter
		int j = 0; 
		PIP_ADAPTER_INFO tmp_pai = m_pai;
		while (j!=i && tmp_pai != NULL)
		{
			++j; 
			tmp_pai = tmp_pai->Next;
		}

		if (tmp_pai!=NULL)
		{
			// tmp_pai contains pointer to the IP_ADAPTER_INFO structure
			j=0; 
			PIP_ADDR_STRING pip = &(tmp_pai->IpAddressList);
			int a=GetAPINumAddresses(i);
			if (a>0 && a>indexIP)
			{
				while (j!=indexIP && pip != NULL)
				{
					++j; 
					pip = pip->Next;
				}

				if (pip!=NULL)
					return (LPCSTR)pip->IpMask.String;
			}
		}
	}
	return NULL;
}

DWORD CSysInfo::GetAPIAdapterIndex(int i)
{
	if (m_nNumAdaptersIphlpapi>0 && m_nNumAdaptersIphlpapi>i)
	{
		int j=0; 
		PIP_ADAPTER_INFO tmp_pai = m_pai;
		while (j!=i && tmp_pai != NULL)
		{
			++j; 
			tmp_pai = tmp_pai->Next;
		}

		if (tmp_pai!=NULL)
			return tmp_pai->Index;
	}
	return 0xFFFFFFFF;
}

BOOL CSysInfo::GetAPIAdapterSpeedStatus(int i, DWORD *pdwSpeed, DWORD *pdwStatus)
{
	// This function works only in Windows 98+ or in Windows NT 4.0 SP4+
	if (m_GetIfEntry!=NULL) 
	{
		DWORD AdapterIndex = GetAPIAdapterIndex(i);
		if (AdapterIndex!=0xFFFFFFFF)
		{
			MIB_IFROW ifrow;
			memset(&ifrow, 0, sizeof(MIB_IFROW));
			ifrow.dwIndex = AdapterIndex;

			if ((*m_GetIfEntry)(&ifrow)==NO_ERROR)
			{	
				*pdwSpeed=ifrow.dwSpeed;
				*pdwStatus=ifrow.dwOperStatus;
				return TRUE;
			}
		}
	}
	return FALSE;
}

/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
//
// Get Network Adapters Info with MIB
//
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
int CSysInfo::MIBRefreshAddresses()
{
	int nAddresses = 0; 
	BOOL bDiff = FALSE;

	for(int i = 0; i < MAX_IPADDRESSES; ++i)
		m_dwMIBIPArray_tmp[i]=0;

	nAddresses=m_mib.MIB_GetIPAddress(&m_dwMIBIPArray_tmp[0], MAX_IPADDRESSES, m_bMIBShowLoopback);
	if (m_nMIBAddresses!=nAddresses)
		bDiff=TRUE;
	else
	{
		for (int i = 0; i < nAddresses; ++i)
		{
			if (m_dwMIBIPArray[i]!=m_dwMIBIPArray_tmp[i])
			{
				bDiff=TRUE;
				break;
			}
		}
	}

	if (bDiff)
	{
		for(int i = 0; i < nAddresses; ++i)
			m_dwMIBIPArray[i]=m_dwMIBIPArray_tmp[i];
		m_nMIBAddresses=nAddresses;
	}

	return m_nMIBAddresses;
}

DWORD CSysInfo::GetMIBIP(int index)
{
	if (m_nMIBAddresses>index && index>=0)
		return m_dwMIBIPArray[index];
	return 0;
}

void CSysInfo::DetectAdaptersMIB()
{
	m_nMIBAdapters=m_mib.GetNICCount(TRUE, m_bMIBShowLoopback);

	if (m_bMIBAllocated)
	{
		free(m_pMIBAdapters);
		m_bMIBAllocated=FALSE;
	}

	if (m_nMIBAdapters>0)
	{
		// Allocate memory for GetNICInfo()
		m_pMIBAdapters=(tSTRUCTNICINFO *)malloc(sizeof(tSTRUCTNICINFO)*m_nMIBAdapters);
		if (m_pMIBAdapters!=NULL)
		{
			memset(m_pMIBAdapters, 0, sizeof(tSTRUCTNICINFO)*m_nMIBAdapters);
			m_bMIBAllocated=TRUE;
			m_mib.GetNICInfo(m_pMIBAdapters);
		}
	}
}

LPCSTR CSysInfo::GetMIBAdapterDescr(int i)
{
	if (m_nMIBAdapters<=0 || m_nMIBAdapters<=i || !m_bMIBAllocated)
		return NULL; 

	tSTRUCTNICINFO	*pInfo = m_pMIBAdapters;
	int j = i;
	while (j!=0)
	{ 
		++pInfo; 
		--j; 
	}

	return (LPCSTR)&pInfo->Description[0];
}

void CSysInfo::GetMIBAdapterIPStr(int i, LPTSTR lpIPStr)
{
	if (m_nMIBAdapters<=0 || m_nMIBAdapters<=i || !m_bMIBAllocated)
		return;

	tSTRUCTNICINFO	*pInfo = m_pMIBAdapters;
	int j = i;

	while (j!=0)
	{ 
		++pInfo; 
		--j; 
	}

	TCHAR szIPTmp[20]; 
	memset(szIPTmp, 0, 20);
	_stprintf(szIPTmp, L"%d.%d.%d.%d", pInfo->IP[0], pInfo->IP[1], pInfo->IP[2], pInfo->IP[3]);
	_tcscpy(lpIPStr, szIPTmp);
}

DWORD CSysInfo::GetMIBAdapterIPDword(int i)
{
	if (m_nMIBAdapters<=0 || m_nMIBAdapters<=i || !m_bMIBAllocated)
		return 0;

	tSTRUCTNICINFO* pInfo = m_pMIBAdapters;
	int j = i;

	while (j!=0)
	{ 
		++pInfo; 
		--j; 
	}

	return (pInfo->IP[0]<<24)+(pInfo->IP[1]<<16)+(pInfo->IP[2]<<8)+pInfo->IP[3];
}

void CSysInfo::GetMIBAdapterMaskStr(int i, LPTSTR lpMaskStr)
{
	if (m_nMIBAdapters<=0 || m_nMIBAdapters<=i || !m_bMIBAllocated)
		return;

	tSTRUCTNICINFO* pInfo = m_pMIBAdapters;
	int j = i;

	while (j!=0)
	{ 
		++pInfo; 
		--j;
	}

	TCHAR szMaskTmp[20]; 
	memset(szMaskTmp, 0, 20);
	_stprintf(szMaskTmp, L"%d.%d.%d.%d", pInfo->SubnetMask[0], pInfo->SubnetMask[1], pInfo->SubnetMask[2], pInfo->SubnetMask[3]);
	_tcscpy(lpMaskStr, szMaskTmp);
}

DWORD CSysInfo::GetMIBAdapterMaskDword(int i)
{
	if (m_nMIBAdapters<=0 || m_nMIBAdapters<=i || !m_bMIBAllocated)
		return 0;

	tSTRUCTNICINFO* pInfo = m_pMIBAdapters;
	int j = i;

	while (j!=0)
	{ 
		++pInfo; 
		--j;
	}

	return (pInfo->SubnetMask[0] << 24)+(pInfo->SubnetMask[1]<<16)+(pInfo->SubnetMask[2]<<8)+pInfo->SubnetMask[3];;
}

DWORD CSysInfo::GetMIBAdapterSpeed(int i)
{
	if (m_nMIBAdapters<=0 || m_nMIBAdapters<=i || !m_bMIBAllocated)
		return 0;

	tSTRUCTNICINFO* pInfo = m_pMIBAdapters;
	int j = i;

	while (j!=0)
	{ 
		++pInfo; 
		--j;
	}

	return pInfo->Speed;
}

DWORD CSysInfo::GetMIBAdapterOperStatus(int i)
{
	if (m_nMIBAdapters<=0 || m_nMIBAdapters<=i || !m_bMIBAllocated)
		return DWORD(-1); 

	tSTRUCTNICINFO* pInfo = m_pMIBAdapters;
	int j = i;

	while (j!=0)
	{ 
		++pInfo; 
		--j; 
	}

	return pInfo->OperStatus;
}

int CSysInfo::GetMIBAdapterType(int i)
{
	if (m_nMIBAdapters<=0 || m_nMIBAdapters<=i || !m_bMIBAllocated)
		return 0;

	tSTRUCTNICINFO* pInfo = m_pMIBAdapters;
	int j = i;

	while (j!=0)
	{ 
		++pInfo; 
		--j;
	}

	return pInfo->type;
}
#endif