MOCA

Introduction

MOCA allows you to expand Origin's functionality through Dynamic Link Libraries (DLL). MOCA consists of a library of C++ classes. These classes are how a MOCA DLL communicates with Origin. There are classes for worksheets, datasets, matrices, and other major components of Origin.

The functionality of a MOCA DLL is accessed through the properties and methods of a LabTalk object. The DLL's author decides what properties and methods will be necessary to access the functionality offered by the DLL. LabTalk's DLL command is used to map a MOCA DLL to a LabTalk object.

A MOCA-based DLL would enable you to do the following:

  • Add string and numeric properties to LabTalk.
  • Add methods to LabTalk.
  • Add Windows interfaces (for example, dialog boxes, windows, and controls) to script code.
  • Access datasets, worksheets, and matrices from C++ code.
  • Calculate complex math equations faster than LabTalk.
  • Execute LabTalk script from C++ code.
  • All the capabilities of a Windows DLL (communicating with other DLLs and EXEs).

Note: Origin also offers the Origin C programming language. Origin C supports a nearly complete ANSI C language syntax as well as a subset of C++ features including internal and DLL-extended classes. For more information on Origin C, see the Programming Guide. For more information on DLL-extended classes see "Class Extender".

Notes: From Origin 2017, Origin does not ship MOCA files together with Origin. If you need these files, you can download them here.

Structure of a MOCA DLL

A MOCA DLL is simply a DLL using the shared MFC DLLs and linked with OriginLab's MOCA library. It has a CWinApp-derived class and a single object of that application class, as does an executable MFC application (see the MFC documentation for more details on such DLLs).

Each MOCA DLL must contain exactly one main object. The class for the main object must be derived from the CMOCAObjBase class.

Examining the DatasetObj.CPP file found in the MOCA\Dataset\ folder will show you how to structure your main object's CPP file. Use the MOCA_ENTRY_POINT(<class name>) macro to define the function that Origin will use to communicate with your MOCA DLL. Origin expects the exported function to be exported with an ordinal value of 70. To do this simply add a "MocaEntry @70" to your project's .DEF file.

The next three parts are used to map LabTalk properties, methods, and subobjects to member functions and data members of your main object's class. The MOCA_BEGIN_PROP_MAP table is used to map LabTalk properties to member functions and/or data members. There are various macros to use depending on the property data type and the amount of control necessary when setting and getting values. The MOCA_BEGIN_METH_MAP table is used to map LabTalk methods to member functions while the MOCA_BEGIN_SUBOBJ_MAP is used to map subobjects to data members.

The functions mapped to LabTalk properties and methods must be declared as follows:

Numeric Integer Property: BOOL GetFoo(int &I); BOOL SetFoo(int I);

Numeric Real Property: BOOL GetFoo(double &d); BOOL SetFoo(double d);

String Property: BOOL GetFoo(LPSTR pstr); BOOL SetFoo(LPCTSTR pcstr);

Method: BOOL FooMethod(double &dLabTalkReturn, CStringArray &args);

Create a MOCA C++ Project in Visual Studio 2012

Create an MFC DLL Project

First we create a project for creating a simple MFC DLL.

  1. Start Visual Studio 2012
  2. Choose File > New > Project...
  3. In the New Project dialog:
    1. In left panel choose Installed Templates.
    2. Under Installed Templates choose Visual C++.
    3. Under Visual C++ choose MFC.
    4. In middle panel choose MFC DLL.
    5. At bottom of dialog enter a name for your project.
    6. Click the OK button to close dialog.
  4. In the MFC DLL Wizard dialog click the Finish button.

Now you have a project for creating a 32-bit MFC DLL.

If you want to make a 64-bit DLL too then follow the steps below.

  1. In Solution Explorer right-click your project and choose Properties
  2. In Property Pages dialog click the Configuration Manager button in the top right corner.
  3. In the Configuration Manager dialog:
    1. Choose New under Active solution Platform.
    2. In the New Solution Platform dialog set Type to x64 and click OK.
  4. Click Close button to close the Configuration Manager dialog.

Now you have a project that can create 32-bit and 64-bit DLLs.

Change Project Settings to Use MOCA

We need to tell the project where to get the MOCA header and library files.

  1. In Solution Explorer right-click your project and choose Properties
  2. In Property Pages dialog:
    1. Set Configuration to All Configurations
    2. Set Platform to All Platforms
    3. In left panel expand Configuration Properties
    4. Under Configuration Properties choose General
    5. In right panel set Character Set to Use Multi-Byte Character Set
    6. In left panel, under Configuration Properties expand C/C++
    7. Under C/C++ choose General
    8. In right panel set Additional Include Directories to the MOCA include folder.
    9. Under C/C++ choose Preprocessor
    10. In right panel add NO_SHOBJIDL_SORTDIRECTION to Preprocessor Definitions.
    11. In left panel, under Configuration Properties, expand Linker
    12. Under Linker choose General
    13. In right panel set Additional Library Directories to the MOCA lib folder.
    14. In left panel, under Linker, choose Input
    15. In right panel you need to add the omocavc library to Additional Dependencies.
      1. For making 32-bit DLL, set Platform to Win32 and add omocavc9.lib.
      2. For making 64-bit DLL, set Platform to x64 and add omocavc9_64.lib.
    16. Click the OK button to close the Property Pages dialog.

The project's settings are now set for creating a MOCA DLL.

Change Existing Source Code Files

When Visual Studio created the project it also created a number of source code files. We need to change three of these files and all three files have the same name as your project. The three files are the .def, .h, and .cpp file.

The first file we will change is the .def file. Open the .def file and after the EXPORTS line add the following line:

MocaEntry @5

This is the exported function that Origin calls to communicate with the MOCA DLL.

The next file to edit is your project's main header file. It's name will be <projectName>.h. Open the file and scroll to the class definition. In the public overrides, add the following member function:

int ExitInstance();

Remember the name of the class. You will need it when editing the next file. It will follow the syntax C<projectName>App, where <projectName> is the name you gave the Visual Studio project.

The next file to edit is your project's main cpp file. It's name will be <projectName>.cpp. Open the file and after the existing include statements add:

#include "MOCADeclare.h"

Now scroll to the end of the file and add the following function definition:

int CMyProjectApp::ExitInstance()
{
	MOCA_CLEANUP
	return CWinApp::ExitInstance();
}

In the above function definition remember replace CMyProjectApp with your class name.

Add New Source Code Files

You need to add two new source code files to the project. These new files will declare and define the class that will handle your MOCA object.

  1. In Solution Explorer right-click your project and choose Add New Item
  2. In the Add New Item dialog:
    1. In left panel expand Visual C++ and select Code
    2. In middle panel select Header File (.h)
    3. In bottom of dialog give your file a name. In this example, we will name it as CMyMocaObj.h
    4. Click the Add button.

Follow the above instructions again but instead of a new Header File (.h) you want to add a C++ File (.cpp).

Now open the header file (CMyMocaObj.h) and paste into it the following code:

#ifndef _CMyMocaObj_h_
#define _CMyMocaObj_h_

#include "mocamain.h" // Required header file

class CMyMocaObj : public CMOCAObjBase
{
	MOCA_DECLARE_PROP_MAP(CMyMocaObj);
	MOCA_DECLARE_METH_MAP(CMyMocaObj)

public: // constructor and destructor
	CMyMocaObj();
	~CMyMocaObj();

};

#endif // _CMyMocaObj_h_

Now open the c++ file (.cpp) and paste into it the following code:

#include "stdafx.h"
#include "CMyMocaObj.h" // Use the header file created above

MOCA_ENTRY_POINT(CMyMocaObj)

MOCA_BEGIN_PROP_MAP(CMyMocaObj, CMOCAObjBase)
MOCA_END_PROP_MAP(CMyMocaObj, CMOCAObjBase)

