Solved

Application does not terminate on shutdown

Posted on 1997-05-14
9
321 Views
Last Modified: 2010-04-04
I coded an application with delphi2 which runs in the system tray.
I am using the TrayIcon component for this.
But when shutting down Windows while my application runs, it does only terminate if it is not minimized.
Seems as if it could have something to do with TrayIcon...

Of course I read several FAQs on this topic and found some hints concerning WM_QUERYENDSESSION and WM_ENDSESSION, but if my application is minimized the message handler does not even get the WM_QUERYENDSESSION message.

What's wrong?
0
Comment
Question by:tier
  • 5
  • 3
9 Comments
 
LVL 3

Accepted Solution

by:
sperling earned 100 total points
Comment Utility
Hmmm. I wrote a trayicon component once which in its first revision had this problem... I had not added handling for WM_QUERYENDSESSION to the trayicons message handler. This could very well be the problem, try to return 1 for this message in the  trayicons windowproc. If you've got source, please post the message handler and I'll look at it.

Regards,

Erik.
0
 
LVL 1

Author Comment

by:tier
Comment Utility
The TrayIcon's WindowProc is as follows. I do not really know how to do the changes you proposed. Please have a look and tell me:

procedure TTrayIcon.WndProc(var Msg:TMessage);
begin
     with Msg
     do
       begin
            if msg = WM_CallBack_Message
            then
                case lParam
                of
                  WM_LButtonDblClk : if Assigned(fOnDblClick) then fOnDblClick(Self);
                  WM_LButtonUp     : if Assigned(fOnClick) then fOnClick(Self);
                  WM_RButtonUp     : HandleRightClick(Self);
                end
            else
                Result:=DefWindowProc(fWindowHandle,Msg,wParam,lParam);
       end;
end;

0
 
LVL 1

Author Comment

by:tier
Comment Utility
Adjusted points to 100
0
 
LVL 1

Author Comment

by:tier
Comment Utility
Hello?! Anyone out there?
Please answer the question, it's urgent...
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 3

Expert Comment

by:sperling
Comment Utility
Could you post the entire TrayIcon source file, or point me to the URL where you found it.

Regards,

Erik.
0
 
LVL 1

Author Comment

by:tier
Comment Utility
OK, this is the entire source:

unit TrayIcon;

