Как преобразовать объект JavaScript для доступа к его данным из C++?
Я использую встроенный элемент управления IE ActiveX в моем приложении C++ (MFC). Встроенный IE имеет метод JavaScript, который передает данные обратно в мое приложение C++, используя следующий (упрощенный) JavaScript:
function passDataTocpp()
{
return {key1: 134, key2:'value2'};
}
Когда я получаю его в своем коде C++, я получаю VARIANT типа VT_DISPATCH. Мне удалось найти этот пример, который преобразует массив в доступные для C++ данные, но, похоже, не работает для ассоциативного массива (или объекта).
Есть идеи, как получить доступ к этим данным?
3 ответа
IDispatch::GetIdsOfNames
, IDispatch::Invoke(DISPID_PROPGET)
, Если вы даже не знаете, какими свойствами обладает объект, запросите IDispatchEx
и использовать GetNextDispID
перечислять их.
Поскольку вы используете ATL, CComDispatchDriver
удобная обертка вокруг IDispatch
(но нет IDispatchEx
- тот, который вам придется позвонить напрямую). По некоторым причинам, это не задокументировано в MSDN. Уважать CComPtr<IDispatch>
специализация в atlcomcli.h, это достаточно просто. CComDispatchDriver
это typedef для него.
На стороне C++ код может выглядеть так (объяснил ответ Игоря):
STDMETHOD(Foo)(VARIANT vValue)
{
ATLASSERT(vValue.vt == VT_DISPATCH);
CComPtr<IDispatch>& pValue = reinterpret_cast<CComPtr<IDispatch>&>
(vValue.pdispVal);
CComVariant vItemValue;
const HRESULT nResult = pValue.GetPropertyByName(L"key1", &vItemValue);
// vItemValue is VT_I4 134 here
Следуя совету @IgorTandetnik, я пришел к следующему методу, который, кажется, выполняет эту работу (хотя это псевдокод):
BOOL VariantToObjectProperties(CComVariant& var)
{
HRESULT hr;
if (var.vt != VT_DISPATCH)
return FALSE;
CComPtr<IDispatch> pDispatch = var.pdispVal;
CComQIPtr<IDispatchEx> pDispatchEx;
if(FAILED(hr = pDispatch->QueryInterface(IID_IDispatchEx, (void **)&pDispatchEx)))
return FALSE;
BSTR bstrName;
DISPID dispid;
//Assume success
BOOL bRes = TRUE;
//Enumerate object names
hr = pDispatchEx->GetNextDispID(fdexEnumAll, DISPID_STARTENUM, &dispid);
while (hr == NOERROR)
{
if(SUCCEEDED(hr = pDispatchEx->GetMemberName(dispid, &bstrName)))
{
// get DISPID of item
DISPID dispidIndex = 0;
LPOLESTR pIndex = reinterpret_cast<LPOLESTR>(const_cast<WCHAR *>(bstrName));
if(SUCCEEDED(hr = pDispatch->GetIDsOfNames(IID_NULL, &pIndex, 1, LOCALE_USER_DEFAULT, &dispidIndex)))
{
CComVariant varItem;
DISPPARAMS dispParams = {0};
if(SUCCEEDED(hr = pDispatch->Invoke(dispidIndex, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dispParams, &varItem, NULL, NULL)))
{
//Object's property name is in 'bstrName'
//Object's property value is in 'varItem'
}
else
{
ASSERT(NULL);
bRes = FALSE;
}
}
else
{
ASSERT(NULL);
bRes = FALSE;
}
}
SysFreeString(bstrName);
hr = pDispatchEx->GetNextDispID(fdexEnumAll, dispid, &dispid);
}
return bRes && hr == S_FALSE;
}