MOCA_BEGIN_METH_MAP(CMyMocaObj, CMOCAObjBase)
MOCA_END_METH_MAP(CMyMocaObj, CMOCAObjBase)

CMyMocaObj::CMyMocaObj()
{
}

CMyMocaObj::~CMyMocaObj()
{
}

The project is now ready for you to add methods and properties to your MOCA object.

Add MOCA Properties

There are two types of properties. The first type simply gets mapped to a data member of your MOCA object class. The second type uses member functions of your MOCA object class.

Lets first add an integer property and a string property. Open your MOCA object's header file and add the following to the end of the class declaration:

private:
    int m_nColumnIndex;
    CString m_strWksName;

Now open your MOCA object's c++ file and scroll down to the MOCA_BEGIN_PROP_MAP. Add the following between the MOCA_BEGIN_PROP_MAP and MOCA_END_PROP_MAP statements.

MOCA_SIMPLE_PROP_INT(m_nColumnIndex, "ColumnIndex")
MOCA_SIMPLE_PROP_STR(m_strWksName, "WksName")

The MOCA_SIMPLE_PROP_INT and MOCA_SIMPLE_PROP_STR are macros that take two parameters. The first parameter is the data member and the second parameter is the name that LabTalk will use to read and write the value into the data member. If you wanted your integer property to be read-only then you would use the MOCA_SIMPLE_PROP_INT_GET macro.

While simple properties are simple to implement they do not allow you to check or validate the values coming from or going to LabTalk. If you need the ability to check and validate the values then you will not want to use the non SIMPLE macros. Replace the code you added with the following:

MOCA_PROP_INT(GetColumnIndex, SetColumnIndex, "ColumnIndex")
MOCA_PROP_STR(GetWksName, SetWksName, "WksName")

The MOCA_PROP_INT and MOCA_PROP_STR are macros that take three parameters. The first parameter is the address of the member function called when getting the property, the second parameter is the address of the member function called when setting the property, and the third parameter is the name that LabTalk will use.

Notice the first two parameters refer to member functions. You need to declare and define these member functions. Open the header file again and add the following to your MOCA object class:

public:
    BOOL GetColumnIndex(int& nValue);
    BOOL SetColumnIndex(int nValue);
    BOOL GetWksName(LPSTR strValue);
    BOOL SetWksName(LPCTSTR strValue);

Now go back to the cpp file, scroll to the end, and add the following:

BOOL CMyMocaObj::GetColumnIndex(int& nValue)
{
    nValue = m_nColumnIndex;
    return TRUE;
}
BOOL CMyMocaObj::SetColumnIndex(int nValue)
{
    if (10 <= nValue && nValue <= 99)
        m_nColumnIndex = nValue;
    return TRUE;
}
BOOL CMyMocaObj::GetWksName(LPSTR strValue)
{
    lstrcpy(strValue, m_strWksName);
    return TRUE;
}
BOOL CMyMocaObj::SetWksName(LPCTSTR strValue)
{
    if (lstrlen(strValue) <= 50)
        m_strWksName = strValue;
    return TRUE;
}

These member functions are called whenever LabTalk gets or sets the properties. This allows you to check and verify the values to meet your specific requirements.

Thats all there is to adding properties to a MOCA object. There are more macros and they are all defined in mocadef.h.

Add MOCA Methods

Open your MOCA object's header file and add the following to the end of the class declaration:

private:
    BOOL AppendColumnMeth(double& dReturn, CStringArray& saArg);

A member function that handles a MOCA method has the following requirements:

  • Return a BOOL
  • First argument is a reference to a double
  • Second argument is a reference to a CStringArray

If the method returns FALSE then LabTalk will report a Command Error. The first argument, the double, is the value returned by the LabTalk function call. The second argument, the CStringArray, contains all the arguments passed to the LabTalk function call.

Now open your MOCA object's c++ file and scroll down to the MOCA_BEGIN_PROP_MAP. Add the following between the MOCA_BEGIN_METH_MAP and MOCA_END_METH_MAP statements.

MOCA_METH_ENTRY(AppendColumnMeth, "AppendColumn")

The MOCA_METH_ENTRY macro adds the MOCA method to the MOCA object's table of methods. The first argument is the name of the member function in the MOCA object class that will be mapped to the LabTalk method. The second argument is the name used by LabTalk to reference the method.

Now scroll to the end of the file and add the following:

BOOL CMyMocaObj::AppendColumnMeth(double& dReturn, CStringArray& strArg)
{
    dReturn = NANUM;

    // check for valid number of arguments
    // for this case we only accept 2 arguments
    if (strArg.GetSize() != 2)
        return FALSE; // LabTalk command error

    // 1st arg contains worksheet name
    MoOriginWks wks(strArg[0]);
    if (!wks.IsValid())
        return FALSE; // LabTalk command error

    // 2nd arg contains column name
    char szTmp[MAX_PATH];
    lstrcpy(szTmp, strArg[1]);
    int nRet = wks.InsertColumn(szTmp);

    return (nRet == 0);
}

In LabTalk we would call this function as follows:

myObj.AppendColumn("MyWksName", "MyNewColumnName")

Examples

The MOCA package contains the files necessary to build and run the following MOCA examples.

Example Description
Worksheet Access a worksheet.
Dataset Access a worksheet's data.
Matrix Access a matrix.
Dialog Using dialog boxes and other resources.
RTScope Multi-threaded and real-time updating of a Scope graph.

For more information, see the following section.

RTScroll Multi-threaded and real-time updating of a Scroll graph.

For more information, see the following section.

RTSweep Multi-threaded and real-time updating of a Sweep graph.

For more information, see the following section.

Real-time Graphs

Origin supports three real-time graphs: Scope, Scroll, and Sweep. MOCA includes three examples to demonstrate the new graphs:

Graph Description
Scope The Scope demo demonstrates the Scope graph. The Scope graph shows the same range of data. As the data values are changed, the graph updates only the data points. The axis scales do not change.
Scroll The Scroll demo demonstrates the Scroll graph. The Scroll graph acts as a window on a large dataset. As data is added to the dataset, the graph's data points and X axis scroll to the left by a user-specified number of points. The right side of the graph displays the new data points.
Sweep The Sweep demo demonstrates the Sweep graph. The Sweep graph acts as a window on a large dataset. As data is added to the dataset, a vertical line the length of the graph's height moves from the left side of the graph to the right side. While the vertical line moves to the right, the data on its left side is replaced with the new data.

Setting Up a Real-time Graph

The graph window that will contain the real-time graph must be created from a template. Once the graph is created you must turn on its bitmap scroll buffer mode using LabTalk's layer -b command option.\

layer -b b 0;  // Turn off buffer mode.
layer -b b 1;  // Turn on buffer mode for Scroll graph.
layer -b b 2;  // Turn on buffer mode for Sweep graph.

Additionally, the redraw mode for the dataset that will be plotted must be set to MoData::REDRAW_REALTIME and MoData::REALTIME_ON_IDLE. Use the MoData::set_redraw_mode function to set these two attributes.

For the Scroll and Sweep graphs, the maximum number of data points must be predetermined and the worksheet must be updated to have enough rows to hold the data. The worksheet can be updated by calling the MoOriginWks::SetWksRowSize() function.

The real-time graph demos use a thread to update the dataset (Scope) or add to the dataset (Scroll and Sweep). The thread for the Scroll and Sweep graphs should be terminated once the maximum number of data points has been reached.

For the Scroll and Sweep graphs, the number of points being added should be 1/3 (or less) the total number of points displayed on the graph. This is necessary to correctly scroll or sweep the graph.

MOCA Classes and Functions

The following sections review the class and functions for the base class of all MOCA objects, as well as the MOCA classes and member functions for worksheet, dataset, and matrix manipulation.

CMOCAObjBase Class

This section describes the class and functions for the base class of all MOCA objects.

CMOCAObjBase is the base class for all MOCA objects. It is declared in MOCADef.H.

