#include "StdAfx.h"
#include "ApiHelper.h"

CWnd* CApiHelper::m_pParent = NULL;
BOOL CApiHelper::m_bInitialized = FALSE;

CApiHelper::CApiHelper(void)
{
	m_hWorkerThread = INVALID_HANDLE_VALUE;
	m_hWorkerThreadExit = INVALID_HANDLE_VALUE;
	m_hActionToDo = INVALID_HANDLE_VALUE;
	m_bInitialized = FALSE;
}

CApiHelper::~CApiHelper(void)
{
	TBD_FUNCTION(CApiHelper::~CApiHelper);

	// kill worker thread
	if (m_hWorkerThread != INVALID_HANDLE_VALUE && m_hWorkerThreadExit != INVALID_HANDLE_VALUE)
	{
		SetEvent(m_hWorkerThreadExit);

		// kill read thread
		if (WAIT_OBJECT_0 != WaitForSingleObject(m_hWorkerThread, INFINITE))
		{
			// Failed to die.

		}

		CloseHandle(m_hWorkerThread);
		m_hWorkerThread = NULL;
		CloseHandle(m_hWorkerThreadExit);
	}

	// close handles
	CloseHandle(m_hActionToDo);
}

BOOL CApiHelper::Initialize(CWnd* pParent)
{
	TBD_FUNCTION(CApiHelper::Initialize);

	if (m_hWorkerThread != INVALID_HANDLE_VALUE)
	{
		TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, L"Worker thread already exists");
		m_bInitialized = TRUE;
		return TRUE;
	}

	// Initialize worker thread
	m_hWorkerThreadExit = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (!m_hWorkerThreadExit)
	{
		return FALSE;
	}

	m_hActionToDo = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (!m_hActionToDo)
	{
		return FALSE;
	}

	m_hWorkerThread = CreateThread(NULL, 0 , WorkerThreadProc, (LPVOID)this, 0, NULL);

	if (!m_hWorkerThread)
	{
		return FALSE;
	}

	// cache parent handle
	m_pParent = pParent;

	m_bInitialized = TRUE;

	return TRUE;
}

DWORD WINAPI CApiHelper::WorkerThreadProc(void* pParam)
{
	CApiHelper* pThis = (CApiHelper*)pParam;

	return pThis->WorkerThread();
}

DWORD CApiHelper::WorkerThread()
{
	TBD_FUNCTION(CApiHelper::WorkerThread);

	// establish array of handles to wait on
	HANDLE arhWaitHandles [] = { m_hWorkerThreadExit, m_hActionToDo };

	while (true)
	{
		if (WaitForMultipleObjects(2, arhWaitHandles, FALSE, INFINITE) == WAIT_OBJECT_0)
		{
			// exit event signaled
			return 0;
		}
		else
		{
			// action event signaled
			TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, L"Action event signaled");
			m_pParent->PostMessage(WM_USER_ExecutionComplete, Execute(), NULL);
		}
	}

	return 0;
}

FARPROC WINAPI GetProcAddress_W(__in HMODULE hModule, __in LPWSTR lpProcName)
{
#ifndef UNDER_CE
	const int nAsciiLen = 256;
	CHAR szAscii[nAsciiLen] =  "";

	WideCharToMultiByte(CP_ACP, 0, lpProcName, -1, szAscii, nAsciiLen, 0, 0);

	return GetProcAddress(hModule, szAscii);
#else
	return GetProcAddress(hModule, lpProcName);
#endif
}