Announcement

Collapse
No announcement yet.

COM Interface: Planning Both Sides

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

  • COM Interface: Planning Both Sides

    Greetings! Tonight I'm inquring if anyone has any input regarding building a basic COM interface between two programs where I'm in control of both sides and where two-way communications (mostly simple strings) are required on each side, assuming COM is even the best mechanism.

    This is my first need for COM and have reviewed many of the examples on the board. All that I've discovered relate to controlling Excel, Word or some other application, and most of which I've been able to make work. However, I have not encountered any examples of a COM "server" in PowerBasic, supposing it can even be done.

    Are there any limitations or common mistakes made when building ones first COM interface? Any tip, suggestions and (hopefully) even a COM server code clip would be greatly appreciated.

    Also, I am very much open to alternate methods of inter-application communication where I can pass strings between them.

    Thanks,
    Dan
    Last edited by Dan Gin zel; 28 May 2008, 12:24 AM.
    www.thecomputerarchive.com Preserving the history of companies that advanced the computer revolution

  • #2
    PB doesn't provide, as of yet, the ability to create COM servers. That's why you dont' find examples here. If you really like to go the COM way, I guess José Roca's forums would eb agood place to look at.

    That said, exchanging "strings" could easily be done via TCP communication. Look at the Echoserver (client/server) in you PB examples folder.

    Comment


    • #3
      There are many, many ways to exchange info between cooperating applications on the same computer...

      - Memory Mappped file objects
      - Window messages, eg WM_COPYDATA
      - Regular disk files
      - Pipes and Mailslots

      I'm sure I've forgotten some. Try a seach here on "interprocess communications."
      Michael Mattias
      Tal Systems (retired)
      Port Washington WI USA
      [email protected]
      http://www.talsystems.com

      Comment


      • #4
        Com servers behave much better than sendmessages and such.
        using sm you can lock up both apps.
        hellobasic

        Comment


        • #5
          An EXE and a DLL.

          Comment


          • #6
            An EXE and a DLL.
            Not to mention, the DLL can have its own "Windows/Dialog/etc"
            Engineer's Motto: If it aint broke take it apart and fix it

            "If at 1st you don't succeed... call it version 1.0"

            "Half of Programming is coding"....."The other 90% is DEBUGGING"

            "Document my code????" .... "WHYYY??? do you think they call it CODE? "

            Comment


            • #7
              First, I want to thank everyone for the input. That's exactly what I needed to get the cognitive processes moving again.

              And now, for the winning entry:
              Originally posted by Knuth Konrad View Post
              That said, exchanging "strings" could easily be done via TCP communication. Look at the Echoserver (client/server) in you PB examples folder.
              The beauty of this solution is that I can use it between more than process, use it for multiple instance detection and here's the key: to use it between computers on a LAN. The latter opens up a whole new realm of possibilities that I had not before considered!

              I've been doing searches looking for existing code as I have little TCP/IP communications experience. Lots to learn by Friday (Demo Day.)

              (Now if someone has any tips or thoughts in this direction, I'm all ears!)

              Thanks again to all! Y'alls input is most appreciated!

              Dan
              www.thecomputerarchive.com Preserving the history of companies that advanced the computer revolution

              Comment


              • #8


                It is a tcp server using sqlite database..
                hellobasic

                Comment


                • #9
                  Dan
                  Here is a very simple TCP server DLL that allows control of and reporting on a VB6 program. The VB6 program just calls StartTCP passing a Callback address. The StartTCP Sub just starts a MODELESS (most important for a TCP server) hidden Dialog, the TCP and returns to VB6. When the VB6 prog is closing down it just calls CloseTCP which closes the Dialog and TCP server.
                  External program (over Internet or LAN) simply connect to the TCP server and send a brief message. Depending on the message it either sends a control code back to the VB6 prog Callback or returns info to the caller.
                  The port number you use is your own choice, preferably not a commonly used one.
                  Code:
                  #PBFORMS CREATED V1.51
                  #COMPILE DLL
                  #DIM ALL
                  
                  #PBFORMS BEGIN INCLUDES
                  #IF NOT %DEF(%WINAPI)
                      #INCLUDE "WIN32API.INC"
                  #ENDIF
                  #PBFORMS END INCLUDES
                  
                  #PBFORMS BEGIN CONSTANTS
                  %Bqt     = 1002
                  %Dtcp    =  101
                  %Tmess   = 1001
                  #PBFORMS END CONSTANTS
                  
                  GLOBAL Htcp AS LONG
                  GLOBAL LoggedIn AS LONG
                  GLOBAL ManualLogout AS LONG
                  GLOBAL LastAct AS STRING
                  GLOBAL LastOrd AS STRING
                  GLOBAL CurrentMonth AS STRING
                  GLOBAL Cfg() AS STRING
                  GLOBAL VBAdd AS DWORD
                  GLOBAL WHndl AS DWORD
                  
                  DECLARE CALLBACK FUNCTION ShowDtcpProc()
                  'DECLARE FUNCTION ShowDtcp(BYVAL hParent AS DWORD) AS LONG
                  #PBFORMS DECLARATIONS
                  DECLARE SUB GiveAction(BYVAL DoThis AS LONG)
                  
                  SUB StartTCP(BYVAL VBAddress AS DWORD) EXPORT
                      LOCAL hDlg  AS DWORD
                      LOCAL fi AS LONG
                      LOCAL a AS LONG
                      LOCAL s AS STRING
                      LOCAL t AS STRING
                      VBAdd = VBAddress
                      fi = FREEFILE
                      OPEN "c:\jiwamcaord.cfg" FOR INPUT AS fi
                      WHILE EOF(fi) = 0
                          LINE INPUT #fi, t
                          a = INSTR(t, "=")
                          IF a THEN
                              s = UCASE$(TRIM$(LEFT$(t, a - 1)))
                              t = TRIM$(RIGHT$(t, LEN(t) - a))
                              SELECT CASE s
                                  CASE "PERIOD START"
                                      CurrentMonth = t
                              END SELECT
                          END IF
                      WEND
                      CLOSE fi
                      DIALOG NEW %HWND_DESKTOP, "Hidden Dialog", 247, 162, 201, 121, TO hDlg
                      CONTROL ADD TEXTBOX, hDlg, %Tmess, "", 5, 5, 190, 90, %WS_CHILD OR _
                          %WS_VISIBLE OR %WS_VSCROLL OR %ES_LEFT OR %ES_MULTILINE OR _
                          %ES_AUTOHSCROLL OR %ES_AUTOVSCROLL OR %ES_READONLY, _
                          %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
                          %WS_EX_RIGHTSCROLLBAR
                      CONTROL ADD BUTTON,  hDlg, %Bqt, "Exit", 76, 100, 50, 15
                  #PBFORMS END DIALOG
                      TCP OPEN SERVER PORT 1122 AS #2    'create a TCP server to handle action requests
                      TCP NOTIFY #2, ACCEPT TO hdlg AS 889    'and have it notify when a session is requested
                      WHndl = hDlg
                      DIALOG SHOW STATE hDlg, %sw_hide
                      DIALOG SHOW MODELESS hDlg, CALL ShowDtcpProc
                  END SUB
                  
                  SUB StopTCP() EXPORT
                      TCP CLOSE #2
                      DIALOG END WHndl
                  END SUB
                  
                  SUB SaveState(Lact AS STRING, LIn AS LONG, MLOut AS LONG) EXPORT
                      LoggedIn = Lin
                      ManualLogout = MLOut
                      LastAct = Lact
                  END SUB
                  
                  SUB OrderDet(Lord AS STRING) EXPORT
                      LastOrd = Lord
                  END SUB
                  
                  
                  CALLBACK FUNCTION ShowDtcpProc()
                      LOCAL buffer AS STRING
                      LOCAL s AS STRING
                      LOCAL fi AS LONG
                      LOCAL a AS LONG
                  
                      SELECT CASE AS LONG CBMSG
                          CASE %WM_INITDIALOG
                  
                          CASE %WM_NCACTIVATE
                              STATIC hWndSaveFocus AS DWORD
                              IF ISFALSE CBWPARAM THEN
                                  hWndSaveFocus = GetFocus()
                              ELSEIF hWndSaveFocus THEN
                                  SetFocus(hWndSaveFocus)
                                  hWndSaveFocus = 0
                              END IF
                  
                          CASE 889    'a new query session has been started
                              htcp = FREEFILE
                              TCP ACCEPT 2 AS htcp
                              TCP NOTIFY htcp, RECV CLOSE TO CBHNDL AS 890
                              SLEEP 500
                  
                          CASE 890    'the requesting packet has been received
                              SELECT CASE CBLPARAM
                                  CASE 1  '%FD_READ
                                      TCP RECV htcp, 512, buffer    'the incoming packet will never be more than 512 bytes
                                      buffer = TRIM$(buffer)
                                      SELECT CASE buffer
                                          CASE "Return Status"
                                              s = LastAct + $CRLF
                                              IF LoggedIn THEN
                                                  s = s + "Logged in to Jiwa" + $CRLF
                                              ELSE
                                                  IF ManualLogout THEN
                                                      s = s + " Manually "
                                                  END IF
                                                  s = s + "Logged out of Jiwa" + $CRLF
                                              END IF
                                              s = s + "Current period start date " + CurrentMonth + $CRLF
                                              s = s + LastOrd
                                              TCP SEND htcp, s 'send the reply back
                                          CASE "Log Out"
                                              CALL DWORD VBAdd USING GiveAction(2)
                                              TCP SEND htcp, "Done" 'send the reply back
                                          CASE "Send Log"
                                              CALL DWORD VBAdd USING GiveAction(1)
                                              TCP SEND htcp, "Done" 'send the reply back
                                          CASE "Shutdown"
                                              CALL DWORD VBAdd USING GiveAction(3)
                                              TCP SEND htcp, "Done" 'send the reply back
                                          CASE ELSE
                                              IF INSTR(buffer, "Log In") THEN
                                                  a = INSTR(buffer, "New Month")
                                                  IF a THEN
                                                      CurrentMonth = TRIM$(RIGHT$(buffer, LEN(buffer) - a - 9))
                                                      REDIM cfg(0)
                                                      fi = FREEFILE
                                                      OPEN "c:\jiwamcaord.cfg" FOR INPUT AS fi
                                                      WHILE EOF(fi) = 0
                                                          LINE INPUT #fi, cfg(UBOUND(cfg))
                                                          a = INSTR(cfg(UBOUND(cfg)) , "=")
                                                          IF a THEN
                                                              s = UCASE$(TRIM$(LEFT$(cfg(UBOUND(cfg)) , a - 1)))
                                                              IF TRIM$(s) = "PERIOD START" THEN
                                                                  cfg(UBOUND(cfg)) = "PERIOD START" + " = " + CurrentMonth
                                                              END IF
                                                          END IF
                                                          REDIM PRESERVE cfg(UBOUND(cfg) + 1)
                                                      WEND
                                                      CLOSE fi
                                                      fi = FREEFILE
                                                      OPEN "c:\jiwamcaord.cfg" FOR OUTPUT AS fi
                                                      FOR a = 0 TO UBOUND(cfg) - 1
                                                          PRINT #fi, cfg(a)
                                                      NEXT
                                                      CLOSE fi
                                                      CALL DWORD VBAdd USING GiveAction(5)
                                                  ELSE
                                                      CALL DWORD VBAdd USING GiveAction(4)
                                                  END IF
                                                  TCP SEND htcp, "Done" 'send the reply back
                                              END IF
                  
                                      END SELECT
                                      SLEEP 500
                                  CASE &H20   'and close the session %FD_CLOSE
                                      TCP CLOSE htcp
                              END SELECT
                          CASE %WM_COMMAND
                              SELECT CASE AS LONG CBCTL
                                  CASE %Tmess
                  
                                  CASE %Bqt
                                      IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                          TCP CLOSE #2
                                          DIALOG END CBHNDL
                                      END IF
                  
                              END SELECT
                      END SELECT
                  END FUNCTION

                  Comment


                  • #10
                    Well, here's the latest.

                    I discovered that one of the third-party programs that I'll be working with already uses 34000 for UDP communications! Therefore the direction is now set!

                    Originally posted by John Petty View Post
                    Here is a very simple TCP server DLL that allows control of and reporting on a VB6 program. The VB6 program just calls StartTCP passing a Callback address. The StartTCP Sub just starts a MODELESS (most important for a TCP server) hidden Dialog, the TCP and returns to VB6. When the VB6 prog is closing down it just calls CloseTCP which closes the Dialog and TCP server.
                    External program (over Internet or LAN) simply connect to the TCP server and send a brief message. Depending on the message it either sends a control code back to the VB6 prog Callback or returns info to the caller.
                    The port number you use is your own choice, preferably not a commonly used one.
                    Well, that looks like as good of a starting point as any. I'll spend some time this weekend to digest it and reorganize it --that's how I learn how things work. I'll then rework it for UDP and use that as the basis for the final version. I do appreciate you taking the time to post the example as it will be most helpful!

                    Thank you to everyone for your comments and assistance!

                    Dan
                    www.thecomputerarchive.com Preserving the history of companies that advanced the computer revolution

                    Comment


                    • #11
                      Hi Dan
                      Working with UDP is somewhat different as it is connectionless, which apart from meaning delivery is not guaranteed means you just can’t send a reply like the TCP server can. However it does give you the IP address of the sending computer so if you want to send information back then you just do a UDP Send. To illustrate here are some fragments from a private network DNS server I wrote a few years ago.
                      Code:
                      ‘ union for converting long IP to dotted IP
                      UNION LtoB
                          l AS LONG
                          b(3) AS BYTE
                      END UNION
                      
                      ‘ set up the window to receive messages
                          DIALOG SHOW MODELESS hdlg, CALL GotUdt 'create a window to receive messages
                          UDP OPEN PORT 13000 AS #1           'open a udp port to receive registrations
                          UDP NOTIFY #1, RECV TO hdlg AS 888  'and have it notify when a message is received
                      
                      ‘ receive a message and reset for next
                      CALLBACK FUNCTION GotUdt()
                          SELECT CASE CBMSG
                              CASE 888
                                  UDP RECV #1, FROM ip.l, pnumvar&, MyName$   'receive a registration
                                  'and extract the senders IP from the packet header and convert to dotted notation adding to registration string
                                  NewText$ = MyName$ + " " + FORMAT$(ip.b(0)) + "." + FORMAT$(ip.b(1)) + "." + FORMAT$(ip.b(2)) + "." + FORMAT$(ip.b(3))
                                  y& = INSTR(MyName$," on ")
                                  t$ = LEFT$(MyName$, y& - 1) 'extract the name from the string which also contains date etc
                                  l& = LEN(t$)
                                  FOR y& = 0 TO ccnt - 1
                                      IF LEFT$(comps(y&),l&) = t$ THEN EXIT FOR   'check if name already registered
                                      'note this test is case sensitive as it assumes you will never change the name
                                      'being transmitted by the registration program
                                  NEXT
                                  IF y& < ccnt THEN
                                      comps(y&) = newtext$    'yes so just replace current reg with new
                                  ELSE
                                      comps(ccnt) = newtext$  'no so create a new registration
                                      ccnt = ccnt + 1
                                      REDIM PRESERVE comps(ccnt)
                                  END IF
                                  LISTBOX RESET hdlg, 1
                                  FOR y& = 0 TO ccnt - 1
                                      LISTBOX ADD hdlg, 1, comps(y&)
                                  NEXT
                                  UDP CLOSE #1
                                  SLEEP 500
                                  UDP OPEN PORT 13000 AS #1
                                  UDP NOTIFY #1, RECV TO hdlg AS 888
                      
                      ‘*********** the sending program just sends it data at a regular period
                          UDP OPEN AS #1
                          EndlessLoop:
                              Stext$ = compnme$ + " on " + DATE$ + " at " + TIME$ 
                              “the sending IP number is by the name server
                              'when it receives the packet
                              UDP SEND #1, AT ip.l, 13000, stext$
                      	'note ip.l is a long not dotted format
                              'I use port 13000, you can choose any port number that is not already used on the
                              'computer running the name server, of course you need to set your name server
                              'to receive on that port
                              SLEEP tme&
                          GOTO EndlessLoop
                          UDP CLOSE #1
                      ‘ *******************

                      Comment

                      Working...
                      X