//----------------------------------------------------------------------------
// ObjectComponents
// Copyright (c) 1994, 1996 by Borland International, All Rights Reserved
/// \file
/// Templatized class implementation of OLE component creation code for
/// TComponentFactory callback for ObjectWindows applications
/// All templates assume an OWLGetAppDictionary() global and a Registrar global
/// User can provide alternate implementation for any or all of the functions
/// The user's derived TApplication class is passed as the template parameter
//
//----------------------------------------------------------------------------
 
#if !defined(OCF_OLEFACTO_H)
#define OCF_OLEFACTO_H
 
#include <owl/private/defs.h>
#if defined(BI_HAS_PRAGMA_ONCE)
# pragma once
#endif
 
#include <ocf/defs.h>
#include <ocf/oleutil.h>
#include <ocf/ocreg.h>
#include <ocf/olewindo.h>
#include <owl/docmanag.h>
#include <owl/appdict.h>
#include <owl/pointer.h>
 
namespace ocf {
 
/// \cond NoSuppressDoxygenWarning
#include <owl/preclass.h>
/// \endcond
 
//----------------------------------------------------------------------------
/// Non-automated application automation callout stub implementation
//
template <class T> struct TOleFactoryNoAuto {
  static void      AutomateApp(T* app, owl::uint32 options);
  static TUnknown* AutomateObject(T* app, const void* obj,const std::type_info& info);
  static void      UnregisterAutomation(T* app);
};
 
//
template<class T> void
TOleFactoryNoAuto<T>::AutomateApp(T* /*app*/, owl::uint32) {
 
}
 
//
template<class T> TUnknown*
TOleFactoryNoAuto<T>::AutomateObject(T*, const void*,const std::type_info&) {
  return 0;
}
 
//
template<class T> void
TOleFactoryNoAuto<T>::UnregisterAutomation(T* /*app*/) {
 
}
 
//----------------------------------------------------------------------------
/// Automated application default automation callout implementation
//
template <class T> struct TOleFactoryAuto {
  static void      AutomateApp(T* app, owl::uint32 options);
  static TUnknown* AutomateObject(T* app, const void* obj,const std::type_info& info);
  static void      UnregisterAutomation(T* app);
};
 
//
/// Default callout to aggregate an automation helper to an automated object
//
template <class T> TUnknown*
TOleFactoryAuto<T>::AutomateObject(T* app,const void* obj,const std::type_info& info)
{
  using ::Registrar;
  CHECK(Registrar);
  return Registrar->CreateAutoObject(obj, info, app, typeid(*app));
}
 
//
/// Default callout to unregister automation active object
//
template <class T> void
TOleFactoryAuto<T>::UnregisterAutomation(T* app)
{
  using ::Registrar;
  CHECK(Registrar);
  Registrar->ReleaseAutoApp(TAutoObject<T>(app));
}
 
//
/// Default callout to aggregate an automation helper to an automated app
//
template <class T> void
TOleFactoryAuto<T>::AutomateApp(T* app, owl::uint32 options)
{
  using ::Registrar;
  CHECK(Registrar);
  Registrar->CreateAutoApp(TAutoObjectDelete<T>(app), options);
}
 
//----------------------------------------------------------------------------
/// Application creation/destruction callouts shared for doc/view and non-d/v
//
template<class T, class Auto> struct TOleFactoryAppBase {
  static T*        CreateApp(owl::uint32 options);
  static void      DestroyApp(T* app);
};
 
//
template<class T, class Auto> T*
TOleFactoryAppBase<T, Auto>::CreateApp(owl::uint32 options)
{
  T* app = new T;
  if ((options & amEmbedding) || !(options & amExeMode))
    app->SetCmdShow(SW_HIDE);
  using ::Registrar;
  CHECK(Registrar);
  app->OcInit(dynamic_cast<TOcRegistrar&>(*Registrar), options);
  Auto::AutomateApp(app, options);
  app->Start();
  return app;
}
 
//
template<class T, class Auto>
void TOleFactoryAppBase<T, Auto>::DestroyApp(T* app)
{
  Auto::UnregisterAutomation(app);
  delete app;
}
 
//----------------------------------------------------------------------------
/// Non-docview application callout implementation, no CreateObject implemented
/// User must either provide an implementation of CreateOleObject for app class
/// or else reimplement this template function for the particular class
//
template<class T, class Auto> struct TOleFactoryNoDocView
                                   : TOleFactoryAppBase<T, Auto> {
  static TUnknown* CreateObject(T* app, owl::uint32 options, owl::TRegLink* link);
};
 
//
template <class T, class Auto> TUnknown*
TOleFactoryNoDocView<T, Auto>::CreateObject(T* app, owl::uint32 options,
                                            owl::TRegLink* link)
{
  return app->CreateOleObject(options, link);
}
 
//----------------------------------------------------------------------------
/// Docview application callout implementation - supplies CreateObject function
//
template <class T, class Auto> struct TOleFactoryDocView
                                    : TOleFactoryAppBase<T, Auto> {
  static TUnknown* CreateObject(T* app, owl::uint32 options, owl::TRegLink* link);
};
 
//
template <class T, class Auto> TUnknown*
TOleFactoryDocView<T, Auto>::CreateObject(T* app, owl::uint32 options, owl::TRegLink* link)
{
  TUnknown* obj = 0;
  if (!link)      // if not coming up embedded, we don't know what to make here
    return 0;
  owl::TDocManager* docMan = app->GetDocManager();
  if (!docMan)
    return 0;
  owl::TDocTemplate* tpl = static_cast<owl::TDocTemplate*>(link);
  owl::TDocument* doc = docMan->CreateDoc(tpl, 0, 0, owl::dtNewDoc | owl::dtNoAutoView);
  owl::TView* view = tpl->ConstructView(*doc);
  ocf::TOleWindow* ow = TYPESAFE_DOWNCAST(view, ocf::TOleWindow);
  if (ow) {
    obj = ow->CreateOcView(tpl, (options & amEmbedding) != 0, 0);
    ocf::TUnknown* autoObj;
    void* viewObj = dynamic_cast<void*>(view); // get address of derived most
    void* docObj = dynamic_cast<void*>(doc);
  if ((autoObj = Auto::AutomateObject(app, viewObj, typeid(*view))) != 0 ||
        (autoObj = Auto::AutomateObject(app, docObj,  typeid(*doc)))  != 0) {
      obj->SetOuter(&autoObj->Aggregate(*obj));
      obj->AdjustRefCount(-1);  // remove extra ref count
      obj = autoObj;
      obj->AdjustRefCount(+1);  // add it back to the new outer sub-object
    }
  }
  doc->InitView(view);
  return (options & amEmbedding) ? obj : 0;
}
 
//----------------------------------------------------------------------------
// Standard factory for OWL components, callouts supplied via template args
//
/// A template class, TOleFactoryBase<> creates callback code for ObjectWindows
/// classes. The main purpose of the factory code is to provide a callback function,
/// Create, that ObjectComponents calls to create objects.
///
/// Just as a recipe consists of a list of instructions about how to make a
/// particular kind of food, a template, such as TOleFactoryBase<>, contains
/// instructions about how to make an object, in this case, a factory object.
/// TOleFactoryBase<> includes two public member functions. The three additional
/// functions are passed as template arguments. Although these template arguments
/// actually belong to the class that is instantiated when you fill in the arguments
/// to TOleFactoryBase<>, they are described here for convenience.
///
/// Use TOleFactoryBase<> to manufacture objects in general, whether or not they are
/// embedded, OLE-enabled, or use the Doc/View model. These objects might or might
/// not be connected to OLE.
///
/// The callouts are supplied through the arguments passed to the template class.
/// The factory base class takes three template parameters: the application type, a
/// set of functions to create the object, and a set of functions to create an
/// automation object. Depending on the arguments passed, you can make the following
/// OLE-enabled components:
/// - Doc/View components that are automated
/// - Doc/View components that are not automated
/// - Non-Doc/View components that are automated
/// - Non-Doc/View components that are not automated
///
/// ObjectWindows provides a standard implementation for object creation and
/// automation. Factory Template Classes gives an overview of these classes.
///
/// By using TOleFactoryBase<> to obtain an OLE interface for your application, you
/// can make objects that are accessible to OLE. That is, TOleFactoryBase<> handles
/// any relationships with IUnknown, a standard OLE interface.
template <class T, class Obj> class TOleFactoryBase {
  public:
/// Converts the object into a pointer to the factory. ObjectComponents uses this
/// pointer to create the object.
    operator TComponentFactory() {return Create;}
    static IUnknown* Create(IUnknown* outer, owl::uint32 options, owl::uint32 id);
};
 
/*
//
template <class T, class Obj>
TOleFactoryBase<T, Obj>::operator TComponentFactory()
{
  return Create;
}
*/
 
//
// Main Create callback function called to create app and/or object
//
/// A TComponentFactory callback function that creates or destroys the application
/// or creates objects. If an application object does not already exist, Create
/// creates a new one. The outer argument points to the OLE 2 IUnknown  interface
/// with which this object aggregates itself. If outer is 0,  If outer is 0, the
/// object will become an independent object.
/// The options argument indicates the application's mode while it is running. The
/// values for options are either set from the command line or set by
/// ObjectComponents. They are passed in by the Registrar to this callback. The
/// application looks at these flags in order to know how to operate, and the
/// factory callback looks at them in order to know what to do. For example, a value
/// of amExeMode indicates that the server is running as an .EXE either because it
/// was built as an .EXE or because it is a .DLL that was launched by an .EXE stub
/// and is now running as an executable program. The TOcAppMode enum description
/// shows the possible values for the options argument.
/// If the application already exists and the object ID (id) equals 0, Create
/// returns the application's OLE interface. Otherwise, it calls OCInit to create a
/// new TOcApp and register the options from TOcAppMode enum, which contains
/// OLE-related flags used in the application's command line. (These flags tell the
/// application whether it has been run as a server, whether it needs to register
/// itself, and so on.) If a component ID was passed, that becomes the component;
/// otherwise, Create runs the application itself based on the values of the
/// TOcAppMode enum and returns the OLE interface.
///
/// \image html bm59.BMP
template <class T, class Obj> IUnknown*
TOleFactoryBase<T, Obj>::Create(IUnknown* outer, owl::uint32 options, owl::uint32 id)
{
  owl::TRegLink* link = reinterpret_cast<owl::TRegLink*>(id);
 
  // Look for the app object for this process, creating one if necessary
  //
  owl::TApplication* existingApp = owl::OWLGetAppDictionary().GetApplication();
  T* app;
  if (!existingApp) {
    if (options & amShutdown)   // app already destructed
      return 0;
    app = Obj::CreateApp(options);
    if (!link && !(options & amEmbedding)) {
      Obj::CreateObject(app, options, link);
    }
  } else {
    app = TYPESAFE_DOWNCAST(existingApp, T);
    if (options & amShutdown) {
      Obj::DestroyApp(app);
      return 0;  // any interface present when passed in has now been released
    }
  }
  TUnknown* obj = app->OcApp;   // app's COM interface, used if not doc object
 
  // If a component ID was passed, make that component, otherwise return app
  //
  if (link) {
    TUnknown* doc = Obj::CreateObject(app, options, link);
    if (doc)
      obj = doc;
    else if (!(options & amEmbedding))  // run DLL in ExeMode from doc factory
      app->OcApp->SetOption(amServedApp, true);
    else
      return 0;  // doc factory failed
  }
  IUnknown* ifc = obj ? obj->SetOuter(outer) : 0; // aggregate to passed outer
 
  // Run message look if ExeMode, either EXE server or DLL server force to run
  // EXE servers come through here twice, no Run if 2nd pass from factory call
  //
  if (options & amRun)
    app->Run();
 
  return ifc;
}
 
//----------------------------------------------------------------------------
///  Factory for OWL non-Doc/View, non-automated OLE components
//
template <class T> class TOleFactory
: public TOleFactoryBase<T, TOleFactoryNoDocView<T, TOleFactoryNoAuto<T> > >
{
};
 
//
///  Factory for OWL Doc/View, non-automated OLE components
//
template <class T> class TOleDocViewFactory
: public TOleFactoryBase<T, TOleFactoryDocView<T, TOleFactoryNoAuto<T> > >
{
};
 
//
///  Factory for OWL non-Doc/View, automated OLE components
//
template <class T> class TOleAutoFactory
: public TOleFactoryBase<T, TOleFactoryNoDocView<T, TOleFactoryAuto<T> > >
{
};
 
//
///  Factory for OWL Doc/View, automated OLE components
//
template <class T> class TOleDocViewAutoFactory
: public TOleFactoryBase<T, TOleFactoryDocView<T, TOleFactoryAuto<T> > >
{
};
 
//----------------------------------------------------------------------------
//  Factory for OWL automated OLE components, no linking/embedding support
//
 
/// A template class, TAutoFactory<> creates callback code for ObjectWindows
/// classes. The application class is passed as the argument to the template. By
/// itself, TAutoFactory<> does not provide linking or embedding support for
/// ObjectWindows automated applications.
///
/// Although TAutoFactory<> simplifies the process of creating the callback
/// function, you can write your own callback function or provide alternate
/// implementation for any or all of TAutoFactory<>'s functions.
template <class T> class TAutoFactory {
  public:
/// Converts the object into a pointer to the factory. ObjectComponents uses this
/// pointer to create the automated object.
    operator TComponentFactory() {return Create;}
 
    // Callouts to allow replacement of individual creation steps
    //
    static T*        CreateApp(owl::uint32 options);
    static void      DestroyApp(T* app);
 
    // Main Create callback function called to create app and/or object
    //
    static IUnknown* Create(IUnknown* outer, owl::uint32 options, owl::uint32 id);
};
 
/*
//
template <class T>
TAutoFactory<T>::operator TComponentFactory()
{
  return Create;
}
*/
 
//
/// Called when the app is not found and needs to be created
//
/// CreateApp creates a new automated application. By default, it creates a new
/// application of template type T with no arguments. The options argument is one of
/// the TOcAppMode enum values, for example, amRun, amAutomation, and so on that
/// indicate the application's mode when running.
//
template <class T> T*
TAutoFactory<T>::CreateApp(owl::uint32 options)
{
  T* app = new T;
  if ((options & amEmbedding) || !(options & amExeMode))
    app->nCmdShow = SW_HIDE;
  app->Start();
  return app;
}
 
//
/// Destroys the previously created application referred to in app.
//
template <class T> void
TAutoFactory<T>::DestroyApp(T* app)
{
  delete app;
}
 
//
/// Create is a TComponentFactory callback function that creates or destroys the
/// application or creates objects. If an application object does not already exist,
/// Create creates a new one. The outer argument points to the OLE 2 IUnknown
/// interface with which this object aggregates itself. If outer is 0, the new
/// object is not aggregated, or it will become the main object.
/// The options argument indicates the application's mode while it is running. The
/// values for options are either set from the command line or set by
/// ObjectComponents. They are passed in by the "Registrar" to this callback. The
/// application looks at these flags to know how to operate, and the factory
/// callback looks at them to know what to do. For example, a value of amExeMode
/// indicates that the server is running as an .EXE either because it was built as
/// an .EXE or because it is a .DLL that was launched by an .EXE stub and is now
/// running as an executable program. See TOcAppMode enum for a description of the
/// possible values for the options argument.
/// If the application already exists, Create returns the application's OLE
/// interface and registers the options from TOcAppMode enum which contains
/// OLE-related flags used in the application's command line. For example, the
/// amAutomation flag tells the server to register itself as a single-user
/// application. (In general, these flags tell the application whether it has been
/// run as a server, whether it needs to register itself, and so on.)
/// The id argument, which is not used for TAutoFactory, is always 0.
///
/// \image html bm59.BMP
//
template <class T> IUnknown*
TAutoFactory<T>::Create(IUnknown* outer, owl::uint32 options, owl::uint32 /*id*/)
{
  IUnknown* ifc = 0;
  owl::TApplication* existingApp = owl::OWLGetAppDictionary().GetApplication();
  T* app;
  if (!existingApp) {
    if (options & amShutdown)   // app already destructed
      return 0;
    app = CreateApp(options);
  }
  else {
    app = TYPESAFE_DOWNCAST(existingApp, T);
    if (options & amShutdown) {
      DestroyApp(app);
      return (options & amServedApp) ? 0 : outer;
    }
  }
 
  if (options & amServedApp) {
    using ::Registrar;
    CHECK(Registrar);
    TUnknown* obj = Registrar->CreateAutoApp(TAutoObjectDelete<T>(app),
                                               options, outer);
    ifc = *obj;  // does an AddRef, reference count owned by container
  }
 
  if (options & amRun) {
    app->Run();
  }
  return ifc;
}
 
/// \cond NoSuppressDoxygenWarning
#include <owl/posclass.h>
/// \endcond
 
} // OCF namespace
 
 
#endif  // OWL_OLEFACTO_H

V773 The exception was thrown without releasing the 'app' pointer. A memory leak is possible.

V522 There might be dereferencing of a potential null pointer 'app'.

V522 There might be dereferencing of a potential null pointer 'app'.