Announcement

Collapse
No announcement yet.

WM_COPYDATA between a Win Program and a PBCC program.

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

  • WM_COPYDATA between a Win Program and a PBCC program.

    Assuming I can give the PBCC program the handle of the target window should I be able to send messages from the CC to the Win program?

    I am trying to create a windows dialog that receives messages from a console app.


  • #2
    ... should I be able to send messages from the CC to the Win program?
    In WinUser.inc see API functions SendMessage and PostMessage.
    Dale

    Comment


    • #3
      Originally posted by David Clarke View Post
      Assuming I can give the PBCC program the handle of the target window should I be able to send messages from the CC to the Win program?

      I am trying to create a windows dialog that receives messages from a console app.
      As Dale says, SendMessage or PostMessage.
      The simple way to get the handle of the target window is by using FindWindow() in your PBCC application as long as your PBWin has a unique Title. ( You can use a hidden window to process the message)

      You only need to use %WM_COPYDATA and a COPYDATA structure if you need to pass complex data to the PBWIn application. Otherwise you can use any user defined message value (with a value above %WM_USER) and WPARAM and LPARAM to pass specific values that your PBWin can act on.

      Comment


      • #4
        I knew it was here somewhere
        https://forum.powerbasic.com/forum/u...tion#post46598

        Comment


        • #5
          Hmm, playing around with it, Postmessage seems to work between two PBWIn Dialog applications (as per the link above), but not between a PBCC Console application and a PBWin DIalog .

          The Console app is very basic and just does what the Dialog in the link does
          '
          Code:
          #COMPILE EXE
          #INCLUDE "win32api.inc"
          FUNCTION PBMAIN() AS LONG
              LOCAL gMsg AS DWORD
              LOCAL ret AS DWORD
              LOCAL MsgString AS STRINGZ * 100
              MsgString = "gb Custom Msg"
              gMsg = RegisterWindowMessage(MsgString)
              ? "Press a key to send broadcast"
                  WAITKEY$
                  ret = PostMessage(%Hwnd_Broadcast, gMsg, 4, 7)
                  ? STR$(ret)
                  ? STR$(getLastError)
                  WAITKEY$
          END FUNCTION
          '

          PostMessage returns1
          Return Values
          If the function succeeds, the return value is nonzero.
          If the function fails, the return value is zero. To get extended error information, call GetLastError.

          Comment


          • #6
            PBCC doesn't have the CB.xxx syntax.
            Rod
            In some future era, dark matter and dark energy will only be found in Astronomy's Dark Ages.

            Comment


            • #7
              "but not between a PBCC Console application and a PBWin DIalog"

              Yes that is the tricky part!
              I have one version using TCP...

              Comment


              • #8
                Dave,

                Just posting a message using the HWND_BROADCAST handle is simple enough to do, you use PostMessage() as it does not wait for return like SendMessage(). If you need to pass more than the two DWORD sized parameters of wParam and lParam, you can mess around with pipes and similar but a memory mapped file is how the OS handles such inter-app data transfers and it is genuinely fast.

                If you need the code to do this, I can find a pair that will do it for you.
                hutch at movsd dot com
                The MASM Forum - SLL Modules and PB Libraries

                http://www.masm32.com/board/index.php?board=69.0

                Comment


                • #9
                  Originally posted by Rodney Hicks View Post
                  PBCC doesn't have the CB.xxx syntax.
                  PBCC doesn't need the CB.xxx syntax to post a message

                  Comment


                  • #10
                    Post #5 wasn't showing up in my feed when I made my response and I thought you might be trying Gary's code.
                    Rod
                    In some future era, dark matter and dark energy will only be found in Astronomy's Dark Ages.

                    Comment


                    • #11
                      Don't know what I did different, but now this works with Garry's "Exe 2" from the link above.
                      '
                      Code:
                      #COMPILE EXE
                      #INCLUDE "win32api.inc"
                      FUNCTION PBMAIN() AS LONG
                          LOCAL gMsg AS DWORD
                          LOCAL hWnd AS DWORD
                          LOCAL ret AS LONG
                          LOCAL MsgString AS STRINGZ * 100
                          MsgString = "gb Custom Msg"
                          gMsg = RegisterWindowMessage(MsgString)
                          hWnd = findWindow("", "EXE #2 " + STR$(gMsg))
                          ? "hnd =" & STR$(hWnd)
                          ? "Press a key to send broadcast"
                              WAITKEY$
                           ret = PostMessage(hwnd, gMsg, 4, 7)
                           ? ret
                             WAITKEY$
                      
                      END FUNCTION
                      '
                      Click image for larger version

Name:	COnsolePostMessage.jpg
Views:	256
Size:	34.1 KB
ID:	818637

                      Comment


                      • #12
                        I am trying to create a windows dialog that receives messages from a console app.
                        Assuming you may more generically describe the above as "sending data to another process with some kind of notification" .....

                        In that case you might consider something other than posting a message and using the WM_COPYDATA message.

                        For example, there are numerous examples here of using pipes to accomplish this. You could also use a memory-mapped file and signal "message ready" using Windows Events. Heck, maybe you could share a PB "Queue Collection" object. (Make your own Enqueue method to signal an event)

                        That said, my choice would be based on the specific application. (But using the PB Queue Collection sounds like fun).
                        Last edited by Michael Mattias; 7 Sep 2022, 05:02 PM.
                        Michael Mattias
                        Tal Systems (retired)
                        Port Washington WI USA
                        [email protected]
                        http://www.talsystems.com

                        Comment


                        • #13
                          First, thank everyone of you!!

                          What I am doing is building a "DEBUG" window for my PBCC CGI programs.

                          Outputting to the browser can become a real pain.
                          So... Send debug messages!

                          Michal - I don't recall any pipe examples - I am not even sure what it is!

                          Memory-mapped file looks kind of busy... Amadeus - "There are simply too many notes." https://www.youtube.com/watch?v=dCud8H7z7vU

                          And that goes double for B "Queue Collection" object.! What is that??

                          Comment


                          • #14
                            Originally posted by David Clarke View Post
                            And that goes double for B "Queue Collection" object.! What is that??


                            COLLECTION Object Group
                            Purpose
                            A collection object is a set of items which can be referred to as a unit. It provides a convenient way to refer to a related group of items as a single object. The items in a collection need only be related by the fact that they exist in the collection. They do not have to share the same data type.
                            ...
                            Queue Collection
                            A Queue Collection is an ordered set of data items, which are accessed on a FIFO (First-In / First-Out) basis. Each data item is passed and stored as a variant variable, using the ENQUEUE and DEQUEUE methods.

                            Comment


                            • #15
                              Originally posted by David Clarke View Post
                              First, thank everyone of you!!

                              What I am doing is building a "DEBUG" window for my PBCC CGI programs.

                              Outputting to the browser can become a real pain.
                              So... Send debug messages!
                              Won't a TXT window work for displaying debug messages?
                              That is in essence "a windows dialog that receives messages from a console app." without needing a second application.

                              '
                              Code:
                              #COMPILE EXE
                              #DIM ALL
                              '%Debug = 1 'comment this line out to turn debugging off
                              FUNCTION PBMAIN() AS LONG
                              #IF %DEF(%debug)
                              LOCAL lDebug AS LONG: TXT.WINDOW EXE.FULL$, 10,10,20,50 TO lDebug
                              #ENDIF
                              
                              '...
                              ' Just to show that something has happened
                              ? "Result"
                              WAITKEY$
                              
                              '...
                                  Debug "Got to here with these values...."
                              '...
                              
                              #IF %DEF(%debug)
                                  'Finalise
                                  TXT.COLOR = %RGB_BLUE
                                  TXT.PRINT
                                  TXT.PRINT "  ....Press any key to exit": TXT.WAITKEY$: TXT.END
                              #ENDIF
                              END FUNCTION
                              
                              FUNCTION Debug(s AS STRING) AS LONG
                              #IF %DEF(%DEBUG)
                                  TXT.PRINT s
                              #ENDIF
                              END FUNCTION
                              '

                              Comment


                              • #16
                                Amazing what happens when you ask for ideas how to accomplish some specific task rather than for help with a technique or method you have already selected, isn't it?

                                Michael Mattias
                                Tal Systems (retired)
                                Port Washington WI USA
                                [email protected]
                                http://www.talsystems.com

                                Comment


                                • #17
                                  Thanks again for the help.

                                  Interesting thing.... When the CGI program tries to "send a message" it doesn't work. I suspect the issue is that the webserver is a different user??

                                  What is working is the CGI writes to a text file and I check the file every few seconds. Solves my problem but not very elegant.... Click image for larger version

