Click here to Skip to main content
Click here to Skip to main content

Inter process communication using registered messages from Visual Basic

By , 18 Mar 2003
 

Introduction

One of the simplest ways to implement multi-tasking in Visual Basic is to create a separate executable program to do each task and simply use the Shell command to run them as necessary. The only problem with this is that, once a program is running, you need to communicate with it in order to control its operation. One way of doing this is using the RegisterWindowMessage and SendMessage API calls to create your own particular window messages and to send them between windows thus allowing you to create two or more programs that communicate with each other. In this example, the server has the job of watching a printer queue and sending a message to every interested client, whenever an event (job added, driver changed, job printed etc.) occurs.

Specifying your own unique messages

Windows communicate with each other by sending each other, standard Windows messages such as WM_CLOSE to close and terminate the window. There are a large number of standard messages which cover most of the standard operations that can be performed by and to different windows. However if you want to implement your own custom communication, you need to create your own custom messages. This is done with the RegisterWindowMessage API call:

'\\ Declaration to register custom messages
Private Declare Function RegisterWindowMessage Lib "user32" Alias _
  "RegisterWindowMessageA" (ByVal  lpString As String) As Long

This API call takes a unique string and registers it as a defined Windows message, returning a system wide unique identifier for that message as a result. Thereafter any call to RegisterWindowMessage in any application that specifies the same string, will return the same unique message ID. Because this value is constant during each session, it is safe to store it in a global variable to speed up execution thus:

     Public Const MSG_CHANGENOTIFY = "MCL_PRINT_NOTIFY" 
     
      Public Function WM_MCL_CHANGENOTIFY() As Long 
      Static msg As Long 
      
      If msg = 0 Then 
            msg = RegisterWindowMessage(MSG_CHANGENOTIFY)
      End If
     
     WM_MCL_CHANGENOTIFY = msg
     
     End Function

Since this message needs to be known to every application that is using it to communicate, it is a good idea to put this into a shared code module common to all projects.

Creating windows to listen for these messages

To create a window in Visual Basic, you usually use the form designer and add a new form to your project. However, since our communications window has no visible component nor interaction with the user, this is a bit excessive. Instead we can use the CreateWindowEx API call to create a window, solely for our communication:

Private Declare Function CreateWindowEx  _
    Lib "user32"  Alias "CreateWindowExA"  
    (ByVal dwExStyle  As Long, _
    '\\ The window class, e.g. "STATIC","BUTTON" etc.
    ByVal lpClassName As String, _
    '\\ The window's name (and caption if it has one) 
    ByVal lpWindowName As String, _
    ByVal dwStyle As Long, _
    ByVal x As Long, _
    ByVal y As Long, _
    ByVal nWidth As Long, _
    ByVal nHeight As Long, _
    ByVal hWndParent As Long, _
    ByVal hMenu As Long, _
    ByVal hInstance As Long, _
    lpParam As Any) As Long 

If this call is successful, it returns a unique window handle which can be used to refer to that window. This can be used in SendMessage calls to send a message to it.

In a typical client/server communication, you need to create one window for the client(s) and one window for the server. Again this can be done with a bit of code common to each application:

Public Const WINDOWTITLE_CLIENT = "Merrion Computing IPC - Client" 
Public Const WINDOWTITLE_SERVER = "Merrion Computing IPC - Server"
     
Public Function CreateCommunicationWindow(ByVal client As Boolean) As Long 
    
    Dim hwndThis As Long 
    Dim sWindowTitle As String 
    
    If client Then 
        sWindowTitle = WINDOWTITLE_CLIENT 
    Else
        sWindowTitle = WINDOWTITLE_SERVER 
    End If 
    
    hwndThis = CreateWindowEx(0, "STATIC", sWindowTitle,_
        0, 0, 0, 0, 0, 0, 0, App.hInstance, ByVal 0&)
    
    CreateCommunicationWindow = hwndThis
    
End Function

Obviously for your own applications you should use different text for the WINDOWTITLE_CLIENT and WINDOWTITLE_SERVER than above, to ensure that your window names are unique.

Processing the custom messages

As it stands, you have a custom message and have created a window to which you can send that message. However, as this message is entirely new to the window it does not do anything when it receives it. To actually process the message you need to subclass the window to intercept and react to the message yourself. To subclass the window, you create a procedure that processes Windows messages and substitute this for the default message handling procedure of that window. Your procedure must have the same parameters and return type as the default window procedure:

