Programmatically kill Outlook/Exchange envelope in tray

Is there any way to programmatically kill the envelope in the tray put there by Outlook or Exchange? I'll take any kind of solution - doesn't appear to be an obvious way to do it. Cleanest answer gets the points.
chrismoAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

NickRepinCommented:
Do you mean you want to remove the icon from the system tray?

If so, goto http:://skyscraper.fortunecity.com/gigo/311 ->Undoc windows -> System tray icon enumeration.
With that code, you can find the icon you want and then remove it with Shell_NotifyIcon.
Ask me if you have any questions regarding this.
0
MadshiCommented:
:-)  Yes, with Nick's sources you can enumerate (and then kill) the trayIcons. But you'll need a bit more if you want to be notified about when this envelope icon is added to the tray area. You can either hook the sysTray window (SetWindowsHookEx) or intercept the Shell_NotifyIcon API in Outlook's process. The easiest way - but not the nicest - would of course be to set up a timer and use Nick's code to enumerate the icons let's say every second or so.

Regards, Madshi.
0
MadshiCommented:
BTW, Nick, have you looked at the extended trayIcon functionality introduced in win2000 already? You can now e.g. hide icons. With your sources all icons are enumerated, but we don't know which icons are really visible. E.g. if you go online and then offline again, the connection icon is still in the trayIcon list - but in hidden state! And there is a lot more new functionality (e.g. a new kind of hint window).
0
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

NickRepinCommented:
>>Nick, have you looked
No, I'm so lucky - I'm not interesting in this. Besides, I have my own big problems with crazy Windows.
0
MadshiCommented:
:-)
0
chrismoAuthor Commented:
Lemme ask you this: what information is required in the NOTIFYICONDATA structure beyond hWnd and uID to Delete an icon? The MSDN online docs don't really say ... do I need the icon handle as well? Do you know?

My first approach was to try and grab the main Outlook hWnd, assume uID was 0, then just assign those two values and delete the icon. That didn't work. One, I may not have the right hWnd - Outlook, of course, spawns many. Two, the question above.

I understand that doing Nick's enum would get me to the NOTIFYICONDATA struct, but I was hoping to not have to implement that (mainly cuz I'm a Delphi programmer & I didn't feel like porting the code).

Nick: how did you learn the info you needed to write that Enum code? I'd love to know how you did that.
0
MadshiCommented:
Hi chrismo,

I can't tell you *exactly* which fields of the structure are needed. I guess, it will be these 3:

  HWND hWnd;
  UINT uID;
  UINT uCallbackMessage;

Perhaps it will work without the uCallbackMessage, but the uID is almost never ever 0, so just trying a value won't work...   :-(

I'm a Delphi programmer, too (why didn't you ask this question in the Delphi forum?). I have written some nice Delphi components that do a lot of low level stuff, including all what Nick's code does and more, but without needing a dll (Nick's code must be executed in a dll, that is injected into the explorer). The problem is: I didn't publish my components yet. But I would be willing to send you some DCUs if you want. Just tell me your Delphi version (must be 4 or 5) and your eMail address.

P.S: The win2000 support is a bit weak in the moment, see my last comments, I will look into that later...

Regards, Madshi.
0
chrismoAuthor Commented:
Excellent. Delphi components that do this stuff would be perfect.

I headed here 1st cuz I didn't want to limit my expert audience to Delphi only people, but Windows people (like Nick <g>).

I'm on D4 at the moment. Send it here: chrism@snellingcorp.com.

Are you going to open up the source at some point?
0
MadshiCommented:
Hmmm... I'll probably make my components available for free for non-commercial use - but only DCUs. If someone wants to use my stuff for commercial use or if one wants to get my sources, he will have to pay for it. At least that's what I'm planning right now. You know, the trayIcon stuff is just a very small part of it...

Components are on the way.

Do this:

procedure DeleteTrayIcons(processExeName: string);
var i1 : integer;
begin
  with TrayIcons do
    for i1 := 0 to ItemCount - 1 do
      if IsTextEqual(Items[i1].Window.OwnerProcess.FileName, processExeName) then
        Items[i1].Delete;
end;

Or this:

procedure DeleteTrayIcons(processID: cardinal);
var i1 : integer;
begin
  with TrayIcons do
    for i1 := 0 to ItemCount - 1 do
      if Items[i1].Window.OwnerProcess.ID = processID then
        Items[i1].Delete;
end;

Or this directly:

  Process('OutlookOrWhatever.exe').TrayIcons.Delete;
  // deletes all trayIcons that belong to outlook

Or this:

  Process(outlookProcessID).TrayIcons.Delete;

Regards, Madshi.
0
chrismoAuthor Commented:
I may not get to try them out right away - this isn't work I'm getting paid for <g>. First chance, I'll try it out and let you know.
0
NickRepinCommented:
Probably it will be really easier to use the hook to intercept a message to the system tray instead of enumerating the icons.
0
NickRepinCommented:
Also it's not necessary to inject a dll even with my original code, because the icon handle is not necessary in this case.

