How can I convert a JavaScript array() to an ATL/COM array?

前端 未结 4 547
情深已故
情深已故 2021-01-14 23:33

How can I convert a JavaScript array() to an ATL/COM array without using VBArray?

What I want to convert is a new Array() to a SAFEARRAY.

4条回答
  •  [愿得一人]
    2021-01-15 00:31

    With IActiveScript you can instantiate a JavaScript engine in C++ and use it to:

    • Make IDispatch* pointers for JavaScript functions
    • Make VARIANT variables containing JavaScript objects
    • Pass JavaScript objects to JavaScript functions in C++

    Using this technique, we shall do the following:

    1. Declare a JavaScript function, e.g. function (arr) { return arr.length; }
    2. Declare a JavaScript array, e.g. [2, 3, 5, 7, 11]
    3. Call the JavaScript function with the JavaScript array as input

    To make this work, you must create an IActiveScriptSite. The following is a C++ console application that demonstrates this concept:

    // C++ headers for ATL and Active Script Hosting.
    #include 
    #include 
    #include 
    
    // A minimal implementation of IActiveScriptSite.
    class ATL_NO_VTABLE CScriptSite :
        public CComObjectRootEx,
        public IActiveScriptSite,
        public IActiveScriptSiteWindow
    {
    public:
    BEGIN_COM_MAP(CScriptSite)
        COM_INTERFACE_ENTRY(IActiveScriptSite)
        COM_INTERFACE_ENTRY(IActiveScriptSiteWindow)
    END_COM_MAP()
        DECLARE_PROTECT_FINAL_CONSTRUCT()
        HRESULT FinalConstruct()
        {
            return S_OK;
        }
        void FinalRelease()
        {
        }
    public:
        // 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 = NULL;
            return S_OK;
        }
        STDMETHOD(EnableModeless)(BOOL fEnable)
        {
            return S_OK;
        }
    };
    
    // ATL in a Console app.
    CComModule _Module;
    BEGIN_OBJECT_MAP(ObjectMap)
    END_OBJECT_MAP()
    
    // Main body
    int _tmain(int argc, _TCHAR* argv[])
    {
        HRESULT hr = S_OK;
        hr = _Module.Init(ObjectMap, NULL, NULL);
    
        // Instantiate JavaScript engine.
        hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
        CComObject* pScriptSite = NULL;
        hr = CComObject::CreateInstance(&pScriptSite);
        pScriptSite->AddRef();
        CComPtr spIActiveScript;
        hr = spIActiveScript.CoCreateInstance(OLESTR("JScript"));
        hr = spIActiveScript->SetScriptSite(pScriptSite);
        CComPtr spIActiveScriptParse;
        hr = spIActiveScript->QueryInterface(IID_IActiveScriptParse, (void **) &spIActiveScriptParse);
        hr = spIActiveScriptParse->InitNew();
        hr = spIActiveScript->SetScriptState(SCRIPTSTATE_CONNECTED);
    
        // Evaluate an anonymous JavaScript function.
        CComVariant vSomeFunc;
        EXCEPINFO ei = { };
        hr = spIActiveScriptParse->ParseScriptText(
            OLESTR("(function () { return function (arr) { return arr.length; }; } )();"),  // pstrCode
            NULL,                       // pstrItemName
            NULL,                       // punkContent
            NULL,                       // pstrDelimiter
            0,                          // dwSourceContextCookie
            0,                          // ulStartingLineNumber
            SCRIPTTEXT_ISEXPRESSION,    // dwFlags
            &vSomeFunc,                 // pvarResult
            &ei                         // pexcepinfo
            );
    
        // Make a JavaScript array object.
        CComVariant vObject;
        hr = spIActiveScriptParse->ParseScriptText(
            OLESTR("[2,3,5,7,11]"), // pstrCode
            NULL,                       // pstrItemName
            NULL,                       // punkContent
            NULL,                       // pstrDelimiter
            0,                          // dwSourceContextCookie
            0,                          // ulStartingLineNumber
            SCRIPTTEXT_ISEXPRESSION,    // dwFlags
            &vObject,                   // pvarResult
            &ei                         // pexcepinfo
            );
    
        // Call the anonymous JavaScript function (gives answer of 5).
        CComVariant vResult;
        DISPPARAMS dispParams = { &vObject, 0, 1, 0 };
        hr = V_DISPATCH(&vSomeFunc)->Invoke(
            DISPID_VALUE,
            IID_NULL,
            0,
            DISPATCH_METHOD,
            &dispParams,
            &vResult,
            &ei,
            NULL);
    
        // Release variables.
        hr = vSomeFunc.Clear();
        hr = vObject.Clear();
        hr = vResult.Clear();
    
        // Release JavaScript engine.
        spIActiveScriptParse = NULL;
        spIActiveScript = NULL;
        pScriptSite->Release();
        pScriptSite = NULL;
        ::CoUninitialize();
        return 0;
    }
    

    To answer the original posters question, we then need to create another JavaScript function to extract elements from the array, say, function (arr,idx) { return arr[idx]; }. Now we have enough functions to walk JavaScript arrays in C++.

提交回复
热议问题