/**
 * DLL Interface classes for C++ Binary Compatibility article
 * article at http://aegisknight.org/cppinterface.html
 *
 * code author:     Ben Scott   (bscott@iastate.edu)
 * article author:  Chad Austin (aegis@aegisknight.org)
 */


#ifndef DLL_INTERFACE_H
#define DLL_INTERFACE_H


#ifdef WIN32
#define DLL_CALL __stdcall
#else
#define DLL_CALL
#endif


/**
 * Interfaces exposed across a DLL boundary should derive from this
 * class to ensure that their memory is released cleanly and
 * safely. This class should be used in conjunction with the DLLImpl
 * template. <b>Your interface should NOT define a destructor!</b>
 *
 * <h3>Example Usage</h3>
 * \code
 *    class MyInterface : public DLLInterface {
 *       // MyInterface method declarations here...
 *       // should NOT include a destructor!
 *    };
 * \endcode
 *
 * @see DLLImpl */
class DLLInterface {
protected:
  /**
   * Handles the destruction of this class. This is essentially a destructor
   * that works across DLL boundaries.
   */
  virtual void DLL_CALL destroy() = 0;

public:
  /**
   * Specialized delete that calls destroy instead of the destructor.
   */
  void operator delete(void* p) {
    if (p) {
      DLLInterface* i = static_cast<DLLInterface*>(p);
      i->destroy();
    }
  }
};


/**
 * Implementations of interfaces across DLL boundaries that derive
 * from DLLInterface should derive from this template to ensure that
 * their memory is released safely and cleanly.
 *
 * <h3>Example Usage</h3>
 * \code
 *    MyImpl : public DLLImpl<MyInterface> {
 *       // MyImpl method declarations, including constructors and
 *       // destructors here ...
 *    };
 * \endcode
 *
 * @see DLLInterface */
template<class Interface>
class DLLImpl : public Interface {
public:

  /**
   * This allows the implementation to simply define a destructor.  It
   * will automatically be called at the right time.
   */
  virtual ~DLLImpl() { }

  /**
   * Implementation of DLLInterface's destroy method. This function will
   * make sure this object gets deleted in a polymorphic manner. You
   * should NOT reimplement this method.
   */
  virtual void DLL_CALL destroy() {
    delete this;
  }

  /**
   * Overloaded operator delete calls global operator delete since
   * DLLInterface modified this functionality to protect memory.
   *
   * @param p    pointer to the memory to delete
   */
  void operator delete(void* p) {
    ::operator delete(p);
  }
};


#endif
