2011-02-16 103 views

回答

0

我已經看過這個過去,據我所知這是不可能的。腳本中唯一的選擇是使用VBScript和VBArray。

0

javascript數組是一個包含IDispatch指針的VARIANT。 IDispatch實現在調度ID爲DISPID_NEWENUM 處具有枚舉器方法。如果使用C++,則可以從對象中查詢IEnumVARIANT以訪問其元素。

8

這裏有一個代碼來做到這一點(考慮你已經得到了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; 
} 

希望幫助。

注:
我看到一個帖子裏someone complained this doesn't work on IE9(但它確實對IE6,7,8),我檢查出來自己 - 對IE9(只)Invoke方法失敗並返回DISP_E_EXCEPTION。
所以我仍然在尋找更好的解決方案。

編輯:
這裏有一個代碼,所有的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; 
     } 

享受:)

+1

非常感謝,我打算放棄並使用逗號分隔的字符串,但是這段代碼確實有效(至少在IE11中)!只是想添加 - 代碼使用了VariantToDispatch和VariantToInt函數,這些函數變得非常簡單。 在前者中,您只需檢查vt == VT_DISPATCH,如果是,則返回pdispVal。後者更棘手 - 您只需使用像VariantChangeType(&newvar,&inputvar,0,VT_I4)這樣的東西,如果它成功了,就可以得到`newvar.intVal`。 我希望我可以插入代碼片段,但我不認爲SO允許在評論中這樣做。 – 2015-03-20 03:28:39

1

隨着IActiveScript,你可以在C++中實例化一個JavaScript引擎,並用它來:

  • 製作IDispatch*用於JavaScript函數的指針
  • 使含VARIANT變量JavaScript對象
  • 通行證的JavaScript對象在C++中的JavaScript函數

使用這種技術,我們應做到以下幾點:

  1. 聲明一個JavaScript函數,例如function (arr) { return arr.length; }
  2. 聲明一個JavaScript數組,例如[2,3,5,7,11]
  3. 呼叫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; 
} 

要回答原來的海報的問題,然後我們需要創建另一個JavaScript函數來提取數組,比如說,function (arr,idx) { return arr[idx]; }元素。現在我們有足夠的功能來在C++中漫遊JavaScript數組。