/************************************************************************/
/*      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"

// Contrib - Vista sensing fix
#include "Log.h"
// <-------- Vista sensing fix

// Contrib - GetProcessTimes
//#include "./EMF/GetCpuUsage.h"
// <-------- GetProcessTimes

#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 "Windows 95"
#define W98_s "Windows 98"
#define WME_s "Windows ME"
#define NT4_s "Windows NT 4.0"
#define WKS_s " Workstation"
#define WXP_s "Windows XP"
#define XHE_s " Home Edition"
#define XPR_s " Professional Edition"
#define WVI_s "Windows Vista"
#define W2K_s "Windows 2000"
#define PRO_s " Professional"
#define DOM_s " Domain Controller"
#define SER_s " Server"
#define ADV_s " Advanced"
#define DTC_s " DataCenter"
#define TER_s " Terminal"
#define BOF_s " BackOffice"

#define IE_CONFIGURATION_KEY "SOFTWARE\\Microsoft\\Internet Explorer"
#define CPU_CONFIGURATION_KEY "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"
#define ADO_CONFIGURATION_KEY "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;
*/

//////////////////////////////////////////////////////////////////////
// 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()
{

// Contrib - GetProcessTimes
//	GetCpuUsage(theApp.m_pszExeName); //call once on init to avoid ugly lag on first call
// <-------- GetProcessTimes

	// Init routines. It must be called before getting system information.
#ifdef SYSINFO_USE_MIB
	m_hmIphlpapiDll = NULL;
	m_nNumAdaptersIphlpapi=0;
	if((m_hmIphlpapiDll=::LoadLibrary(_T("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(_T("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();

// By Taz - track eMule mem usage
#ifdef TRACK_MEM
	m_dwEmulePeakMemory = 0;
	m_dwEmuleVirtual = 0;
	m_dwEmulePeakVirtual = 0;
#endif
// <------- track eMule mem usage

}

//
//  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=_T(W95_s); };
		if (m_dwWinMinor==10) { m_sOSType=_T(W98_s); };
		if (m_dwWinMinor==90) { m_sOSType=_T(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,_T("%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=_T(NT4_s);
	}

// Contrib - Vista sensing fix
//>> pP: VistaFix
/*
	else
	{
		if (m_dwWinMajor>=5)
		{
			if (m_dwWinMinor==0)
				m_sOSType=_T(W2K_s);  // Windows 2000
			else if (m_dwWinMinor==1)
				m_sOSType=_T(WXP_s);  // Windows XP
			else if (m_dwWinMinor==1)
				m_sOSType=_T(WVI_s);  // Windows Vista+Longhorn Server
		};
	};
*/
	else if (m_dwWinMajor==5)
	{
		if (m_dwWinMinor==0)
			m_sOSType=_T(W2K_s);  // Windows 2000
		else if (m_dwWinMinor==1)
			m_sOSType=_T(WXP_s); // Windows XP
	}
	// pp // Windows Vista
	else if (m_dwWinMajor>=6){
		CString sProduct, sService;
		bOSINFOEXWorking=false; // skip extended info, not supported for Vista anyways
		sProduct = GetRegKeyVista(L"ProductName");
		sService = GetRegKeyVista(L"CSDVersion");
		if (!sProduct.IsEmpty())
			m_sOSType.Format(L"%s %s", sProduct, sService.IsEmpty()?L"":sService);
		else
			m_sOSType.Format(L"Microsoft Windows %u.%u, unknown version", m_dwWinMajor, m_dwWinMinor);
	}
//<< pP: VistaFix
// <-------- Vista sensing fix

	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+=_T(XHE_s); }
					else
					{ m_sOSType+=_T(XPR_s); };
				};

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

				if (osvi.dwMajorVersion==4)
				{
					// Windows NT 4.0 Workstation
					m_sOSType+=_T(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+=_T(ADV_s); };
					if (osvi.wSuiteMask & VER_SUITE_DATACENTER) { m_sOSType+=_T(DTC_s); };
					if (osvi.wSuiteMask & VER_SUITE_TERMINAL) { m_sOSType+=_T(TER_s); };
					if (osvi.wSuiteMask & VER_SUITE_BACKOFFICE) { m_sOSType+=_T(BOF_s); };
					m_sOSType+=_T(SER_s);
				};
				if (osvi.dwMajorVersion==4 && osvi.dwMinorVersion==0) { m_sOSType+=_T(SER_s); };
			};

			if (osvi.wProductType==VER_NT_DOMAIN_CONTROLLER)
			{ m_sOSType+=_T(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, _T(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,_T("Version"),NULL,&dwType,
		(LPBYTE)szKeyValue,&dwSize);

	RegCloseKey(NewKey);

	if (lresult == ERROR_SUCCESS && dwSize != 0)
		_stscanf(szKeyValue,_T("%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, _T(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, _T("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, _T("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, _T("ProcessorNameString"),
		NULL, &dwType, (LPBYTE)szKeyValue, &dwSize);

	if (lresult == ERROR_SUCCESS && dwSize != 0){
		TCHAR trim[] = TEXT(" ");
		StrTrim(szKeyValue, trim);
		m_sCPUNameString = szKeyValue;
	}

	DWORD dwData = 0;
	dwType = REG_DWORD;
	dwSize = sizeof(dwData);
	lresult = RegQueryValueEx(NewKey, _T("~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, _T(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, _T("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, _T("Version"),
			NULL, &dwType,(LPBYTE)szKeyValue, &dwSize);
	};

	if (lresult == ERROR_SUCCESS && dwSize != 0)
		_stscanf(szKeyValue,_T("%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,_T("\\"),(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(_T("%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);

// By Taz - track eMule mem usage
#ifdef TRACK_MEM
			m_dwEmulePeakMemory = (DWORD)((m_ProcMemCounters.PeakWorkingSetSize) >> 10);

//			m_dwEmuleVirtual = (DWORD)((m_ProcMemCounters.PagefileUsage));
//			m_dwEmulePeakVirtual = (DWORD)((m_ProcMemCounters.PeakPagefileUsage));

			MEMORYSTATUSEX statex;

			statex.dwLength = sizeof (statex);
			if (GlobalMemoryStatusEx (&statex) != 0) {
				m_dwEmuleVirtual = (DWORD)((statex.ullTotalVirtual - statex.ullAvailVirtual) >> 10);
				if (m_dwEmuleVirtual > m_dwEmulePeakVirtual)
					m_dwEmulePeakVirtual = m_dwEmuleVirtual;
			}
#endif
// <------- track eMule mem usage

			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(_T("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,_T("%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; pInfo=m_pMIBAdapters;
	int j = i;

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

	DWORD dwIP=0, dwTmp;

	dwTmp=pInfo->IP[0];
	dwIP=dwTmp<<24;
	dwTmp=pInfo->IP[1];
	dwIP=dwIP+(dwTmp<<16);
	dwTmp=pInfo->IP[2];
	dwIP=dwIP+(dwTmp<<8);
	dwTmp=pInfo->IP[3];
	dwIP=dwIP+dwTmp;

	return dwIP;
}

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

	tSTRUCTNICINFO	*pInfo; pInfo=m_pMIBAdapters;
	int j = i;

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

	TCHAR szMaskTmp[20]; memset(szMaskTmp,0,20);
	_stprintf(szMaskTmp,_T("%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; pInfo=m_pMIBAdapters;
	int j = i;

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

	DWORD dwIP=0, dwTmp;

	dwTmp=pInfo->SubnetMask[0];
	dwIP=dwTmp<<24;
	dwTmp=pInfo->SubnetMask[1];
	dwIP=dwIP+(dwTmp<<16);
	dwTmp=pInfo->SubnetMask[2];
	dwIP=dwIP+(dwTmp<<8);
	dwTmp=pInfo->SubnetMask[3];
	dwIP=dwIP+dwTmp;

	return dwIP;
}

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

	tSTRUCTNICINFO	*pInfo; 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; 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; pInfo=m_pMIBAdapters;
	int j = i;

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

// Contrib - Vista sensing fix
//>> pP: VistaFix
CString CSysInfo::GetRegKeyVista(CString sKey)
{
	// get the WinVer from registry
	int long lnResult;
	HKEY hKey=NULL;
	LPCTSTR lpSubKey = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
	lnResult=RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, &hKey);

	if(!hKey){
#ifdef _DEBUG
		AddLogLine(0, L"RegOpenKeyEx failed (%s)", sKey);
#endif
		return L"";
	}

	DWORD dwType;
	TCHAR szValue[100];
	DWORD dwSize = sizeof(szValue)*sizeof(TCHAR);
	LONG lRet = RegQueryValueEx(hKey, sKey, NULL, &dwType, (LPBYTE) szValue, &dwSize);

	if ((lRet == ERROR_SUCCESS) && ( (dwType == REG_SZ) || (dwType == REG_EXPAND_SZ))){
#ifdef _DEBUG
		AddLogLine(0, L"RegQueryValueEx (%s) returned '%s'", sKey, szValue);
#endif
		return (CString)szValue;
	}
	AddLogLine(0, L"RegQueryValueEx failed (%s)", sKey);
	return L"";
}
//<< pP: VistaFix
// <-------- Vista sensing fix
