1.19.1.3 Access Python via External DLL

In Origin C, there is no way to call Python functions directly. However, if you want to reuse your Python code in Origin C, it is recommended to wrap the Python functions in a DLL first, and then expose the functions in the DLL to Origin C code. In the following sections of this chapter, an example will be shown on how to do this step by step.

Notes: From Origin 2015, we can run python in Origin (support both command line and .py file), and use a PyOrigin module to access Origin from Python. view Python.chm for more details.

Running Environment

The example shown below is based on the following environment.

  1. Windows 7
  2. Python 3.3.5 (Assume the Python settings are already OK.)
  3. Visual Studio 2012

Python File

The Python functions defined in the following are going to be reused in Origin C.

def SayHello():
    print("Welcome to use Python in your Origin C programs!") #actually this string will not show in Origin C
    return 12345

def Add(a, b):
    return a + b

def Sub(a, b):
    return a - b

def Mult(a, b):
    return a * b

def Div(a, b):
    return a / b

def Mod(a, b):
    return a % b
  1. First of all, go to the Python installed directory, then create a Python file under this directory, say "myLib.py". Then open this newly created file using a text editor, Notepad for example, and put the Python code above to this file, and save.
  2. Start Windows Console (cmd.exe), and then switch the current path to the directory where Python installed.
  3. Run the following command to compile the Python file created just now.
    python -m py_compile myLib.py
    If successfully, there will be a pyc file (myLib.cpython-33.pyc, or something similar with "myLib") under this folder <Python Installation Directory>/__pycache__/ by default.

Build DLL

  1. Start Visual Studio 2012, and create a new Win32 Project, named OPython.
  2. PythonDLL 1.png

  3. Click OK, and select the Application type to be DLL, and click Finish to create the project.
  4. PythonDLL 2.png

  5. Set the Solution Configurations to be Release. Right click on the project, and choose Property from the context menu, to open the Property dialog.
  6. Note: Here the 32-bit DLL will be created, and that will be used in 32-bit version of Origin.

  7. In the Property dialog, from the left panel, activate Configuration Properties: VC++ Directories, and then in the right panel, add the Python header file path and library path to Include Directories and Library Directories respectively.
  8. PythonDLL 3.png

  9. From the left panel, activate Configuration Properties: Linker: Input, and then in the right panel, add the Python library to Additional Dependencies, here is python33.lib. Apply all the settings and click OK.
  10. PythonDLL 4.png

  11. Add a header file, named OPython.h, to the project, and put the following code to it.
  12. #ifndef	_OPYTHON_H_
    #define	_OPYTHON_H_
    
    #ifdef	_OPYTHON_CPP_
    	#define	OP_API	__declspec(dllexport)	//use in VC
    #else
    	#define	OP_API							//use in OC
    	#pragma dll(OPython) //this line is important, when use in OC, Origin will find function body by searching in this DLL. Note:OPythonDLL, is the generated dll, without extension name.
    #endif
    
    OP_API	int	  PY_SayHello();
    
    OP_API	float PY_Add(float a, float b);
    
    OP_API	float PY_Sub(float a, float b);
    
    OP_API	float PY_Mult(float a, float b);
    
    OP_API	float PY_Div(float a, float b);
    
    OP_API	float PY_Mod(float a, float b);
    
    #endif	//_OPYTHON_H_
  13. Open the OPython.cpp, which is created automatically when creating the project (If no such file, create it). Replace the original code by the following code.
  14. #include "stdafx.h"
    #define	_OPYTHON_CPP_ //use this macro to identify whether OPython.h is included in VC(when create the DLL) or OC(when use the DLL)
    #include "OPython.h"
    #include <Python.h>
    
    class PythonManager
    {
    public:
    	PythonManager(); //init python environment
    	~PythonManager(); //clean python environment
    };
    
    PythonManager::PythonManager()
    {
    	Py_Initialize();
    }
    
    PythonManager::~PythonManager()
    {
    	Py_Finalize();
    }
    
    OP_API	int	  PY_SayHello()
    {
    	PythonManager pm;
    
    	PyObject* pModule;
    	PyObject* pFunc;
    	//call python function, with no parameters
    	int nRet = 0;
    	pModule = PyImport_ImportModule("myLib");
    	if ( NULL == pModule )
    		return nRet;
    
    	pFunc = PyObject_GetAttrString(pModule, "SayHello");
    	if ( pFunc )
    	{
    		PyObject* pRet = NULL;
    		pRet = PyEval_CallObject(pFunc, NULL);
    
    		PyArg_Parse(pRet, "i", &nRet);
    	}
    	return nRet;
    }
    
    static	float	_call_float_float(LPCSTR lpcszFunc, float a, float b)
    {
    	PythonManager pm;
    
    	PyObject* pModule;
    	PyObject* pFunc;
    	//call python function, with multiple parameters
    	float fRet = 0;
    	pModule = PyImport_ImportModule("myLib");
    	if ( NULL == pModule )
    		return fRet;
    
    	pFunc = PyObject_GetAttrString(pModule, lpcszFunc);
    	if ( pFunc )
    	{
    		PyObject* pParams = NULL;
    		pParams = PyTuple_New(2);		  //create tuple to put parameters
    
    		PyTuple_SetItem(pParams, 0, Py_BuildValue("f", a));
    		PyTuple_SetItem(pParams, 1, Py_BuildValue("f", b));
    		PyObject* pRet = NULL;
    		pRet = PyEval_CallObject(pFunc, pParams);
    
    		PyArg_Parse(pRet, "f", &fRet);
    	}
    	return fRet;
    }
    OP_API	float PY_Add(float a, float b)
    {
    	return _call_float_float("Add", a, b);
    }
    
    OP_API	float PY_Sub(float a, float b)
    {
    	return _call_float_float("Sub", a, b);
    }
    
    OP_API	float PY_Mult(float a, float b)
    {
    	return _call_float_float("Mult", a, b);
    }
    
    OP_API	float PY_Div(float a, float b)
    {
    	return _call_float_float("Div", a, b);
    }
    
    OP_API	float PY_Mod(float a, float b)
    {
    	return _call_float_float("Mod", a, b);
    }
  15. Add a Module-Definition File, named OPython.def, to the project, and replace the original code with the code below.
  16. LIBRARY	"OPython"
    
    EXPORTS
    
    		;Functions to export
    		PY_SayHello
    		PY_Add
    		PY_Sub
    		PY_Mult
    		PY_Div
    		PY_Mod
  17. Build the solution to generate the DLL, OPython.dll, by default

