/*** 
*
*  Copyright (C) 1993-1994, Microsoft Corporation.  All Rights Reserved.
*  Information Contained Herein Is Proprietary and Confidential.
*
*  File:
*    hello.cpp
*
*  Purpose:
*    See comment in hello.h
*
*****************************************************************************/


#include "common.h"       
#include "resource.h"
#include "hello.h"       





IUnknown FAR*
CreateDispatchInterface(
  IUnknown FAR*	punkController,
  void FAR* pProgInterface)
{
    HRESULT hresult;
    ITypeLib FAR* ptlib;
    ITypeInfo FAR* ptinfo;
    IUnknown FAR* punkStdDisp;
    
    // Load the the hellotlb type library.
    hresult = LoadRegTypeLib(LIBID_HELLOTLB, 1, 0, 0x0409, &ptlib);
    if (hresult != NOERROR) {
      #define TLB_NAME OLESTR("hello.tlb")

      // if it wasn't registered, try to load it from the path/current directory
      // if this succeeds, it will have registered the type library for us
      // for the next time.
      if((hresult = LoadTypeLib(TLB_NAME, &ptlib)) != NOERROR)
	 return NULL;
    }

    // Get Dispatch TypeInfo from the type library. 
    // Exit if an error occurs.
    hresult = ptlib->GetTypeInfoOfGuid(IID_IHello, &ptinfo);
    if (hresult != NOERROR)
	return NULL;

    ptlib->Release();
	
    // Create a standard dispatch object.  
    // Release the pointer to the previously created TypeInfo.
    // Exit if an error occurred.
    hresult = CreateStdDispatch(punkController,
	    			pProgInterface,		
				ptinfo,
      				&punkStdDisp);
    ptinfo->Release();
    if (hresult != NOERROR)
	return NULL;


    // If execution has reached this point, then no errors occurred.
    return punkStdDisp;
}





/*
 *	CHello::CHello(void)
 *   
 */
CHello::CHello()
{
    m_refs = 1;
    m_disp_interface = NULL;
    m_prog_interface = new CHelloPro;
    m_prog_interface->m_phello = this;
    m_bstrHelloMsg = SysAllocString(OLESTR("Hello, world"));		
}





/*
 *	CHello::~CHello(void)
 *
 */
CHello::~CHello()
{
    SysFreeString(m_bstrHelloMsg);		
    delete m_prog_interface;
}





/*
 *	CHello *CHello::Create(void)
 *
 *	Creates a new instance of the CHello object.
 *
 *  	Returns a pointer to the newly created instance or
 *	NULL if the creation fails.
 *
 */
CHello FAR*
CHello::Create()
{
    CHello FAR* phello;
    IUnknown FAR* punkStdDisp; 


    // Create an instance of CHello.  Exit if an error occurs.    
    phello = new FAR CHello();
    if(phello == NULL)
      return NULL;

    punkStdDisp = CreateDispatchInterface((IUnknown FAR*) phello,
					  phello->m_prog_interface);
    if (punkStdDisp == NULL) {
      phello->Release();
      return NULL;
    }


    // If execution has reached this point, then no errors have occurred.
    // Save the standard dispatch item and return the new instance.
    phello->m_disp_interface = punkStdDisp;
    return phello; 
}





/*
 *	void CHello::ProcessCommand(WPARAM param)
 *
 *	Process a windows WM_COMMAND with the specified parameter.
 *
 */
void CHello::ProcessCommand(WPARAM wparam)
{
    switch(wparam) {
	case IDC_SAYHELLO:
	// The user pressed the "Say Hello" button.
	m_prog_interface->SayHello();
	break;
    }
}





//---------------------------------------------------------------------
//                        IUnknown methods
//---------------------------------------------------------------------


/* 	CHello::QueryInterface(...)
 *
 *	Someone wants to know if CHello support the interface identified
 *	by riid.  CHello supports IUnknown and we defer to a member 
 *      (m_disp_interfaceatch) and thus support IDispatch.
 *
 *	CHello doesn't support any other interfaces.
 * 
 */
STDMETHODIMP
CHello::QueryInterface(REFIID riid, void FAR* FAR* ppv)
{
    // riid identifies an interface type.  Do we support it?

    if (IsEqualIID(riid, IID_IUnknown))
	// Someone is asking us for our controlling IUnknown.  
	// CHello is that IUnknown, so "this" is the answer.
	*ppv = this;
    else if (IsEqualIID(riid, IID_IDispatch) ||
	     IsEqualIID(riid, IID_DHello))
        // Someone is asking us for our IDispatch or dispinterface.
    	// We simply defer to the standard dispatch interface 
    	// we created earlier.
    	return m_disp_interface->QueryInterface(IID_IDispatch, ppv);
    else if (IsEqualIID(riid, IID_IHello))
	// Someone is asking us for our IHelloPro interface.
	// We simply defer to the standard dispatch interface 
	// we created earlier.
	*ppv = &m_prog_interface;
    else {
	// They must have asked for another interface -- something
   	// we don't support.  Report the error.
  	*ppv = NULL;
	return ResultFromScode(E_NOINTERFACE);
    }

    // If execution reached this point then no error occurred.
    AddRef();
    return NOERROR;
}






STDMETHODIMP_(ULONG)
CHello::AddRef()
{
    return ++m_refs;
}





STDMETHODIMP_(ULONG)
CHello::Release()
{
    if(--m_refs == 0)
    {
      if(m_disp_interface != NULL)
		m_disp_interface->Release();
      PostQuitMessage(0);
      delete this;
      return 0;
    }
    return m_refs;
}




//---------------------------------------------------------------------
//                      The CHello Class Factory
//---------------------------------------------------------------------


CHelloCF::CHelloCF()
{ 
    m_refs = 1; 
}





IClassFactory FAR*
CHelloCF::Create()
{
    return new FAR CHelloCF();
}





STDMETHODIMP
CHelloCF::QueryInterface(REFIID riid, void FAR* FAR* ppv)
{
    if(IsEqualIID(riid, IID_IUnknown) ||
       IsEqualIID(riid, IID_IClassFactory)) {
      AddRef();
      *ppv = this;
      return NOERROR;
    }
    *ppv = NULL;
    return ResultFromScode(E_NOINTERFACE);
}





STDMETHODIMP_(ULONG)
CHelloCF::AddRef()
{
    return ++m_refs;
}





STDMETHODIMP_(ULONG)
CHelloCF::Release()
{
    if(--m_refs == 0) {
       delete this;
       return 0;
    }
    return m_refs;
}





STDMETHODIMP
CHelloCF::CreateInstance(
    IUnknown FAR* punkOuter,
    REFIID riid,
    void FAR* FAR* ppv)
{
    extern CHello FAR* g_phello;
    
    
    return g_phello->QueryInterface(riid, ppv);
}





STDMETHODIMP
CHelloCF::LockServer(BOOL fLock)
{
    return NOERROR;
}
