在(Windows)C++应用程序中嵌入Python解释器

4
我正在编写一个用C++编写的窗口应用程序,希望能够利用几个Python库。
这里不需要任何花哨的Python互操作。我的方法如下:
- 打开一个线程来运行Python解释器。 - 从C++向Python解释器发送命令。C++可能需要为互操作编写一些中间文件。
这种方法很粗糙,但它可以适用于许多类似解释器的环境,例如gnuplot、lua等。
我的问题是,有什么API可供我用来完成这个任务?也许我需要一些Win32 API?
编辑:我不需要任何特定于Python的内容。我真的想要通用的方法。这样我的应用程序也可以与gnuplot等一起使用。

1
有人用过 Boost::Python 吗?这不是你说的那个,但可能更容易上手。 - user395760
即使您使用Boost.Python,也必须以C样式嵌入实际解释器(尽管这不是太麻烦,基本上只需链接几个库并调用Py_Init)。 - filmor
@Yin Zhu,看起来你不想在不同的线程中启动解释器,而是想在不同的进程中启动并通过stdin/stdout进行通信。如果你真的想走这条路,在Windows上这篇文章似乎描述了如何实现... - filmor
4个回答

4
如果您有Python的源代码分发包,您可以在Demo/embed目录中查找示例。相关文档在这里

3
我已经编写了一个“Hello World”的IActiveScript C++ ATL控制台应用程序,它具有以下功能:
  • 实现了一个名为CSimpleScriptSite的新类
  • 继承了IActiveScriptSiteIActiveScriptSiteWindow
  • 使用IActiveSite接口在Python引擎上调用CoCreateInstance
  • 执行Python语句print 'Hello World. 5 squared is: ' + str(5 * 5)
  • 没有针对错误的Python进行处理。您可以参考MSDN IActiveScriptError
  • 具有带有存根return S_OK;实现的函数
  • 我安装了Python 2.6,但您可以使用任何Python解释器。
  • 我使用了具有ProgID为PythonPython for Windows extensions,它提供了Python解释器的IActiveScript包装器
  • 但是,您可以让代码与任何支持IActiveScript的Python解释器一起工作,只需更新ProgID(例如Python.AXScript.2)

下面是Python Hello World示例:

#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;
}

2
ActivePython(http://www.activestate.com/activepython/downloads)将自己安装为ActiveScript引擎。ProgID是Python.AXScript.2。因此,您可以通过Windows标准IActiveScript接口与COM一起使用它。请查阅相关资料。
分发是另一回事。要么要求客户拥有它,要么尝试从ActiveState的包中提取重要部分,或者可能有官方方法进行无人值守设置...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接