1. Communicating processes using WM_COPYDATA
- Posted by Pete Lomax <petelomax at blueyonder.co.uk> Apr 01, 2005
- 558 views
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
2. Re: Communicating processes using WM_COPYDATA
- Posted by Bernie Ryan <xotron at bluefrog.com> Apr 01, 2005
- 506 views
- Last edited Apr 02, 2005
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
3. Re: Communicating processes using WM_COPYDATA
- Posted by Pete Lomax <petelomax at blueyonder.co.uk> Apr 02, 2005
- 518 views
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.
4. Re: Communicating processes using WM_COPYDATA
- Posted by Bernie Ryan <xotron at bluefrog.com> Apr 02, 2005
- 519 views
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
5. Re: Communicating processes using WM_COPYDATA
- Posted by Pete Lomax <petelomax at blueyonder.co.uk> Apr 02, 2005
- 522 views
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
6. Re: Communicating processes using WM_COPYDATA
- Posted by jacques deschĂȘnes <desja at globetrotter.net> Apr 02, 2005
- 516 views
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.
7. Re: Communicating processes using WM_COPYDATA
- Posted by Al Getz <Xaxo at aol.com> Apr 02, 2005
- 541 views
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"