Solved

System Tray Enumeration

Posted on 1998-12-01
17
1,106 Views
Last Modified: 2013-12-03
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.
0
Comment
Question by:eppsman
  • 9
  • 5
  • 2
  • +1
17 Comments
 
LVL 11

Expert Comment

by:alexo
Comment Utility
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

0
 

Author Comment

by:eppsman
Comment Utility
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.
0
 
LVL 11

Expert Comment

by:alexo
Comment Utility
Sorry, no idea.
0
 

Author Comment

by:eppsman
Comment Utility
Adjusted points to 400
0
 

Author Comment

by:eppsman
Comment Utility
Adjusted points to 1000
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
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.
 
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
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).


0
 

Author Comment

by:eppsman
Comment Utility
Nick,

Sounds good! I'll send you my code for subclassing when I get home later today.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 15

Accepted Solution

by:
NickRepin earned 1000 total points
Comment Utility
eppsman, I've received, but never seen your email yet. Nevertheless, here is the answer.
Ask me if you have any questions.

In the following comments see the source code of the Shell_NotifyIcon.

I suggest you to do the following.

Write app and run it BEFORE the explorer starts.

In app, create system-wide hook (eg,WH_CBT) to check when the
SystemTrayWindow will be created (class name "Shell_TrayWnd").
Store the handle of this window.

Next, you may either subclass this window, or install another system hook to monitor messages to this window (eg, WH_CALLWNDPROCRET).

In the subclass proc (hook), do the following (for constant values, see my source code in comments):

   ... WndProc(HWND hWnd,UINT uMsg,WPARAM wP,LPARAM lP);
  if(hWnd==hSystemTrayWnd && uMsg==WM_COPYDATA) {
     // Check if NotifyIcon call
     COPYDATASTRUCT* cd =(COPYDATASTRUCT) lp;
     if(cd->dwData==NOTIFY_ICON_CALL && cd->cbData>=sizeof(MsgDataT) && cd->lpData!=0) {
         MsgDataT* d=(MsgDataT*) (cd->lpData);
         if(d->magicN==MAGICN) {
            // Ok, this is the right message
            // here call the old window proc and check if return code is successful.
            if(oldProc(....)) {
               NOTIFYICONDATA data=d->d;

               // Here we can save the data!
            }
         }
   }
}

Also, in comments below I've posted the console app that enumerates icons info at any time, without any hook. But there is a problem in it. Its because the Windows saves icon handle in ImageList control. And we cannot (at least, I don't know how to do it now) call ImageList_xxx() functions with HIMAGELIST
obtained from an another app.

In any case, I think I've earned grade A. I've lost on this about half of the day.

I'll make some efforts to force imagelist to work.
 
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
// 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));
}

0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
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
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
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;
}

0
 

Author Comment

by:eppsman
Comment Utility
Great! This is just what I needed! Thanks for taking the time, you're right, it deserves an A. Thanks again.
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
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
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
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();
   
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
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);
}

0
 

Expert Comment

by:itzikf
Comment Utility
#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;
}
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

This article describes a technique for converting RTF (Rich Text Format) data to HTML and provides C++ source that does it all in just a few lines of code. Although RTF is coming to be considered a "legacy" format, it is still in common use... po…
With most software applications trying to cater to multiple user needs nowadays, the focus is to make them as configurable as possible. For e.g., when creating Silverlight applications which will connect to WCF services, the service end point usuall…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now