Announcement

Collapse
No announcement yet.

Sending Control to a DLL without a DIALOG

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

  • Sending Control to a DLL without a DIALOG

    I have had to take a new direction with my project. I want to control the DLL that is being called hundreds of times by TradeStation, from an app compiled in PB - Control APP.

    The DLL is called by TradeStation and DOES NOT produce a dialog.

    I need a way of sending something from the PB Control APP such that the DLL waits untill it receives this message/value/whatever befor continuing ie:
    WHILE %VarFromApp = 0
    LOOP

    I would like to keep it simple because the DLL is called thousands of times (once for each minutes data in TradeStation back 3 yrs).

    Is there any way to do this without creating a dialog in the DLL?

    ------------------
    Kind Regards
    Mike

  • #2
    FYI, this has been discussed off-line via Tech Support.

    After much discussion, Mike is probably going to use memory mapped files since he needs inter-process communication with a GUI-less DLL.


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

    Comment


    • #3
      If anyone has any examples of Memory mapping to send a couple of simple LONGS I would greatly appreciate it.

      Also if anyone has an example of a Named pipe ...

      ------------------
      Kind Regards
      Mike

      Comment


      • #4
        I forgot to mention my biggest challenge - to trap a message without a DIALOG (Case WM_RECEIVE) for eaxmple.

        WM_SENDMSG = RegisterWindowMessage("Inter_Process_Message_A")
        WM_RECEIVE = RegisterWindowMessage("Inter_Process_Message_B")
        You then use,
        SendMessage %HWND_BROADCAST,WM_SENDMSG,0,0
        and at the other program,
        Case WM_RECEIVE

        How do you Recieve without a DIALOG in the DLL?

        ------------------
        Kind Regards
        Mike

        Comment


        • #5
          For Example,
          In Semens excellent examples, how would you recieve if one of the apps was a DLL without a dialog window?


          compile both programs (almost the same) and run first

          #Compile Exe "Smp1.Exe"
          #Register None
          #Dim All
          #Include "Win32Api.Inc"
          Type COPYDATASTRUCT
          dwData As Dword Ptr
          cbData As Dword
          lpData As Asciiz Ptr
          End Type
          CallBack Function DlgProc
          Static Cdt As COPYDATASTRUCT, i As Long, hDlgR As Long, _
          lpCdt As COPYDATASTRUCT Ptr, Txt As String
          Select Case CbMsg
          Case %WM_INITDIALOG
          Control Add TextBox, CbHndl, 101, "", 10, 10, 80, 12
          Control Add Button, CbHndl, 102, "Send", 30, 30, 40, 12
          Control Add Frame, CbHndl, -1, " Received ", 5, 50, 90, 26
          Control Add Label, CbHndl, 103, " ", 10, 60, 80, 12
          i = Shell("Smp2.Exe" + Str$(CbHndl), 1)
          Case %WM_USER + 1
          hDlgR = CbWparam
          Case %WM_COMMAND
          If CbCtl = 102 Then
          Control Get Text CbHndl, 101 To Txt
          Cdt.cbdata = Len(Txt) + 1
          Cdt.lpData = StrPtr(Txt)
          SendMessage hDlgR, %WM_COPYDATA, 0, VarPtr(Cdt)
          End If
          Case %WM_COPYDATA
          lpCdt = CbLparam
          Control Set Text CbHndl, 103, @[email protected]
          Function = 1: Exit Function
          End Select
          End Function
          Function PbMain
          Dim hDlg As Long
          Dialog New 0, "#1", 200, 200, 100, 85, %WS_CAPTION Or %WS_SYSMENU To hDlg
          Dialog Show Modal hDlg Call DlgProc
          End Function

          Program #2

          #Compile Exe "Smp2.Exe"
          #Register None
          #Dim All
          #Include "Win32Api.Inc"
          Type COPYDATASTRUCT
          dwData As Dword Ptr
          cbData As Dword
          lpData As Asciiz Ptr
          End Type
          CallBack Function DlgProc
          Static Cdt As COPYDATASTRUCT, i As Long, hDlgR As Long, _
          lpCdt As COPYDATASTRUCT Ptr, Txt As String
          Select Case CbMsg
          Case %WM_INITDIALOG
          Control Add TextBox, CbHndl, 101, "", 10, 10, 80, 12
          Control Add Button, CbHndl, 102, "Send", 30, 30, 40, 12
          Control Add Frame, CbHndl, -1, " Received ", 5, 50, 90, 26
          Control Add Label, CbHndl, 103, " ", 10, 60, 80, 12
          hdlgR = Val(Command$)
          PostMessage hDlgR, %WM_USER + 1, CbHndl, 0
          Case %WM_COMMAND
          If CbCtl = 102 Then
          Control Get Text CbHndl, 101 To Txt
          Cdt.cbdata = Len(Txt) + 1
          Cdt.lpData = StrPtr(Txt)
          SendMessage hDlgR, %WM_COPYDATA, 0, VarPtr(Cdt)
          End If
          Case %WM_COPYDATA
          lpCdt = CbLparam
          Control Set Text CbHndl, 103, @[email protected]
          Function = 1: Exit Function
          End Select

          End Function
          Function PbMain
          Local hDlg As Long
          Dialog New 0, "#2", 400, 200, 100, 85, %WS_SYSMENU Or %WS_CAPTION To hDlg
          Dialog Show Modal hDlg Call DlgProc
          End Function

          ------------------
          Kind Regards
          Mike

          Comment


          • #6
            How about using a Mutex?


            Peter.


            ------------------
            [email protected]
            [email protected]

            Comment


            • #7
              Don't know like others, but I don't understand, where appears IPC.

              As I understand, there is a leading system (Exe), which is able to transfer information to external modules by calling DLL.
              There is a wish to process this information in "independent" module.
              PB DLL can simply start a thread.



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

              Comment


              • #8
                Mike,

                =================================================================

                WM_SENDMSG = RegisterWindowMessage("Inter_Process_Message_A")
                WM_RECEIVE = RegisterWindowMessage("Inter_Process_Message_B")
                You then use,
                SendMessage %HWND_BROADCAST,WM_SENDMSG,0,0
                and at the other program,
                Case WM_RECEIVE

                =================================================================

                This approach is primarily for 2 or more seperate EXE files that cannot
                communicate in the same way as a DLL, EXE files do not share the same
                memory space. The other problem is that it requires a message handling
                procedure to poll messages, this is not a necessary feature in a DLL.

                A DLL is mapped into the calling applications memory space and can be
                accessed by the calling application without the need for private messages.
                What I am not sure about is if the DLL being called by the other APP is
                one that you have written.

                If its your DLL, why not do the processing completely in the DLL so that
                you can use a dialog or window ? I wonder what is the point of writing
                a controlling application if you have access to the code in the DLL.

                Memory mapped files sounds right but there is another approach that may
                do the job, a DLL can call an EXPORT function in an EXE file from memory
                so this approach may be useful if a bit complicated, it means the DLL
                would need to call the PB EXE on a regular basis, perhaps accessing the
                values you want to pass as return values from that EXPORT function.

                This can be done by passing multiple values in a UDT back to the DLL.

                Regards,

                [email protected]

                ------------------
                hutch at movsd dot com
                The MASM Forum

                www.masm32.com

                Comment


                • #9
                  Thank you all very much for your input guys. I am so out of my depth here but I am determined to get this to work

                  The problem is a little unique in that the DLL in this story does not MAKE DIALOG. The reason is that as soon as it makes a dialog it would be destroyed as control returns to the calling app (TradeStation).

                  You see TradeStation (a commecially available app NOT written by me) calls my DLL function many thousands of times. There are times when I want to allow this process to continue as fast as possible yet still have control over some parameters within the DLL.

                  If I create a dialog in the DLL to do this, It will have to be created and destroyed thousands of times and would require dismissing each time OR would flash so fast as to be a grey blur. Either way its useless.

                  SO I have written a SEPERATE EXE with a dialog and control buttons and progress bar etc etc. The problem is to first of all get a few LONGs to/from the DLL and second to do it at the DLL end WITHOUT a DIALOG.

                  So I have 3 elements, TradeStation.EXE which calls MyDLL.DLL written in PB, and MyControlApp.EXE written in PB.

                  I can only write code for MyDLL.DLL and MyControlApp.EXE.

                  I guess you could say I am trying to extract data from Tradestation with MyDLL.DLL into MyControlApp.EXE and send a few variables back to MyDLL.DLL.

                  Obviously MyDLL.DLL does not share memory space with MyControlApp.EXE (because it is not called by it) so I need a pipe or Memmory mapping to get the variables back and forth.

                  If that wanst enough, I also need to trap in the DLL without using a DIALOG!

                  I hope this helps explain the problem. I have read and read the API and SDK and other help files. However I am still a green horn and statements like "Points to the memory address in the calling process's address space where mapping should begin. This must be a multiple of the system's memory allocation granularity"
                  means absolutly nothing to me. So I have to rely on your kindness and a few lines of code from which I can glean the meaning of such "explanations" by example.



                  ------------------
                  Kind Regards
                  Mike

                  Comment


                  • #10
                    Following code illustrates, about what I told (tested under Win2000 only)
                    Main Exe permanently calls DLL.
                    During first Call a DLL creates a dialog in thread.

                    Code:
                       #Compile Exe
                       #Register None
                       #Dim All
                       #Include "Win32Api.Inc"
                    
                       Declare Function PbProc Lib "Pb.Dll" Alias "PbProc" (ByVal w As Long) As Long
                       CallBack Function DlgProc
                          Select Case CbMsg
                             Case %WM_INITDIALOG
                                Control Add TextBox, CbHndl, 101, "", 10, 10, 80, 12
                                Control Add Button, CbHndl, 102, "Send", 30, 30, 40, 12
                                Control Add Button, CbHndl, 103, "Stop", 30, 50, 40, 12
                             Case %WM_COMMAND
                                If CbCtl = 102 Then SetTimer CbHndl, 1, 50, ByVal 0&
                                If CbCtl = 103 Then KillTimer CbHndl, 1
                             Case %WM_TIMER
                                Static xx As Long
                                Incr xx: PbProc xx
                          End Select
                       End Function
                    
                       Function PbMain
                          Dim hDlg As Long
                          Dialog New 0, "TradeStation", 100, 100, 100, 85, %WS_CAPTION Or %WS_SYSMENU To hDlg
                          Dialog Show Modal hDlg Call DlgProc
                       End Function

                    Code:
                       #Compile Dll "Pb.Dll"
                       #Register None
                       #Dim All
                       #Include "Win32Api.Inc"
                    
                       Global hDlg As Long
                    
                       Function LibMain (ByVal hInstance As Long, ByVal fwdReason As Long, _
                                         ByVal lpvReserved As Long) Export As Long
                          Select Case fwdReason
                             Case %DLL_PROCESS_DETACH
                                If hDlg Then
                                   ' Delete resources
                                   Dim i As Long
                                   i = Shell ("NotePad.Exe") ' Test
                                End If
                          End Select
                          LibMain = 1
                       End Function
                    
                       CallBack Function DlgProc
                          Select Case CbMsg
                             Case %WM_INITDIALOG: Control Add Label, CbHndl, 101, "", 10, 10, 80, 12
                             Case %WM_USER + 1:   Control Set Text CbHndl, 101, Format$(CbWparam)
                          End Select
                       End Function
                    
                    
                       Function GUIActivate (ByVal h As Long) As Long
                          Dialog New 0, "Pb Dll", 250, 100, 100, 30, %WS_CAPTION Or %WS_SYSMENU To hDlg
                          Dialog Show Modal hDlg Call DlgProc
                       End Function
                    
                       Function PbProc Alias "PbProc" (ByVal w As Long)  Export As Long
                          Static x As Long
                          Dim idThread As Long
                          Incr x
                          If x = 1 Then
                             Thread Create GUIActivate(0) To idThread
                             Thread Close idThread To idThread
                             Do
                                If hDlg > 0 Then Exit Do
                                Sleep 20
                             Loop
                          End If
                          PostMessage hDlg, %WM_USER + 1, w, 0
                          
                       End Function


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

                    Comment


                    • #11
                      I have read and re-read the original question.

                      DLL's do not require a dialog. Never did.

                      DLL's will always wait to be called. Thats how they work.

                      If you want them to sit in memory, maintaining static variables,
                      you can use LoadLibrary.

                      Did this thread go off-subject, or was the original question
                      mis-phrased?


                      ------------------
                      Thanks,

                      John Kovacich
                      Thanks,

                      John Kovacich
                      Ivory Tower Software

                      Comment


                      • #12
                        Yes you are right this has meandered around the topic a little.

                        Please excuse me, but i do not really know what i am
                        asking for when i write some of these questions. Thank
                        you all for being so patient.

                        The problem has turned ut to be two problems. Inter
                        application communication (memory mapping as a solution) and
                        trapping without a dialog.

                        I have had some wonderfull examples of memmory
                        mapping.

                        Now I am trying to find one that i can use without
                        creating a dialog in a DLL. This DLL needs to communicate with an EXE but *NOT* the one that called it.

                        This is a little unusual because the first thing you usually
                        do is to create some kind of dialog. In
                        this case i am writing a DLL. All the dialogs are in
                        the calling app - Tradestation (a commercial compiled
                        app) so i have no access to these dialogs.

                        Any trapping in my DLL must be done without creating a
                        dialog. So this thread should really be called "interprocess commuication without creating a dialog on one side".
                        sorry for any confusion.


                        ------------------
                        Kind Regards
                        Mike

                        Comment


                        • #13
                          Semen what a great Example. Thank you.

                          In your example the Calling EXE talks to the called DLL with the thread - very clever.

                          Can I send data to this DLL from a second .EXE? (ControlApp.EXE)

                          This is the problem.

                          Peter Lameijn suggested that I use PEEK and POKE with Memory mapping. He very kindly sent me two apps to demostrate this. All I can say is WOW!

                          Two Apps one TransMitting, One Recieveing. Launch the TX app first then launch the RX app.

                          TX App

                          #COMPILE EXE
                          #INCLUDE "win32api.inc"
                          %BTN = %WM_USER + 2040
                          %PAGE_READONLY = &h2 ' Missing from Win32API.Inc
                          %PAGE_READWRITE = &h4 ' Missing from Win32API.Inc
                          %PAGE_WRITECOPY = &h8 ' Missing from Win32API.Inc
                          %WAIT_FAILED = &HFFFFFFFF& ' Missing from Win32API.Inc
                          GLOBAL hDlg AS LONG, hMap AS LONG
                          '------------------------------------------------------------------------------'
                          CALLBACK FUNCTION MainCb ()
                          LOCAL lString AS STRING
                          SELECT CASE CBMSG
                          CASE %WM_COMMAND
                          SELECT CASE CBCTL
                          CASE %BTN
                          lString = TIME$ + " - " + DATE$
                          POKE$ hMap,lString ' send string to SharedMemory
                          SLEEP 200
                          lString = " "
                          POKE$ hMap,lString
                          END SELECT
                          END SELECT
                          END FUNCTION
                          '------------------------------------------------------------------------------'
                          'Main program '
                          '------------------------------------------------------------------------------'
                          FUNCTION PBMAIN () AS LONG
                          LOCAL MapName AS ASCIIZ * 64, lRet AS LONG, lString AS STRING
                          MapName = "MyMap"
                          lRet = CreateFileMapping _
                          (BYVAL -1 ,_ ' handle to file to map
                          BYVAL 0 ,_ ' optional security attributes
                          BYVAL %PAGE_READWRITE ,_ 'protection for mapping object
                          BYVAL 0 ,_ ' high-order 32 bits of object size
                          65535 ,_ ' low-order 32 bits of object size
                          MapName)' name of file-mapping object )
                          IF lRet THEN
                          hMap = MapViewOfFile (lRet, %FILE_MAP_ALL_ACCESS, 0, 0, 0)
                          DIALOG NEW 0, "File mapping",800,1,100,50, %WS_VISIBLE OR %WS_SYSMENU TO hDlg
                          CONTROL ADD BUTTON, hDlg&, %BTN, "Send time and date", 10, 10, 80, 12
                          DIALOG SHOW MODAL hDlg, CALL MainCb
                          ELSE
                          MSGBOX "Cannot create file mapping"
                          END IF
                          END FUNCTION
                          '------------------------------------------------------------------------------'


                          RX App:

                          #COMPILE EXE
                          #INCLUDE "win32api.inc"
                          '------------------------------------------------------------------------------'
                          FUNCTION PBMAIN () AS LONG
                          LOCAL hMap AS LONG, MapName AS ASCIIZ * 64, lRet AS LONG, lString AS STRING
                          MapName = "MyMap"
                          lRet = OpenFileMapping _
                          (%FILE_MAP_ALL_ACCESS,_ ' access mode
                          BYVAL %NULL, _ ' inherit flag
                          MapName) ' pointer to name of file-mapping object
                          IF lRet THEN
                          hMap = MapViewOfFile _
                          (lRet,_ ' file-mapping object to map into address space
                          %FILE_MAP_ALL_ACCESS,_ ' access mode
                          0,_ ' high-order 32 bits of file offset
                          0,_ ' low-order 32 bits of file offset
                          0) ' number of bytes to map
                          WHILE %True
                          lString = TRIM$(PEEK$(hMap,100), ANY CHR$(0,32)) ' Format Time and Date
                          IF lString <> "" THEN
                          IF MSGBOX (lString, %MB_OKCANCEL OR %MB_ICONASTERISK, "Data change: (press cancel to end)") <> 1 THEN EXIT FUNCTION
                          SLEEP 100
                          END IF
                          WEND
                          ELSE
                          MSGBOX "Cannot open file mapping" + CHR$(13) + "Filemap must exist!",%MB_ICONSTOP,"Error:"
                          END IF
                          END FUNCTION
                          '------------------------------------------------------------------------------'




                          ------------------
                          Kind Regards
                          Mike

                          Comment


                          • #14
                            Mike --
                            In variant, which I suggested, DLL is combined with "Control App.Exe", which is located in thread.
                            There is no second Exe and you can avoid slowly IPC at all.

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

                            Comment


                            • #15
                              Well after *ALOT* of work and assistance, my journey through the dark woods of Windows SDK is drawing to a close.

                              I have learnt about, memory Mapping, Threads, Pointers, Types, Shelling, Dialogs, Messages, Strings et al, PEEKing and POKEing, Handles, Memory allocation, Byte lengths of variable types, and more about the SDK than I ever thought existed.

                              After more consultation with the true masters of this forum, without whom this journey would have left me in the thick of the woods lost and dying, I have been able to get it to happen.

                              The First methor is indeed using memory mapping. I am still working on a method using threads.

                              Here are two Apps that send ANY type of data from one to the other (and potentially back and forth) WITHOUT a single NEW DIALOG statement to be found!

                              Obvioulsy the code for either on of these could be contained in a DLL. The First EXE creates shared Memory with CreateFileMapping (I still have no idea what files have to do with it) and stuffs data into the shared memory.

                              The Second EXE opens a "view" of that shared memory (gains access to it) and retrives the data. (It is only necessary to launch mmaptx.exe )

                              They are short and VERY sweet. (thanks Peter L)


                              #COMPILE EXE "mmaptx.exe"
                              #INCLUDE "win32api.inc"
                              TYPE MyDataType
                              Var1 AS LONG ' Any Data Types you want
                              Var2 AS SINGLE ' As long as they are fixed length ie:
                              Str1 AS ASCIIZ * 20 ' AS STRING - not allowed
                              Str2 AS STRING * 40 ' is allowed
                              END TYPE
                              GLOBAL TXData AS MyDataType ' Create an instance of MyDataType to put the data into
                              GLOBAL MemSize AS LONG ' Make enough room for all the data
                              GLOBAL hMap AS LONG, lRet AS LONG, MsgStr AS STRING, ShRet AS LONG, TXString AS STRING
                              '------------------------------------------------------------------------------'
                              FUNCTION PBMAIN () AS LONG
                              MemSize = 1020 ' See manual for how many bytes each type requires
                              lRet = CreateFileMapping(BYVAL -1, BYVAL 0, BYVAL %PAGE_READWRITE, BYVAL 0,MemSize, "MyMemMap")
                              IF lRet THEN
                              hMap = MapViewOfFile (lRet, %FILE_MAP_ALL_ACCESS, 0, 0, 0)
                              TXData.Var1 = hMap ' an example LONG variable to send
                              TXData.Var2 = MemSize ' a differnt example lONG to send
                              TXData.Str1 = DATE$ ' an example STRING to send
                              TXData.Str2 = TIME$ ' a different example STRING to send
                              TXString = PEEK$(VARPTR(TXData), LEN(TXData)) ' Put the entire Type into a String (in Apps memory)
                              POKE$ hMap, TXString ' transfer to SHARED Memory (from memory avaiable to this app only)
                              ShRet = SHELL("mmaprx") ' launch the Receiving app
                              MsgStr = "1 " & STR$(TXData.Var1) & $CRLF & "2 " & STR$(TXData.Var2) & $CRLF & _
                              "3 " & TXData.Str1 & $CRLF & "4 " & TXData.Str2
                              MSGBOX MsgStr,,"Data Sent ..."
                              UnmapViewOfFile BYVAL lRet ' Memory is not released untill BOTH Programs
                              CloseHandle hMap ' have UnMapped their views AND closed thier Handles!
                              ELSE
                              MSGBOX "ERROR: Cannot create file mapping"
                              END IF
                              END FUNCTION
                              '-----------------------------------------------------------------------------

                              #COMPILE EXE "mmaprx.exe"
                              #INCLUDE "win32api.inc"
                              TYPE MyDataType ' Must be defined exactly the same way as the TX App
                              Var1 AS LONG
                              Var2 AS SINGLE
                              Str1 AS ASCIIZ * 20
                              Str2 AS STRING * 40
                              END TYPE
                              GLOBAL RXData AS MyDataType
                              GLOBAL hMap AS LONG, lRet AS LONG, MsgStr AS STRING, RXString AS STRING
                              '------------------------------------------------------------------------------'
                              FUNCTION PBMAIN () AS LONG
                              lRet = OpenFileMapping(%FILE_MAP_ALL_ACCESS, BYVAL %NULL, "MyMemMap")
                              IF lRet THEN
                              hMap = MapViewOfFile(lRet, %FILE_MAP_ALL_ACCESS, 0, 0, 0)
                              SLEEP 1000
                              RXString = PEEK$(hMap, LEN(RXData)) ' Recover the Data in MyDataType from the Shared Memory
                              POKE$ VARPTR(RXData), RXString ' Stuff it into memory avaiable to this app only
                              MsgStr = "1 " & STR$(RXData.Var1) & $CRLF & "2 " & STR$(RXData.Var2) & $CRLF & _
                              "3 " & RXData.Str1 & $CRLF & "4 " & RXData.Str2
                              MSGBOX MsgStr,,"Data Recieved ..."
                              UnmapViewOfFile BYVAL lRet ' Memory is not released untill BOTH Programs
                              CloseHandle hMap ' have UnMapped their views AND closed thier Handles!
                              END IF
                              END FUNCTION
                              '------------------------------------------------------------------------------'


                              ------------------
                              Kind Regards
                              Mike

                              Comment

                              Working...
                              X