2013-09-10 3 views
2

У меня есть окно, основанное на CAxWindow. В этом окне я создаю элемент управления WebBrowser. Когда DISPID_DOCUMENTCOMPLETE происходит я:Разрешение отклонено на кадре

void __stdcall document_complete(LPDISPATCH pBrowser, VARIANT*) 
{ 
    CComQIPtr<IWebBrowser2> wb(pBrowser); 

    CComPtr<IDispatch> doc; 

    if(SUCCEEDED(wb->get_Document(&doc))) 
    { 
     _docs.push_back(doc); 
    } 

    ... 
} 

При загрузке страницы Призывает каждый документ в _docs скрипт (IActiveScript и IActiveScriptSite):

function main(doc) 
{ 
    try 
    { 
     return doc.URL; 
    } 
    catch(e) 
    { 
     return "Error: " + e.description; 
    } 
} 

На некоторых документах, которые я получаю сообщение об ошибке: «Разрешение отказано». с машинным кодом У меня нет никаких проблем:

for(auto disp : _docs) 
{ 
    CComQIPtr<IHTMLDocument2> doc(disp); 

    _bstr_t url; 

    ATLVERIFY(SUCCEEDED(doc->get_URL(url.GetAddress()))); 
} 

Как я могу избежать ошибки?

Оказалось, что сценарии не были причиной:

for(auto disp : _docs) 
{ 
    CComQIPtr<IDispatchEx> doc(disp); 

    DISPID id = 0; 
    auto hr = doc->GetDispID(_bstr_t(L"URL"), 0, &id); 

    // hr == E_ACCESSDENIED 
} 

ответ

1

Насколько я понимаю, у вас есть пользовательский сервер сценариев 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 
+0

К сожалению, оба варианта не работают. IDispatchEx :: GetDispID не работает с E_ACCESSDENIED. – Sharpeye

+0

Не используйте 'IDispatchEx :: GetDispID'. Чтобы сделать второй вариант, используйте 'CDispatchWrapper', который я только что опубликовал. – Noseratio

+0

'm_dispatch-> GetIDsOfNames' и' m_dispatch-> GetTypeInfo' не работает с E_ACCESSDENIED – Sharpeye

Смежные вопросы