NCSA Symera
by Pat Flanigan and Jawed Karim


Listing One
///////// SymLib (symobj.h)  
#include <objbase.h>
#include "SymCon.h"
#include "SymSem.h"
class CSymObjRef;
class CSymObj : public IS3JobImp,
                public IS3SymObj,
                public CConnObject
{
private:
    DWORD         m_cRef;          // object reference count
    CS3Semaphore  m_Semaphore;     // critical section semaphore
    DWORD         m_dwObjectID;    // application-unique object ID
    DWORD         m_dwIJobConGIT;  // GIT cookie for Job Controller
protected:
    List<CSymObjRef*> m_ObjectList; 
    CSymObj();
    ~CSymObj();
public:
    static ULONG g_objcount;
    // IUnknown methods 
    STDMETHOD(QueryInterface)(REFIID riid, void** ppvObj);
    STDMETHOD_(ULONG, AddRef)(void);
    STDMETHOD_(ULONG, Release)(void);
    
    // IS3JobImp methods
    STDMETHOD(SetObjectID)(TIME time, DWORD dwObjectID);
    STDMETHOD(GetObjectID)(TIME time, DWORD* pdwObjectID);
    STDMETHOD(CreateConnectionPoint)(REFIID riid);

    // IS3SymObj methods
    STDMETHOD(Send)(TIME time, DWORD dwObjectID, DWORD dwType, BYTE* pData, 
                    long lBytes, DWORD dwFlags);
    // CConnObj virtual methods... fired in CConnObj when passive connections 
    // are created upon Advise() and destroyed upon Unadvise()
    virtual HRESULT AdviseNotify(DWORD dwAdviseCookie, void* pSink);
    virtual HRESULT UnadviseNotify(DWORD dwAdviseCookie);
        
    // virtual handlers
    virtual BOOL OnSend(DWORD dwObjectID, DWORD dwType, 
                     BYTE *pData, long l) {return FALSE;}
    HRESULT SendTo(DWORD dwTargetID, DWORD dwType, BYTE* pData = NULL, 
                    long lBytes = 0, DWORD dwFlags = S3CALL_SYNC);
    void    SetObjectID(DWORD dwID) { m_dwObjectID = dwID; }
    DWORD   GetObjectID() { return m_dwObjectID; }
    int     ObjectCount() { return m_ObjectList.GetCount(); }
    BOOL    AddObject(CSymObjRef* pObj);
    BOOL    RemoveObject(CSymObjRef* pObj);
    HRESULT CreateGIT();
    HRESULT DestroyAllObjects();
    HRESULT Connect(CSymObjRef* pRefObj,    // the calling CSymObjRef
        REFCLSID rclsid,        // CLSID of the requested object
        const char* szMachine,  // machine for creation, if NULL: local
        void** ppUnk,           // retrieved pointer IUnknown 
        void** ppSym,           // retrieved pointer IS3SymObj
        void** ppConn,          // retrieved pointer IConnectionPointContainer
        DWORD dwAppObjectID,    // application specific ID
        DWORD dwCoupleObjID);   // "coupling" directive object ID

    HRESULT Disconnect(DWORD dwICPCGIT, DWORD dwAdviseCookie); 
    HRESULT AdviseObject(IConnectionPointContainer* pConn, DWORD* pdwCookie);
    HRESULT UnadviseObject(DWORD dwICPCGIT, DWORD dwAdviseCookie);
    HRESULT GetpConn(DWORD dwICPCGIT, IConnectionPointContainer** ppConn);
    HRESULT GetJCInterface(IS3JobCon** ppJobCon);
    HRESULT SetJCInterface();
    HRESULT RevokeJCInterface();
};

Listing Two
///////// SymLib (symobjref.h)  
#include <ocidl.h>
#include <limits.h>
#include "SymLibPS.h"
#include "SymObj.h"
#define  NO_COUPLING UINT_MAX
#define  PARENT      0

class CSymObjRef
{
friend class CSymObj;
private:
    char*      m_szMachine;
    LPOLESTR   m_szCLSID;
    DWORD      m_dwAppObjectID;
    CSymObj*   m_pParentObject;

