如何从嵌入式 Python 中的 C++ 应用程序添加 IDispatch COM 对象(该对象是在 C++ 代码中创建为 Python 中的命名对象)并使用它

问题描述 投票:0回答:1

我能够在我的 MSVS Windows C++ 应用程序中使用嵌入式 Python,并且运行良好。我可以创建 com 对象并像这样使用它们:

    import win32com.client as win32
    Dialogs = win32.Dispatch('DialogControls.Dialogs')
    Dialogs.Message(0, "Hello from C++ object")`

我有许多在 C++ 应用程序中创建的对象,我想在 Python 中访问它们以及它们的事件处理程序。以前我使用 VBScript,并且可以使用 AddObjectEx 做到这一点,但在 Python 中我没有成功。我尝试过类似的方法,但它不起作用。 pComObject 为 NULL。

void PythonEng::PassComObjectToPython(const CString& ObjName, IDispatch* pMyComObject) {
    Py_Initialize();
    PyObject* pModule = PyImport_ImportModule("win32com.client");
    if (pModule) {
        PyObject* pDict = PyModule_GetDict(pModule);
        PyObject* pDispatch = PyDict_GetItemString(pDict, "Dispatch");
        if (pDispatch && PyCallable_Check(pDispatch)) {
            PyObject* pArgs = PyTuple_Pack(1, PyLong_FromVoidPtr(pMyComObject));
            PyObject* pComObject = PyObject_CallObject(pDispatch, pArgs);
            Py_DECREF(pArgs);
            if (pComObject) {
                PyObject* pGlobals = PyDict_New();
                CT2CA pszConvertedAnsiString(ObjName);
                std::string strObjName(pszConvertedAnsiString);
                PyDict_SetItemString(pGlobals, strObjName.c_str(), pComObject);
                Py_DECREF(pComObject);
                // Now you can execute Python code that uses my_com_object
                PyRun_String("MyGen.Idle(10)", Py_file_input, pGlobals, pGlobals);
                Py_DECREF(pGlobals);
            }
        }
        Py_DECREF(pModule);
    }
    Py_Finalize();
}

我尝试使用上面的代码添加我的 com 对象并从嵌入式 Python 中使用它。

python c++ embedded
1个回答
0
投票

这里有一些想法给你:

#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <cassert>
#include <atlcom.h>
#include <atlbase.h>
#include <Windows.h>

#include <MsXml6.h>
#include <string>

//-----------------------------------------------------------------------------
// ALL your legacy + COM code

class legacy_cpp_com_code
{
public:
    legacy_cpp_com_code()
    {
        // make sure ::CoInitializeEx has been called etc. 
        auto hr = m_xmlDocument.CoCreateInstance(CLSID_DOMDocument60, nullptr, CLSCTX_INPROC_SERVER);
    }

    std::wstring GetName()
    {
        ATL::CComBSTR str;
        m_xmlDocument->get_baseName(&str);
        return { static_cast<LPWSTR>(str) };
    }

    void some_method()
    {
    }

private:
    ATL::CComPtr<IXMLDOMDocument> m_xmlDocument;
};

// Or you can use these kind of COM factory methods, to later hide the COM objects in "C" API calls.

ATL::CComPtr<IXMLDOMDocument> GetXmlDocument()
{
    // initialization from lamda into a static com pointer (this will be released when the library unloads)
    static ATL::CComPtr<IXMLDOMDocument> xmlDocument = []
    {  
        ATL::CComPtr<IXMLDOMDocument> localXmlDocument;
        auto hr = localXmlDocument.CoCreateInstance(CLSID_DOMDocument60, nullptr, CLSCTX_INPROC_SERVER);
        return localXmlDocument;
    }();

    return xmlDocument;
}


//-----------------------------------------------------------------------------
// Your "new" scripting API

legacy_cpp_com_code instance;


extern "C"
{
    const wchar_t* GetName(void)
    {
        return instance.GetName().c_str();

        // or
        // GetXmlDocument().GetName().c_str();
    }

    void some_method(void)
    {
        instance.some_method();
    }
}
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.