/*
*********************************************************************
*
*	The Essence of OLE
*
*	Source code sample
*
*	Copyright (c) 1996, Rolling Thunder Computing, Ipswich MA
*
*	e-mail: essence@rollthunder.com
*	CompuServe: 73540,3430
*	Web: http://www.rollthunder.com
*
*	File Name: CELIZA.CPP
*
*	Purpose: Custom marshaling IMarshal interface for IEliza program
*
*********************************************************************
*/

#include <windows.h>

#include "celiza.h"

extern "C" void Eliza (TCHAR *InStr, TCHAR *OutStr) ;

DWORD __stdcall ThreadFunc (LPVOID lpVoid)
{
	CElizaServer *pEliza = (CElizaServer *) lpVoid ;

	for (;;)
	{

/*
Wait for client to set event
*/
		WaitForSingleObject (pEliza->m_hComplaintEvent, INFINITE) ;

/*
Event set, check first DWORD of shared file mapping.  If set to 1,
then that's the release.
*/

		if (*(DWORD *) pEliza->m_pSharedMem == 1)
		{
			pEliza->Release ( ) ;
			return 0 ;
		}
/*
If it isn't, then the 128 characters after the first DWORD contain the 
patient's complaint.  Pass that to Eliza, and have her put her reply
in the same buffer.  Set the event when done, the client should be waiting
on it.
*/
		else
		{
			pEliza->Complain (pEliza->m_pSharedMem+4, pEliza->m_pSharedMem+132) ;
			SetEvent (pEliza->m_hResponseEvent) ;
		}
	}
	return 0 ;
}


CElizaServer::CElizaServer (LPOLESTR lpStr)
{
	lstrcpy (m_ShareName, lpStr) ;
    m_RefCount = 1 ;  
    return;
}


CElizaServer::~CElizaServer(void)
{
	UnmapViewOfFile (m_pSharedMem) ;
	CloseHandle (m_hMap) ;
	CloseHandle	(m_hComplaintEvent) ;
	CloseHandle (m_hResponseEvent) ;
	CloseHandle (m_hThread) ;

	SendMessage (m_hWnd, WM_CLOSE, 0, 0) ;
    return;
}



STDMETHODIMP CElizaServer::QueryInterface(REFIID riid, LPVOID *ppv)
{
    if (riid == IID_IUnknown || riid == IID_IEliza)
	{
        *ppv = (LPVOID)	this;
		AddRef( ) ;
		return NOERROR;
	}

	else if (riid == IID_IMarshal)
	{
       *ppv = (LPMARSHAL) this ;
		AddRef( ) ;
		return NOERROR;
	}
	else
	{
    	*ppv = NULL ;
    	return E_NOINTERFACE ;
	}
        
}


STDMETHODIMP_(ULONG) CElizaServer::AddRef(void)
{
    return ++m_RefCount;
}


STDMETHODIMP_(ULONG) CElizaServer::Release(void)
{
	m_RefCount -- ;

    if (m_RefCount == 0)
	{
        delete this;
		return 0 ;
	}

    return m_RefCount ;
}


STDMETHODIMP CElizaServer::Complain (LPOLESTR pIn, LPOLESTR pOut)
{
	if (*pIn != 0x00)
	{
 		TCHAR out [256] ;
		wsprintf (out, TEXT("Client: %s%c%c"), pIn, 0x0D, 0x0A) ;
		SendMessage (m_hEdit, EM_SETSEL, (WPARAM) -1, (LPARAM)-1) ;
		SendMessage (m_hEdit, EM_REPLACESEL, 0, (LPARAM) out) ;

		Eliza (pIn, pOut) ;

		SendMessage (m_hEdit, EM_SETSEL, (WPARAM) -1, (LPARAM)-1) ;
		SendMessage (m_hEdit, EM_REPLACESEL, 0, (LPARAM) pOut) ;
	}
	return NOERROR ;
}


STDMETHODIMP CElizaServer::GetUnmarshalClass (REFIID riid, VOID* pVoid, DWORD dwDestCtx, VOID*, DWORD, 
	CLSID *pClsid )
{

/*
We only know how to marshall the IEliza interface.  Anything else is
an error.
*/
	if (riid != IID_IEliza && riid != IID_IUnknown)
	{
		*pClsid = IID_NULL ;
		return S_FALSE ;
	}
/*
This marshalling depends on running on the same machine.  If not,
fail with an error
*/

	if (dwDestCtx != MSHCTX_LOCAL)
	{
		TCHAR out [256] ;
		wsprintf (out, L"GetUnmarshalClass Fail dwDestCtx == 0x%x", dwDestCtx) ;
		MessageBox (NULL, out, L"", 0) ;

		*pClsid = IID_NULL ;
		return S_FALSE ;
	}
	 
/*
Return the class ID of the server that provides our proxy DLL
*/

	*pClsid = CLSID_ElizaProxy ;
	
	return S_OK ;

}

STDMETHODIMP CElizaServer::GetMarshalSizeMax (REFIID riid, VOID* pv, DWORD dwDestCtx, 
	VOID* pvReserved, DWORD dwFlags, DWORD *pSize)
{

	*pSize = sizeof(m_ShareName) ;
	return S_OK ;
}

STDMETHODIMP CElizaServer::MarshalInterface (IStream *pStream, REFIID riid, 
	VOID * pv, DWORD dwDestCtx, VOID *pvReserved, DWORD dwFlags)
{

/*
Write the name we will use for the file mapping and event into the
stream provided.  This is the marshaling packet that will be passed
to the client proxy.
*/

	pStream->Write (m_ShareName, sizeof(m_ShareName), NULL) ;

/*
Additional AddRef( ) on this object to make up for the lack of
a system-supplied stub.
*/

	AddRef( ) ;

/*
Create file mapping and map it into our address space
*/

	TCHAR out [256] ;
	wsprintf (out, TEXT("%sMap"), m_ShareName) ;

	m_hMap = CreateFileMapping ((HANDLE)-1, NULL, PAGE_READWRITE, 0, 1000, out) ;
	m_pSharedMem = (LPTSTR) MapViewOfFile (m_hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0) ;

/*
Create events that the client proxy will set to signal us that 
data has been placed in the shared RAM buffer.  Create a thread to
wait on the event.
*/

	wsprintf (out, TEXT("%sComplaintEvent"), m_ShareName) ;
	m_hComplaintEvent = CreateEvent (NULL, FALSE, FALSE, out) ;
	wsprintf (out, TEXT("%sResponseEvent"), m_ShareName) ;
	m_hResponseEvent = CreateEvent (NULL, FALSE, FALSE, out) ;

	m_hThread = CreateThread (NULL, 0, ThreadFunc, (LPVOID)this, 0, &m_ThreadID) ;

	return S_OK ;
}

STDMETHODIMP CElizaServer::UnmarshalInterface (IStream *pStream, REFIID riid, VOID **ppv)
{
	MessageBox (NULL, L"Unexpected UnmarshalInterface", L"", 0) ;
	return S_OK ;
}

STDMETHODIMP CElizaServer::ReleaseMarshalData (IStream *pStream)
{
	MessageBox (NULL, L"Unexpected ReleaseMarshalData", L"", 0) ;
	return S_OK ;
}

STDMETHODIMP CElizaServer::DisconnectObject (DWORD dwReserved)
{
	MessageBox (NULL, L"Unexpected DisconnectObject", L"", 0) ;
	return S_OK ;
}

