Announcement

Collapse
No announcement yet.

Sending data between apps.

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

  • Sending data between apps.

    When an app is started and a previous instance is present,
    I want to forward the command-line to the previous instance.

    This works:
    Code:
        MyMessage = RegisterWindowMessage("DoCmdLine")
        If FindWindow(ByVal StrPtr(Class$), ByVal %NULL) Then
         TmpWnd& = FindWindow(ByVal StrPtr(Class$), ByVal %NULL)
         If IsIconic(TmpWnd&) Then ShowWindow TmpWnd& ,%SW_RESTORE
         SetForegroundWindow TmpWnd&
         Call SendMessage(TmpWnd&,MyMessage,ByVal StrPtr(CmdLine$),ByVal Len(CmdLine$))
         Function = 0:Exit Function
        End If
    This is executed but there are no data...
    Code:
        Select Case Msg&
         Case MyMessage
          CmdLine$ = Peek$(wParam&,lParam&)
          Call ExecuteCmdLine(CmdLine$)
          Function = 0:Exit Function
     ...etc
    I have tried globalAlloc/globalLock/globalunlock with no success
    Would certainly need some advice here...
    Thank you




    -------------
    Fred
    mailto:[email protected][email protected]</A>
    http://www.oxenby.se

    Fred
    mailto:[email protected][email protected]</A>
    http://www.oxenby.se

  • #2
    With StrPtr(CmdLine$) it was go/nogo, sometimes it worked
    sometimes not.
    Changed my code to this and it seems to work all the time
    even with a blank cmdline

    Code:
    Function WinMain (BYVAL hInstance     AS LONG, _
                      BYVAL hPrevInstance AS LONG, _
                      lpCmdLine           AS ASCIIZ PTR, _
                      BYVAL iCmdShow      AS LONG) AS LONG
    
    Local Msg As tagMsg
    Local wc  As WndClassEx
    Local sk  As skall    
    Local TmpWnd&,CmdLine$,hParent&,FServer$,TrText$
    
        ReDim gDlgId(%Tx_Start To %Tx_Slut)
        Title$       = "Transaktionsregister"
        Class$       = "CLSTRANS"
    '--Get the cmdLine-------------------------------    
        CmdLine$ = UCase$(@lpCmdLine)
    '--IsPrevInst? ----------------------------------
        MyMessage = RegisterWindowMessage("DoCmdLine")
        If FindWindow(ByVal StrPtr(Class$), ByVal %NULL) Then
         TmpWnd& = FindWindow(ByVal StrPtr(Class$), ByVal %NULL)
         Call SendMessage(TmpWnd&,MyMessage,lpCmdLine,ByVal Len(CmdLine$))
         If IsIconic(TmpWnd&) Then ShowWindow TmpWnd& ,%SW_RESTORE
         SetForegroundWindow TmpWnd&
         Function = 0:Exit Function
        End If
    ...
    ...

    ------------------
    Fred
    mailto:[email protected][email protected]</A>
    http://www.oxenby.se

    Fred
    mailto:[email protected][email protected]</A>
    http://www.oxenby.se

    Comment


    • #3
      The effect you noticed with STRPTR could be due to dynamic memory re-allocation - the handle is fixed but the pointer is not guaranteed to say the same - at least that's my understanding.

      Cheers

      Florent

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

      Comment


      • #4
        Fred --
        there is a nice method - %WM_COPYDATA (see my samples of global hooks, #2)

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

        Comment


        • #5
          The technique is known as "Inter-Process Communication" (IPC).

          Firstly, it is important to note that even separate instances of the same application occupy separate address spaces, so it is not possible to just pass a pointer to a string from one process to another - the address will be meaningless to the target process because memory address space is private to each process. Attempting to do this will earn you one GPF point for trying.

          %WM_COPYDATA gets around this for small quantities of data, as Windows handles the transfer of the target data block between the two process's address space. Using the %WM_COPYDATA message is really the easiest technique, but there are other ways to perform IPC. The best solution depends on the amount of data you wish to send between processes.

          If you search this BBS for "WM_COPYDATA" you should find some more information, and a link to Don Dickinson's web site that features some IPC code.

          Also, a search for "IPC" on msdn.microsoft.com should reveal a lot more information.



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

          Comment


          • #6
            Originally posted by Lance Edmonds:
            The technique is known as "Inter-Process Communication" (IPC).
            Firstly, it is important to note that even separate instances of the same application occupy separate address spaces, so it is not possible to just pass a pointer to a string from one process to another - the address will be meaningless to the target process because memory address space is private to each process. Attempting to do this will earn you one GPF point for trying.
            Well I dont know, but this is fron MSDN
            The RegisterWindowMessage function is typically used to register messages for communicating between two cooperating applications.
            and IMHO this would be meaningless if the two applications could
            not share the data....
            Anyhow, my simple solution uses a pointer to the applications command-line, perhaps this is why it works in WIN98/WIN2000



            ------------------
            Fred
            mailto:[email protected][email protected]</A>
            http://www.oxenby.se

            Fred
            mailto:[email protected][email protected]</A>
            http://www.oxenby.se

            Comment


            • #7
              Fred --
              Lance told well-known thing, described in all API books.
              RegisterWindowMessage doesn't design to share the data beetween processes.
              Sure, that your solution "works" until you will start some new apps.
              Sometimes I encounted very strange situations: during debugging I deleted SelectObject hDC, hBmp, but saw a picture.
              Of course, all finished after starting Word.

              WM_COPYDATA message is specially designed to pass data (but not pointers) to another application.
              I only don't understand, why Lance talks "small pieces".
              I don't see length restrictions (another question, read-only and so on).

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

              Comment


              • #8
                Fred,

                You have DV32, don't you?

                Then see dvCreateCommonZone it creates a common zone of memory to be used by any number of DV32 applications to share data, or retrieves it in case a common zone with the same name already exists.
                See also the COMZON1.BAS and COMZON2.BAS examples.




                ------------------
                Patrice Terrier
                mailto[email protected][email protected]</A>
                Patrice Terrier
                www.zapsolution.com
                www.objreader.com
                Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

                Comment


                • #9
                  Fred,

                  I would be inclined to try out the methods that Lance and Semen have
                  suggested and see if you can get it going. I have lost the example code
                  I had but the process of memory mapped files may do the job for you
                  as well.

                  A long time ago I have used DDE but unless you particularly need that
                  style of code, I would be inclined to avoid it as it is no joy to get
                  going reliably.

                  A while ago, one of the members posted the code for memory mapped files
                  and it looked straight forward enough.

                  Regards,

                  [email protected]

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

                  www.masm32.com

                  Comment


                  • #10
                    Yes Patrice, I know that this is possible in DV32,but this is a small function I want
                    to implement via API-calls.
                    I am not using %WM_COPYDATA because I don't fully understand the COPYDATASTRUCT
                    Members
                    dwData Specifies data to be passed to the receiving application.
                    cbData Specifies the size, in bytes, of the data pointed to by the lpData member.
                    lpData Pointer to data to be passed to the receiving application. This member can be NULL.
                    If someone can explain in "simple english for infants" I am listening...
                    dwData => ULONG_PTR (?) Why a pointer
                    Is this member not used to identify (describe) the data to the
                    receiving party, so it can decide what to do with it..?
                    -----------
                    My example, sending the pointer to the cmdline Windows provided at application start,
                    seems to be a special case. It works in win95/98/NT4/Win2000 as far as my testing goes.
                    Anything else (but this pointer) fails, and you good guys have explained why.
                    -----------

                    ------------------
                    Fred
                    mailto:[email protected][email protected]</A>
                    http://www.oxenby.se

                    Fred
                    mailto:[email protected][email protected]</A>
                    http://www.oxenby.se

                    Comment


                    • #11
                      The COPYDATASTRUCT is simply a UDT that you place an arbitary 32 bit value, the length of the data (LEN or SIZEOF), plus a pointer to the data (STRPTR).

                      When you use the WM_COPYDATA message, Windows takes the data that the COPYDATASTRUCT points to, and places a copy of it in the target applications address space, records the pointer of this new then sends the "new" address to the target process's message queue via a %WM_COPYDATA message. The target app should immediately allocate it's own storage space anc copy the data using the pointer and length detailed in the COPYDATASTRUCT passed to it.

                      Dead simple. (Note, this is a fairly non-technical description, good enough for these discussions... lets NOT get into discussions on how memory mapping between processes is implemented by Windows... please!)

                      OTOH, RegisterWindowMessage() does not provide a way to pass anything more than two 32-bit values via the WPARAM and LPARAM message parameters. As I noted earlier, pointers to data in one process are meaningless to another process, so passing pointers through a registered message breaks the rules.

                      It appears that your tests using just the command-line parameter is exploting a loophole of some kind. I'd personally never use that technique in a commercial application as it stands a very good chance of incompatibility (ie it may fail) with future versions of Windows or service packs.



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

                      Comment


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

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

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

                        Comment


                        • #13
                          Semen, you are a gentleman and a scholar! Thanks so
                          much for these excellent examples, the speed with which
                          you knock these out blows me away. You are much appreciated!

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

                          Comment


                          • #14
                            Code:
                            Thank you guys for your enormous support.
                            I was stumbling over this little quirk in a
                            project where a separate "error-clean-up" application
                            would be callable from other running applications on a single PC.
                            The Idea was based on the fact that "automation-software" is seldom
                            supervised. It often take long time before operators notice that this
                            kind of software has generated an log entry of a kind.
                            Automation-software has to abandon a "lost job" and go on with things
                            it CAN do, leaving to someone else to clean up the mess.
                            Especially loss of network-resources are hard to catch, as it often
                            is a certain unit using that resource, getting the error,and other units
                            are not affected.
                            '----------------
                            My first idea was to register a message and send the cmdline in this message.
                            This worked fine. No need for another sulotion.
                            Later this code were changed, instead of the original pointer to cmdline,
                            we used a pointer to a copy of cmdline. And this did not work.
                            For obvious reason as Lance would put it. ):
                            '----------------
                            I have JCFullers Memshare-example, it looked very easy to implement, easy
                            to understand, but MSDN-s description of COPYDATASTRUCT did not comply with 
                            JC's example. Sometimes English is a hard to understand.....
                            Lance's explanation made it somewhat easier.
                            Of course WM_COPYDATA is the route to take, it is more comprehensive
                            '----------------
                            So, once more: thank you Lance,Semen,Steve,Patrice,Florent and everybody else
                            making this forum to such a great source for knowledge and inspiration.
                            ------------------
                            Fred
                            mailto:[email protected][email protected]</A>
                            http://www.oxenby.se

                            Fred
                            mailto:[email protected][email protected]</A>
                            http://www.oxenby.se

                            Comment


                            • #15
                              I haven't seen anyone mention DDE. This is particularly
                              suprising since the windows shell will automatically use
                              DDE to pass the name of a double-clicked file to the file's
                              associated EXE if the EXE is already running and if such
                              DDE commands have been registered.

                              For example:

                              Code:
                              REGEDIT
                              HKEY_CLASSES_ROOT\.xxx = MYEXEFILE
                              HKEY_CLASSES_ROOT\MYEXEFILE = Special File for MyEXE
                              HKEY_CLASSES_ROOT\MYEXEFILE\shell\open\command = MYEXE.EXE /%1
                              HKEY_CLASSES_ROOT\MYEXEFILE\shell\open\ddeexec = LOAD %1
                              HKEY_CLASSES_ROOT\MYEXEFILE\shell\open\ddeexec\application = MYEXE
                              HKEY_CLASSES_ROOT\MYEXEFILE\shell\open\ddeexec\topic = System
                              The preceeding lines, placed in a .REG file will:

                              1. associate files with extension .xxx to MYEXE.EXE
                              2. launch "MYEXE.EXE /[filename]" when I double click an
                              .xxx file AND MYEXE.EXE is not yet running
                              3. send "LOAD [filename]" as a DDE command to MYEXE.EXE
                              if MYEXE.EXE is already running



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

                              Comment

                              Working...
                              X