////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This is a part of the COM Serialization SDK VC++ Library.
//  
// Copyright 2009 BPM Microsystems
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//                                                                                                                    //
// $Header: //sesca/src/Winprog/COMSerializationSDK/VC++/HeaderLib/ComSerSdk/Detail/rcs/SerialDataServerComObject.h 1.6 2011/07/21 11:28:58 arturoc Exp $
//                                                                                                                    //
///////// 120 columns, Tab = Insert 3 Spaces ///////////////////////////////////////////////////////////////////////////

/**
   This header file defines the ESS COM object interface and implementation.
*/

#pragma once

#include "Server.h"

namespace ComSerSdk
{

namespace Detail
{

#if defined(COMSERSDK_USER_SPECIFIED_ESS_NAME)
   #pragma warning(push)
   #pragma warning(disable:4321)//disables warning "automatically generating a IID for interface"
   #pragma warning(disable:4322)//disables warning "automatically generating a CLSID for class"
   #pragma warning(disable:4323)//disables warning "re-using registered CLSID for class"
#endif

/**
   Defines the interface expected by BPWin.  The use of ATL attributes inserts this interface into the type library,
   which facilitates:
   a.) the code in the ATL library that uses the type library to invoke methods via IDispatch
   b.) default type library marshalling (see "Marshaling Details" in MSDN)
*/
[
   object,
#if !defined(COMSERSDK_USER_SPECIFIED_ESS_NAME)
   uuid("A415A780-4E83-4e7f-8D2D-16CA3A445E1F"),
#endif
   dual,
   pointer_default(unique)
]
__interface COMSERSDK_ESS_ITF_NAME : IDispatch
{
   /**
      Specified according to item 4.3 of the appendix of the COM Serialization SDK documentation.
   */
   [id(1)] HRESULT GetSerialData([in]BSTR sCurrentHandle, [out,retval] IDispatch ** ppoDictionary);
   
   /**
      Specified according to item 5.1 of the appendix of the COM Serialization SDK documentation.
   */
   [id(2)] HRESULT OnBeginJob([in]BSTR sLastHandle, [in] LONG lNumDevices);
   
   /**
      Specified according to item 6.1 of the appendix of the COM Serialization SDK documentation.
   */
   [id(3)] HRESULT OnResult([in]BSTR sHandle, [in] VARIANT_BOOL bSuccess, [in] LONG lSite, [in] LONG lSocket);

   /**
      Specified according to item 8.1 of the appendix of the COM Serialization SDK documentation.
   */
   [id(4)] HRESULT SetInitializationData([in] BSTR sInitializationData);

   /**
      
   */
   [id(5)] HRESULT GetSocketSerialData([in]BSTR sCurrentHandle,
                                       [in]LONG lSite,
                                       [in]LONG lSocket,
                                       [in]BSTR sSiteId,
                                       [in]BSTR sAdapter,
                                       [in]BSTR sSocketId,
                                       [out,retval] IDispatch ** ppoDictionary);

   /**
      
   */
   [id(6)] HRESULT OnRetry([in]BSTR sCurrentHandle,
                           [in]LONG lSite,
                           [in]LONG lSocket,
                           [in]BSTR sSiteId,
                           [in]BSTR sAdapter,
                           [in]BSTR sSocketId);

   /**
      Specified according to item 6.1 of the appendix of the COM Serialization SDK documentation.
   */
   [id(7)] HRESULT OnSocketResult([in]BSTR sHandle, [in] VARIANT_BOOL bSuccess, [in] LONG lSite, [in] LONG lSocket,
                                  [in]BSTR sSiteId, [in]BSTR sAdapter, [in]BSTR sSocketId);

/**
Declares a Device-Driven Serialization (DDS) method in the ISerialServer interface that adheres to BPWin requirements.
*/
#define COMSERSDK_ITF_METHODSPEC(idno, methname) [id(idno)] HRESULT methname([in] BSTR sHandle, \
                                                                             [in] VARIANT oDataIn, \
                                                                             [out,retval] VARIANT* poDataOut);

/**
Declares the Device-Driven Serialization (DDS) method with the name specified by the library user with their definition
of COMSERSDK_METHOD1NAME.
*/
#if defined(COMSERSDK_METHOD1NAME)
   COMSERSDK_ITF_METHODSPEC(8, COMSERSDK_METHOD1NAME)
#endif

/**
Declares the Device-Driven Serialization (DDS) method with the name specified by the library user with their definition
of COMSERSDK_METHOD2NAME.
*/
#if defined(COMSERSDK_METHOD2NAME)
   COMSERSDK_ITF_METHODSPEC(9, COMSERSDK_METHOD2NAME)
#endif

/**
Declares the Device-Driven Serialization (DDS) method with the name specified by the library user with their definition
of COMSERSDK_METHOD3NAME.
*/
#if defined(COMSERSDK_METHOD3NAME)
   COMSERSDK_ITF_METHODSPEC(10, COMSERSDK_METHOD3NAME)
#endif

/**
Declares the Device-Driven Serialization (DDS) method with the name specified by the library user with their definition
of COMSERSDK_METHOD4NAME.
*/
#if defined(COMSERSDK_METHOD4NAME)
   COMSERSDK_ITF_METHODSPEC(11, COMSERSDK_METHOD4NAME)
#endif

/**
Declares the Device-Driven Serialization (DDS) method with the name specified by the library user with their definition
of COMSERSDK_METHOD5NAME.
*/
#if defined(COMSERSDK_METHOD5NAME)
   COMSERSDK_ITF_METHODSPEC(12, COMSERSDK_METHOD5NAME)
#endif

/**
Declares the Device-Driven Serialization (DDS) method with the name specified by the library user with their definition of
COMSERSDK_METHOD6NAME.
*/
#if defined(COMSERSDK_METHOD6NAME)
   COMSERSDK_ITF_METHODSPEC(13, COMSERSDK_METHOD6NAME)
#endif

/**
Declares the Device-Driven Serialization (DDS) method with the name specified by the library user with their definition of
COMSERSDK_METHOD7NAME.
*/
#if defined(COMSERSDK_METHOD7NAME)
   COMSERSDK_ITF_METHODSPEC(14, COMSERSDK_METHOD7NAME)
#endif

/**
Declares the Device-Driven Serialization (DDS) method with the name specified by the library user with their definition of
COMSERSDK_METHOD8NAME.
*/
#if defined(COMSERSDK_METHOD8NAME)
   COMSERSDK_ITF_METHODSPEC(15, COMSERSDK_METHOD8NAME)
#endif

/**
Declares the Device-Driven Serialization (DDS) method with the name specified by the library user with their definition of
COMSERSDK_METHOD9NAME.
*/
#if defined(COMSERSDK_METHOD9NAME)
   COMSERSDK_ITF_METHODSPEC(16, COMSERSDK_METHOD9NAME)
#endif

/**
Declares the Device-Driven Serialization (DDS) method with the name specified by the library user with their definition of
COMSERSDK_METHOD10NAME.
*/
#if defined(COMSERSDK_METHOD10NAME)
   COMSERSDK_ITF_METHODSPEC(17, COMSERSDK_METHOD10NAME)
#endif

/**
Declares the Device-Driven Serialization (DDS) method with the name specified by the library user with their definition of
COMSERSDK_METHOD11NAME.
*/
#if defined(COMSERSDK_METHOD11NAME)
   COMSERSDK_ITF_METHODSPEC(18, COMSERSDK_METHOD11NAME)
#endif

/**
Declares the Device-Driven Serialization (DDS) method with the name specified by the library user with their definition of
COMSERSDK_METHOD12NAME.
*/
#if defined(COMSERSDK_METHOD12NAME)
   COMSERSDK_ITF_METHODSPEC(19, COMSERSDK_METHOD12NAME)
#endif

#undef COMSERSDK_ITF_METHODSPEC

