VB6 ImplementsAuthor: David Zimmer Date: 12.03.22 - 5:48am So how does VB6 handle the Implements keyword? The VTable and PrivObjs both take on changes first off. 'cPrintSample.cls 'Implements IVBPrint 'Private Property Let IVBPrint_Column(ByVal RHS As Long) 'Private Property Get IVBPrint_Column() As Long 'Private Sub IVBPrint_WriteText(ByVal strText As String) 'Private Sub mytest(x As String) '$ ==> >7013306E MSVBVM60.BASIC_CLASS_QueryInterface '$+4 >70132F45 MSVBVM60.Zombie_AddRef '$+8 >70132D18 MSVBVM60.Zombie_Release '$+C >701E2FE1 MSVBVM60.BASIC_DISPINTERFACE_GetTICount '$+10 >70173ADC MSVBVM60.BASIC_DISPINTERFACE_GetTypeInfo '$+14 >7013F26C MSVBVM60.BASIC_CLASS_GetIDsOfNames '$+18 >7013F141 MSVBVM60.BASIC_CLASS_Invoke '$+1C >00000000 '$+20 >00000000 '$+24 >00000000 '$+28 >00401614 Project1.00401614 '$+2C >00401621 Project1.00401621 '$+30 >0040162E Project1.0040162E '$+34 >004030D0 Project1.004030D0 VTable Dump: (Beta) [0] IUnknown.QueryInterface [4] IUnknown.AddRef [8] IUnknown.Release [C] IDispatch.GetTypeInfoCount [10] IDispatch.GetTypeInfo [14] IDispatch.GetIDsOfNamese [18] IDispatch.Invoke [Get/Let/Set Null Entries] Implements IVBPrint{000204F0-0000-0000-C000-000000000046} [28] - MemID:68030000 - Public Property Let IVBPrint_Column(ByVal RHS As Long) [2c] - MemID:68030000 - Public Property Get IVBPrint_Column() As Long [30] - MemID:60030002 - Public Sub IVBPrint_WriteText(ByVal strText As String) [34] - cPrintSample.proc_4030D0 Structure dump of Public VarTypes: VA Off Name = Value 402464 000 lpName = 402674 -> Implements IVBPrint {000204F0-0000-0000-C000-000000000046} 402468 004 nul1 = 0 40246C 008 nul2 = FFFFFFFF 402470 00C index = FFFF 402472 00E unk1 = FF 402473 00F unk2 = FF 402474 010 unk3 = 2 402476 012 vOff = FFFF [Get/Let/Set Null Entries] 402478 014 dataOffset = FFFFFFFF So a fake public var with no vtable offsets was added (although it does inject 3 null entries in the actual vtable) and all of the private methods were converted to public and had type info added to teh PrivObj IDispatch type info. I still need to see if the GUID was somehow added to the QueryInterface lookup list. They must have shoe horned this in as a special case to have created the fake public variable with the type information. If you add another implements it will add another block of nulls in where other public prop get/let/set would usually be. VTable Layout is:
So actually the vtable layout rules get complicated with implements involved. The interface functions are laid out according to the private object rules. IE sequential order in the source. If you interleave a regular private function in between, it will retain that vtable slot and the interface functions are not sequential. So even though they are listed in the type info as pub functions..they are not moved to the front of the vtable like actual public functions are. Additionally if you Public I as long Implements IVBPrint Private Sub mytest(x As String) Private Property Let IVBPrint_Column(ByVal RHS As Long) Private Property Get IVBPrint_Column() As Long Private Sub IVBPrint_WriteText(ByVal strText As String)Then the vtable will be in the same order as defined. $+18 >7013F141 MSVBVM60.BASIC_CLASS_Invoke $+1C >00401728 Project1.0401728 ;get i as long $+20 >00401737 Project1.00401737 ;let i as long $+24 >00000000 $+28 >00000000 $+2C >00000000 $+30 >0040174E Project1.0040174E ;JMP Project1.cPrintSample::mytest $+34 >0040175B Project1.0040175B $+38 >00401768 Project1.00401768 $+3C >00401775 Project1.00401775And a final example of the reshuffling: Source order: Public i As Long Implements IVBPrint Private Property Let IVBPrint_Column(ByVal RHS As Long) Public Function myPubFunc(x As Long) Private Sub mytest(x As String) Private Property Get IVBPrint_Column() As Long Private Sub IVBPrint_WriteText(ByVal strText As String) Actual VTable: $ ==> >7013306E MSVBVM60.BASIC_CLASS_QueryInterface $+4 >70132F45 MSVBVM60.Zombie_AddRef $+8 >70132D18 MSVBVM60.Zombie_Release $+C >701E2FE1 MSVBVM60.BASIC_DISPINTERFACE_GetTICount $+10 >70173ADC MSVBVM60.BASIC_DISPINTERFACE_GetTypeInfo $+14 >7013F26C MSVBVM60.BASIC_CLASS_GetIDsOfNames $+18 >7013F141 MSVBVM60.BASIC_CLASS_Invoke $+1C >00401740 Project1.00401740 ; get i $+20 >0040174F Project1.0040174F ; let i $+24 >00000000 ; 3 null for Implements "pubVar" $+28 >00000000 $+2C >00000000 $+30 >00401773 Project1.00401773 JMP cPrintSample::myPubFunc $+34 >00401766 Project1.00401766 JMP cPrintSample::IVBPrint_Column__Let $+38 >00401780 Project1.00401780 JMP cPrintSample::mytest $+3C >0040178D Project1.0040178D JMP cPrintSample::IVBPrint_Column__Get $+40 >0040179A Project1.0040179A JMP cPrintSample::IVBPrint_WriteTextIf we only cared about the vtable offsets for public members its fine since they are given to us. But I kinda want to be able to accurately predict the full vtable including the entries for the private members. Also note that the pubFunc entries, IVBPrint_Column will appear before myPubFunc. Which screws up the display anyway. VTable Dump: (Beta) [0] IUnknown.QueryInterface [4] IUnknown.AddRef [8] IUnknown.Release [C] IDispatch.GetTypeInfoCount [10] IDispatch.GetTypeInfo [14] IDispatch.GetIDsOfNamese [18] IDispatch.Invoke [Get 1C] Public i As Long [+34] [Let 20] Public i As Long [+34] [Get/Let/Set Null Entries] Implements IVBPrint{000204F0-0000-0000-C000-000000000046} [+FFFFFFFF] [34] - MemID:68030000 - Public Property Let IVBPrint_Column(ByVal RHS As Long) [30] - MemID:60030001 - Public Function myPubFunc(x As Long) As Variant -- out of order [3C] - MemID:68030000 - Public Property Get IVBPrint_Column() As Long [40] - MemID:60030003 - Public Sub IVBPrint_WriteText(ByVal strText As String) [40] - cPrintSample.proc_402E20 -- wrong should be 38And Private Sub mytest is showing up in the wrong slot in my calculated dump. (mixing known offsets with calculated offsets..beta feature indeed... This is painful.. I will update this post as I learn more about how the QueryInterface lookup on it was modified... Damn it, so one more interesting thing. So if you implement an interface, you can access that interface directly and are handed a small mini interface of just that and IUnknown. Dim p As IVBPrint Set c = New cPrintSample Set p = c debug.print Hex(ObjPtr(c)) 59B210 debug.print Hex(ObjPtr(p)) 59B250 $59B210 >00404424 OFFSET Project1.404424 = ObjPtr(c) main class $+4 >00000000 $+8 >0059B22C $+C >02AE2E64 $+10 >02AE2E4C $+14 >00000000 $+18 >00000000 $+1C >7014AE80 MSVBVM60.7014AE80 $+20 >00000004 $+24 >00000000 $+28 >00000000 $+2C >0000100F $+30 >00000000 $+34 >00000000 $+38 >0040172C Project1.0040172C $+3C >00000000 $+40 >00401764 Project1.00401764 (ObjPtr(p) = va:59B250) <-- IVBPrint interface 00404424 >7013306E MSVBVM60.BASIC_CLASS_QueryInterface ... 0040445C 004017AF Project1.004017AF JMP Project1.cPrintSample::IVBPrint_Column__Let 00404464 004017D6 Project1.004017D6 JMP Project1.cPrintSample::IVBPrint_Column__Get 00404468 004017E3 Project1.004017E3 JMP Project1.cPrintSample::IVBPrint_WriteText 00401764 004012CC JMP to MSVBVM60.EVENT_SINK_QueryInterface 00401768 004012DE JMP.&MSVBVM60.EVENT_SINK2_AddRef 0040176C 004012E4 JMP.&MSVBVM60.EVENT_SINK2_Release 00401770 004017DB Project1.004017DB 00401774 004017A7 Project1.004017A7 00401778 004017CE Project1.004017CE ;org esp+4 was 59B250 (this for IVbPrint) final is 59B211 why +1 from parent this? 004017DB 816C24 04 3F0000>SUB DWORD PTR SS:[ESP+4],3F 004017E3 E9 58190000 JMP Project1.cPrintSample::IVBPrint_WriteText 004017A7 816C24 04 3F0000>SUB DWORD PTR SS:[ESP+4],3F 004017AF E9 7C160000 JMP Project1.cPrintSample::IVBPrint_Column__Let 004017CE 816C24 04 3F0000>SUB DWORD PTR SS:[ESP+4],3F 004017D6 E9 55180000 JMP Project1.cPrintSample::IVBPrint_Column__Get Comments: (0) |
About Me More Blogs Main Site
|
||||||||||||||||||||||||||