Automate ODTK With C# and C++

In addition to invoking a full copy of ODTK application, you can now use a slimmed down version of the ODTK.Engine, but you still have the responsibility to initialize most of its environment yourself. The following examples show how to integrate the ODTK Engine into C# or C++ applications. Please contact AGI Technical Support for any additional questions.

C# Example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ODTKEngLib;

namespace ODTKEngTestCS
{
    class Program
    {
        static void Main(string[] args)
        {
            Type oType = Type.GetTypeFromProgID("ODTK6.Engine");
            //Type oType = Type.GetTypeFromProgID("ODTK6.Automation");
            dynamic eng1 = Activator.CreateInstance(oType);
            eng1.Visible = false;
            eng1.UserControl = false;
            eng1.OpenLogFile(@"c:\temp\logCS.txt", AgEOpenLogFileMode.eOpenLogFileForWriting);
            eng1.LogMsg(AgEUiLogMsgType.eUiLogMsgInfo, "Hi");
            
            eng1.LoadPersonality("ODTK.Engine"); // Do not load any user preferences for engine

            dynamic ODTK = eng1.Personality;
            string userPath = ODTK.ApplicationPathUserData.value;

            dynamic ne = ODTK.Application.TrackingDataFileTypes.NewElem();
                ne.Extensions = "geosc;geos;dat";
                ne.PluginID   = "IAgODProvideTrackingData6.AgODProvideGeoscTrackingData";
            ODTK.Application.TrackingDataFileTypes.insert(ne);
                ne.Extensions = "gobs;s";
                ne.PluginID   = "IAgODProvideTrackingData6.AgODProvideGenericTrackingData";
            ODTK.Application.TrackingDataFileTypes.insert(ne);
            
            dynamic res = (ODTK.Application.LoadObject("", @"c:\temp\Scenario1.sco")).Value;

            if (res == true)
            {
                dynamic scen = ODTK.Children.Scenario.Item(0);
                string scName = scen.name.Value;
                eng1.LogMsg(AgEUiLogMsgType.eUiLogMsgDebug, "scenName = " + scName);


                dynamic fil = scen.Filter.Item(0);
                dynamic res2 = fil.Go();

                eng1.LogMsg(AgEUiLogMsgType.eUiLogMsgDebug, "filter.Go() returned = " + res2.value);

                ODTK.Application.DeleteObject(scen);
            }
        }
    }
}

C++ Example

#define _CRT_SECURE_NO_WARNINGS

#include 
#define _AFXDLL
#include 
#include 
#include 
#include 
#include 

#import "C:\Program Files (x86)\AGI\ODTK 6\bin\ODTKEng.dll"

int lAgFpieeeHandler(_FPIEEE_RECORD *pieee);

#define X(expr) if( !(SUCCEEDED(expr)) ) exit(__LINE__)

#define GetDD(DD,name,propDD) { VARIANT v; X(DD.GetPropertyByName(name,&v)); propDD.p = v.pdispVal; }
#define GetVal(DD,name,propV) { CComDispatchDriver propDD; GetDD(DD,name,propDD); X(propDD.GetPropertyByName(L"value",propV)); }
#define SetVal(DD,name,propV) { CComVariant vv(propV); X(DD.PutPropertyByName(name,&vv));       }
#define ConvertRetVal(retVar) { CComDispatchDriver propDD; propDD.p = retVar.pdispVal; retVar.vt = VT_EMPTY; X(propDD.GetPropertyByName(L"value",&retVar)); }

#define Iv0( DD,funcName)         { DISPID funcID; X(DD.GetIDOfName(funcName,&funcID)); X(DD.Invoke0(funcID)); }
#define Iv0r(DD,funcName,ret) { DISPID funcID; X(DD.GetIDOfName(funcName,&funcID));     X(DD.Invoke0(funcID,ret)); }

#define Iv1( DD,funcName,a1)   { DISPID funcID; CComVariant v1(a1); X(DD.GetIDOfName(funcName,&funcID)); X(DD.Invoke1(funcID,&v1)); }
#define Iv1r(DD,funcName,a1,r) { DISPID funcID; CComVariant v1(a1); X(DD.GetIDOfName(funcName,&funcID)); X(DD.Invoke1(funcID,&v1,r)); }

#define Iv2(DD,funcName,arg1,arg2)      \
        {DISPID funcID; CComVariant varg1(arg1), varg2(arg2);\
        X(DD.GetIDOfName(funcName,&funcID));\
        X(DD.Invoke2(funcID,&varg1,&varg2));\
        }

#define GetItem(DD,scopeName,i,itemDD) \
        { CComDispatchDriver scopeDD;\
          GetDD(DD,scopeName,scopeDD);\
          VARIANT v; Iv1r(scopeDD, L"Item",i,&v); itemDD.p = v.pdispVal; }