Method Description
CreateSubObject Allocates pointers to a subobject.
GetSpecialSubObjectPtr Returns a pointer to a MOCA subobject.
InitAllocatedSubObjects Initializes subobjects allocated at run time.
OnUnloadDLL Performs some saving or cleaning before the DLL is unloaded.

CreateSubObject Method

Declarations
CMOCAObjBase* CreateSubObject(LPCSTR lpcszSubObjName)
Arguments
LPCSTR lpcszSubObjName - object name to allocate the pointer to.
Return
Pointer to the specified object.
Remarks
This is a special function used specifically for building MOCA projects that can be used as a library to create advanced MOCA projects using the functionalities of the first MOCA projects. For MOCA projects that are intended to be expanded, the MOCA subobjects that are member objects of the main MOCA object should be allocated at run time.
LabTalk Equivalent
NA

GetSpecialSubObjectPtr Method

Declarations
virtual CMOCAObjBase* GetSpecialSubObjectPtr()
Arguments
None.
Return
Pointer to a MOCA object.
Remarks
This function can be overloaded to return a pointer to a MOCA subobject. The properties, methods, and subobject tables of the subobject whose pointer is returned will become a part of the class from which this function is called. In other words, the subobject whose pointer is returned at run time becomes a part of the object from which the function is called. This should be declared as a private function.
LabTalk Equivalent
NA

InitAllocatedSubObjects Method

Declarations
virtual BOOL InitAllocatedSubObjects()
Arguments
None.
Return
If initialization is successful then TRUE, else FALSE.
Remarks
This is a virtual function used for some special initialization of the subobjects allocated at run time, if needed. This is a simple virtual function so if partial work is done in the derived class, it must call the

base classes initialization before or after its own, as the need may be.

LabTalk Equivalent
NA

OnUnloadDLL Method

Declarations
virtual void OnUnloadDLL()
Arguments
None.
Return
None.
Remarks
This function can be overloaded from the main object (and only the main object) to do some saving or cleaning before the DLL is freed/unloaded.
LabTalk Equivalent
NA

MoOriginWks Class

This section describes the classes and functions for worksheet access from MOCA DLLs. Examples of using some of these functions can be found in the Worksheet demo.

MoOriginWks - the main class for accessing worksheets. It is declared in MoWks.H.

MoWksName - derived from MoString and used for handling worksheet names.

MoOriginWks Member Functions

Method Description
MoOriginWks Constructor.
&GetWksName Gets the name of the worksheet.
ClearOfData Clears the worksheet of all its data.
CreateDataAndPlot Creates a graph window and plots the worksheet data using the specified X and Y columns.
Destroy Destroys the worksheet.
GetAsText Gets the value, as text, in the worksheet at the specified column and row number.
GetColLabel Gets the label of the column.
GetColLabelMaxWidth Gets the label width for the column.
GetColName Gets the name of the column.
GetColNameWidth Gets the number of characters in the column's name.
GetColumnType Gets the Display Type of the column.
GetColumnWidth Gets the width of the column.
GetDatasetName Gets the dataset name for the column.
GetLargestContentsWidth Gets the maximum width of the contents of a column.
GetNumCols Gets the number of columns in the worksheet.
InsertColumn Inserts a new column into the worksheet and optionally sets its location and label.
InsertMixedColumn Inserts a new column of Display Type=Text & Numeric into the worksheet.
InsertTextColumn Inserts a new column of Display Type=Text into the worksheet.
IsValid Checks to see if the object refers to an existing Origin worksheet.
RemoveColumn Removes (deletes) the column from the worksheet.
SetColName Sets the name of the column.
SetColNumDecPlaces Sets the significant number of decimal places for the data in the column.
SetColumnAsMixed Sets the column to Display Type=Text & Numeric.
SetColumnAsNone Sets the column to have no plot designation.
SetColumnAsNumeric Sets the column to Display Type=Numeric.
SetColumnAsTextual Sets the column to Display Type=Text.
SetColumnAsX Sets the column to be an X column.
SetColumnAsY Sets the column to be a Y column.
SetColumnHeadingHeight Sets the height of the column's heading.
SetColumnLabel Sets the label of the column.
SetColumnsToNiceWidths Auto-sets the width of all columns.
SetColumnWidth Sets the width of the column.
SetNiceColumnWidth Auto-sets the width of the column.
SetValue Sets the value in the worksheet at the specified column and row number.
SetWksLabel Sets the worksheet's label.
SetWksRowSize Sets the number of rows in the worksheet.

