阅读提示:COM 初学者,IE,ActiveX,Javascript如何调用activex的 接口,为什么可以这样调用。
=============================================================================
function testGpc()
{
//alert(“TestGPC”);
var gpcinst = document.getElementById(“ATGpcControl”);
gpcinst.setParam(“test”,”test”);
}
上面的code,取到一个 activex的实例,然后调用它的结构 setParam,那IE 是怎么调用这个接口呢?
看 call stack:
mshtml.dll!CElement::DoClick() + 0x114 bytes
mshtml.dll!CInput::DoClick() + 0x68 bytes
mshtml.dll!CDoc::PumpMessage() + 0x63b74 bytes
mshtml.dll!CDoc::OnMouseMessage() + 0x235 bytes
mshtml.dll!CDoc::OnWindowMessage() + 0xb1afd bytes
mshtml.dll!CServer::WndProc() + 0x4e bytes
这个call stack 很明显了,先处理鼠标移动,然后click 事件,先从 doc 到 input,input 应该是个element,如下call stack:
mshtml.dll!CBase::InvokeDispatchWithThis() + 0xc2 bytes
mshtml.dll!CBase::InvokeEvent() – 0x1dd70c bytes
mshtml.dll!CBase::FireEvent() + 0xfb bytes
mshtml.dll!CElement::BubbleEventHelper() – 0x30f bytes
mshtml.dll!CElement::FireEvent() – 0x1664ba bytes
mshtml.dll!CElement::Fire_onclick() + 0x59 bytes
也是很明显的,一级一级往上call,直到 基类CBase。看下面的call stack。
> ieatgpc.dll!ATL::CComTypeInfoHolder::Invoke(IDispatch * p=0x09970a5c, long dispidMember=2, const _GUID & __formal={…}, unsigned long lcid=1, unsigned short wFlags=1, tagDISPPARAMS * pdispparams=0x039cca38, tagVARIANT * pvarResult=Empty, tagEXCEPINFO * pexcepinfo=0x039cc9f8, unsigned int * puArgErr=0x00000000) Line 3698 + 0x1e bytes C++
mshtml.dll!InvokeDispatchWithNoThis() + 0x3d bytes
mshtml.dll!COleSite::InvokeControl() + 0x53 bytes
mshtml.dll!COleSite::ContextInvokeEx() – 0x6ba46 bytes
mshtml.dll!CObjectElement::VersionedInvokeEx() + 0x4f bytes
mshtml.dll!CBase::PrivateInvokeEx() + 0x4d bytes
jscript9.dll!HostDispatch::CallInvokeEx() + 0xca bytes
jscript9.dll!HostDispatch::InvokeMarshaled() + 0x3d bytes
jscript9.dll!HostDispatch::InvokeByDispId() + 0x1dc bytes
jscript9.dll!DispMemberProxy::DefaultInvoke() + 0x22 bytes
jscript9.dll!DispMemberProxy::DefaultInvoke() + 0x20 bytes
jscript9.dll!Js::JavascriptFunction::CallFunction() + 0x87 bytes
jscript9.dll!Js::JavascriptFunction::CallRootFunction() + 0xa9 bytes
jscript9.dll!ScriptSite::CallRootFunction() + 0x4f bytes
jscript9.dll!ScriptSite::Execute() + 0x5f bytes
jscript9.dll!JavascriptDispatch::InvokeOnSelf() + 0xdc bytes
jscript9.dll!JavascriptDispatch::InvokeEx() + 0x167 bytes
但还是没有解决我想要的问题?
为什么 是 setParam呢? 我在 native的实现是 SetParam的接口啊,怎么从 JS的function,转到 native 的接口呢? 继续分析!
先把setParam 变成 SetParam 试试。
调试发现也是可以的。
所以猜想是 Ie内部已经把
setParam
SetParam 与 dispatch 的ID 关联起来了。
我们试着再调用它的另一个接口:
dispidMember = 3.
那这个2,3 是怎么确定的呢?
我们可以看下 idl 文件里的定义:
那试试去改一下行不行呢?
build 完之后,我们看一下 tlb 文件里的接口:
dispinterface IGpcContainer
{
properties:
methods:
[id(0), restricted] void QueryInterface(
[in] GUID* riid,
[out] void** ppvObj);
[id(1), restricted] unsigned long AddRef();
[id(2), restricted] unsigned long Release();
这个无需解释,前3个必须是这,继承IUnknown,如果你不晓得,只能去google,或者看看书了。
我们试着把 InitDone 改成id(5),结果显示:
可见这个id 还是起作用的。
但 tlb 里的接口是这样的,它的Id代表什么意思呢?
其实读过《com技术内幕》等书的人,一眼就知道 GetIDsOfNames 这个来自 IDispatch 的接口是干嘛用的,不过我们还是来调试一下,亲自感觉下:
然后我们看看 这个 SetParam ,肯定是page 传过来的,看看它取的ID 是多少?
IDispatchImpl 是 ATL 默认的实现
接着跳转到下面的function,在atlcom.h 里面
HRESULT GetIDsOfNames(REFIID /* riid */, _In_count_(cNames) LPOLESTR* rgszNames, UINT cNames,
LCID lcid, DISPID* rgdispid)
{
HRESULT hRes = EnsureTI(lcid);
if (m_pInfo != NULL)
{
hRes = E_FAIL;
// Look in cache if
// cache is populated
// parameter names are not requested
if (m_pMap != NULL && cNames == 1)
{
int n = int( ocslen(rgszNames[0]) );
for (int j=m_nCount-1; j>=0; j--)
{
if ((n == m_pMap[j].nLen) &&
(memcmp(m_pMap[j].bstr, rgszNames[0], m_pMap[j].nLen * sizeof(OLECHAR)) == 0))
{
rgdispid[0] = m_pMap[j].id;
hRes = S_OK;
break;
}
}
}
// if cache is empty or name not in cache or parameter names are requested,
// delegate to ITypeInfo::GetIDsOfNames
if (FAILED(hRes))
{
hRes = m_pInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
}
}
return hRes;
}
我们来解释一下上面的function:TBD
下面看这个图:
总结:
1. js call 一个function
2.IE 会根据这个function 名字去 call activex的 GetIDsOfNames,取到它的ID,然后invoke,其他同基本的COM知识。
=========================================================================================
以下是 call stack,从下往上读。
inline HRESULT CComModule::GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw()
/\
> ieatgpc.dll!DllGetClassObject(const _GUID & rclsid={…}, const _GUID & riid={…}, void * * ppv=0x039c7098) Line 98 C++
ole32.dll!CClassCache::CDllPathEntry::DllGetClassObject(const _GUID & rclsid={…}, const _GUID & riid={…}, IUnknown * * ppUnk=0x039c7098, int fMakeValid=1) Line 3324 + 0x3 bytes C++
ole32.dll!CClassCache::CDllFnPtrMoniker::BindToObjectNoSwitch(const _GUID & riid={…}, void * * ppvResult=0x039c7098) Line 3831 C++
ole32.dll!CClassCache::GetClassObject(const ACTIVATION_PROPERTIES & ap={…}) Line 4582 + 0xf bytes C++
ole32.dll!CServerContextActivator::GetClassObject(IActivationPropertiesIn * pInActProperties=0x039c7644, IActivationPropertiesOut * * ppOutActProperties=0x039c7bac) Line 839 + 0x9 bytes C++
ole32.dll!ActivationPropertiesIn::DelegateGetClassObject(IActivationPropertiesOut * * pActPropsOut=0x039c7bac) Line 1850 C++
ole32.dll!CApartmentActivator::GetClassObject(IActivationPropertiesIn * pInActProperties=0x039c7644, IActivationPropertiesOut * * ppOutActProperties=0x039c7bac) Line 2171 + 0x12 bytes C++
ole32.dll!CProcessActivator::GCOCallback(unsigned long dwContext=1, IUnknown * pUnkOuter=0x00000000, ActivationPropertiesIn * pActIn=0x039c74a0, IActivationPropertiesIn * pInActProperties=0x039c7644, IActivationPropertiesOut * * ppOutActProperties=0x039c7bac) Line 1673 + 0xf bytes C++
ole32.dll!CProcessActivator::AttemptActivation(ActivationPropertiesIn * pActIn=0x039c74a0, IUnknown * pUnkOuter=0x00000000, IActivationPropertiesIn * pInActProperties=0x039c7644, IActivationPropertiesOut * * ppOutActProperties=0x039c7bac, HRESULT (unsigned long, IUnknown *, ActivationPropertiesIn *, IActivationPropertiesIn *, IActivationPropertiesOut * *)* pfnCtxActCallback=0x76c73d49, unsigned long dwContext=1) Line 1630 C++
ole32.dll!CProcessActivator::ActivateByContext(ActivationPropertiesIn * pActIn=0x039c74a0, IUnknown * pUnkOuter=0x00000000, IActivationPropertiesIn * pInActProperties=0x039c7644, IActivationPropertiesOut * * ppOutActProperties=0x039c7bac, HRESULT (unsigned long, IUnknown *, ActivationPropertiesIn *, IActivationPropertiesIn *, IActivationPropertiesOut * *)* pfnCtxActCallback=0x76c73d49) Line 1487 + 0x12 bytes C++
ole32.dll!CProcessActivator::GetClassObject(IActivationPropertiesIn * pInActProperties=0x039c7644, IActivationPropertiesOut * * ppOutActProperties=0x039c7bac) Line 1308 + 0x17 bytes C++
ole32.dll!ActivationPropertiesIn::DelegateGetClassObject(IActivationPropertiesOut * * pActPropsOut=0x039c7bac) Line 1850 C++
ole32.dll!CClientContextActivator::GetClassObject(IActivationPropertiesIn * pInActProperties=0x039c7644, IActivationPropertiesOut * * ppOutActProperties=0x039c7bac) Line 590 C++
ole32.dll!ActivationPropertiesIn::DelegateGetClassObject(IActivationPropertiesOut * * pActPropsOut=0x039c7bac) Line 1850 C++
ole32.dll!ICoGetClassObject(const _GUID & rclsid={…}, unsigned long dwContext=7, _COSERVERINFO * pServerInfo=0x00000000, const _GUID & riid={…}, unsigned long dwActvFlags=0, void * * ppvClassObj=0x039c8e68, ActivationPropertiesIn * pActIn=0x00000000) Line 886 + 0x13 bytes C++
ole32.dll!CComActivator::DoGetClassObject(const _GUID & rclsid={…}, unsigned long dwContext=7, _COSERVERINFO * pServerInfo=0x00000000, const _GUID & riid={…}, void * * ppvClassObj=0x039c8e68, ActivationPropertiesIn * pActIn=0x00000000) Line 298 C++
ole32.dll!CoGetClassObject(const _GUID & rclsid={…}, unsigned long dwContext=7, void * pvReserved=0x00000000, const _GUID & riid={…}, void * * ppvClassObj=0x039c8e68) Line 73 C++
urlmon.dll!CoGetClassObjectForObjectBinding() + 0x39 bytes
urlmon.dll!_CoGetClassObjectFromURLInternal@44() + 0x9a3 bytes
urlmon.dll!TUnknown_DllRefcount_MTBase<char>::_ReleaseNoDllRef() + 0xd bytes
mshtml.dll!CProgSink::AddProgress() + 0x13d bytes
mshtml.dll!CCodeLoad::Init() + 0x150 bytes
mshtml.dll!COleSite::CreateObject() + 0x1d9 bytes
mshtml.dll!CObjectElement::FinalCreateObject() + 0x35f bytes
mshtml.dll!CObjectElement::CreateObject() + 0x93 bytes
mshtml.dll!CHtmObjectParseCtx::Execute() + 0x9 bytes
mshtml.dll!CHtmParse::Execute() + 0x4727 bytes
mshtml.dll!CHtmPost::Broadcast() + 0xf bytes
mshtml.dll!CHtmPost::Exec() + 0x3ae4c bytes
mshtml.dll!CHtmPost::Run() + 0x40 bytes
mshtml.dll!PostManExecute() + 0x8e bytes
mshtml.dll!PostManResume() + 0x96 bytes
mshtml.dll!CHtmPost::OnDwnChanCallback() + 0x10 bytes
mshtml.dll!CDwnChan::OnMethodCall() + 0x1f bytes
mshtml.dll!GlobalWndOnMethodCall() + 0xf8 bytes
mshtml.dll!GlobalWndProc() + 0x45162 bytes
user32.dll!_InternalCallWinProc@20() + 0x23 bytes
user32.dll!_UserCallWinProcCheckWow@32() + 0xb7 bytes
user32.dll!_DispatchMessageWorker@8() + 0xed bytes
user32.dll!_DispatchMessageW@4() + 0xf bytes
ieframe.dll!CTabWindow::_TabWindowThreadProc() + 0x39b bytes
ieframe.dll!LCIETab_ThreadProc() + 0x2fd bytes
iertutil.dll!CIsoScope::RegisterThread() – 0x2b67 bytes
ieframe.dll!Detour_DefWindowProcA() + 0x66a6e bytes
kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes
ntdll.dll!___RtlUserThreadStart@8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x1b bytes
0