Link to home
Start Free TrialLog in
Avatar of eppsman
eppsman

asked on

System Tray Enumeration

Is there a way to enumerate all the icons on the system tray? I would like to be able to find out the IDs for all of the icons on the tray, but there doesn't appear to be an API to do it.

Thanks in advance.
Avatar of alexo
alexo
Flag of Antarctica image

There isn't any documented way of doing it.

However, see if these can help:
    http://www.dejanews.com/getdoc.xp?AN=217891054
    http://www.dejanews.com/getdoc.xp?AN=329990694

Avatar of eppsman
eppsman

ASKER

Thanks, that did give me an idea for a starting point. I've decided to try to tackle the problem from a different angle. I was able to force a DLL that I wrote into explorer's address space, and subclass the system tray. I can now see any WM_COPYDATA messages that are sent via Shell_NotifyIcon(). The problem is, when I go to examine the data as a NOTIFYICONDATA structure, all I can get is garbage that holds the same value every time - even in different Windows sessions. I disassembled Shell_NotifyIcon(), and it looks like it fudges with the NOTIFYICONDATA structure before sending the WM_COPYDATA message. Unfortunately, I am not fluent enough in assembly to be able to figure out what Shell_NotifyIcon() is doing. Does anybody know what is going on?

Thanks in advance.
Sorry, no idea.
Avatar of eppsman

ASKER

Adjusted points to 400
Avatar of eppsman

ASKER

Adjusted points to 1000
eppsman, the cost of you Q is very interesting, so may be I can help you.
At first, what exactly do you want:
   1) Hook to the explorer at boot time and intercept icon calls to save icon info. It seems that this is more easy than 2)
or,
   2) Run your program at any time to enumerate icon (this may be impossible at all, at least, without 1)

Next, I'm fluent in asm, so you can post to me asm code along with information you discovered (WM_COPYDATA, and the source to sublassing tray window). My email is nick@rtzi.ru.
It can take about 2-3 day to see what can be done.
 
I've made a little investigation into the Shell_NotifyIcon code.
I can offer to you (for grade A) following solution (w/source code):

  1)Hook to the explorer
  2)After hooking, you will be able to intercept the all calls to the  Shell_NotifyIcon.

  If you agree, post a comment.
  Also, to save time, you may post to me the code to sublass the system tray (see address in comments above).


Avatar of eppsman

ASKER

Nick,

Sounds good! I'll send you my code for subclassing when I get home later today.
ASKER CERTIFIED SOLUTION
Avatar of NickRepin
NickRepin

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
// Source code for Shell_NotifyIcon - Windows 95
//

#include <windows.h>
#include <commctrl.h>
#include <iostream.h>
#include <stdlib.h>

struct MsgDataT {
   DWORD magicN;
   DWORD msg;
   NOTIFYICONDATA d;
};
#define MAGICN 0x34753423
#define NOTIFY_ICON_CALL 1

//-----------------------------------------
WINSHELLAPI BOOL WINAPI _Shell_NotifyIcon(DWORD dwMessage,
   PNOTIFYICONDATA pnid)
{
   HWND tray=FindWindow("Shell_TrayWnd",0);
   if(!tray) return 0;
   MsgDataT data;
   data.magicN=MAGICN;
   data.msg=dwMessage;
   data.d=*pnid;
   data.d.uFlags&=7;

   COPYDATASTRUCT cd;
   cd.dwData=NOTIFY_ICON_CALL;
   cd.cbData=sizeof(MsgDataT);
   cd.lpData=&data;

   return SendMessage(tray,WM_COPYDATA,WPARAM(pnid->hWnd),LPARAM(&cd));
}

I've tired to wait while exeprts-exchange processes my comments.
So all of the code (4 files) is here
**********************************************************************
**********************************************************************
// Source code for Shell_NotifyIcon - Windows 95
//

#include <windows.h>
#include <commctrl.h>
#include <iostream.h>
#include <stdlib.h>

struct MsgDataT {
   DWORD magicN;
   DWORD msg;
   NOTIFYICONDATA d;
};
#define MAGICN 0x34753423
#define NOTIFY_ICON_CALL 1

