VB6拾遗:IUnknown接口与COM对象

标签: , , , , , ,

VB6是建立在COM之上的,所有的COM对象都必须实现IUnknown接口。

IUnknown接口的IDL定义如下:


interface IUnknown
{
    HRESULT QueryInterface(
        [in] REFIID riid,
        [out, iid_is(riid)] void **ppvObject);
    ULONG AddRef();
    ULONG Release();
}

QueryInterface用于接口查询,AddRef和Release用于引用计数。

COM是很复杂的东西,不是一两句话能够说得清楚的,感兴趣的话可以看看《COM原理与应用》、《COM技术内幕》、《COM本质论》等书籍。

VB6将复杂的COM都隐藏起来了,使得COM对象使用起来非常的简单:


Sub Main()
    Dim o1 As Collection
    Dim o2 As Object
    Dim o3 As Control
    
    Set o1 = New Collection
    Set o2 = o1
    Set o3 = o1
End Sub

生成的汇编代码如下:


00401891  push    ___vba@095E3C24      ; /Arg1 = Project1.___vba@095E3C24
00401896  call    ___vbaNew            ; \MSVBVM60.__vbaNew
0040189B  push    eax                  ; /Arg2
0040189C  lea     eax, [ebp-14]        ; |
0040189F  push    eax                  ; |Arg1 => offset LOCAL.5
004018A0  call    ___vbaObjSet         ; \MSVBVM60.__vbaObjSet
004018A5  push    dword ptr [ebp-14]   ; /Arg2 => [LOCAL.5]
004018A8  lea     eax, [ebp-18]        ; |
004018AB  push    eax                  ; |Arg1 => offset LOCAL.6
004018AC  call    ___vbaObjSetAddref   ; \MSVBVM60.__vbaObjSetAddref
004018B1  push    ___vba@095E3C38      ; /Arg2 = Project1.___vba@095E3C38
004018B6  push    dword ptr [ebp-14]   ; |Arg1 => [LOCAL.5]
004018B9  call    ___vbaCastObj        ; \MSVBVM60.__vbaCastObj
004018BE  push    eax                  ; /Arg2
004018BF  lea     eax, [ebp-1C]        ; |
004018C2  push    eax                  ; |Arg1 => offset LOCAL.7
004018C3  call    ___vbaObjSet         ; \MSVBVM60.__vbaObjSet
004018C8  push    004018E6
004018CD  lea     ecx, [ebp-14]
004018D0  call    @__vbaFreeObj        ; [MSVBVM60.__vbaFreeObj
004018D5  lea     ecx, [ebp-18]
004018D8  call    @__vbaFreeObj        ; [MSVBVM60.__vbaFreeObj
004018DD  lea     ecx, [ebp-1C]
004018E0  call    @__vbaFreeObj        ; [MSVBVM60.__vbaFreeObj

__vbaNew函数用于创建对象,__vbaObjSet用于将对象变量指向内存中的对象。

当用一个对象变量给另一个对象变量赋值时,如果两边变量的类型相同,Set赋值时使用__vbaObjSetAddref函数,使其指向同一个对象,并调用该对象的AddRef函数增加引用计数;如果变量的类型不同,Set赋值前调用__vbaCastObj函数,__vbaCastObj内部调用对象的QueryInterface查询对象是否实现了相应的接口,实现了的话则用__vbaObjSet赋值,否则抛出异常“类型不匹配”。

当变量超出作用范围时需要调用__vbaFreeObj函数,与函数的名称不符,该函数并不一定会释放对象所占用的内存,而只是调用对象的Release函数减少引用计数,只有当对象的引用计数为0时对象所占的内存才会被释放。

随机文章:

  1. 配置OpenWrt防止3DS自动升级
  2. 用VBS获取图片分辨率
  3. AscW函数返回负数的问题
  4. BAT批处理编辑器BatEdit
  5. 价值50大洋的VBS脚本

一条评论 发表在“VB6拾遗:IUnknown接口与COM对象”上

  1. 野牛说道:

    Hi,Demon,反汇编的注释好详细,可否请教使用的工具信息。万分感谢。

留下回复