views:

906

answers:

2

I am reading the NOTIFYICONDATA documentation in MSDN.

It says the NOTIFYICONDATA structure has a cbSize member should be set to the size of the structure, but NOTIFYICONDATA structure's size has different size in every Shell32.dll, so you should get the Shell32.dll version before setting cbSize.

The following quotes from MSDN:


If it is version 5.0 or later, initialize the cbSize member as follows.

nid.cbSize = sizeof(NOTIFYICONDATA);

Setting cbSize to this value enables all the version 5.0 and 6.0 enhancements. For earlier versions, the size of the pre-6.0 structure is given by the NOTIFYICONDATA_V2_SIZE constant and the pre-5.0 structure is given by the NOTIFYICONDATA_V1_SIZE constant. Initialize the cbSize member as follows. nid.cbSize = NOTIFYICONDATA_V2_SIZE;

Using this value for cbSize will allow your application to use NOTIFYICONDATA with earlier Shell32.dll versions, although without the version 6.0 enhancements.


I found it a bit of vague, because 'sizeof(NOTIFYICONDATA)' has different value in Win98 (using Shell32.dll version 4.x), Win2K (version 5.0) and WinXP (version 6.0). How could it 'enable all version 5.0 and 6.0 enhancements'?

So I looked for the definition of NOTIFYICONDATA_V1_SIZE (source code as below), I see:

NOTIFYICONDATA_V1_SIZE is for Win 2K (doesn't include 2K)

NOTIFYICONDATA_V2_SIZE is for Win XP

NOTIFYICONDATA_V3_SIZE is for Vista

(not sure if I am right)

It's completely different from what MSDN says? and none for Win2K?

So, I am totally confused right now. How should I set the cbSize member according to Shell32.dll version?

//= = = = = = = = ShellAPI.h = = = = = = = =

typedef struct _NOTIFYICONDATAA {
    DWORD cbSize;
    HWND hWnd;
    UINT uID;
    UINT uFlags;
    UINT uCallbackMessage;
    HICON hIcon;
#if (NTDDI_VERSION < NTDDI_WIN2K)
    CHAR   szTip[64];
#endif
#if (NTDDI_VERSION >= NTDDI_WIN2K)
    CHAR   szTip[128];
    DWORD dwState;
    DWORD dwStateMask;
    CHAR   szInfo[256];
    union {
        UINT  uTimeout;
        UINT  uVersion;  // used with NIM_SETVERSION, values 0, 3 and 4
    } DUMMYUNIONNAME;
    CHAR   szInfoTitle[64];
    DWORD dwInfoFlags;
#endif
#if (NTDDI_VERSION >= NTDDI_WINXP)
    GUID guidItem;
#endif
#if (NTDDI_VERSION >= NTDDI_VISTA)
    HICON hBalloonIcon;
#endif
} NOTIFYICONDATAA, *PNOTIFYICONDATAA;


typedef struct _NOTIFYICONDATAW {
    DWORD cbSize;
    HWND hWnd;
    UINT uID;
    UINT uFlags;
    UINT uCallbackMessage;
    HICON hIcon;
#if (NTDDI_VERSION < NTDDI_WIN2K)
    WCHAR  szTip[64];
#endif
#if (NTDDI_VERSION >= NTDDI_WIN2K)
    WCHAR  szTip[128];
    DWORD dwState;
    DWORD dwStateMask;
    WCHAR  szInfo[256];
    union {
        UINT  uTimeout;
        UINT  uVersion;  // used with NIM_SETVERSION, values 0, 3 and 4
    } DUMMYUNIONNAME;
    WCHAR  szInfoTitle[64];
    DWORD dwInfoFlags;
#endif
#if (NTDDI_VERSION >= NTDDI_WINXP)
    GUID guidItem;
#endif
#if (NTDDI_VERSION >= NTDDI_VISTA)
    HICON hBalloonIcon;
#endif
} NOTIFYICONDATAW, *PNOTIFYICONDATAW;


#define NOTIFYICONDATAA_V1_SIZE     FIELD_OFFSET(NOTIFYICONDATAA, szTip[64])
#define NOTIFYICONDATAW_V1_SIZE     FIELD_OFFSET(NOTIFYICONDATAW, szTip[64])
#ifdef UNICODE
#define NOTIFYICONDATA_V1_SIZE      NOTIFYICONDATAW_V1_SIZE
#else
#define NOTIFYICONDATA_V1_SIZE      NOTIFYICONDATAA_V1_SIZE
#endif


#define NOTIFYICONDATAA_V2_SIZE     FIELD_OFFSET(NOTIFYICONDATAA, guidItem)
#define NOTIFYICONDATAW_V2_SIZE     FIELD_OFFSET(NOTIFYICONDATAW, guidItem)
#ifdef UNICODE
#define NOTIFYICONDATA_V2_SIZE      NOTIFYICONDATAW_V2_SIZE
#else
#define NOTIFYICONDATA_V2_SIZE      NOTIFYICONDATAA_V2_SIZE
#endif


#define NOTIFYICONDATAA_V3_SIZE     FIELD_OFFSET(NOTIFYICONDATAA, hBalloonIcon)
#define NOTIFYICONDATAW_V3_SIZE     FIELD_OFFSET(NOTIFYICONDATAW, hBalloonIcon)
#ifdef UNICODE
#define NOTIFYICONDATA_V3_SIZE      NOTIFYICONDATAW_V3_SIZE
#else
#define NOTIFYICONDATA_V3_SIZE      NOTIFYICONDATAA_V3_SIZE
#endif

(Seems like the code doesn't look good on the web site, but it from ShellAPI.h, all the same)

+1  A: 

It depends on the lowest Windows version you compile for. You don't set the size dynamically. You set the size according to the lowest version of Windows you support.

__grover
+1  A: 

Which features are available through platform sdk headers are controlled by _WIN32_WINNT, which should be defined to the lower version of the operating system you are targeting.

From http://msdn.microsoft.com/en-us/library/6sehtctf.aspx the correct values are:

0x0500 for Windows 2000 operating system, 0x0501 for Windows XP, 0x0502 for Windows Server 2003, and 0x0600 for Windows Vista.

So NOTIFYICONDATA_V1_SIZE refer to any version lower than 2K, NOTIFYICONDATA_V2_SIZE to 2K, NOTIFYICONDATA_V3_SIZE to XP and none to Vista (in this case you can use sizeof(NOTIFYICONDATA)).

If you compile your project with _WIN32_WINNT set to the latest version, and detect which version of shell.dll you are running on runtime you can set .cbSize to the correct size, the rest of the fields will be ignored.

Something like this should work:

NOTIFYICONDATA notify;
ZeroMemory(&notify, sizeof(notify)); 
if(version >= VISTA) {
  notify.cbSize = sizeof(NOTIFYICONDATA);
}
else if(version >= XP) {
  notify.cbSize = NOTIFYICONDATA_V3_SIZE;
}
else if(version >= 2K) {
  notify.cbSize = NOTIFYICONDATA_V2_SIZE;
}
else {
  notify.cbSize = NOTIFYICONDATA_V1_SIZE;
}
Ismael