Reputation: 17119
I am building a window application written in C++. I'd like to utilize several python libraries.
I don't need any fancy Python interop here. My method is like this:
Open a thread to run Python interpreter.
Send commands from C++ to the Python interpreter. The C++ may need to write some intermediate files for the interop.
This method is dirty, but it will work for a lot of interpreter-like environments, e.g. gnuplot, lua.
My question is that what kind of API are there for me to use for this task. Maybe I need some Win32 API?
EDIT: I don't need any Python specific. I really want the general method. So that my application could also work with gnuplot, etc..
Upvotes: 4
Views: 1914
Reputation: 26179
I've put together a "Hello World" IActiveScript C++ ATL console application that:
CSimpleScriptSite
IActiveScriptSite
and IActiveScriptSiteWindow
Python
engine with the IActiveSite
interfacePython
statement print 'Hello World. 5 squared is: ' + str(5 * 5)
Python
. You should consult MSDN IActiveScriptErrorreturn S_OK;
implementationPython
which gives the Python interpreter IActiveScript
wrappersIActiveScript
, you just need to update the ProgID (e.g. Python.AXScript.2)Here's the Python Hello World sample:
#include <atlbase.h>
#include <activscp.h>
#define CHECKHR(stmt) \
{ \
HRESULT hr = S_OK; \
if (FAILED(hr = (stmt))) { return hr; } \
}
class CSimpleScriptSite :
public IActiveScriptSite,
public IActiveScriptSiteWindow
{
public:
CSimpleScriptSite() : m_cRefCount(1), m_hWnd(NULL) { ZeroMemory(&m_clsidScriptEngine, sizeof(m_clsidScriptEngine)); }
// IUnknown
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject);
// IActiveScriptSite
STDMETHOD(GetLCID)(LCID *plcid){ *plcid = 0; return S_OK; }
STDMETHOD(GetItemInfo)(LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown **ppiunkItem, ITypeInfo **ppti) { return TYPE_E_ELEMENTNOTFOUND; }
STDMETHOD(GetDocVersionString)(BSTR *pbstrVersion) { *pbstrVersion = SysAllocString(L"1.0"); return S_OK; }
STDMETHOD(OnScriptTerminate)(const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo) { return S_OK; }
STDMETHOD(OnStateChange)(SCRIPTSTATE ssScriptState) { return S_OK; }
STDMETHOD(OnScriptError)(IActiveScriptError *pIActiveScriptError) { return S_OK; }
STDMETHOD(OnEnterScript)(void) { return S_OK; }
STDMETHOD(OnLeaveScript)(void) { return S_OK; }
// IActiveScriptSiteWindow
STDMETHOD(GetWindow)(HWND *phWnd) { *phWnd = m_hWnd; return S_OK; }
STDMETHOD(EnableModeless)(BOOL fEnable) { return S_OK; }
// Miscellaneous
HRESULT CloseScriptEngine();
HRESULT Evaluate(LPCOLESTR szScript, VARIANT *pResult, LPCOLESTR strItemName);
HRESULT Execute(LPCOLESTR szScript, LPCOLESTR strItemName);
HRESULT OpenScriptEngine(CLSID &rclsid);
HRESULT OpenScriptEngine(LPCOLESTR szScriptEngine);
HRESULT SetWindow(HWND hWnd) { m_hWnd = hWnd; }
private:
CComPtr<IActiveScript> m_ptrIActiveScript;
CLSID m_clsidScriptEngine;
ULONG m_cRefCount;
HWND m_hWnd;
};
STDMETHODIMP_(ULONG) CSimpleScriptSite::AddRef()
{
return InterlockedIncrement(&m_cRefCount);
}
STDMETHODIMP_(ULONG) CSimpleScriptSite::Release()
{
if (!InterlockedDecrement(&m_cRefCount))
{
delete this;
return 0;
}
return m_cRefCount;
}
STDMETHODIMP CSimpleScriptSite::QueryInterface(REFIID riid, void **ppvObject)
{
if (riid == IID_IUnknown || riid == IID_IActiveScriptSiteWindow)
{
*ppvObject = (IActiveScriptSiteWindow *) this;
AddRef();
return NOERROR;
}
if (riid == IID_IActiveScriptSite)
{
*ppvObject = (IActiveScriptSite *) this;
AddRef();
return NOERROR;
}
return E_NOINTERFACE;
}
HRESULT CSimpleScriptSite::OpenScriptEngine(CLSID &rclsid)
{
m_ptrIActiveScript = NULL;
CHECKHR(CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, IID_IActiveScript, (void **) &m_ptrIActiveScript));
CHECKHR(m_ptrIActiveScript->SetScriptSite(this));
CComPtr<IActiveScriptParse> ptrIActiveScriptParse;
CHECKHR(m_ptrIActiveScript->QueryInterface(IID_IActiveScriptParse, (void **) &ptrIActiveScriptParse));
CHECKHR(ptrIActiveScriptParse->InitNew());
m_clsidScriptEngine = rclsid;
return S_OK;
}
HRESULT CSimpleScriptSite::OpenScriptEngine(LPCOLESTR szScriptEngine)
{
CLSID clsid;
CHECKHR(CLSIDFromProgID(szScriptEngine, &clsid));
return OpenScriptEngine(clsid);
}
HRESULT CSimpleScriptSite::CloseScriptEngine()
{
if (!m_ptrIActiveScript) { return S_OK; }
CHECKHR(m_ptrIActiveScript->SetScriptState(SCRIPTSTATE_CLOSED));
m_ptrIActiveScript = NULL;
return S_OK;
}
HRESULT CSimpleScriptSite::Evaluate(LPCOLESTR szScript, VARIANT *pResult, LPCOLESTR strItemName)
{
if (!m_ptrIActiveScript) { return E_POINTER; }
if (!pResult) { return E_INVALIDARG; }
EXCEPINFO ei = {0};
CComPtr<IActiveScriptParse> ptrIActiveScriptParse;
CHECKHR(m_ptrIActiveScript->QueryInterface(IID_IActiveScriptParse, (void **) &ptrIActiveScriptParse));
CHECKHR(ptrIActiveScriptParse->ParseScriptText(szScript, strItemName, NULL, NULL, 0, 0, SCRIPTTEXT_ISEXPRESSION, pResult, &ei));
return m_ptrIActiveScript->SetScriptState(SCRIPTSTATE_CONNECTED);
}
HRESULT CSimpleScriptSite::Execute(LPCOLESTR szScript, LPCOLESTR strItemName)
{
if (!m_ptrIActiveScript) { return E_POINTER; }
EXCEPINFO ei = {0};
CComPtr<IActiveScriptParse> ptrIActiveScriptParse;
CHECKHR(m_ptrIActiveScript->QueryInterface(IID_IActiveScriptParse, (void **) &ptrIActiveScriptParse));
CHECKHR(ptrIActiveScriptParse->ParseScriptText(szScript, strItemName, NULL, NULL, 0, 0, 0L, NULL, &ei));
return m_ptrIActiveScript->SetScriptState(SCRIPTSTATE_CONNECTED);
}
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr = S_OK;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
CSimpleScriptSite *pScriptSite = new CSimpleScriptSite();
hr = pScriptSite->OpenScriptEngine(OLESTR("Python"));
hr = pScriptSite->Execute(OLESTR("print 'Hello World. 5 squared is: ' + str(5 * 5)"), NULL);
hr = pScriptSite->CloseScriptEngine();
hr = pScriptSite->Release();
::CoUninitialize();
return 0;
}
Upvotes: 3
Reputation: 2372
You can also use boost Python: http://www.boost.org/doc/libs/1_45_0/libs/python/doc/index.html
Upvotes: 0
Reputation: 61388
ActivePython (http://www.activestate.com/activepython/downloads) installs itself as an ActiveScript engine.The ProgID is Python.AXScript.2 . So you can use it with COM via the Windows standard IActiveScript interface. Read up on it.
Distribution is another matter. Either you require that customers have it, or you could try and extract the juicy bits from the ActiveState's package, or maybe there's an official way to do unattended setup...
Upvotes: 2