embedding Python in COM server loaded with win32com

Fozzie david.foster at citigroup.com
Mon Jun 5 10:57:20 EDT 2006


Hi,

I have a problem which is quite circular, and hopefully either someone
has encountered something similar or has a reason why this will not
work.

We have a COM library providing mathematics to various systems, most
functions are hard-coded but we want to embed a scripting language to
allow arbitrary functions to be used in the numeric engines within the
library, and am using Python for this.

This seems to work fine called from standalone apps, and from VB,
however, Python scripts, which access the scripts via win32com.client
fail in the embedding code in C++ whenever I attempt to call
PyImport_AddModule.

As a concrete example, consider the following minimal interface,
(created using an ATL project in VC7),  which has a single property,
the user supplied script, and a single function 'findRoot', which in
this case is nothing more than an indicator that the embedding worked,

-------------------------------------------------------------
STDMETHODIMP CMinEmbed::get_script(BSTR* pVal)
{
	USES_CONVERSION;
	*pVal = SysAllocString(A2OLE(__script.c_str()));
	return S_OK;
}
STDMETHODIMP CMinEmbed::put_script(BSTR newVal)
{
	USES_CONVERSION;
	__script = std::string( OLE2A( newVal));
	return S_OK;
}
STDMETHODIMP CMinEmbed::findRoot(DOUBLE* root)
{
	std::string progress;
	PyObject * main, * globals, * res, * func;

	try {

		progress = "calling PyInitialize";
		if(!Py_IsInitialized()) Py_Initialize();

		progress = "get __main__ module";
		main = PyImport_AddModule("__main__");

		progress = "get __main__module dictionary";
		globals = PyModule_GetDict(main);

		progress = "Run the script.";
		res = PyRun_String(__script.c_str(), Py_file_input, globals,
globals);

		progress = "Get the function from main dictionary.";
		func = PyDict_GetItemString(globals, "func");

		progress = "test function, and return indicator";
		if(NULL != func && PyCallable_Check(func)) {
			*root = 1.0;
		} else {
			*root = -1.0;
		}

		progress = "clean up";
		Py_XDECREF(res);
		Py_Finalize();
		return S_OK;

	} catch(...) {
		// SetFailString just sets the ISupportErrorInfo interface
		SetFailString(IID_IMinEmbed, progress.c_str());
		return E_FAIL;
	}
}
-------------------------------------------------------------


When I build my server with the above method and run it at the Python
interpretor I get,

>>> from win32com.client import Dispatch
>>> s = Dispatch('minServer.MinEmbed')
>>> s.script = 'def func(x) : return x*x'
>>> s.findRoot()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<COMObject minServer.MinEmbed>", line 2, in findRoot
  File "i:\1111\Python24\lib\site-packages\win32com\client\dynamic.py",
line 251, in _ApplyTypes_
    result = self._oleobj_.InvokeTypes(*(dispid, LCID, wFlags, retType,
argTypes) + args)
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None,
'Failure to get main module', None, 0, -2147467259), None)

However, works fine from VB and standalone apps.

Is this approach even doable? 


Thanks in advance 


Dave Foster




More information about the Python-list mailing list