//-----------------------------------------
WINSHELLAPI BOOL WINAPI _Shell_NotifyIcon(DWORD dwMessage,
   PNOTIFYICONDATA pnid)
{
   HWND tray=FindWindow("Shell_TrayWnd",0);
   if(!tray) return 0;
   MsgDataT data;
   data.magicN=MAGICN;
   data.msg=dwMessage;
   data.d=*pnid;
   data.d.uFlags&=7;

   COPYDATASTRUCT cd;
   cd.dwData=NOTIFY_ICON_CALL;
   cd.cbData=sizeof(MsgDataT);
   cd.lpData=&data;

   return SendMessage(tray,WM_COPYDATA,WPARAM(pnid->hWnd),LPARAM(&cd));
}
**********************************************************************
**********************************************************************
// Source code for Shell_NotifyIcon - Windows NT
//

#include <windows.h>
#include <commctrl.h>
#include <iostream.h>
#include <stdlib.h>

struct MsgDataT {
   DWORD magicN;
   DWORD msg;
   NOTIFYICONDATAW d;
};
#define MAGICN 0x34753423;
#define NOTIFY_ICON_CALL 1

//-----------------------------------------
WINSHELLAPI BOOL WINAPI _Shell_NotifyIconW(DWORD dwMessage,
   PNOTIFYICONDATAW pnid)
{
   wchar_t* clsName=L"Shell_TrayWnd";
   HWND tray=FindWindowW(clsName,0);
   if(!tray) return 0;
   MsgDataT data;
   data.magicN=MAGICN;
   data.msg=dwMessage;
   data.d=*pnid;
   data.d.uFlags&=7;

   COPYDATASTRUCT cd;
   cd.dwData=NOTIFY_ICON_CALL;
   cd.cbData=sizeof(MsgDataT);
   cd.lpData=&data;

   return SendMessageW(tray,WM_COPYDATA,WPARAM(pnid->hWnd),LPARAM(&cd));
}
//-----------------------------------------
WINSHELLAPI BOOL WINAPI _Shell_NotifyIconA(DWORD dwMessage,
   PNOTIFYICONDATAA pnid)
{
   NOTIFYICONDATAW d;
   d.hWnd=pnid->hWnd;
   d.uID=pnid->uID;
   d.uFlags=pnid->uFlags;
   d.uCallbackMessage=pnid->uCallbackMessage;
   d.hIcon=pnid->hIcon;

   MultiByteToWideChar(CP_ACP,0,pnid->szTip,sizeof(pnid->szTip),
      d.szTip,sizeof(d.szTip)/2);

   return Shell_NotifyIconW(dwMessage,&d);
}
**********************************************************************
**********************************************************************
//   Enumerate systray icons - Windows 95
//
#include <windows.h>
#include <commctrl.h>
#include <iostream.h>
#include <stdlib.h>

