Results 1 to 2 of 2

Thread: call API functions by their pointers

  1. #1

    Thread Starter
    Lively Member rm_03's Avatar
    Join Date
    Aug 2004
    Posts
    92

    call API functions by their pointers

    With some ASM we can call functions by their pointers or
    even call them in new threads so our app keeps responding.
    It's actually the first time I've written the ASM code myself,
    so please don't bash me for any crashes.
    I used an upload at pscode for orientation, but I can't find it atm.

    First we need a module. Let's name it modFncPtr.
    Its functions are:
    * GetFncAddress - like GetProcAddress, just more comfortable
    * WaitForThread - wait for the end of a thread in a DoEvents loop
    * CallPointerAsync - run a function in a new thread
    * CallPointer - just run a function

    VB Code:
    1. Option Explicit
    2.  
    3. Private Declare Function GetExitCodeThread Lib "kernel32" ( _
    4.             ByVal hThread As Long, _
    5.             lpExitCode As Long) As Long
    6.  
    7. Private Declare Function CreateThread Lib "kernel32" ( _
    8.             lpThreadAttributes As Long, _
    9.             ByVal dwStackSize As Long, _
    10.             ByVal lpStartAddress As Long, _
    11.             lpParameter As Any, _
    12.             ByVal dwCreationFlags As Long, _
    13.             lpThreadId As Long) As Long
    14.  
    15. Private Declare Function CallWindowProcA Lib "user32" ( _
    16.             ByVal adr As Long, _
    17.             ByVal p1 As Long, _
    18.             ByVal p2 As Long, _
    19.             ByVal p3 As Long, _
    20.             ByVal p4 As Long) As Long
    21.  
    22. Private Declare Function LoadLibraryA Lib "kernel32" ( _
    23.             ByVal szLib As String) As Long
    24.  
    25. Private Declare Function GetProcAddress Lib "kernel32" ( _
    26.             ByVal hModule As Long, _
    27.             ByVal szFnc As String) As Long
    28.  
    29. Private Declare Function GetModuleHandleA Lib "kernel32" ( _
    30.             ByVal szModule As String) As Long
    31.  
    32. Private Declare Sub RtlFillMemory Lib "kernel32" ( _
    33.             pDst As Any, _
    34.             ByVal dlen As Long, _
    35.             ByVal Fill As Byte)
    36.  
    37. Private Declare Sub RtlMoveMemory Lib "kernel32" ( _
    38.             pDst As Any, _
    39.             pSrc As Any, _
    40.             ByVal dlen As Long)
    41.  
    42. Private Const STILL_ACTIVE  As Long = 259&
    43. Private Const MAXCODE       As Long = &HEC00&
    44.  
    45. Public Type ASYNCCALL
    46.     hThread                 As Long
    47.     ret                     As Long
    48.     asm(MAXCODE - 1)        As Byte
    49. End Type
    50.  
    51. Private lngAsyncRet         As Long
    52.  
    53. ' like GetProcAddress, but with a more comfortable first parameter
    54. Public Function GetFncAddress(ByVal library As String, ByVal sFunction As String) As Long
    55.     Dim hModule As Long
    56.     Dim pFunc   As Long
    57.  
    58.     ' check if module already loaded
    59.     hModule = GetModuleHandleA(library)
    60.     If hModule = 0 Then
    61.         ' module not loaded, try to load it
    62.         hModule = LoadLibraryA(library)
    63.         If hModule = 0 Then
    64.             Err.Raise 999, , "library missing!"
    65.             Exit Function
    66.         End If
    67.     End If
    68.  
    69.     ' get entry point of function
    70.     pFunc = GetProcAddress(hModule, sFunction)
    71.     If pFunc = 0 Then
    72.         Err.Raise 998, , "not a exported function!"
    73.         Exit Function
    74.     End If
    75.  
    76.     GetFncAddress = pFunc
    77. End Function
    78.  
    79. ' wait for end of thread
    80. Public Sub WaitForThread(hThread As Long)
    81.     Dim dwExitCode  As Long
    82.  
    83.     Do
    84.         GetExitCodeThread hThread, dwExitCode
    85.         If dwExitCode <> STILL_ACTIVE Then Exit Do
    86.         DoEvents
    87.     Loop
    88. End Sub
    89.  
    90. ' run a function in a new thread
    91. Public Sub CallPointerAsync(ByVal fnc As Long, udtAsync As ASYNCCALL, ParamArray params())
    92.     Dim pASM            As Long
    93.     Dim TID             As Long
    94.     Dim hThread         As Long
    95.     Dim i               As Integer
    96.  
    97.     pASM = VarPtr(udtAsync.asm(0))
    98.  
    99.     ' fill code array with INT 3s (Debugger)
    100.     RtlFillMemory ByVal pASM, MAXCODE, &HCC
    101.  
    102.     AddByte pASM, &H58                  ' POP EAX
    103.     AddByte pASM, &H59                  ' POP ECX
    104.     AddByte pASM, &H50                  ' PUSH EAX
    105.  
    106.     For i = UBound(params) To 0 Step -1
    107.         AddPush pASM, CLng(params(i))   ' PUSH dword
    108.     Next
    109.  
    110.     AddCall pASM, fnc                   ' CALL rel. addr
    111.  
    112.     AddByte pASM, &HBA                  ' MOV EDX, |||||
    113.     AddLong pASM, VarPtr(udtAsync.ret)  '          dword
    114.  
    115.     AddByte pASM, &H89                  ' MOV ||||| ||| |||||, EAX
    116.     AddByte pASM, &H2                   '     dword ptr [EDX]
    117.  
    118.     AddByte pASM, &HC3                  ' RET
    119.  
    120.     hThread = CreateThread(ByVal 0&, 0, VarPtr(udtAsync.asm(0)), _
    121.                            ByVal 0&, 0, TID)
    122.  
    123.     udtAsync.hThread = hThread
    124. End Sub
    125.  
    126. ' run function by its pointer
    127. Public Function CallPointer(ByVal fnc As Long, ParamArray params()) As Long
    128.     Dim btASM(MAXCODE - 1)  As Byte
    129.     Dim pASM                As Long
    130.     Dim i                   As Integer
    131.  
    132.     pASM = VarPtr(btASM(0))
    133.  
    134.     ' fill code array with INT 3s (Debugger)
    135.     RtlFillMemory ByVal pASM, MAXCODE, &HCC
    136.  
    137.     ' remove CallWindowProc parameters from stack
    138.     AddByte pASM, &H58                  ' POP EAX
    139.     AddByte pASM, &H59                  ' POP ECX
    140.     AddByte pASM, &H59                  ' POP ECX
    141.     AddByte pASM, &H59                  ' POP ECX
    142.     AddByte pASM, &H59                  ' POP ECX
    143.     AddByte pASM, &H50                  ' PUSH EAX
    144.  
    145.     For i = UBound(params) To 0 Step -1
    146.         AddPush pASM, CLng(params(i))   ' PUSH dword
    147.     Next
    148.  
    149.     AddCall pASM, fnc                   ' CALL rel addr
    150.     AddByte pASM, &HC3                  ' RET
    151.  
    152.     CallPointer = CallWindowProcA(VarPtr(btASM(0)), _
    153.                                   0, 0, 0, 0)
    154. End Function
    155.  
    156. Private Sub AddPush(pASM As Long, lng As Long)
    157.     AddByte pASM, &H68
    158.     AddLong pASM, lng
    159. End Sub
    160.  
    161. Private Sub AddCall(pASM As Long, addr As Long)
    162.     AddByte pASM, &HE8
    163.     AddLong pASM, addr - pASM - 4
    164. End Sub
    165.  
    166. Private Sub AddLong(pASM As Long, lng As Long)
    167.     RtlMoveMemory ByVal pASM, lng, 4
    168.     pASM = pASM + 4
    169. End Sub
    170.  
    171. Private Sub AddByte(pASM As Long, bt As Byte)
    172.     RtlMoveMemory ByVal pASM, bt, 1
    173.     pASM = pASM + 1
    174. End Sub

    Example on how to call user32.MessageBoxA in the same thread:
    VB Code:
    1. Dim fnc         As Long
    2.     Dim ret         As Long
    3.  
    4.     Dim strTitle    As String
    5.     Dim strMsg      As String
    6.  
    7.     ' Get the entry point of user32.MessageBoxA
    8.     fnc = GetFncAddress("user32", "MessageBoxA")
    9.  
    10.     ' convert message to Ansi
    11.     strTitle = StrConv("Title", vbFromUnicode)
    12.     strMsg = StrConv("Messages", vbFromUnicode)
    13.  
    14.     ' call function pointer
    15.     ret = CallPointer(fnc, hWnd, StrPtr(strMsg), StrPtr(strTitle), vbInformation)
    16.  
    17.     MsgBox "Return: " & ret
    That was easy, wasn't it?

    One more for an asynchronous call:
    VB Code:
    1. Dim MsgBoxThread As ASYNCCALL
    2.     Dim fnc         As Long
    3.  
    4.     Dim strTitle    As String
    5.     Dim strMsg      As String
    6.  
    7.     ' get entry point of user32.MessageBoxA
    8.     fnc = GetFncAddress("user32", "MessageBoxA")
    9.  
    10.     'convert message to Ansi
    11.     strTitle = StrConv("Title", vbFromUnicode)
    12.     strMsg = StrConv("Message", vbFromUnicode)
    13.  
    14.     ' call function in a new thread
    15.     ' the udt MsgBoxThread will contain the thread handle, the return value
    16.     ' and the asm code(!)
    17.     ' make sure MsgBoxThread doesn't run out of scope before
    18.     ' the thread is finished! Else your app will crash!
    19.     CallPointerAsync fnc, MsgBoxThread, hWnd, StrPtr(strMsg), StrPtr(strTitle), vbInformation
    20.  
    21.     With MsgBoxThread
    22.         ' wait for the thread to finish
    23.         WaitForThread .hThread
    24.         ' when the thread is finished .ret contains the return value
    25.         MsgBox "Return: " & .ret
    26.     End With

  2. #2
    Hyperactive Member
    Join Date
    Aug 2002
    Location
    UK
    Posts
    417

    Re: call API functions by their pointers

    Nise handy code. this should have with my small Windows Scripting Lanuage. as now I can also call API. nise job Excellent *****
    When your dreams come true.
    On error resume pulling hair out.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width