May 07, 2024, 10:59:59 PM

News:

IonicWind Snippit Manager 2.xx Released!  Install it on a memory stick and take it with you!  With or without IWBasic!


Passing strings between applications

Started by ZeroDog, July 29, 2007, 03:40:16 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

ZeroDog

July 29, 2007, 03:40:16 PM Last Edit: July 29, 2007, 04:12:03 PM by ZeroDog
I've been trying to pass a string variable from one instance of my program to another instance via the sendmessage function without any sucess.  Basically,  what I'm doing is creating a media player.  When the media player is running, and someone clicks on a media file, or drops a file on the media player icon, it should check to see if the player is running,  if it is, then it should send the filename of the media file to the previously running instance of the player, and exit.  everything works fine, except it's not passing the string correctly.  Obviously, I'm doing something wrong.     I just can't figuure out what. 

compile the program, and run it.  then drag and drop a file on the .exe file while the first instance is still running.  it *should* print the filename in the window.  but I get something like H|A ...  Any help or ideas would be much appreciated. 


a string via SendMessage test
DECLARE IMPORT,GetCommandLineA(),STRING
DECLARE IMPORT,FindWindowA(lpClassName:STRING, lpWindowName:STRING),INT
HwndResult = FindwindowA("EmergenceWndClass","TestWindow")
if HwndResult<>0
Filename=GetCommandLineA()
Filename=MID$(Filename,INSTR(Filename,".exe")+6)
if Filename<>""
sendmessage(HwndResult, 9999, 0, Filename)
endif
end
endif

def win:window

openwindow win,0,0,400,200,@CAPTION,0,"TestWindow",&winproc

run=1
waituntil run=0
closewindow win
end

sub winproc
select @class
case 9999
move win,0,0
print win, ##<string>@lparam

case @idclosewindow
run=0

endselect
return
endsub

srod

Hi,

afraid you are not going to be able to send a string this way. The second process is unable to directly access the memory of the first process. There are various ways of achieving what you're after and they are generally a little more complex than simply sending a message.

I can outline a couple of methods but I'm afraid my EMBasic skills are not quite advanced enough for me to hack up a working example as yet. (I'll soon be there though!  ;) )

One way is to use the process memory functions. Your first process would allocate some memory in the second process; write the name of the file to this memory and then send a message with the address of this memory etc. The second process could use a simple pointer to get at this string. On return the first process frees this memory etc.  This could work quite well with the code you've posted above; you just need to get a-hold of the process id of the second process with GetWindowThreadProcessId() etc.

An alternative method is to use named pipes which are pretty cool!  Fiddly at first but quite powerful.

By the way you can use a static control to pass text between processes. Open up an invisible static control in the first process, place the name of the file in it. Send a message to the second thread with the handle of the static control in lParam and use api #WM_GETTEXT etc.  I've used this cheeky method in the past!  Windows handles all the inter-process communication in such cases.



SnarlingSheep

July 29, 2007, 04:44:32 PM #2 Last Edit: July 29, 2007, 05:15:51 PM by SnarlingSheep
I've always used GlobalAddAtom in the second instance of the program, to add the string(path to media file) to the atom table.
Then SendMessage the Atom ID to the first instance.
Then GlobalGetAtomName in the first instance to retrieve that string.

srod

