home *** CD-ROM | disk | FTP | other *** search
/ Planet Source Code Jumbo …e CD Visual Basic 1 to 7 / 5_2007-2008.ISO / data / Zips / Universal_2106383172008.psc / Classes / cCallFunc2.cls
Text File  |  2008-03-12  |  38KB  |  466 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "cCallFunc2"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = True
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14.  
  15. '**********************************************************************************
  16. '** cCallFunc2.cls - cCallFunc with added fastcall support, call by address and
  17. '**                  additional return types
  18. '**
  19. '** Universal dll function/sub calling class
  20. '**   cdecl/stdcall/fastcall calling convention
  21. '**   Call by ordinal, name or address
  22. '**   Module (.bas) callbacks for cdecl.
  23. '**   Object (.cls/.frm/.ctl) callbacks for cdecl/stdcall
  24. '**   Support for multiple callbacks.
  25. '**   Support for multiple cCallFunc2 instances
  26. '**   Support unicode path\module names
  27. '**
  28. '** If you wish to do crazy stuff like CallFunc with callbacks inside a callback
  29. '** then the best solution is to make a copy of the class, eg cCallFunc1.cls, and
  30. '** use an instance of that where needed.
  31. '**
  32. '** Calling conventions:
  33. '**   stdcall:  parameters right to left, called routine adjusts the stack
  34. '**   cdecl:    parameters right to left, caller adjusts the stack
  35. '**   fastcall: first parameter, if present, in the ecx register
  36. '**               second parameter, if present, in the edx register
  37. '**               any other parameters are pushed to the stack
  38. '**               called routine adjusts the stack
  39. '**               N.B. fastcall isn't standardised, differing conventions exist.
  40. '**               This class supports the Microsoft/GCC implementation.
  41. '**
  42. '** paul_caton@hotmail.com
  43. '**
  44. '** 20031029 First cut....................................................... v1.00
  45. '** 20071129 Now using virtual memory to fix a DEP issue..................... v1.01
  46. '** 20071130 Hacked from cCDECL, now supports stdcall and ordinals........... v1.02
  47. '** 20071201 Added support for callback objects.............................. v1.03
  48. '** 20071202 Unicode support for paths\modules where available............... v1.04
  49. '** 20071213 Forked from cCallFunc.cls
  50. '**          Added support for fastcall calling convention
  51. '**          Added CallPointer
  52. '**          Changed the interface to be more property like.................. v1.05
  53. '** 20080212 Support Byte, Integer, Long, Single and Double return types..... v1.06
  54. '** 20080311 Added IsValidDll and IsValidMethod
  55. '**          Parameter block made global
  56. '**          Eliminated MAX_ARG, VB has a limit of 60 parameters
  57. '**          Various optimizations........................................... v1.07
  58. '**********************************************************************************
  59.  
  60. Option Explicit
  61.  
  62. 'API declarations
  63. Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
  64. Private Declare Function GetDesktopWindow Lib "user32" () As Long
  65. Private Declare Function GetLastError Lib "kernel32" () As Long
  66. Private Declare Function GetProcByName Lib "kernel32" Alias "GetProcAddress" (ByVal hModule As Long, ByVal lpProcName As String) As Long
  67. Private Declare Function GetProcByOrdinal Lib "kernel32" Alias "GetProcAddress" (ByVal hModule As Long, ByVal nOrdinal As Long) As Long
  68. Private Declare Function IsBadCodePtr Lib "kernel32" (ByVal lpfn As Long) As Long
  69. Private Declare Function IsWindowUnicode Lib "user32" (ByVal hWnd As Long) As Long
  70. Private Declare Function LoadLibraryA Lib "kernel32" (ByVal lpLibFileName As String) As Long
  71. Private Declare Function LoadLibraryW Lib "kernel32" (ByVal lpLibFileName As Long) As Long
  72. Private Declare Function VirtualAlloc Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As Long
  73. Private Declare Function VirtualFree Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal dwFreeType As Long) As Long
  74.  
  75. Private Declare Sub GetMem1 Lib "msvbvm60" (ByVal Addr As Long, RetVal As Byte)
  76. Private Declare Sub GetMem4 Lib "msvbvm60" (ByVal Addr As Long, RetVal As Long)
  77. Private Declare Sub PutMem1 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Byte)
  78. Private Declare Sub PutMem2 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Integer)
  79. Private Declare Sub PutMem4 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Long)
  80. Private Declare Sub PutMem8 Lib "msvbvm60" (ByVal Addr As Long, ByVal NewVal As Currency)
  81. Private Declare Sub SetLastError Lib "kernel32" (ByVal dwErrCode As Long)
  82.  
  83. Public Enum eObjType                                                          'Object type for CallbackObj... also incorporates vTable offsets
  84.   objCls = &H1C                                                               'Class object callback
  85.   objFrm = &H6F8                                                              'Form object callback
  86.   objCtl = &H7A4                                                              'UserControl object callback
  87. End Enum                                                                      '
  88.                                                                               '
  89. Public Enum eReturnType                                                       'CallFunc/CallPointer return types... also incorporates return type jump values
  90.   retByte = &H0                                                               'Return Byte
  91.   retInteger = &H4                                                            'Return Integer
  92.   retLong = &H9                                                               'Return Long
  93.   retInt64 = &HD                                                              'Return 64 bit value eg. Currency
  94.   retSingle = &H14                                                            'Return Single
  95.   retDouble = &H18                                                            'Return Double
  96.   retSub = &H1A                                                               'No return value
  97. End Enum                                                                      '
  98.                                                                               '
  99. Private Const SRC           As String = "cCallFunc2."                         'Error source
  100.                                                                               '
  101. Private Type tParamBlock                                                      'Parameter block type
  102.   ParamCount                As Long                                           'Number of parameters
  103.   Params(0 To 59)           As Long                                           'Array of parameters
  104. End Type                                                                      '
  105.                                                                               '
  106. Private m_FastCall          As Boolean                                        'FastCall private property value
  107. Private m_LastError         As Long                                           'LastError private property value
  108.                                                                               
  109. Private bUnicode            As Boolean                                        'Unicode flag                                                                              '
  110. Private vCode               As Long                                           'Pointer to the machine-code thunks
  111. Private vTable              As Long                                           'Class vTable address
  112. Private nAddrPb             As Long                                           'Address of the parameter block
  113. Private hModule             As Long                                           'Current/last-used dll handle
  114. Private strLastDLL          As String                                         'Current/last-used dll name
  115. Private strLastFunc         As String                                         'Current/last-used function/sub name
  116. Private pb                  As tParamBlock                                    'Parameter block
  117.  
  118. 'CallFunc:
  119. '
  120. ' strDLL      - Name of the DLL
  121. ' RetType     - Function return type
  122. ' strFunc     - Name of the function or it's ordinal value preceded by a '#' eg. "#2"
  123. ' ParamLongs  - Any number [or none] of parameters As Long.
  124. '                 To pass the address (ByRef) of a string use StrPtr, eg. StrPtr(strPath)
  125. '                 To pass the address (ByRef) of a variable or UDT use VarPtr, eg. VarPtr(i)
  126. Public Function CallFunc(ByRef strDll As String, _
  127.                          ByVal RetType As eReturnType, _
  128.                          ByRef strFunc As String, _
  129.                     ParamArray ParamLongs() As Variant) As Variant            '
  130.   Dim bNewDll As Boolean                                                      'New dll flag
  131.                                                                               '
  132.   If StrComp(strDll, strLastDLL, vbTextCompare) <> 0 Then                     'If the module is new
  133.     Dim hMod As Long                                                          '
  134.                                                                               '
  135.     If bUnicode Then                                                          'If unicode
  136.       hMod = LoadLibraryW(StrPtr(strDll & vbNullChar))                        'Load the module with the unicode version of LoadLibrary
  137.     Else                                                                      '
  138.       hMod = LoadLibraryA(strDll)                                             'Load the module with the ascii version of LoadLibrary
  139.     End If                                                                    '
  140.                                                                               '
  141.     If hMod = 0 Then                                                          'If the load failed
  142.       Debug.Assert False                                                      'Halt if running under the VB IDE
  143.       Err.Raise vbObjectError + 0, SRC & "CallFunc", "DLL failed load"        'Raise an error if running compiled
  144.     End If                                                                    '
  145.                                                                               '
  146.     If hModule <> 0 Then                                                      'If a module is already loaded
  147.       FreeLibrary hModule                                                     'Free the last module
  148.     End If                                                                    '
  149.                                                                               '
  150.     hModule = hMod                                                            'Save the module handle
  151.     strLastDLL = strDll                                                       'Save the new module name
  152.     bNewDll = True                                                            'Indicate that it's a new module
  153.   End If                                                                      '
  154.                                                                               '
  155.   If bNewDll Or StrComp(strFunc, strLastFunc, vbBinaryCompare) <> 0 Then      'If the function or module is new
  156.     Dim fnAddress As Long                                                     'Function address
  157.                                                                               '
  158.     If Asc(strFunc) = 35 Then                                                 'If "#..." eg "#2", ordinal 2
  159.       fnAddress = GetProcByOrdinal(hModule, CLng(Mid$(strFunc, 2)))           'Get the address of the function by ordinal
  160.     Else                                                                      '
  161.       fnAddress = GetProcByName(hModule, strFunc)                             'Get the address of the function by name
  162.     End If                                                                    '
  163.                                                                               '
  164.     If fnAddress = 0 Then                                                     'If the function wasn't found in the module
  165.       Debug.Assert False                                                      'Halt if running under the VB IDE
  166.       Err.Raise vbObjectError + 1, SRC & "CallFunc", "Function not found"     'Raise an error if running compiled
  167.     End If                                                                    '
  168.                                                                               '
  169.     strLastFunc = strFunc                                                     'Save the function name
  170.     PutMem4 vCode + &H19, fnAddress - vCode - (&H19 + 4)                      'Patch the code with the relative address to the target function
  171.   End If                                                                      '
  172.                                                                               '
  173.   With pb                                                                     '
  174.     Dim i As Long                                                             'Parameter loop vars
  175.     Dim j As Long                                                             'Parameter loop vars
  176.                                                                               '
  177.     j = UBound(ParamLongs)                                                    'Get the upper parameter array bound
  178.     For i = 0 To j                                                            'For each parameter
  179.       .Params(i) = ParamLongs(i)                                              'Store the parameter in the parameter block
  180.     Next i                                                                    '
  181.                                                                               '
  182.     .ParamCount = i                                                           'Store the parameter count (j + 1)
  183.   End With                                                                    '
  184.                                                                               '
  185.   CallFunc = CallCommon(RetType)                                              'Call common code
  186. End Function                                                                  '
  187.  
  188. 'CallPointer: call a function by address
  189. '
  190. ' RetType     - Function return type
  191. ' fnAddress   - Address of the target function
  192. ' ParamLongs  - Any number of parameters As Long, or none.
  193. '                 To pass the address (ByRef) of a string use StrPtr, eg. StrPtr(strPath)
  194. '                 To pass the address (ByRef) of a variable or UDT use VarPtr, eg. VarPtr(i)
  195. Public Function CallPointer(ByVal RetType As eReturnType, _
  196.                             ByVal fnAddress As Long, _
  197.                        ParamArray ParamLongs() As Variant) As Variant         '
  198.   Dim i  As Long                                                              'Parameter loop vars
  199.   Dim j  As Long                                                              'Parameter loop vars
  200.                                                                               '
  201.   With pb                                                                     '
  202.     j = UBound(ParamLongs)                                                    'Get the upper parameter array bound
  203.     For i = 0 To j                                                            'For each parameter
  204.       .Params(i) = ParamLongs(i)                                              'Store the parameter in the parameter block
  205.     Next i                                                                    '
  206.                                                                               '
  207.     .ParamCount = i                                                           'Store the parameter count (j + 1)
  208.   End With                                                                    '
  209.                                                                               '
  210.   strLastFunc = vbNullString                                                  'Ensure we don't clash with CallFunc caching
  211.   PutMem4 vCode + &H19, fnAddress - vCode - (&H19 + 4)                        'Patch the code with the relative address to the target function
  212.   CallPointer = CallCommon(RetType)                                           'Call common code
  213. End Function
  214.  
  215. 'CallbackCdecl: return a wrapper address for a bas module routine to be used as a callback for a cdecl function.
  216. '               Note: stdcall functions don't need a thunk to use a bas module function as a callback, use direct.
  217. '
  218. ' nModFuncAddr - The address of the bas module callback function, use AddressOf to get this value
  219. ' nParms       - The number of parameters that will be passed to the bas module callback function
  220. ' nIndex       - Allow for multiple simultaneous callbacks
  221. Public Function CallbackCdecl(ByVal nModFuncAddr As Long, _
  222.                               ByVal nParams As Long, _
  223.                      Optional ByVal nIndex As Long = 1) As Long
  224.   
  225.   If nIndex < 1 Or nIndex > 60 Or nParams > 60 Then                           'Parameter sanity checks
  226.     Debug.Assert False                                                        'Halt if running under the VB IDE
  227.     Err.Raise vbObjectError + 2, SRC & "CallbackCdecl", "Invalid parameter"   'Raise error if running compiled
  228.   End If                                                                      '
  229.                                                                               '
  230.   CallbackCdecl = vCode + 128 + ((nIndex - 1) * 64)                           'Address of the callback wrapper. Pass this return value as the callback address parameter of the cdecl function
  231.                                                                               '
  232.   PutMem8 CallbackCdecl + 0, 465203369712025.6232@                            'Callback wrapper machine code
  233.   PutMem8 CallbackCdecl + 8, -140418483381718.8339@                           '
  234.   PutMem8 CallbackCdecl + 16, -801546908679710.9163@                          '
  235.                                                                               '
  236.   PutMem4 CallbackCdecl + 10, nModFuncAddr - CallbackCdecl - (10 + 4)         'Patch the code to call the vb bas module callback function
  237.   PutMem1 CallbackCdecl + 16, nParams * 4                                     'Patch the code to apply the necessary stack adjustment
  238. End Function                                                                  '
  239.                                                                               '
  240. 'CallbackObj: return a wrapper address for an object callback from a cdecl or stdcall function
  241. '
  242. ' objType     - Callback object type
  243. ' objCallback - The callback object
  244. ' nParams     - The number of parameters that will be passed to the object callback function
  245. ' nOrdinal    - Callback ordinal. 1 = last private function in the callback object, 2 = second last private function in the callback object, etc
  246. ' bCDECL      - Specifes whether the callback calling function is cdecl or stdcall
  247. ' nIndex      - Allow for multiple simultaneous callbacks
  248. Public Function CallbackObj(ByVal objType As eObjType, _
  249.                             ByRef objCallback As Object, _
  250.                             ByVal nParams As Long, _
  251.                    Optional ByVal nOrdinal As Long = 1, _
  252.                    Optional ByVal bCDECL As Boolean = False, _
  253.                    Optional ByVal nIndex As Long = 1) As Long
  254.   Dim o As Long                                                               'Object pointer
  255.   Dim i As Long                                                               'vTable entry counter
  256.   Dim j As Long                                                               'vTable address
  257.   Dim n As Long                                                               'Method pointer
  258.   Dim b As Byte                                                               'First method byte
  259.   Dim m As Byte                                                               'Known good first method byte
  260.                                                                               '
  261.   If nIndex < 1 Or nIndex > 60 Or nParams > 60 Then                           'Parameter sanity checks
  262.     Debug.Assert False                                                        'Halt if running under the VB IDE
  263.     Err.Raise vbObjectError + 3, SRC & "CallbackObj", "Invalid parameter"     'Raise error if running compiled
  264.   End If                                                                      '
  265.                                                                               '
  266.   o = ObjPtr(objCallback)                                                     'Get the callback object's address
  267.   GetMem4 o, j                                                                'Get the address of the callback object's vTable
  268.   j = j + objType                                                             'Increment to the the first user entry for this callback object type
  269.   GetMem4 j, n                                                                'Get the method pointer
  270.   GetMem1 n, m                                                                'Get the first method byte... &H33 if pseudo-code, &HE9 if native
  271.   j = j + 4                                                                   'Bump to the next vtable entry
  272.                                                                               '
  273.   For i = 1 To 511                                                            'Loop through a 'sane' number of vtable entries
  274.     GetMem4 j, n                                                              'Get the method pointer
  275.                                                                               '
  276.     If IsBadCodePtr(n) Then                                                   'If the method pointer is an invalid code address
  277.       GoTo vTableEnd                                                          'We've reached the end of the vTable, exit the for loop
  278.     End If                                                                    '
  279.                                                                               '
  280.     GetMem1 n, b                                                              'Get the first method byte
  281.                                                                               '
  282.     If b <> m Then                                                            'If the method byte doesn't matche the known good value
  283.       GoTo vTableEnd                                                          'We've reached the end of the vTable, exit the for loop
  284.     End If                                                                    '
  285.                                                                               '
  286.     j = j + 4                                                                 'Bump to the next vTable entry
  287.   Next i                                                                      'Bump counter
  288.   
  289.   Debug.Assert False                                                          'Halt if running under the VB IDE
  290.   Err.Raise vbObjectError + 4, SRC & "CallbackObj", "Ordinal not found"       'Raise error if running compiled
  291.                                                                               '
  292. vTableEnd:                                                                    'We've hit the end of the vTable
  293.   GetMem4 j - (nOrdinal * 4), n                                               'Get the method pointer for the specified ordinal
  294.                                                                               '
  295.   CallbackObj = vCode + 128 + ((nIndex - 1) * 64)                             'Address of the callback wrapper. Pass this return value as the callback address parameter
  296.                                                                               '
  297.   PutMem8 CallbackObj + 0, 648518346342877.6073@                              'Callback wrapper machine code
  298.   PutMem8 CallbackObj + 8, 9425443492.7235@                                   '
  299.   PutMem8 CallbackObj + 16, -29652486425477.8624@                             '
  300.   PutMem8 CallbackObj + 24, 614907631944580.0296@                             '
  301.   PutMem8 CallbackObj + 32, -444355163233240.1323@                            '
  302.   PutMem4 CallbackObj + 40, &H90900055                                        '
  303.                                                                               '
  304.   PutMem1 CallbackObj + &HD, nParams                                          'Patch the number of params
  305.   PutMem4 CallbackObj + &H19, o                                               'Patch the callback object
  306.   PutMem4 CallbackObj + &H1E, n - CallbackObj - (&H1E + 4)                    'Patch the callback call address
  307.   PutMem1 CallbackObj + &H28, IIf(bCDECL, 0, nParams * 4)                     'Patch the stack correction
  308. End Function                                                                  '
  309.                                                                               
  310. Public Property Get FastCall() As Boolean                                     'Get FastCall flag
  311.   FastCall = m_FastCall                                                       '
  312. End Property                                                                  '
  313.                                                                               '
  314. Public Property Let FastCall(ByVal bValue As Boolean)                         'Let Fastcall flag
  315.   m_FastCall = bValue                                                         '
  316.   PutMem2 vCode + &H11, IIf(m_FastCall, &H34EB, &H9090)                       'Patch the code as per FastCall status
  317. End Property                                                                  '
  318.                                                                               
  319. 'IsValidDll - return whether the passed dll [path\]name is valid
  320. '
  321. ' strDLL - [path\]name of the DLL
  322. Public Function IsValidDll(ByRef strDll As String)                            '
  323.   Dim hMod As Long                                                            '
  324.                                                                               '
  325.   If bUnicode Then                                                            'If unicode
  326.     hMod = LoadLibraryW(StrPtr(strDll & vbNullChar))                          'Load the module with the unicode version of LoadLibrary
  327.   Else                                                                        '
  328.     hMod = LoadLibraryA(strDll)                                               'Load the module with the ascii version of LoadLibrary
  329.   End If                                                                      '
  330.                                                                               '
  331.   If hMod Then                                                                'If the library loaded okay
  332.     FreeLibrary hMod                                                          'Free the library
  333.     IsValidDll = True                                                         'Indicate success
  334.   End If                                                                      '
  335. End Function                                                                  '
  336.  
  337. 'IsValidMethod - return whether the passed dll [path\]name / method name is valid
  338. '
  339. ' strDLL   - [path\]name of the DLL
  340. ' strFunc  - Name of the function or it's ordinal value preceded by a '#' eg. "#2"
  341. Public Function IsValidMethod(ByRef strDll As String, _
  342.                               ByRef strFunc As String)                        '
  343.   Dim hMod As Long                                                            '
  344.                                                                               '
  345.   If bUnicode Then                                                            'If unicode
  346.     hMod = LoadLibraryW(StrPtr(strDll & vbNullChar))                          'Load the module with the unicode version of LoadLibrary
  347.   Else                                                                        '
  348.     hMod = LoadLibraryA(strDll)                                               'Load the module with the ascii version of LoadLibrary
  349.   End If                                                                      '
  350.                                                                               '
  351.   If hMod Then                                                                'If the library loaded okay
  352.     Dim nFuncAddr As Long                                                     'Function address
  353.                                                                               '
  354.     If Asc(strFunc) = 35 Then                                                 'If "#..." eg "#2", ordinal 2
  355.       nFuncAddr = GetProcByOrdinal(hModule, CLng(Mid$(strFunc, 2)))           'Get the address of the function by ordinal
  356.     Else                                                                      '
  357.       nFuncAddr = GetProcByName(hModule, strFunc)                             'Get the address of the function by name
  358.     End If                                                                    '
  359.                                                                               '
  360.     If nFuncAddr Then                                                         'If the function was found in the module
  361.       IsValidMethod = True                                                    'Indicate success
  362.     End If                                                                    '
  363.                                                                               '
  364.     FreeLibrary hMod                                                          'Free the library
  365.   End If                                                                      '
  366. End Function                                                                  '
  367.  
  368. Public Property Get LastError() As Long                                       'Get last error
  369.   LastError = m_LastError                                                     '
  370. End Property                                                                  '
  371.                                                                               
  372. 'CallCommon: common CallFunc/CallPointer code
  373. '
  374. ' RetType - Function return type
  375. Private Function CallCommon(ByVal RetType As eReturnType) As Variant
  376.   PutMem1 vCode + &H27, RetType                                               'Patch the return type jump
  377.                                                                               '
  378.   SetLastError 0                                                              'Clear the error code
  379.                                                                               '
  380.   'N.B. we patch the vTable on each call because there could be multiple
  381.   'instances of this class. Multiple instances share the same code...
  382.   'and would otherwise share the vCode of the last created instance.
  383.   'So we re-patch the vTable on each call to ensure the entry is hooked
  384.   'to the instance's vCode
  385.   Select Case RetType                                                         'Select on return type
  386.     Case eReturnType.retByte                                                  'Return a Byte
  387.       PutMem4 vTable + (19 * 4), vCode                                        'Patch the z_CallFunc_i08 entry to point to vCode
  388.       CallCommon = z_CallFunc_i08(nAddrPb)                                    'Call
  389.                                                                               '
  390.     Case eReturnType.retInteger                                               'Return an Integer
  391.       PutMem4 vTable + (20 * 4), vCode                                        'Patch the z_CallFunc_i16 entry to point to vCode
  392.       CallCommon = z_CallFunc_i16(nAddrPb)                                    'Call
  393.                                                                               '
  394.     Case eReturnType.retLong                                                  'Return a Long
  395.       PutMem4 vTable + (21 * 4), vCode                                        'Patch the z_CallFunc_i32 entry to point to vCode
  396.       CallCommon = z_CallFunc_i32(nAddrPb)                                    'Long
  397.                                                                               '
  398.     Case eReturnType.retInt64                                                 'Return 64bits (e.g. Currency)
  399.       PutMem4 vTable + (22 * 4), vCode                                        'Patch the z_CallFunc_i64 entry to point to vCode
  400.       CallCommon = z_CallFunc_i64(nAddrPb)                                    'Call
  401.                                                                               '
  402.     Case eReturnType.retSingle                                                'Return a Single
  403.       PutMem4 vTable + (23 * 4), vCode                                        'Patch the z_CallFunc_Sng entry to point to vCode
  404.       CallCommon = z_CallFunc_Sng(nAddrPb)                                    'Call
  405.                                                                               '
  406.     Case eReturnType.retDouble                                                'Return a Double
  407.       PutMem4 vTable + (24 * 4), vCode                                        'Patch the z_CallFunc_Dbl entry to point to vCode
  408.       CallCommon = z_CallFunc_Dbl(nAddrPb)                                    'Call
  409.                                                                               '
  410.     Case eReturnType.retSub                                                   'Subroutine, no return value
  411.       PutMem4 vTable + (25 * 4), vCode                                        'Patch the z_CallFunc_Sub entry to point to vCode
  412.       Call z_CallFunc_Sub(nAddrPb)                                            'Call
  413.       
  414.     Case Else                                                                 'Undefined return type
  415.       Debug.Assert False                                                      'Halt if running under the VB IDE
  416.       Err.Raise vbObjectError + 5, SRC & "CallCommon", "Unknown return type"  'Raise error if running compiled
  417.   End Select                                                                  '
  418.                                                                               '
  419.   m_LastError = GetLastError()                                                'Get the error code
  420. End Function
  421.  
  422. 'Class_Initialize: initialize the cCallFunc2 instance
  423. Private Sub Class_Initialize()                                                '
  424.   vCode = VirtualAlloc(0, &H1000&, &H1000&, &H40&)                            'Allocate 4k of read/write/executable memory
  425.                                                                               '
  426.   PutMem8 vCode + 0, 695618785647368.6248@                                    'Universal function caller machine code
  427.   PutMem8 vCode + 8, -208726556020175.3831@                                   '
  428.   PutMem8 vCode + 16, -29652486425143.4233@                                   '
  429.   PutMem8 vCode + 24, 614902794093417.828@                                    '
  430.   PutMem8 vCode + 32, 193965741455568.6229@                                   '
  431.   PutMem8 vCode + 40, -151277692825560.6392@                                  '
  432.   PutMem8 vCode + 48, -857442152266638.7183@                                  '
  433.   PutMem8 vCode + 56, 21029022751752.3025@                                    '
  434.   PutMem8 vCode + 64, -7203916540378.4739@                                    '
  435.   PutMem8 vCode + 72, -61276775362635.1564@                                   '
  436.   PutMem8 vCode + 80, -454553025687766.4117@                                  '
  437.                                                                               '
  438.   GetMem4 ObjPtr(Me), vTable                                                  'Get the address of the class vTable
  439.                                                                               '
  440.   If GetProcByName(LoadLibraryA("user32"), "IsWindowUnicode") Then            'Is IsWindowUnicode present
  441.     bUnicode = IsWindowUnicode(GetDesktopWindow())                            'Determine whether we'll use the unicode version of LoadLibrary
  442.   End If                                                                      '
  443.                                                                               '
  444.   FastCall = False                                                            'Default to non-Fastcall
  445.   nAddrPb = VarPtr(pb)                                                        'Address of the parameter block
  446. End Sub                                                                       '
  447.                                                                               '
  448. 'Class_Terminate: cleanup the cCallFunc2 instance
  449. Private Sub Class_Terminate()                                                 '
  450.   If hModule <> 0 Then                                                        'If a module is loaded
  451.     FreeLibrary hModule                                                       'Free the loaded module
  452.   End If                                                                      '
  453.                                                                               '
  454.   VirtualFree vCode, 0, &H8000&                                               'Free the allocated memory
  455. End Sub
  456.                                                                               
  457. '*******************************************************************************************************************
  458. ' DO NOT MOVE THE FOLLOWING ROUTINES...
  459. Private Function z_CallFunc_i08(ByVal nParmAddr As Long) As Byte:     End Function
  460. Private Function z_CallFunc_i16(ByVal nParmAddr As Long) As Integer:  End Function
  461. Private Function z_CallFunc_i32(ByVal nParmAddr As Long) As Long:     End Function
  462. Private Function z_CallFunc_i64(ByVal nParmAddr As Long) As Currency: End Function
  463. Private Function z_CallFunc_Sng(ByVal nParmAddr As Long) As Single:   End Function
  464. Private Function z_CallFunc_Dbl(ByVal nParmAddr As Long) As Double:   End Function
  465.      Private Sub z_CallFunc_Sub(ByVal nParmAddr As Long):             End Sub
  466.