Anyway, Madshi will be more useful because he's Delphi programmer. I'm not.
0
NickRepinCommented:
To delete the icon, you need hWnd and uID only.

      NOTIFYICONDATA d;
      d.cbSize=sizeof(NOTIFYICONDATA);
      d.hWnd=hWin;
      d.uID=UINT(this);
      d.uFlags=0;
      Shell_NotifyIcon(NIM_DELETE,&d);

So all you have to know is hWnd and uID.
I assume that Outlook (and Exchnage) uses the constant uID, at least for any particular version
(different versions of Outlook can use different values of uId, so you have to provide the separate code for each).

I offer a solution that allow to eliminate the hard task of the icon enumeration.
Keep in mind that you have to use the different code for 95/98, Nt 4.0 and Win2000 to enumerate the system tray icons.

So you have to:
1) Make Outlook to place the icon on the systray.
2) Run the program to enumerate the icons.
3) Write down the Outlook's icon uID and hWnd.
(I should note that you have to do the all above in any case)
4) Run Spy++ (Microsoft) of Winsight32 (Borland), find the window hWnd, write down its title and class name.


Now in your program you have to just find the window by title/class name and call Shell_NotifyIcon.

For example, to delete the icon of the Outlook Express 5.0 on NT (probably, it will works for all OExpress 4.0-5.0):

HWND hWnd=FindWindow("OutlookExpressHiddenWindow","OutlookExpressHiddenWindow");
NOTIFYICONDATA d;
d.cbSize=sizeof(NOTIFYICONDATA);
d.hWnd=hWnd;
d.uID=0; // Outlook Express uses zero as uID.
d.uFlags=0;
Shell_NotifyIcon(NIM_DELETE,&d);


You can perform this in loop (for example, by timer). It will be much faster (less CPU consuming) than icons enumerating.
If there is no icon on the system tray, the code above will not cause any problems.

You can download the programs to enumerate the icons from
http://skyscraper.fortunecity.com/gigo/311/winprog/sh95.exe
http://skyscraper.fortunecity.com/gigo/311/winprog/shnt.exe

I can write such program for Win2000 also.

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
NickRepinCommented:
Using a hook to prevent an icon to be placed on the system tray is a little bit harder then the way offered by me above.

For 95/98/NT4 you have to:

1) Find window HWND tray=FindWindowW("Shell_TrayWnd",0); and install two hooks on it - WH_CALLWNDPROC and WH_CALLWNDPROCRET.
2) In 1st hook proc you have to subclass tray window using your own window proc.
In this proc you have to handle WM_COPYDATA message which carries NOTIFYICONDATA structure. If you decide not to place the icon to the systray, you have to not pass this message to the original window proc.
3) In the 2nd hook you have remove sublassing.

Or you can permanently subclass a tray window, but in this case you also have to inject dll into the address space of the explorer.

0
MadshiCommented:
Well, if Outlook really uses (uID == 0) in all versions (4-5) on all OSs, then it's surely the most simple way to drop enumeration and simply delete the icon, regardless whether it is there or not.

Regards, Madshi.
0
NickRepinCommented:
Anyway we have to know uID or CallbackMessage if we enumerate the icons. So anyway different uIds or CallbackMessages will affect the code.
0
MadshiCommented:
Hi Nick, what do you mean with your last comment, I don't understand it somehow - sorry...
0
NickRepinCommented:
I added my comment as answer on your one:

>>if Outlook really uses (uID == 0) in all versions (4-5) on all OSs

Suppose, we enumerate the icons on the system tray. How can we detect that this particular icon is envelope, and others aren't?

We can check the fields of NOTIFYICONDATAs (obtained by enumeration) and compare these fields with some known values. There is no other way, isn't?

szTip - may vary, especially for localized versions.
hIcon, uFlags - useless.

uID and uCallbackMessage - good candidates, but your comment may be applied to them: <<if Outlook really uses (uID == 0) in all versions (4-5) on all OSs>>

hWnd - well, may be, it's enough to check hWnd only. We have to check the process id of hWnd and compare it with the process id of Outlook or Exchange.
In general, program can put two or more icons on the system tray. But it seems it is not in our case.

On the other hand, if program uses only one icon, then most likely the icon id will be zero or at least the constant value across all versions.
0
TryCommented:
NOTIFYICONDATA  nid;
ZeroMemory(&nid, sizeof(NOTIFYICONDATA));
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.uID = ICON_ID;

Shell_NotifyIcon(NIM_DELETE, &nid);

------------------------------------

That'll do it!
0
NickRepinCommented:
^^^ Nice joke :)
0
MadshiCommented:
Nick, you're right. My plan was to simply delete ALL Outlook icons (by checking whether the window belongs to Outlook).
0
NickRepinCommented:
Yes, it's simply to delete, but hard to enumerate :)
0
chrismoAuthor Commented:
Nick - I've decided to give the points to you. Madshi - I appreciate all your input, but since I can't use your non OpenSource Delphi-ed version of Nick's code, I'll have to do that myself. Post an answer and I'll slide them your way.
0
chrismoAuthor Commented:
Ah - hadn't been in ExEx for a while - hadn't seen the "accept comment as answer".

There she be.
0
NickRepinCommented:
Thank you.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.