Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

COM Communication Relay between Apps

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

  • PBWin COM Communication Relay between Apps

    Click image for larger version  Name:	New Bitmap Image.jpg Views:	0 Size:	122.6 KB ID:	788755

    This pair of apps and a DLL have been constructed to share data via a COM interface. The COM instance variable
    uses a Shared Memory Mapped location so each app can access the data. The Shared Memory Mapped data size
    is set to 3MB. Currently only tested to 160 KB.

    If you want to go higher you will have to modify the textboxes to handle 2 MB.
    Easy fix:
    Code:
    SendMessageA GetDlgItem(hDlg, %IDC_TxtBox1), %EM_SETLIMITTEXT, &H200000&, 0 'set text limit to 2 Meg
    SendMessageA GetDlgItem(hDlg, %IDC_TxtBox2), %EM_SETLIMITTEXT, &H200000&, 0 'set text limit to 2 Meg
    Even though the apps are named Host App and Client App they each have the same capability. The names were
    chosen so that FindWindow could identify them easily.

    No timing code used to periodically capture the targeted message.
    The read data signal is issued via RegisterWindowMessageA.

    No app registration in registry for COM.

    Not seen in the screen capture is the Loop Test button that will send a "LOOPTEST" message which is responded
    to by the sister app.

    Button description:
    DLL Test - Validates that the DLL is there and the Status EVENTS are working.
    Test LoopBack - Validates that the loopback Events are working.
    Reset Text - Refreshes the editable text on the left and clears the text on the right.
    Test Message - Sends a simple built-in message to the sister app and clears the text on the right.
    Send Message - Sends the text on the left to the sister app and clears the text on the right.
    Test Loop - Sends a LOOPTEST to the sister app and clears the text on the right. If the LOOPTEST is processed by the sister app then it displays LOOPTEST on the right and sends a short validation message back to the message originator that the Loop Test was successful. Very
    Yes, you can type in LOOPTEST on the left and press Send Message.

    Note:
    The apps were built and tested in the same folder but they do not have to remain there. If you move the apps away from the DLL all you have to do is update the Link to the DLL. Very Easy with this line:
    Code:
     
    LET oTest = NEWCOM CLSID $CLSID_MYCLASS LIB EXE.PATH$ + "DispatchServer.dll"
    Sorry all the formatting was lost when posting.
    To answer your question "Yes, this feature will be added to xBot."

    Say you have one Host app and multiple Client apps named differently. The current code is not designed for that although it could be easily modified to do that. The DLL instance variable is not consumed by a read operation so multiple clients could read the same info. You could also target individual clients via a message header and different registered messages. "The sky is the limit."

    If you have multiple Clients up with the same names then these apps can do that. Be advised the clearing of the right textbox is controlled by the button clicks on only the app that executed the button push unless the app received an incoming message.

    For your convenience in zip but did not include DispatchServer.tlb.



    COM_Relay.zip
    Attached Files
    Last edited by Jim Fritts; 17 Jan 2020, 08:22 PM.

  • #2
    Host App:
    Code:
    '==============================================================================
    '
    ' Loosely based on:
    ' Direct.bas example for PowerBASIC For Windows Compiler
    '
    ' 1) Demonstrates raising events in a dispatch event interface for
    ' DLL test and Test Loopback.
    '
    ' 2) Demonstrates storing the COM string instance variable in a Shared Memory
    ' Mapped area so App_1 and App_2 can retrieve a message via COM. Allows
    ' message to be up to 3 MB in size.
    '
    ' 3) Demonstrates inner system messaging to signal the other app to read
    ' its COM message.
    '
    ' 4) No timer needed.
    '
    '==============================================================================
    ' In-Process Communications App for Host App_1
    '==============================================================================
    'Compilable Example:
    #COMPILER PBWIN 10
    #COMPILE EXE "App_1.exe"
    #DIM ALL
    
    GLOBAL hDlg AS DWORD
    GLOBAL hWnd2 AS DWORD
    GLOBAL iRet AS LONG
    GLOBAL oTest AS ITest ' Object reference to the ITest Interface
    GLOBAL oStatus AS DISPATCH ' Dispatch Object reference to the IStatus event Interface
    GLOBAL oRecv AS DISPATCH ' Dispatch Object reference to the IStatusHost Interface
    
    GLOBAL MyMessage AS STRING
    
    'Notification message for app to read the Shared Memory Mapped COM string
    $MESSAGE_NAME_1 = "abcdedjdsj8489327483498294829" ' Host notification
    $MESSAGE_NAME_2 = "abcdedjdsj8489327483498294830" ' Client notification
    GLOBAL IMSG_1 AS DWORD
    GLOBAL IMSG_2 AS DWORD
    
    %HWND_BROADCAST = &HFFFFFFFF???
    
    ENUM Equates SINGULAR
    IDC_TxtBox1
    IDC_TxtBox2
    IDC_Button1
    IDC_Button2
    IDC_ButtonTest
    IDC_ButtonReset
    IDC_Button3
    IDC_ButtonLoop
    END ENUM
    
    DECLARE FUNCTION RegisterWindowMessageA IMPORT "USER32.DLL" ALIAS "RegisterWindowMessageA" ( _
    BYREF lpString AS ASCIIZ _ ' __in LPCSTR lpString
    ) AS DWORD ' UINT
    
    DECLARE FUNCTION FindWindowA IMPORT "USER32.DLL" ALIAS "FindWindowA" ( _
    OPTIONAL BYREF lpClassName AS ASCIIZ _ ' __in_opt LPCSTR lpClassName
    , OPTIONAL BYREF lpWindowName AS ASCIIZ _ ' __in_opt LPCSTR lpWindowName
    ) AS DWORD ' HWND
    
    DECLARE FUNCTION SendMessageA IMPORT "USER32.DLL" ALIAS "SendMessageA" ( _
    BYVAL hWnd AS DWORD _ ' __in HWND hWnd
    , BYVAL Msg AS DWORD _ ' __in UINT Msg
    , BYVAL wParam AS DWORD _ ' __in WPARAM wParam
    , BYVAL lParam AS LONG _ ' __in LPARAM lParam
    ) AS LONG ' LRESULT
    
    DECLARE FUNCTION GetLastError IMPORT "KERNEL32.DLL" ALIAS "GetLastError" ( _
    ) AS DWORD ' DWORD
    
    DECLARE FUNCTION PostMessageA IMPORT "USER32.DLL" ALIAS "PostMessageA" ( _
    BYVAL hWnd AS DWORD _ ' __in_opt HWND hWnd
    , BYVAL Msg AS DWORD _ ' __in UINT Msg
    , BYVAL wParam AS DWORD _ ' __in WPARAM wParam
    , BYVAL lParam AS LONG _ ' __in LPARAM lParam
    ) AS LONG ' BOOL
    
    '/////////////////////////////////////////////////////
    'START OF COM REFERENCES
    '/////////////////////////////////////////////////////
    ' Class Identifiers
    $CLSID_MYCLASS = GUID$("{00000098-0000-0000-0000-000000000003}")
    $CLSID_EvClassGuid = GUID$("{00000098-0000-0000-0000-000000000001}")
    $CLSID_EvClassHost = GUID$("{00000098-0000-0000-0000-000000000101}")
    $CLSID_EvClassClient = GUID$("{00000098-0000-0000-0000-000000000201}")
    
    ' Interface Identifiers
    $IID_MYTEST = GUID$("{00000098-0000-0000-0000-000000000004}")
    $IID_STATUS = GUID$("{00000098-0000-0000-0000-000000000002}")
    $IID_STATUSHOST = GUID$("{00000098-0000-0000-0000-000000000021}")
    $IID_STATUSCLIENT = GUID$("{00000098-0000-0000-0000-000000000022}")
    
    INTERFACE ITest $IID_MYTEST
    INHERIT IDISPATCH
    METHOD DoTest
    PROPERTY GET ForClient <100> () AS STRING
    PROPERTY SET ForClient <100> (BYVAL ForClientString AS STRING)
    PROPERTY GET ForHost <101> () AS STRING
    PROPERTY SET ForHost <101> (BYVAL ForHostString AS STRING)
    END INTERFACE
    
    ' The Event handler classes
    ' This class is called from Event Source class
    CLASS EvClass $CLSID_EvClassGuid AS EVENT
    INTERFACE IStatus $IID_STATUS AS EVENT
    INHERIT IDISPATCH
    
    ' Event method called by Object Raiseevent IStatus.Done()
    METHOD Done
    CONTROL SET TEXT hDlg, %IDC_TxtBox1, "The DLL is functioning!"
    END METHOD
    
    END INTERFACE
    
    END CLASS
    
    CLASS EvClassHost $CLSID_EvClassHost AS EVENT
    INTERFACE IStatusHost $IID_STATUSHOST AS EVENT
    INHERIT IDISPATCH
    
    METHOD LoopBack
    CONTROL SET TEXT hDlg, %IDC_TxtBox1, "Confirmed Loopback!"
    END METHOD
    
    END INTERFACE
    
    END CLASS
    
    '/////////////////////////////////////////////////////
    'END OF COM REFERENCES
    '/////////////////////////////////////////////////////
    
    FUNCTION PBMAIN() AS LONG
    MyMessage = $CRLF & _
    "Host Message." & $CRLF & $CRLF & _
    " 1) Demonstrates raising events in a dispatch" & $CRLF & _
    " event interface for DLL test and Test Loopback." & $CRLF & $CRLF & _
    " 2) Demonstrates storing the COM string instance" & $CRLF & _
    " variable in a Shared Memory Mapped area so" & $CRLF & _
    " App_1 and App_2 can retrieve a message via" & $CRLF & _
    " COM. Allows messages up to 3 MB in size." & $CRLF & $CRLF & _
    " 3) Demonstrates inner system messaging to" & $CRLF & _
    " signal the other app to read its COM message." & $CRLF & $CRLF & _
    " 4) No timer needed."
    
    IMSG_1 = RegisterWindowMessageA ($MESSAGE_NAME_1) ' for host
    IMSG_2 = RegisterWindowMessageA ($MESSAGE_NAME_2) ' for client
    
    LET oTest = NEWCOM CLSID $CLSID_MYCLASS LIB EXE.PATH$ + "DispatchServer.dll"
    
    IF ISOBJECT(oTest) THEN
    oStatus = CLASS "EvClass" ' Create an instance of the EvClass object
    oRecv = CLASS "EvClassHost"
    
    ' Connect the event handler interface to the event source Interface
    EVENTS FROM oTest CALL oStatus
    EVENTS FROM oTest CALL oRecv
    END IF
    
    DIALOG NEW PIXELS, 0, "Host App",300,300,670,220, %WS_OVERLAPPEDWINDOW TO hDlg
    CONTROL ADD TEXTBOX, hDlg, %IDC_TxtBox1,"", 120 + 270,10,270,200, _
    %WS_CHILD OR %WS_VISIBLE OR _
    %ES_AUTOHSCROLL OR %WS_HSCROLL OR %WS_VSCROLL OR %ES_AUTOVSCROLL OR _
    %ES_NOHIDESEL OR %ES_READONLY OR %ES_MULTILINE OR %WS_BORDER
    
    CONTROL ADD TEXTBOX, hDlg, %IDC_TxtBox2, MyMessage, 10,10,270,200, _
    %WS_CHILD OR %WS_VISIBLE OR _
    %ES_AUTOHSCROLL OR %WS_HSCROLL OR %WS_VSCROLL OR %ES_AUTOVSCROLL OR _
    %ES_NOHIDESEL OR %ES_MULTILINE OR %WS_BORDER OR _
    %ES_WANTRETURN
    
    CONTROL ADD BUTTON, hDlg, %IDC_Button1,"Dll Test", 10 + 275,10,100,20
    CONTROL ADD BUTTON, hDlg, %IDC_Button2,"Test Loopback", 10 + 275,40,100,20
    CONTROL ADD BUTTON, hDlg, %IDC_ButtonReset,"Reset Text", 10 + 275,70,100,20
    
    CONTROL ADD BUTTON, hDlg, %IDC_ButtonTest,"Test Message", 10 + 275,120,100,20
    CONTROL ADD BUTTON, hDlg, %IDC_Button3,"Send Message", 10 + 275,150,100,20
    CONTROL ADD BUTTON, hDlg, %IDC_ButtonLoop,"Loop Test", 10 + 275,180,100,20
    DIALOG SHOW MODAL hDlg CALL DlgProc
    
    ' Disconnect the event handler interface from the event source Interface
    EVENTS END oStatus
    EVENTS END oRecv
    oTest = NOTHING
    oStatus = NOTHING
    oRecv = NOTHING
    
    END FUNCTION
    
    CALLBACK FUNCTION DlgProc() AS LONG
    SELECT CASE CB.MSG
    CASE IMSG_1
    IF ISOBJECT(oTest) THEN
    LOCAL MyString AS STRING
    oTest.ForHost() TO MyString
    CONTROL SET TEXT hDlg, %IDC_TxtBox1, MyString
    IF MyString = "LOOPTEST" THEN
    MyMessage = "The loop test relay was successful!"
    oTest.ForClient() = MyMessage
    hWnd2 = FindWindowA("", "Client App")
    IF hWnd2 THEN
    'tell app_2 to read its COM message
    iRet = PostMessageA (%HWND_BROADCAST, IMSG_2, 4, 7) 'iRet = 5 = access denied but still works
    ELSE
    'do nothing
    END IF
    END IF
    ELSE
    ? "error"
    END IF
    
    CASE %WM_INITDIALOG
    
    CASE %WM_COMMAND
    SELECT CASE CB.CTL
    
    CASE %IDC_Button1
    
    IF ISOBJECT(oTest) THEN
    
    ' Call the DoTest method in ITest Interface
    oTest.DoTest
    
    ELSE
    ? "error"
    END IF
    
    CASE %IDC_Button2
    IF ISOBJECT(oTest) THEN
    CALL oTest.ForClient() = "LOOPBACK"
    ELSE
    ? "error"
    END IF
    
    CASE %IDC_ButtonReset
    MyMessage = $CRLF & _
    "Host Message." & $CRLF & $CRLF & _
    " 1) Demonstrates raising events in a dispatch" & $CRLF & _
    " event interface for DLL test and Test Loopback." & $CRLF & $CRLF & _
    " 2) Demonstrates storing the COM string instance" & $CRLF & _
    " variable in a Shared Memory Mapped area so" & $CRLF & _
    " App_1 and App_2 can retrieve a message via" & $CRLF & _
    " COM. Allows messages up to 3 MB in size." & $CRLF & $CRLF & _
    " 3) Demonstrates inner system messaging to" & $CRLF & _
    " signal the other app to read its COM message." & $CRLF & $CRLF & _
    " 4) No timer needed."
    CONTROL SET TEXT hDlg, %IDC_TxtBox2, ""
    CONTROL SET TEXT hDlg, %IDC_TxtBox2, MyMessage
    CONTROL SET TEXT hDlg, %IDC_TxtBox1, ""
    
    CASE %IDC_ButtonTest
    CONTROL SET TEXT hDlg, %IDC_TxtBox1,""
    IF ISOBJECT(oTest) THEN
    MyMessage = "This is a simple test message from the Host."
    oTest.ForClient() = MyMessage
    hWnd2 = FindWindowA("", "Client App")
    IF hWnd2 THEN
    'tell app_2 to read its COM message
    iRet = PostMessageA (%HWND_BROADCAST, IMSG_2, 4, 7) 'iRet = 5 = access denied but still works
    ELSE
    'do nothing
    END IF
    ELSE
    ? "error"
    END IF
    
    CASE %IDC_Button3
    CONTROL SET TEXT hDlg, %IDC_TxtBox1,""
    IF ISOBJECT(oTest) THEN
    CONTROL GET TEXT hDlg, %IDC_TxtBox2 TO MyMessage
    oTest.ForClient() = MyMessage
    hWnd2 = FindWindowA("", "Client App")
    IF hWnd2 THEN
    'tell app_2 to read its COM message
    iRet = PostMessageA (%HWND_BROADCAST, IMSG_2, 4, 7) 'iRet = 5 = access denied but still works
    ELSE
    'do nothing
    END IF
    ELSE
    ? "error"
    END IF
    
    CASE %IDC_ButtonLoop
    CONTROL SET TEXT hDlg, %IDC_TxtBox1,""
    IF ISOBJECT(oTest) THEN
    oTest.ForClient() = "LOOPTEST"
    hWnd2 = FindWindowA("", "Client App")
    IF hWnd2 THEN
    'tell app_2 to read its COM message
    iRet = PostMessageA (%HWND_BROADCAST, IMSG_2, 4, 7) 'iRet = 5 = access denied but still works
    ELSE
    'do nothing
    END IF
    ELSE
    ? "error"
    END IF
    END SELECT
    END SELECT
    END FUNCTION

    Comment


    • #3
      Dll:
      Code:
      '==============================================================================
      '
      ' Loosely based on:
      ' Direct.bas example for PowerBASIC For Windows Compiler
      '
      ' 1) Demonstrates raising events in a dispatch event interface for
      ' DLL test and Test Loopback.
      '
      ' 2) Demonstrates storing the COM string instance variable in a Shared Memory
      ' Mapped area so App_1 and App_2 can retrieve a message via COM. Allows
      ' message to be up to 3 MB in size.
      '
      ' 3) Demonstrates inner system messaging to signal the other app to read
      ' its COM message.
      '
      ' 4) No timer needed.
      '
      '==============================================================================
      ' COM Dispatch Server
      '==============================================================================
      
      'Compilable Example:
      #COMPILE DLL "DispatchServer.dll"
      #DIM ALL
      
      #OPTION ANSIAPI 'No UNICODE internal processes
      
      '$MyAppGuid = GUID$("{FE3984DB-8B6C-4299-AA0F-F80EA67EDEDD}") 'fixed GUID
      
      '#COM GUID $MyAppGuid
      'If no GUID is specified, PowerBASIC substitutes a random GUID for this purpose.
      'Specifies the GUID which identifies the entire application or library.
      
      
      'START OF COM REFERENCES
      '/////////////////////////////////////////////////////
      #COM NAME "DispatchServer", 1
      #COM DOC "Dispatch COM Server"
      #COM TLIB ON
      #RESOURCE TYPELIB, 1, "DispatchServer.tlb"
      
      #INCLUDE ONCE "Win32API.inc"
      
      ' Class Identifiers
      $CLSID_MYCLASS = GUID$("{00000098-0000-0000-0000-000000000003}")
      $CLSID_EvClassGuid = GUID$("{00000098-0000-0000-0000-000000000001}")
      $CLSID_EvClassHost = GUID$("{00000098-0000-0000-0000-000000000101}")
      $CLSID_EvClassClient = GUID$("{00000098-0000-0000-0000-000000000201}")
      
      ' Interface Identifiers
      $IID_MYTEST = GUID$("{00000098-0000-0000-0000-000000000004}")
      $IID_STATUS = GUID$("{00000098-0000-0000-0000-000000000002}")
      $IID_STATUSHOST = GUID$("{00000098-0000-0000-0000-000000000021}")
      $IID_STATUSCLIENT = GUID$("{00000098-0000-0000-0000-000000000022}")
      
      INTERFACE IStatus AS EVENT
      INHERIT IDISPATCH
      METHOD Done
      END INTERFACE
      
      INTERFACE IStatusClient $IID_STATUSCLIENT AS EVENT
      INHERIT IDISPATCH
      METHOD LoopBack
      END INTERFACE
      
      INTERFACE IStatusHost $IID_STATUSHOST AS EVENT
      INHERIT IDISPATCH
      METHOD LoopBack
      END INTERFACE
      
      ' Event source class
      ' This class calls the IStatus Event Interface
      CLASS MyClass $CLSID_MYCLASS AS COM
      
      INTERFACE ITest $IID_MYTEST
      INHERIT IDISPATCH
      
      METHOD DoTest
      ' Call the event handler when calculations have completed.
      OBJECT RAISEEVENT IStatus.Done()
      END METHOD
      
      PROPERTY GET ForClient <100> () AS STRING
      PROPERTY = GetSharedString()
      END PROPERTY
      
      PROPERTY SET ForClient <100> (BYVAL value AS STRING)
      SetSharedString(value) ' set changed shared string
      
      IF value = "LOOPBACK" THEN
      OBJECT RAISEEVENT IStatusHost.LoopBack()
      ELSE
      'do nothing
      END IF
      
      END PROPERTY
      
      PROPERTY GET ForHost <101> () AS STRING
      PROPERTY = GetSharedString()
      END PROPERTY
      
      PROPERTY SET ForHost <101> (BYVAL value AS STRING)
      SetSharedString(value) ' set changed shared string
      
      IF value = "LOOPBACK" THEN
      'testing return to client
      OBJECT RAISEEVENT IStatusClient.LoopBack()
      ELSE
      'do nothing
      END IF
      END PROPERTY
      
      END INTERFACE
      
      ' Declare an event interface to be called by Object RaiseEvent by the server
      EVENT SOURCE DISPATCH
      
      END CLASS
      
      'END OF COM REFERENCES
      '/////////////////////////////////////////////////////
      
      '====================================================================
      
      %SHMEMSIZE = 3000000 ' 2 MB + room for extra, change to own liking
      GLOBAL pzString AS ASCIIZ PTR
      
      '====================================================================
      ' DLL main..
      '--------------------------------------------------------------------
      FUNCTION LIBMAIN (BYVAL hInstance AS DWORD, _
      BYVAL fwdReason AS LONG, _
      BYVAL lpvReserved AS LONG) AS LONG
      
      LOCAL hMapObj AS DWORD
      
      SELECT CASE fwdReason
      CASE %DLL_PROCESS_ATTACH
      hMapObj = CreateFileMapping(BYVAL -1, BYVAL %Null, _
      BYVAL %PAGE_READWRITE, _
      BYVAL 0, %SHMEMSIZE, "myDllMemFilemap")
      IF hMapObj THEN
      pzString = MapViewOfFile (hMapObj, BYVAL %FILE_MAP_ALL_ACCESS, 0, 0, 0)
      IF pzString THEN FUNCTION = 1
      END IF
      
      CASE %DLL_PROCESS_DETACH
      IF pzString THEN UnMapViewOfFile(pzString)
      IF hMapObj THEN CloseHandle(hMapObj)
      FUNCTION = 1
      
      CASE %DLL_THREAD_ATTACH : FUNCTION = 1
      CASE %DLL_THREAD_DETACH : FUNCTION = 1
      END SELECT
      END FUNCTION
      
      '====================================================================
      ' Set string for further processing
      '--------------------------------------------------------------------
      SUB SetSharedString ALIAS "SetSharedString" (BYVAL sText AS STRING) EXPORT
      @pzString = sText '@pzString is now a max %SHMEMSIZE byte global string
      END SUB
      
      '====================================================================
      ' Return processed string
      '--------------------------------------------------------------------
      FUNCTION GetSharedString ALIAS "GetSharedString" () EXPORT AS STRING
      FUNCTION = @pzString
      END FUNCTION
      Last edited by Jim Fritts; 17 Jan 2020, 05:50 PM.

      Comment


      • #4
        See Post #1 for full details and zip file.

        Client App:
        Code:
        '==============================================================================
        '
        ' Loosely based on:
        ' Direct.bas example for PowerBASIC For Windows Compiler
        '
        ' 1) Demonstrates raising events in a dispatch event interface for
        ' DLL test and Test Loopback.
        '
        ' 2) Demonstrates storing the COM string instance variable in a Shared Memory
        ' Mapped area so App_1 and App_2 can retrieve a message via COM. Allows
        ' message to be up to 3 MB in size.
        '
        ' 3) Demonstrates inner system messaging to signal the other app to read
        ' its COM message.
        '
        ' 4) No timer needed.
        '
        '==============================================================================
        ' In-Process Communications App for Client App_2
        '==============================================================================
        'Compilable Example:
        #COMPILER PBWIN 10
        #COMPILE EXE "App_2.exe"
        #DIM ALL
        
        GLOBAL hDlg AS DWORD
        GLOBAL hWnd1 AS DWORD
        GLOBAL iRet AS LONG
        GLOBAL oTest AS ITest ' Object reference to the ITest Interface
        GLOBAL oStatus AS DISPATCH ' Dispatch Object reference to the IStatus event Interface
        GLOBAL oRecv AS DISPATCH ' Object reference to the IStatusHost Interface
        
        GLOBAL MyMessage AS STRING
        
        'Notification message for app to read the Shared Memory Mapped COM string
        $MESSAGE_NAME_1 = "abcdedjdsj8489327483498294829" ' Host notification
        $MESSAGE_NAME_2 = "abcdedjdsj8489327483498294830" ' Client notification
        GLOBAL IMSG_1 AS DWORD
        GLOBAL IMSG_2 AS DWORD
        
        %HWND_BROADCAST = &HFFFFFFFF???
        
        ENUM Equates SINGULAR
        IDC_TxtBox1
        IDC_TxtBox2
        IDC_Button1
        IDC_Button2
        IDC_ButtonReset
        IDC_ButtonTest
        IDC_Button3
        IDC_ButtonLoop
        END ENUM
        
        DECLARE FUNCTION RegisterWindowMessageA IMPORT "USER32.DLL" ALIAS "RegisterWindowMessageA" ( _
        BYREF lpString AS ASCIIZ _ ' __in LPCSTR lpString
        ) AS DWORD ' UINT
        
        DECLARE FUNCTION FindWindowA IMPORT "USER32.DLL" ALIAS "FindWindowA" ( _
        OPTIONAL BYREF lpClassName AS ASCIIZ _ ' __in_opt LPCSTR lpClassName
        , OPTIONAL BYREF lpWindowName AS ASCIIZ _ ' __in_opt LPCSTR lpWindowName
        ) AS DWORD ' HWND
        
        DECLARE FUNCTION SendMessageA IMPORT "USER32.DLL" ALIAS "SendMessageA" ( _
        BYVAL hWnd AS DWORD _ ' __in HWND hWnd
        , BYVAL Msg AS DWORD _ ' __in UINT Msg
        , BYVAL wParam AS DWORD _ ' __in WPARAM wParam
        , BYVAL lParam AS LONG _ ' __in LPARAM lParam
        ) AS LONG ' LRESULT
        
        DECLARE FUNCTION GetLastError IMPORT "KERNEL32.DLL" ALIAS "GetLastError" ( _
        ) AS DWORD ' DWORD
        
        DECLARE FUNCTION PostMessageA IMPORT "USER32.DLL" ALIAS "PostMessageA" ( _
        BYVAL hWnd AS DWORD _ ' __in_opt HWND hWnd
        , BYVAL Msg AS DWORD _ ' __in UINT Msg
        , BYVAL wParam AS DWORD _ ' __in WPARAM wParam
        , BYVAL lParam AS LONG _ ' __in LPARAM lParam
        ) AS LONG ' BOOL
        
        'START OF COM REFERENCES
        '/////////////////////////////////////////////////////
        
        ' Class Identifiers
        $CLSID_MYCLASS = GUID$("{00000098-0000-0000-0000-000000000003}")
        $CLSID_EvClassGuid = GUID$("{00000098-0000-0000-0000-000000000001}")
        $CLSID_EvClassHost = GUID$("{00000098-0000-0000-0000-000000000101}")
        $CLSID_EvClassClient = GUID$("{00000098-0000-0000-0000-000000000201}")
        
        ' Interface Identifiers
        $IID_MYTEST = GUID$("{00000098-0000-0000-0000-000000000004}")
        $IID_STATUS = GUID$("{00000098-0000-0000-0000-000000000002}")
        $IID_STATUSHOST = GUID$("{00000098-0000-0000-0000-000000000021}")
        $IID_STATUSCLIENT = GUID$("{00000098-0000-0000-0000-000000000022}")
        
        INTERFACE ITest $IID_MYTEST
        INHERIT IDISPATCH
        METHOD DoTest
        PROPERTY GET ForClient <100> () AS STRING
        PROPERTY SET ForClient <100> (BYVAL ForClientString AS STRING)
        PROPERTY GET ForHost <101> () AS STRING
        PROPERTY SET ForHost <101> (BYVAL ForHostString AS STRING)
        END INTERFACE
        
        ' The Event handler class
        ' This class is called from Event Source class
        CLASS EvClass $CLSID_EvClassGuid AS EVENT
        INTERFACE IStatus $IID_STATUS AS EVENT
        INHERIT IDISPATCH
        
        ' Event method called by Object Raiseevent IStatus.Done()
        METHOD Done
        CONTROL SET TEXT hDlg, %IDC_TxtBox1, "The DLL is functioning!"
        END METHOD
        
        END INTERFACE
        
        END CLASS
        
        CLASS EvClassClient $CLSID_EvClassClient AS EVENT
        INTERFACE IStatusClient $IID_STATUSCLIENT AS EVENT
        INHERIT IDISPATCH
        
        METHOD LoopBack
        CONTROL SET TEXT hDlg, %IDC_TxtBox1, "Confirmed Loopback!"
        END METHOD
        
        END INTERFACE
        
        END CLASS
        
        'END OF COM REFERENCES
        '/////////////////////////////////////////////////////
        
        FUNCTION PBMAIN() AS LONG
        MyMessage = $CRLF & _
        "Client Message." & $CRLF & $CRLF & _
        " 1) Demonstrates raising events in a dispatch" & $CRLF & _
        " event interface for DLL test and Test Loopback." & $CRLF & $CRLF & _
        " 2) Demonstrates storing the COM string instance" & $CRLF & _
        " variable in a Shared Memory Mapped area so" & $CRLF & _
        " App_1 and App_2 can retrieve a message via" & $CRLF & _
        " COM. Allows messages up to 3 MB in size." & $CRLF & $CRLF & _
        " 3) Demonstrates inner system messaging to" & $CRLF & _
        " signal the other app to read its COM message." & $CRLF & $CRLF & _
        " 4) No timer needed. "
        
        LET oTest = NEWCOM CLSID $CLSID_MYCLASS LIB EXE.PATH$ + "DispatchServer.dll"
        
        IMSG_1 = RegisterWindowMessageA ($MESSAGE_NAME_1) ' for host
        IMSG_2 = RegisterWindowMessageA ($MESSAGE_NAME_2) ' for client
        
        IF ISOBJECT(oTest) THEN
        oStatus = CLASS "EvClass" ' Create an instance of the EvClass object
        oRecv = CLASS "EvClassClient"
        
        ' Connect the event handler interface to the event source Interface
        EVENTS FROM oTest CALL oStatus
        EVENTS FROM oTest CALL oRecv
        END IF
        
        DIALOG NEW PIXELS, 0, "Client App",300,300,670,220, %WS_OVERLAPPEDWINDOW TO hDlg
        CONTROL ADD TEXTBOX, hDlg, %IDC_TxtBox1,"", 120 + 270,10,270,200, _
        %WS_CHILD OR %WS_VISIBLE OR _
        %ES_AUTOHSCROLL OR %WS_HSCROLL OR %WS_VSCROLL OR %ES_AUTOVSCROLL OR _
        %ES_NOHIDESEL OR %ES_READONLY OR %ES_MULTILINE OR %WS_BORDER
        
        CONTROL ADD TEXTBOX, hDlg, %IDC_TxtBox2, MyMessage, 10,10,270,200, _
        %WS_CHILD OR %WS_VISIBLE OR _
        %ES_AUTOHSCROLL OR %WS_HSCROLL OR %WS_VSCROLL OR %ES_AUTOVSCROLL OR _
        %ES_NOHIDESEL OR %ES_MULTILINE OR %WS_BORDER OR _
        %ES_WANTRETURN
        
        CONTROL ADD BUTTON, hDlg, %IDC_Button1,"Dll Test", 10 + 275,10,100,20
        CONTROL ADD BUTTON, hDlg, %IDC_Button2,"Test Loopback", 10 + 275,40,100,20
        CONTROL ADD BUTTON, hDlg, %IDC_ButtonReset,"Reset Text", 10 + 275,70,100,20
        
        CONTROL ADD BUTTON, hDlg, %IDC_ButtonTest,"Test Message", 10 + 275,120,100,20
        CONTROL ADD BUTTON, hDlg, %IDC_Button3,"Send Message", 10 + 275,150,100,20
        CONTROL ADD BUTTON, hDlg, %IDC_ButtonLoop,"Loop Test", 10 + 275,180,100,20
        DIALOG SHOW MODAL hDlg CALL DlgProc
        
        ' Disconnect the event handler interface from the event source Interface
        EVENTS END oStatus
        EVENTS END oRecv
        oTest = NOTHING
        oStatus = NOTHING
        oRecv = NOTHING
        
        END FUNCTION
        
        CALLBACK FUNCTION DlgProc() AS LONG
        SELECT CASE CB.MSG
        CASE IMSG_2
        IF ISOBJECT(oTest) THEN
        LOCAL MyString AS STRING
        oTest.ForClient() TO MyString
        CONTROL SET TEXT hDlg, %IDC_TxtBox1, MyString
        IF MyString = "LOOPTEST" THEN
        MyMessage = "The loop test relay was successful!"
        oTest.ForHost() = MyMessage
        hWnd1 = FindWindowA("", "Host App")
        IF hWnd1 THEN
        'tell app_1 to read its COM message
        iRet = PostMessageA (%HWND_BROADCAST, IMSG_1, 4, 7) 'iRet = 5 = access denied but still works
        ELSE
        'do nothing
        END IF
        END IF
        ELSE
        ? "error"
        END IF
        
        CASE %WM_INITDIALOG
        
        CASE %WM_COMMAND
        SELECT CASE CB.CTL
        
        CASE %IDC_Button1
        
        IF ISOBJECT(oTest) THEN
        
        ' Call the DoTest method in ITest Interface
        oTest.DoTest
        
        ELSE
        ? "error"
        END IF
        
        CASE %IDC_Button2
        IF ISOBJECT(oTest) THEN
        CALL oTest.ForHost() = "LOOPBACK"
        ELSE
        ? "error"
        END IF
        
        CASE %IDC_ButtonReset
        
        MyMessage = $CRLF & _
        "Client Message." & $CRLF & $CRLF & _
        " 1) Demonstrates raising events in a dispatch" & $CRLF & _
        " event interface for DLL test and Test Loopback." & $CRLF & $CRLF & _
        " 2) Demonstrates storing the COM string instance" & $CRLF & _
        " variable in a Shared Memory Mapped area so" & $CRLF & _
        " App_1 and App_2 can retrieve a message via" & $CRLF & _
        " COM. Allows messages up to 3 MB in size." & $CRLF & $CRLF & _
        " 3) Demonstrates inner system messaging to" & $CRLF & _
        " signal the other app to read its COM message." & $CRLF & $CRLF & _
        " 4) No timer needed. "
        CONTROL SET TEXT hDlg, %IDC_TxtBox2, ""
        CONTROL SET TEXT hDlg, %IDC_TxtBox2, MyMessage
        CONTROL SET TEXT hDlg, %IDC_TxtBox1, ""
        
        CASE %IDC_ButtonTest
        CONTROL SET TEXT hDlg, %IDC_TxtBox1,""
        IF ISOBJECT(oTest) THEN
        MyMessage = "This is a simple test message from the Client."
        oTest.ForHost() = MyMessage
        hWnd1 = FindWindowA("", "Host App")
        IF hWnd1 THEN
        'tell app_1 to read its COM message
        iRet = PostMessageA (%HWND_BROADCAST, IMSG_1, 4, 7) 'iRet = 5 = access denied but still works
        ELSE
        'do nothing
        END IF
        ELSE
        ? "error"
        END IF
        
        CASE %IDC_Button3
        CONTROL SET TEXT hDlg, %IDC_TxtBox1,""
        IF ISOBJECT(oTest) THEN
        CONTROL GET TEXT hDlg, %IDC_TxtBox2 TO MyMessage
        CALL oTest.ForHost() = MyMessage
        hWnd1 = FindWindowA("", "Host App")
        IF hWnd1 THEN
        'tell app_1 to read its COM message
        IMSG_1 = RegisterWindowMessageA ($MESSAGE_NAME_1)
        iRet = PostMessageA (%HWND_BROADCAST, IMSG_1, 4, 7) 'iRet = 5 = access denied but still works
        ELSE
        'do nothing
        END IF
        ELSE
        ? "error"
        END IF
        
        CASE %IDC_ButtonLoop
        CONTROL SET TEXT hDlg, %IDC_TxtBox1,""
        IF ISOBJECT(oTest) THEN
        oTest.ForHost() = "LOOPTEST"
        hWnd1 = FindWindowA("", "Host App")
        IF hWnd1 THEN
        'tell app_1 to read its COM message
        iRet = PostMessageA (%HWND_BROADCAST, IMSG_1, 4, 7) 'iRet = 5 = access denied but still works
        ELSE
        'do nothing
        END IF
        ELSE
        ? "error"
        END IF
        END SELECT
        END SELECT
        END FUNCTION
        Last edited by Jim Fritts; 17 Jan 2020, 04:26 PM.

        Comment


        • #5
          A simple listener app that is designed to just sit there waiting for a signal to read the COM stored message.
          Listen App:

          Code:
          '==============================================================================
          '
          ' Loosely based on:
          ' Direct.bas example for PowerBASIC For Windows Compiler
          '
          ' 1) Demonstrates a simple RegisterWindowMessage listener app.
          '
          ' 2) Will display a message that was ment for App_1 or App_2 by
          ' reading the COM stored message whenever signaled to read a
          ' message via RegisterWindowMessage.
          '
          ' 3) No timer needed.
          '
          ' 4) Does not respond to com events.
          '
          ' 5) Does not send any registered messages.
          '
          ' 6) Is not designed to replace either App_1 or App_2.
          '
          ' 7) Is a listener app not a traffic cop. Shhhh
          '
          '==============================================================================
          ' In-Process Communications Listener App for Host App_1 and Client App_2
          '==============================================================================
          'Compilable Example:
          #COMPILER PBWIN 10
          #COMPILE EXE "App_3.exe"
          #DIM ALL
          
          GLOBAL hDlg AS DWORD
          GLOBAL oTest AS ITest ' Object reference to the ITest Interface
          
          'Notification message for app to read the Shared Memory Mapped COM string
          $MESSAGE_NAME_1 = "abcdedjdsj8489327483498294829" ' Host notification
          $MESSAGE_NAME_2 = "abcdedjdsj8489327483498294830" ' Client notification
          GLOBAL IMSG_1 AS DWORD
          GLOBAL IMSG_2 AS DWORD
          
          %HWND_BROADCAST = &HFFFFFFFF???
          
          %EM_LIMITTEXT = &HC5
          %EM_SETLIMITTEXT = %EM_LIMITTEXT
          
          ENUM Equates SINGULAR
          IDC_TxtBox1
          END ENUM
          
          DECLARE FUNCTION RegisterWindowMessageA IMPORT "USER32.DLL" ALIAS "RegisterWindowMessageA" ( _
          BYREF lpString AS ASCIIZ _ ' __in LPCSTR lpString
          ) AS DWORD ' UINT
          
          'DECLARE FUNCTION FindWindowA IMPORT "USER32.DLL" ALIAS "FindWindowA" ( _
          ' OPTIONAL BYREF lpClassName AS ASCIIZ _ ' __in_opt LPCSTR lpClassName
          ' , OPTIONAL BYREF lpWindowName AS ASCIIZ _ ' __in_opt LPCSTR lpWindowName
          ' ) AS DWORD ' HWND
          
          DECLARE FUNCTION SendMessageA IMPORT "USER32.DLL" ALIAS "SendMessageA" ( _
          BYVAL hWnd AS DWORD _ ' __in HWND hWnd
          , BYVAL Msg AS DWORD _ ' __in UINT Msg
          , BYVAL wParam AS DWORD _ ' __in WPARAM wParam
          , BYVAL lParam AS LONG _ ' __in LPARAM lParam
          ) AS LONG ' LRESULT
          
          'DECLARE FUNCTION GetLastError IMPORT "KERNEL32.DLL" ALIAS "GetLastError" ( _
          ' ) AS DWORD ' DWORD
          '
          'DECLARE FUNCTION PostMessageA IMPORT "USER32.DLL" ALIAS "PostMessageA" ( _
          ' BYVAL hWnd AS DWORD _ ' __in_opt HWND hWnd
          ' , BYVAL Msg AS DWORD _ ' __in UINT Msg
          ' , BYVAL wParam AS DWORD _ ' __in WPARAM wParam
          ' , BYVAL lParam AS LONG _ ' __in LPARAM lParam
          ' ) AS LONG ' BOOL
          '
          DECLARE FUNCTION GetDlgItem IMPORT "USER32.DLL" ALIAS "GetDlgItem" ( _
          BYVAL hDlg AS DWORD _ ' __in_opt HWND hDlg
          , BYVAL nIDDlgItem AS LONG _ ' __in int nIDDlgItem
          ) AS DWORD ' HWND
          
          'START OF COM REFERENCES
          '/////////////////////////////////////////////////////
          
          ' Class Identifiers
          $CLSID_MYCLASS = GUID$("{00000098-0000-0000-0000-000000000003}")
          
          ' Interface Identifiers
          $IID_MYTEST = GUID$("{00000098-0000-0000-0000-000000000004}")
          
          INTERFACE ITest $IID_MYTEST
          INHERIT IDISPATCH
          METHOD DoTest
          
          PROPERTY GET ForClient <100> () AS STRING
          PROPERTY SET ForClient <100> (BYVAL ForClientString AS STRING)
          PROPERTY GET ForHost <101> () AS STRING
          PROPERTY SET ForHost <101> (BYVAL ForHostString AS STRING)
          END INTERFACE
          
          'END OF COM REFERENCES
          '/////////////////////////////////////////////////////
          
          FUNCTION PBMAIN() AS LONG
          
          LET oTest = NEWCOM CLSID $CLSID_MYCLASS LIB EXE.PATH$ + "DispatchServer.dll"
          
          IMSG_1 = RegisterWindowMessageA ($MESSAGE_NAME_1) ' for host
          IMSG_2 = RegisterWindowMessageA ($MESSAGE_NAME_2) ' for client
          
          DIALOG NEW PIXELS, 0, "Listen App",300,300,290,220, %WS_OVERLAPPEDWINDOW TO hDlg
          CONTROL ADD TEXTBOX, hDlg, %IDC_TxtBox1,"", 10,10,270,200, _
          %WS_CHILD OR %WS_VISIBLE OR _
          %ES_AUTOHSCROLL OR %WS_HSCROLL OR %WS_VSCROLL OR %ES_AUTOVSCROLL OR _
          %ES_NOHIDESEL OR %ES_READONLY OR %ES_MULTILINE OR %WS_BORDER
          
          SendMessageA GetDlgItem(hDlg, %IDC_TxtBox1), %EM_SETLIMITTEXT, &H200000&, 0 'set text limit to 2 Meg
          
          DIALOG SHOW MODAL hDlg CALL DlgProc
          
          oTest = NOTHING
          
          END FUNCTION
          
          CALLBACK FUNCTION DlgProc() AS LONG
          LOCAL MyString AS STRING
          
          SELECT CASE CB.MSG
          CASE IMSG_1
          IF ISOBJECT(oTest) THEN
          oTest.ForHost() TO MyString
          CONTROL SET TEXT hDlg, %IDC_TxtBox1, MyString
          ELSE
          ? "error"
          END IF
          
          CASE IMSG_2
          IF ISOBJECT(oTest) THEN
          oTest.ForClient() TO MyString
          CONTROL SET TEXT hDlg, %IDC_TxtBox1, MyString
          ELSE
          ? "error"
          END IF
          
          CASE %WM_INITDIALOG
          
          CASE %WM_COMMAND
          SELECT CASE CB.CTL
          END SELECT
          END SELECT
          END FUNCTION

          Comment


          • #6
            A simple remote control for App_1 and App_2

            HTML Code:
            [code]'==============================================================================
            '
            '  Loosely based on:
            '  Direct.bas example for PowerBASIC For Windows Compiler
            '
            '  1) Demonstrates sending commands directly to individual apps.
            '
            '  2) Demonstrates inner system messaging to signal the other app to read
            '  its COM message.
            '
            '  3) No timer needed.
            '
            '  4) If you want to control an app it must be running.
            '
            '  5) Example commands:
            '     TESTDLL
            '     TESTLOOPBACK
            '     RESETTEXT
            '     This is a simple test message from the Remote.
            '     SENDMESSAGE
            '     LOOPTEST
            '
            '==============================================================================
            '        In-Process Remote Control App for Host App_1 and Client App_2
            '==============================================================================
            'Compilable Example:
            #COMPILER PBWIN 10
            #COMPILE EXE "App_4.exe"
            #DIM ALL
            
            GLOBAL hDlg    AS DWORD
            GLOBAL oTest   AS ITest       ' Object reference to the ITest Interface
            
            GLOBAL MyMessage AS STRING
            
            'Notification message for app to read the Shared Memory Mapped COM string
            $MESSAGE_NAME_1 = "abcdedjdsj8489327483498294829"  ' Host notification
            $MESSAGE_NAME_2 = "abcdedjdsj8489327483498294830"  ' Client notification
            GLOBAL IMSG_1 AS DWORD
            GLOBAL IMSG_2 AS DWORD
            
            %HWND_BROADCAST = &HFFFFFFFF???
            
            ENUM Equates SINGULAR
              IDC_Frame1
              IDC_Frame2
              IDC_Button1
              IDC_Button2
              IDC_ButtonReset
              IDC_ButtonTest
              IDC_Button3
              IDC_ButtonLoop
            
              IDC_Button1X
              IDC_Button2X
              IDC_ButtonResetX
              IDC_ButtonTestX
              IDC_Button3X
              IDC_ButtonLoopX
            END ENUM
            
            DECLARE FUNCTION RegisterWindowMessageA IMPORT "USER32.DLL" ALIAS "RegisterWindowMessageA" ( _
               BYREF lpString AS ASCIIZ _                           ' __in LPCSTR lpString
             ) AS DWORD                                             ' UINT
            
            DECLARE FUNCTION FindWindowA IMPORT "USER32.DLL" ALIAS "FindWindowA" ( _
               OPTIONAL BYREF lpClassName AS ASCIIZ _               ' __in_opt LPCSTR lpClassName
             , OPTIONAL BYREF lpWindowName AS ASCIIZ _              ' __in_opt LPCSTR lpWindowName
             ) AS DWORD                                             ' HWND
            
            DECLARE FUNCTION SendMessageA IMPORT "USER32.DLL" ALIAS "SendMessageA" ( _
               BYVAL hWnd AS DWORD _                                ' __in HWND hWnd
             , BYVAL Msg AS DWORD _                                 ' __in UINT Msg
             , BYVAL wParam AS DWORD _                              ' __in WPARAM wParam
             , BYVAL lParam AS LONG _                               ' __in LPARAM lParam
             ) AS LONG                                              ' LRESULT
            
            DECLARE FUNCTION GetLastError IMPORT "KERNEL32.DLL" ALIAS "GetLastError" ( _
               ) AS DWORD                                           ' DWORD
            
            DECLARE FUNCTION PostMessageA IMPORT "USER32.DLL" ALIAS "PostMessageA" ( _
               BYVAL hWnd AS DWORD _                                ' __in_opt HWND hWnd
             , BYVAL Msg AS DWORD _                                 ' __in UINT Msg
             , BYVAL wParam AS DWORD  _                             ' __in WPARAM wParam
             , BYVAL lParam AS LONG _                               ' __in LPARAM lParam
             ) AS LONG                                              ' BOOL
            
            DECLARE FUNCTION GetDlgItem IMPORT "USER32.DLL" ALIAS "GetDlgItem" ( _
               BYVAL hDlg AS DWORD _                                ' __in_opt HWND hDlg
             , BYVAL nIDDlgItem AS LONG _                           ' __in int nIDDlgItem
             ) AS DWORD                                             ' HWND
            
            'START OF COM REFERENCES
            '/////////////////////////////////////////////////////
            
            ' Class Identifiers
            $CLSID_MYCLASS = GUID$("{00000098-0000-0000-0000-000000000003}")
            
            ' Interface Identifiers
            $IID_MYTEST = GUID$("{00000098-0000-0000-0000-000000000004}")
            
            INTERFACE ITest $IID_MYTEST
              INHERIT IDISPATCH
            
              METHOD DoTest
            
              PROPERTY GET ForClient <100> () AS STRING
              PROPERTY SET ForClient <100> (BYVAL ForClientString AS STRING)
              PROPERTY GET ForHost <101> () AS STRING
              PROPERTY SET ForHost <101> (BYVAL ForHostString AS STRING)
            END INTERFACE
            
            'END OF COM REFERENCES
            '/////////////////////////////////////////////////////
            
            FUNCTION PBMAIN() AS LONG
            
                LET oTest = NEWCOM CLSID $CLSID_MYCLASS LIB EXE.PATH$ + "DispatchServer.dll"
            
                IMSG_1 = RegisterWindowMessageA ($MESSAGE_NAME_1) ' for host
                IMSG_2 = RegisterWindowMessageA ($MESSAGE_NAME_2) ' for client
            
                DIALOG NEW PIXELS, 0, "Remote App",300,300,570,220, %WS_OVERLAPPEDWINDOW TO hDlg
                CONTROL ADD FRAME, hDlg, %IDC_Frame1,"Host", 10,10,270,200,
                CONTROL ADD FRAME, hDlg, %IDC_Frame2,"Client", 290,10,270,200,
            
                CONTROL ADD BUTTON, hDlg, %IDC_Button1,"Dll Test", 40,30,100,20
                CONTROL ADD BUTTON, hDlg, %IDC_Button2,"Test Loopback", 40,60,100,20
                CONTROL ADD BUTTON, hDlg, %IDC_ButtonReset,"Reset Text", 40,90,100,20
            
                CONTROL ADD BUTTON, hDlg, %IDC_ButtonTest,"Test Message", 40,120,100,20
                CONTROL ADD BUTTON, hDlg, %IDC_Button3,"Send Message", 40,150,100,20
                CONTROL ADD BUTTON, hDlg, %IDC_ButtonLoop,"Loop Test", 40,180,100,20
            
                CONTROL ADD BUTTON, hDlg, %IDC_Button1X,"Dll Test", 320,30,100,20
                CONTROL ADD BUTTON, hDlg, %IDC_Button2X,"Test Loopback", 320,60,100,20
                CONTROL ADD BUTTON, hDlg, %IDC_ButtonResetX,"Reset Text", 320,90,100,20
            
                CONTROL ADD BUTTON, hDlg, %IDC_ButtonTestX,"Test Message", 320,120,100,20
                CONTROL ADD BUTTON, hDlg, %IDC_Button3X,"Send Message", 320,150,100,20
                CONTROL ADD BUTTON, hDlg, %IDC_ButtonLoopX,"Loop Test", 320,180,100,20
            
                DIALOG SHOW MODAL hDlg CALL DlgProc
            
                oTest = NOTHING
            
            END FUNCTION
            
            CALLBACK FUNCTION DlgProc() AS LONG
                SELECT CASE CB.MSG
            
                    CASE %WM_INITDIALOG
            
                    CASE %WM_COMMAND
                        SELECT CASE CB.CTL
                            'Host commands
                            CASE %IDC_Button1
            
                                IF ISOBJECT(oTest) THEN
                                    MyMessage = "TESTDLL"
                                    oTest.ForHost() = MyMessage
                                    CALL SIGNAL_HOST_TO_READ_MESSAGE
                                ELSE
                                    ? "error"
                                END IF
            
                            CASE %IDC_Button2
                                IF ISOBJECT(oTest) THEN
                                    MyMessage = "TESTLOOPBACK"
                                    oTest.ForHost() = MyMessage
                                    CALL SIGNAL_HOST_TO_READ_MESSAGE
                                ELSE
                                    ? "error"
                                END IF
            
                            CASE %IDC_ButtonReset
                                IF ISOBJECT(oTest) THEN
                                    MyMessage = "RESETTEXT"
                                    oTest.ForHost() = MyMessage
                                    CALL SIGNAL_HOST_TO_READ_MESSAGE
                                ELSE
                                    ? "error"
                                END IF
            
                            CASE %IDC_ButtonTest
                                IF ISOBJECT(oTest) THEN
                                    MyMessage = "This is a simple test message from the Remote."
                                    oTest.ForHost() = MyMessage
                                    CALL SIGNAL_HOST_TO_READ_MESSAGE
                                ELSE
                                    ? "error"
                                END IF
            
                            CASE %IDC_Button3
                                IF ISOBJECT(oTest) THEN
                                    MyMessage = "SENDMESSAGE"
                                    oTest.ForHost() = MyMessage
                                    CALL SIGNAL_HOST_TO_READ_MESSAGE
                                ELSE
                                    ? "error"
                                END IF
            
                            CASE %IDC_ButtonLoop
                                IF ISOBJECT(oTest) THEN
                                    oTest.ForHost() = "LOOPTEST"
                                    CALL SIGNAL_HOST_TO_READ_MESSAGE
                                ELSE
                                    ? "error"
                                END IF
            
            
                            'Client commands
                            CASE %IDC_Button1X
            
                                IF ISOBJECT(oTest) THEN
                                    MyMessage = "TESTDLL"
                                    oTest.ForClient() = MyMessage
                                    CALL SIGNAL_CLIENT_TO_READ_MESSAGE
                                ELSE
                                    ? "error"
                                END IF
            
                            CASE %IDC_Button2X
                                IF ISOBJECT(oTest) THEN
                                    MyMessage = "TESTLOOPBACK"
                                    oTest.ForClient() = MyMessage
                                    CALL SIGNAL_CLIENT_TO_READ_MESSAGE
                                ELSE
                                    ? "error"
                                END IF
            
                            CASE %IDC_ButtonResetX
                                IF ISOBJECT(oTest) THEN
                                    MyMessage = "RESETTEXT"
                                    oTest.ForClient() = MyMessage
                                    CALL SIGNAL_CLIENT_TO_READ_MESSAGE
                                ELSE
                                    ? "error"
                                END IF
            
                            CASE %IDC_ButtonTestX
                                IF ISOBJECT(oTest) THEN
                                    MyMessage = "This is a simple test message from the Remote."
                                    oTest.ForClient() = MyMessage
                                    CALL SIGNAL_CLIENT_TO_READ_MESSAGE
                                ELSE
                                    ? "error"
                                END IF
            
                            CASE %IDC_Button3X
                                IF ISOBJECT(oTest) THEN
                                    MyMessage = "SENDMESSAGE"
                                    oTest.ForClient() = MyMessage
                                    CALL SIGNAL_CLIENT_TO_READ_MESSAGE
                                ELSE
                                    ? "error"
                                END IF
            
                            CASE %IDC_ButtonLoopX
                                IF ISOBJECT(oTest) THEN
                                    oTest.ForClient() = "LOOPTEST"
                                    CALL SIGNAL_CLIENT_TO_READ_MESSAGE
                                ELSE
                                    ? "error"
                                END IF
                        END SELECT
                END SELECT
            END FUNCTION
            
            SUB SIGNAL_HOST_TO_READ_MESSAGE
              LOCAL hWnd1   AS DWORD
              LOCAL iRet    AS LONG
            
              hWnd1 = FindWindowA("", "Host App")
              IF hWnd1 THEN
                  'tell app_1 to read its COM message
                  iRet = PostMessageA (%HWND_BROADCAST, IMSG_1, 4, 7) 'iRet = 5 = access denied but still works
              ELSE
                  'do nothing
              END IF
            END SUB
            
            SUB SIGNAL_CLIENT_TO_READ_MESSAGE
              LOCAL hWnd2   AS DWORD
              LOCAL iRet    AS LONG
            
              hWnd2 = FindWindowA("", "Client App")
              IF hWnd2 THEN
                  'tell app_2 to read its COM message
                  iRet = PostMessageA (%HWND_BROADCAST, IMSG_2, 4, 7) 'iRet = 5 = access denied but still works
              ELSE
                  'do nothing
              END IF
            END SUB[/code]

            Comment


            • #7
              Thank you Jim
              Probably would need you to repost #4 and #5 with code tags as it would look better

              Comment


              • #8
                Tim,
                I'll roll up a new version shortly with all the changes in a zip. The initial posts were just to make the coding show up in forum searches.
                As you can see they did have CODE tags.
                Last edited by Jim Fritts; 18 Jan 2020, 03:04 PM.

                Comment


                • #9
                  New and improved versions,
                  Zip includes
                  Host App ==> App_1.exe
                  Client App ==> App_2.exe
                  Listen App ==> App_3.exe
                  Remote App ==> App_4.exe
                  DispatchServer.dll
                  DispatchServer.tlb

                  and the bas files.
                  Note:
                  The Test Message buttons on the Remote App send the Remote App's own test message "This is a simple test message from the Remote."

                  COM_Relay (2).zip
                  Attached Files

                  Comment


                  • #10
                    Remote control for xBot:

                    Click image for larger version  Name:	New Bitmap Image.jpg Views:	0 Size:	25.5 KB ID:	788905

                    HTML Code:
                    [code]'==============================================================================
                    '
                    '  Loosely based on:
                    '  Direct.bas example for PowerBASIC For Windows Compiler
                    '
                    '  1) Demonstrates sending commands directly to individual apps.
                    '
                    '  2) Demonstrates inner system messaging to signal the other app to read
                    '  its COM message.
                    '
                    '  3) No timer needed.
                    '
                    '  4) If you want to control an app it must be running. In this case xBot is the target.
                    '
                    '  5) Example commands:
                    '      Play Music
                    '      Pause Music
                    '      Stop Music
                    '      Play Next
                    '      Play Last
                    '      Change Mode
                    '
                    '      Next List
                    '      Last List
                    '      Reset List
                    '      Up 10 Tracks
                    '      Down 10 Tracks
                    '      Save to Favorites
                    '
                    '==============================================================================
                    '                  In-Process Remote Control App for xBot
                    '==============================================================================
                    'Compilable Example:
                    #COMPILER PBWIN 10
                    #COMPILE EXE "Remote_1.exe"
                    #DIM ALL
                    
                    GLOBAL hDlg    AS DWORD
                    GLOBAL oTest   AS ITest       ' Object reference to the ITest Interface
                    
                    GLOBAL MyMessage AS STRING
                    
                    'Notification message for app to read the Shared Memory Mapped COM string
                    $MESSAGE_NAME_1 = "abcdedjdsj8489327483498294829"  ' Host notification
                    '$MESSAGE_NAME_2 = "abcdedjdsj8489327483498294830"  ' Client notification
                    GLOBAL IMSG_1 AS DWORD
                    'GLOBAL IMSG_2 AS DWORD
                    
                    %HWND_BROADCAST = &HFFFFFFFF???
                    
                    ENUM Equates SINGULAR
                      IDC_Frame1       'control frame
                    
                      IDC_Button101    'Play Music
                      IDC_Button102    'Pause Music
                      IDC_Button103    'Stop Music
                      IDC_Button104    'Play Next
                      IDC_Button105    'Play Last
                      IDC_Button106    'Change Mode
                    
                      IDC_Button107    'Next List
                      IDC_Button108    'Last List
                      IDC_Button109    'Reset List
                      IDC_Button110    'Up 10 Tracks
                      IDC_Button111    'Down 10 Tracks
                      IDC_Button112    'Save to Favorites
                    END ENUM
                    
                    DECLARE FUNCTION RegisterWindowMessageA IMPORT "USER32.DLL" ALIAS "RegisterWindowMessageA" ( _
                       BYREF lpString AS ASCIIZ _                           ' __in LPCSTR lpString
                     ) AS DWORD                                             ' UINT
                    
                    DECLARE FUNCTION FindWindowA IMPORT "USER32.DLL" ALIAS "FindWindowA" ( _
                       OPTIONAL BYREF lpClassName AS ASCIIZ _               ' __in_opt LPCSTR lpClassName
                     , OPTIONAL BYREF lpWindowName AS ASCIIZ _              ' __in_opt LPCSTR lpWindowName
                     ) AS DWORD                                             ' HWND
                    
                    DECLARE FUNCTION SendMessageA IMPORT "USER32.DLL" ALIAS "SendMessageA" ( _
                       BYVAL hWnd AS DWORD _                                ' __in HWND hWnd
                     , BYVAL Msg AS DWORD _                                 ' __in UINT Msg
                     , BYVAL wParam AS DWORD _                              ' __in WPARAM wParam
                     , BYVAL lParam AS LONG _                               ' __in LPARAM lParam
                     ) AS LONG                                              ' LRESULT
                    
                    DECLARE FUNCTION GetLastError IMPORT "KERNEL32.DLL" ALIAS "GetLastError" ( _
                       ) AS DWORD                                           ' DWORD
                    
                    DECLARE FUNCTION PostMessageA IMPORT "USER32.DLL" ALIAS "PostMessageA" ( _
                       BYVAL hWnd AS DWORD _                                ' __in_opt HWND hWnd
                     , BYVAL Msg AS DWORD _                                 ' __in UINT Msg
                     , BYVAL wParam AS DWORD  _                             ' __in WPARAM wParam
                     , BYVAL lParam AS LONG _                               ' __in LPARAM lParam
                     ) AS LONG                                              ' BOOL
                    
                    DECLARE FUNCTION GetDlgItem IMPORT "USER32.DLL" ALIAS "GetDlgItem" ( _
                       BYVAL hDlg AS DWORD _                                ' __in_opt HWND hDlg
                     , BYVAL nIDDlgItem AS LONG _                           ' __in int nIDDlgItem
                     ) AS DWORD                                             ' HWND
                    
                    'START OF COM REFERENCES
                    '/////////////////////////////////////////////////////
                    
                    ' Class Identifiers
                    $CLSID_MYCLASS = GUID$("{00000098-0000-0000-0000-000000000003}")
                    
                    ' Interface Identifiers
                    $IID_MYTEST = GUID$("{00000098-0000-0000-0000-000000000004}")
                    
                    INTERFACE ITest $IID_MYTEST
                      INHERIT IDISPATCH
                    
                      METHOD DoTest
                    
                      PROPERTY GET ForClient <100> () AS STRING
                      PROPERTY SET ForClient <100> (BYVAL ForClientString AS STRING)
                      PROPERTY GET ForHost <101> () AS STRING
                      PROPERTY SET ForHost <101> (BYVAL ForHostString AS STRING)
                    END INTERFACE
                    
                    'END OF COM REFERENCES
                    '/////////////////////////////////////////////////////
                    
                    FUNCTION PBMAIN() AS LONG
                    
                        LET oTest = NEWCOM CLSID $CLSID_MYCLASS LIB EXE.PATH$ + "DispatchServer.dll"
                    
                        IMSG_1 = RegisterWindowMessageA ($MESSAGE_NAME_1) ' for host
                        'IMSG_2 = RegisterWindowMessageA ($MESSAGE_NAME_2) ' for client
                    
                        DIALOG NEW PIXELS, 0, "xBot Remote App",300,300,290,220, %WS_OVERLAPPEDWINDOW TO hDlg
                        CONTROL ADD FRAME, hDlg, %IDC_Frame1,"Control Commands", 10,10,270,200,
                    
                        'sent to only Host
                        CONTROL ADD BUTTON, hDlg, %IDC_Button101,"Play Music", 40,30,100,20
                        CONTROL ADD BUTTON, hDlg, %IDC_Button102,"Pause Music", 40,60,100,20
                        CONTROL ADD BUTTON, hDlg, %IDC_Button103,"Stop Music", 40,90,100,20
                        CONTROL ADD BUTTON, hDlg, %IDC_Button104,"Play Next", 40,120,100,20
                        CONTROL ADD BUTTON, hDlg, %IDC_Button105,"Play Last", 40,150,100,20
                        CONTROL ADD BUTTON, hDlg, %IDC_Button106,"Change Mode", 40,180,100,20
                    
                        CONTROL ADD BUTTON, hDlg, %IDC_Button107,"Next List", 160,30,100,20
                        CONTROL ADD BUTTON, hDlg, %IDC_Button108,"Last List", 160,60,100,20
                        CONTROL ADD BUTTON, hDlg, %IDC_Button109,"Reset List", 160,90,100,20
                        CONTROL ADD BUTTON, hDlg, %IDC_Button110,"Up 10 Tracks", 160,120,100,20
                        CONTROL ADD BUTTON, hDlg, %IDC_Button111,"Down 10 Tracks", 160,150,100,20
                        CONTROL ADD BUTTON, hDlg, %IDC_Button112,"Save to Favorites", 160,180,100,20
                    
                        DIALOG SHOW MODAL hDlg CALL DlgProc
                    
                        oTest = NOTHING
                    
                    END FUNCTION
                    
                    CALLBACK FUNCTION DlgProc() AS LONG
                        SELECT CASE CB.MSG
                    
                            CASE %WM_INITDIALOG
                    
                            CASE %WM_COMMAND
                                SELECT CASE CB.CTL
                    
                                    'Host commands
                                    CASE %IDC_Button101    'Play Music
                    
                                        IF ISOBJECT(oTest) THEN
                                            MyMessage = "PLAY MUSIC"
                                            oTest.ForHost() = MyMessage
                                            CALL SIGNAL_HOST_TO_READ_MESSAGE
                                        ELSE
                                            ? "error"
                                        END IF
                    
                                    CASE %IDC_Button102    'Pause Music
                                        IF ISOBJECT(oTest) THEN
                                            MyMessage = "PAUSE MUSIC"
                                            oTest.ForHost() = MyMessage
                                            CALL SIGNAL_HOST_TO_READ_MESSAGE
                                        ELSE
                                            ? "error"
                                        END IF
                    
                                    CASE %IDC_Button103    'Stop Music
                                        IF ISOBJECT(oTest) THEN
                                            MyMessage = "STOP MUSIC"
                                            oTest.ForHost() = MyMessage
                                            CALL SIGNAL_HOST_TO_READ_MESSAGE
                                        ELSE
                                            ? "error"
                                        END IF
                    
                                    CASE %IDC_Button104    'Play Next
                                        IF ISOBJECT(oTest) THEN
                                            MyMessage = "PLAY NEXT"
                                            oTest.ForHost() = MyMessage
                                            CALL SIGNAL_HOST_TO_READ_MESSAGE
                                        ELSE
                                            ? "error"
                                        END IF
                    
                                    CASE %IDC_Button105    'Play Last
                                        IF ISOBJECT(oTest) THEN
                                            MyMessage = "PLAY LAST"
                                            oTest.ForHost() = MyMessage
                                            CALL SIGNAL_HOST_TO_READ_MESSAGE
                                        ELSE
                                            ? "error"
                                        END IF
                    
                                    CASE %IDC_Button106    'Change Mode
                                        IF ISOBJECT(oTest) THEN
                                            MyMessage = "CHANGE MODE"
                                            oTest.ForHost() = MyMessage
                                            CALL SIGNAL_HOST_TO_READ_MESSAGE
                                        ELSE
                                            ? "error"
                                        END IF
                    
                    
                                    CASE %IDC_Button107    'Next List
                    
                                        IF ISOBJECT(oTest) THEN
                                            MyMessage = "NEXT LIST"
                                            oTest.ForHost() = MyMessage
                                            CALL SIGNAL_HOST_TO_READ_MESSAGE
                                        ELSE
                                            ? "error"
                                        END IF
                    
                                    CASE %IDC_Button108    'Last List
                                        IF ISOBJECT(oTest) THEN
                                            MyMessage = "LAST LIST"
                                            oTest.ForHost() = MyMessage
                                            CALL SIGNAL_HOST_TO_READ_MESSAGE
                                        ELSE
                                            ? "error"
                                        END IF
                    
                                    CASE %IDC_Button109    'Reset List
                                        IF ISOBJECT(oTest) THEN
                                            MyMessage = "RESET LIST"
                                            oTest.ForHost() = MyMessage
                                            CALL SIGNAL_HOST_TO_READ_MESSAGE
                                        ELSE
                                            ? "error"
                                        END IF
                    
                                    CASE %IDC_Button110    'Up 10 Tracks
                                        IF ISOBJECT(oTest) THEN
                                            MyMessage = "UP 10 TRACKS"
                                            oTest.ForHost() = MyMessage
                                            CALL SIGNAL_HOST_TO_READ_MESSAGE
                                        ELSE
                                            ? "error"
                                        END IF
                    
                                    CASE %IDC_Button111    'Down 10 Tracks
                                        IF ISOBJECT(oTest) THEN
                                            MyMessage = "DOWN 10 TRACKS"
                                            oTest.ForHost() = MyMessage
                                            CALL SIGNAL_HOST_TO_READ_MESSAGE
                                        ELSE
                                            ? "error"
                                        END IF
                    
                                    CASE %IDC_Button112    'Save to Favorites
                                        IF ISOBJECT(oTest) THEN
                                            MyMessage = "SAVE TO FAVORITES"
                                            oTest.ForHost() = MyMessage
                                            CALL SIGNAL_HOST_TO_READ_MESSAGE
                                        ELSE
                                            ? "error"
                                        END IF
                                END SELECT
                        END SELECT
                    END FUNCTION
                    
                    SUB SIGNAL_HOST_TO_READ_MESSAGE
                      LOCAL hWnd1   AS DWORD
                      LOCAL iRet    AS LONG
                    
                      hWnd1 = FindWindowA("", "xBot")
                      IF hWnd1 THEN
                          'tell app_1 to read its COM message
                          iRet = PostMessageA (%HWND_BROADCAST, IMSG_1, 4, 7) 'iRet = 5 = access denied but still works
                      ELSE
                          'do nothing
                      END IF
                    END SUB
                    
                    [/code]
                    Note:
                    These messages will show up in the Listener app and the Host App if they are running.
                    The reasons for that are:
                    1) I'm using the same RegisterWindowMessage.
                    2) the COM instance variable is a Shared Memory Mapped variable.

                    Very

                    Comment


                    • #11
                      Note:
                      Due to the fact that the COM instance variable is Shared the DispatchServer.dll does not have to be linked to some location outside your app folder. All you need to do is have a copy in your application folder. Very easy.

                      This is how I am using it.

                      Remote control folder includes:
                      Remote App and DispatchServer.dll copy

                      App to be controlled folder:
                      Target App and DispatchServer.dll copy

                      Only minimal code is needed in the target app to get it up and running with the remote control app.

                      This is placed in the variable section
                      HTML Code:
                      [code]
                      'START OF COM REFERENCES
                      '/////////////////////////////////////////////////////
                      
                      ' Class Identifiers
                      $CLSID_MYCLASS = GUID$("{00000098-0000-0000-0000-000000000003}")
                      
                      ' Interface Identifiers
                      $IID_MYTEST = GUID$("{00000098-0000-0000-0000-000000000004}")
                      
                      INTERFACE ITest $IID_MYTEST
                        INHERIT IDISPATCH
                        METHOD DoTest
                      
                        PROPERTY GET ForClient <100> () AS STRING
                        PROPERTY SET ForClient <100> (BYVAL ForClientString AS STRING)
                        PROPERTY GET ForHost <101> () AS STRING
                        PROPERTY SET ForHost <101> (BYVAL ForHostString AS STRING)
                      END INTERFACE
                      
                      'END OF COM REFERENCES
                      '/////////////////////////////////////////////////////
                      
                      GLOBAL oTest   AS ITest       ' Object reference to the ITest Interface
                      
                      'Notification message for app to read the Shared Memory Mapped COM string
                      $MESSAGE_NAME_1 = "abcdedjdsj8489327483498294829"  ' Host notification
                      '$MESSAGE_NAME_2 = "abcdedjdsj8489327483498294830"  ' Client notification
                      GLOBAL IMSG_1 AS DWORD
                      'GLOBAL IMSG_2 AS DWORD
                      
                      %HWND_BROADCAST = &HFFFFFFFF???  
                      [/code]

                      This is placed in the WndProc or CALLBACK section

                      HTML Code:
                      [code]
                          CASE IMSG_1
                                  IF ISOBJECT(oTest) THEN
                                      oTest.ForHost() TO MyString
                                      SELECT CASE MyString
                                          CASE "PLAY MUSIC"
                                              PostMessageA hWndMain, %WM_COMMAND, %ID_MusicJB001, 0
                                          CASE "PAUSE MUSIC"
                                              PostMessageA hWndMain, %WM_COMMAND, %ID_MusicJB002, 0
                                          CASE "STOP MUSIC"
                                              PostMessageA hWndMain, %WM_COMMAND, %ID_MusicJB003, 0
                                          CASE "PLAY LAST"
                                              PostMessageA hWndMain, %WM_COMMAND, %ID_MusicJB007, 0
                                          CASE "PLAY NEXT"
                                              PostMessageA hWndMain, %WM_COMMAND, %ID_MusicJB008, 0
                                          CASE "CHANGE MODE"
                                              PostMessageA hWndMain, %WM_COMMAND, %ID_MusicJB009, 0
                                          CASE "LAST LIST"
                                              PostMessageA hWndMain, %WM_COMMAND, %ID_MusicJB013, 0
                                          CASE "RESET LIST"
                                              PostMessageA hWndMain, %WM_COMMAND, %ID_MusicJB014, 0
                                          CASE "NEXT LIST"
                                              PostMessageA hWndMain, %WM_COMMAND, %ID_MusicJB015, 0
                                          CASE "DOWN 10 TRACKS"
                                              PostMessageA hWndMain, %WM_COMMAND, %ID_MusicJB019, 0
                                          CASE "UP 10 TRACKS"
                                              PostMessageA hWndMain, %WM_COMMAND, %ID_MusicJB021, 0
                                          CASE "PASTE TO FAVORITES"
                                              PostMessageA hWndMain, %WM_COMMAND, %ID_MusicJB022, 0
                                      END SELECT
                                  ELSE
                                      ? "error"
                                  END IF
                      [/code]
                      and this is placed in the WINMAIN or PBMAIN section

                      HTML Code:
                      [code]
                          LET oTest = NEWCOM CLSID $CLSID_MYCLASS LIB EXE.PATH$ + "DispatchServer.dll"
                      
                          IMSG_1 = RegisterWindowMessageA ($MESSAGE_NAME_1) ' for host
                      [/code]
                      Last edited by Jim Fritts; 19 Jan 2020, 09:28 PM.

                      Comment


                      • #12
                        Note:
                        Do not forget that your remote app must contain the name of the targeted app here:
                        Code:
                         
                        hWnd1 = FindWindowA("", "xBot") '<=====
                        If the named app is not running the read signal will not be sent.

                        Comment


                        • #13
                          One more thing, if you have a folder open named xBot and you use hWnd1 = FindWindowA("","xBot") that is also sufficient to satisfy the test for app running. I should probably incorporate a validation that the window is actually an app and not a folder.

                          Easy enough to include the class name:
                          hWnd1 = FindWindowA("MobileApp", "xBot")

                          Comment


                          • #14
                            Hi Jim
                            Will you post the latest copy of Com_Relay .zip file ?

                            Comment


                            • #15
                              Anne,
                              Sorry there were no significant changes other than what has been documented in the previous posts. Eventually I will post a new version of xBot which will include this technology. In the mean time is there a question that I can help with?

                              As it is you just have to put the DispatchServer.dll in your app folder and place a DispatchServer.dll in your Remote Control folder if the main app is not sharing a folder with the Remote Control.

                              The remote control example above shows just the bare minimum code needed with some example commands to send to another app. (One Direction Only)

                              Post#11 highlights the code needed in the main app to receive the commands from the remote control.

                              You can also modify the Remote Control to receive feedback from the main app. The COM_Relay(2).zip demonstrate how that can be done. Look at the Client app (App_2) for the code needed to do that and look at Host App (App_1) for what is needed in your main app to support that. (Bidirectional Messaging)

                              Comment


                              • #16
                                Anne,
                                Zip includes:

                                Host App ==> App_1.exe Modified to send feedback to Client or Remote App 3.
                                Client App ==> App_2.exe
                                Listen App ==> App_3.exe
                                Remote App ==> App_4.exe basic remote (One Direction Only)
                                Remote App 2 ==> App_5.exe median remote to send to both Host and Client at the same time. (One Direction Only)
                                Remote App 3 ==> App_6.exe Superior remote that shows feedback from the Host. (Bidirectional Messaging)
                                Sorry, I did not insert a response message for the Host LOOPTEST command. See Note below for fix.

                                DispatchServer.dll
                                DispatchServer.tlb

                                and the bas files.

                                Note:
                                To do a simple remote control test just use Host App (App_1) and Remote App 3 (App_6). No Client app needed for the Host to send a message.

                                Easy fix for LOOPTEST under Remote App 3 CALLBACK FUNCTION change IMSG_2 to this:
                                HTML Code:
                                [code]
                                        CASE IMSG_2 'received from host
                                            IF ISOBJECT(oTest) THEN
                                                oTest.ForClient() TO MyString
                                                CONTROL SET TEXT hDlg, %IDC_Button119, MyString
                                                SELECT CASE MyString
                                                    CASE "LOOPTEST"
                                                        CALL SEND_THIS_MESSAGE("The loop test relay was successful!")
                                
                                                END SELECT
                                            END IF
                                [/code]



                                COM_Relay (3).zip
                                Attached Files
                                Last edited by Jim Fritts; 3 Feb 2020, 12:03 PM.

                                Comment


                                • #17
                                  Thanks Jim,
                                  Brilliant work

                                  Comment


                                  • #18

                                    Zip includes:

                                    Host App ==> App_1.exe Modified to close Remote App 3 on command and can query the status of the remote. Simplified
                                    Client App ==> App_2.exe Simplified
                                    Listen App ==> App_3.exe no change
                                    Remote App ==> App_4.exe basic remote (One Direction Only) Simplified
                                    Remote App 2 ==> App_5.exe median remote to send to both Host and Client at the same time. (One Direction Only) Simplified
                                    Remote App 3 ==> App_6.exe Superior remote can be closed by Host and reports its status to the Host. (Bidirectional Messaging) Simplified

                                    DispatchServer.dll
                                    DispatchServer.tlb

                                    and the bas files.

                                    Note:
                                    To do a simple remote control test just use Host App (App_1) and Remote App 3 (App_6).
                                    No Client app needed for the Host to send a message.

                                    COM_Relay (4).zip
                                    Attached Files
                                    Last edited by Jim Fritts; 8 Feb 2020, 06:35 PM.

                                    Comment


                                    • #19
                                      The LOOPTEST was found to be too generic and has been replaced with HOSTTEST or CLIENTTEST so it is now directed at the target app.
                                      Added more refinements. I had to remove the compiled apps to meet my monthly quota.

                                      COM_Relay (5).zip
                                      Attached Files

                                      Comment

                                      Working...
                                      X