{ TrayIcon v1.0
  Copyright (c) 1996 James Roberts-Thomson (com3roberjd@ntu.ac.uk)

  Based on TrayIcon v1.1, Tempest Software and
           TrayIcon v1.3, Peter Ness (102347.710@compuserve.com)

  A Delphi2 component designed to make creating SystemTray icons easier.
  Adding this component to a form, and when the control is active, the
  application will minimize to the SystemTray instead of the TaskBar.
  A popup menu may be made available (via a right-click on the icon).

  The component operates in two modes - if the "SeparateIcon" property is
  False (default), then the SysTray icon only appears when/if the application
  is minimized.  Setting the "SeparateIcon" property true allows both taskbar
  and SystemTray icons to appear, and also a SystemTray icon when the
  application isn't minimized.

  Requires Delphi 2.0 (32-bit), and either Windows95 or Windows-NT v4.0
  Component will compile and run with NT v3.51; but functionality is
  automatically disabled (NT v3.51 doesn't have a SystemTray).

  This component is Freeware, as were those it was based on.  You may freely
  use this component in any Application (be it Commercial, Shareware, or
  Freeware) without fee or royalty, provided this copyright notice remains
  intact.  Some minor form of recognition for commercial or shareware software
  would be nice.
 }

interface

uses
  Windows, Messages, SysUtils, ShellApi, Classes, Graphics, Controls,
  Forms, Menus;

Const WM_CallBack_Message = WM_User + 1;

type
  TTrayIcon = class(TComponent)
  private
    {Properties}
    fActive:Boolean;
    fHint:String;
    fIcon:TIcon;
    fPopupMenu:TPopupMenu;
    fSeparateIcon:Boolean;

    {events}
    fOnClick:TNotifyEvent;
    fOnDblClick:TNotifyEvent;
    fOnRightClick:TMouseEvent;
    fOnMinimize:TNotifyEvent;
    fOnRestore:TNotifyEvent;

    {Internal variables}
    fData:TNotifyIconData;
    fWindowHandle:hwnd;
    fWinVer4:Boolean;
    fMinimized:Boolean;
    fNoTrayIcon:Boolean;

  protected
    procedure SetActive(Value:Boolean);
    procedure SetHint(Value:String);
    procedure SetIcon(Icon:TIcon);
    procedure SetSeparateIcon(Value:Boolean);

    procedure AddIconToTray;
    procedure RemoveIconFromTray;
    procedure UpdateTrayIcon;
    procedure WndProc(var Msg:TMessage);
    procedure HandleRightClick(Sender:TObject);
    procedure HandleMinimize(Sender:TObject);
    procedure HandleRestore(Sender:TObject);

  public
    constructor Create(Owner:TComponent); override;
    destructor Destroy; override;

  published
    property Active:Boolean read fActive write SetActive;
    property Hint:string read fHint write SetHint;
    property Icon:TIcon read fIcon write SetIcon;
    property PopupMenu:TPopupmenu read fPopupMenu write fPopupMenu;
    property SeparateIcon:Boolean read fSeparateIcon write SetSeparateIcon;

    property OnClick:TNotifyEvent read fOnClick write fOnClick;
    property OnDblClick:TNotifyEvent read fOnDblClick write fOnDblClick;
    property OnRightClick:TMouseEvent read fOnRightClick write fOnRightClick;
    property OnMinimize:TNotifyEvent read fOnMinimize write fOnMinimize;
    property OnRestore:TNotifyEvent read fOnRestore write fOnRestore;
  end;

procedure Register;

implementation

{Create the Component}
constructor TTrayIcon.Create(Owner:TComponent);
var Hint:String;
    OSVerInfo:TOSVersionInfo;
    WindowPlacement:TWindowPlacement;
begin
     {Call inherited create method}
     Inherited Create(Owner);

     {Create the fIcon object, and assign the Application Icon to it}
     fIcon:=TIcon.Create;
     fIcon.Assign(Application.Icon);

     GetVersionEx(OSVerInfo);
     if OSVerInfo.dwMajorVersion > 3
     then
         fWinVer4:=True
     else
         fWinVer4:=False;

     fNoTrayIcon:=True;

     if not (csDesigning in ComponentState)
     then
         {At RunTime *only*, perform the following:}
         begin
              FillChar(fData, SizeOf(fData), 0);

              fWindowHandle:=AllocateHWnd(WndProc);

              fData.cbSize:=SizeOf(fData);
              fData.wnd:=fWindowHandle;
              fData.hIcon:=fIcon.Handle;
              fData.uFlags:=NIF_Icon OR NIF_Message;
              fData.uCallbackMessage:=WM_CallBack_Message;

              if fHint = ''
              then
                  Hint:=Application.Title
              else
                  Hint:=fHint;

              if Hint <> ''
              then
                  begin
                       fData.uFlags:=fData.uFlags OR NIF_Tip;
                       StrPLCopy(fData.szTip,Hint,SizeOf(fData.szTip)-1);
                  end;

              Application.OnMinimize:=HandleMinimize;
              Application.OnRestore:=HandleRestore;

              FillChar(WindowPlacement,SizeOf(WindowPlacement),0);
              WindowPlacement.length:=SizeOf(WindowPlacement);
              GetWindowPlacement(Application.Handle,@WindowPlacement);
              if WindowPlacement.showCmd = SW_ShowMinimized
              then
                  fMinimized:=True
              else
                  fMinimized:=False;

              if fActive and fMinimized
              then
                  AddIconToTray;
         end;
end;

{Destroy the Component}
destructor TTrayIcon.Destroy;
begin
     if fActive
     then
         RemoveIconFromTray;

     if not (csDesigning in ComponentState)
     then
         DeAllocateHWnd(FWindowHandle);

     fIcon.Free;
     inherited Destroy;
end;

procedure TTrayIcon.SetSeparateIcon(Value:Boolean);
begin
     if fSeparateIcon <> Value
     then
         fSeparateIcon:=Value;

     if not (csDesigning in ComponentState)
     then
         case fSeparateIcon
         of
           False:if fActive and (NOT fMinimized)
                 then
                     RemoveIconFromTray;
           True:if fActive
                then
                    AddIconToTray;
         end;
end;

procedure TTrayIcon.SetActive(Value:Boolean);
begin
     if fActive <> Value
     then
         fActive:=Value;

     if not (csDesigning in ComponentState)
     then
         if fActive and (fMinimized xor fSeparateIcon)
         then
             AddIconToTray
         else
             RemoveIconFromTray;
end;

procedure TTrayIcon.SetHint(Value:String);
begin
     if fHint <> Value
     then
         begin
              fHint:=Value;

              if not (csDesigning in ComponentState)
              then
                  begin
                       StrPLCopy(fData.szTip,fHint,SizeOf(fData.szTip)-1);
                       if fHint <> ''
                       then
                           fData.uFlags:=fData.uFlags OR NIF_Tip
                       else
                           fData.uFlags:=fData.uFlags AND NOT NIF_Tip;
                       UpdateTrayIcon;
                  end;
         end;
end;

procedure TTrayIcon.SetIcon(Icon:TIcon);
begin
     if fIcon <> Icon
     then
         begin
              fIcon.Assign(Icon);
              fData.hIcon:=Icon.Handle;
              UpdateTrayIcon;
         end;
end;

procedure TTrayIcon.AddIconToTray;
begin
     if fActive AND fWinVer4 AND fNoTrayIcon
     then
         if not Shell_NotifyIcon(NIM_Add,@fData)
         then
             raise EOutOfResources.Create('Cannot create shell notification icon')
         else
             fNoTrayIcon:=False;
end;

procedure TTrayIcon.RemoveIconFromTray;
begin
     if fWinVer4
     then
         Shell_NotifyIcon(NIM_Delete,@fData);
     fNoTrayIcon:=True;
end;

procedure TTrayIcon.UpdateTrayIcon;
begin
     if (fActive AND fWinVer4) AND not (csDesigning in ComponentState)
     then
         Shell_NotifyIcon(NIM_Modify,@fData);
end;

procedure TTrayIcon.WndProc(var Msg:TMessage);
begin
     with Msg
     do
       begin
            if msg = WM_CallBack_Message
            then
                case lParam
                of
                  WM_LButtonDblClk : if Assigned(fOnDblClick) then fOnDblClick(Self);
                  WM_LButtonUp     : if Assigned(fOnClick) then fOnClick(Self);
                  WM_RButtonUp     : HandleRightClick(Self);
                end
            else
                Result:=DefWindowProc(fWindowHandle,Msg,wParam,lParam);
       end;
end;

procedure TTrayIcon.HandleRightClick(Sender:TObject);
var CursorPos:TPoint;
begin
     if Assigned(fPopupMenu) AND ((NOT IsWindowVisible(Application.Handle)) OR
                                  fSeparateIcon)
     then
         begin
              GetCursorPos(CursorPos);
              fPopupMenu.Popup(CursorPos.X,CursorPos.Y);
         end;

     if Assigned(fOnRightClick)
     then
         fOnRightClick(Sender,mbRight,[],CursorPos.X,CursorPos.Y);
end;

procedure TTrayIcon.HandleMinimize(Sender:TObject);
begin
     if fActive
     then
         begin
              ShowWindow(Application.Handle,SW_Hide);
              if fNoTrayIcon
              then
                  AddIconToTray;
         end;
     fMinimized:=True;
     if Assigned(fOnMinimize)
     then
         fOnMinimize(Sender);
end;

procedure TTrayIcon.HandleRestore(Sender:TObject);
begin
     if fActive
     then
         begin
              ShowWindow(Application.Handle,SW_Restore);
              if not fSeparateIcon
              then
                  RemoveIconFromTray;
         end;
     if Assigned(fOnRestore)
     then
         fOnRestore(Sender);
     fMinimized:=False;
end;

procedure Register;
begin
  RegisterComponents('3rd Party', [TTrayIcon]);
end;

end.

0
 
LVL 3

Expert Comment

by:sperling
Comment Utility
Try changing WndProc a bit.
Change:
---
end
else
  Result:=DefWindowProc(fWindowHandle,Msg,wParam,lParam);
end;
---
To:
---
end else if msg.msg = WM_ENDSESSION then begin
  if (msg.wParam<>0) then begin
    Active := FALSE;
  end;
end else if msg.msg = WM_QUERYENDSESSION then begin
  msg.Result := WORD(TRUE);
end
else
  Result:=DefWindowProc(fWindowHandle,Msg,wParam,lParam);
end;



Might help, but I ain't sure....

Regards,

Erik.

0
 
LVL 13

Expert Comment

by:Mirkwood
Comment Utility
Bought This Question.
0
 
LVL 1

Author Comment

by:tier
Comment Utility
What does it mean?
Why did you 'buy' this damn old question?
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

771 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

12 Experts available now in Live!

Get 1:1 Help Now