//******************************************************************
//*******************************************************************
//*** Client that uses the CLSID_Thesaurus object which reuses
//*** the ISpell and IOcr interfaces of the CLSID_OcrEngine 
//*** object by aggregation
//*******************************************************************
//*******************************************************************

//-------------------------------------------------------------------
//  Required definitions
//-------------------------------------------------------------------
#define UNICODE
#define _WIN32_DCOM

//-------------------------------------------------------------------
//  includes
//-------------------------------------------------------------------
#include <assert.h>
#include <stdio.h>
#include <windows.h>
#include <initguid.h>
#include "..\..\..\idl\ocr.h"   
#include "..\idl\aggregate.h"   

//-------------------------------------------------------------------
//  includes
//-------------------------------------------------------------------
CRITICAL_SECTION g_cs;

//*******************************************************************
//*******************************************************************
//***  UTILITY FUNCTIONS
//*******************************************************************
//*******************************************************************
void DisplayStatus(wchar_t *pwszMsg, HRESULT hr)
{

   if (hr == S_OK) { wprintf(TEXT("%s\n"), pwszMsg); return; }

   if (HRESULT_FACILITY(hr) == FACILITY_WINDOWS)
      hr = HRESULT_CODE(hr);

   wchar_t *pwszStatus;
   FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
       FORMAT_MESSAGE_FROM_SYSTEM,
       NULL,
       hr,
       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
       (LPWSTR)&pwszStatus,
       0,
       NULL );

   wprintf(TEXT("%s: %s (ECode: %lx)\n"), pwszMsg, pwszStatus, hr);

   LocalFree(pwszStatus);
}


//*******************************************************************
//*******************************************************************
//*** Main
//*******************************************************************
//*******************************************************************
void main(int argc, char **argv)
{
   // In order to run this program, you must you the following:
   // (1) register the inner.dll, since it's used by aggregate.exe
   // (2) register the ocrps.dll proxy/stub
   // (3) register the aggregateps.dll proxy/stub
   // (4) register aggregate.exe for the SCM to find it.
   //     i.e., if you don't register, you must run 
   //     aggregate.exe so that it registers the its CLSID
   //     with the SCM via CoRegisterClassObject!
   //  2&3 are need because this client runs in separate
   //  process from aggregate.exe, which is this client's server.


   InitializeCriticalSection(&g_cs); 

   DisplayStatus(TEXT("Client: Started"), S_OK);

   HRESULT hr = S_OK;

   // Init COM
   hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
   assert(SUCCEEDED(hr));

  MULTI_QI mqi[] = {
       {&IID_IThesaurus, NULL, E_FAIL}, 
       {&IID_ISpell, NULL, E_FAIL} 
   };

   // client testing aggregation : CLSID_Thesaurus is
   // object aggregating CLSID_OcrEngine
   hr = CoCreateInstanceEx(CLSID_Thesaurus, 
       NULL, 
       CLSCTX_SERVER, 
       NULL, 
       sizeof(mqi)/sizeof(mqi[0]), 
       mqi);
   DisplayStatus(TEXT("CoCreateInstanceEx"), hr);

   if (SUCCEEDED(mqi[0].hr) && SUCCEEDED(mqi[1].hr)) {
       IThesaurus * pDict = static_cast<IThesaurus*>(mqi[0].pItf);
       ISpell * pSpell = static_cast<ISpell*>(mqi[1].pItf);

       hr = pDict->LookUp();
       DisplayStatus(TEXT("Called pDict->LookUp"), hr);

       // This call here supported by the CLSID_Thesaurus object
       // but it forwards the call to the CLSID_OcrEngine object
       // because it reuses the CLSID_OcrEngine object by
       // containment.
       PossibleWords pw;
       hr = pSpell->Check(TEXT("AWord"), &pw);
       DisplayStatus(TEXT("Called pSpell->Check"), hr);
       wprintf(TEXT("ISpell::Check returned:  (%s, %s)\n"), pw.wszOne, pw.wszTwo);

       pSpell->Release();
       pDict->Release();
   }

   CoUninitialize();
   DisplayStatus(TEXT("Client shutting down..."), S_OK);

   DeleteCriticalSection(&g_cs);
}