FunctionDelegator.bas
上传用户:davilee3
上传日期:2015-04-22
资源大小:986k
文件大小:7k
源码类别:

浏览器

开发平台:

Visual Basic

  1. Attribute VB_Name = "modFunctionDelegator"
  2. '***************************************************************
  3. ' (c) Copyright 2000 Matthew J. Curland
  4. '
  5. ' This file is from the CD-ROM accompanying the book:
  6. ' Advanced Visual Basic 6: Power Techniques for Everyday Programs
  7. '   Author: Matthew Curland
  8. '   Published by: Addison-Wesley, July 2000
  9. '   ISBN: 0-201-70712-8
  10. '   http://www.PowerVB.com
  11. '
  12. ' You are entitled to license free distribution of any application
  13. '   that uses this file if you own a copy of the book, or if you
  14. '   have obtained the file from a source approved by the author. You
  15. '   may redistribute this file only with express written permission
  16. '   of the author.
  17. '
  18. ' This file depends on:
  19. '   References:
  20. '     VBoostTypes6.olb (VBoost Object Types (6.0))
  21. '   Files:
  22. '     None
  23. '   Minimal VBoost conditionals:
  24. '     None
  25. '   Conditional Compilation Values:
  26. '     FUNCTIONDELEGATOR_NOSTACK = 1 'eliminates support for NewDelegator
  27. '     FUNCTIONDELEGATOR_NOHEAP = 1  'eliminates support for InitDelegator
  28. '
  29. ' This file is discussed in Chapter 11.
  30. '***************************************************************
  31. Option Explicit
  32. 'Here's the magic asm for doing the function pointer call.
  33. 'The stack comes in with the following:
  34. 'esp: return address
  35. 'esp + 4: this pointer for FunctionDelegator
  36. 'All that we need to do is remove the this pointer from the
  37. 'stack, replace it with the return address, then jmp to the
  38. 'correct function.  In other words, we're just squeezing the
  39. 'this pointer completely out of the picture.
  40. 'The code is:
  41. 'pop ecx (stores return address)
  42. 'pop eax (gets the this pointer)
  43. 'push ecx (restores the return address)
  44. 'jmp DWORD PTR [eax + 4] (jump to address at this + 4, 3 byte instruction)
  45. 'The corresponding byte stream for this is: 59 58 51 FF 60 04
  46. 'We pad these six bytes with two int 3 commands (CC CC) to get eight
  47. 'bytes, which can be stored in a Currency constant.
  48. 'Note that the memory location of this constant is not executable, so
  49. 'it must be copied into a currency variable.  The address of the variable
  50. 'is then used as the forwarding function.
  51. #Const STACKALLOCSUPPORT = FUNCTIONDELEGATOR_NOSTACK = 0
  52. #Const HEAPALLOCSUPPORT = FUNCTIONDELEGATOR_NOHEAP = 0
  53. Private Const cDelegateASM As Currency = -368956918007638.6215@
  54. Private m_DelegateASM As Currency
  55. Private Type DelegatorVTables
  56.     VTable(7) As Long 'OKQI vtable in 0 to 3, FailQI vtable in 4 to 7
  57. End Type
  58. #If STACKALLOCSUPPORT Then
  59. 'Structure for a stack allocated Delegator
  60. Private m_VTables As DelegatorVTables
  61. Private m_pVTableOKQI As Long       'Pointer to vtable, no allocation version
  62. Private m_pVTableFailQI As Long     'Pointer to vtable, no allocation version
  63. Public Type FunctionDelegator
  64.     pVTable As Long  'This has to stay at offset 0
  65.     pfn As Long      'This has to stay at offset 4
  66. End Type
  67. #End If 'STACKALLOCSUPPORT
  68. #If HEAPALLOCSUPPORT Then
  69. 'Structure for a heap allocated Delegator
  70. Private m_VTablesHeapAlloc As DelegatorVTables
  71. Private m_pVTableHeapAllocOKQI As Long   'Pointer to vtable, heap version
  72. Private m_pVTableHeapAllocFailQI As Long 'Pointer to vtable, heap version
  73. Private Type FunctionDelegatorHeapAlloc
  74.     pVTable As Long  'This has to stay at offset 0
  75.     pfn As Long      'This has to stay at offset 4
  76.     cRefs As Long
  77. End Type
  78. #End If 'HEAPALLOCSUPPORT
  79. #If STACKALLOCSUPPORT Then
  80. 'Functions to initialize a Delegator object on an existing FunctionDelegator
  81. Public Function InitDelegator(Delegator As FunctionDelegator, Optional ByVal pfn As Long) As IUnknown
  82.     If m_pVTableOKQI = 0 Then InitVTables
  83.     With Delegator
  84.         .pVTable = m_pVTableOKQI
  85.         .pfn = pfn
  86.     End With
  87.     CopyMemory InitDelegator, VarPtr(Delegator), 4
  88. End Function
  89. Private Sub InitVTables()
  90. Dim pAddRefRelease As Long
  91.     With m_VTables
  92.         .VTable(0) = FuncAddr(AddressOf QueryInterfaceOK)
  93.         .VTable(4) = FuncAddr(AddressOf QueryInterfaceFail)
  94.         pAddRefRelease = FuncAddr(AddressOf AddRefRelease)
  95.         .VTable(1) = pAddRefRelease
  96.         .VTable(5) = pAddRefRelease
  97.         .VTable(2) = pAddRefRelease
  98.         .VTable(6) = pAddRefRelease
  99.         m_DelegateASM = cDelegateASM
  100.         .VTable(3) = VarPtr(m_DelegateASM)
  101.         .VTable(7) = .VTable(3)
  102.         m_pVTableOKQI = VarPtr(.VTable(0))
  103.         m_pVTableFailQI = VarPtr(.VTable(4))
  104.     End With
  105. End Sub
  106. Private Function QueryInterfaceOK(This As FunctionDelegator, riid As Long, pvObj As Long) As Long
  107.     pvObj = VarPtr(This)
  108.     This.pVTable = m_pVTableFailQI
  109. End Function
  110. Private Function AddRefRelease(ByVal This As Long) As Long
  111.     'Nothing to do, memory not refcounted
  112. End Function
  113. #End If 'STACKALLOCSUPPORT
  114. #If HEAPALLOCSUPPORT Then
  115. 'Functions to create a refcounted version of the function pointer wrapper object
  116. Public Function NewDelegator(ByVal pfn As Long) As IUnknown
  117. Dim Struct As FunctionDelegatorHeapAlloc
  118. Dim ThisPtr As Long
  119.     If m_pVTableHeapAllocOKQI = 0 Then InitHeapAllocVTables
  120.     With Struct
  121.         ThisPtr = CoTaskMemAlloc(LenB(Struct))
  122.         If ThisPtr = 0 Then Err.Raise 7
  123.         .pVTable = m_pVTableHeapAllocOKQI
  124.         .cRefs = 1
  125.         .pfn = pfn
  126.         CopyMemory ByVal ThisPtr, Struct, LenB(Struct)
  127.         CopyMemory NewDelegator, ThisPtr, 4
  128.     End With
  129. End Function
  130. Private Sub InitHeapAllocVTables()
  131.     With m_VTablesHeapAlloc
  132.         .VTable(0) = FuncAddr(AddressOf QueryInterfaceHeapAllocOK)
  133.         .VTable(4) = FuncAddr(AddressOf QueryInterfaceFail)
  134.         .VTable(1) = FuncAddr(AddressOf AddRefHeapAlloc)
  135.         .VTable(5) = .VTable(1)
  136.         .VTable(2) = FuncAddr(AddressOf ReleaseHeapAlloc)
  137.         .VTable(6) = .VTable(2)
  138.         m_DelegateASM = cDelegateASM
  139.         .VTable(3) = VarPtr(m_DelegateASM)
  140.         .VTable(7) = .VTable(3)
  141.         m_pVTableHeapAllocOKQI = VarPtr(.VTable(0))
  142.         m_pVTableHeapAllocFailQI = VarPtr(.VTable(4))
  143.     End With
  144. End Sub
  145. Private Function QueryInterfaceHeapAllocOK(This As FunctionDelegatorHeapAlloc, riid As Long, pvObj As Long) As Long
  146.     With This
  147.         pvObj = VarPtr(.pVTable)
  148.         .cRefs = .cRefs + 1
  149.         .pVTable = m_pVTableHeapAllocFailQI
  150.     End With
  151. End Function
  152. Private Function AddRefHeapAlloc(This As FunctionDelegatorHeapAlloc) As Long
  153.     With This
  154.         .cRefs = .cRefs + 1
  155.         AddRefHeapAlloc = .cRefs
  156.     End With
  157. End Function
  158. Private Function ReleaseHeapAlloc(This As FunctionDelegatorHeapAlloc) As Long
  159.     With This
  160.         .cRefs = .cRefs - 1
  161.         ReleaseHeapAlloc = .cRefs
  162.         If .cRefs = 0 Then
  163.             'Don't try to step over FreeBuffer, we're freeing
  164.             'This, and the debugger could die.
  165.             CoTaskMemFree VarPtr(.pVTable)
  166.         End If
  167.     End With
  168. End Function
  169. #End If 'HEAPALLOCSUPPORT
  170. Private Function QueryInterfaceFail(ByVal This As Long, riid As Long, pvObj As Long) As Long
  171.     pvObj = 0
  172.     QueryInterfaceFail = E_NOINTERFACE
  173. End Function
  174. Private Function FuncAddr(ByVal pfn As Long) As Long
  175.     FuncAddr = pfn
  176. End Function