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

Inter process communication using registered messages from Visual Basic

, 18 Mar 2003
Rate this:
Please Sign up or sign in to vote.
This article shows how you can register custom windows messages and create windows solely for dealing with these messages, and use these to communicate between your applications.


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 Function WM_MCL_CHANGENOTIFY() As Long 
      Static msg As Long 
      If msg = 0 Then 
            msg = RegisterWindowMessage(MSG_CHANGENOTIFY)
      End If
     End Function


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, _
    ByVal lpClassName As String, _
    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 
        sWindowTitle = WINDOWTITLE_SERVER 
    End If 
    CreateCommunicationWindow = hwndThis
End Function


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 
       wParam As Long, ByVal lParam As Long) As Long

    '\\                     UINT, WPARAM, LPARAM); 
    '\\ Parameters: 
    '\\   hwnd - window handle receiving message 
    '\\   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 
      '\\Respond to the custom message here
        '\\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 
   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" _
   As Long, ByVal lParam As Long) 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




About the Author

Duncan Edwards Jones
Software Developer (Senior)
Ireland Ireland
C# / SQL Server developer
Microsoft MVP 2006, 2007
Visual Basic .NET
Follow on   Twitter   LinkedIn

Comments and Discussions

GeneralSome thoughts... PinmemberMerrion19-Mar-03 9:05 



| Advertise | Privacy | Mobile
Web03 | 2.8.140709.1 | Last Updated 19 Mar 2003
Article Copyright 2003 by Duncan Edwards Jones
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid