MOCAMOCA
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.
- Start Visual Studio 2012
- Choose File > New > Project...
- In the New Project dialog:
- In left panel choose Installed Templates.
- Under Installed Templates choose Visual C++.
- Under Visual C++ choose MFC.
- In middle panel choose MFC DLL.
- At bottom of dialog enter a name for your project.
- Click the OK button to close dialog.
- 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.
- In Solution Explorer right-click your project and choose Properties
- In Property Pages dialog click the Configuration Manager button in the top right corner.
- In the Configuration Manager dialog:
- Choose New under Active solution Platform.
- In the New Solution Platform dialog set Type to x64 and click OK.
- 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.
- In Solution Explorer right-click your project and choose Properties
- In Property Pages dialog:
- Set Configuration to All Configurations
- Set Platform to All Platforms
- In left panel expand Configuration Properties
- Under Configuration Properties choose General
- In right panel set Character Set to Use Multi-Byte Character Set
- In left panel, under Configuration Properties expand C/C++
- Under C/C++ choose General
- In right panel set Additional Include Directories to the MOCA include folder.
- Under C/C++ choose Preprocessor
- In right panel add NO_SHOBJIDL_SORTDIRECTION to Preprocessor Definitions.
- In left panel, under Configuration Properties, expand Linker
- Under Linker choose General
- In right panel set Additional Library Directories to the MOCA lib folder.
- In left panel, under Linker, choose Input
- In right panel you need to add the omocavc library to Additional Dependencies.
- For making 32-bit DLL, set Platform to Win32 and add omocavc9.lib.
- For making 64-bit DLL, set Platform to x64 and add omocavc9_64.lib.
- 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.
- In Solution Explorer right-click your project and choose Add New Item
- In the Add New Item dialog:
- In left panel expand Visual C++ and select Code
- In middle panel select Header File (.h)
- In bottom of dialog give your file a name. In this example, we will name it as CMyMocaObj.h
- 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.
|
|