Now why did I never think of that?   :-[

Nice method.

SnarlingSheep

Quote from: srod on July 29, 2007, 04:53:40 PM
Now why did I never think of that?   :-[
I think you have to run head-first into a few brick walls first.. worked for me. :)

srod

Quote from: SnarlingSheep on July 29, 2007, 05:16:45 PM
Quote from: srod on July 29, 2007, 04:53:40 PM
Now why did I never think of that?   :-[
I think you have to run head-first into a few brick walls first.. worked for me. :)

I'll give that a go asap. Sounds like fun!  ;D

SnarlingSheep


sapero

July 29, 2007, 05:34:20 PM #7 Last Edit: July 29, 2007, 05:46:02 PM by sapero
Hey ZD!
Use the old trick with remote memory:
1. having the hwnd, get the process id (int) by calling GetWindowThreadProcessId(hwnd, &pid)
2. having the pid, open the process: hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid)
3. allocate memory in remote process: memo = VirtualAllocEx(hProcess, 0, 4096, MEM_COMMIT, PAGE_READWRITE) // 4096=minimal memory chunk, standard page size
4. Copy your string to opened processWriteProcessMemory(hProcess, memo, Filename, len(Filename)+1, 0)
5. send the message, replacing Filename with memo:sendmessage(HwndResult, 9999, 0, memo) // the process will read from valid address
6. more messages ?
7. read back the string ? if yes, use Read- instead Write- ProcessMemory
8. cleanup: VirtualFreeEx(hProcess, memo, 0, MEM_RELEASE) : CloseHandle(hProcess)

Or send the properr message - WM_DROPFILES: use GlobalAlloc(GMEM_MOVEABLE, 300) to allocate DROPFILES structure +string, lock the memory (GlobalLock), fill the struct, append the string to it, unlock the memory and send WM_DROPFILES message. It will work as someone would drag-drop a file on this window

ZeroDog

:)  Thanks for the ideas

I've already set the program up for drag and drop operation, so perhaps I'll try the lst suggestion first.
I had considered other alternatives such as copying the filename to the clipboard, or sending each character in a seperate message, but some of these suggestions are much better. :)

Thanks again, and I'll post my media player for all to play with when it's done.

-= ZeroDog =-


LarryMc

Quote from: ZeroDog on July 29, 2007, 07:50:37 PM
:)  Thanks for the ideas

I've already set the program up for drag and drop operation, so perhaps I'll try the lst suggestion first.
I had considered other alternatives such as copying the filename to the clipboard, or sending each character in a seperate message, but some of these suggestions are much better. :)

Thanks again, and I'll post my media player for all to play with when it's done.

-= ZeroDog =-


I've got exactly the same problem right now.
You don't happen to have the code you used to create the drag/drop stil laround do you?

It would save me a lot of trial and error.

LarryMc
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

LarryMc

Found some old code by bevets that I was able to adapt and now have that part working.
thanks anyway.

LarryMc
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

ZeroDog

April 18, 2012, 11:05:03 PM #11 Last Edit: April 18, 2012, 11:10:04 PM by ZeroDog
I actually wrote a drag and drop tutorial that never made it to the forums:

'ZeroDog's Tips N Tricks
'Fun With Windows
'Part 8 - Drag 'N Drop Windows
'*******************************

'Creating windows that you can drop files into is easy to do with
'only a few commands.  We can modify any window to accept files
'by using the MODIFYEXSTYLE function with the WS_EX_ACCEPTFILES flag,
'or we can use the DragAcceptFiles function to setup the window for
'drag and drop operation. Either method has the same results. Then we
'simply respond to the WM_DROPFILES window message that our window
'is sent when a file is dropped.  To get the filename of the file
'that was dropped we can use the DragQueryFileA function. You can
'Get the x,y point at which the file was dropped in the window by
'using the DragQueryPoint function.

'First thing we need to do is define our window variable.
DEF win:WINDOW

