Category: win32


If you have been following this blog, then you would know that I was trying to create a simple timer/stopwatch that would run from the system tray. Well I did manage to get the application in a runnable state a long time ago. Recently I made it upon source and committed it to codeplex.com. So without further ado, you can get download the code from

http://traytimer.codeplex.com

I would love to hear comments, criticisms anything about it.

So here I was debugging my super awesome stop watch, and I was debugging it using the win32 MessageBox function. If I wished to check whether my program is calling a function, I would put a message box in the function. To check whether the flow is going into a condition or not, I would put a message box. To check If  a window Message is recieved, you guessed it a message box. Basically, I was mimicking the Printf, Println to the console debugging, Which meant I had a lot of message boxes for debugging purposes.  I know this isn’t the most proper way of doing things, but I guess I like the simplicity of print statements i.e message box displays while debugging.

So the situation was that I had a lot of debugging code in my actual code. This code needed to be compiled and executed only when the project was running under the debug build, and not under release build. The simplest solution was to enclose all my debug code as follows

#ifdef _DEBUG
 MessageBox(...)
#endif

Whenever we are in the debug build, Visual Studio defines the _DEBUG Macro for us (Its under the project settings). Thus when we compile a debug build, my message boxes would work and during a release build they would never be compiled into the executable.

This was the simpleset solution, but the problem was my code started to look crowded. i.e every time I wanted to put a debug message box I had to type in at least three lines of code, thus increasing the size of my code. The other problem that I still faced was with the message box function itself. The typical message box function looks something like this

MessageBox(NULL, L"Caption", L"Message", MB_OK|MB_CANCEL|MB_ICONEXCLAMATION);

Now as far as debugging was concerned, I always wanted a message box with just MB_OK button, and didn’t care about the icon displays. But I still had to type the entire message box call each time I wanted to have a message box. This is where pre processer macros helped out a lot. To reduce the message box call, I ended up with a macro as follows

#define POPINFO(X, Y) { MessageBox(NULL, L#X, L#Y, MB_OK); }

So now I just replaced all my MessageBox calls with POPINFO calls, for example

POPINFO(Constructor, Inside Constructor of Application);

This had a very nice side effect, I no longer had to enclose my strings with a L”..”.
I further refined this macro to take into consideration the _DEBUG flag as follows

#ifdef POPINFOENABLE
    #ifndef POPINFO
        #define POPINFO(X, Y) { MessageBox(NULL, L#X, L#Y, MB_OK); }
    #endif
#else
    #ifndef POPINFO
        #define POPINFO(X, Y)
    #endif
#endif

Whenever I wanted to enable debug Message Boxes, I would define the POPINFOENABLE macro and whenever I didnt want them, I would not define it, or explicitly undef it. This was my solution to simplifying the use of MessageBox for debugging purposes. I hope everyone find it to be useful, and would love to hear how you go about debugging your windows apps.

One of the requriements I thought up for my stop watch, is to detect if the system has been idle for a long time. If it has been idle for say half an hour, and clock is running, then it should alert the user and pause. This is to prevent the clock from counting incase I forget to pause it or stop and leave the computer for some reason.

There are two ways to achieve this, One is to monitor the system for the keyboard/mouse events and keep a count of time elapsed, the other is to use the win32 api GetLastInputInfo().

GetLastInputInfo : This is a very simple method to get the system idle time. Let us have a look at the function prototype.

BOOL GetLastInputInfo(PLASTINPUTINFO plii);

The function accepts a pointer to the LASTINPUTINFO structure, which is described as below.

typedef struct tagLASTINPUTINFO
{
   UINT cbSize;
   DWORD dwTime;
} LASTINPUTINFO, *PLASTINPUTINFO;

As you can see it is a very basic structure, before calling the GetLastInputInfo function we have to initialise the cbSize variable. This is easily achieved by sizeof(LASTINPUTINFO). The function returns the last tick count of any mouse or keyboard events. The tick count is the number of milliseconds which have elapsed since the sytem was booted up. i.e. the same type of information returned by GetTickCount() function. For more information on tick count, look up GetTickCount() function on msdn.

Once we have this info, it is very easy to compare it with the current time and determine the system idle time. For example :


LASTINPUTINFO lii;
lii.cbSize = sizeof(LASTINPUTINFO);

GetSystemInputInfo(&lii);
DWORD currentTime = GetTickCount();

