// SysMem.cpp : Defines the initialization routines for the DLL.
//
// created by Unwinder
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"

#include <float.h>
#include <shlwapi.h>
#include <afxdllx.h>
#include <winbase.h>
 
#include "SysMem.h"
#include "RivaTunerExports.h"
#include "MonitoringSourceDesc.h"
/////////////////////////////////////////////////////////////////////////////
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
static AFX_EXTENSION_MODULE SysMemDLL = { NULL, NULL };
/////////////////////////////////////////////////////////////////////////////
typedef struct MEMORYSTATUSEX 
{  
	DWORD		dwLength;  
	DWORD		dwMemoryLoad;  
	DWORDLONG	ullTotalPhys;  
	DWORDLONG	ullAvailPhys;  
	DWORDLONG	ullTotalPageFile;
	DWORDLONG	ullAvailPageFile;
	DWORDLONG	ullTotalVirtual;
	DWORDLONG	ullAvailVirtual;
	DWORDLONG	ullAvailExtendedVirtual;
} MEMORYSTATUSEX,  *LPMEMORYSTATUSEX;
/////////////////////////////////////////////////////////////////////////////
typedef BOOL (__stdcall * LPGLOBALMEMORYSTATUSEX)(LPMEMORYSTATUSEX lpBuffer);
/////////////////////////////////////////////////////////////////////////////
HINSTANCE					g_hModule						= 0;
LPGLOBALMEMORYSTATUSEX		g_pGlobalMemoryStatusEx			= NULL;
/////////////////////////////////////////////////////////////////////////////
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
	UNREFERENCED_PARAMETER(lpReserved);

	if (dwReason == DLL_PROCESS_ATTACH)
	{
		if (!AfxInitExtensionModule(SysMemDLL, hInstance))
			return 0;

		new CDynLinkLibrary(SysMemDLL);

		g_hModule = hInstance;
	}
	else if (dwReason == DLL_PROCESS_DETACH)
	{
		AfxTermExtensionModule(SysMemDLL);
	}
	return 1;
}
//////////////////////////////////////////////////////////////////////
// This exported function is called by RivaTuner to get a number of
// data sources in this plugin
//////////////////////////////////////////////////////////////////////
SYSMEM_API DWORD GetSourcesNum()
{
	return 2;
}
//////////////////////////////////////////////////////////////////////
// This exported function is called by RivaTuner to get descriptor
// for the specified data source
//////////////////////////////////////////////////////////////////////
SYSMEM_API BOOL GetSourceDesc(DWORD dwIndex, LPMONITORING_SOURCE_DESC pDesc)
{
	//get host application module handle

	HMODULE hHost = GetModuleHandle(NULL);
	if (!hHost)
		return FALSE;

	//we'll use this condition to verify if we're under RivaTuner v2.0 RC 15.7
	//(older versions are not supported) or any other compatible host

	GET_HOST_APP_ID_PROC pGetHostAppID = (GET_HOST_APP_ID_PROC)GetProcAddress(hHost, "GetHostAppID");
	if (!pGetHostAppID)
		return FALSE;

	g_pGlobalMemoryStatusEx = (LPGLOBALMEMORYSTATUSEX)GetProcAddress(LoadLibrary("kernel32.dll"), "GlobalMemoryStatusEx");

	switch (dwIndex)
	{
	case 0:
		strcpy(pDesc->szName	, "Physical memory usage");
		strcpy(pDesc->szDim		, "MB");
		if (pDesc->dwVersion >= 0x00010002)
			strcpy(pDesc->szGroup, "RAM");

		pDesc->fltMaxLimit	= 4096.0f;
		pDesc->fltMinLimit	= 0.0f;
		pDesc->fltGridDim	= 10.0f;

		if (g_pGlobalMemoryStatusEx)
			strcpy(pDesc->szDesc	, "Physical memory usage reported by GlobalMemoryStatusEx");
		else
			strcpy(pDesc->szDesc	, "Physical memory usage reported by GlobalMemoryStatus");

		return TRUE;
	case 1:
		strcpy(pDesc->szName	, "Page file usage");
		strcpy(pDesc->szDim		, "MB");
		if (pDesc->dwVersion >= 0x00010002)
			strcpy(pDesc->szGroup, "RAM");

		pDesc->fltMaxLimit	= 4096.0f;
		pDesc->fltMinLimit	= 0.0f;
		pDesc->fltGridDim	= 10.0f;

		if (g_pGlobalMemoryStatusEx)
			strcpy(pDesc->szDesc	, "Page file usage reported by GlobalMemoryStatusEx");
		else
			strcpy(pDesc->szDesc	, "Page file usage reported by GlobalMemoryStatus");

		return TRUE;
	}

	return FALSE;
}
//////////////////////////////////////////////////////////////////////
// This exported function is called by RivaTuner to get capabilities
// for the specified data source
//////////////////////////////////////////////////////////////////////
SYSMEM_API BOOL GetSourceCaps(DWORD dwIndex, DWORD dwCaps, LPDWORD lpResult)
{
	//all sources are system wide monitoring so it is safe to ignore passed
	//index and check just the capability

	switch (dwCaps)
	{
	case  MONITORING_SOURCE_CAPS_SYSTEM_WIDE:
		*lpResult = 1;
		return TRUE;
	}

	return FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// This exported function is called by RivaTuner to poll data sources
/////////////////////////////////////////////////////////////////////////////
SYSMEM_API FLOAT GetSourceData(DWORD dwIndex)
{
	if (g_pGlobalMemoryStatusEx)
	{
		MEMORYSTATUSEX status; 
		status.dwLength = sizeof(MEMORYSTATUSEX);

		g_pGlobalMemoryStatusEx(&status);

		switch (dwIndex)
		{
		case 0:
			return (__int64)(status.ullTotalPhys - status.ullAvailPhys) / 1048576.0f;
		case 1:
			return (__int64)(status.ullTotalPageFile - status.ullAvailPageFile) / 1048576.0f;
		}
	}
	else
	{
		MEMORYSTATUS status; 
		status.dwLength = sizeof(MEMORYSTATUS);

		GlobalMemoryStatus(&status);

		switch (dwIndex)
		{
		case 0:
			return (status.dwTotalPhys - status.dwAvailPhys) / 1048576.0f;
		case 1:
			return (status.dwTotalPageFile - status.dwAvailPageFile) / 1048576.0f;
		}
	}

	return FLT_MAX;
}
/////////////////////////////////////////////////////////////////////////////
