如何将JavaScript数组()转换为ATL/COM数组?

如何将JavaScript数组()转换为ATL/COM数组?,javascript,c++,arrays,atl,Javascript,C++,Arrays,Atl,如何在不使用VBArray的情况下将JavaScript数组()转换为ATL/COM数组 我想将一个新数组()转换为一个安全数组。我过去曾研究过这个问题,据我所知,这是不可能的。脚本中的唯一选项是使用VBScript和VBArray。javascript数组是包含IDispatch指针的变体。IDispatch实现在调度id处有一个枚举器方法 . 如果你使用C++,你也可以从对象中查询iQueXiFipe来访问它的元素。 < P>这里有一个代码要做(考虑到你已经把JS数组对象作为C++变量),与

如何在不使用VBArray的情况下将JavaScript数组()转换为ATL/COM数组


我想将一个新数组()转换为一个安全数组。

我过去曾研究过这个问题,据我所知,这是不可能的。脚本中的唯一选项是使用VBScript和VBArray。

javascript数组是包含IDispatch指针的变体。IDispatch实现在调度id处有一个枚举器方法 .
如果你使用C++,你也可以从对象中查询iQueXiFipe来访问它的元素。

< P>这里有一个代码要做(考虑到你已经把JS数组对象作为C++变量),与<盛江> <强>的方式相同:
bool VariantToArray(__in const CComVariant& var, __out vector<CComVariant>& vecVars)
{
    // convert variant to dispatch object
    CComPtr<IDispatch> pDispatch = VariantToDispatch(var);
    if (!pDispatch)
        return false;

    // invoke the object to retrieve the enumerator containing object
    CComVariant varResult;
    DISPPARAMS dispparamsNoArgs = {0};
    EXCEPINFO excepInfo = {0};
    UINT uiArgErr = (UINT)-1;  // initialize to invalid arg
    HRESULT hr = pDispatch->Invoke( DISPID_NEWENUM,
                                    IID_NULL,
                                    LOCALE_USER_DEFAULT,
                                    DISPATCH_METHOD | DISPATCH_PROPERTYGET,
                                    &dispparamsNoArgs,
                                    &varResult,
                                    &excepInfo,
                                    &uiArgErr);
    if (FAILED(hr))
        return false;

    // query the retrieved interface and get the enumerator object
    CComPtr<IEnumVARIANT> pEnumVariant;
    switch (varResult.vt)
    {
        case VT_UNKNOWN:
        {
            CComPtr<IUnknown> pUnknownResult = varResult.punkVal;
            if (!pUnknownResult)
                return false;
            pEnumVariant = pUnknownResult; // implied query interface
        }
        break;

        case VT_DISPATCH:
        {
            CComPtr<IDispatch> pDispatchResult = varResult.pdispVal;
            if (!pDispatchResult)
                return false;
            pEnumVariant = pDispatchResult; // implied query interface
        }
        break;

        default:
            return false;
    }

    if (!pEnumVariant)
        return false;

    // reset enumerator to beginning of the list
    hr = pEnumVariant->Reset();
    if (FAILED(hr))
        return false;

    // enumerate and fetch items
    CComVariant varItem;
    ULONG uiFetched = 0;
    do 
    {
        // get next item
        hr = pEnumVariant->Next(1, &varItem, &uiFetched);
        if (FAILED(hr))
            return false;

        if (uiFetched == NULL) // last item
            break;

        // insert the item to the vector 
        vecVars.push_back(varItem);
    } while (true);

    return true;
}
bool VariantToArray(\uuuu in-const-CComVariant&var,\uuuu out-vector&vecVars)
{
//将变量转换为分派对象
CComPtr pDispatch=VariantotDispatch(var);
如果(!pDispatch)
返回false;
//调用该对象以检索包含该对象的枚举数
变异结果;
DISPPARAMS dispparamsNoArgs={0};
EXEPINFO EXEPINFO={0};
UINT uiArgErr=(UINT)-1;//初始化为无效参数
HRESULT hr=pDispatch->Invoke(dispatid\u NEWENUM,
IID_NULL,
区域设置\用户\默认值,
调度方法|调度属性集,
&disparamsnoargs,
&varResult,
&除此之外,
&uiArgErr);
如果(失败(小时))
返回false;
//查询检索到的接口并获取枚举器对象
CComPtr pEnumVariant;
开关(varResult.vt)
{
案例VT_未知:
{
CComPtr punnownresult=varResult.punkVal;
如果(!PunnownResult)
返回false;
pEnumVariant=pUnknownResult;//隐含查询接口
}
打破
案例VT_调度:
{
CComPtr pDispatchResult=varResult.pdispVal;
如果(!pDispatchResult)
返回false;
pEnumVariant=pDispatchResult;//隐含查询接口
}
打破
违约:
返回false;
}
如果(!pEnumVariant)
返回false;
//将枚举数重置为列表的开头
hr=pEnumVariant->Reset();
如果(失败(小时))
返回false;
//枚举和获取项目
变异变量;
ULONG uiFetched=0;
做
{
//获取下一项
hr=pEnumVariant->Next(1,&varItem,&uiFetched);
如果(失败(小时))
返回false;
if(uiFetched==NULL)//最后一项
打破
//将项目插入到向量中
向量推回(变量);
}虽然(正确);
返回true;
}
希望有帮助