DWORD timeElapsed = currentTime - lii.dwTime;

This will give us, in milliseconds, the time for which the system has been idle. It can easily be converted to seconds, minutes, hours etc according to our needs.

There are two drawback of this function. Firstly, we cannot accurately measure the time beyond 49 days. This is in fact a limitation of the tick concept and the precision being DWORD (refer to the GetTickCount msdn article for furthur explaination). This ofcourse is not going to be a big concern for my app, as the use case of someone leaving the sysem idle for 49 days is very rare (I am targeting work stations and not servers).  The other drawback is that the GetSystemInputInfo returns the last input time for current user. This again is not a concern for my application, but could be an issue for applications like screensavers, auto shutdown etc.

The other method for tracking the system idle time is setting system wide hooks to capture the WM_KEYBOARD and WM_MOUSE events from the all processes, and keeping a count ourselves. I will discuss this method in another post as it is a bit more complicated.

I hope everyone finds this useful, and would love to hear some comments.

Remember the main function from our standard C programs or the win32 console programs. It used to have two arguments argc and argv as follows

int main(int argc, char * argv[]) ...

These parameters helped us send command line parameters to our programs. ‘argc’ would hold the number of arguments passed and argv would be an array of   the parameters passed. But when we are doing a GUI based win32 application in visual studio, we would use the WinMain function as our entry point. This function doesnt have an argc or an argv argument. So how do we pass command line parameters to Windows programs, and how do we access them in our programs.

lpCmdLine argument

One solution is the WinMain function itself. Let us look at the typical declaration of WinMain

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)..

As we can see in the declaration, we have an argument called lpCmdLine of type LPSTR (char *). This variable stores the entire command line minus the name of the program. For eg if we had a program called ‘test.exe’ and if we called it as

test.exe Some arguments here

The variable lpCmdLine would hold the value “Some arguments here”. This is one way of accessing command line parameters,  although not as helpful as the classic argc and argv. We would have to write the code to parse the lpCmdLine variable ourselves, thus increasing the complexity of our program. Also, as we can see lpCmdLine is actually an ANSI string and thus would not work with Unicode characters being passed at commandline.

GetCommandLine()

Another method is to use GetCommandLine() api. This function returns the entire command line, i.e. it includes the program name (which could include the absolute path) and also all the parameters in a single string. This is similar to directly accessing lpCmdLine, but the advantage is that it is mapped to either the ANSI GetCommandLineA() function or the unicode GetCommandLineW() function depending on your projects settings. This solves the problem of unicode input thru command line, but it still doesnt provide a count of arguments neither the arguments as seperate variables like argv.

CommandLineToArgvW()

The last method that I am going to discuss is CommandLineToArgvW This function only works with the Unicode/Wide character set and there seem to be no CommandLineToArgvA ANSI equivalent function. The prototype is as follows

LPWSTR *CommandLineToArgvW(LPCWSTR lpCmdLine, int *pNumArgs)

This function comes closest to the simplicity of argc and argv, or rather it gives us access to our argc and argv in the windows program. As we can see the function accepts two arguments, one is a unicode commandline string which needs to be parsed, the second is a pointer to an int variable. The function stores the number of arguments in this variable when it returns.

The function returns an array of strings, which is similar to argv. Lets look at an example.

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    LPWSTR *szArgList;
    int argCount;

     szArgList = CommandLineToArgvW(GetCommandLine(), &argCount);
     if (szArgList == NULL)
     {
         MessageBox(NULL, L"Unable to parse command line", L"Error", MB_OK);
         return 10;
     }

     for(int i = 0; i < argCount; i++)
     {
         MessageBox(NULL, szArgList[i], L"Arglist contents", MB_OK);
     }

     LocalFree(szArgList);
     return 0;
}

As we can see above by using this function, we get the commandline as the number of arguments(argc) and a list of strings (argv). The only thing to remember here is that, the function allocates a block of memory for the argument list. We have to manually delete this memory whenever we are done with it, or we will have a leaking application.

EDIT: Variables __argc and __argv

As pointed below by anonymous, Microsoft compiler provides us with the variables __argc and __argv. These variables are automatically populated at runtime by windows. The variables are available in two flavors, the ASCII version and the Unicode version. __argv is the ascii version, whereas __wargv is the unicode version. To use them we have to include stdlib.h, which is automatically included whenever you include windows.h. To let the project setting decide which version of the variable to use, we can access __targv, by including TCHAR.h.

