Commit 4c2c3eff authored by Alexandre Julliard's avatar Alexandre Julliard

shell32: Pack the systray data structure to allow crossing 32/64 boundaries.

parent 3cd9f971
...@@ -38,6 +38,30 @@ WINE_DEFAULT_DEBUG_CHANNEL(systray); ...@@ -38,6 +38,30 @@ WINE_DEFAULT_DEBUG_CHANNEL(systray);
static const WCHAR classname[] = /* Shell_TrayWnd */ {'S','h','e','l','l','_','T','r','a','y','W','n','d','\0'}; static const WCHAR classname[] = /* Shell_TrayWnd */ {'S','h','e','l','l','_','T','r','a','y','W','n','d','\0'};
struct notify_data /* platform-independent format for NOTIFYICONDATA */
{
LONG hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
WCHAR szTip[128];
DWORD dwState;
DWORD dwStateMask;
WCHAR szInfo[256];
union {
UINT uTimeout;
UINT uVersion;
} u;
WCHAR szInfoTitle[64];
DWORD dwInfoFlags;
GUID guidItem;
/* data for the icon bitmap */
UINT width;
UINT height;
UINT planes;
UINT bpp;
};
/************************************************************************* /*************************************************************************
* Shell_NotifyIcon [SHELL32.296] * Shell_NotifyIcon [SHELL32.296]
* Shell_NotifyIconA [SHELL32.297] * Shell_NotifyIconA [SHELL32.297]
...@@ -103,7 +127,8 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid) ...@@ -103,7 +127,8 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid)
{ {
HWND tray; HWND tray;
COPYDATASTRUCT cds; COPYDATASTRUCT cds;
char *buffer = NULL; struct notify_data data_buffer;
struct notify_data *data = &data_buffer;
BOOL ret; BOOL ret;
TRACE("dwMessage = %d, nid->cbSize=%d\n", dwMessage, nid->cbSize); TRACE("dwMessage = %d, nid->cbSize=%d\n", dwMessage, nid->cbSize);
...@@ -127,6 +152,8 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid) ...@@ -127,6 +152,8 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid)
if (!tray) return FALSE; if (!tray) return FALSE;
cds.dwData = dwMessage; cds.dwData = dwMessage;
cds.cbData = sizeof(*data);
memset( data, 0, sizeof(*data) );
/* FIXME: if statement only needed because we don't support interprocess /* FIXME: if statement only needed because we don't support interprocess
* icon handles */ * icon handles */
...@@ -137,6 +164,7 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid) ...@@ -137,6 +164,7 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid)
BITMAP bmColour; BITMAP bmColour;
LONG cbMaskBits; LONG cbMaskBits;
LONG cbColourBits; LONG cbColourBits;
char *buffer;
if (!GetIconInfo(nid->hIcon, &iconinfo)) if (!GetIconInfo(nid->hIcon, &iconinfo))
goto noicon; goto noicon;
...@@ -149,9 +177,9 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid) ...@@ -149,9 +177,9 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid)
goto noicon; goto noicon;
} }
cbMaskBits = (bmMask.bmPlanes * bmMask.bmWidth * bmMask.bmHeight * bmMask.bmBitsPixel) / 8; cbMaskBits = (bmMask.bmPlanes * bmMask.bmWidth * bmMask.bmHeight * bmMask.bmBitsPixel + 15) / 16 * 2;
cbColourBits = (bmColour.bmPlanes * bmColour.bmWidth * bmColour.bmHeight * bmColour.bmBitsPixel) / 8; cbColourBits = (bmColour.bmPlanes * bmColour.bmWidth * bmColour.bmHeight * bmColour.bmBitsPixel + 15) / 16 * 2;
cds.cbData = nid->cbSize + 2*sizeof(BITMAP) + cbMaskBits + cbColourBits; cds.cbData = sizeof(*data) + cbMaskBits + cbColourBits;
buffer = HeapAlloc(GetProcessHeap(), 0, cds.cbData); buffer = HeapAlloc(GetProcessHeap(), 0, cds.cbData);
if (!buffer) if (!buffer)
{ {
...@@ -159,38 +187,47 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid) ...@@ -159,38 +187,47 @@ BOOL WINAPI Shell_NotifyIconW(DWORD dwMessage, PNOTIFYICONDATAW nid)
DeleteObject(iconinfo.hbmColor); DeleteObject(iconinfo.hbmColor);
return FALSE; return FALSE;
} }
cds.lpData = buffer;
data = (struct notify_data *)buffer;
memcpy(buffer, nid, nid->cbSize); memset( data, 0, sizeof(*data) );
buffer += nid->cbSize; data->width = bmColour.bmWidth;
memcpy(buffer, &bmMask, sizeof(bmMask)); data->height = bmColour.bmHeight;
buffer += sizeof(bmMask); data->planes = bmColour.bmPlanes;
memcpy(buffer, &bmColour, sizeof(bmColour)); data->bpp = bmColour.bmBitsPixel;
buffer += sizeof(bmColour); buffer += sizeof(*data);
GetBitmapBits(iconinfo.hbmMask, cbMaskBits, buffer); GetBitmapBits(iconinfo.hbmMask, cbMaskBits, buffer);
buffer += cbMaskBits; buffer += cbMaskBits;
GetBitmapBits(iconinfo.hbmColor, cbColourBits, buffer); GetBitmapBits(iconinfo.hbmColor, cbColourBits, buffer);
/* Reset pointer to allocated block so it can be freed later.
* Note that cds.lpData cannot be passed to HeapFree since it
* points to nid when no icon info is found. */
buffer = cds.lpData;
DeleteObject(iconinfo.hbmMask); DeleteObject(iconinfo.hbmMask);
DeleteObject(iconinfo.hbmColor); DeleteObject(iconinfo.hbmColor);
} }
else
{
noicon: noicon:
cds.cbData = nid->cbSize; data->hWnd = HandleToLong( nid->hWnd );
cds.lpData = nid; data->uID = nid->uID;
data->uFlags = nid->uFlags;
if (data->uFlags & NIF_MESSAGE)
data->uCallbackMessage = nid->uCallbackMessage;
if (data->uFlags & NIF_TIP)
lstrcpynW( data->szTip, nid->szTip, sizeof(data->szTip)/sizeof(WCHAR) );
if (data->uFlags & NIF_STATE)
{
data->dwState = nid->dwState;
data->dwStateMask = nid->dwStateMask;
}
if (data->uFlags & NIF_INFO)
{
lstrcpynW( data->szInfo, nid->szInfo, sizeof(data->szInfo)/sizeof(WCHAR) );
lstrcpynW( data->szInfoTitle, nid->szInfoTitle, sizeof(data->szInfoTitle)/sizeof(WCHAR) );
data->u.uTimeout = nid->u.uTimeout;
data->dwInfoFlags = nid->dwInfoFlags;
} }
if (data->uFlags & NIF_GUID)
data->guidItem = nid->guidItem;
/* FIXME: balloon icon */
cds.lpData = data;
ret = SendMessageW(tray, WM_COPYDATA, (WPARAM)nid->hWnd, (LPARAM)&cds); ret = SendMessageW(tray, WM_COPYDATA, (WPARAM)nid->hWnd, (LPARAM)&cds);
if (data != &data_buffer) HeapFree( GetProcessHeap(), 0, data );
/* FIXME: if statement only needed because we don't support interprocess
* icon handles */
HeapFree(GetProcessHeap(), 0, buffer);
return ret; return ret;
} }
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <assert.h> #include <assert.h>
#define UNICODE #define UNICODE
#define NONAMELESSUNION
#define _WIN32_IE 0x500 #define _WIN32_IE 0x500
#include <windows.h> #include <windows.h>
#include <commctrl.h> #include <commctrl.h>
...@@ -35,6 +36,30 @@ WINE_DEFAULT_DEBUG_CHANNEL(systray); ...@@ -35,6 +36,30 @@ WINE_DEFAULT_DEBUG_CHANNEL(systray);
#define IS_OPTION_FALSE(ch) \ #define IS_OPTION_FALSE(ch) \
((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0') ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
struct notify_data /* platform-independent format for NOTIFYICONDATA */
{
LONG hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
WCHAR szTip[128];
DWORD dwState;
DWORD dwStateMask;
WCHAR szInfo[256];
union {
UINT uTimeout;
UINT uVersion;
} u;
WCHAR szInfoTitle[64];
DWORD dwInfoFlags;
GUID guidItem;
/* data for the icon bitmap */
UINT width;
UINT height;
UINT planes;
UINT bpp;
};
static int (CDECL *wine_notify_icon)(DWORD,NOTIFYICONDATAW *); static int (CDECL *wine_notify_icon)(DWORD,NOTIFYICONDATAW *);
/* an individual systray icon, unpacked from the NOTIFYICONDATA and always in unicode */ /* an individual systray icon, unpacked from the NOTIFYICONDATA and always in unicode */
...@@ -346,52 +371,46 @@ static void cleanup_destroyed_windows(void) ...@@ -346,52 +371,46 @@ static void cleanup_destroyed_windows(void)
static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds) static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds)
{ {
struct icon *icon = NULL; struct icon *icon = NULL;
const struct notify_data *data;
NOTIFYICONDATAW nid; NOTIFYICONDATAW nid;
DWORD cbSize;
int ret = FALSE; int ret = FALSE;
if (cds->cbData < NOTIFYICONDATAW_V1_SIZE) return FALSE; if (cds->cbData < sizeof(*data)) return FALSE;
cbSize = ((PNOTIFYICONDATAW)cds->lpData)->cbSize; data = cds->lpData;
if (cbSize < NOTIFYICONDATAW_V1_SIZE) return FALSE;
nid.cbSize = sizeof(nid);
ZeroMemory(&nid, sizeof(nid)); nid.hWnd = LongToHandle( data->hWnd );
memcpy(&nid, cds->lpData, min(sizeof(nid), cbSize)); nid.uID = data->uID;
nid.uFlags = data->uFlags;
nid.uCallbackMessage = data->uCallbackMessage;
nid.hIcon = 0;
nid.dwState = data->dwState;
nid.dwStateMask = data->dwStateMask;
nid.u.uTimeout = data->u.uTimeout;
nid.dwInfoFlags = data->dwInfoFlags;
nid.guidItem = data->guidItem;
lstrcpyW( nid.szTip, data->szTip );
lstrcpyW( nid.szInfo, data->szInfo );
lstrcpyW( nid.szInfoTitle, data->szInfoTitle );
nid.hBalloonIcon = 0;
/* FIXME: if statement only needed because we don't support interprocess /* FIXME: if statement only needed because we don't support interprocess
* icon handles */ * icon handles */
if ((nid.uFlags & NIF_ICON) && (cds->cbData >= nid.cbSize + 2 * sizeof(BITMAP))) if ((nid.uFlags & NIF_ICON) && cds->cbData > sizeof(*data))
{ {
LONG cbMaskBits; LONG cbMaskBits;
LONG cbColourBits; LONG cbColourBits;
BITMAP bmMask; const char *buffer = (const char *)(data + 1);
BITMAP bmColour;
const char *buffer = cds->lpData;
buffer += nid.cbSize; cbMaskBits = (data->width * data->height + 15) / 16 * 2;
cbColourBits = (data->planes * data->width * data->height * data->bpp + 15) / 16 * 2;
memcpy(&bmMask, buffer, sizeof(bmMask)); if (cds->cbData < sizeof(*data) + cbMaskBits + cbColourBits)
buffer += sizeof(bmMask);
memcpy(&bmColour, buffer, sizeof(bmColour));
buffer += sizeof(bmColour);
cbMaskBits = (bmMask.bmPlanes * bmMask.bmWidth * bmMask.bmHeight * bmMask.bmBitsPixel) / 8;
cbColourBits = (bmColour.bmPlanes * bmColour.bmWidth * bmColour.bmHeight * bmColour.bmBitsPixel) / 8;
if (cds->cbData < nid.cbSize + 2 * sizeof(BITMAP) + cbMaskBits + cbColourBits)
{ {
WINE_ERR("buffer underflow\n"); WINE_ERR("buffer underflow\n");
return FALSE; return FALSE;
} }
nid.hIcon = CreateIcon(NULL, data->width, data->height, data->planes, data->bpp,
/* sanity check */
if ((bmColour.bmWidth != bmMask.bmWidth) || (bmColour.bmHeight != bmMask.bmHeight))
{
WINE_ERR("colour and mask bitmaps aren't consistent\n");
return FALSE;
}
nid.hIcon = CreateIcon(NULL, bmColour.bmWidth, bmColour.bmHeight,
bmColour.bmPlanes, bmColour.bmBitsPixel,
buffer, buffer + cbMaskBits); buffer, buffer + cbMaskBits);
} }
...@@ -400,7 +419,7 @@ static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds) ...@@ -400,7 +419,7 @@ static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds)
{ {
if (wine_notify_icon && ((ret = wine_notify_icon( cds->dwData, &nid )) != -1)) if (wine_notify_icon && ((ret = wine_notify_icon( cds->dwData, &nid )) != -1))
{ {
if (nid.uFlags & NIF_ICON) DestroyIcon( nid.hIcon ); if (nid.hIcon) DestroyIcon( nid.hIcon );
return ret; return ret;
} }
ret = FALSE; ret = FALSE;
...@@ -422,11 +441,7 @@ static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds) ...@@ -422,11 +441,7 @@ static BOOL handle_incoming(HWND hwndSource, COPYDATASTRUCT *cds)
break; break;
} }
/* FIXME: if statement only needed because we don't support interprocess if (nid.hIcon) DestroyIcon( nid.hIcon );
* icon handles */
if (nid.uFlags & NIF_ICON)
DestroyIcon(nid.hIcon);
return ret; return ret;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment