Насколько я понимаю, у вас есть пользовательский сервер сценариев JavaScript хостинг через активные интерфейсы сценариев. JavaScript-движок использует IDispatchEx::Invoke для вызова COM-объектов (всякий раз, когда IDispatchEx
доступен, как и у объекта MSHTML doc
) и передает его вызов IServiceProvider
. Полагаю, вот как реализована реализация doc
, она вызывается из среды сценариев, отличной от ее собственных скриптов, и ограничивает ее методы соображениями безопасности (в отличие от собственных вызовов кода).
Я не знаю документированный способ превратить это поведение, но вы можете попробовать следующие варианты:
- Реализовать
IServiceProvider
на вашем IActiveScriptSite
объекта и перенаправлять все запросы на обслуживание к IServiceProvider
вы получите от Объект IHTMLDocument2
(doc
). Это может работать или не работать.
- Wrap
doc
с родным объектом C++, который реализует только IDispatch
и переадресует все его вызовы на IHTMLDocument2
. Передайте объект оболочки к вашему скрипту вместо оригинала doc
. Скорее всего, это должно сработать.
Сообщите нам, если вам повезло с вышеуказанным.
[РЕДАКТИРОВАНИЕ] Попробуйте это:
class CDispatchWrapper:
public CComObjectRoot,
public IDispatch
{
// http://stackoverflow.com/questions/18718366/permission-denied-on-frame/
protected:
CDispatchWrapper() {}
struct MEMBER
{
CComPtr<IUnknown> unk;
CComPtr<ITypeInfo> ti;
};
CComPtr<ITypeLib> m_typeLib;
CComPtr<IDispatch> m_dispatch;
CSimpleMap<CComBSTR, DISPID> m_dispids;
CSimpleMap<DISPID, MEMBER> m_members;
public:
BEGIN_COM_MAP(CDispatchWrapper)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
// create and initialize
static HRESULT Create(IDispatch* dispatch, const GUID& libid, CDispatchWrapper** pp)
{
CComObject<CDispatchWrapper>* pThis = NULL;
CComObject<CDispatchWrapper>::CreateInstance(&pThis);
if (!pThis)
return E_OUTOFMEMORY;
if (FAILED(LoadRegTypeLib(libid, 0xFFFF, 0xFFFF, 0, &pThis->m_typeLib)))
return E_FAIL;
pThis->m_dispatch = dispatch;
(*pp = pThis)->AddRef();
return S_OK;
}
// IDispatch
STDMETHODIMP GetTypeInfoCount(UINT* pctinfo)
{
return E_NOTIMPL;
}
STDMETHODIMP GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{
return E_NOTIMPL;
}
STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid)
{
if (cNames != 1 || !rgszNames || !rgszNames[0] || !*rgszNames[0] || !rgdispid)
return E_INVALIDARG;
CComBSTR name(rgszNames[0]);
if (!name)
return E_OUTOFMEMORY;
int n = m_dispids.FindKey(name);
if (n >= 0)
{
DISPID dispid = m_dispids.GetValueAt(n);
if (dispid == DISPID_UNKNOWN)
return DISP_E_UNKNOWNNAME;
rgdispid[0] = dispid;
return S_OK;
}
// find the name(s) in the typelib
UINT cMax = m_typeLib->GetTypeInfoCount();
ITypeInfo** ppTypeInfo = (ITypeInfo**)_alloca(sizeof(ITypeInfo*) * cMax);
MEMBERID* pMemberid = (MEMBERID*)_alloca(sizeof(MEMBERID*) * cMax);
USHORT cTypes = cMax;
if (FAILED(m_typeLib->FindName(name, 0, ppTypeInfo, pMemberid, &cTypes)) || !cTypes)
return DISP_E_UNKNOWNNAME;
bool found = false;
MEMBER member;
DISPID dispid = DISPID_UNKNOWN;
for (int i = 0; i < cTypes && !found; i++)
{
TYPEATTR* pTypeAttr = NULL;
member.ti.Release();
member.unk.Release();
member.ti = ppTypeInfo[i];
member.ti->GetTypeAttr(&pTypeAttr);
if (pTypeAttr)
{
// check to see if m_dispatch object also implements pTypeAttr->guid interface
m_dispatch->QueryInterface(pTypeAttr->guid, (void**)&member.unk);
if (member.unk)
{
// could use pMemberid[i], but let's make sure
dispid = DISPID_UNKNOWN;
if (SUCCEEDED(member.ti->GetIDsOfNames(rgszNames, 1, &dispid)))
found = true;
}
member.ti->ReleaseTypeAttr(pTypeAttr);
}
}
for (int i = 0; i < cTypes; i++)
ppTypeInfo[i]->Release();
if (found)
{
if (!m_dispids.Add(name, dispid))
return E_OUTOFMEMORY;
if (!m_members.Add(dispid, member))
return E_OUTOFMEMORY;
rgdispid[0] = dispid;
return S_OK;
}
if (!m_dispids.Add(name, DISPID_UNKNOWN))
return E_OUTOFMEMORY;
return DISP_E_UNKNOWNNAME;
}
STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
int n = m_members.FindKey(dispidMember);
if (n >= 0)
{
const MEMBER& member = m_members.GetValueAt(n);
return member.ti->Invoke(member.unk, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
}
return DISP_E_MEMBERNOTFOUND;
}
};
Использование:
CComPtr<IHTMLDocument2> doc;
// ...
// once doc != NULL, wrap it
CComPtr<CDispatchWrapper> wrapper;
CDispatchWrapper::Create(doc, LIBID_MSHTML, &wrapper);
// now pass the wrapper to the script, instead of doc
К сожалению, оба варианта не работают. IDispatchEx :: GetDispID не работает с E_ACCESSDENIED. – Sharpeye
Не используйте 'IDispatchEx :: GetDispID'. Чтобы сделать второй вариант, используйте 'CDispatchWrapper', который я только что опубликовал. – Noseratio
'm_dispatch-> GetIDsOfNames' и' m_dispatch-> GetTypeInfo' не работает с E_ACCESSDENIED – Sharpeye