This method is the simplest of them all, but the caveat is that we have to link to the VC++ runtime library i.e. msvcrt.dll (which we would for almost 99% of windows programs).

I hope this helps everyone, would love to hear everyone’s comments regarding the same.

I wanted to implement a double click method to close the display window. That is, whenever the user double clicked on the client window, my window should close.


case WM_LBUTTONDBLCLK:
 ShowWindow(hWnd, SW_HIDE);
 break;

To implement this I decided to process the WM_LBUTTONDBLCLK message in my window procedure, as follows.

Short and simple, but I was wrong.  I ran this code and tried to double click the window, nothing happend. I changed a few things and tried again, still nothing happening. I finally put a break point inside the WM_LBUTTONDBLCLK case, and realized, that no matter how fast or slow I double clicked, the window never recieves the WM_LBUTTONDBLCLK message.

After digging about in msdn( yes the WM_LBUTTONDBLCLK page), I found out that, for our window to recieve the WM_LBUTTONDBLCLK message, we have to define our window class as having the style CS_DBLCLKS.

ie when we define WNDCLASS or WNDLCASSEX, we have to include CS_DBLCLKS as a style. For example, my window class defination now looks like

WNDCLASSEX wcex;
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS
.....

On normal windows class, whenever we double click on the client area, windows generates a series of WM_LBUTTONDOWN and WM_LBUTTONUP. i.e. we may recieve something like the following.

WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDOWN, WM_LBUTTONUP .....

There is also no guarentee, that we would recieve all of them simultanously, i.e. there might be other messages present between them. So we cant rely on the sequence to determine a doubleclick. Whenever, we define our window class to have the style of CS_DBLCLKS, Windows replaces the second WM_LBUTTONDOWN message with the WM_LBUTTONDBLCLK, whenever the left button is clicked twice with the system defined intervel. But we will still recieve four mouse messages as follows.

WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK, WM_LBUTTONUP ...

The lesson to learn  is that, we will recieve a buttondown and a buttonup message before our dblclk message.  Thus whatever processing we are doing for the down and up events will be executed along with the dblclk logic.

As I have mentioned before, I am creating a stop watch application using Visual C++ express and win32. One of the features I wanted to implement, was to be able to drag/move the display window using mouse.  I had implemented this window using the WS_EX_TOOLWINDOW and WS_POPUPWINDOW style. This meant that the window would not have a caption bar, and hence no way to drag/move the window. Even the ‘Move’ command of system menu would fail, as there was no caption bar. There could be many ways to overcome this problem. I am going to list here the method that I used.

Here are some basic steps to solve this :

  1. Indicate to our window, that we want to drag or move. This can be done thru a menu option,  mouse event, a button, a key etc I chose to do it whenever the left button is held down. This would mean processing the WM_LBUTTONDOWN event on the main window.
  2. Capture the mouse, so that Windows will pass all the mouse events to our window.
  3. Process the WM_MOUSEMOVE event to actually move the window.
  4. Indicate to the Window,  that we are done moving. Again, this can be done thru a menu option,  mouse event, a button, a key etc I chose to do it whenever the left button is released and process WM_LBUTTONUP. This would mimic the typical drag and drop behavior, ensuring consistency with windows.

So let us see an example of the same. As I mentioned earlier, I was going to mimic the typical drag and drop behaviour. Whenever the user would press and hold the left mouse button, I would enter the drag state and capture the mouse to the window. This can be achived by processing the WM_LBUTTONDOWN command in our Window Procedure.

case WM_LBUTTONDOWN:
     dragWindow = true;
     SetCapture(hWnd);
     break;

Windows will always send our window procedure the WM_MOUSEMOVE command, irrespective of any button press etc.  If we were to just process the WM_MOUSEMOVE command and move our window, it would move everytime we moved the mouse, irrespective of any buttons being pressed. To overcome this we use a variable, which I called ‘dragWindow’. We want to move our window in the WM_MOUSEMOVE message only if this variable is true. Thus we set it to true whenever the left mouse button is pressed.

Also the SetCapture(HWND hWnd) function captures the mouse for us. This will ensure that our window recieves each and every mouse event, irrespective of whether it is within our client window or anywhere else. We should release the mouse whenever we are done with our movements. To do this we use the function called ReleaseCapture() as follows