注意:
我看到一篇帖子,其中(但在IE6、7、8上是这样),我自己检查了一下——在IE9上(仅限)调用方法失败并返回DISP_E_异常。
所以我仍然在寻找更好的解决方案

编辑:
以下代码适用于所有IE浏览器:

bool VariantToArray(__in const CComVariant& var, __out vector<CComVariant>& vecVars)
        {
            // convert variant to dispatch object
            CComPtr<IDispatch> pDispatch = VariantToDispatch(var);
            if (!pDispatch)
                return false;

            // get DISPID of length parameter from array object
            LPOLESTR sLengthName = L"length";
            DISPID dispidLength = 0;
            HRESULT hr = pDispatch->GetIDsOfNames(IID_NULL, &sLengthName, 1, LOCALE_USER_DEFAULT, &dispidLength);
            if (FAILED(hr))
                return false;

            // get the number of elements using the DISPID of length parameter
            CComVariant varLength;
            DISPPARAMS dispParams = {0};
            hr = pDispatch->Invoke(dispidLength, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &varLength, NULL, NULL);
            if (FAILED(hr))
                return false;

            int nLength = 0; // length of the array
            bool bGotInt = VariantToInt(varLength, nLength);
            if (!bGotInt)
                return false;

            // get items of array
            for (int i=0 ; i<nLength ; ++i)
            {
                // get DISPID of item[i] from array object
                wstring strIndex = StringUtils::IntToString(i);
                DISPID dispidIndex = 0;
                LPOLESTR pIndex = reinterpret_cast<LPOLESTR>(const_cast<WCHAR *>(strIndex.data()));
                hr = pDispatch->GetIDsOfNames(IID_NULL, &pIndex, 1, LOCALE_USER_DEFAULT, &dispidIndex);
                if (FAILED(hr))
                    continue;

                CComVariant varItem;
                hr = pDispatch->Invoke(dispidIndex, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &varItem, NULL, NULL);
                if (FAILED(hr))
                    continue;

                vecVars.push_back(varItem);
            }

            return true;
        }
bool VariantToArray(\uuuu in-const-CComVariant&var,\uuuu out-vector&vecVars)
{
//将变量转换为分派对象
CComPtr pDispatch=VariantotDispatch(var);
如果(!pDispatch)
返回false;
//从数组对象获取长度参数的DISPID
LPOLESTR SLENGHTNAME=L“长度”;
DISPID dispidleength=0;
HRESULT hr=pDispatch->GetIDsOfNames(IID_NULL,&slengtname,1,LOCALE_USER_DEFAULT,&dispatidlength);
如果(失败(小时))
返回false;
//使用DISPID of length参数获取元素数
变异变长;
DISPPARAMS DISPPARAMS={0};
hr=pDispatch->Invoke(dispatidlength,IID_NULL,LOCALE_USER_DEFAULT,DISPATCH_PROPERTYGET,&dispatchparams,&varLength,NULL,NULL);
如果(失败(小时))
返回false;
int nLength=0;//数组的长度
bool bGotInt=VariantToInt(varLength,nLength);
如果(!bgoint)
返回false;
//获取数组的项
对于(int i=0;iGetIDsOfNames(IID_NULL,&pIndex,1,LOCALE_USER_DEFAULT,&dispid索引);
如果(失败(小时))
继续;
变异变量;
hr=pDispatch->Invoke(dispatdindex,IID\u NULL,LOCALE\u USER\u DEFAULT,DISPATCH\u PROPERTYGET,&dispatchparams,&varItem,NULL,NULL);
如果(失败(小时))
继续;
向量推回(变量);
}
返回true;
}

< < /P> < P> > <代码> IActiveScript < /Cord> >您可以在C++中实例化JavaScript引擎,并将其用于:

  • 为JavaScript函数生成
    IDispatch*
    指针
  • 生成包含JavaScript对象的
    VARIANT
    变量
  • 将JavaScript对象传递给C中的JavaScript函数++
使用此技术,我们将执行以下操作:

  • 声明一个JavaScript函数,例如
    函数(arr){return arr.length;}
  • 声明一个JavaScript数组,例如[2,3,5,7,11]
  • 使用JavaScript数组作为输入调用JavaScript函数
  • 要实现此功能,必须创建一个
    IActiveScriptSite
    。下面是一个演示这个概念的C++控制台应用程序:

    // C++ headers for ATL and Active Script Hosting.
    #include <atlbase.h>
    #include <atlcom.h>
    #include <activscp.h>
    
    // A minimal implementation of IActiveScriptSite.
    class ATL_NO_VTABLE CScriptSite :
        public CComObjectRootEx<CComSingleThreadModel>,
        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<CScriptSite>* pScriptSite = NULL;
        hr = CComObject<CScriptSite>::CreateInstance(&pScriptSite);
        pScriptSite->AddRef();
        CComPtr<IActiveScript> spIActiveScript;
        hr = spIActiveScript.CoCreateInstance(OLESTR("JScript"));
        hr = spIActiveScript->SetScriptSite(pScriptSite);
        CComPtr<IActiveScriptParse> 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;
    }
    
    < ATL和活动脚本托管的代码> //C++标题。 #包括 #包括 #包括 //IActiveScriptSite的最小实现。 类别ATL_NO_VTABLE CScriptSite: 公共CComObjectRootEx, 公共活动描述网站, 公共IActiveScriptSiteWindow { 公众: 开始COM地图(CScriptSite) 国际通信