I made a way to support dropping on systray notification icons without the use of an external DLL. The trick is to create a transparent child window to the taskbar and place it above the trayicon.
It must be HWND_TOP while dragging and HWND_BOTTOM during mouse actions because otherwise for instance tooltips don't work. I use a timer to fallback to HWND_TOP after a mouse action.
Not all the code is placed here, but the missing parts are evident.
BOOL _TrayTools_CreateTrayDragDropWnd(TSysTray *in_TrayInfo, TSysTrayEntry *in_Entry)
{
VOID *lv_CP[2];
RECT lv_Rect;
HWND lv_hAnchor;
HWND lv_hNotiTB;
WNDCLASS lv_WndClass;
if (in_Entry->DragDrop.hDropWnd && IsWindow(in_Entry->DragDrop.hDropWnd))
return TRUE;
lv_hNotiTB = Shell_GetSysTaskbarNotifyWindowTB();
lv_hAnchor = Shell_GetSysTaskbarNotifyWindow();
if (!lv_hNotiTB || !lv_hAnchor)
return NULL;
if (!TrayTools_GetSysTrayIconRect(in_TrayInfo, in_Entry->Def.TrayID, &lv_Rect))
return FALSE;
if (!GetClassInfo(gv_AppInfo.hInstance, CLASSNAME_TRAYDRAGDROP, &lv_WndClass))
{
memset(&lv_WndClass, 0, sizeof(WNDCLASS));
lv_WndClass.style = CS_DBLCLKS;
lv_WndClass.lpfnWndProc = _TrayTools_TrayDragDropWndProc;
lv_WndClass.hInstance = gv_AppInfo.hInstance;
lv_WndClass.lpszClassName = CLASSNAME_TRAYDRAGDROP;
lv_WndClass.cbWndExtra = TRAYDRAGDROP_GWLP_LAST;
lv_WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClass(&lv_WndClass);
}
in_Entry->DragDrop.hAnchor = lv_hAnchor;
in_Entry->DragDrop.hNotifyTB = lv_hNotiTB;
lv_CP[0] = in_TrayInfo;
lv_CP[1] = in_Entry;
ScreenToClientRect(in_Entry->DragDrop.hAnchor, &lv_Rect);
in_Entry->DragDrop.hDropWnd = CreateWindowEx(
WS_EX_TRANSPARENT | WS_EX_NOACTIVATE,
CLASSNAME_TRAYDRAGDROP, NULL,
WS_VISIBLE | WS_CHILD,
lv_Rect.left, lv_Rect.top,
lv_Rect.right - lv_Rect.left,
lv_Rect.bottom - lv_Rect.top,
in_Entry->DragDrop.hAnchor, NULL, gv_AppInfo.hInstance, lv_CP);
if (!in_Entry->DragDrop.hDropWnd)
return FALSE;
SetWindowPos(
in_Entry->DragDrop.hDropWnd, HWND_TOP, 0,0,0,0,
SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
return TRUE;
}
BOOL _TrayTools_DoneTrayDragDropWnd(TSysTrayEntry *in_Entry)
{
if (in_Entry->DragDrop.hDropWnd)
{
DestroyWindow(in_Entry->DragDrop.hDropWnd);
in_Entry->DragDrop.hDropWnd = NULL;
}
return TRUE;
}
LRESULT CALLBACK _TrayTools_TrayDragDropWndProc
(
HWND in_hWnd,
UINT in_uMsg,
WPARAM in_wParam,
LPARAM in_lParam
)
{
UINT_PTR *lv_CP;
RECT lv_Rect1;
RECT lv_Rect2;
TSysTray *lv_TrayInfo;
TSysTrayEntry *lv_Entry;
if (in_uMsg == WM_CREATE)
{
if ((lv_CP = (UINT_PTR*)((CREATESTRUCT *)in_lParam)->lpCreateParams) == NULL)
return -1;
SetWindowLongAsPtr(in_hWnd, TRAYDRAGDROP_GWLP_TRAYINFO, lv_CP[0]);
SetWindowLongAsPtr(in_hWnd, TRAYDRAGDROP_GWLP_TRAYENTRY, lv_CP[1]);
lv_TrayInfo = (TSysTray*) lv_CP[0];
lv_Entry = (TSysTrayEntry*)lv_CP[1];
}
else
{
lv_TrayInfo = (TSysTray*) GetWindowLongAsPtr(in_hWnd, TRAYDRAGDROP_GWLP_TRAYINFO);
lv_Entry = (TSysTrayEntry*)GetWindowLongAsPtr(in_hWnd, TRAYDRAGDROP_GWLP_TRAYENTRY);
}
switch (in_uMsg)
{
case WM_CREATE:
{
ShellDD_RegisterWindow(in_hWnd);
break;
}
case WM_NCDESTROY:
{
ShellDD_UnregisterWindow(in_hWnd);
if (lv_Entry->DragDrop.TimerID)
KillTimer(in_hWnd, lv_Entry->DragDrop.TimerID);
lv_Entry->DragDrop.TimerID = 0;
lv_Entry->DragDrop.hDropWnd = NULL;
break;
}
}
if (lv_TrayInfo && lv_Entry)
{
switch (in_uMsg)
{
case WM_MOUSEMOVE:
case WM_LBUTTONUP:
case WM_LBUTTONDOWN:
case WM_LBUTTONDBLCLK:
case WM_RBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONDBLCLK:
case WM_NCHITTEST:
{
SetWindowPos(in_hWnd, HWND_BOTTOM, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
lv_Entry->DragDrop.LastMouseTime = GetTickCount();
if (!lv_Entry->DragDrop.TimerID)
lv_Entry->DragDrop.TimerID = SetTimer(in_hWnd, 987, 3000, 0);
ClientToClientPoint16(in_hWnd, lv_Entry->DragDrop.hNotifyTB, (POINT16*)&in_lParam);
return SendMessage(lv_Entry->DragDrop.hNotifyTB, in_uMsg, in_wParam, in_lParam);
}
case WM_TIMER:
{
if (lv_Entry->DragDrop.TimerID == in_wParam)
{
if (GetTickCount() - lv_Entry->DragDrop.LastMouseTime > 1000)
{
SetWindowPos(in_hWnd, HWND_TOP, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
KillTimer(in_hWnd, lv_Entry->DragDrop.TimerID);
lv_Entry->DragDrop.TimerID = 0;
}
}
break;
}
case WM_SETCURSOR:
return SendMessage(lv_Entry->DragDrop.hNotifyTB, in_uMsg, in_wParam, in_lParam);
case WM_PAINT:
{
if (TrayTools_GetSysTrayIconRect(lv_TrayInfo, lv_Entry->Def.TrayID, &lv_Rect1))
{
GetWindowRect(in_hWnd, &lv_Rect2);
if (lv_Rect1.left != lv_Rect2.left ||
lv_Rect1.top != lv_Rect2.top ||
lv_Rect1.right != lv_Rect2.right ||
lv_Rect1.bottom != lv_Rect2.bottom)
{
ScreenToClientRect(lv_Entry->DragDrop.hAnchor, &lv_Rect1);
SetWindowPos(
lv_Entry->DragDrop.hDropWnd, HWND_TOP,
lv_Rect1.left,
lv_Rect1.top,
lv_Rect1.right - lv_Rect1.left,
lv_Rect1.bottom - lv_Rect1.top,
SWP_NOACTIVATE);
}
}
break;
}
case WM_DROPFILES:
{
if (lv_Entry->Def.DropFileProc)
lv_Entry->Def.DropFileProc((HDROP)in_wParam);
break;
}
}
}
return DefWindowProc(in_hWnd, in_uMsg, in_wParam, in_lParam);
}
|