case WM_LBUTTONUP:
     ReleaseCapture();
     dragWindow = false;
     break;

The WM_LBUTTONUP message is sent whenever the left button is released, thus indicating that our drag operation is complete. Thus we also set the dragWindow variable to false. Now to implement the actual movement code.

To acutally move the window we have to process the WM_MOUSEMOVE messages. Everytime we recieve the message, we set a new position for our window. This could be done in many ways, like using SetWindowPos() API or destroying and recreating our window or using MoveWindow() api. I chose to use the MoveWindow API, because it seems to exist  just to facilitate  the dragging and moving of windows.

case WM_MOUSEMOVE:
     if (dragWindow == true)
     {
         RECT mainWindowRect;
         POINT pos;
         int windowWidth, windowHeight;

         pos.x = (int)(short) LOWORD(lParam);
         pos.y = (int)(short) HIWORD(lParam);

         GetWindowRect(hWnd,&mainWindowRect);
         windowHeight = mainWindowRect.bottom - mainWindowRect.top;
         windowWidth = mainWindowRect.right - mainWindowRect.left;

         ClientToScreen(hWnd, &pos);
         MoveWindow(hWnd, pos.x, pos.y, windowWidth, windowHeight, TRUE);
     }
     break;

The WM_MOUSEMOVE message is sent whenever the mouse moves inside our window, but as we have captured the mouse, it would be recieved irrespective of mouse position. The lParam variable contains the new ‘X’ and ‘Y’ value of the cursor as the LOWORD and the HIWORD. The position returned is in the client space and not in screen space. To convert this position to actual screen space co-ordinates, we use the ClientToScreen(HWND, *RECT) function.  Once we have this information, we calculate the window widht and height.

Uptill now we haven’t moved the window. To move the window, we invoke the MoveWindow() API.  The function takes six parameters, the window handle which we are moving, new x and y co-ordinates, new width and height. The last variable indicates whether we want to refresh the window while moving. If it is set to TRUE, then the function will send out a WM_PAINT message, otherwise we will have to explicitly redraw the window after MoveWindow.

Well that is about it. Please do leave a comment if you find this useful or if there is anything missing.

So here I was, happily programming my little stopwatch, I had already created my system tray icon and embedded some version info into. Now I was ready to implement to heart of my application, A popup menu to control the stopwatch. I looked up msdn, searched the net and came up with my code to create the popup menu.

From what I understood, it was a three step process create a handle to a menu, append items to the menu and display the menu using ‘TrackPopupMenu’. To start of with, I decided to implement just two commands under the menu. Just to test out the code and how it works. Following is the code that I implemented.

HMENU hPopup = CreateMenu();
AppendMenu(hPopup, MF_STRING, ID_START, L"Start");
AppendMenu(hPopup, MF_STRING, ID, L"Stop");

POINT pt;
GetCursorPos(&pt);

TrackPopupMenuEx(hPopup, TPM_RIGHTALIGN  | TPM_LEFTBUTTON, pt.x, pt.y, hWnd, NULL);

DestroyMenu(hPopup);

I compiled my code and ran my program. I rightclick on my icon and Bam, A menu as thin as angel hair spagehti, with no strings displayed. Check out the screenshot.

Menu over my system tray icon

Tray Icon Menu

Menu over the application Window

Menu over the application Window

As you can see in the two screen shots, the menu has the required number of rows, i.e. 3 as per my description and it even sends out the appropriate messages when one of them is clicked, It just doesn’t display anything. This little discrepancy took me a while to figure out. From what I found out, this problem is faced by people new to win32. This is one of those little Idiosyncrasy of win32 API. The way to resolve this problem is a bit peculiar.

To get the menu displaying properly, first we need to append our menu to a temporary menu as a POPUP to it, then we have to extract the menu back using GetSubMenu function and use that handle in TrackPopupMenuEx function. The code below would explain it much better.

HMENU hPopup = CreateMenu();
HMENU hTemp = CreateMenu();

AppendMenu(hPopup, MF_STRING, ID_START, L"Start");
AppendMenu(hPopup, MF_STRING, ID_STOP, L"Stop");

AppendMenu(hTemp, MF_POPUP, (UINT_PTR) hPopup, L"Dummy");
hPopup = GetSubMenu(hTemp, 0);