   [id(20)] HRESULT GetSerialAddresses([out,retval] IDispatch ** ppoDictionary);
};

/**
   The External Serialization Server.
   This is the class definition that implements the above-specified ISerialServer interface, providing overrides for 
   its methods.

   See the description of the FinalConstruct() override in this class for important details regarding the function of
   this class.
   
   All implemented methods from the ISerialServer interface firewall and handle exceptions so that we may properly
   query the available exception information and provide it to BPWin (for details, see 
   ComSerSdk::Detail::HandleExceptions in <ComSerSdk/Exceptions.h>).
*/
[
	coclass,
	threading(apartment),
	vi_progid(COMSERSDK_ESS_PROGID  ),
	   progid(COMSERSDK_ESS_PROGID".1"),
	version(1.0),
   registration_script(script="none")
#if !defined(COMSERSDK_USER_SPECIFIED_ESS_NAME)
	,uuid(COMSERSDK_ESS_CLSID)
#endif

]
class COMSERSDK_ESS_CPP_CLASS_NAME : public COMSERSDK_ESS_ITF_NAME
{
public:

   /**
   When the ATL Library notifies us that it has completed instantiating us (as a result of BPWin instantiating the 
   ESS), we take that opportunity to create the ComSerSdk library-user's "server class" instance via 
   _AtlModule.GetApp()->CreateServer(), and store off the returned reference so that we may, essentially, forward our
   functionality to it.
   */
   virtual HRESULT FinalConstruct()
   {
      try
      {
         CheckAppAvailable();
         SetServer();
      }
      catch(...)
      {
         return HandleExceptions(__uuidof(COMSERSDK_ESS_CPP_CLASS_NAME));
      }
      return S_OK;
   }

private:

