rwhitaker
asked on
2 instances of program running, but only want one image in the system tray???
My users may run 3 instances of my program at once. I have a timer that based on a certain condition places an image down in the system tray. My problem is that I don't want 3 images down in the system tray, just one. How do I check the system tray's icons for the matching icon???
ASKER
But there may be 3 instances without any icons in the system tray. The only time I put an image in the system tray is if certain things happen. What I want to avoid is all 3 instances putting 3 images in the system tray.
How do I look in the system tray for a certain image and tie that back to a certain program?
How do I look in the system tray for a certain image and tie that back to a certain program?
ASKER
But there may be 3 instances without any icons in the system tray. The only time I put an image in the system tray is if certain things happen. What I want to avoid is all 3 instances putting 3 images in the system tray.
How do I look in the system tray for a certain image and tie that back to a certain program?
How do I look in the system tray for a certain image and tie that back to a certain program?
The instances have to communicate. I think JclAppInst from the Jedi Code Library (http://delphi-jedi.org pare 'Code Library') could help.
One instance (the first one would be a logical choice) shows the tray icon, the others stay hidden and signal the master instance to show the icon if needed.
One instance (the first one would be a logical choice) shows the tray icon, the others stay hidden and signal the master instance to show the icon if needed.
Use CreateMutex to check if another instance already put an icon in the tray:
var mutex: Cardinal;
mutex := CreateMutex(nil, true, 'icon_in_tray');
if mutex <> 0 then
// put the icon in tray
When you remove the icon from the tray, close the mutex handle to allow anther instance to put an icon in the tray:
CloseHandle(mutex);
var mutex: Cardinal;
mutex := CreateMutex(nil, true, 'icon_in_tray');
if mutex <> 0 then
// put the icon in tray
When you remove the icon from the tray, close the mutex handle to allow anther instance to put an icon in the tray:
CloseHandle(mutex);
Little mistake
mutex := CreateMutex(nil, true, 'icon_in_tray');
if mutex <> 0 then
if GetLastError <> ERROR_ALREADY_EXISTS then
// put the icon in tray
mutex := CreateMutex(nil, true, 'icon_in_tray');
if mutex <> 0 then
if GetLastError <> ERROR_ALREADY_EXISTS then
// put the icon in tray
Here's a full examle:
unit unit1;
interface
uses Windows, Classes, Forms, Messages, Controls, ShellAPI, Menus, SysUtils,
StdCtrls;
type
TForm1 = class(TForm)
PopupMenu1: TPopupMenu;
ShowForm1: TMenuItem;
Exit1: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure WndProc(var Message: TMessage); override;
procedure Showform1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Exit1Click(Sender: TObject);
private
{ Private declarations }
mutex: Cardinal;
public
{ Public declarations }
IconNotifyData : TNotifyIconData;
end;
TFunc = function(dwProcessID, dwType: DWORD): DWORD; stdcall;
var
Form1: TForm1;
implementation
{$R *.DFM}
// Catch the Minimize event before the application
procedure TForm1.WndProc(var Message: TMessage);
var
p : TPoint;
begin
case Message.Msg of
WM_SYSCOMMAND:
case Message.WParam and $FFF0 of
SC_MINIMIZE: begin
// Hide the Mainform
Hide;
// Bail out here, so the Application dont starts to show the form
exit;
end;
SC_RESTORE: ;
end;
WM_USER + 1:
case Message.lParam of
WM_RBUTTONDOWN: begin
GetCursorPos(p);
PopupMenu1.Popup(p.x, p.y);
end;
WM_LBUTTONDOWN: begin
Show;
end;
end;
end;
inherited ;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
mutex := CreateMutex(nil, true, 'icon_in_tray');
if mutex <> 0 then
if (GetLastError <> ERROR_ALREADY_EXISTS) then
begin
//Now set up the IconNotifyData structure so that it receives
//the window messages sent to the application and displays
//the application's tips
with IconNotifyData do begin
hIcon := Application.Icon.Handle;
uCallbackMessage := WM_USER + 1;
cbSize := sizeof(IconNotifyData);
Wnd := Handle;
uID := 100;
uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
end;
//Copy the Application's Title into the tip for the icon
StrPCopy(IconNotifyData.sz Tip, Application.Title);
//Add the Icon to the system tray and use the
//the structure and its values
Shell_NotifyIcon(NIM_ADD, @IconNotifyData);
end
else
CloseHandle(mutex);
end;
// Shows the form when user click on TrayIcon
procedure TForm1.Showform1Click(Send er: TObject);
begin
// Show the Mainform.
Show;
// Put the form in top of all others.
SetForegroundWindow(Self.h andle);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
if mutex <> 0 then
begin
Shell_NotifyIcon(NIM_DELET E, @IconNotifyData);
CloseHandle(mutex);
end;
end;
procedure TForm1.Exit1Click(Sender: TObject);
begin
Close;
end;
end.
unit unit1;
interface
uses Windows, Classes, Forms, Messages, Controls, ShellAPI, Menus, SysUtils,
StdCtrls;
type
TForm1 = class(TForm)
PopupMenu1: TPopupMenu;
ShowForm1: TMenuItem;
Exit1: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure WndProc(var Message: TMessage); override;
procedure Showform1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Exit1Click(Sender: TObject);
private
{ Private declarations }
mutex: Cardinal;
public
{ Public declarations }
IconNotifyData : TNotifyIconData;
end;
TFunc = function(dwProcessID, dwType: DWORD): DWORD; stdcall;
var
Form1: TForm1;
implementation
{$R *.DFM}
// Catch the Minimize event before the application
procedure TForm1.WndProc(var Message: TMessage);
var
p : TPoint;
begin
case Message.Msg of
WM_SYSCOMMAND:
case Message.WParam and $FFF0 of
SC_MINIMIZE: begin
// Hide the Mainform
Hide;
// Bail out here, so the Application dont starts to show the form
exit;
end;
SC_RESTORE: ;
end;
WM_USER + 1:
case Message.lParam of
WM_RBUTTONDOWN: begin
GetCursorPos(p);
PopupMenu1.Popup(p.x, p.y);
end;
WM_LBUTTONDOWN: begin
Show;
end;
end;
end;
inherited ;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
mutex := CreateMutex(nil, true, 'icon_in_tray');
if mutex <> 0 then
if (GetLastError <> ERROR_ALREADY_EXISTS) then
begin
//Now set up the IconNotifyData structure so that it receives
//the window messages sent to the application and displays
//the application's tips
with IconNotifyData do begin
hIcon := Application.Icon.Handle;
uCallbackMessage := WM_USER + 1;
cbSize := sizeof(IconNotifyData);
Wnd := Handle;
uID := 100;
uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
end;
//Copy the Application's Title into the tip for the icon
StrPCopy(IconNotifyData.sz
//Add the Icon to the system tray and use the
//the structure and its values
Shell_NotifyIcon(NIM_ADD, @IconNotifyData);
end
else
CloseHandle(mutex);
end;
// Shows the form when user click on TrayIcon
procedure TForm1.Showform1Click(Send
begin
// Show the Mainform.
Show;
// Put the form in top of all others.
SetForegroundWindow(Self.h
end;
procedure TForm1.FormDestroy(Sender:
begin
if mutex <> 0 then
begin
Shell_NotifyIcon(NIM_DELET
CloseHandle(mutex);
end;
end;
procedure TForm1.Exit1Click(Sender: TObject);
begin
Close;
end;
end.
ASKER
Thanks Epsylon,
But how do I pass the icon in the tray as a PChar. I have tried PChar(strayReadyToPrint.Ic on.GetName Path) without success.
But how do I pass the icon in the tray as a PChar. I have tried PChar(strayReadyToPrint.Ic
Pass the icon in the tray as a PChar?????
ASKER
yep that is what CreateMutex is looking for. Anyways, I figured it out, but now I get an external exception when I try to call CloseHandle....
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
ok, i am with you now. but I still have a problem with it; mutex never gets set back to 0, do I need to set this to 0 when removing the icon? I currently get an exception in the main else when closing the handle. Here is sample code.
if (condition is met to put add icon to tray) then
begin
mutex := CreateMutex(nil, true, 'READY TO PRINT ICON');
if mutex <> 0 then
if GetLastError <> ERROR_ALREADY_EXISTS then
strayReadyToPrint.Active := True //adds icon
else
CloseHandle (mutex); //remove handle
end
else
begin
strayReadyToPrint.Active := False; //removes icon
if mutex <> 0 then
CloseHandle(mutex);
end;
if (condition is met to put add icon to tray) then
begin
mutex := CreateMutex(nil, true, 'READY TO PRINT ICON');
if mutex <> 0 then
if GetLastError <> ERROR_ALREADY_EXISTS then
strayReadyToPrint.Active := True //adds icon
else
CloseHandle (mutex); //remove handle
end
else
begin
strayReadyToPrint.Active := False; //removes icon
if mutex <> 0 then
CloseHandle(mutex);
end;
ASKER
Epsylon,
ok, i figured it out. Because I have the above function tied to a timer event, I need to do it a little differently. But I am still using CreateMutex.
Thanks for the help Epsylon. It works awesome. Post an answer and I will accept with high grade.
Thanks again.......
Rick
ok, i figured it out. Because I have the above function tied to a timer event, I need to do it a little differently. But I am still using CreateMutex.
Thanks for the help Epsylon. It works awesome. Post an answer and I will accept with high grade.
Thanks again.......
Rick
ASKER
Thanks Epsylon
Oh well, I was about to look at your code :o)
Thank you too.
Btw, setting mutex:=0 after CloseHandle is a wise idea if you re-use the mutex handle.
Thank you too.
Btw, setting mutex:=0 after CloseHandle is a wise idea if you re-use the mutex handle.
ASKER
yep, that is exactly what I did, plus a few other minor changes to take in account the timer.
I don't know if i understood you well, but if you want only one image in system tray, when u run ur program check it there are any instance, if it's the first instanece place an image in the system tray, if there are any instance, that's mean there's one already and u don't want to add another one
Mohammed