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.
- Windows 7
- Python 3.3.5 (Assume the Python settings are already OK.)
- 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
- 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.
- Start Windows Console (cmd.exe), and then switch the current path to the directory where Python installed.
- 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
- Start Visual Studio 2012, and create a new Win32 Project, named OPython.
- Click OK, and select the Application type to be DLL, and click Finish to create the project.
- Set the Solution Configurations to be Release. Right click on the project, and choose Property from the context menu, to open the Property dialog.
Note: Here the 32-bit DLL will be created, and that will be used in 32-bit version of Origin.
- 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.
- 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.
- Add a header file, named OPython.h, to the project, and put the following code to it.
#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_
- 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.
#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);
}
- Add a Module-Definition File, named OPython.def, to the project, and replace the original code with the code below.
LIBRARY "OPython"
EXPORTS
;Functions to export
PY_SayHello
PY_Add
PY_Sub
PY_Mult
PY_Div
PY_Mod
- 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.
- Copy the DLL generated above (OPython.dll), and paste it to the directory where Origin installed.
- Copy the header file created above (OPython.h) to this folder: <User Files Folder>/OriginC/.
- Start 32-bit version of Origin and launch Code Builder. Create a new C file and replace with the following code to it.
#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;
}
- Compile the above code in Code Builder, and then run the following line in LabTalk Console (Open by Code Builder menu View: LabTalk Console).
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);
|