自己實現IDispatch::Invoke方法

因為種種原因,在只能得到一個IWebBrowser指針的情況下要接收javascript的window.external.XXX調用,不得已自己實現了IDocHostUIHandler和IDispatch,為了使用方便,自己又需要實現類似MFC的DISPATCH_MAP:首先用一個結構體保存每個DISPATCH方法的ID,名字,this指針,函數地址,返回值類型,參數類型列表。這些都沒有什么難度。然后在IDispatch::GetIDsOfNames里面通過方法名稱查找到方法ID返回。最關鍵的是IDispatch::Invoke方法的實現,怎么實現可變參數調用。

  1. 根據Invoke方法的參數與對應的保存的結構體信息對參數個數,參數類型,返回值類型做安全校驗。
  2. 因為保存的函數地址指針,沒法確定函數原型(和MFC的DISPATCH_MAP一樣,參數個數、類型和返回值類型都是不定的),只好想用匯編的call指令來直接調用,但參數入棧又是一個難題。
  3. 后來想了一個辦法,因為VC++里面標準__thiscall調用約定,會按順序把參數壓入棧,把this指針寫入ECX寄存器,所以我先根據參數類型把所有參數序列化到一個buffer里,得到所有參數總長度size,然后在棧上分配長度為size的空間,把buffer直接copy到分配好的棧里。然后直接用call指令調用函數,這其中還有要注意的一些東西,一是原寄存器的保存,及調用后的還原。二是不要修改EBP,不然在后面的匯編指令里不能直接使用原來的局部變量了,因為臨時變量和參數實際都是通過EBP這個棧幀來快速訪問(訪問參數用EBP+XX、訪問局部變量用EBP-XX)。三是保持棧平衡,寄存器入棧、出棧,分配的棧空間釋放等。
  4. 返回值的獲取,32位返回值會保存在EAX里,64位返回值分別在EDX和EAX保存高低32位,我的做法是直接用一個64位變量取出EDX和EAX值,然后根據函數實際的返回值類型取對應的8/32/64位,因為在匯編里做這些判斷是很麻煩的,而這個取EDX和EAX的值對程序又不會有影響。

下面是關鍵代碼:

_asm{
        push ecx;
        mov ecx, pthis;  //把this指針壓入ECX
        push ebx;
        mov ebx, esp;   //保存棧幀,不要使用ebp, 會導致后面不能直接使用棧變量
        sub esp, liSize;   //移動棧指針 分配liSize大小的棧空間

        push esi;       //memcpy begin 把序列化好的參數copy到分配好的棧里
        push edi;
        push ecx;
        mov ecx, liSize
        mov esi, pStack;
        mov edi, ebx;
        sub edi, liSize
        rep movsb;
        pop ecx;
        pop edi;
        pop esi;        //memcpy end

        call fn;       //調用函數
        mov esp, ebx;
        pop ebx;
        
        mov dword ptr[result], eax; //取返回值 如果沒返回值 這個也不會有影響
        lea eax, [result];
        add eax, 4;
        mov dword ptr[eax], edx;   //假定都返回64位返回值 這里取高32位
    }

后來才知道,微軟有一個API實現了這個功能。

HRESULT DispInvoke(
  void *_this,
  ITypeInfo *ptinfo,
  DISPID dispidMember,
  WORD wFlags,
  DISPPARAMS *pparams,
  VARIANT *pvarResult,
  EXCEPINFO *pexcepinfo,
  UINT *puArgErr
);
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 原文地址:C語言函數調用棧(一)C語言函數調用棧(二) 0 引言 程序的執行過程可看作連續的函數調用。當一個函數執...
    小豬啊嗚閱讀 4,673評論 1 19
  • Return-Oriented-Programming(ROP FTW) Author: Saif El-Sher...
    RealSys閱讀 3,387評論 0 2
  • 1.地址總線,數據總線,控制總線在哪里,它們有什么作用?答:它們都是cpu連接外部組件的線路。地址總線:地址總線A...
    MagicalGuy閱讀 1,497評論 0 1
  • 人生不如意十有八九,沒有人的人生是完美無瑕的,沒有缺憾的人生會是平淡乏味的。《孔雀》講述了一個家庭中三姐弟不同的...
    瘋子一樣的神經病閱讀 273評論 0 0
  • 曾經為民營企業提供咨詢培訓,逐漸對民企管理有了一定的了解。 過去幾年,有案例外企高管跳槽民企后,容易水土不服,熬不...
    怡躍閱讀 358評論 2 3