   /**
      Implements the GetSerialData method of the ESS; forwards functionality to a helper member function.
   */
   STDMETHOD(GetSerialData)(BSTR sCurrentNumber, IDispatch ** ppoDictionaryAsIDispatch)
   {
      try
      {
         return GetServerSerializationData(sCurrentNumber, ppoDictionaryAsIDispatch);
      }
      catch(...)
      {
         return HandleExceptions(__uuidof(COMSERSDK_ESS_CPP_CLASS_NAME));
      }
      return S_OK;
   }

   /**
      Implements the GetSocketSerialData method of the ESS; forwards functionality to a helper member function.
   */
   STDMETHOD(GetSocketSerialData)(BSTR sCurrentNumber, LONG lSite, LONG lSocket, 
                                  BSTR sSiteId, BSTR sAdapter, BSTR sSocketId, IDispatch ** ppoDictionaryAsIDispatch)
   {
      try
      {
         return GetServerSerializationData(sCurrentNumber, ppoDictionaryAsIDispatch, lSite, lSocket, sSiteId, sAdapter, sSocketId);
      }
      catch(...)
      {
         return HandleExceptions(__uuidof(COMSERSDK_ESS_CPP_CLASS_NAME));
      }
      return S_OK;
   }

   /**
      Implements the OnBeginJob method of the ESS to forward to the library-user-provided server class.
   */
   STDMETHOD(OnBeginJob)(BSTR sLastHandle, LONG lNumDevices)
   {
      try
      {
         return m_spoServer->OnBeginJob(sLastHandle, lNumDevices);
      }
      catch(...)
      {
         return HandleExceptions(__uuidof(COMSERSDK_ESS_CPP_CLASS_NAME));
      }
      return S_OK;
   }

   /**
      Implements the OnBeginJob method of the ESS to forward to the library-user-provided server class.
   */
   STDMETHOD(OnResult)(BSTR sHandle, VARIANT_BOOL bSuccess, LONG lSite, LONG lSocket)
   {
      try
      {
          return m_spoServer->OnResult(sHandle, bSuccess, lSite, lSocket);
      }
      catch(...)
      {
         return HandleExceptions(__uuidof(COMSERSDK_ESS_CPP_CLASS_NAME));
      }  
      return S_OK;
   }

   STDMETHOD(OnSocketResult)(BSTR sHandle, VARIANT_BOOL bSuccess, LONG lSite, LONG lSocket, BSTR sSiteId, BSTR sAdapter,
                             BSTR sSocketId)
   {
      try
      {
          return m_spoServer->OnSocketResult(sHandle, bSuccess, lSite, lSocket, sSiteId, sAdapter, sSocketId);
      }
      catch(...)
      {
         return HandleExceptions(__uuidof(COMSERSDK_ESS_CPP_CLASS_NAME));
      }  
      return S_OK;
   }

   /**
      Implements the SetInitializationData method of the ESS to forward to the library-user-provided server class.
   */
   STDMETHOD(SetInitializationData)(BSTR sInitializationData)
   {
      try
      {
          return m_spoServer->SetInitializationData(sInitializationData);
      }
      catch(...)
      {
         return HandleExceptions(__uuidof(COMSERSDK_ESS_CPP_CLASS_NAME));
      }  
      return S_OK;
   }

   STDMETHOD(OnRetry)(BSTR sCurrentHandle,
                      LONG lSite,
                      LONG lSocket,
                      BSTR sSiteId,
                      BSTR sAdapter,
                      BSTR sSocketId)
   {
      try
      {
          return m_spoServer->OnRetry(sCurrentHandle, lSite, lSocket, sSiteId, sAdapter, sSocketId);
      }
      catch(...)
      {
         return HandleExceptions(__uuidof(COMSERSDK_ESS_CPP_CLASS_NAME));
      }  
      return S_OK;
   }

   /**
      Type of function pointer to a DDS method defined in CServerBase.
   */
   typedef HRESULT (CServerBase::*DdsMethodType)(BSTR, VARIANT, VARIANT*);

