帧上的权限被拒绝
Permission denied on frame
我有一个基于CAxWindow的窗口。在此窗口中,我创建了 Web 浏览器控件。当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
}
据我了解,您有一个自定义脚本主机,通过活动脚本接口托管JavaScript。JavaScript 引擎使用 IDispatchEx::Invoke 调用 COM 对象(只要IDispatchEx
可用,就像 MSHTML doc
对象一样),并将自己的IServiceProvider
传递给调用。我想,这就是doc
实现意识到它是从不同于其自己的脚本的脚本环境中调用的方式,并出于安全原因限制其方法(与本机代码调用不同)。
我不知道关闭此行为的记录方法,但您可以尝试以下选项:
- 在
IActiveScriptSite
对象上实现IServiceProvider
,并将所有服务请求转发到从IHTMLDocument2
对象获得的IServiceProvider
(doc
)。这可能有效,也可能无效。 - 使用本机 C++ 对象包装
doc
,该对象仅实现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
相关文章:
- Termux权限被拒绝
- AWS Lambda C++运行时权限被拒绝
- 为什么 KMS drmModeSetCrtc() 在 X11 会话中运行时会失败并被拒绝权限?
- 使用崇高文本 3 进行C++拒绝授予权限?
- 安卓inotify_add_watch失败:权限被拒绝?
- clang --版本权限被拒绝错误
- 为什么 mkdir() 后跟 ofstream::operator<< 失败并被拒绝权限?
- QSSLSLSOCKETS无法解决和权限拒绝错误
- 运行简单 c++ 程序时出现权限被拒绝错误
- Apache HTTPD模块共享内存权限拒绝了错误
- CLION无法打开输出文件,拒绝了权限
- 无法打开输出文件___.exe:权限被拒绝
- 写入文件权限被拒绝
- .out 使用 -c 指令和 g++ 拒绝权限
- 当我使用 remove() 时权限被拒绝
- Linux 拒绝使用 boost asio 的套接字绑定权限
- 获取错误 - 启用权限后,OpenProcess() 中的访问被拒绝
- 连接到Boost.Asio创建的域套接字时权限被拒绝
- 无法打开输出文件:binDebugPrimeChecker.exe权限被拒绝
- 在Linux中拒绝权限