Announcement

Collapse
No announcement yet.

DLL call function in owning EXE

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Edwin Knoppert
    replied
    Didn't read much about this topic yet but,
    I saw the statement VB doesn't do exported functions.

    Well www.desaware.com has a tool for that.
    Click spyworks and scroll down.

    Or: http://www.desaware.com/ExportedFunctionsL3.htm

    Don't know how it works tough.


    ------------------

    Leave a comment:


  • Nathan Evans
    replied
    Thanks Semen. I overlooked the possibility of using SETTEXT and another SendMessage together!

    Many thanks to you all!

    - Nathan

    Leave a comment:


  • Semen Matusovski
    replied
    Nathan --
    Try following (NT/2000) (POFFS, PB IDE ...)

    Vb Exe

    Form1:
    Code:
    Private Const UniqueName = "My Hook"
    Private Sub Form_Load()
       Me.Caption = UniqueName
       Hook Me.hWnd
       SetHook Me.hWnd, Form2.hWnd
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
       End
    End Sub
    Form2 - empty (no code)
    Module1:
    Code:
    Option Explicit
    
    Declare Function SetHook Lib "hookd" (hWndM As Long, hWndT As Long) As Long
    Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, _
       ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    
    Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, _
       ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    
    Public Const GWL_WNDPROC = -4
    Public Const WM_DESTROY = &H2
    Public Const WM_USER = &H400
    Global lpPrevWndProc As Long
    
    Public Sub Hook(hWnd As Long)
       lpPrevWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WindowProc)
    End Sub
    
    Function WindowProc(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
       Select Case wMsg
          Case WM_USER + 401:
             Form2.Caption = "[Hook]" + Form2.Caption
          Case WM_DESTROY: SetWindowLong hWnd, GWL_WNDPROC, lpPrevWndProc
       End Select
       WindowProc = CallWindowProc(lpPrevWndProc, hWnd, wMsg, wParam, lParam)
    End Function
    Pb/Dll
    Code:
       #Compile Dll "HookD.Dll"
       #Register None
       #Dim All
       #Include "Win32Api.Inc"
    
       $UniqueName = "My Hook"
       Global hInstDLL As Long, MainDll As Long
    
       Function SetHookProc(Op As Long) As Long
          Static hProc As Long, tProc As String
          Local hLib As Long
          If hProc = 0 Then
             hLib = GetModuleHandle("gdi32.dll")
             hProc = GetProcAddress(hLib, "TextOutA")
             tProc = Peek$(hProc, 7)
             If IsFalse(VirtualProtect (ByVal hProc, 7, ByVal %PAGE_EXECUTE_READWRITE, ByRef hLib)) Then _
                MsgBox "Error in VirtualProtect": hProc = 0: Exit Function
             ' Under 9x VirtualProtect doesn't work in the shared virtual address space (from 0x80000000 through 0xBFFFFFFF).
             ' For example, for system dlls.
          End If
          If Op = 1 Then Poke$ hProc, Chr$(&HB8) + Mkl$(CodePtr(MyTextOut)) + Chr$(&HFF, &HE0)
          If Op = 2 Then Poke$ hProc, tProc
          FlushInstructionCache GetCurrentProcess, ByVal hProc, ByVal 7
       End Function
    
       Function MyTextOut (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal lpString As Dword, ByVal nCount As Long) As Long
          Static hDlg As Long, hWndT As Long
          Local MyString As Asciiz * 1000
          If hWndT = 0 Then hDlg = FindWindow("", $UniqueName): _
             If hDlg Then hWndT = GetProp(hDlg, ByVal 2)
          If hWndT Then
             SetWindowText hWndT, ByVal lpString
             SendMessage hDlg, %WM_USER + 401, 0, 0
             GetWindowText hWndT, MyString, SizeOf(MyString)
             SetHookProc 2
             TextOut hdc, x, y, MyString, Len(MyString)
             SetHookProc 1
          End If
       End Function
    
       Function LibMain(ByVal hInstance As Long, ByVal fwdReason As Long, _
          ByVal lpvReserved As Long) Export As Long
          Select Case fwdReason
             Case %DLL_PROCESS_ATTACH: hInstDLL = hInstance: LibMain = 1: SetHookProc 1
             Case %DLL_PROCESS_DETACH: LibMain = 1: SetHookProc 2
          End Select
       End Function
    
       Function HookProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) Export As Long
          Static hHook As Long, hDlg As Long
          hDlg = FindWindow("", $UniqueName)
          If hHook = 0 Then If hDlg Then hHook = GetProp(hDlg, ByVal 1)
          If hHook Then Function = CallNextHookEx(ByVal hHook, ByVal nCode, ByVal wParam, ByVal lParam)
          If IsFalse(MainDll) And (IsFalse(hDlg) Or IsFalse(hHook)) Then FreeLibrary hInstDll
       End Function
    
       Function SetHook Alias "SetHook" (hWndM As Long, hWndT As Long) Export As Long
          Local hHook As Long
          hHook = SetWindowsHookEx (%WH_CBT, CodePtr(HookProc), ByVal hInstDLL, ByVal 0)
          SetProp hWndM, ByVal 1, ByVal hHook
          SetProp hWndM, ByVal 2, ByVal hWndT
          MainDll = 1
       End Function
    Because VB IDE doesn't like hooks, I'd recommend to compile and to run Vb.Exe from explorer

    ------------------
    E-MAIL: [email protected]

    Leave a comment:


  • Nathan Evans
    replied
    i feel the type of hook i'm using is of some relevance now: http://www.powerbasic.com/support/pb...ad.php?t=21331
    it is some great code put together by semen matusovski.

    i'm trying to perform all this in the function that's referenced in place of the original function.
    this is the 'mytextout' function in the first example on the url above.

    thanks!!

    [updated]
    in my vb exe i tested the strptr returned to me by the pb dll using isbadstringptr.
    i called it like: msgbox isbadstringptr(lparam, 1), this would test if the app has read access to the pointer at a length of 1 byte.
    it returned 1, according to msdn - nonzero means the app does not have read access to that location.


    - nathan


    [this message has been edited by nathan evans (edited august 08, 2001).]

    Leave a comment:


  • Nathan Evans
    replied
    I think the real problem i'm having here is that this is a DLL performing a hook, so it has
    multiple instances. I just tested this.. I made a 'GLOBAL lPtr AS LONG' in the General Decs section.

    Then i added a parameter of 'lP AS LONG' to the first function my VB EXE calls, called "StartHook".
    And in the Hook's callback I added 'MSGBOX FORMAT$(lPtr)', so when the hook is triggered it displays the number
    that was in the second parameter in my 'StartHook' function.

    In my VB EXE, I added the extra parameter to the declare, and called it like: 'Call StartHook(Me.hWnd, 123123)'

    When i triggered the Hook's event - it displayed 0 in the MSGBOX.



    Semen, I have experimented with this method, but there is no way to set the WindowProc's return if I rely
    on VB to control WM_SETTEXT for the TextBox. I have to control the WindowProc return number so my DLL may respond
    to what the EXE has told it.

    - Nathan.

    Leave a comment:


  • Semen Matusovski
    replied
    The easiest way to transfer string to VB is to make hidden textbox on VB form and to use SendWindowtext in PB.
    VB controls have hWnd property, which you can pass to PB.


    ------------------
    E-MAIL: [email protected]

    Leave a comment:


  • Lance Edmonds
    replied
    Well, how about creating the "string buffer" in VB (say, using a BYTE array), and pass the first element BYREF to the PB code (ie, a pointer to the array) and let the PB code manipulate the storage buffer directly (DIM..AT or with a pointer, etc).

    VB's VARPTR() function should help with this.

    Also, it looks like you are really trying to read/write a UDT, so the same techquie could be applied. Allocate the storage in VB, pass a pointer to the UDT to the PB code.


    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>

    Leave a comment:


  • Nathan Evans
    replied
    Can I send Strings using SendMessage? I've seen some variants in VB before, like SendMessageByString.

    I tried declaring this in PB, but it reported a duplicate declaration - so I guess that idea is out unless I change my SendMessage declaration
    in the win32api.inc entirely..

    Leave a comment:


  • Nathan Evans
    replied
    Lance,

    I have tried using STRPTR in place of VARPTR but makes no difference. I think it is my VB code at fault, rather than the PB code.

    I am 'calling back' my EXE, from a DLL - so i am using a VB WindowProc, the one Semen kindly posted.

    I have to use Messaging, since i have tried and not succeeded in using a callback to the VB EXE. Besides, my VB app is actually receiving the message, but
    is GPF'ing when attempting to read the variable at the pointer.

    I've been experimenting in using just simple Strings (let alone Types) to see what's up, and i could send a pointer to a 255 byte string across, then have VB attempt to read just 1 byte of it - but a GPF.



    - Nathan

    Leave a comment:


  • Lance Edmonds
    replied
    VARPTR on a dynamic string returns a pointer to the string handle. You probably want to pass the STRPTR value instead.

    Also, the most likely reason the VB code is able to return the function return value is that it is unlikely to be using the dialog engine (VB tends to use it's own custom windows). It is the Windows Dialog engine which is most likely to be swallowing your FUNCTION = values (PowerBASIC's DDT engine relies on the Windows dialog engine for default message handling).

    Semen shows you here how to use dialog subclassing to manipulate the message sucessfully.

    As someone else has asked... Do you have to use messaging here? calling DLL functions directly and passing strings as parameters seems the easiest solution.



    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>

    Leave a comment:


  • Nathan Evans
    replied
    I have *no idea* why this simple bit of code isn't working..

    In my PB DLL:

    Code:
          STATIC gtempdata AS STRING
          gtempdata = "test data"
    
          DIALOG SEND hDlg, %WM_USER + 999&, 0, VARPTR(gtempdata) TO lResult
    In my VB EXE's WindowProc function:

    Code:
          Case WM_USER + 999
                      
               Dim tempdata As String
                 tempdata = Space$(255)
                  CopyMemory tempdata, ByVal lParam, ByVal 1
                  MsgBox tempdata
                 WindowProc = 1
    The VB EXE is getting the Pointer to the string variable, then uses CopyMemory to grab just 1 byte from it. But it GPFs!



    [This message has been edited by Nathan Evans (edited August 08, 2001).]

    Leave a comment:


  • Nathan Evans
    replied
    Morning,

    I'm actually receiving the messages fine at the VB program - but having problems copying the data from the pointer and length
    into a VB type.

    Code:
           Dim cntd As sockaddr
           CopyMemory tempdata, ByVal lParam, ByVal 5
    I've tried sending a STRPTR of a String to the VB app with SendMessage - but it still GPFs.

    I also tried using CALL DWORD to an AddressOf a sub in my VB app - this caused the EXE to exit abruptly, no GPF however.

    Eric, this is just the start of the program and the EXE must be coded in VB, and DLLs in PB.

    This DLL is using SetWindowsHookEx within it's code - maybe this is causing the problems?

    Thanks!



    [This message has been edited by Nathan Evans (edited August 08, 2001).]

    Leave a comment:


  • Semen Matusovski
    replied
    Actually in VB is possible to use traditional technique.
    Imagine that we wrote Pb.Dll, which has starting function
    Code:
       Function Pb (VB_hWnd As Long) Export As Long
     ...   
       End Function
    where VB_hWnd is a handle of main VB form.

    In Form_Load we call two functions
    1) Hook Me.hWnd <-- to subclass VB form
    2) Pb Me.hWnd <-- to pass hWnd of main VB form to PB DLL

    Pb/DLL program can send messages to VB window by usual way.

    Now how Hook and subclass functions look (separate VB module).
    Code:
    Option Explicit
    
    Declare Function Pb Lib "Pb.Dll" Alias "PB" (hWnd As Long) As Long
    
    Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, _
       ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    
    Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, _
       ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    
    Public Const GWL_WNDPROC = -4
    Public Const WM_DESTROY = &H2
    Public Const WM_USER = &H400
    Global lpPrevWndProc As Long
    
    Public Sub Hook(hWnd As Long)
       lpPrevWndProc = SetWindowLong(hWnd, GWL_WNDPROC, AddressOf WindowProc)
    End Sub
    
    Function WindowProc(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
       Select Case wMsg
          Case WM_USER + xxx: <---- Process Pb Message
          Case WM_DESTROY: SetWindowLong hWnd, GWL_WNDPROC, lpPrevWndProc
       End Select
       WindowProc = CallWindowProc(lpPrevWndProc, hWnd, wMsg, wParam, lParam)
    End Function
    ------------------
    E-MAIL: [email protected]

    Leave a comment:


  • Eric Pearson
    replied
    Nathan --

    > The EXE is coded in VB - so i can't use Exports

    Sorry, I thought you converted the EXE from PB to VB to solve this problem, and that it was a pretty quick re-write (based on the dates/times of your messages) that wouldn't be hard to un-do.

    You're right, VB can't create "real" EXEs and DLLs with exported functions, so you can't just cross-DECLARE the functions as you can with PB.

    I suppose you could use the VB AddressOf operator (the rough equivalent of PB's CODEPTR function) to pass the address of the VB function to the DLL, during the EXE initialization. Then you could use CALL DWORD in the DLL to "call back" to the function in the EXE. That works perfectly with PB EXEs and DLLs, and it should work with VB... but I've never tried it with VB. According to the VB docs it should work.

    -- Eric


    ------------------
    Perfect Sync Development Tools
    Perfect Sync Web Site
    Contact Us: mailto:[email protected][email protected]</A>

    Leave a comment:


  • Lance Edmonds
    replied
    When returning a pointer to a UDT (or to any variable for that matter) it cannot be a LOCAL variable in the DLL, or it's memory is freed when the Sub/Function terminates, and you'll get a GPF when you try to reference it via the pointer from outside of the module (or from another Sub/Function in the same module).

    Use STATIC or GLOBAL scope in the DLL code instead...

    ------------------
    Lance
    PowerBASIC Support
    mailto:[email protected][email protected]</A>

    Leave a comment:


  • Nathan Evans
    replied
    No matter what I do, the VB program GPFs as if i'm not allowed to read that memory.

    My PBDLL fills wParam with the SIZEOF, and lParam with a VARPTR to the type structure.

    Then in my VB program:

    Code:
               Dim cntd As connectdata
               CopyMemory cntd, ByVal lParam, ByVal wParam
    Any ideas?

    Thanks.

    Leave a comment:


  • Nathan Evans
    replied
    Eric,

    The EXE is coded in VB - so i can't use Exports

    Don,

    I've been working with CopyMemory all day trying to get this to work. But VB keeps returning incorrect
    values from the Type structure. I'm working on it though

    Thanks!!

    ------------------

    Leave a comment:


  • Eric Pearson
    replied
    > make the DLL somehow call a
    > function in the main EXE.

    All this talk about messages and dialogs sounds like "the hard way" to me.

    If you wrote both the DLL and EXE, you should be able to simply DECLARE (in the source for the DLL) the function that is located in the EXE. Then you just call the function!.

    If your application is single-theaded, it should be just this easy...

    Code:
    DECLARE FUNCTION MyFunc LIB "WHATEVER.EXE" ALIAS "MyFunc" (params) AS LONG
    ...and make sure the function is marked FOR EXPORT in the EXE. (Of course VB doesn't do EXPORTs, but if the EXE is written in PB it should work perfectly.)

    Or am I missing something?

    -- Eric

    ------------------
    Perfect Sync Development Tools
    Perfect Sync Web Site
    Contact Us: mailto:[email protected][email protected]</A>



    [This message has been edited by Eric Pearson (edited August 07, 2001).]

    Leave a comment:


  • Don Dickinson
    replied
    You'll probably have to send the address (varptr) of the structure over to vb as lparam or wparam. Then in vb, use RtlMoveMemory (or the like) to copy the data into your vb structure.
    Best Regards,
    Don

    ------------------
    dickinson.basicguru.com

    Leave a comment:


  • Nathan Evans
    replied
    Can i use one of the DIALOG SEND parameters to send a Type structure over to my VB program?

    Thanks!!

    - Nathan

    Leave a comment:

Working...
X