void run(void)
{
        char str[128];
        CComVariant v1;
        CComBSTR z, z2, z3;
        ODTKEngLib::IAgODTKEnginePtr eng1;
        CComDispatchDriver persDD, appDD, appChDD, scenDD, simDD, filDD, trkDD, neDD, rDD;

        X(CoInitialize(0));
        X(eng1.CreateInstance("ODTK6.Engine"));
        //X(eng1->put_LoggingMode(eLogActive));
        X(eng1->raw_OpenLogFile(L"c:\\temp\\log1.txt", ODTKEngLib::eOpenLogFileForWriting,&v1.boolVal));

        eng1->raw_GetLicenseHostID(&z);
        eng1->get_Version(&z2);
        eng1->get_LogFile(&z3);

        X(eng1->raw_LogMsg(ODTKEngLib::eUiLogMsgDebug,z));

        X(eng1->get_Personality(&persDD.p));

        GetDD(persDD, L"Application", appDD );
        GetDD(persDD, L"Children",        appChDD );
        GetDD(appDD,  L"TrackingDataFileTypes", trkDD );

        Iv0r(trkDD,L"NewElem",&v1); neDD = v1.pdispVal;
                SetVal(neDD,L"Extensions",L"geosc;geos;dat");
                SetVal(neDD,L"PluginID",L"IAgODProvideTrackingData6.AgODProvideGeoscTrackingData");
        Iv1(trkDD, L"insert", CComVariant(neDD.p));
                SetVal(neDD, L"Extensions",L"gobs;s");
                SetVal(neDD, L"PluginID",  L"IAgODProvideTrackingData6.AgODProvideGenericTrackingData");
        Iv1(trkDD, L"insert", CComVariant(neDD.p));

        //
        //  Assuming scenario has ready to run Simulator and Filter objects
        //

        Iv2(appDD,L"LoadObject",L"",L"c:\\temp\\Scenario1.sco");

        GetVal(appChDD, L"size", &v1 );         sprintf_s(str,"#scenario loaded = %d", v1.intVal);      X(eng1->LogMsg(ODTKEngLib::eUiLogMsgDebug,str));

        GetItem(appChDD,L"Scenario",  0, scenDD);
        GetItem(scenDD, L"Simulator", 0, simDD);
        GetItem(scenDD, L"Filter",    0, filDD);

        Iv0r(simDD, L"Go", &v1);        ConvertRetVal(v1);              sprintf_s(str, "# simulator run successfully = %s", v1.boolVal != FALSE ? "true" : "false");    X(eng1->LogMsg(ODTKEngLib::eUiLogMsgDebug, str));

        Iv0r(filDD, L"Go", &v1);        ConvertRetVal(v1);              sprintf_s(str,    "# filter run successfully = %s", v1.boolVal != FALSE ? "true" : "false");    X(eng1->LogMsg(ODTKEngLib::eUiLogMsgDebug, str));
}

int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR lpCmdLine, int nCmdShow)
{
        // By default all exceptions are masked.  Value of the environment 
        // variable determines which ones will be unmasked based on the 
        // exception masks defined in float.h.  _control87 is used rather 
        // than _controlfp because it allows us to control the denormal 
        // exceptions.
        //
        // for example, you could set the environment variable to any 
        // combination of the following.  A typical value to trap 
        // zero divide or invalid numbers would be 0x18.
        // 
        //      _EM_INEXACT    = 0x00000001 
        //      _EM_UNDERFLOW  = 0x00000002 
        //      _EM_OVERFLOW   = 0x00000004 
        //      _EM_ZERODIVIDE = 0x00000008 
        //      _EM_INVALID    = 0x00000010 
        //  _EM_DENORMAL   = 0x00080000

        unsigned int flag = 0x18;

        char *flagStr = getenv("AGI_FLOATING_POINT_EXCEPTIONS");
        if (flagStr != NULL)
        {
                sscanf(flagStr, "%i", &flag);
        }

        // limit the possible values so you can't really
        // screw up the FP processor
        flag &= 0x0008001f;

        int cw = _control87( 0,0 );
        _control87( cw & ~flag, MCW_EM );
        SetProcessAffinityMask(GetCurrentProcess(), 0);//m_nProcAffinityMsk);
        __try
        {
                run();
        }
        __except((_fpieee_flt(GetExceptionCode(), GetExceptionInformation(), lAgFpieeeHandler)))
        {
        }
        
        return 0;
}    


int lAgFpieeeHandler(_FPIEEE_RECORD *pieee)
{
        _clearfp();

        char *sMessage = "Floating point arithmetic error.";

        if(pieee->Cause.ZeroDivide)
        {
                sMessage = "Division by zero.";
        }
        else if(pieee->Cause.InvalidOperation)
        {
                sMessage = "Invalid floating point operation.";
        }
        else if (pieee->Cause.Inexact)
        {
                sMessage = "Inexact result.";
        }
        else if (pieee->Cause.Underflow)
        {
                sMessage = "Underflow occurred.";
        }
        else if (pieee->Cause.Overflow)
        {
                sMessage = "Overflow occurred.";
        }
        else
        {
                sMessage = "An unknown floating point error occurred.";
        }

        fprintf(stderr, "FP exception caught: %s", sMessage);

        return EXCEPTION_CONTINUE_EXECUTION;
}

 

ODTK 6.5