    // Global Interface Table cookies
    DWORD      m_dwIMonGIT;
    DWORD      m_dwIUnkGIT;
    DWORD      m_dwISymGIT;
    DWORD      m_dwICPCGIT;
    DWORD      m_dwAdviseCookie;
    
    // private default constructor
    CSymObjRef() {}
public:
    // constructor for explicit creation
    CSymObjRef(CSymObj* pParent, REFCLSID rclsid, DWORD dwAppObjectID = 0, 
           const char* szMachine = NULL, DWORD dwCoupleObjID = NO_COUPLING);
    // constructor for passive connection creation
    CSymObjRef(CSymObj* pParent, DWORD dwAppObjectID, DWORD dwAdviseCookie, 
               IUnknown* pUnk, IS3SymObj* pSym);
    ~CSymObjRef();
    void       Cleanup();
    BOOL       SetMachine(const char* szMachine);
    char*      GetMachine() { return m_szMachine; }
    HRESULT    SetCLSID(REFCLSID rclsid); 
    LPOLESTR   GetCLSID() { return m_szCLSID; }
    void       SetAppObjID(DWORD dwAppObjectID) { m_dwAppObjectID = 
                                                             dwAppObjectID; }
    DWORD      GetAppObjID() { return m_dwAppObjectID; }
    void       SetParent(CSymObj* pParent) { m_pParentObject = pParent; }
    CSymObj*   GetParent() { return m_pParentObject; }
    HRESULT    SetInterfaces(IUnknown* pUnk, IS3SymObj* pSym, 
                             IConnectionPointContainer* pConn = NULL);
    HRESULT    RevokeInterfaces();
    HRESULT    GetpUnk(IUnknown** ppUnk);
    HRESULT    GetpSym(IS3SymObj** ppSym);
    HRESULT    GetCPCcookie() { return m_dwICPCGIT; }
    void       SetAdviseCookie(DWORD dwCookie) { m_dwAdviseCookie=dwCookie; }
    DWORD      GetAdviseCookie() { return m_dwAdviseCookie; }
        
    // IS3SymObj method handlers
    HRESULT    Send(DWORD dwType = 0, BYTE* pData = NULL, long lBytes = 0, 
                    DWORD dwFlags = S3CALL_SYNC);
};

Listing Three
///////// Life3D (cubeface.h) ...first version 
const NUM_NEIGHBORS = 4;
const NUM_FACES = 6;

#define WM_BORDER_UPDATE WM_USER+1000
typedef enum tagNeighborTypes
{
    LEFT, TOP, RIGHT, BOTTOM 
} NEIGHBOR;
class CMainWindow; 
class CCubeFace
{
    CMainWindow* m_pMainWnd;    // main window
    int          m_iWhichFace;  // which of the six faces?
    int          m_iDimension;  // dimension + 2(border cells)
    bool**       m_ppCells;     // cell state array
    bool**       m_ppTemp;      // temp state array
    int*         m_pBorderIDs;  // neighbor ID's
    
    void GrowthPhase();
    void CleanUp();
    NEIGHBOR WhoIsIt(int);
public:
    CCubeFace(int dim, int which);
    ~CCubeFace();

    void UpdateBorders();
    void CreateNextGeneration();
    void ClearAll();
    void RandomCells();
    void ConnectNeighbors();
    void SetState(int, int, bool);
    void ReDimension(int);
    long UpdateBordersIn(int, BYTE*, long);
    
    inline bool GetState(int i, int j) { return m_ppCells[i+1][j+1]; }
    inline int  GetNumberOfCells() { return m_iDimension-2; }
    void SaveFace (FILE*);
    void LoadFace (FILE*);
};

Listing Four
///////// Life3D (cubeface.h) ...Symera version 
// interface class
#include <SymObjRef.h>
#include <SymObjCF.h>

// {99CA424F-1059-11d2-9835-0060B0CE3DAD}
const CLSID CLSID_FaceImp = {0x99ca424f,0x1059,0x11d2,{0x98,0x35,0x00,0x60,
                                                      0xb0,0xce,0x3d,0xad}};
enum ImplementTypes
{
    IMP_UPDATE_BORDERS, IMP_CREATE_NEXT, IMP_SET_STATE, IMP_CLEAR_ALL, 
    IMP_RANDOM_CELLS, IMP_REDIMENSION, IMP_CONNECT_NEIGHBORS, IMP_UPDATE
};
class CMainWindow;
class CCubeFace : public CSymObjRef
{
    CMainWindow* m_pMainWnd;
    int          m_iWhichFace;  // which of the six faces?
    int          m_iDimension;  // dimension + 2(border cells)
    bool**       m_ppCells;     // cell state array