POINT pt;
GetCursorPos(&pt);
TrackPopupMenuEx(hPopup, TPM_RIGHTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, hWnd, NULL);

DestroyMenu(hTemp);
DestroyMenu(hPopup);

And with that, my popup menu gives up its diet and displays perfectly.

Menu after it stopped Dieting

Menu after it stopped Dieting

I hope this helps out people who are just starting out with win32 and ran into this problem, as I had to spend a lot of time trying to figure out this problem.

What if the menu is defined as a resource

Let me define the orginal menu as a resource, remember this will show up as a thin bar.

First the resource.rc file

MENUDEMO MENU DISCARDABLE
BEGIN
    MENUITEM "Start"  ID_START
    MENUITEM "Stop"   ID_STOP
END

To fix this description, we have to add a fake POPUP block to the description as follows.

MENUDEMO MENU DISCARDABLE
BEGIN
     POPUP "Dummy"
     BEGIN
          MENUITEM "Start" ID_START
          MENUITEM "Stop"  ID_STOP
     END
END

Now as before, we would extract the submenu using the GetSubMenu function and then display the submenu using TrackPopupMenuEx function.

I hope this helps out everyone, as it was very frustrating to figure this problem out. Do drop by and let me know if there is a better way of solving this problem, I would love to hear about it.

In windows xp, whenever we right click on an executable file, we can see a Version info tab.

Tab displays additional information of the executable

Tab displays additional information of the executable

To include this information in our application, we need to create a VERSIONINFO resource in our application. This would generally be in your .rc file.

For example the resource file for the above executable is as follows.

#DEFINE VER_FILEVERSION          1,0,0,0
#DEFINE VER_FILEVERSION_STR      "1.0"
#DEFINE VER_PRODUCTVERSION       1,0,0,0
#DEFINE VER_PRODUCTVERSION_STR   "1.0"

VS_VERSION_INFO        VERSIONINFO
FILEVERSION            VER_FILEVERSION
PRODUCTVERSION         VER_PRODUCTVERSION
FILEOS                 VOS_NT_WINDOWS32
FILETYPE               VFT_APP
FILESUBTYPE            VFT2_UNKNOWN
BEGIN
     BLOCK "StringFileInfo"
     BEGIN
         BLOCK "040904E4"
         BEGIN
             VALUE "CompanyName"          "Testing Times"
             VALUE "FileDescription"      "Testing My Version Info"
             VALUE "LegalCopyright"       "Copyright 2009 (c) PJ. All rights reserved."
             VALUE "ProductName"          "Test Ahoy!!"
             VALUE "ProductVersion"       VER_PRODUCTVERSION_STR
             VALUE "FileVersion"          VER_FILEVERSION_STR
         END
     END
END

We can also define custom parameters in the StringFileInfo block, such as  support information, contact information etc.

The msdn article on VERSIONINFO is quiet detailed, so I am just going to point to it for further reference.

VERSIONINFO – Click here to goto to MSDN.

I took up a project to create a simple Stopwatch. The aim of the project was to keep a track of the time I spend on various projects. I wanted a very simple application which was able to Start Pause and Stop a Stopwatch.

The best approach that I thought up was through a System Tray application. This would give me easy access to the controls and display, without interfering with my open windows. As I am trying to have a go at C++ and win32, I decided to implement it using Visual C++ 2008 express edition and win32 API.