Private Declare Function CallWindowProc Lib 
      "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc 
      As Long, ByVal hwnd As Long, ByVal msg As Long, ByVal
       wParam As Long, ByVal lParam As Long) As Long

   
   
    '\\ --[VB_WindowProc]--------------------------------- 
    '\\ 'typedef LRESULT (CALLBACK* WNDPROC)(HWND, 
    '\\                     UINT, WPARAM, LPARAM); 
    '\\ Parameters: 
    '\\   hwnd - window handle receiving message 
    '\\   wMsg - The window message (WM_..etc.) 
    '\\   wParam - First message parameter 
    '\\   lParam - Second message parameter 
Public Function VB_WindowProc(ByVal hwnd As Long, _
     ByVal wMsg As Long, ByVal wParam As Long,_
     ByVal lParam As Long) As Long 
     
    If wMsg = WM_MCL_CHANGENOTIFY Then 
      '\\Respond to the custom message here
     
    Else
        '\\Pass the message to the previous 
        '\\window procedure to handle it
        VB_WindowProc = CallWindowProc(hOldProc, hwnd, _
                                    wMsg, wParam, lParam)
    End If
     
End Function

You then need to inform Windows to substitute this procedure for the existing window procedure. To do this you call SetWindowLong to change the address of the procedure as stored in the GWL_WINDPROC index.

Public Const GWL_WNDPROC = (-4) 
Public Declare Function SetWindowLongApi  Lib "user32" _
     Alias "SetWindowLongA" _
    (ByVal hwnd  As Long, ByVal nIndex  As Long, _
     ByVal dwNewLong  As Long) As Long 
   
   '\\ Use (after creating the window...) 
   hOldProc = SetWindowLongApi(hwndThis, _
      GWL_WNDPROC, AddressOf VB_WindowProc)

You keep the address of the previous window procedure address in hOldProc in order to pass on all the messages that you don't deal with for default processing. It is a good idea to set the window procedure back to this address before closing the window.

Sending the custom messages

There are two steps to sending the custom message to your server window: First you need to find the window handle of that window using the FindWindowEx API call. Then you need to send the message using the SendMessage API call.

'\\ Declarations 
Public Declare Function SendMessageLong Lib "user32" Alias "SendMessageA" _
   (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam _
   As Long, ByVal lParam As Long) As Long _
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
   (ByVal lpClassName As String, ByVal lpWindowName As String) As Long 
  
  '\\ use.... 
  Dim hwndTarget As Long
  
  hwndTarget = FindWindow(vbNullString, WINDOWTITLE_SERVER)
  
  If hwndTarget <> 0 Then 
      Call SendMessageLong(hwnd_Server, _
           WM_MCL_CHANGENOTIFY, 0,0) 
  End If

This will send the WM_MCL_CHANGENOTIFY message to the server window and return when it has been processed.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Duncan Edwards Jones
Software Developer (Senior) JP Morgan
Ireland Ireland
Member
C# / SQL Server developer
Microsoft MVP 2006, 2007
Visual Basic .NET

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalcalling C#.net application from VB6.0 and parameter passingmemberranjanpiyush22 Oct '07 - 4:15 
Hi
how can we call C#.net application from VB6.0 application.In my case i have to pass perameter from vb to .net.
thanks
QuestionWhich?memberCoderKevin2 Jul '07 - 19:49 
Good article. As for performance, which is better--IPC or Named Pipes?
 
Thanks,
Kevin
AnswerRe: Which?memberDuncan Edwards Jones29 Aug '07 - 2:51 
My instinct is that windows messages would be more performant but not nearly as powerful as named pipes...I mainly use windows messages for notification type communication.
 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd

GeneralThanks!memberillium12 Dec '06 - 13:15 
Some of are still supporting VB6 apps... Some of us don't want to be... Wink | ;)
 
This was extremely helpful when trying to integrate our old VB6 stuff with our new stuff!
 
Thanks,
illium
GeneralFound a better versionmemberHelix40011 Mar '05 - 14:29 
I found this example to be very confusing and unhelpful.
 
A better example, with downloadable code in a clean, crisp, easy to use form with one process talking to another is found here: http://www.d2dsources.com/ViewSource.aspx?Type=VB&ID=109052
GeneralRe: Found a better versionmemberMerrion13 Mar '05 - 4:50 
An article is for education and knowledge sharing whereas a drag and drop code is for instant gratification. The latter may suit you more in which case go with it.
 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd
GeneralRe: Found a better versionsussAnonymous20 Mar '05 - 7:49 
Im sure this example is more stable than hooking msgs in a vb form...
GeneralRe: Found a better versionsussAnonymous25 Oct '05 - 17:29 
If you look close at the link you posted, it pretty much looks like it was written from this tutorial. Maybe if you would have read it compleatly, you would not have been so confused.
 
GREAT TUTORIAL, this is just what I looked so hard to find. Worked awesome. Especially loved the part about creating the "communication" window.
GeneralCommunicating with a third part app from my VB appmemberjpsharma23 May '04 - 8:21 
Hi,
I am trying to interface my VB6 application with a third party app. The third party app has published the Message String and list of Wparam and Lparam to implement the desired communication between my App and theirs. I am new to window messaging and your article is very helpful for me to get started on it. Thanks for the nice writeup. However, it will be very helpful if anyone can give me some answer to the following.
 
a. How do I determine which window of the third party application I should send the message. It is not mentioned in their documentation.
 
b. How will the third party app know which window in my application it should return the response?
 
c. As shown in this example, I am planing to make two windows one Server window that sends message to the 3rd party application and a Client window that receive and process the message from the 3rd party application. Am I in the right track? At present it is not working, but I hope to get it through. Any comments/suggestion please
 
JP
GeneralRe: Communicating with a third part app from my VB appmemberMerrion11 Oct '04 - 3:23 
(a) If the window concerned is not specified then it is probably the application main window.
 
(b) If you use SendMessage your app will wait for the recipient to process the message and the result will be returned to you.
 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd
GeneralThank You Very Much...memberVishal Goswami23 Oct '03 - 21:59 
Smile | :) Your Article Was Really Amazing, It Could be Very useful If We Read this type of more and more Articles So plese Write some Tutorials or Leassons for VB again Thank you Very much...
 
