//*********************************************************************************
//
// Title: Terminal Services Drag Drop
//
//*********************************************************************************
#define _UNICODE
#include "DDHook.h"
#include "ProcessData.h"
#include <Windowsx.h> // MapWindowRect
#include <commctrl.h>
struct TRAYDATA
{
HWND hwnd;
UINT uID;
UINT uCallbackMessage;
DWORD Reserved[2];
HICON hIcon;
};
#define DLL_EXPORT extern "C" __declspec(dllexport)
// Shared DATA
#pragma data_seg ( "SHAREDDATA" )
// this is the total number of processes this dll is currently attached to
int iInstanceCount = 0;
HWND g_hWnd = 0;
#pragma data_seg ()
#pragma comment(linker, "/section:SHAREDDATA,rws")
bool bHooked = false;
HHOOK hhook = 0;//msgs
HINSTANCE hInst = 0;
BOOL APIENTRY DllMain( HINSTANCE hinstDLL, DWORD ul_reason_for_call, LPVOID lpReserved )
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
// remember our instance handle
//OutputDebugString("DDHook dll loaded...");
hInst = hinstDLL;
++iInstanceCount;
TCHAR szMsg[256] = {0};
//wsprintf(szMsg,L"Tray Rectangle: %d-%d %d-%d",R.left,R.right,R.top,R.bottom);
wsprintfW(szMsg,L"DDHook dll loaded...,iInstanceCount: %d", iInstanceCount);
OutputDebugStringW(szMsg);
break;
}
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
{
//OutputDebugString("DDHook dll unloaded...");
--iInstanceCount;
TCHAR szMsg[256] = {0};
//wsprintf(szMsg,L"Tray Rectangle: %d-%d %d-%d",R.left,R.right,R.top,R.bottom);
wsprintfW(szMsg,L"DDHook dll unloaded...,iInstanceCount: %d", iInstanceCount);
OutputDebugStringW(szMsg);
//CloseVirtualChannel();
}
break;
}
return TRUE;
}
void QueryDragDropFileNames(HDROP hDrop)
{
// this could be used later to actually drop stuff directly onto windows in the RDP session
POINT pt = {0};
if (DragQueryPoint(hDrop,&pt))
{
TCHAR szText1[MAX_PATH] = {0};
wsprintfW(szText1,L"Dropped at pos: x[%d] y[%d]", pt.x,pt.y);
OutputDebugStringW(szText1);
}
else
{
OutputDebugStringW(L"Failed to run DragQueryPoint()");
}
UINT cFiles = DragQueryFile(hDrop, 0xFFFFFFFF/*(UINT)-1*/, NULL, 0);
TCHAR szText[MAX_PATH] = {0};
wsprintfW(szText,L"Drag/Drop %d files/directories:", cFiles);
OutputDebugStringW(szText);
for( UINT indx = 0; indx < cFiles; indx++ )
{
TCHAR szFile[MAX_PATH] = {0};
UINT cChars = DragQueryFileW(hDrop, indx, szFile, sizeof(szFile));
if (cChars > 0)
{
OutputDebugStringW(szFile);
}
}
}
HWND FindSysPagerWindow()
{
HWND hWnd = FindWindowEx(GetDesktopWindow(), 0, "Shell_TrayWnd", NULL);
if(hWnd)
{
hWnd = FindWindowEx(hWnd,NULL,"TrayNotifyWnd", NULL);
if(hWnd)
{
hWnd = FindWindowEx(hWnd,NULL,"SysPager", NULL);
}
}
return hWnd;
}
HWND FindTrayToolbarWindow()
{
HWND hWnd = FindWindow("Shell_TrayWnd", NULL);
if(hWnd)
{
hWnd = FindWindowEx(hWnd,NULL,"TrayNotifyWnd", NULL);
if(hWnd)
{
hWnd = FindWindowEx(hWnd,NULL,"SysPager", NULL);
if(hWnd)
{
hWnd = FindWindowEx(hWnd, NULL,"ToolbarWindow32", NULL);
}
}
}
return hWnd;
}
BOOL FileDroppedAtIcon(const HWND a_hWndOwner, const int a_iButtonID, const PPOINT pPoint)
{
HWND hWndTray = FindTrayToolbarWindow();
//now we have to get an ID of the parent process for system tray
DWORD dwTrayProcessID = -1;
GetWindowThreadProcessId(hWndTray, &dwTrayProcessID);
//here we get a handle to tray application process
HANDLE hTrayProc = OpenProcess(PROCESS_ALL_ACCESS, 0, dwTrayProcessID);
//now we check how many buttons is there - should be more than 0
int iButtonsCount = SendMessage(hWndTray, TB_BUTTONCOUNT, 0, 0);
//We want to get data from another process - it's not possible
//to just send messages like TB_GETBUTTON with a locally
//allocated buffer for return data. Pointer to locally allocated
//data has no usefull meaning in a context of another
//process (since Win95) - so we need
//to allocate some memory inside Tray process.
//We allocate sizeof(TBBUTTON) bytes of memory -
//because TBBUTTON is the biggest structure we will fetch.
//But this buffer will be also used to get smaller
//pieces of data like RECT structures.
LPVOID lpData = VirtualAllocEx(hTrayProc, NULL,
sizeof(TBBUTTON), MEM_COMMIT, PAGE_READWRITE);
BOOL bIconFound = FALSE;
for(int iButton=0; iButton<iButtonsCount; iButton++)
{
//first let's read TBUTTON information
//about each button in a task bar of tray
DWORD dwBytesRead = -1;
TBBUTTON buttonData;
SendMessage(hWndTray, TB_GETBUTTON, iButton, (LPARAM)lpData);
//we filled lpData with details of iButton icon of toolbar
//- now let's copy this data from tray application
//back to our process
ReadProcessMemory(hTrayProc, lpData, &buttonData, sizeof(TBBUTTON), &dwBytesRead);
//let's read extra data of each button:
//there will be a HWND of the window that
//created an icon and icon ID
DWORD dwExtraData[2] = { 0,0 };
ReadProcessMemory(hTrayProc, (LPVOID)buttonData.dwData,dwExtraData, sizeof(dwExtraData), &dwBytesRead);
HWND hWndOfIconOwner = (HWND) dwExtraData[0];
int iIconId = (int) dwExtraData[1];
if(hWndOfIconOwner != a_hWndOwner || iIconId != a_iButtonID)
{
continue;
}
//we found our icon - in WinXP it could be hidden - let's check it:
if( buttonData.fsState & TBSTATE_HIDDEN )
{
break;
}
//now just ask a tool bar of rectangle of our icon
RECT rcPosition = {0,0};
SendMessage(hWndTray, TB_GETITEMRECT, iButton, (LPARAM)lpData);
// ReadProcessMemory(hTrayProc, lpData, lprcPosition/*&rcPosition*/, sizeof(RECT), &dwBytesRead);
ReadProcessMemory(hTrayProc, lpData, &rcPosition, sizeof(RECT), &dwBytesRead);
MapWindowRect(hWndTray,NULL,&rcPosition);
if (pPoint->x > rcPosition.left && pPoint->x < rcPosition.right &&
pPoint->y > rcPosition.top && pPoint->y < rcPosition.bottom)
{
OutputDebugString("Stuff dropped at our icon...!!!");
bIconFound = TRUE;
break;
}
break;
}
VirtualFreeEx(hTrayProc, lpData, NULL, MEM_RELEASE);
CloseHandle(hTrayProc);
return bIconFound;
}
LRESULT CALLBACK GetMsgProc(UINT nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
MSG* msg = (MSG*)lParam;
HWND hWnd = msg->hwnd;
if (msg->message == WM_DROPFILES)
{
OutputDebugString("WM_DROPFILES received");
TCHAR szText1[MAX_PATH] = {0};
wsprintfW(szText1,L"nCode: [%d] wParam: [%d] lParam: [%d]",nCode,wParam,lParam);
OutputDebugStringW(szText1);
RECT R_DROP = {0};
GetWindowRect( msg->hwnd, &R_DROP );
TCHAR szMsg[256] = {0};
wsprintfW(szMsg,L"DropRectangle: %d-%d %d-%d",R_DROP.left,R_DROP.right,R_DROP.top,R_DROP.bottom);
OutputDebugStringW(szMsg);
wsprintfW(szMsg,L"DropPoint: x:%d y:%d",msg->pt.x,msg->pt.y);
OutputDebugStringW(szMsg);
wsprintfW(szMsg,L"nCode: [%d] wParam: [%d] lParam: [%d]",msg->time,msg->wParam,msg->lParam);
OutputDebugStringW(szMsg);
HWND hSysPager = FindSysPagerWindow();
if (hSysPager != NULL)
{
RECT R2 = {0};
GetWindowRect( hSysPager, &R2 );
// check if the drop area is the same as the tray area...
if (R_DROP.left == R2.left &&
R_DROP.right == R2.right &&
R_DROP.bottom == R2.bottom &&
R_DROP.top == R2.top)
{
HWND hToolbarWindow32 = FindTrayToolbarWindow();
if (hToolbarWindow32)
{
DWORD dwTrayPid = 0;
GetWindowThreadProcessId(hToolbarWindow32, &dwTrayPid);
int count = (int)SendMessage(hToolbarWindow32, TB_BUTTONCOUNT, 0, 0);
CProcessData<TBBUTTON> data(dwTrayPid);
TBBUTTON tb = {0};
TRAYDATA tray = {0};
for(int i=0; i<count; i++)
{
SendMessage(hToolbarWindow32, TB_GETBUTTON, i, (LPARAM)data.GetData());
data.ReadData(&tb);
data.ReadData<TRAYDATA>(&tray,(LPCVOID)tb.dwData);
if (tray.hwnd == g_hWnd && FileDroppedAtIcon(g_hWnd,i,&msg->pt))
{
SendMessage(g_hWnd,msg->message,msg->wParam,msg->lParam);
}
}
}
}
}
}
}
else
{
//return CallNextHookEx(hhook, nCode, wParam, lParam);
}
return CallNextHookEx(hhook, nCode, wParam, lParam);
}
DLL_EXPORT void SetMsgHook(HWND hWnd)
{
if (!bHooked)
{
hhook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, hInst, (DWORD)NULL);
bHooked = true;
g_hWnd = hWnd;
}
}
DLL_EXPORT void RemoveMsgHook(void)
{
if (bHooked)
{
UnhookWindowsHookEx(hhook);
bHooked = false;
g_hWnd = NULL;
}
}
DLL_EXPORT int GetInstanceCount()
{
return iInstanceCount;
}