Name:	Snap23538.jpg
Views:	104
Size:	299.4 KB
ID:	818740

                                  Comment


                                  • #18
                                    Originally posted by David Clarke View Post
                                    Interesting thing.... When the CGI program tries to "send a message" it doesn't work. I suspect the issue is that the webserver is a different user??

                                    What is working is the CGI writes to a text file and I check the file every few seconds. Solves my problem but not very elegant.... [/ATTACH]
                                    I missed the significance of the CGI earlier. Obviously a TXT window is not appropriate since the CGI exe doesn't stay open

                                    How about a simple Echo Client/Server based on code in the ..\Samples\Internet directory. It would be very easy to implement.

                                    The CGI application could send it's messages over TCP or UDP to a "listener" which can display them in a listbox or whatever.



                                    Comment


                                    • #19
                                      This works with the TCP Echo Server in Samples "out of box". No need to write anything to get the server working

                                      '
                                      Code:
                                      #COMPILE EXE
                                      #DIM ALL
                                      ' Dummy server name, should be empty for this (local) example
                                      '
                                      $SERVER = ""
                                      
                                      FUNCTION PBMAIN () AS LONG
                                      'do whatever you want with the CGI code
                                      '...
                                      TCPLog TIME$ & ": The CGI application was called"
                                      '...
                                      ' do something else with the CGI code
                                      END FUNCTION
                                      
                                      '
                                      FUNCTION TCPLog (msg AS STRING) AS LONG
                                          LOCAL nSocket AS LONG
                                          TCP OPEN PORT 999 AT $SERVER AS nSocket TIMEOUT 5000
                                          TCP PRINT nSocket, msg
                                          TCP CLOSE nSocket
                                      END FUNCTION
                                      '
                                      Click image for larger version  Name:	CGILogger.jpg Views:	1 Size:	49.1 KB ID:	818743

                                      Comment


                                      • #20
                                        How about a simple Echo Client/Server based on code in the ..\Samples\Internet directory. It would be very easy to implement.
                                        The CGI application could send it's messages over TCP or UDP to a "listener" which can display them in a listbox or whatever.​
                                        What is working is the CGI writes to a text file and I check the file every few seconds. Solves my problem but not very elegant....
                                        When I need to do that, I monitor the log file with filewatcher.

                                        If you need a cgi program, I have a small cgi program that returns secure data from a database to a program or the browser.

                                        This code starts a server in another thread then calls ClientHere.
                                        It uses the function MakeWindow so everything can run in PBCC or PBWin.
                                        It also shows remote ip and port if you want to log it.
                                        Note: Port 999 may need to be forwarded in router software to server machine and allowed through firewall.
                                        Code:
                                        #COMPILE EXE  'Echo server and client for either PB/CC or PBWIN
                                        #DIM ALL
                                        %PortNumber = 999
                                        $IP=""
                                        '%CCWIN = 0
                                        '#INCLUDE "\pbwin90\winapi\WS2_32.INC" 'if pbcc50 or pbwin9
                                        #INCLUDE "win32api.inc"
                                        #INCLUDE "winsock2.inc"
                                        #INCLUDE "ws2def.inc"
                                        %TCP_ACCEPT = %WM_USER + 4093  ' Any value larger than %WM_USER + 500
                                        %TCP_ECHO   = %WM_USER + 4094  ' Any value larger than %WM_USER + 500
                                        
                                        GLOBAL hwndTCP         AS LONG
                                        
                                        FUNCTION PBMAIN () AS LONG
                                          LOCAL hThread AS LONG
                                          THREAD CREATE WindowThread(%NULL) TO hThread&
                                          THREAD CLOSE hThread& TO hThread&
                                          ClientHere
                                          SendMessage hwndTCP, %WM_CLOSE, 0, 0
                                        END FUNCTION
                                        '--------------------------  Client code --------------------------------------------------------
                                        SUB ClientHere
                                          LOCAL nSocket AS LONG
                                          LOCAL x AS LONG
                                          LOCAL sBuffer AS STRING
                                          LOCAL sPacket AS STRING
                                        DO
                                        
                                          #IF %DEF(%PB_CC32)
                                            ? STRING$(60,"-")
                                            LINE INPUT ">";sBuffer
                                          #ELSE
                                            sBuffer = INPUTBOX$("Send this to server","Client")
                                          #ENDIF
                                          IF LEN(sBuffer) = 0 THEN EXIT DO
                                        
                                          'Client open
                                          nSocket = FREEFILE
                                          TCP OPEN PORT %PortNumber AT $Ip AS #nSocket
                                          IF ERR THEN
                                            ? "Client unable to open port" + STR$(%PortNumber)
                                            EXIT SUB
                                          END IF
                                        
                                          'Client send
                                          TCP PRINT #nSocket, sBuffer
                                          sBuffer = ""
                                          sPacket = ""
                                          'Client wait for response
                                          DO
                                            TCP RECV nSocket, 1024, sBuffer
                                            sPacket = sPacket & sBuffer
                                          LOOP UNTIL sBuffer = "" OR ISTRUE EOF(nSocket) OR ISTRUE ERR
                                          TCP CLOSE #nSocket  'no reason to leave open
                                        
                                          IF LEN(sPacket) THEN
                                            #IF %DEF(%PB_CC32)
                                             ? sPacket
                                            #ELSE
                                            BEEP
                                              ? sPacket,,"From port" + STR$(%PortNumber)
                                            #ENDIF
                                          END IF
                                        LOOP
                                        
                                        END SUB
                                        '------------------------------------------------------------------------------
                                        FUNCTION MakeWindow () AS LONG
                                            LOCAL wce         AS WndClassEx
                                            LOCAL szClassName AS ASCIIZ * 64
                                            LOCAL hWnd        AS LONG
                                            LOCAL hInst       AS LONG
                                            STATIC registered AS LONG
                                            hInst = GetModuleHandle(BYVAL %NULL)
                                            IF ISFALSE registered THEN
                                                szClassName          = "PBTCPCOMM"
                                                wce.cbSize           = SIZEOF(wce)
                                                wce.style            = %CS_HREDRAW OR %CS_VREDRAW
                                                wce.lpfnWndProc      = CODEPTR(TcpProc)
                                                wce.cbClsExtra       = 0
                                                wce.cbWndExtra       = 0
                                                wce.hInstance        = hInst
                                                wce.hIcon            = %NULL
                                                wce.hCursor          = %NULL
                                                wce.hbrBackground    = %NULL
                                                wce.lpszMenuName     = %NULL
                                                wce.lpszClassName    = VARPTR(szClassName)
                                                wce.hIconSm          = %NULL
                                                RegisterClassEx wce
                                                registered = %TRUE
                                            END IF
                                            hWnd = CreateWindow(szClassName, _
                                                                "TCP Handler", _
                                                                %WS_OVERLAPPEDWINDOW, _
                                                                5, 5, 10, 10, _
                                                                %NULL, _
                                                                %NULL, _
                                                                hInst, _
                                                                BYVAL %NULL)
                                            IF ISFALSE hWnd THEN
                                                hWnd = GetLastError
                                            ELSE
                                                ShowWindow hWnd, %SW_HIDE
                                                UpdateWindow hWnd
                                            END IF
                                            FUNCTION = hWnd
                                        END FUNCTION
                                        '------------------------------------------------------------------------------
                                        ' Callback function to handle events for the GUI window
                                        '
                                        FUNCTION TcpProc (BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
                                                          BYVAL wParam AS LONG, BYVAL lParam AS LONG) EXPORT AS LONG
                                            STATIC hServer AS LONG
                                            STATIC hEcho   AS LONG
                                            LOCAL  sBuffer AS STRING
                                            LOCAL  sPacket AS STRING
                                            SELECT CASE wMsg
                                            CASE %WM_CREATE
                                                hServer = FREEFILE
                                                TCP OPEN SERVER PORT %PortNumber AS hServer TIMEOUT 2000
                                                IF ERR THEN
                                                    sBuffer = "Couldn't create socket!"
                                                ELSE
                                                    TCP NOTIFY hServer, ACCEPT TO hWnd AS %TCP_ACCEPT
                                                    sBuffer = "Connected to Port" + STR$(%PortNumber)
                                                END IF
                                                hEcho = %INVALID_SOCKET
                                                FUNCTION = 1
                                            CASE %TCP_ACCEPT
                                                SELECT CASE LO(WORD, lParam)
                                                CASE %FD_ACCEPT
                                                    hEcho = FREEFILE
                                                    TCP ACCEPT hServer AS hEcho
                                                    TCP NOTIFY hEcho, RECV CLOSE TO hWnd AS %TCP_ECHO
                                                END SELECT
                                                FUNCTION = 1
                                            CASE %TCP_ECHO
                                                SELECT CASE LO(WORD, lParam)
                                                CASE %FD_READ
                                                    IF hEcho <> %INVALID_SOCKET THEN
                                                        ' Perform a receive-loop until there is no data left (ie, the end of stream)
                                                   '---------------------------------------------------------------------------
                                                        sBuffer = ""
                                                        sPacket = ""
                                                        DO
                                                          TCP RECV hEcho, 1024, sBuffer
                                                          sPacket = sPacket & sBuffer
                                                        LOOP UNTIL sBuffer = "" OR ISTRUE EOF(hEcho) OR ISTRUE ERR
                                                   '---------------------------------------------------------------------------
                                                        'Server will send back
                                                        IF LEN(sPacket) THEN
                                                          TCP SEND hEcho, FORMAT$(LEN(sPacket)) + " bytes echoed back from " + TCPADDR(hEcho) + "(" + sPacket + ")"
                                                        END IF
                                                    'ELSE
                                                    END IF
                                                CASE %FD_CLOSE
                                                    TCP CLOSE hEcho
                                                    hEcho = %INVALID_SOCKET
                                                    '? "Closed hEcho socket"
                                                END SELECT
                                                FUNCTION = 1
                                            CASE %WM_DESTROY
                                                TCP CLOSE hServer
                                            END SELECT
                                            FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)
                                        END FUNCTION
                                        '------------------------------------------------------------------------------
                                        THREAD FUNCTION WindowThread (BYVAL nIgnored AS LONG) AS LONG
                                            LOCAL Msg AS tagMsg
                                            hwndTCP = MakeWindow
                                            DO WHILE IsWindow(hwndTCP) AND GetMessage(Msg, %NULL, 0, 0)
                                                TranslateMessage Msg
                                                DispatchMessage Msg
                                            LOOP
                                        END FUNCTION
                                        '------------------------------------------------------------------------------
                                        FUNCTION TCPADDR(BYVAL lSock AS LONG) AS STRING
                                          'Paul Purvis code to get remote IP and port from client
                                          LOCAL sa AS sockaddr_in
                                          LOCAL l AS LONG
                                          LOCAL lHandle AS LONG
                                          LOCAL b AS BYTE PTR
                                          LOCAL lSockHandle AS LONG
                                          lSockHandle = FILEATTR(lSock,2)
                                          l = SIZEOF(sa)
                                          IF getpeername(lSockHandle, BYVAL VARPTR(sa), l) = 0 THEN
                                            'b = VARPTR(sa.sin_addr.s_addr) 'return IP address of connection
                                            b = VARPTR(sa.sin_addr) 'return IP address of connection
                                        
                                            FUNCTION = USING$("#_.#_.#_.#", @b, @b[1], @b[2], @b[3]) + " on remote port" + STR$(sa.sin_port)
                                          END IF
                                        END FUNCTION

                                        Comment

                                        Working...
                                        X