How can I send data (strings) between 2 standalone apps?
Printable View
How can I send data (strings) between 2 standalone apps?
Need to elaborate a bit on your problem. You want to send text to another application from your app? Or send text/data using a connection such as winsock to a server side app.
Also, do you have the ability to alter both programs. If so, you would probably get quicker answers in a different forum, since the solution would probably be winsock rather than API.
If they're on the same machine, send a WM_USER + X message. You can pass the string in the lParam parameter.
Then subclass the receiving app, and check for the WM_USER + X message.
Look at CreateFileMapping API. Passing it a null for the name of a file will let windows know you want share memory. You give the shared mem a name when creating and another app can open using that name.
packetvb
Hi Megatron,
I am facing a similar issue. i appreciate that u can elaborate on WM_USER + X message. even better if u have sample code.
Thank you very much
Named pipe's and Mailslots are capable of communicating between apps
Megatron, I am not sure what you mean by "subclass the receiving app", but I doubt that it is easy.
A WM_USER message would work only for very short strings. The first suggestion should be the WM_COPYDATA message, which can be used for much larger strings. The WM_COPYDATA message will do a CreateFileMapping for you. There is very little to be concerned about when using the WM_COPYDATA message except the receiving application must copy the string (and/or other data) when the message is processed; that is, before the message processing function returns.
The WM_COPYDATA message can be very useful and very easy to use. If the requirement is more complex than what can be done using the WM_COPYDATA message, then there are other possibilities. Look at "Interprocess Communication" (IPC) in the Platform SDK. An ActiveX Component is relatively easy for VB programmers and can be a very useful solution that many people might not think about.
Subclassing is a means of accessing the window procedure from VB. Generically speaking it replaces the default window procedure with a custom one. It's definetly not a difficult task, as window procedures are essential for programming in Windows.Quote:
Megatron, I am not sure what you mean by "subclass the receiving app", but I doubt that it is easy.
Well, sure, if you're passing a mystery novel through a window message, then yes; you're going to run into problems. Maybe quaso can fill us in on the length of strings he wants to pass.Quote:
A WM_USER message would work only for very short strings
As opposed to what? WM_USER?Quote:
The WM_COPYDATA message can be very useful and very easy to use
They're both window messages, and are subject to the same constraints. Anything that can be done with WM_COPYDATA can also be done with WM_USER.
More over, WM_COPYDATA is a custom message. This means that there is no default action for it, and it's up to the user to process this message (if at all). And how do we do it? You guessed it: Subclassing.
Yes, I am familiar with subclassing windows. However you said "subclass the receiving app", and that is what I am not sure of. If you meant "subclass the receiving application's window" or something such as that, then that I understand.Quote:
Originally Posted by Megatron
Subclassing a window for an application that is within the same address space is relatively easy, at least for C and C++ programs. I assume there are enough existing samples of doing that in VB too. However when using VB some messages will be more difficult than others to process.Quote:
Originally Posted by Megatron
In this context, the requirement is to subclass a window in another address space, which is much more complex. I assure you it is not easy for a beginner to write all the code themselves to do that, and it should not be easy for a beginner to simply copy a sample if the beginner needs to modify the code. When crossing address spaces, there are too many things that a person could make a small mistake with and mess up the system.
It is not possible to put a pointer in most Windows messages, including none of the WM_USER messages, and then send the message accross address spaces. The pointer would be totally meaningless in another address space. Therefore, without pointers, it is possible to send a maximum of four (16-bit) Unicode characters or a maximum of eight ASCII (8-bit) characters.Quote:
Originally Posted by Megatron
There is definitely a difference. The WM_COPYDATA message is provided to overcome the limitations of the other messages. Just search the MSDN for what it says about the WM_COPYDATA message.Quote:
Originally Posted by Megatron
If the WM_COPYDATA message is more difficult to process than WM_USER messages, then that is unfortunate, since the WM_COPYDATA message is so useful and eliminates most or all of the technicalities that might be a hassle for VB. However I really doubt that there are not any samples of processing the WM_COPYDATA message using VB.Quote:
Originally Posted by Megatron
As I indicated, subclassing within an address space is easier than across address spaces, so if the WM_COPYDATA message must be processed by subclassing a window, then that I assume is easy, since Microsoft tries to make things as easy as possible for VB programmers.
Note that the Platform SDK warns against using messages with message ids in the WM_USER range; it is better to use the range WM_APP through 0xBFFF. The WM_USER range is usually safe but it is just as easy to use WM_APP instead of WM_USER. Even better than WM_APP is to use the RegisterWindowMessage function to retrieve a message id. However none of those will allow you to send a pointer in the message that is valid in another address space.
If you want me to be specific: "Replace the receiving appliation's window procedure with a custom procedure of your own."Quote:
Yes, I am familiar with subclassing windows. However you said "subclass the receiving app", and that is what I am not sure of. If you meant "subclass the receiving application's window" or something such as that, then that I understand.
You're confusing "subclassing" with direct access to a window procedure. Subclassing a window procedure is just as easy in VB, as it is in C or C++. Both require the exact same API's. Processing messages is no different either. Think Win32, not VB vs C vs C++.Quote:
Subclassing a window for an application that is within the same address space is relatively easy, at least for C and C++ programs. I assume there are enough existing samples of doing that in VB too. However when using VB some messages will be more difficult than others to process.
You're assuming that the receiving app is pre-compiled (i.e. he is not making it)Quote:
In this context, the requirement is to subclass a window in another address space, which is much more complex. I assure you it is not easy for a beginner to write all the code themselves to do that, and it should not be easy for a beginner to simply copy a sample if the beginner needs to modify the code. When crossing address spaces, there are too many things that a person could make a small mistake with and mess up the system.
And in which case, if two way communication is required, then you need to subclass the external process (Replace the receiving appliation's window procedure with a custom procedure of your own). You cannot just send your custom message to another application because it will not know what to do with it. In order to make something happen, subclassing is required.
If, on the other hand, you simply need to send data to a specific address location in this external process (one-way communication) then WriteProcessMemory will do the trick.
What's impossible about that? A pointer is simply a number, just like 123 or 456. It represents a specific location of memory in the current address space. If you pass this pointer through SendMessage, you can read it from an external address space via the ReadProcessMemory function for example.Quote:
It is not possible to put a pointer in most Windows messages, including none of the WM_USER messages, and then send the message accross address spaces. The pointer would be totally meaningless in another address space. Therefore, without pointers, it is possible to send a maximum of four (16-bit) Unicode characters or a maximum of eight ASCII (8-bit) characters.
WM_COPYDATA is a window message. It's no more special than WM_LBUTTONDOWN, or WM_CLOSE or any other message. What you're probably referring to as "special" is it takes care of copying the data into the receiving process's address space, though there's really no magic to it.Quote:
There is definitely a difference. The WM_COPYDATA message is provided to overcome the limitations of the other messages. Just search the MSDN for what it says about the WM_COPYDATA message.
Whether WM_COPYDATA is easier to process than a customized WM_USER message is a subjective question.Quote:
If the WM_COPYDATA message is more difficult to process than WM_USER messages, then that is unfortunate, since the WM_COPYDATA message is so useful and eliminates most or all of the technicalities that might be a hassle for VB. However I really doubt that there are not any samples of processing the WM_COPYDATA message using VB.
No easier or harder than any other window message.Quote:
As I indicated, subclassing within an address space is easier than across address spaces, so if the WM_COPYDATA message must be processed by subclassing a window, then that I assume is easy, since Microsoft tries to make things as easy as possible for VB programmers.
WM_APP isn't "better" than WM_USER, nor is it the other way around. Granted, Microsoft generally uses WM_USER in controls, rather than main appliation windows, but so long as you have control of both window procedures, it really doesn't matter what range of values you use (either WM_USER or WM_APP).Quote:
Note that the Platform SDK warns against using messages with message ids in the WM_USER range; it is better to use the range WM_APP through 0xBFFF. The WM_USER range is usually safe but it is just as easy to use WM_APP instead of WM_USER.
RegisterWindowMessage creates a new message identifier in the message table, and it stays there for the duration of your windows session. There's nothing wrong with using this, though it offers no significant advantage over WM_USER if you are writing both applications and are in charge of handling the message. It does come in handy when you need to send to HWND_BROADCAST for example (but that's not the issue here).Quote:
Even better than WM_APP is to use the RegisterWindowMessage function to retrieve a message id. However none of those will allow you to send a pointer in the message that is valid in another address space.
Bottom line? Pick your favourite, and use it. Neither offers significant advantages over the others.
No. I know what window subclassing is. See the second paragraph of Safe Subclassing in Win32 in which it says:Quote:
Originally Posted by Megatron
You probably think that is not accurate, eventhough it is in the MSDN Technical Article on the subject. So I won't try to convince you otherwise, but I hope I am saving other people's time.Quote:
an application cannot subclass a window or class that belongs to another process
ReadProcessMemory and WriteProcessMemory are debugging functions. They are not listed in the IPC APIs. I certainly recommend not to use functions such as them in production applications, but you can if you want to. When suggesting for others solutions that require ReadProcessMemory and/or WriteProcessMemory, they should be told that the solution requires use of a debugging API. People should not allow application software to use debugging APIs for any other purpose than debugging, since hackers and viruses and worms could use them to get total control of our systems. People should be warned about use of ReadProcessMemory and WriteProcessMemory. You can use them in your software but when advising others you really need to warn them.Quote:
Originally Posted by Megatron
I did not say it is magical. Yes, as far as I know, it does nothing we can't do ourselves. However it does do a lot. It does not use ReadProcessMemory and/or WriteProcessMemory or anything like that. It does do the same things that we would normally transfer data across address spaces. The fact that it does that makes it special, since it is different from the other messages.Quote:
Originally Posted by Megatron
Note that I did not say that WM_COPYDATA is easier to process; you indicated that it is not easier.Quote:
Originally Posted by Megatron
It is just as easy to suggest use of WM_APP as it is to suggest use of WM_USER, so it is better to suggest to others that they use WM_APP. There is no reason not to suggest to others that they use WM_APP instead of suggesting use of WM_USER.Quote:
Originally Posted by Megatron
Message table? What message table? Does VB have a message table? If VB has a message table, then RegisterWindowMessage could not update it, since RegisterWindowMessage is a SDK function that knows nothing about VB.Quote:
Originally Posted by Megatron
Most experienced software developers understand the value of flexible solutions such as RegisterWindowMessage. I understand that you don't see the value, but many others do. My guess is that most developers of commercial software require use of RegisterWindowMessage when messages are sent across applications.
You sure you read the full article?Quote:
Originally Posted by Sam Hobbs
2 paragraph's down from that that, he also states:
"However, there are ways you can add subclassing functionality to every process."
So subclassing a window in an external process is possible so long as the window procedure is mapped into its address space. This can be acheived by having your window procedure in a stanard DLL. See my post in the codebank.
General rule of thumb: You shouldn't always take Microsoft's words as engraved in stone.
Granted, they are advanced functions, and you need to know what you're doing when working with them, but your argument of "just because they're debugging functions" really doesn't have any justification.Quote:
ReadProcessMemory and WriteProcessMemory are debugging functions. They are not listed in the IPC APIs. I certainly recommend not to use functions such as them in production applications, but you can if you want to.
The fact that they're listed under the debug API's in the platform SDK is irrelevent, and does not degrade their functionality; they're still part of the kernerl32 library.Quote:
When suggesting for others solutions that require ReadProcessMemory and/or WriteProcessMemory, they should be told that the solution requires use of a debugging API.
So by your logic, should I warn someone that they're using GDI API when I suggest BitBlt?Quote:
People should be warned about use of ReadProcessMemory and WriteProcessMemory. You can use them in your software but when advising others you really need to warn them.
I don't follow: How does the use of Read/WriteProcessMemory in my or your application allow a 3rd party hacker to take total control of the system?Quote:
People should not allow application software to use debugging APIs for any other purpose than debugging, since hackers and viruses and worms could use them to get total control of our systems.
(If he's that sophisticated, he can write his own application. No need to tamper with ours)
My point exactly. WM_COPYDATA is just like any other window message.Quote:
Yes, as far as I know, it does nothing we can't do ourselves
Nor did I say it was more difficult. Window messages are window messages.Quote:
Note that I did not say that WM_COPYDATA is easier to process; you indicated that it is not easier.
I'm going to be repeating myself, but WM_USER is no "better" than WM_APP. Microsoft may use WM_USER for controls, and WM_APP for inter-application communication, but it's really a matter of preference.Quote:
It is just as easy to suggest use of WM_APP as it is to suggest use of WM_USER, so it is better to suggest to others that they use WM_APP. There is no reason not to suggest to others that they use WM_APP instead of suggesting use of WM_USER.
Re-read my previous posts, as I would be repeating myself again.
The system message table. When you call RegisterWindowMessage, a new value is added to this internal table (system-wide).Quote:
Message table? What message table? Does VB have a message table? If VB has a message table, then RegisterWindowMessage could not update it, since RegisterWindowMessage is a SDK function that knows nothing about VB.
Like I said, as long as you have control of both window procedures, it does not matter which method you use. Those "experienced software developers" can verify this.Quote:
Most experienced software developers understand the value of flexible solutions such as RegisterWindowMessage.
We can keep going in circles here, but the underlying facts are:
1. WM_USER, WM_APP or RegisterWindowMessage are ways of creating a custom window message to communicate between applications.
2. To process these messages, you need direct access to the window procedure of the receiving window. In C, you already have access to it, whereas in VB you have to subclass. If it's an external process, you'll have to subclass in either case (using a DLL to map the procedure in the receiver's address space)
3. WM_COPYDATA is a generic message for sending data, and needs to be processed in the same way as any other message.
4. There are other means of transferring data, if you so desire, such as pipes, file mapping etc.
The solution you are talking about does not subclass a window in another process. The subclassing is done in the DLL that is in the same address space as the window. The solution uses a hook, which makes it possible for the subclassing to be controlled by another application, but the subclassing is done within the subclassed window's address space.Quote:
Originally Posted by Megatron
Also, your solution uses C++, which proves my point that it is not easy to do in VB.
I knew you would say that the quote I provided was not accurate. However if that quote and the quote you provided are interpreted in context, other people will understand that in 32-bit Windows, a process cannot subclass a window belonging to another process.Quote:
Originally Posted by Megatron
I am concerned that people will be misled into believing that a solution is easier and more typical than they realy are.Quote:
Originally Posted by Megatron
Quote:
Originally Posted by Megatron
You are one of those people that will never admit a mistake. You will continue to insist you are right until someome tells us to stop. So unless someone else can contribute to this discussion in a factual manner, I will let you say whatever you want to say.Quote:
Originally Posted by Megatron
I hope I have made my point for the benefit of others that WM_COPYDATA is a likely solution to the requirement in this thread and if it is a solution it is very easy to use.
Fact - Who said it wasn't a solution? I believe Megatron was insisting that is is not necessarily the ONLY solution nor the best to use in the thread starters situation.
I don't mean to interrupt the bout' , so i'll let round 3 begin as soon as Megatron has replied.
- commentary by: me
:thumb:
And thus you have a method to subclass a window in an external process.Quote:
Originally Posted by Sam Hobbs
We were never debating C vs VB.Quote:
Also, your solution uses C++, which proves my point that it is not easy to do in VB.
Not sure what you're trying to prove here.Quote:
I knew you would say that the quote I provided was not accurate. However if that quote and the quote you provided are interpreted in context, other people will understand that in 32-bit Windows, a process cannot subclass a window belonging to another process.
Yes strictly speaking, a process cannot directly subclass a window in another process; that's already a known fact. But for all intents and purposes, the aid of a standard DLL makes it possible to achieve the same effect.
You keep making reference to "easy" and "difficult" concepts. If a solution is optimal, then the relative difficultly to implement it should be the least of our worries.Quote:
I am concerned that people will be misled into believing that a solution is easier and more typical than they realy are.
What if our car manufacturers followed the same philosophy?
(Though in this case neither is significantly more optimal than the other, but I thought I would point that out.)
Have a look here.Quote:
You are one of those people that will never admit a mistake.
.
I will leave that for others to judge for themselves.Quote:
Originally Posted by Megatron
That is all I was saying. If you had said this from the beginning, then there would have been nothing more for me to say on the subject of subclassing.Quote:
Originally Posted by Megatron
So I was wrong when I said that you will never say you have made a mistake, sorry. I hope you do here too.
Actually, as I understood, you were originally debating the relative difficulty of subclassing a window in an external process (2nd/3rd paragraph of your 2nd post)Quote:
Originally Posted by Sam Hobbs
But I'll let it go, as this issue has been run over more than enough times now.
Gladly; if you can point it out for me? (For the benefit of the readers of the thread, of course)Quote:
So I was wrong when I said that you will never say you have made a mistake, sorry. I hope you do here too.
As far as I can see, both you and I are merely pointing out different methods to achieve the same goal.
VB Code:
'************************************************************************************************ '* Name Function SubClass '* '* Author '* '* Purpose This function instructs Windows to redirect the Window Procedure of a '* given control to a custom procedure. '* '* The function creates (sets) a property of the given Wnd called 'OldWndProc' '* This ensures that the window retains it's own state with regard to its '* original Window Procedure. '* '* Parameters --> hWnd LONG The handle of the window to be subclassed '* --> lpfnNew LONG Address of function of which to redirect the '* the standard WndProc too. '* '* Version 14/02/2002 Created '* '************************************************************************************************ Public Function SubClass(hwnd As Long, lpfnNew As Long) As Boolean Dim lpfnOld As Long Dim fSuccess As Boolean '************************************************************* '* If we haven't set the property for this window before . . . '************************************************************* If (GetProp(hwnd, OLDWNDPROC) = 0) Then '***************************************** '* Redirect Windows Proc to New Proc . . . '***************************************** lpfnOld = SetWindowLong(hwnd, GWL_WNDPROC, lpfnNew) '********************************************************** '* Set Old Proc Address to the property of the window . . . '********************************************************** If lpfnOld Then fSuccess = SetProp(hwnd, OLDWNDPROC, lpfnOld) End If End If '************************************* '* Did we subclass successfully . . . '************************************* If fSuccess Then SubClass = True Else '************************************************* '* If we have the old proc address, '* and still have failed, remove redirection . . . '************************************************* If lpfnOld Then Call UnSubClass(hwnd) End If '* Oh **** !! MsgBox "Unable to successfully subclass " & hwnd, vbCritical End If End Function '************************************************************************************************ '* Name Function UnSubClass '* '* Author '* '* Purpose This function removes the OldWndProc property of the hWnd, and resets the '* Window Procedure back to the original. '* '* See Function SubClass '* '* Parameters --> hWnd LONG The handle of the window to be subclassed '* '* Version 14/02/2002 Created '* '************************************************************************************************ Public Function UnSubClass(hwnd As Long) As Boolean Dim lpfnOld As Long '********************************** '* Can we get Window property . . . '********************************** lpfnOld = GetProp(hwnd, OLDWNDPROC) '************************************************************* '* If we have property, remove it, and return Window Proc to '* original . . . '************************************************************* If lpfnOld Then If RemoveProp(hwnd, OLDWNDPROC) Then UnSubClass = SetWindowLong(hwnd, GWL_WNDPROC, lpfnOld) End If End If End Function '************************************************************************************************ '* Name Function GridWndProc '* '* Author '* '* Purpose SubClass function for Windows Procedure redirection. Use only for the '* FlexGrid. '* '* See Function SubClass '* '* Parameters --> See MSDN Documentation '* '* Version 14/02/2002 Created '* '************************************************************************************************ Public Function NewWndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Dim uCDS As COPYDATASTRUCT Dim uData() As Byte Dim oPb As PropertyBag Select Case uMsg Case WM_COPYDATA '************************************* '* Retrieve Copy Data Structure . . . '************************************* CopyMemory uCDS, ByVal lParam, Len(uCDS) ReDim uData(uCDS.cbData) CopyMemory uData(0), ByVal uCDS.lpData, uCDS.cbData Set oPb = New PropertyBag oPb.Contents = uData Select Case uCDS.dwData Case BM_CURRENCY gEnv.CurrencyCode = oPb.ReadProperty("Code") gEnv.CurrencyExchange = oPb.ReadProperty("ExchangeRate") End Select Set oPb = Nothing End Select '************************************************************ '* Carry on processing in the original Window Procedure . . . '************************************************************ NewWndProc = CallWindowProc(GetProp(hwnd, OLDWNDPROC), hwnd, uMsg, wParam, lParam) End Function
and an example of how to send . . .
VB Code:
Private Sub SendCurrency(lHWnd As Long, uCurrency As CURRENCY_EX) On Error GoTo ERR_SendCurrency Dim oPacket As PropertyBag Dim uCopyData As COPYDATASTRUCT Dim Stream() As Byte Set oPacket = New PropertyBag With oPacket .WriteProperty ("Code"), uCurrency.Code .WriteProperty ("Description"), uCurrency.Description .WriteProperty ("ExchangeRate"), uCurrency.ExchangeRate .WriteProperty ("Format"), uCurrency.Format .WriteProperty ("IsValid"), uCurrency.IsValid Stream = .Contents End With With uCopyData .dwData = BM_CURRENCY .cbData = UBound(Stream) - LBound(Stream) + 1 .lpData = VarPtr(Stream(LBound(Stream))) End With SendMessageA lHWnd, WM_COPYDATA, 0&, uCopyData Set oPacket = Nothing Exit Sub ERR_SendCurrency: Set oPacket = Nothing End Sub
Thank you, yrwyddfa.
It is unfortunate that it is necessary to do all that to use the WM_COPYDATA message in VB. I suppose most of the code is for the message process and once it is done that adding other messages to be received would be easy and correspondingly it would be relatively easy to add processing of WM_COPYDATA to a program with a message loop.
I found another sample; see How To Pass String Data Between Applications Using SendMessage.
Yeah - they could've made it easier . . .
Most of the awkward looking API stuff here is for serialising/deserialising the message stream and putting it in and out of property bags.
If you take a look at my VB6 multithreading example, it has code there which allows you to send VERY LARGE structured data between 2 apps, using the send, or post, message API functions.
The DLL that does this is called vbGatewayy.dll that I wrote.
Take a look.
Not sure if that's relevant :D
Woka
Woka, I assume your sample is useful. For those applications that require something more complicated than what WM_COPYDATA is capable of, I assume it is worth evaluating. Note that the WM_COPYDATA message does automatically a lot of things that a program such as yours must do.
Since the WM_COPYDATA message is not as easy to process in VB as other messages are, and since VB makes COM objects so easy, it is probably practical to use a COM object. I am not sure of the terminology but I hope most people understand. Probably I mean an ActiveX component, but the term ActiveX is not clearly defined.
Summary
It's funny that the original poster has not posted anything here after the original post to clarify the problem. The ensuing discussion however was rather informative so I have compiled what I think is an accurate summary of the conversation. Please correct me if I erred.
As I see it there are two possible scenarios.
1. Both applications are "owned" by the poster (i.e. he has access to the source code of both.)
2. He does not have access to the source code of one of the applications.
Solution for case 1:
Subclass a window in each app to receive messages (yrwyddfa shows how to do that) and use WM_USER, WM_APP or WM_COPYDATA to pass messages back and forth (yrwyddfa again with an example).
Solution for case 2:
Subclass a window in your app to receive messages and hook the other app. The hook will have to point to a routine that resides in a WIN32 DLL which cannot be done with VB (I use VC++ for this). The "owned" app can then communicate with the DLL and hence the other app using the same technique as in case 1.
Notes:
1. Standard windows messages sent between processes, such as WM_SETTEXT and WM_COPYDATA, can contain pointers since the OS knows about these messages and handles the marshalling. If user defined messages such as WM_USER and WM_APP contain pointers, the pointers will only be valid in the address space from which they are sent. One way to handle pointers between processes in user defined messages is to use ReadProcessMemory to retrieve the data.
2. To make sure that your message is not being used by another application, you can register it with the OS with RegisterWindowMessage. It is probably safer to use the WM_APP range because some predefined window classes have already defined values in the WM_USER range.
3. WM_COPYDATA is great for sending text strings or data structures as long as the data structure does not have a pointer in it. If it does, you'll have to use ReadProcessMemory to get that data just like you would with WM_APP.
4. Take a look at Wokawidget's code if you want to see how complex it can get sending code between two applications. Warning: this code is not for beginners especially since it contains no comments. What’s up with that Woka? :ehh:
I think that sums it up :D
Comments...Hmmmm :blush:
I never use comments, they get in my way and annoy me. The 1st thingI do when I download someones code is I remove the comments.
This also means that you must manually figure out what code does. I have done this from the 1st day I started learning programming, 4.5 yrs ago. Personally I think the learning curve is steeper without comments.
I know others like them, and maybe some would be beneficial, but hey, no one is perfect ;)
WM_COPYDATA cannot be used with PostMessage.
Woka
This might help (my apologies if someone has already posted this, I couldn't be bothered reading the entire thread :bigyello: )http://www.thescarms.com/vbasic/PassString.asp
Thank you, moeur. I know you are trying to help.It is more common than it should be. I usually avoid guessing and therefore just ask for clarification before proceeding further. For example, ice_531 askedQuote:
Originally Posted by moeur
and Shaggy Hiker askedQuote:
"You want to send text to another application from your app? Or send text/data using a connection such as winsock to a server side app."
I think the issue should have been left there, until clarification was provided.Quote:
"Also, do you have the ability to alter both programs."
My experience has been (in the CodeGuru forums) that when a vague question is asked and not clarified, it is common for it to explode into a lengthy discussion. That happens because there is not a topic specific enough to adequately limit discussion, and the vague nature of the subject likely results in differing understandings and points of views. For example Megatron posted comments with a couple or more mistakes.
One of the mistakes was "subclass the receiving app". Applications aren't subclassed; windows are. It was a simple mistake, and I realize that most people would understand what he meant. Note that I tried to be subtle and reasonable in my comment about it. However instead of clarifying what he said, he tried to defend it.
Megatron also said that it is possible to "pass the string in the lParam parameter" of a "WM_USER + X message", which is not possible. If Megatron meant that the string could be put into a lParam parameter, then it is possible to send only a few characters, not enough to be considered a string. If Megatron meant that the string could be sent by using memory outside the message and passing just a pointer in the lParam parameter, then it is necessary to also say that custom marshalling is required.What would help the most is to verify what we have said, before summarizing. Since you have created your summary using inaccurate information, it contributes to the problem, not the solution.Quote:
Originally Posted by moeur
I do understand that you meant well, and I hope I have not discouraged you from helping in the future. The way you could help the most is, as I said, correct any mistakes that we have made. It does not need to be personal and should not be personal, but it is entirely possible to state facts without being personal. Just stating the facts I think is a mature solution.No; the WM_COPYDATA does not need custom marshalling, but WM_USER and WM_APP messages do. Look at the documentation of the BroadcastSystemMessage, SendMessageTimeout, SendMessage, BroadcastSystemMessageEx, PostMessage, PostThreadMessage, SendNotifyMessage and SendMessageCallback message functions.Quote:
Originally Posted by moeur
Receiving messages in another application that cannot be by modified at the source code level is one thing, but how to process them in that other application is a more critical problem, and likely more difficult than simply receiving the messages. Therefore I think it is best to assume that this is not a requirement until it is stated explicitly that it is.Quote:
Originally Posted by moeur
As far as I know, what you are saying here is accurate, or at least close enough to being accurate. Except it should be stated that it is best to avoid use of ReadProcessMemory, at least in programs being developed for use by other people. I am working on getting some authoritative references on the subject.Quote:
Originally Posted by moeur
I think that what you meant is accurate, but not what you actually said. What you said seems to be saying that is probably safer to use the WM_APP range for message ids instead of message ids obtained using RegisterWindowMessage.Quote:
Originally Posted by moeur
No, use of ReadProcessMemory and WriteProcessMemory are not required. It might be possible to easily convert the data such that pointers are not used. If that is not possible and/or the data is large, then memory-mapped files are more efficient and safer than ReadProcessMemory and/or WriteProcessMemory.Quote:
Originally Posted by moeur
Memory mapped files?
Woka
I might be using incorrect terminology but it is correct to the extent that this is a common use of the term. I don't know how familiar you are with Memory mapped files, so I should try to define them assuming you know very little. If I don't do that well enough, then say so.Quote:
Originally Posted by Wokawidget
Memory mapped files is a common way for processes to share data; perhaps the most common. It does seem to be an indirect solution, and it probably is, at least somewhat. A Unix system, for example, has more direct functions for sharing memory; at least if my memory is accurate.
When a file is mapped to memory, a portion of memory in each process's address space is mapped to a common portion of virtual memory. The memory can be paged in and out, but that is not done unless physical memory is used to the extent that pages need to be swapped, whether they are part of a memory-mapped file or not. Data in a memory-mapped file can be accessed as efficiently as normal memory in an address space. In terms of efficiency, the memory is the same as the rest of memory for the process. ReadProcessMemory and/or WriteProcessMemory are very inefficient in comparison.
A memory-mapped file can be backed by the pagefile(s), for which the file becomes just a way to share memory. Believe me, that is a solution that is very, very common.
Any exmaples of code? :D
Woka
How did you search? Whatever you are using to search is no good, since there should be many to be found. As soon as I get through doing things such as checking ther weather, I will look for samples using VB, and hopefully we can help you in knowing how to search.Quote:
Originally Posted by Wokawidget
Hahaha. You sarcastic sod :D Hahaha.
OK. I will search. I was just wondering if you had any small samples to hand. Not actively looking for this code as I have no need.
Woof
I did not know of any samples, expecially not VB samples. There are many more samples that use the C/C++ languages but the following are two that use VB:
Visual Basic Samples by Karl E. Peterson (MapFile.zip)
Binaryworld - Sharing Data Between Processes Using Memory-Mapped Files ... [ VB -> Memory ]
Also, the MSDN previously contained an online copy of Hardcore Visual Basic, in which there is an article called "Shared Memory Through Memory-Mapped Files".
Cheers for that.
Just got to work. Will check out those link.
Much appreciated :D
Woka
A grave mistake, that was.Quote:
Originally Posted by Sam Hobbs
Do you see the irony in me finger-pointing this insignificant "mistake" you made?Quote:
Megatron also said that it is possible to "pass the string in the lParam parameter" of a "WM_USER + X message" which is not possible. If Megatron meant that the string could be put into a lParam parameter, then it is possible to send only a few characters, not enough to be considered a string
Life's too short to buy green bananas.
No. If the data structure you're passing with WM_COPYDATA contains pointers to other locations of memory, you'll need to improvise a different approach (i.e. remove the pointers).Quote:
No; the WM_COPYDATA does not need custom marshalling, but WM_USER and WM_APP messages do.
If you're sending strings between two applications, what good is it to only be notified when a string is received? The sole reason you are sending the message (string) is so the other application can make use of it (process it). You can process the messages in that external process by subclassing. Since you have already installed a hook (the callback is already mapped into the address space of that process) you're already half-way there.Quote:
Receiving messages in another application that cannot be by modified at the source code level is one thing, but how to process them in that other application is a more critical problem, and likely more difficult than simply receiving the messages. Therefore I think it is best to assume that this is not a requirement until it is stated explicitly that it is.
To say it's more "difficult" is subjective. Yes, there's more typing involved, but I wouldn't consider that difficult.
So long as the memory locations are not modifiable by the user, it does not present a security risk. If you are not confident with your own ability to harness these functions, then don't use them.Quote:
avoid use of ReadProcessMemory, at least in programs being developed for use by other people. I am working on getting some authoritative references on the subject.
I don't know what you are referring to.Quote:
Originally Posted by Megatron
That is a subject for the chit-chat forum, but when the closest store that sells ripe bananas is far away, life is to short not to buy green bananas.Quote:
Originally Posted by Megatron
Of course. If we had to specify all exceptions such as that (such as WM_COPYDATA works except to send pointers) then we would never get anything done. It's like wasting time driving around in search of ripe bananas.Quote:
Originally Posted by Megatron
It depends on what is needed. Yes, if it is simply a matter of processing a message sent to/from a window, then that is as easy as you describe. However if there is something that needs to be done with the data differently than what the other application does, then it can be a lot of work.Quote:
Originally Posted by Megatron
For example, if the requirement is to draw text on an image in another application's window, then that might be quite easy. If the image can be resized (zoomed) by the other application, and if the text needs to be correspondingly resized, then that is more work. And it is likely to be more work than someone might think initially, since the text would potentially need to be redrawn after each paint message. If however the requirement is to draw the text in the bitmap that is shown in a window, then that might be significantly more difficult. When I say bitmap here, I mean it might be a bitmap drawn in memory (a memory device context?) that potentially could be written to disk, and the requirement is that the additional text be included in the image when it is written to disk.
Then there are millions of other possible requirements, such as a requirement to alter text that is being processed from/to a database.I am talking more from the point of view of the user of the software. It is my understanding that security specialists would object to use of ReadProcessMemory and WriteProcessMemory. ReadProcessMemory can be a problem when used to get passwords and such. A security specialist has reason to be concerned about allowing use of ReadProcessMemory, since when it is allowed, it has access to all of a process's memory. Also, if a person does not understand Windows adequately, a user might allow use of ReadProcessMemory for an account (theirs or another account) in such a manner that allows all other applications that execute under that user's authority (including unintentional applications such as viruses) to have that access.Quote:
Originally Posted by Megatron
Programmers essentially need to have a userid that allows general use of ReadProcessMemory and WriteProcessMemory, right? So for programmers, it might be an insignificant problem. If an application is to be used in a relatively more secure environment, then ReadProcessMemory and WriteProcessMemory would be an important consideration. I am not familiar with Windows security enough to clear about details, but I am attempting to get help from security specialists.
Read the red. You contradicted yourself.Quote:
Originally Posted by Sam Hobbs
(But like I said: That's green banana's)
The fact that pointers cannot be used needs to be mentioned, as many data structures do work with pointers.Quote:
Originally Posted by Sam Hobbs
Little things like an integer only stores 16-bits can be left out.
As I stated earlier, we cannot explicity state it's more difficult.Quote:
It depends on what is needed. Yes, if it is simply a matter of processing a message sent to/from a window, then that is as easy as you describe. However if there is something that needs to be done with the data differently than what the other application does, then it can be a lot of work.
I don't doubt the possibility that some "specialists" will object to the use of these functions.Quote:
Originally Posted by Sam Hobbs
I also don't doubt that some "specialists" will approve of these functions.
By this logic, we should also disallow the use of WM_GETTEXT, since it can also be used to retrieve passwords.Quote:
Originally Posted by Sam Hobbs
Yes, an inexperienced user is prone to harmful attacks committed with deliberate misuse of WriteProcessMemory, but there are just as much -- if not more -- viruses that utilize other methods. The registry, for instance. Point being, if WriteProcessMemory viruses can slip by this user, what's to stop registry viruses (or other types) from doing the same?Quote:
Also, if a person does not understand Windows adequately, a user might allow use of ReadProcessMemory for an account (theirs or another account) in such a manner that allows all other applications that execute under that user's authority (including unintentional applications such as viruses) to have that access.
Yes, it is a minor issue, but I did not contradict myself; at worst, I was just not clear. I did not write that (for the benefit of others: it is the quote above with the red) as well as I could have, so you just misunderstood it.Quote:
Originally Posted by Megatron
You probably meant to say something such as "definitively" rather than "explicity". I did not say it is definitely more difficult; I was just saying that there is a good chance it could be, depending on requirements. I just was saying that until trying to answer the original question, the question from Shaggy Hiker asking if the other program can be modified should be answered, since the answer is potentially so much more complicated if the other program cannot be modified.Quote:
Originally Posted by Megatron
I hope and expect to get comments from the most definitive and respectable specialists on the subject; however I know of someone else that is more adamant than you are that WriteProcessMemory and ReadProcessMemory are valid for use as IPC. (Brad Jones knows who I am talking about.) If you know of any more specialists that consider WriteProcessMemory and ReadProcessMemory to be valid for use as IPC, then please tell us; I am very interested in knowing about them. The more people there are, the more justification I have to get a response form the specialists that will insist that WriteProcessMemory and ReadProcessMemory should not be used for IPC.Quote:
Originally Posted by Megatron
Yes, that problem should be solved. Obviously it can't be solved easily, at least not as easily as simply disallowing use of WM_GETTEXT. However use of WriteProcessMemory and ReadProcessMemory can easily be avoided.Quote:
Originally Posted by Megatron
I have said what needs to be said in response to that, so I have nothing more to say except (for the benefit of others) that I have nothing more to say.Quote:
Originally Posted by Megatron
Precisely; a misunderstanding not even worth mentioning. I merely pointed it out to demonstrate just how fruitless nitpicking insignificant errors are (i.e. "Subclass the app"), rather than focusing on the primary issue.Quote:
Originally Posted by Sam Hobbs
I hope the irony is apparant, by now.
I'm going to be repeating myself, but there are specialists both in favour, and against the use of these functions. It's the same with any other area. Custom GINA's for instance: Some specialists are opposed to the idea, yet large scale software giants such as Symantec and Cisco continue to use them. You will not be breaking any new grounds by finding a specialist whose belief's coincide with yours, nor will I be breaking new grounds if I locate a specialist whose belief's coincide with mine. Though if it makes you feel any better, by all means ask them, but it will be the same as asking a Honda salesman if Hondas outrank Fords.Quote:
Originally Posted by Sam Hobbs
In order to gain an true unbiased understanding, you will need to draw conclusions from arguments on both sides of the debate.
Yes!Quote:
Originally Posted by Megatron
Therefore, it is imperative for us to have available to us comments from those in support of your position. I hope to get comments from at least one person more authoritative than Mick, who is a moderator in the CodeGuru forums, and who also recommends use of ReadProcessMemory and WriteProcessMemory, except the comments I am looking for would of course support what I am saying.