Use the DLL

The following code show how to use the DLL generated above in Origin C.

  1. Copy the DLL generated above (OPython.dll), and paste it to the directory where Origin installed.
  2. Copy the header file created above (OPython.h) to this folder: <User Files Folder>/OriginC/.
  3. Start 32-bit version of Origin and launch Code Builder. Create a new C file and replace with the following code to it.
  4. #include <Origin.h>
    #include "OPython.h" //remember to include this header.
    
    int test_Python()
    {
    	int nRet = PY_SayHello();
    
    	float c = PY_Add(2, 4);
    	
    	float d = PY_Div(2, 3);
    
    	return 0;
    }
  5. Compile the above code in Code Builder, and then run the following line in LabTalk Console (Open by Code Builder menu View: LabTalk Console).
  6. test_Python;

Remarks

The example shown in this page is only to create a simple DLL that can reuse the functions written in Python. If to process a large amount of data in Python, and transfer the data between Origin and Python, a buffer will be recommended. With buffer, when transfer data from Origin's Column, the vector, which contains data, can be passed from Origin C to a DLL function, which receive a pointer (maybe double *pBuffer) as parameter. And any change based on this buffer will take effect immediately on the vector in Origin C. In \Samples\Python folder of your Origin software, you can see code example( CCallPython.cpp , CCallPython.py , and python.h ) to transfer data buffer by two OC API:

OPYTHON_API OIP OPy_GetItemsFromList(int nType, void* pyObj, void* pBuffer);
OPYTHON_API void* OPy_SetItemsToList(int nType, void* pBuffer, OIP* pnDims, int nDims);