'Now declare the API function calls (we can IMPORT from user32.dll)
DECLARE IMPORT, DragQueryFileA(hDrop:INT, iFile:UINT, lpStr:STRING, lpSize:INT),INT
'hDrop is the handle to the drop message. Found in the @WPARAM of the WM_DROPFILES @MESSAGE
' Ex: @WPARAM
'iFile is the Index of the file to query.
'If the value of the iFile parameter is 0xFFFFFFFF, DragQueryFile returns a count of the files dropped.
'If the value of the iFile parameter is between zero and the total number of files dropped,
'DragQueryFile copies the file name with the corresponding value to the buffer pointed to by the lpszFile parameter.
'In this case, we're only testing the first file dropped, so we will set it to 0 
' Ex: 0
'lpStr is string that will be recieving the filename of the file dropped
' Ex: Filename
'lpSize is the size of the string that will be used to recieve the filename
' Ex: 10000
'Example useage of the function:
'DragQueryFileA(@WPARAM,0,Filename,10000)
DECLARE IMPORT, DragQueryPoint(hDrop:INT, lpPoint:POINT),INT
'hDrop is the handle to the drop message. Found in the @WPARAM of the WM_DROPFILES @MESSAGE
' Ex: @WPARAM
'lpPoint is a POINT type structure (x,y) that will be receiving the position where the file was dropped
' Ex: DropPoint
'Example useage of the function:
'DragQueryPoint(@WPARAM,DropPoint)
DECLARE IMPORT, DragAcceptFiles(hwnd:INT, fAccept:INT)
'hwnd is the handle of the window that you want to enable/disable dropping of files onto
' Ex: win.hwnd
'fAccept is the true/false flag.  If set to TRUE (1) then the dropping will be enabled
' Ex: 1
'Example useage of the function:
'DragAcceptFiles(win.hwnd,1)

'Set the constant that we will be using with the MODIFYEXSTYLE.
CONST WS_EX_ACCEPTFILES = 0x10
'Set the  window message constant that is sent when a file is dropped on the window.
CONST WM_DROPFILES = 0x233

'Define the POINT structure to recieve the coords of where the file is dropped in the window.
DEF DropPoint:POINT
'Define the ISTRING we will use to recieve the filename of the file that is dropped.
DEF Filename[10000]:ISTRING

'Now we open up our window.
OPENWINDOW win, 0,0,400,200,@CAPTION|@SIZE|@TOPMOST, 0, "ZDTNT-FWW-8: Drag 'N Drop Windows",&winproc

'Write some instructions in the window
move win,0,0
print win,"Drag and drop a file into the window."

'We now modify the window we opened to accept file dropping.
'We can do this two different ways.  We can Use the DragAcceptFiles
'function or modify the window style with MODIFYEXSTYLE.  In this
'example we have used the MODIFYEXSTYLE, but you can comment out the
'next line and uncomment the following line to use the DragAcceptFiles
'function.
MODIFYEXSTYLE win, WS_EX_ACCEPTFILES, 0
'DragAcceptFiles(win.hwnd,1)

'At this point, the program is all set up, so we will set our run variable
'to 1 and process window messages until the run variable is set to 0, when
'the program is closed.
run=1
WAITUNTIL run=0
CLOSEWINDOW win
END
'Main program end.


'This is our window message handler subroutine.
SUB winproc(),int
'--This message is sent when the window is initially created.
IF @MESSAGE = @IDCREATE THEN CENTERWINDOW win

'--This message is sent when the window/program is closed.
IF @MESSAGE = @IDCLOSEWINDOW THEN run=0

'--This message is sent when a file is dropped on the window
IF @MESSAGE = WM_DROPFILES
'A file was dropped, so now we get the filename with DragQueryFileA
DragQueryFileA(@WPARAM,0,Filename,10000)
'Print the filename to the screen (with some spaces after it, just for looks)
MOVE win,0,50
PRINT win,Filename+SPACE$(200)
'We can get the x,y position of where the file was dropped with DragQueryPoint.
DragQueryPoint(@WPARAM,DropPoint)
MOVE win,0,100
'Print the x,y position of the file dropped to the window.
PRINT win,"Dropped at: "+STR$(DropPoint.x)+","+STR$(DropPoint.y)+SPACE$(200)
ENDIF
RETURN 0
ENDSUB
'End of window message handler subroutine.

LarryMc

Nice tutorial and it lets me know that I got that part right.

Thanks

LarryMc
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library