    void CleanUp();
public:
    CCubeFace(int dim, int which, CSymObj* pParent);
    ~CCubeFace();

    // interface (externally called) functions that are mapped to CFace object
    HRESULT UpdateBorders();
    HRESULT CreateNextGeneration();
    HRESULT ClearAll(bool bLocal = false);
    HRESULT RandomCells();
    HRESULT ConnectNeighbors();
    HRESULT SetState (int, int, bool);
    HRESULT ReDimension(int);

    inline bool GetState(int i, int j) { return m_ppCells[i+1][j+1]; }
    inline int  GetNumberOfCells() { return m_iDimension-2; }
    void   SaveFace (FILE*);
    void   LoadFace (FILE*); 
    void   UpdateState(BYTE* pData, long lBytes);
};

Listing Five
///////// Life3D (face.h) ...Symera version 
// implementation COM class
#include <SymStream.h>
#include <SymString.h>
#include <SymObjRef.h>
#include <SymObjCF.h>

// {99CA424F-1059-11d2-9835-0060B0CE3DAD}
const CLSID CLSID_FaceImp = {0x99ca424f,0x1059,0x11d2,{0x98,0x35,0x00,0x60,
                                                       0xb0,0xce,0x3d,0xad}};
const NUM_NEIGHBORS = 4;
const NUM_FACES = 6;

enum ImplementTypes
{
    IMP_UPDATE_BORDERS, IMP_CREATE_NEXT, IMP_SET_STATE, IMP_CLEAR_ALL, 
    IMP_RANDOM_CELLS, IMP_REDIMENSION, IMP_CONNECT_NEIGHBORS, IMP_UPDATE
};
typedef enum tagNeighborTypes
{
    LEFT, TOP, RIGHT, BOTTOM 
} NEIGHBOR;

class CFace : public CSymObj
{
    int          m_iWhichFace;  // which of the six faces?
    int          m_iDimension;  // dimension + 2(border cells)
    bool**       m_ppCells;     // cell state array
    bool**       m_ppTemp;      // temp state array
    int*         m_pBorderIDs;  // neighbor ID's
    
    void GrowthPhase();
    void CleanUp();
    void UpdateParent();
    NEIGHBOR WhoIsIt(int);
public:
    CFace();
    ~CFace();

    // CSymObj virtual methods
    virtual BOOL OnSend(DWORD dwFace, DWORD dwType, BYTE *pData, long lBytes);

    // interface (externally called) functions mapped to CCubeFace ref object
    void UpdateBorders();
    void CreateNextGeneration();
    void ClearAll();
    void RandomCells();
    void ConnectNeighbors();
    void SetState (BYTE*, long);
    void ReDimension(BYTE*, long);
    void UpdateBordersIn(DWORD, BYTE*, long);
};

