IE load activex in detail-未完

阅读提示: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
下面看这个图:
ATL对象创建外部机制
总结:
1. js call 一个function
2.IE 会根据这个function 名字去 call activex的 GetIDsOfNames,取到它的ID,然后invoke,其他同基本的COM知识。
=========================================================================================
以下是 call stack,从下往上读。
inline HRESULT CComModule::GetClassObject(REFCLSID rclsidREFIID riidLPVOIDppvthrow()
/\
> 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