   /**
      To minimize the amount of code specified by macros, a call to this function is the only thing specified in
      the COMSERSDK_COMOBJ_METHODDEF macro.  This function does what the macro would otherwise be defined to do.
   */
   HRESULT CallDdsMethod(DdsMethodType pfnDdsMethod, BSTR sHandle, VARIANT oDataIn, VARIANT * poDataOut)
   {
      try
      {
         return (m_spoServer.get()->*pfnDdsMethod)(sHandle, oDataIn, poDataOut);
      }
      catch(...)
      {
         return HandleExceptions(__uuidof(COMSERSDK_ESS_CPP_CLASS_NAME));
      }
      return S_OK;
   }

   STDMETHOD(GetSerialAddresses)(IDispatch ** ppoDictionary)
   {
      try
      {
          return m_spoServer->GetSerialAddresses(ppoDictionary);
      }
      catch(...)
      {
         return HandleExceptions(__uuidof(COMSERSDK_ESS_CPP_CLASS_NAME));
      }
      return S_OK;
   }

   

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
*/
#define COMSERSDK_COMOBJ_METHODDEF(methname)                                     \
   STDMETHOD(methname)(BSTR sHandle, VARIANT oDataIn, VARIANT* poDataOut)        \
   {                                                                             \
      return CallDdsMethod(&CServerBase::methname, sHandle, oDataIn, poDataOut); \
   }

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
The override has the name specified by the library user with their definition of COMSERSDK_METHOD1NAME.
*/
#if defined(COMSERSDK_METHOD1NAME)
   COMSERSDK_COMOBJ_METHODDEF(COMSERSDK_METHOD1NAME)
#endif

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
The override has the name specified by the library user with their definition of COMSERSDK_METHOD2NAME.
*/
#if defined(COMSERSDK_METHOD2NAME)
   COMSERSDK_COMOBJ_METHODDEF(COMSERSDK_METHOD2NAME)
#endif

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
The override has the name specified by the library user with their definition of COMSERSDK_METHOD3NAME.
*/
#if defined(COMSERSDK_METHOD3NAME)
   COMSERSDK_COMOBJ_METHODDEF(COMSERSDK_METHOD3NAME)
#endif

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
The override has the name specified by the library user with their definition of COMSERSDK_METHOD4NAME.
*/
#if defined(COMSERSDK_METHOD4NAME)
   COMSERSDK_COMOBJ_METHODDEF(COMSERSDK_METHOD4NAME)
#endif

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
The override has the name specified by the library user with their definition of COMSERSDK_METHOD5NAME.
*/
#if defined(COMSERSDK_METHOD5NAME)
   COMSERSDK_COMOBJ_METHODDEF(COMSERSDK_METHOD5NAME)
#endif

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
The override has the name specified by the library user with their definition of COMSERSDK_METHOD6NAME.
*/
#if defined(COMSERSDK_METHOD6NAME)
   COMSERSDK_COMOBJ_METHODDEF(COMSERSDK_METHOD6NAME)
#endif

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
The override has the name specified by the library user with their definition of COMSERSDK_METHOD7NAME.
*/
#if defined(COMSERSDK_METHOD7NAME)
   COMSERSDK_COMOBJ_METHODDEF(COMSERSDK_METHOD7NAME)
#endif

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
The override has the name specified by the library user with their definition of COMSERSDK_METHOD8NAME.
*/
#if defined(COMSERSDK_METHOD8NAME)
   COMSERSDK_COMOBJ_METHODDEF(COMSERSDK_METHOD8NAME)
#endif

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
The override has the name specified by the library user with their definition of COMSERSDK_METHOD9NAME.
*/
#if defined(COMSERSDK_METHOD9NAME)
   COMSERSDK_COMOBJ_METHODDEF(COMSERSDK_METHOD9NAME)
#endif

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
The override has the name specified by the library user with their definition of COMSERSDK_METHOD10NAME.
*/
#if defined(COMSERSDK_METHOD10NAME)
   COMSERSDK_COMOBJ_METHODDEF(COMSERSDK_METHOD10NAME)
#endif

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
The override has the name specified by the library user with their definition of COMSERSDK_METHOD11NAME.
*/
#if defined(COMSERSDK_METHOD11NAME)
   COMSERSDK_COMOBJ_METHODDEF(COMSERSDK_METHOD11NAME)
#endif

/**
For Device-Driven Serialization (DDS), provides an override for a DDS method declared in the ISerialServer interface.
The override has the name specified by the library user with their definition of COMSERSDK_METHOD12NAME.
*/
#if defined(COMSERSDK_METHOD12NAME)
   COMSERSDK_COMOBJ_METHODDEF(COMSERSDK_METHOD12NAME)
#endif

#undef COMSERSDK_COMOBJ_METHODDEF