Listing Six
///////// TestObj (main.cpp)
#include <SymUtils.h>
#include "TestObj.h"
/////////////////////////////////////////////////////////////////////////////
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                                LPTSTR lpCmdLine, int nShowCmd)
{
    HRESULT hr = E_FAIL;
    try
    {
        BOOL bEmbedded = FALSE; 
        BOOL bRegister = FALSE;
        TCHAR szTokens[] = _T(" -/");
        LPCTSTR lpszToken = _tcstok(lpCmdLine, szTokens);
        while (lpszToken)
        {
            // check to see if COM started server
            if (!_tcsicmp(lpszToken, _T("Embedding")))
            {
                bEmbedded = TRUE; // started by COM 
                break;
            }
            else if (!_tcsicmp(lpszToken, _T("RegServer")))
            {
                // register the server
                hr = RegisterServer(CLSID_TestObj, _T("TestObj.TestObj.1"), 
                                                        _T("TestObj.Class"));
                if (FAILED(hr))
                    throw("RegisterServer() failed...");
            }
            else if (!_tcsicmp(lpszToken, _T("RegApp")))
            {
                // register the application
                hr = RegisterApp("TestApp");
                if (FAILED(hr))
                    throw("RegisterApp() failed...");
            }
            else if (!_tcsicmp(lpszToken, _T("UnRegServer")))
            {
                // unregister the server
                hr = UnRegisterServer(CLSID_TestObj, _T("TestObj.TestObj.1"), 
                                                        _T("TestObj.Class"));
                if (FAILED(hr))
                    throw("UnRegisterServer() failed...");
            }
            else if (!_tcsicmp(lpszToken, _T("UnRegApp")))
            {
                // unregister the application
                hr = UnRegisterApp("TestApp");
                if (FAILED(hr))
                    throw("RegisterApp() failed...");
            }
            lpszToken = _tcstok(NULL, szTokens);
            bRegister = TRUE;
        }
        if (bRegister)
            return 0;

        // initialize COM
        hr = InitCOM();
        if (FAILED(hr))
            throw("InitCOM() failed...");
 
        // initialize the class factory
        LPCLASSFACTORY pcf = new CSymObjCF<CTestObj>;
        hr = InitClassFactory(pcf, CLSID_TestObj);
        if (FAILED(hr))
            throw("InitClassFactory() failed...");
 
        if (!bEmbedded)
        {
            // initialize Symera interaction
            hr = InitSymeraHost("octave.job");
            if (FAILED(hr))
                throw("InitSymeraHost() failed...");
            // create GUI here if desired
            // stop Symera interaction
            hr = RevokeSymeraHost();
            if (FAILED(hr))
                throw("RevokeSymeraHost() failed...");
        }
        else
        {
            MSG msg;
            while (GetMessage(&msg, NULL, 0, 0))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        // destroy the class factory
        hr = RevokeClassFactory();
        if (FAILED(hr))
            throw("RevokeClassFactory() failed...");
        // uninitialize COM
        hr = RevokeCOM();
        if (FAILED(hr))
            throw("RevokeCOM() failed...");
    }
    catch(char* szComment)
    {
        LastErrorBox(szComment, hr);
    } 
    return 0;
}
///////// TestObj (testobj.h)
// {5E1BD1C5-20C9-11d2-9845-0060B0CE3DAD}
const CLSID CLSID_TestObj = {0x5e1bd1c5,0x20c9,0x11d2,{0x98,0x45,0x00,0x60,
                                                       0xb0,0xce,0x3d,0xad}};
class CTestObj : public CSymObj
{
public:
    CTestObj();
    ~CTestObj();

   // CSymObj virtual methods
   virtual BOOL OnSend(DWORD dwObjectID,DWORD dwType,BYTE *pData,long lBytes);
};
///////// TestObj (testobj.cpp)
#include "TestObj.h"
// implement the class factory for CBeep
IMPLEMENT_IUNKNOWN(CSymObjCF<CTestObj>, IID_IClassFactory, IClassFactory)
IMPLEMENT_ICLASSFACTORY(CSymObjCF<CTestObj>, CLSID_TestObj)

CTestObj::CTestObj()
{   
}
CTestObj::~CTestObj()
{
}
// incoming CSymObj methods
BOOL CTestObj::OnSend(DWORD dwObjectID,DWORD dwType,BYTE *pData,long lBytes)
{
    // implementation
    return TRUE;
}

Listing Seven
///////// TestObj (testobj.job)  
<S3JOB>
<META>
    <NAME>Life3D Job File</NAME>
    <DESCRIPTION>This job file is used by TestObj.</DESCRIPTION>
    <SUBMITTER>Vic Wrestle</SUBMITTER>
    <DATE FORMAT="UNIX">Wed Jul 29 16:05:52 CDT 1998</DATE>
</META>
<NODE>
    <DRONE
    ID="TestObj_Drone"
    SRC="s3trans://cosmo/c:/symera/bin/TestObj.exe" 
    CLSID="{5E1BD1C5-20C9-11d2-9845-0060B0CE3DAD}">
    </DRONE>
</NODE>
    <NOTIFICATION TYPE="email" EMAIL="vic@ncsa.uiuc.edu">
    <OUTFILE DEST="s3trans://cosmo/c:/symera/results/results.dat"/>
    <LOGFILE DEST="s3trans//cosmo/c:/symera/results/log.txt"/>
    </NOTIFICATION>
</S3JOB>


1