MoData Class

This section describes the classes and functions for dataset access from MOCA DLLs. Examples of using some of these functions can be found in the Dataset demo.

MoData - the base class for Origin internal dataset access. It is declared in MoData.H.

The following classes for dataset access are derived from MoData and are declared in MoData.H:

MoSourceData - the class for the object corresponding to a source dataset. The object must be interfaced with an existing dataset.

MoTempData - the class for an "abstract" (in the sense that it is not associated with a real dataset) Y dataset object with an associated X dataset.

MoTempDataset - the class for an "abstract" (in the sense that it is not associated with a real dataset) dataset object.

The following classes, declared in ODLL.H, are also used with datasets:

MoDataSetName - the class for the dataset name.

MoWksName - the class for the worksheet name.

MoColumnNum - the class for the column number (first column is number 1).

MoData Member Functions

Method Description
MoSourceData Constructor.
MoTempData Constructor.
MoTempDataset Constructor.
GetId Gets the dataset ID.
GetMissingNum Gets the number of cells in the dataset that are not set to any value.
GetNumericValueAsText Gets the value at the specified index in a dataset as text.
GetSafeXY Gets a Y and associated X value.
GetValue Gets the string value in the cell.
GetXY Gets a Y and associated X value.
GetYfromX Gets the Y for the specified X value.
iRange1 Gets the low bound (the smallest index) of the range of the dataset.
iRange2 Gets the high bound (the largest index) of the range of the dataset.
IsEmpty Checks if the dataset is empty.
IsTextualDataset Checks if the dataset is Display Type=Text.
IsValid Checks that the MoSourceData object is associated with a valid dataset.
LeftEnd Gets the value in the first row with data.
ResetRange Resets the range to 0,0.
RightEnd Gets the value in the last row with data.
SetRange Sets the lowest and the highest index for the range of a dataset.
SetSelRange Sets the selection range.
SetValue Sets the value in a cell.
SetXY Sets a Y and associated X value.
Operator Description
*= Multiply a specified value or dataset values to the values in the dataset.
/= Divide the dataset values by a specified value or dataset values.
+= Add a specified value or dataset values to the values in the dataset.
-= Subtract a specified value or dataset values from the values in the dataset.

MoMatrix Class

This section describes the class and functions for matrix access from MOCA DLLs. Examples of using some of these functions can be found in the Matrix demo.

MoMatrixName - the class for the matrix name. Derived from MoString.

MoMatrix - the class for the object corresponding to a matrix. Derived from MoData.

MoMatrix Member Functions

Method Description
MoSourceData Constructor.
GetMatrixXY Gets the minimum and maximum X and Y values for the matrix.
GetxMax Gets the maximum X value.
GetxMin Gets the minimum X value.
GetyMax Gets the maximum Y value.
GetyMin Gets the minimum Y value.
IsValid Checks if the MoMatrix object is associated with a valid matrix.
nCols Gets the number of columns in the matrix.
nRows Gets the number of rows in the matrix.
SetDim Sets the dimensions of the matrix.
SetVal Sets the value in the specified row and column.
SetxMax Sets the maximum X coordinate for plotting.
SetxMin Sets the minimum X coordinate for plotting.
SetXY Sets the minimum and maximum X and Y values for the matrix.
SetyMax Sets the maximum Y coordinate for plotting.
SetyMin Sets the minimum Y coordinate for plotting.
Operator Description
operator () Gets the value in the specified row and column.