【问题标题】:Embed a Python interpreter in a (Windows) C++ application在 (Windows) C++ 应用程序中嵌入 Python 解释器
【发布时间】:2011-01-04 16:38:56
【问题描述】:

我正在构建一个用 C++ 编写的窗口应用程序。我想利用几个 python 库。

我在这里不需要任何花哨的 Python 互操作。我的方法是这样的:

  • 打开一个线程来运行 Python 解释器。

  • 将命令从 C++ 发送到 Python 解释器。 C++ 可能需要为互操作编写一些中间文件。

这个方法很脏,但它适用于很多类似解释器的环境,例如gnuplot,lua。

我的问题是我可以使用什么样的 API 来完成这项任务。也许我需要一些 Win32 API?

编辑:我不需要任何特定的 Python。我真的想要一般的方法。这样我的应用程序也可以与 gnuplot 等一起使用。

【问题讨论】:

  • Boost::Python 有人吗?不是你描述的那样,但可能更容易。
  • 即使您使用 Boost.Python,您也必须嵌入实际的 C 风格解释器(不过这并不麻烦,基本上是链接几个库并调用 Py_InitIIRC)。跨度>
  • @Yin Zhu,您似乎不想在不同的线程中启动解释器,而是在不同的进程中启动并通过 stdin/stdout 与该进程通信。 This article 似乎描述了如何在 Windows 上执行此操作,如果您真的想走那条路……

标签: c++ python winapi api


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    我已经组装了一个“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 解释器。
    • 我使用了 Python for Windows extensions,它的 ProgID 为 Python,它为 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;
    }
    

    【讨论】:

      【解决方案3】:

      ActivePython (http://www.activestate.com/activepython/downloads) 将自身安装为 ActiveScript 引擎。ProgID 是 Python.AXScript.2 。因此,您可以通过 Windows 标准 IActiveScript 接口将它与 COM 一起使用。阅读它。

      分销是另一回事。要么你要求客户拥有它,要么你可以尝试从 ActiveState 的包中提取多汁的部分,或者也许有一种官方的方式来进行无人值守的设置......

      【讨论】:

        【解决方案4】:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-06-23
          • 1970-01-01
          • 2021-03-28
          • 1970-01-01
          • 2011-04-23
          • 2019-05-26
          相关资源
          最近更新 更多