Supposing I have made an app, or several apps, in VB.
I want send a message to one app from the other one, or from one instance to another. What are the methods I can use, apart from DDE?
I found this application on VBForums, it uses winsock connection
Play around with it
Regards,
Mark
Please remember to rate posts! Rate any post you find helpful. Use the link to the left - "Rate this Post". Please use [highlight='vb'] your code goes in here [/highlight] tags when posting code. When a question you asked has been resolved, please go to the top of the original post and click "Thread Tools" then select "Mark Thread Resolved."
OK thanks, that works. So thats one method. But Winsock is a pretty inefficient method unless you are sending messages to a different computer, which I'm not.
I'm looking for something more like a API call or similar. Any ideas?
A message from one instance/app telling the other to execute a command.
For example, "Open a New Window", or "Close Now" or similar. It needs to be immediate, like the SendMessage API. I was wondering if there was a way to use that, but not sure where to start.
Manipulating another window is fairly simple, using FindWindow and PostMessage and/or SendMessage. If you could give me some specific examples of what you want, I'll whip something together that should, at the very least, get you started.
User then manages to open it again, possibly by opening a .url link file or somehow doing some form of ShellExecute. I then want the 2nd instance to send the 1st instance a message, telling it to open a new window and passing the URL to open as a string, before closing itself (leaving the user with only 1 instance still and none the wiser).
I didn't think this was possible using PostMessage etc. (thought you could only use the specific constants as messages)
User then manages to open it again, possibly by opening a .url link file or somehow doing some form of ShellExecute. I then want the 2nd instance to send the 1st instance a message, telling it to open a new window and passing the URL to open as a string, before closing itself (leaving the user with only 1 instance still and none the wiser).
For this, it seems the easiest thing to do is have your app check to see if it is already running, and it so, then not allow a second instance to be executed.
Originally Posted by penagate
I didn't think this was possible using PostMessage etc. (thought you could only use the specific constants as messages)
Yes, you are right about that and now that I know the specifics of your request, those APIs I mentioned would not do you any good.
For this, it seems the easiest thing to do is have your app check to see if it is already running, and it so, then not allow a second instance to be executed.
Yeah, I already do that, but the problem is I need the 1st instance to open the URL passed in the 2nd instance's command arguments. Otherwise the user will be getting frustrated when their URLs don't open
Actually you don't need to register a message. You don't even have to send the string. Since what you want to do is to notify an earlier instance of your program of a file to open (or in this case an URL). All you then have to do is to send a unique user defined message to the previous instance window. Of course you could use RegisterWindowMessage to get such a unique message but you could just as well pick any value above WM_USER that will be unique for your program.
You also need to know the hWnd of the main window of the first started application so you can send a message to that. You could use FindWindow if you want but an easier way is that when the application starts, check if a previous instance exists. If not save the hWnd of your main window to the registry or anyother repository you want to use. If a previous instance of your application exists read the hWnd of that instance main window and send it your unique message using SendMessage.
Now how will the program get the URL to open when it gets the message? Well. again you could use the Registry to write the URL to use before sending the message. Another approach could be to create a Global Atom using the GlobalAddAtom message. The return value for that call should be sent to your previous instance, in for example the wParam argument. You can then use this value with the GlobalGetAtomName to get the URL, just make sure you call GlobalDeleteAtom when you have the URL.
Now for all of this to work you must of course subclass your main window and listen for your own unique message.
Thanks for that mate. I'll have a look at making atoms.
and, more subclassing...
Can you show me, or point me to a link where I can find out, how to listen for the message? I already have some subclassing in my app but the technique hasn't really stuck.... it was a copy & paste job
Add the above in a Module. You can start the subclassing by calling the HookForm Sub and pass the hWnd of the Form. You stop subclassing by calling the UnhookForm. You check for the messages in the WinProc function, I've already put in code to check for the WM_DESTROY message which your form gets before it is unloaded. I then stop the subclassing. This is for safety reasons in the case you would forget to call the UnhookForm before your window is closed.
Remember when you subclass a Form not to use the End statement or clicking the End button in VB since it will then crash and burn.
I would use SendMessage to send a WM_COPYDATA message betwen apps. This message uses the COPYDATASTRUCT structure.
VB Code:
Type COPYDATASTRUCT
dwData as long
cbData as long
lpData as long
End Type
where
dwData is a long you may want to pass
ldData is a pointer to your string
cdData is the length or your string
That's all fine moeur... Have you tried that between two VB processes? I'm most intrested to learn how you've created a VB string and passed the address of it in the ldData member.
Don't think that I'm trying to ridicule you or your answer because I don't! I just want to know how you passed on the string because I've tried that before but never succeeded.
There is a limitation with WM_COPYDATA, the data pointer can point to anything including a data structure, but the data structure cannot contain any pointers itself.
I'm really sorry for replying this 4 years old thread. I was just reading around forum and got interested on this one..
In my beginner's mind, why this task is so hard to do? why must use subclassing (which is difficult for me)?
with SendMessageByString i can send string between my 2 apps:
App 1 Sender
Code:
Option Explicit
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function SendMessageByString Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
Private Const WM_SETTEXT = &HC
Private Sub cmdSend_Click()
Dim thunderrtformdc As Long, thunderrttextbox As Long
thunderrtformdc = FindWindow("thunderrt6formdc", "Receiver")
If thunderrtformdc <> 0 Then
thunderrttextbox = FindWindowEx(thunderrtformdc, thunderrttextbox, "thunderrt6textbox", vbNullString)
Call SendMessageByString(thunderrttextbox, WM_SETTEXT, 0&, "Text sent by sender")
End If
End Sub
App 2 Receiver:
only 1 textbox
thank you for explanation..
and sorry for bringing up this old thread..
What you are doing here is sending a Set Text message to another window (form). This will change the caption of the form to your new message and you can then retrieve the message by reading the caption property.
Let's say that you don't want your string showing up on your form, then you can't use the Set Text windows message.
In addition, suppose you want to send something more complicated than a string such as a user defined type. Now the job becomes more complicated.