struct TWIconDataT {
   DWORD internalId
I've tired to wait while exeprts-exchange processes my comments.
So all of the code (4 files) is here
**********************************************************************
**********************************************************************
// Source code for Shell_NotifyIcon - Windows 95
//

#include <windows.h>
#include <commctrl.h>
#include <iostream.h>
#include <stdlib.h>

struct MsgDataT {
   DWORD magicN;
   DWORD msg;
   NOTIFYICONDATA d;
};
#define MAGICN 0x34753423
#define NOTIFY_ICON_CALL 1

//-----------------------------------------
WINSHELLAPI BOOL WINAPI _Shell_NotifyIcon(DWORD dwMessage,
   PNOTIFYICONDATA pnid)
{
   HWND tray=FindWindow("Shell_TrayWnd",0);
   if(!tray) return 0;
   MsgDataT data;
   data.magicN=MAGICN;
   data.msg=dwMessage;
   data.d=*pnid;
   data.d.uFlags&=7;

   COPYDATASTRUCT cd;
   cd.dwData=NOTIFY_ICON_CALL;
   cd.cbData=sizeof(MsgDataT);
   cd.lpData=&data;

   return SendMessage(tray,WM_COPYDATA,WPARAM(pnid->hWnd),LPARAM(&cd));
}
**********************************************************************
**********************************************************************
// Source code for Shell_NotifyIcon - Windows NT
//

#include <windows.h>
#include <commctrl.h>
#include <iostream.h>
#include <stdlib.h>

struct MsgDataT {
   DWORD magicN;
   DWORD msg;
   NOTIFYICONDATAW d;
};
#define MAGICN 0x34753423;
#define NOTIFY_ICON_CALL 1

//-----------------------------------------
WINSHELLAPI BOOL WINAPI _Shell_NotifyIconW(DWORD dwMessage,
   PNOTIFYICONDATAW pnid)
{
   wchar_t* clsName=L"Shell_TrayWnd";
   HWND tray=FindWindowW(clsName,0);
   if(!tray) return 0;
   MsgDataT data;
   data.magicN=MAGICN;
   data.msg=dwMessage;
   data.d=*pnid;
   data.d.uFlags&=7;

   COPYDATASTRUCT cd;
   cd.dwData=NOTIFY_ICON_CALL;
   cd.cbData=sizeof(MsgDataT);
   cd.lpData=&data;

   return SendMessageW(tray,WM_COPYDATA,WPARAM(pnid->hWnd),LPARAM(&cd));
}
//-----------------------------------------
WINSHELLAPI BOOL WINAPI _Shell_NotifyIconA(DWORD dwMessage,
   PNOTIFYICONDATAA pnid)
{
   NOTIFYICONDATAW d;
   d.hWnd=pnid->hWnd;
   d.uID=pnid->uID;
   d.uFlags=pnid->uFlags;
   d.uCallbackMessage=pnid->uCallbackMessage;
   d.hIcon=pnid->hIcon;

   MultiByteToWideChar(CP_ACP,0,pnid->szTip,sizeof(pnid->szTip),
      d.szTip,sizeof(d.szTip)/2);

   return Shell_NotifyIconW(dwMessage,&d);
}
**********************************************************************
**********************************************************************
//   Enumerate systray icons - Windows 95
//
#include <windows.h>
#include <commctrl.h>
#include <iostream.h>
#include <stdlib.h>

struct TWIconDataT {
   DWORD internalId;  // image index, -1 if no image in iconList
   NOTIFYICONDATA d;
};

typedef TWIconDataT* pTWIconDataT;

struct TWIconsInfoT {
   int Cnt;
   pTWIconDataT* iconData;
};

struct TWDataT {
   DWORD unknown[7];
   TWIconsInfoT* iconsInfo;
   HIMAGELIST    iconList;
};

void main(void)
{
   InitCommonControls();

   HWND stw=FindWindow("Shell_TrayWnd",0);
   if(!stw) {
      cout<<"System tray not found!"<<endl;
      return;
   }

   HWND tw=FindWindowEx(stw,0,"TrayNotifyWnd",0);
   if(!tw) {
      cout<<"TrayNotifyWnd not found!"<<endl;
      return;
   }
   TWDataT* twd=(TWDataT*)GetWindowLong(tw,0);
   if(!twd) {
      cout<<"Cannot get TrayNotifyWnd data! "<<GetLastError()<<endl;
      return;
   }

   // We cannot just read memory of another process

   DWORD idExplorer;
   GetWindowThreadProcessId(tw,&idExplorer);
   HANDLE hExplorer=OpenProcess(PROCESS_VM_READ,FALSE,idExplorer);
   if(!hExplorer) {
      cout<<"Cannot open Explorer process! "<<GetLastError()<<endl;
      return;
   }

   //Read tray window data
   TWDataT data;
   BOOL r=ReadProcessMemory(hExplorer,twd,&data,sizeof(data),0);
   if(!r) {
      cout<<"Cannot read tray window data! "<<GetLastError()<<endl;
      return;
   }

   cout<<"Image list="<<data.iconList<<endl;

   // Read icons info
   TWIconsInfoT iconsInfo;
   r=ReadProcessMemory(hExplorer,data.iconsInfo,&iconsInfo,
      sizeof(iconsInfo),0);
   if(!r) {
      cout<<"Cannot read icons info! "<<GetLastError()<<endl;
      return;
   }

   if(iconsInfo.Cnt==0) {
      cout<<"No tray icons!"<<endl;
      return;
   }
   else cout<<"Icons count="<<(iconsInfo.Cnt)<<endl;

   // Ok, now read pointers to icons data
   pTWIconDataT* ppIconData=new pTWIconDataT[iconsInfo.Cnt];
   r=ReadProcessMemory(hExplorer,iconsInfo.iconData,ppIconData,
      sizeof(pTWIconDataT)*iconsInfo.Cnt,0);
   if(!r) {
      cout<<"Cannot read pointers to icons data! "<<GetLastError()<<endl;
      return;
   }

   // Now read icons data itself
   pTWIconDataT pIconData=new TWIconDataT[iconsInfo.Cnt];
   for(int i=0;i<iconsInfo.Cnt;i++) {
      r=ReadProcessMemory(hExplorer,ppIconData[i],pIconData+i,
         sizeof(TWIconDataT),0);
      if(!r) {
         cout<<"Cannot read icon data #"<<i<<"! "<<GetLastError()<<endl;
         return;
      }
   }

   delete[] ppIconData;
   CloseHandle(hExplorer);

   // Now, add points to Nick's account for wasted 4 hour!!

   for(int i=iconsInfo.Cnt-1;i>=0;i--) {
      cout<<endl<<"# "<<i<<" *****************"<<endl;
      cout<<"internalId="<<(pIconData[i].internalId)<<endl;
      cout<<"hWnd="<<(pIconData[i].d.hWnd)<<endl;
      cout<<"uID="<<(pIconData[i].d.uID)<<endl;
      cout<<"uFlags="<<(pIconData[i].d.uFlags)<<endl;
      cout<<"uCallbackMessage="<<(pIconData[i].d.uCallbackMessage)<<endl;
      cout<<"hIcon="<<(pIconData[i].d.hIcon)<<endl;
      cout<<"szTip="<<(pIconData[i].d.szTip)<<endl;
      // Will not work
      //HICON icon=ImageList_GetIcon(data.iconList,pIconData[i].internalId,
      //   ILD_NORMAL);
      //cout<<"Real icon="<<icon<<endl;
   }

   delete[] pIconData;
}
**********************************************************************
**********************************************************************
//  Enumerate system tray icons - Windows NT
//
#include <windows.h>
#include <commctrl.h>
#include <iostream.h>
#include <stdlib.h>

struct TWIconDataT {
   DWORD internalId;  // image index, -1 if no image in iconList
   NOTIFYICONDATAW d;
};

typedef TWIconDataT* pTWIconDataT;

struct TWIconsInfoT {
   int Cnt;
   pTWIconDataT* iconData;
};

struct TWDataT {
   DWORD unknown[7];
   TWIconsInfoT* iconsInfo;
   HIMAGELIST    iconList;
};

void main(void)
{
   InitCommonControls();

   HWND stw=FindWindow("Shell_TrayWnd",0);
   if(!stw) {
      cout<<"System tray not found!"<<endl;
      return;
   }

   HWND tw=FindWindowEx(stw,0,"TrayNotifyWnd",0);
   if(!tw) {
      cout<<"TrayNotifyWnd not found!"<<endl;
      return;
   }
   TWDataT* twd=(TWDataT*)GetWindowLong(tw,0);
   if(!twd) {
      cout<<"Cannot get TrayNotifyWnd data! "<<GetLastError()<<endl;
      return;
   }

   // We cannot just read memory of another process

   DWORD idExplorer;
   GetWindowThreadProcessId(tw,&idExplorer);
   HANDLE hExplorer=OpenProcess(PROCESS_VM_READ,FALSE,idExplorer);
   if(!hExplorer) {
      cout<<"Cannot open Explorer process! "<<GetLastError()<<endl;
      return;
   }

   //Read tray window data
   TWDataT data;
   BOOL r=ReadProcessMemory(hExplorer,twd,&data,sizeof(data),0);
   if(!r) {
      cout<<"Cannot read tray window data! "<<GetLastError()<<endl;
      return;
   }

   cout<<"Image list="<<data.iconList<<endl;

   // Read icons info
   TWIconsInfoT iconsInfo;
   r=ReadProcessMemory(hExplorer,data.iconsInfo,&iconsInfo,
      sizeof(iconsInfo),0);
   if(!r) {
      cout<<"Cannot read icons info! "<<GetLastError()<<endl;
      return;
   }

   if(iconsInfo.Cnt==0) {
      cout<<"No tray icons!"<<endl;
      return;
   }
   else cout<<"Icons count="<<(iconsInfo.Cnt)<<endl;

   // Ok, now read pointers to icons data
   pTWIconDataT* ppIconData=new pTWIconDataT[iconsInfo.Cnt];
   r=ReadProcessMemory(hExplorer,iconsInfo.iconData,ppIconData,
      sizeof(pTWIconDataT)*iconsInfo.Cnt,0);
   if(!r) {
      cout<<"Cannot read pointers to icons data! "<<GetLastError()<<endl;
      return;
   }

   // Now read icons data itself
   pTWIconDataT pIconData=new TWIconDataT[iconsInfo.Cnt];
   for(int i=0;i<iconsInfo.Cnt;i++) {
      r=ReadProcessMemory(hExplorer,ppIconData[i],pIconData+i,
         sizeof(TWIconDataT),0);
      if(!r) {
         cout<<"Cannot read icon data #"<<i<<"! "<<GetLastError()<<endl;
         return;
      }
   }

   delete[] ppIconData;
   CloseHandle(hExplorer);

   // Now, add points to Nick's account for wasted 4 hour!!

   for(int i=iconsInfo.Cnt-1;i>=0;i--) {
      cout<<endl<<"# "<<i<<" *****************"<<endl;
      cout<<"internalId="<<(pIconData[i].internalId)<<endl;
      cout<<"hWnd="<<(pIconData[i].d.hWnd)<<endl;
      cout<<"uID="<<(pIconData[i].d.uID)<<endl;
      cout<<"uFlags="<<(pIconData[i].d.uFlags)<<endl;
      cout<<"uCallbackMessage="<<(pIconData[i].d.uCallbackMessage)<<endl;
      cout<<"hIcon="<<(pIconData[i].d.hIcon)<<endl;
      char buf[64];
      wcstombs(buf,pIconData[i].d.szTip,sizeof(buf));
      cout<<"szTip="<<buf<<endl;
      // Will not work
      //HICON icon=ImageList_GetIcon(data.iconList,pIconData[i].internalId,
      //   ILD_NORMAL);
      //cout<<"Real icon="<<icon<<endl;
   }

   delete[] pIconData;
}

Avatar of eppsman

ASKER

Great! This is just what I needed! Thanks for taking the time, you're right, it deserves an A. Thanks again.
Here is the full answer to your Q (w/ icon handles). It works for NT and 95 and more simple.


//***************************************************************
//  sh.cpp - Enumerate system tray icons - main module (console app).
//  Run it in window, not in the full-screen mode.
//
//  Creates the console, attached to the Explorer.
//  The icons info will be printed on this console.
//  Icons itself will be painted on the console window caption
//       at 200-pixels offset from the left.
//
//  Console automatically destroys after 10 sec.
//
//  Link with shdll.dll.
//
//***************************************************************
#define STRICT

#include <windows.h>
#include <iostream.h>
#include <conio.h>


void _import SetTrayHook();

void main(void)
{
   SetTrayHook();

   Sleep(15000);

   SetTrayHook();
}
//*******************************************
// File: shdll.cpp. Compile as DLL
//*******************************************
#define STRICT
#include <windows.h>
#include <commctrl.h>
#include <stdlib.h>

bool IsNT()
{
   OSVERSIONINFO v;
   v.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
   ::GetVersionEx(&v);
   return v.dwPlatformId==VER_PLATFORM_WIN32_NT;
}

bool isNT=IsNT();

void _export SetTrayHook();
void enumerateIcons();
void out(char* p=0);
LRESULT CALLBACK MsgProc(int,WPARAM,LPARAM);

HINSTANCE hInstance;
HHOOK hHook=0;
HWND SysTray=0;
HWND NotifyWnd=0;
DWORD dwExplorerThreadId=0,dwExplorerProcessId=0;

char msg[256];
HANDLE hCon=0;
HWND wCon=0;

BOOL WINAPI DllEntryPoint(HINSTANCE hInstDll,DWORD fdwReason,LPVOID)
{
   switch(fdwReason) {
   case DLL_PROCESS_ATTACH:
      hInstance=hInstDll;
      break;
   case DLL_THREAD_ATTACH:
      break;
   case DLL_PROCESS_DETACH:
      break;
   case DLL_THREAD_DETACH:
      break;
   }
   return TRUE;
}

void SetTrayHook()
{
   if(hHook==NULL) {
      SysTray=FindWindow("Shell_TrayWnd",NULL);
      NotifyWnd=FindWindowEx(SysTray,0,"TrayNotifyWnd",0);
      dwExplorerThreadId=GetWindowThreadProcessId(SysTray,
         &dwExplorerProcessId);
      hHook=SetWindowsHookEx(WH_CALLWNDPROC,HOOKPROC(MsgProc),
         hInstance,dwExplorerThreadId);
      //PostThreadMessage(dwExplorerThreadId,WM_NULL,0,0);
   }
   else {
      UnhookWindowsHookEx(hHook);
      hHook=NULL;
   }
   return;
}

bool isFirst=true;
LRESULT CALLBACK MsgProc(int nCode,WPARAM wParam,LPARAM lParam)
{
   if(isFirst) {
      isFirst=false;
      isNT=IsNT();
      SysTray=FindWindow("Shell_TrayWnd",NULL);
      NotifyWnd=FindWindowEx(SysTray,0,"TrayNotifyWnd",0);
      // To display messages
      AllocCo
Here is the full answer to your Q. It works for NT and 95 and more simple.


//***************************************************************
//  sh.cpp - Enumerate system tray icons - main module (console app).
//  Run it in window, not in the full-screen mode.
//
//  Creates the console, attached to the Explorer.
//  The icons info will be printed on this console.
//  Icons itself will be painted on the console window caption
//       at 200-pixels offset from the left.
//
//  Console automatically destroys after 10 sec.
//
//  Link with shdll.dll.
//
//***************************************************************
#define STRICT

#include <windows.h>
#include <iostream.h>
#include <conio.h>


void _import SetTrayHook();

void main(void)
{
   SetTrayHook();

   Sleep(15000);

   SetTrayHook();
}
//*******************************************
// File: shdll.cpp. Compile as DLL
//*******************************************
#define STRICT
#include <windows.h>
#include <commctrl.h>
#include <stdlib.h>

bool IsNT()
{
   OSVERSIONINFO v;
   v.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
   ::GetVersionEx(&v);
   return v.dwPlatformId==VER_PLATFORM_WIN32_NT;
}

bool isNT=IsNT();

void _export SetTrayHook();
void enumerateIcons();
void out(char* p=0);
LRESULT CALLBACK MsgProc(int,WPARAM,LPARAM);

HINSTANCE hInstance;
HHOOK hHook=0;
HWND SysTray=0;
HWND NotifyWnd=0;
DWORD dwExplorerThreadId=0,dwExplorerProcessId=0;

char msg[256];
HANDLE hCon=0;
HWND wCon=0;

BOOL WINAPI DllEntryPoint(HINSTANCE hInstDll,DWORD fdwReason,LPVOID)
{
   switch(fdwReason) {
   case DLL_PROCESS_ATTACH:
      hInstance=hInstDll;
      break;
   case DLL_THREAD_ATTACH:
      break;
   case DLL_PROCESS_DETACH:
      break;
   case DLL_THREAD_DETACH:
      break;
   }
   return TRUE;
}

void SetTrayHook()
{
   if(hHook==NULL) {
      SysTray=FindWindow("Shell_TrayWnd",NULL);
      NotifyWnd=FindWindowEx(SysTray,0,"TrayNotifyWnd",0);
      dwExplorerThreadId=GetWindowThreadProcessId(SysTray,
         &dwExplorerProcessId);
      hHook=SetWindowsHookEx(WH_CALLWNDPROC,HOOKPROC(MsgProc),
         hInstance,dwExplorerThreadId);
      //PostThreadMessage(dwExplorerThreadId,WM_NULL,0,0);
   }
   else {
      UnhookWindowsHookEx(hHook);
      hHook=NULL;
   }
   return;
}

bool isFirst=true;
LRESULT CALLBACK MsgProc(int nCode,WPARAM wParam,LPARAM lParam)
{
   if(isFirst) {
      isFirst=false;
      isNT=IsNT();
      SysTray=FindWindow("Shell_TrayWnd",NULL);
      NotifyWnd=FindWindowEx(SysTray,0,"TrayNotifyWnd",0);
      // To display messages
      AllocConsole();
   
Here is the full answer to your Q. It works for NT and 95 and more simple.


//***************************************************************
//  sh.cpp - Enumerate system tray icons - main module (console app).
//  Run it in window, not in the full-screen mode.
//
//  Creates the console, attached to the Explorer.
//  The icons info will be printed on this console.
//  Icons itself will be painted on the console window caption
//       at 200-pixels offset from the left.
//
//  Console automatically destroys after 10 sec.
//
//  Link with shdll.dll.
//
//***************************************************************
#define STRICT

#include <windows.h>
#include <iostream.h>
#include <conio.h>


void _import SetTrayHook();

void main(void)
{
   SetTrayHook();

   Sleep(15000);

   SetTrayHook();
}
//*******************************************
// File: shdll.cpp. Compile as DLL
//*******************************************
#define STRICT
#include <windows.h>
#include <commctrl.h>
#include <stdlib.h>

bool IsNT()
{
   OSVERSIONINFO v;
   v.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
   ::GetVersionEx(&v);
   return v.dwPlatformId==VER_PLATFORM_WIN32_NT;
}

bool isNT=IsNT();

void _export SetTrayHook();
void enumerateIcons();
void out(char* p=0);
LRESULT CALLBACK MsgProc(int,WPARAM,LPARAM);

HINSTANCE hInstance;
HHOOK hHook=0;
HWND SysTray=0;
HWND NotifyWnd=0;
DWORD dwExplorerThreadId=0,dwExplorerProcessId=0;

char msg[256];
HANDLE hCon=0;
HWND wCon=0;

BOOL WINAPI DllEntryPoint(HINSTANCE hInstDll,DWORD fdwReason,LPVOID)
{
   switch(fdwReason) {
   case DLL_PROCESS_ATTACH:
      hInstance=hInstDll;
      break;
   case DLL_THREAD_ATTACH:
      break;
   case DLL_PROCESS_DETACH:
      break;
   case DLL_THREAD_DETACH:
      break;
   }
   return TRUE;
}

void SetTrayHook()
{
   if(hHook==NULL) {
      SysTray=FindWindow("Shell_TrayWnd",NULL);
      NotifyWnd=FindWindowEx(SysTray,0,"TrayNotifyWnd",0);
      dwExplorerThreadId=GetWindowThreadProcessId(SysTray,
         &dwExplorerProcessId);
      hHook=SetWindowsHookEx(WH_CALLWNDPROC,HOOKPROC(MsgProc),
         hInstance,dwExplorerThreadId);
      //PostThreadMessage(dwExplorerThreadId,WM_NULL,0,0);
   }
   else {
      UnhookWindowsHookEx(hHook);
      hHook=NULL;
   }
   return;
}

bool isFirst=true;
LRESULT CALLBACK MsgProc(int nCode,WPARAM wParam,LPARAM lParam)
{
   if(isFirst) {
      isFirst=false;
      isNT=IsNT();
      SysTray=FindWindow("Shell_TrayWnd",NULL);
      NotifyWnd=FindWindowEx(SysTray,0,"TrayNotifyWnd",0);
      // To display messages
      AllocConsole();
      hCon=CreateFile("CONOUT$",GENERIC_READ|GENERIC_WRITE,
         FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,0);
      SetConsoleMode(hCon,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT);
      CONSOLE_SCREEN_BUFFER_INFO bi;
      GetConsoleScreenBufferInfo(hCon,&bi);
      bi.dwSize.Y=200;
      SetConsoleScreenBufferSize(hCon,bi.dwSize);
      SetConsoleTitle("Nick's console");
      wCon=FindWindow(0,"Nick's console");
      out("We are in the Explorer!\r\n");
      wsprintf(msg,"Console wnd=%X\r\n\r\n",wCon);
      out();

      enumerateIcons();

      Sleep(10000);  // Wait 10 sec

      CloseHandle(hCon);
      FreeConsole();
   }
   return CallNextHookEx(hHook,nCode,wParam,lParam);
}

struct TWIconDataT {
   DWORD imageIndex;  // image index, -1 if no image in iconList
   union {
      NOTIFYICONDATAW dw;
      NOTIFYICONDATAA da;
   };
};

typedef TWIconDataT* pTWIconDataT;

struct TWIconsInfoT {
   int Cnt;
   pTWIconDataT* iconData;
};

struct TWDataT {
   DWORD unknown[7];
   TWIconsInfoT* iconsInfo;
   HIMAGELIST    iconList;
};

typedef pTWIconDataT WINAPI (*COMCTL32_332_T) (TWIconsInfoT* info,int index);
COMCTL32_332_T COMCTL32_332;

void enumerateIcons()
{
   // Load useful function
   HINSTANCE hLib=LoadLibrary("COMCTL32.DLL");
   COMCTL32_332=(COMCTL32_332_T) GetProcAddress(hLib,LPCSTR(332));

   TWDataT* twd=(TWDataT*)GetWindowLong(NotifyWnd,0);

   wsprintf(msg,"Proc=%X, NotifyWnd=%X, data=%X\r\n",COMCTL32_332,
      NotifyWnd,twd);
   out();

   int cnt=twd->iconsInfo->Cnt;  // icons count

   if(cnt==0) {
      out("No tray icons!\r\n");
      return;
   }

   wsprintf(msg,"Icons count=%d",cnt);
   out();

   int x=200; // Offset for icon painting

   for(int i=cnt-1;i>=0;i--) {
      wsprintf(msg,"\r\n\r\n# %d *****************\r\n",i); out();
      pTWIconDataT p=COMCTL32_332(twd->iconsInfo,i);
      wsprintf(msg,"ImageIndex=%d\r\n",p->imageIndex); out();
      wsprintf(msg,"hWnd=%X\r\n",p->dw.hWnd); out();
      wsprintf(msg,"uID=%d\r\n",p->dw.uID); out();
      wsprintf(msg,"uFlags=%d\r\n",p->dw.uFlags); out();
      wsprintf(msg,"uCallbackMessage=%d\r\n",p->dw.uCallbackMessage); out();
      wsprintf(msg,"hIcon=%X\r\n",p->dw.hIcon); out();
      memset(msg,0,sizeof(msg));
      strcpy(msg,"szTip=");
      if(isNT)
         wcstombs(msg+strlen(msg),p->dw.szTip,sizeof(p->dw.szTip)/2);
      else
         strcpy(msg+strlen(msg),p->da.szTip);
      out();

      HICON icon=ImageList_GetIcon(twd->iconList,p->imageIndex,ILD_NORMAL);
      wsprintf(msg,"Real icon=%X\r\n",icon);

      // Draw icon
      HDC dc=GetWindowDC(wCon);
      ImageList_Draw(twd->iconList,p->imageIndex,dc,x,4,ILD_NORMAL);
      ReleaseDC(wCon,dc);
      x+=30;
   }
}

void out(char* p)
{
   DWORD dwWritten;
   if(p) strcpy(msg,p);
   WriteConsole(hCon,msg,strlen(msg),&dwWritten,0);
}

#include "stdafx.h"
#include <tlhelp32.h>

BOOL CALLBACK enumThreadWndProc(HWND hWnd, LPARAM lParam);

void Delete_Outlook_Systray_Icon()
{

     HWND hWnd = FindWindowEx(NULL, NULL, "rctrl_renwnd32", NULL);
     if (hWnd==NULL)
     {
          AfxMessageBox("Outlook Window not found");
          return;
     }
     
     DWORD dwProcessID;
     DWORD dwThreadID = GetWindowThreadProcessId(hWnd, &dwProcessID);

     if (dwThreadID==0)
     {
          AfxMessageBox("Outlook Thread not found");
          return;
     }


    BOOL          bFound      = FALSE;
    HANDLE        hModuleSnap = NULL;
    MODULEENTRY32 me32        = {0};
 
    // Take a snapshot of all modules in the specified process.

    hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessID);
    if (hModuleSnap == (HANDLE)-1)
     {
          AfxMessageBox("Could not creat Tool-Help snapshot for the Outlook process");
          return;
     }


    // Fill the size of the structure before using it.

    me32.dwSize = sizeof(MODULEENTRY32);
 
    // Walk the module list of the process, and find the module of
    // interest.

    if (!Module32First(hModuleSnap, &me32))
     {
          AfxMessageBox("Could find any module for the Outlook process");
          return;
     }

     bFound = false;
    do
    {
          if (lstrcmpi(me32.szModule, "Outlook.exe") == 0)
          {
            bFound = true;
               break;
        }
    }
    while (!bFound && Module32Next(hModuleSnap, &me32));
 
 
    // Do not forget to clean up the snapshot object.

    CloseHandle (hModuleSnap);
 
     if (!bFound)
     {
          AfxMessageBox("Could not identify Outlook Module name");
          return;
     }

     bool bIconDeleted = false;
     BOOL bScanToLast =
          EnumThreadWindows(dwThreadID, enumThreadWndProc, (LPARAM)&bIconDeleted);
     if(!bIconDeleted)
     {
          AfxMessageBox("Could not find or delete Outlook Notification Icon");
          return;
     }
     
     if (bScanToLast)
     {
          AfxMessageBox("Fishy: Had to scan ALL Outlook windows but anyway seems to delete Outlook Notification icon");
          return;
     }
}

BOOL MyTaskBarDeleteIcon(HWND hwnd, UINT uID)
{
    BOOL res;
    NOTIFYICONDATA tnid;
 
    tnid.cbSize = sizeof(NOTIFYICONDATA);
    tnid.hWnd = hwnd;
    tnid.uID = uID;
         
    res = Shell_NotifyIcon(NIM_DELETE, &tnid);
    return res;
}

BOOL CALLBACK enumThreadWndProc(HWND hWnd, LPARAM lParam)
{
     if (!MyTaskBarDeleteIcon(hWnd, 0))
          return true;

     *(bool*)lParam = true;

     char msg[512];
     wsprintf(msg,"Icon Deleted. window = %x", hWnd);
     AfxMessageBox(msg, MB_OK);
     return false;
}