如何在不使用 VBArray 的情况下将 JavaScript array() 转换为 ATL/COM 数组?
我想将一个新的 Array() 转换为一个 SAFEARRAY。
最佳答案
这里有一段代码可以做到这一点(考虑到您已经将 JS Array 对象作为 C++ 变体),与 Sheng Jiang 之前建议的方法相同:
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;
}
享受 :)
关于javascript - 如何将 JavaScript array() 转换为 ATL/COM 数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5014711/