   /**
      Ensures the user properly instantiated their concrete of the CApplicationBase class.
   */
   void CheckAppAvailable()
   {
      if(_AtlModule.GetApp()) return;

      throw CLibraryException("Error: The application object isn't set.  The SDK requires its client code to define"
                              " a class derived from ComSerSdk::CApplicationBase and a global instance of it to be"
                              " defined as well.",
                              COMSERSDK_CODELOCATION);
   }

   /**
      Invokes the library-user's implementation of the server class factory and stores the result so that we may
      forward all of our functionality to it.
   */
   void SetServer()
   {
      m_spoServer = _AtlModule.GetApp()->CreateServer();

      if(!m_spoServer.get())
      {
         throw CLibraryException("Error: The ComSerSdk::CApplicationBase::CreateServer() call returned a NULL "
                                 "pointer.",
                                 COMSERSDK_CODELOCATION);
      }
   }

   /**
      Implements the GetSerialData method of the ESS to forward to the server class provided by the library-user.
   */
   HRESULT GetServerSerializationData(BSTR sCurrentNumber, IDispatch ** ppoDictionaryAsIDispatch)
   {
      return GetServerSerializationData(sCurrentNumber, ppoDictionaryAsIDispatch, -1, -1, NULL, NULL, NULL);
   }

   /**
      Implements the GetSerialData method of the ESS to forward to the server class provided by the library-user.
   */
   HRESULT GetServerSerializationData(BSTR sCurrentNumber,
                                      IDispatch ** ppoDictionaryAsIDispatch,
                                      long lSite,
                                      long lSocket,
                                      BSTR sSiteId,
                                      BSTR sAdapter,
                                      BSTR sSocketId)
   {
      // Despite BPWin initializing the pointer to NULL, the COM subsystem doesn't keep the pointer NULL when it
      // makes it here.
      //
      *ppoDictionaryAsIDispatch = NULL;
      HRESULT hResult = NULL;
      if(lSite == -1)
      {
         hResult = m_spoServer->GetSerialData(sCurrentNumber, ppoDictionaryAsIDispatch);
      }
      else
      {
         hResult = m_spoServer->GetSocketSerialData(sCurrentNumber,
                                                    lSite,
                                                    lSocket,
                                                    sSiteId,
                                                    sAdapter,
                                                    sSocketId,
                                                    ppoDictionaryAsIDispatch);
      }

      if(SUCCEEDED(hResult) && *ppoDictionaryAsIDispatch == NULL)
      {
         throw CLibraryException("Error: The ComSerSdk::CServerBase::GetSerialData() call did not set the "
                                 "dictionary pointer to non-NULL.",
                                 COMSERSDK_CODELOCATION);
      }

      // Important to do this despite any failures indicated by the HRESULT.
      //
      if(*ppoDictionaryAsIDispatch != NULL)
      {
         (*ppoDictionaryAsIDispatch)->AddRef();
      }

      return hResult;
   }

   /**
      Reference to the library-user-provided server class instance that we forward our interface method implementations
      to.
   */
   CServerPtr m_spoServer;
};

#if defined(COMSERSDK_USER_SPECIFIED_ESS_NAME)
   #pragma warning(pop)
#endif

/**
Utility to determine the VC++ compiler-generated CLSID of the ESS COM object.
Defined here, below the ESS COM object class, because it is at this location that we are guaranteed that the expression
__uuidof(COMSERSDK_ESS_CPP_CLASS_NAME) will not produce a compilation error.
*/
CString GetClassClsid()
{
   LPOLESTR pszClsid = NULL;
   const HRESULT hConversionResult = ::StringFromCLSID(__uuidof(COMSERSDK_ESS_CPP_CLASS_NAME), &pszClsid);

   if(FAILED(hConversionResult))
   {
      throw CHresultException("Could not convert the CLSID of " COMSERSDK_STRINGIZE(COMSERSDK_ESS_CPP_CLASS_NAME) " to "
                              "a string.",
                              hConversionResult,
                              "::StringFromCLSID()",
                              COMSERSDK_CODELOCATION);

   }

   const CString sRet(pszClsid);
   ::CoTaskMemFree(pszClsid);
   return sRet;
}
}//end namespace Detail
}//end namespace ComSerSdk