So without any further delay, here are the basic steps needed to create an icon in the system tray.

  1. Include the “shellapi.h” header file, and link to “shell32.lib” library (Visual C++ links to it by default.
  2. Define a custom message identifier for our icon. Whenever there is a mouse or keyboard event on our icon, windows will use this identifer to send messages to our message procedure.
  3. Create and initialize the NOTIFYICONDATA structure according to our needs.
  4. Invoke Shell_NotifyIcon() API, with a pointer to NOTIFYICONDATA, to create, modify or delete our icon.

To demonstrate the steps let us consider this example. For our application, we would like to have an icon in the system tray. It should display a message box whenever it is double clicked and ‘Tray Icon’ whenever the mouse hovers on top of it.

To begin with we need to include ‘shellapi.h’ in our application.

#include <shellapi.h>

The next step would be to define a custom message identifier. Whenever a mouse event occurs on our icon, Windows will send this custom message to our message procedure. The lParam variable will have the actual mouse or keyboard event and wParam will contain the iconid.

#define WM_MYMESSAGE (WM_USER + 1)

Now we should create a variable of type NOTIFYICONDATA and populate it as per our icon’s need. I will first show the example, before explaining the structure further.

NOTIFYICONDATA nid;

nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = 100;
nid.uVersion = NOTIFYICON_VERSION;
nid.uCallbackMessage = WM_MYMESSAGE;
nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcscpy_s(nid.szTip, L"Tray Icon");
nid.uFlags = NIF_MESSAGE NIF_ICON NIF_TIP;

Shell_NotifyIcon(NIM_ADD, &nid);

cbSize : It indicates the size of our structure.

hWnd : It takes the handle to our window which will process the messages from our icon.

uID : This is a unique Id for our icon. Shell uses hWnd + uID to identify which icon to operate on when Shell_NotifyIcon() is invoked.

uVersion : It defines the behavior of our icon, i.e. whether it should behave like a windows 98 icon, a windows xp icon or windows Vista icon. Based on the value of this variable, certain other variables of the NOTIFYICONDATA become available to us. (refer to MSDN for more info).

uCallBackMessage : This indicates the message to be sent to the message procedure whenever a mouse event occurs on our icon.

hIcon : This stores the handle to the Icon to be used for display in the system tray. Any icon that is available to our application can be used, here I have used the system defined icon.

szTip : Here we can store a null terminated string which will be displayed near the icon, whenever the mouse is on it. The type of variable depends on your language settings, I am using the unicode version in the example.

uFlags : This variable defines whether the variables are uCallbackMessage, hIcon and szTip are valid or not. This is achieved by bit masks NIF_MESSAGE, NIF_ICON, NIF_TIP.

Once we have defined our NOTIFYICONDATA structure, we should invoke Shell_NotifyIcon() as follows.

Shell_NotifyIcon(NIM_ADD, &nid);

This will create and display our icon in system tray. As we can see Shell_NotifyIcon takes two parameters.

  1. dwMessage : This could be NIM_ADD, NIM_MODIFY or NIM_DELETE.
  2. lpdata : A pointer to our NOTIFYICONDATA variable, which defines our icon.

The last thing that we need to do is capture and process the WM_MYMESSAGE message in our message procedure. Consider a typical message handler procedure as follows.

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
         break;
    ....
    ....
    case WM_MYMESSAGE:
         switch(lParam)
         {
         case WM_LBUTTONDBLCLK:
                 MessageBox(NULL, L"Tray icon double clicked!", L"clicked", MB_OK);
                 break;
         default:
                return DefWindowProc(hWnd, msg, wParam, lParam);
         };
         break;
     .....
     .....
     default:
           return DefWindowProc(hWnd, msg, wParam, lParam);
     };
     return 0;
 }

Here you can see that we are trapping our WM_MYMESSAGE and then checking lParam to see what mouse event occured. As described in our example, we wanted to show a messagebox whenever our icon is double clicked. Thus we are processing the WM_LBUTTONDBLCLK message from the lParam variable. We can process other messages also, as per the application’s requirements. For example, we can process WM_LBUTTONUP to do something whenever a user clicks on it etc.

In this way we can create, display and interact with our System Tray Icon.

To delete the icon whenever we are done with it, for example when our program is exiting we should define the NOTIFYDATAICON to point to our icon and call Shell_NotifyIcon with NIM_DELETE message. For example, to delete the icon created above we need to define.

NOTIFYICONDATA nid;
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = 100;
Shell_NotifyIcon(NIM_DELETE, &nid);

We don’t have to define any other member of the NOTIFYICONDATA structure.

Similarly to modify the icon we should define the NOTIFYICONDATA and call Shell_NotifyIcon with NIM_MODIFY. For example to modify the icon tip.

NOTIFYICONDATA nid;
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = 100;
wcscpy_s(nid.szTip, L"Modified Tip");
nid.uFlags = NIF_TIP;
Shell_NotifyIcon(NIM_MODIFY, &nid);

We can combine NIF_TIP and NIF_ICON to modify the tip and icon together.

Well thats about it regarding the system tray icons and how to use them.

A note regarding WM_MYMESSAGE :
As you can see I defined WM_MYMESSAGE as WM_USER + 1, this is because, all the message numbers below 1024(0x0400) are reserved by Windows. If you checkout WinUser.h file, you will see that WM_USER has been defined as 0x0400 (1024), thus we can base our custom messages starting with this value.