Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A minimal footprint performance monitor using Windows messaging

0.00/5 (No votes)
24 Feb 2008 1  
In an unmanaged environment, using Windows performance monitors may prove challenging. This article propose an alternative which is both easy and efficient.

Introduction

In an unmanaged environment, using Windows performance monitors may become tricky. This article proposes an alternative which is both easy and efficient: a Windows messaging based performance monitor.

Background

Windows messaging is a technology that goes back to the early days of Windows, the ability to post messages to/between windows is exposed as part of the basic APIs (Win32 APIs), and plays a major part in the Windows Operating System. This article does not intend to cover the concepts of Windows messaging or how to use it, but rather to suggest how it can be harnessed to help with performance monitoring. More general information on Windows messaging can be found in the "Additional Reading" section below.

Application Defined Message

In addition to standard Windows messages that are used to control various window states like resizing, mouse and keyboard actions, Windows messaging allows the use of "application defined messages". The latter go between the values of WM_APP through 0xBFFF, and are guaranteed to be unique at any given time; such uniqueness is obtained by a registration mechanism exposed by the RegisterWindowMessage API. Application defined messages can be used for various objectives, and are especially useful when a lightweight communication channel between multiple applications is of need. There are many advantages for using such a communication channel over a Remoting/DCOM one:

  1. It has a tiny foot print (no negative effect on performance).
  2. It does not require any special setup or configuration.
  3. It does not require that both the client and server are present.
  4. It is asynchronous.

That being said, there are some limitations too:

  1. You cannot carry much data on a Windows message; in fact, you can carry very little: the numeric lParam and wParam are all that you can carry. Having said that, that is good enough for performance reporting.
  2. It is asynchronous, thus, unidirectional.

How Does It Work?

The idea behind a Windows messaging based performance monitor is that applications can post performance meters over the Windows messaging framework, and a client can listen and record relevant messages. As messages are within an application defined range, they will be ignored by both other applications and the Operating System, and if you combine this fact with the fact that they are very lightweight, you get a pretty good performance monitoring solution: it does not require a setup or configuration, does not take disk space, and does not slow your application down.

At the technical level, the solution exploits the two open slots available on the Windows message structure (MSG) to carry the performance meter information; the idea is that every performance meter has a unique, predefined name which is registered using RegisterWindowMessage and used to identify the meter on both the monitor and application side, while the actual performance "results" are carried on the lParam and wParam members of the MSG struct, which means that every meter can carry up to two results.

The solution can be implemented in any Microsoft based language. However, given the ease of integrating with the Windows performance monitor in .NET based solutions, it is more useful to implement this solution in the older generation languages in which the Windows performance monitor is more challenging to integrate with. The code below demonstrates how this can be used in all three major platforms: C++, VB6, and .NET.

The Code

The attached code contains an example of a rudimentary monitor coded in C# and three sample apps coded in CPP, VB, and C#.

Example 1, posting messages in CPP:

void CCPPDlg::LogPerformance(LPCWSTR bsMeterName, int iResult1, int iResult2)
{
    int iMessageID = RegisterWindowMessage(bsMeterName);
    PostMessageA(HWND_BROADCAST, iMessageID, iResult1, iResult2);
}

Example 2, posting messages in VB:

Private Declare Function RegisterWindowMessage Lib "user32.dll" _
        Alias "RegisterWindowMessageA" (ByVal lpString As String) As Long
Private Declare Function PostMessage Lib "user32.dll" _
        Alias "PostMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, _
                              ByVal wParam As Long, ByVal lParam As Long) As Long

Private Const HWND_BROADCAST = &HFFFF&

.
.
.

Private Sub LogPerformance(ByVal MeterName As String, ByVal Result1 As Integer, _
                           ByVal Result2 As Integer)
Dim lMessageID As Long

    lMessageID = RegisterWindowMessage(MeterName)
    Call PostMessage(HWND_BROADCAST, lMessageID, Result1, Result2)

End Sub

Example 3, posting messages in C#:

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern uint RegisterWindowMessage(string lpString);

[DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true, 
CharSet = CharSet.Auto)]
private static extern uint PostMessage(int hWnd, uint Msg, int wParam, int lParam);

private const int HWND_BROADCAST = 0xffff;

.
.
.

private void LogPerformance(string MeterName, int Result1, int Result2)
{
    uint iMessageID = RegisterWindowMessage(MeterName);
    PostMessage(HWND_BROADCAST, iMessageID, Result1, Result2);
}

Additional Reading

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here