Vishalgiri Goswami (Who Else)
GeneralIPC in C#memberMadhu AB6 Aug '03 - 19:31 
Hi
a very nice article - got the the basics of IPC clearly
but i would like to know how can you have communication between two process
in c#
 
i have an application which bringsup another application in another process
and would like to communicate between them
 
thax for any help
Madhu

GeneralRe: IPC in C#sussAnonymous6 Aug '03 - 21:53 
In the .NET framework, inter process communication is best acheived by use of the "remoting" classes.
GeneralRe: IPC in C#sussNicolas Mulard11 Dec '03 - 20:22 
you should take a look at this nice article
Simple Interprocess Communications using WM_COPYDATA[^]
GeneralRe: IPC in C#membersanjit_rath21 Jun '05 - 1:38 
Another easier and unique way that i can visualize, is by using threads. Threads are unique across processes and can communicate if the thread id is passed between them.
 
The other benefit of using the threads are there is no overhead of implementing queue for processing messages, cuase this will be handled by the OS Smile | :)
 
Also, we can use the File Mapping to communicate with another process.

 
Cheers Smile | :)
GeneralError ERROR_INVALID_INDEXmemberbigwizard29 Jul '03 - 4:50 
Hello!
 
I have trouble with
hOldProc = SetWindowLong(hwndThis, GWL_WNDPROC, AddressOf VB_WindowProc)
SetWindowLong return 0 and error code is ERROR_INVALID_INDEX
 
What's wrong?
 
Thanks

GeneralRe: Error ERROR_INVALID_INDEXmemberMerrion29 Jul '03 - 5:10 
Not something I have come across before.
 
You have the declkarations:
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Const GWL_WNDPROC = (-4)
 
And hwndThis is pointing to a valid window handle?
 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd
GeneralRe: Error ERROR_INVALID_INDEXmemberbigwizard30 Jul '03 - 4:05 
Thanks!
 
I haven't had the declkarations GWL_WNDPROC
 


GeneralRe: Error ERROR_INVALID_INDEXmemberjesal19 May '04 - 10:26 
hi,
 
im using the above code to do some inter app communications..precisely vb.net/excel..
 
and when i try to do this..
 
hOldProc = SetWindowLong(hwndThis, GWL_WNDPROC, AddressOf VB_WindowProc)
 
it tells me..(1170): 'AddressOf' expression cannot be converted to 'Long' because 'Long' is not a delegate type.
 
any help is appreciated..
 
thanks.
jesal

GeneralRe: Error ERROR_INVALID_INDEXmemberMerrion19 May '04 - 22:26 
There is a VB.Net example here: http://www.thecodeproject.com/useritems/VB6andVBNETWindowMessages.asp[^]
 

 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd
QuestionHow about remotingmemberMatthias Gerloff20 Mar '03 - 6:26 
Hi!
 
Interprocess communication can easily be done via .net remoting, which gives you a full interface to the other service. Give it a try.
 
Regards, Matthias
AnswerRe: How about remotingmemberMerrion20 Mar '03 - 7:13 
This is true of .NET but the article is targetted at VB5/6.

 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd
GeneralRe: How about remotingmemberMatthias Gerloff21 Mar '03 - 6:00 
ups, my mistake Blush | :O
GeneralSome thoughts...memberMerrion19 Mar '03 - 9:05 
The API call "SendMessage" is a blocking call. If you require your communicating applications to operate asynchronously replace this with calls to "PostMessage".
 
'--8<------------------------
Ex Datis:
Duncan Jones
Merrion Computing Ltd

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 19 Mar 2003
Article Copyright 2003 by Duncan Edwards Jones
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid