// RTHMSharedMemorySampleDlg.cpp : implementation file
//
// created by Unwinder
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "RTHMSharedMemorySample.h"
#include "RTHMSharedMemorySampleDlg.h"

#include <float.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
/////////////////////////////////////////////////////////////////////////////
class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}
/////////////////////////////////////////////////////////////////////////////
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}
/////////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CRTHMSharedMemorySampleDlg dialog
/////////////////////////////////////////////////////////////////////////////
CRTHMSharedMemorySampleDlg::CRTHMSharedMemorySampleDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CRTHMSharedMemorySampleDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CRTHMSharedMemorySampleDlg)
	m_strStatus = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	m_hMapFile = NULL;
	m_pMapAddr = NULL;
	m_nTimerID = NULL;
}
/////////////////////////////////////////////////////////////////////////////
void CRTHMSharedMemorySampleDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CRTHMSharedMemorySampleDlg)
	DDX_Text(pDX, IDC_STATUS, m_strStatus);
	//}}AFX_DATA_MAP
}
/////////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CRTHMSharedMemorySampleDlg, CDialog)
	//{{AFX_MSG_MAP(CRTHMSharedMemorySampleDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_TIMER()
	ON_WM_DESTROY()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CRTHMSharedMemorySampleDlg message handlers
/////////////////////////////////////////////////////////////////////////////
BOOL CRTHMSharedMemorySampleDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	SetIcon(m_hIcon, TRUE);			// Set big icon
	
	m_nTimerID = SetTimer(0x1234, 1000, NULL);

	return TRUE;  // return TRUE  unless you set the focus to a control
}
/////////////////////////////////////////////////////////////////////////////
void CRTHMSharedMemorySampleDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}
/////////////////////////////////////////////////////////////////////////////
// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.
/////////////////////////////////////////////////////////////////////////////
void CRTHMSharedMemorySampleDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}
/////////////////////////////////////////////////////////////////////////////
// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
/////////////////////////////////////////////////////////////////////////////
HCURSOR CRTHMSharedMemorySampleDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}
/////////////////////////////////////////////////////////////////////////////
// This function is used to connect to RivaTuner hardware monitoring
// shared memory
/////////////////////////////////////////////////////////////////////////////
void CRTHMSharedMemorySampleDlg::Connect()
{
	Disconnect();
		//we must disconnect from the previously connected shared memory before
		//connecting to new one

	m_hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "RTHMSharedMemory");

	if (m_hMapFile)
		m_pMapAddr = MapViewOfFile(m_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
}
/////////////////////////////////////////////////////////////////////////////
// This function is used to disconnection from RivaTuner hardware monitoring
// shared memory
/////////////////////////////////////////////////////////////////////////////
void CRTHMSharedMemorySampleDlg::Disconnect()
{
	if (m_pMapAddr)
		UnmapViewOfFile(m_pMapAddr);

	m_pMapAddr = NULL;

	if (m_hMapFile)
		CloseHandle(m_hMapFile);

	m_hMapFile = NULL;
}
/////////////////////////////////////////////////////////////////////////////
// we'll update sample's window on timer once per second
/////////////////////////////////////////////////////////////////////////////
void CRTHMSharedMemorySampleDlg::OnTimer(UINT nIDEvent) 
{
	//if we're not connected to RivaTuner hardware monitoring shared memory yet - do it now

	if (!m_pMapAddr)
		Connect();

	if (m_pMapAddr)
		//if we're connected to shared memory, we must check if it is valid or not
	{
		LPRTHM_SHARED_MEMORY_HEADER_V_1_0 lpHeaderV10	= (LPRTHM_SHARED_MEMORY_HEADER_V_1_0)m_pMapAddr;

		if (lpHeaderV10->dwSignature == 0xDEAD)
			//if the memory is marked as dead (e.g. RivaTuner was unloaded), we should disconnect from it and
			//try to connect again
			Connect();
	}

	if (m_pMapAddr)
	{
		LPRTHM_SHARED_MEMORY_HEADER_V_1_0	lpHeaderV10	= (LPRTHM_SHARED_MEMORY_HEADER_V_1_0)m_pMapAddr;

		if (lpHeaderV10->dwSignature == 'RTHM')
			//check if we're connected to valid memory
		{
			CTime time(lpHeaderV10->time);
			CString strBuf = time.Format("%d-%m-%Y %H:%M:%S");
				//format data polling time

			DWORD dwSources = lpHeaderV10->dwNumEntries;
				//get number of data sources

			m_strStatus.Format("Connected to RTHM shared memory v%d.%d\n\n%d data source(s) have been polled on %s\n\n", lpHeaderV10->dwVersion>>16, lpHeaderV10->dwVersion & 0xffff, dwSources, strBuf);

			for (DWORD dwSource=0; dwSource<dwSources; dwSource++)
				//display info for each data source
			{
				if (lpHeaderV10->dwVersion == 0x10000)
					//we must use special handling code for shared memory v1.0, because entry size field (which is 
					//reuiqred for unified access to entries) was added to header in v1.1 only
				{
					LPRTHM_SHARED_MEMORY_ENTRY_V_1_0 lpEntry = (LPRTHM_SHARED_MEMORY_ENTRY_V_1_0)((LPBYTE)(lpHeaderV10 + 1) + dwSource * sizeof(RTHM_SHARED_MEMORY_ENTRY_V_1_0));
						//get ptr to  the current data source's entry

					//display data source's info

					if (lpEntry->data == FLT_MAX)
						strBuf.Format("%-32s\t : N/A\n", lpEntry->czSrc);
					else
						strBuf.Format("%-32s\t : %.1f %s\n", lpEntry->czSrc, lpEntry->data, lpEntry->czDim);
				}
				else
				{
					LPRTHM_SHARED_MEMORY_HEADER	lpHeader	= (LPRTHM_SHARED_MEMORY_HEADER)m_pMapAddr;
					LPRTHM_SHARED_MEMORY_ENTRY	lpEntry		= (LPRTHM_SHARED_MEMORY_ENTRY)((LPBYTE)(lpHeader + 1) + dwSource * lpHeader->dwEntrySize);
						//get ptr to the current data source's entry

					CString strSrc;

					//display data source's info

					if (lpEntry->offset == 0.0f)
						strSrc = lpEntry->czSrc;
					else
						strSrc.Format("%s (%+.1f)", lpEntry->czSrc, lpEntry->offset);
		
					if (lpEntry->data == FLT_MAX)
						strBuf.Format("%-32s\t : N/A", lpEntry->czSrc);
					else
						strBuf.Format("%-32s\t : %.1f %s", strSrc, lpEntry->dataTransformed + lpEntry->offset, lpEntry->czDim);

					if (lpEntry->flags & RTHM_SHARED_MEMORY_ENTRY_FLAG_SHOW_IN_ICON)
						strBuf += ", in icon";

					if (lpEntry->flags & RTHM_SHARED_MEMORY_ENTRY_FLAG_SHOW_IN_TOOLTIP)
						strBuf += ", in tooltip";

					if (lpEntry->flags & RTHM_SHARED_MEMORY_ENTRY_FLAG_SHOW_IN_OSD)
						strBuf += ", in OSD";

					strBuf += "\n";
				}

				m_strStatus += strBuf;
			}
		}
		else
			m_strStatus = "Connected to uninitialized RTHM shared memory";
	}
	else
		m_strStatus = "Failed to connect to RTHM shared memory, please start RivaTuner and activate low-level hardware monitoring module";
	
	UpdateData(FALSE);

	CDialog::OnTimer(nIDEvent);
}
/////////////////////////////////////////////////////////////////////////////
void CRTHMSharedMemorySampleDlg::OnDestroy() 
{
	if (m_nTimerID)
		KillTimer(m_nTimerID);

	m_nTimerID = NULL;

	MSG msg; 
	while (PeekMessage(&msg, m_hWnd, WM_TIMER, WM_TIMER, PM_REMOVE));

	Disconnect();

	CDialog::OnDestroy();
}
/////////////////////////////////////////////////////////////////////////////
