1. Communicating processes using WM_COPYDATA

I've got this working, but it begs a question.

Two programs, P and Q, (both exw, sorry Tone) are communicating using
the WM_COPYDATA method.

Let's say P wants to get a string from Q. My first instinct was that P
sends a message, which Q replies to by allocating some space, poking
the text into it, and returning the address. However the peek (in P)
crashes. Scratching my head, and with a WM_GETTEXTLENGTH/ allocate/
WM_GETTEXT immediately above, I tried that approach, and it worked
fine, ie P asks Q how long the string it wants is, allocates space,
and then passes a memory address to Q for storing the string in.

My question is: Does this mean a windows program can /*poke*/ into the
memory space of another process, but cannot peek it?

That just seems completely the wrong way round! It would certainly
explain why windows programs so often manage to kill off other
programs! Wouldn't it have been smarter to 1) P asks Q to allocate,
poke and return the address, 2) P lets Q know it can now free() that
memory?

Confused,
Pete

new topic     » topic index » view message » categorize

2. Re: Communicating processes using WM_COPYDATA

Pete:
  When ever you receive a pointer to some data from
  windows I read somewhere that you must immediately
  make a copy of the data when you receive the message
  because the data will no longer be valid on the next message.

Bernie

My files in archive:
w32engin.ew mixedlib.e eu_engin.e win32eru.ew

Can be downloaded here:
http://www.rapideuphoria.com/cgi-bin/asearch.exu?dos=on&win=on&lnx=on&gen=on&keywords=bernie+ryan

new topic     » goto parent     » topic index » view message » categorize

3. Re: Communicating processes using WM_COPYDATA

On Fri, 01 Apr 2005 13:00:07 -0800, Bernie Ryan
<guest at RapidEuphoria.com> wrote:

