/*
*********************************************************************
*
*	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:	CHANLWND.CPP
*
*	Purpose: Main Window Response Function for Custon Interface Client
*
*********************************************************************
*/

#define _WIN32_DCOM

#include <windows.h>

#include "resource.h"
#include "elizacl.h"
#include "ieliza.h"
#include "idualeliza.h"
#include "itypelibmarshaledeliza.h"

extern HINSTANCE hInst ;

HWND hOutWnd, hInWnd, hSend ;

IEliza *pEliza = NULL ;
IDispatch *pDispEliza = NULL ;

CLSID CLSID_Eliza ;
CLSID CLSID_CustomEliza ;
CLSID CLSID_MfcEliza ;
CLSID CLSID_AutoElizaLocal ;
CLSID CLSID_AutoElizaInproc ;
CLSID CLSID_TypeLibMarshaled ;
CLSID CLSID_DualEliza ;

UINT nReps = 1000 ;
BOOL bUseEliza = FALSE ;
BOOL bUseDispatch = FALSE ;
BOOL bTypeLibMarshaled = FALSE ;
BOOL bDual = FALSE ;

DWORD dwLastElapsedMs = 0 ;

DispatchComplain (LPOLESTR pOut, LPOLESTR pIn)
{
	HRESULT hr ; 
	EXCEPINFO ei ;
	UINT uiErr ; 
	
	VARIANT vars [2] ;

	VariantInit (&vars[0]) ;
	VariantInit (&vars[1]) ;

/*
Allocate a BSTR for the complaint and another for the response.
Place in VARIANT structures.
*/

	BSTR Complaint = SysAllocString (pOut) ;
	BSTR Response = SysAllocString (L"ABCDE                             ") ;

	vars [1].pbstrVal = &Complaint ;
	vars [1].vt = VT_BSTR | VT_BYREF ;

	vars [0].pbstrVal = &Response ;
	vars [0].vt = VT_BSTR | VT_BYREF ;
 	
/*
Initialize parameter array.  Here it is empty.
*/
	DISPPARAMS dp ; 
	dp.rgvarg = vars ;
	dp.cArgs = 2 ;

	dp.rgdispidNamedArgs = NULL ;
	dp.cNamedArgs = 0 ;



/*
Call IDispatch::Invoke( )
*/
	hr = pDispEliza->Invoke (
		1,
		IID_NULL,
		LOCALE_SYSTEM_DEFAULT,
		DISPATCH_METHOD,
		&dp,
		NULL,
		&ei,
		&uiErr ) ;  
/*
Copy returned string and free BSTRS
*/

	lstrcpy (pIn, Response) ;
	SysFreeString (Complaint) ;
	SysFreeString (Response) ;

	return hr ;

}


LONG CALLBACK MainWndProc (HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{

	switch (Message)
	{
		case WM_CREATE:
		{
				
/*
Get class ID of Eliza object from registry by name.
*/

			HKEY hKey ;
			TCHAR StrClsId [128]; 
			LONG nActual = sizeof(StrClsId) ;
			LONG lOK ;

			RegOpenKey (HKEY_CLASSES_ROOT, TEXT("EssenceOfOle.Eliza"), &hKey) ;
			
			lOK = RegQueryValue (hKey, TEXT("CLSID"), StrClsId, &nActual) ;
			CLSIDFromString (StrClsId, &CLSID_Eliza) ;

			lOK = RegQueryValue (hKey, TEXT("Custom.CLSID"), StrClsId, &nActual) ;
			CLSIDFromString (StrClsId, &CLSID_CustomEliza) ;

			RegCloseKey (hKey) ;
/*
Get class IDs of MFC servers
*/
			CLSIDFromProgID (L"EssenceOfOle.Eliza.MfcCustomInProc", &CLSID_MfcEliza) ;
			CLSIDFromProgID (L"Mfclocau.Document", &CLSID_AutoElizaLocal) ;
			CLSIDFromProgID (L"EssenceOfOle.AutoElizaInproc", &CLSID_AutoElizaInproc) ;
			CLSIDFromProgID (L"EssenceOfOle.DualEliza", &CLSID_DualEliza) ;
			CLSIDFromProgID (L"EssenceOfOle.TypeLibMarshaledEliza", &CLSID_TypeLibMarshaled) ;

/*
Create windows to record conversations
*/

			hOutWnd = CreateWindow (TEXT("edit"), TEXT(""), 
				WS_CHILD | WS_BORDER | WS_VISIBLE | ES_AUTOHSCROLL,
				20, 30, 450, 30, 
				hWnd, (HMENU) IDC_OUTGOING, hInst, NULL) ;
			SetFocus (hOutWnd) ;

			hInWnd = CreateWindow (TEXT("edit"), TEXT(""),
				WS_CHILD | WS_BORDER | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY,
				20, 90, 450, 200,
				hWnd, (HMENU) IDC_INCOMING, hInst, NULL) ;

			hSend = CreateWindow (TEXT("button"), TEXT("&Send"), 
				WS_CHILD |  WS_VISIBLE | WS_DISABLED | BS_PUSHBUTTON,
				500, 30, 60, 20,
				hWnd, (HMENU) IDC_SEND, hInst, NULL) ;

			return 0 ;

		}

		case WM_COMMAND:
		{
			switch (LOWORD(wParam))
			{

				case ID_ELIZA_CREATEINPROC:
				{
					HRESULT hr ;

					hr = CoCreateInstance (
						CLSID_Eliza, 	// Eliza object ID from registry
						NULL, 			// no aggregation
						CLSCTX_INPROC_SERVER, 	// in-proc server
						IID_IEliza,		// IEliza custom interface ID
						(LPVOID *) &pEliza) ;	// output variable

					if (!SUCCEEDED(hr))
					{
						MessageBox (hWnd, TEXT("Couldn't create in-proc Eliza"), TEXT("Error"), MB_ICONSTOP) ;
					}
					else
					{
						EnableWindow (hSend, TRUE) ;
					}
					return 0 ;
				}

				case ID_ELIZA_CREATELOCAL:
				{
					HRESULT hr ;

					hr = CoCreateInstance (
						CLSID_Eliza, 	// Eliza object ID
						NULL, 			// no aggregation
						CLSCTX_LOCAL_SERVER, 	// local server
						IID_IEliza,		// IEliza custom interface ID
						(LPVOID *) &pEliza) ;	// output variable

					if (!SUCCEEDED(hr))
					{
						MessageBox (hWnd, TEXT("Couldn't create local Eliza"), TEXT("Error"), MB_ICONSTOP) ;
					}
					else
					{
						EnableWindow (hSend, TRUE) ;
					}
					return 0 ;
				}

				case ID_ELIZA_CREATECUSTOMMARHSALING:
				{
					HRESULT hr ;


					IClassFactory *pcf ;

					hr = CoGetClassObject (
						CLSID_CustomEliza, 		// Eliza object ID
						CLSCTX_LOCAL_SERVER, 	// local server
						NULL,
						IID_IClassFactory,
						(LPVOID*)&pcf) ;

					hr = pcf->CreateInstance (NULL, IID_IEliza, (LPVOID *)&pEliza) ;
					pcf->Release( ) ;

					if (!SUCCEEDED(hr))
					{
						MessageBox (hWnd, TEXT("Couldn't create local Custom Eliza"), TEXT("Error"), MB_ICONSTOP) ;
					}
					else
					{
						EnableWindow (hSend, TRUE) ;
					}
					return 0 ;
				}

			
				case ID_ELIZA_CREATEMFCINPROC:
				{
					HRESULT hr ;

					hr = CoCreateInstance (
						CLSID_MfcEliza, 			// Eliza object ID
						NULL, 					// no aggregation
						CLSCTX_INPROC_SERVER, 	// in-proc server
						IID_IEliza,				// IEliza custom interface ID
						(LPVOID *) &pEliza) ;	// output variable

					if (!SUCCEEDED(hr))
					{
						MessageBox (hWnd, TEXT("Couldn't create MFC Eliza"), TEXT("Error"), MB_ICONSTOP) ;
					}
					else
					{
						EnableWindow (hSend, TRUE) ;
					}
					return 0 ;
				}

				case ID_ELIZA_CREATEMFCLOCAL:
				{
					HRESULT hr ;

					hr = CoCreateInstance (
						CLSID_MfcEliza, 			// Eliza object ID
						NULL, 					// no aggregation
						CLSCTX_LOCAL_SERVER, 	// in-proc server
						IID_IEliza,				// IEliza custom interface ID
						(LPVOID *) &pEliza) ;	// output variable

					if (!SUCCEEDED(hr))
					{
						MessageBox (hWnd, TEXT("Couldn't create MFC Eliza"), TEXT("Error"), MB_ICONSTOP) ;
					}
					else
					{
						EnableWindow (hSend, TRUE) ;
					}
					return 0 ;
				}

				case ID_ELIZA_CREATEINPROCAUTOMATION:
				{
					HRESULT hr ;

					hr = CoCreateInstance (
						CLSID_AutoElizaInproc, 		// Eliza object ID
						NULL, 					// no aggregation
						CLSCTX_INPROC_SERVER, 	// in-proc server
						IID_IDispatch,			// IDispatch custom interface ID
						(LPVOID *) &pDispEliza) ;	// output variable

					if (!SUCCEEDED(hr))
					{
						MessageBox (hWnd, TEXT("Couldn't create inproc automation Eliza"), TEXT("Error"), MB_ICONSTOP) ;
					}
					else
					{
						EnableWindow (hSend, TRUE) ;
						bUseDispatch = TRUE ;
					}
					return 0 ;
				}


				case ID_ELIZA_CREATELOCALAUTOMATION:
				{
					HRESULT hr ;

					hr = CoCreateInstance (
						CLSID_AutoElizaLocal, 		// Eliza object ID
						NULL, 					// no aggregation
						CLSCTX_LOCAL_SERVER, 	// local server
						IID_IDispatch,			// IDispatch custom interface ID
						(LPVOID *) &pDispEliza) ;	// output variable

					if (!SUCCEEDED(hr))
					{
						MessageBox (hWnd, TEXT("Couldn't create local automation Eliza"), TEXT("Error"), MB_ICONSTOP) ;
					}
					else
					{
						EnableWindow (hSend, TRUE) ;
						bUseDispatch = TRUE ;
					}
					return 0 ;
				}


				case ID_ELIZA_CREATETYPELIBRARYMARSHALED:
				{
					HRESULT hr ;

					hr = CoCreateInstance (
						CLSID_TypeLibMarshaled, 	// Eliza object ID
						NULL, 			// no aggregation
						CLSCTX_LOCAL_SERVER, 	// local server
						IID_ITypeLibMarshaledEliza,		// IEliza custom interface ID
						(LPVOID *) &pEliza) ;	// output variable

					if (!SUCCEEDED(hr))
					{
						MessageBox (hWnd, TEXT("Couldn't create type library marshaled Eliza"), TEXT("Error"), MB_ICONSTOP) ;
					}
					else
					{
						EnableWindow (hSend, TRUE) ;
						bTypeLibMarshaled = TRUE ;
					}
					return 0 ;
				}

				case ID_ELIZA_CREATEDUAL:
				{
					HRESULT hr ;

					hr = CoCreateInstance (
						CLSID_DualEliza, 	// Eliza object ID
						NULL, 			// no aggregation
						CLSCTX_LOCAL_SERVER, 	// local server
						IID_IDualEliza,		// IEliza custom interface ID
						(LPVOID *) &pEliza) ;	// output variable

					if (!SUCCEEDED(hr))
					{
						MessageBox (hWnd, TEXT("Couldn't create dual Eliza"), TEXT("Error"), MB_ICONSTOP) ;
					}
					else
					{
						EnableWindow (hSend, TRUE) ;
						bDual = TRUE ;
					}
					return 0 ;
				}

				case ID_ELIZA_RELEASE:
				{
					if (pEliza)
					{
						pEliza->Release( ) ;
					}
					if (pDispEliza)
					{
						pDispEliza->Release( ) ;
					}

					pDispEliza = NULL ;
					pEliza = NULL ;
					EnableWindow (hSend, FALSE) ;
					bUseDispatch = FALSE ;
					bTypeLibMarshaled = FALSE ;
					bDual = FALSE ;

					return 0 ;
				}


				case IDC_SEND:
				{
					TCHAR WinText [256], out [256], in [256]  ;
					int length ;
				
					if (pEliza || pDispEliza)
					{
						length = GetWindowText (hOutWnd, WinText, sizeof(WinText)) ;

						wsprintf (out, TEXT("You: %s%c%c"), WinText, 0x0D, 0x0A) ;
						SendMessage (hInWnd, EM_SETSEL, (WPARAM) -1, (LPARAM)-1) ;
						SendMessage (hInWnd, EM_REPLACESEL, 0, (LPARAM) out) ;

						if (bUseDispatch)
						{
							DispatchComplain (out, in) ;
						}
						else if (bTypeLibMarshaled == TRUE)
						{
							BSTR bstrOut = SysAllocString (WinText) ;
							BSTR bstrIn = SysAllocString (L"") ;
							HRESULT hre = ((ITypeLibMarshaledEliza *)pEliza)->Complain (&bstrOut, &bstrIn) ;
							lstrcpy (in, bstrIn) ;
						}
						else if (bDual == TRUE)
						{
							BSTR bstrOut = SysAllocString (WinText) ;
							BSTR bstrIn = SysAllocString (L"") ;
							HRESULT hre = ((IDualEliza *)pEliza)->Complain (&bstrOut, &bstrIn) ;
							lstrcpy (in, bstrIn) ;
						}
						else
						{
							pEliza->Complain (WinText, in) ;						
						}
																
						SendMessage (hInWnd, EM_SETSEL, (WPARAM) -1, (LPARAM)-1) ;
						SendMessage (hInWnd, EM_REPLACESEL, 0, (LPARAM) in) ;
					}
					
					return 0 ;
				}

				case ID_ELIZA_TIMETEST:
				{
					if (DialogBox (hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd,
						(DLGPROC)TimeTestDlgProc) == IDOK)
					{
						TCHAR out [256], in [256] ;

/*
If the Perform Eliza Processing button is checked, then get text from
edit window to send to Eliza as a complaint.  If not, then send an empty
string (which Eliza will ignore) to test only the call overhead.
*/
						if (bUseEliza)
						{
							GetWindowText (hOutWnd, out, sizeof (out)) ;
						}
						else
						{
							out [0] = 0x00 ;
						}

						DWORD dwStartTime = GetTickCount ( ) ;

						UINT i ;
						for (i = 0 ; i < nReps ; i ++)
						{
							if (bUseDispatch)
							{
								DispatchComplain (out, in) ;	
							}
							else
							{
								pEliza->Complain (out, in) ;
							}
						}

						dwLastElapsedMs = GetTickCount( ) - dwStartTime ;
						InvalidateRect (hWnd, NULL, TRUE) ;

						SendMessage (hInWnd, EM_SETSEL, (WPARAM) -1, (LPARAM)-1) ;
						SendMessage (hInWnd, EM_REPLACESEL, 0, (LPARAM) in) ;
					}
					return 0 ;
				}
				case ID_ELIZA_EXIT:
				{
					SendMessage (hWnd, WM_CLOSE, 0, 0) ;
					return 0 ;
				}
            
			}

			return 0 ;
		}

		case WM_INITMENU:
		{
			HMENU hMenu = GetMenu (hWnd) ;

			if (pEliza == NULL && pDispEliza == NULL)
			{
				EnableMenuItem (hMenu, ID_ELIZA_CREATELOCAL, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATEINPROC, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATECUSTOMMARHSALING, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATEREMOTABLE, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATEMFCINPROC, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATEMFCLOCAL, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATEINPROCAUTOMATION, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATELOCALAUTOMATION, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATETYPELIBRARYMARSHALED, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATEDUAL, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_ELIZA_RELEASE, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_ELIZA_TIMETEST, MF_GRAYED) ;
			}
			else
			{
				EnableMenuItem (hMenu, ID_ELIZA_CREATELOCAL, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATEINPROC, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATECUSTOMMARHSALING, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATEREMOTABLE, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATEMFCINPROC, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATEMFCLOCAL, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATEINPROCAUTOMATION, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATELOCALAUTOMATION, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATETYPELIBRARYMARSHALED, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_ELIZA_CREATEDUAL, MF_GRAYED) ;
				EnableMenuItem (hMenu, ID_ELIZA_RELEASE, MF_ENABLED) ;
				EnableMenuItem (hMenu, ID_ELIZA_TIMETEST, MF_ENABLED) ;
			}

			return 0 ;
		}

		case WM_PAINT:
		{
			HDC hDC ;
			PAINTSTRUCT ps ;
			TCHAR out [256] ;
			int length ;

			hDC = BeginPaint (hWnd, &ps) ;

			TextOut (hDC, 10, 10, TEXT("Outgoing Text"), 13) ;
			TextOut (hDC, 10, 70, TEXT("Incoming Text"), 13) ;

			length = wsprintf (out, TEXT("Last time test elapsed ms = %d"), dwLastElapsedMs) ;
			TextOut (hDC, 10, 300, out, length) ;

			EndPaint (hWnd, &ps) ;
			return 0 ;

		}

		case WM_DESTROY:
		{
			PostQuitMessage (0) ;
			return 0;
		}

		default:
		{
			return DefWindowProc (hWnd, Message, wParam, lParam) ;
		}
	}
}