>Pete:
>  When ever you receive a pointer to some data from
>  windows I read somewhere that you must immediately
>  make a copy of the data when you receive the message
>  because the data will no longer be valid on the next message.
I did it immediately. The case was P asking Q for a string:
--(NB: I've deleted the actual code, this is best recollection)
Q:
	elsif msg = CD_FILE then
		text=string&0
		mem=allocate(length(text))
--		?mem
		poke(mem,text)
		return {mem}

P:
	poke4(CDS,{CD_FILE,0,0})
	mem=c_func(xSendMessage,{hwnd, WM_COPYDATA, NULL, CDS})
--	?mem
	text=peek_string(mem)	-- <<== //**CRASHES**//


The peek() crashed no matter what; the memory address was correct (I
even tried a hard-coded length). Are you saying that peek in this way
may sometimes work?

Steadily getting even more confused, if that is possible,
Pete

PS lest anyone misinterpret, this is not about the RDS implementation
of peek and poke, but about what is and what is not a valid memory
address under the windows OS, I think.

new topic     » goto parent     » topic index » view message » categorize

4. Re: Communicating processes using WM_COPYDATA

Pete Lomax wrote:
> 
> On Fri, 01 Apr 2005 13:00:07 -0800, Bernie Ryan
> <guest at RapidEuphoria.com> wrote:
> 
> >Pete:
> >  When ever you receive a pointer to some data from
> >  windows I read somewhere that you must immediately
> >  make a copy of the data when you receive the message
> >  because the data will no longer be valid on the next message.
> I did it immediately. The case was P asking Q for a string:
> }}}
<eucode>
> --(NB: I've deleted the actual code, this is best recollection)
> Q:
> 	elsif msg = CD_FILE then
> 		text=string&0
> 		mem=allocate(length(text))
> --		?mem
> 		poke(mem,text)
> 		return {mem}
> 
> P:
> 	poke4(CDS,{CD_FILE,0,0})
> 	mem=c_func(xSendMessage,{hwnd, WM_COPYDATA, NULL, CDS})
> --	?mem
> 	text=peek_string(mem)	-- <<== //**CRASHES**//
> 
> </eucode>
{{{

> 
> The peek() crashed no matter what; the memory address was correct (I
> even tried a hard-coded length). Are you saying that peek in this way
> may sometimes work?
> 
> Steadily getting even more confused, if that is possible,
> Pete
> 
> PS lest anyone misinterpret, this is not about the RDS implementation
> of peek and poke, but about what is and what is not a valid memory
> address under the windows OS, I think.
> 
> 

Pete:

   Your setting DWORD cbData as ZERO

typedef struct tagCOPYDATASTRUCT {  // cds 
    DWORD dwData; 
    DWORD cbData; 
    PVOID lpData; 
} COPYDATASTRUCT; 
 
Members
dwData 
Specifies up to 32 bits of 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

Bernie

My files in archive:
w32engin.ew mixedlib.e eu_engin.e win32eru.ew

Can be downloaded here:
http://www.rapideuphoria.com/cgi-bin/asearch.exu?dos=on&win=on&lnx=on&gen=on&keywords=bernie+ryan

new topic     » goto parent     » topic index » view message » categorize

5. Re: Communicating processes using WM_COPYDATA

On Fri, 01 Apr 2005 16:38:42 -0800, Bernie Ryan
<guest at RapidEuphoria.com> wrote:

>Pete:
>
>   Your setting DWORD cbData as ZERO
>
>typedef struct tagCOPYDATASTRUCT {  // cds 
>    DWORD dwData; 
>    DWORD cbData; 
>    PVOID lpData; 
>} COPYDATASTRUCT; 
> 
Bernie, my instinctive idea was that P send no data whatsoever to Q,
just a request. I was expecting back a memory address (which I got
correctly, but could not peek).

However, I think you may have hinted at the concept I am missing.
If P creates and passes a memory area, and *SendMessage* marks that
memory area (or more likely an entire page of the heap) as writeable
by Q then my fears are allayed. Still seems a bit odd though. Far
safer (and easier, IMO) that Q should only ever be allowed to write to
(heap) pages it owns, rather than a read by P triggering a segfault.

Nevermind, I'm sure there are even worse guffs in the windows API.

Regards,
Pete

new topic     » goto parent     » topic index » view message » categorize

6. Re: Communicating processes using WM_COPYDATA

Pete,
Here an excerpt from msdn library about  WM_COPYDATA

WM_COPYDATA Message

An application sends the WM_COPYDATA message to pass data to another
application.

Syntax

To send this message, call the SendMessage function as follows.

    lResult = SendMessage( 	    // returns LRESULT in lResult
       (HWND) hWndControl, 	    // handle to destination control
       (UINT) WM_COPYDATA, 	    // message ID
       (WPARAM) wParam, 	    // = (WPARAM) () wParam;
       (LPARAM) lParam 	    // = (LPARAM) () lParam;
    ); 	

Parameters

    wParam
        Handle to the window passing the data. 
    lParam
Pointer to a COPYDATASTRUCT structure that contains the data to be
        passed.

Return Value

If the receiving application processes this message, it should return TRUE;
    otherwise, it should return FALSE.


Remarks

The data being passed must not contain pointers or other references to
    objects not accessible to the application receiving the data.

While this message is being sent, the referenced data must not be changed by
    another thread of the sending process.

The receiving application should consider the data read-only. The lParam
    parameter is valid only during the processing of the message. The receiving
    application should not free the memory referenced by lParam. If the receiving
    application must access the data after SendMessage returns, it must copy the data
    into a local buffer.

new topic     » goto parent     » topic index » view message » categorize

7. Re: Communicating processes using WM_COPYDATA

Hi Pete,

Using COPYDATA to send stuff from one process to another is only
one step harder than using SendMessage, and it always works properly
if everything is done correctly.  I use this technique for my
function calculator which has to send lots of data from one open
calculator to another, and i've tested it under Win98 and XP with
no problems.

Since you want P to send a request to Q for Q to send data to P
you can have P send Q a message requesting data and have Q allocate
and send WM_COPYDATA to P, at which time P can read the data.
This will *definitely* work ok.

One way to do this (which would also allow either process to act
as either P or Q at any time) is to have P send WM_COPYDATA with
ulong set to 'constant REQUEST_DATA=1' (or whatever you like) and
Q can respond by simply returning '1' for ok and '2' for not ok
(or whatever) and P goes idle, then Q can allocate and poke and
send WM_COPYDATA to P, then P reads the data and returns from
its WM_COPYDATA call so Q can be ready for the next request.
Taken one step at a time it's not difficult.

There's never a problem peeking the data that is sent to another
process via WM_COPYDATA but Microsoft doesnt allow poking into
that received memory or freeing it, nor expecting it to be constant
once the WM_COPYDATA call returns.  This of course means that only
the process that *SENDS* the WM_COPYDATA message should poke data.


Here's an excerpt from my function calculator...

(note: onCopyData is just WM_COPYDATA really with added 'atom ID')

function onCopyData_MainAppWindow(atom ID,atom hWnd,atom uMsg, atom wParam, atom
lParam)
  atom hWndFrom,pCDS,ulong,cb,pData,pWT
  sequence data

  hWndFrom=wParam --the hwnd of the calling process window
  pCDS=lParam     --the COPYDATA struct

  ulong=peek4u(pCDS) --user data, used as function id here
  cb=peek4u(pCDS+4) --number of bytes pointed to by pData
  pData=peek4u(pCDS+8) --bytes pointer
  data=peek({pData,cb-1})--leave off the terminating 0 (for this partic app)

  --now process ulong as function id's returning whatever per function...
  if ulong=1 then
    --do function #1 (like process request for data)
    return whatever1
  elsif ulong=2 then
    --do function #2 (like receive data)
    return whatever2
  end if

end function


The sending process must set up the struct and poke in ulong, cb, and
the pointer.


Take care,
Al

And, good luck with your Euphoria programming!

My bumper sticker: "I brake for LED's"

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu