Solved

Application not closing when Windows shut down

Posted on 1998-11-30
21
354 Views
Last Modified: 2010-04-04
I have an application that runs in the tray, it has a hidden main window with a pop-up menu and a tray icon.  Everything runs fine expect when I go to shut down windows it will not shut down.  I don't know which message windows sends at shut down, but I tried handling (via Applicaiton.OnMessage) WM_CLOSE, WM_QUIT, WM_ENDSESSION and calling Application.Terminate for each.  I put in a showmessage so I would know if the message was received. I never got the showmessage to work, so I think the application is simply not processing Windows messsages propertly.  The inconsistent thing is I have a 'terminate' option on my popup menu that appears when you right click on the tray icon.  If I try to close the app this way, it works fine.  Anyone know why my app won't process messages?
0
Comment
Question by:pswenson
  • 8
  • 4
  • 2
  • +6
21 Comments
 
LVL 8

Expert Comment

by:ZifNab
ID: 1348619
Hi pswenson,

First, read this article and be sure you work that way to make your tray application. If the problem persists send us some code so we can search for a possible cause.

http://www.delumpa.com/tips/apps/apps3.htm

Regards, Zif.
0
 

Author Comment

by:pswenson
ID: 1348620
Upon further testing I think the tray has nothing to do with the problem.  The app creates some TThread descendents that have to be terminated when the project is shut down.  If I don't create the Threads, it shuts down fine.  I also wrote a test app that sends my main app a WM_CLOSE or a WM_QUIT message, both of which shut it down properly (although I notice WM_QUIT shuts it down faster).  I ran WinSpecter to see what messages get sent to the app at shut-down and didn't see any.  So I guess that leads me to the question "how does windows shut down the apps when you click start/restart or start/shutdown?"
0
 
LVL 12

Expert Comment

by:rwilson032697
ID: 1348621
Windows sends WM_QUIT messages to all app when shutting down.

Cheers,

Raymond.
0
 
LVL 7

Expert Comment

by:ahalya
ID: 1348622
Windows send the "QueryEndSession" message followed by "EndSession". if your app doesn't close for the "EndSession" Windows will then display that dreaded "application not responding - Wait, Kill or cancel" mesage.

When you receive the WM_EndSession, check the wparam to make sure that windows is closing.
0
 

Author Comment

by:pswenson
ID: 1348623
I don't see ANY messages begin sent to my app with WinSpector at shut-down.  I can see those messages during a normal run though.  I can send an END_SESSION or WM_QUIT message normally from a little test app and shut down my app.  During shut-down it just doesn't work!  I always get the "application not responding" message.  I don't get it!
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 1348624
pwenson, maybe some code would be helpfull?
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1348625
Try something like this...

OnMessage()
begin
  case Msg of
    WM_QUIT, WM_CLOSE, WM_QUERYENDSESSION, WM_ENDSESSION :            Application.Terminate;
  end;
end;

Cheers,
Viktor†
0
 

Author Comment

by:pswenson
ID: 1348626
I tried Viktornet's solution, it didn't work...

The purpose of the project is to use Win NT file notification to automatically convert DFMs to text files when they are written to disk (and vice versa).  The app should stay down in the tray and have a popup that lets the user bring up a config screen, force conversion on a particular directory or file, and terminate.  Everything works great except when you shut windows down.

The code uses several components but I will post most of it.  The main form creates a bunch of datamodules that use components encapsulating TThread descendents}
unit frm_Main;
{===================================================================================================
  Description:  Main form for DFM Converter
  Usage: Hidden form, never interacted with except thru the TrayIcon's pop-up menu
  Copyright© 1998 Corporate Express, Inc.

  Keywords:
  $Author: Phil Swenson$
  $Date: 11/24/98 10:50:36 AM$
  $Workfile: C:\Prj\Dev\DFM Converter\D4\src\frm_Main.pas$
  $Project: DFM Converter$
  $Revision: 4$
  $Folder: src$
===================================================================================================}
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, TrayIcon,
  dlg_Properties, dlg_ForceConvert, StdCtrls, ExtCtrls, ThreadedTimer, uDFMConverterGlobals
  {$IFDEF DEBUG}, RzCSIntf{$ENDIF};

type

  TfrmMain = class(TForm)
    TrayNotifyIcon: TTrayNotifyIcon;
    PopupMenu: TPopupMenu;
    menuProperties: TMenuItem;
    menuTerminate: TMenuItem;
    menuForceConvert: TMenuItem;
    procedure menuPropertiesClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure menuTerminateClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure menuForceConvertClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
    Log: TStringList;
    DirectoryWatchList: TList;
    dlgProperties: TdlgProperties;
    dlgForceConvert: TdlgForceConvert;
    function GetTextExtension: string;
    procedure LoadConfigData;
    procedure StartWatch(const sDirectoryToWatch, sTextExtension: string; const bWatchSubTree);
    procedure FreeAllWatches;
    procedure EnableAllWatches;
    procedure DisableAllWatches;
    procedure ShowPropertiesDialog;
    procedure ForceConvert;
    procedure MsgHandler(var Msg: TMsg; var Handled: Boolean);
  public
    { Public declarations }
  end;

var
  frmMain: TfrmMain;

implementation
uses dm_DirectoryWatcher, uDFMConverterPersist;
{$R *.DFM}
procedure TfrmMain.FormCreate(Sender: TObject);
begin
  TrayNotifyIcon.IconVisible:= True;
  DirectoryWatchList:= TList.Create;
  Log:= TStringList.Create;
  LoadConfigData;
  dlgProperties:= nil;
  dlgForceConvert:= nil;
  Application.OnMessage:= MsgHandler;
end;

procedure TfrmMain.MsgHandler(var Msg: TMsg; var Handled: Boolean);
begin
  case Msg.Message of
    WM_QUIT, WM_CLOSE, WM_QUERYENDSESSION, WM_ENDSESSION:
      Application.Terminate;
  end;    
end;

procedure TfrmMain.menuPropertiesClick(Sender: TObject);
begin
  ShowPropertiesDialog;
end;

procedure TfrmMain.ShowPropertiesDialog;
begin
  if Assigned(dlgProperties) then
  begin
    dlgProperties.BringToFront;
    Exit;
  end;
  dlgProperties:= TdlgProperties.Create(nil);
  try
    if dlgProperties.ShowModal = mrOK then
      LoadConfigData;
  finally
    try
      dlgProperties.Free;
    finally
      dlgProperties:= nil;
    end;
  end;
end;

procedure TfrmMain.LoadConfigData;
var
  iCount: Integer;
  DirectoryList: TDirectoryArray;
  ConverterPers: TDFMConverterPersistentData;
  DirectoryData: TDirectoryData;
  sTextExtension: string;
begin
  ConverterPers:= TDFMConverterPersistentData.Create;
  try
    FreeAllWatches;
    if not ConverterPers.ConverterEnabled then Exit;
    sTextExtension:= ConverterPers.TextFileExtension;
    //ConverterPers.LogFileEnabled;
    //ConverterPers.LogFilePath;
    DirectoryList:= ConverterPers.DirectoryList;
  finally
    ConverterPers.Free;
  end;

  for iCount:= Low(DirectoryList) to High(DirectoryList) do
  begin
    DirectoryData:= DirectoryList[iCount];
    if DirectoryData.DirectoryToWatch <> '' then
      StartWatch(DirectoryData.DirectoryToWatch, sTextExtension, DirectoryData.WatchSubTree);
  end;
end;

procedure TfrmMain.StartWatch(const sDirectoryToWatch, sTextExtension: string; const bWatchSubTree);
var
  dmDirectoryWatcher: TdmDirectoryWatcher;
begin
  dmDirectoryWatcher:= TdmDirectoryWatcher.Create(nil);
  DirectoryWatchList.Add(dmDirectoryWatcher);
  with dmDirectoryWatcher do
  begin
    DirectoryToWatch:= sDirectoryToWatch;
    TextExtension:= sTextExtension;
    Enabled:= True;
  end;
end;

procedure TfrmMain.FreeAllWatches;
var
  dmDirectoryWatcher: TdmDirectoryWatcher;
  iCount: Integer;
begin
  for iCount:= DirectoryWatchList.Count - 1 downto 0 do
  begin
    dmDirectoryWatcher:= DirectoryWatchList[iCount];
    dmDirectoryWatcher.Free;
  end;
  DirectoryWatchList.Clear;
end;

procedure TfrmMain.DisableAllWatches;
var
  dmDirectoryWatcher: TdmDirectoryWatcher;
  iCount: Integer;
begin
  for iCount:= DirectoryWatchList.Count - 1 downto 0 do
  begin
    dmDirectoryWatcher:= DirectoryWatchList[iCount];
    dmDirectoryWatcher.Enabled:= False;
  end;
end;

procedure TfrmMain.EnableAllWatches;
var
  dmDirectoryWatcher: TdmDirectoryWatcher;
  iCount: Integer;
begin
  for iCount:= DirectoryWatchList.Count - 1 downto 0 do
  begin
    dmDirectoryWatcher:= DirectoryWatchList[iCount];
    dmDirectoryWatcher.Enabled:= True;
  end;
end;

procedure TfrmMain.menuTerminateClick(Sender: TObject);
begin
  Close;
end;

function TfrmMain.GetTextExtension: string;
var
  ConverterPers: TDFMConverterPersistentData;
begin
  ConverterPers:= TDFMConverterPersistentData.Create;
  try
    Result:= ConverterPers.TextFileExtension;
  finally
    ConverterPers.Free;
  end;
end;

procedure TfrmMain.menuForceConvertClick(Sender: TObject);
begin
  ForceConvert;
end;

procedure TfrmMain.ForceConvert;
var
  sTextExt: string;
begin
  if Assigned(dlgForceConvert) then
  begin
    dlgForceConvert.BringToFront;
    Exit;
  end;
  DisableAllWatches;
  try
    sTextExt:= GetTextExtension;
    dlgForceConvert:= TdlgForceConvert.Create(nil);
    dlgForceConvert.TextExtension:= sTextExt;
    dlgForceConvert.ShowModal;
    try
      dlgForceConvert.Free;
    finally
      dlgForceConvert:= nil;
    end;
  finally
    EnableAllWatches;
  end;
end;

procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  FreeAllWatches;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  DirectoryWatchList.Free;
  Log.Free;
end;


end.
0
 

Author Comment

by:pswenson
ID: 1348627
The datamodule code is below...the rest of the code a tray icon component, a threaded timer, and a file notification component (using a thread per component).  There is one threaded timer and one file notification component per data module.  The tray icon component is on the main form.  There are also some utility units that should have no bearing on this problem (screens to edit properties, unit to save/load configuration).

unit dm_DirectoryWatcher;
{===================================================================================================
  Description:  Watches directory and converts files
  Usage: One instance created per directory to be watched
  Copyright© 1998 Corporate Express, Inc.

  Keywords:
  $Author: Phil Swenson$
  $Date: 11/30/98 8:37:14 AM$
  $Workfile: C:\Prj\Dev\DFM Converter\D4\src\dm_DirectoryWatcher.pas$
  $Project: DFM Converter$
  $Revision: 4$
  $Folder: src$
===================================================================================================}
interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  DirWatch, ThreadedTimer, uUtils, uDFMConverterGlobals, SyncObjs{$IFDEF DEBUG}, RzCSIntf{$ENDIF};

type
  TdmDirectoryWatcher = class;
  TFileItem = class
    FileName: string;
    Extension: string;
    Valid: Boolean;
  end;

  TdmDirectoryWatcher = class(TDataModule)
    tmQueueCheck: TThreadedTimer;
    DirWatch: TDirWatch;
    procedure dmDirectoryMonitorDestroy(Sender: TObject);
    procedure dmDirectoryMonitorCreate(Sender: TObject);
    procedure DirWatchNotify(Sender: TObject; Action: Integer; const FileName: string);
    procedure tmQueueCheckTimer(Sender: TObject);
  private
    { Private declarations }
    NoConvertList: TStringList;
    iQueueCount, iOldQueueCount: integer;
    FileQueue: TList;
    FsTextExtension: string;
    bNoConvertListEmpty, bFileConverted: Boolean;
    CriticalSection: TCriticalSection;
    function ProcessQueue: Boolean;
    procedure ConvertFile(FileItem: TFileItem);
    function GetFullPath(const sFileName: string): string;
    function GetDirectoryToWatch: string;
    procedure SetDirectoryToWatch(const Value: string);
    function GetDirWatchEnabled: Boolean;
    procedure SetDirWatchEnabled(const Value: Boolean);
    procedure SetTextExtension(const Value: string);
    procedure CleanUpFileQueue;
  public
    { Public declarations }
    property DirectoryToWatch: string read GetDirectoryToWatch write SetDirectoryToWatch;
    property Enabled: boolean read GetDirWatchEnabled write SetDirWatchEnabled;
    property TextExtension: string read FsTextExtension write SetTextExtension;
  end;

implementation

{$R *.DFM}

procedure TdmDirectoryWatcher.dmDirectoryMonitorCreate(Sender: TObject);
{$IFDEF DEBUG}const sRoutine = 'TdmDirectoryWatcher.dmDirectoryMonitorCreate';{$ENDIF}
begin
  {$IFDEF DEBUG}CodeSite.EnterMethod(sRoutine);{$ENDIF DEBUG}
  CriticalSection:= TCriticalSection.Create;
  FileQueue:= TList.Create;
  NoConvertList:= TStringList.Create;
  iQueueCount:= 0;
  iOldQueueCount:= 0;
  bNoConvertListEmpty:= True;
  {$IFDEF DEBUG}CodeSite.ExitMethod(sRoutine);{$ENDIF DEBUG}
end;

procedure TdmDirectoryWatcher.dmDirectoryMonitorDestroy(Sender: TObject);
{$IFDEF DEBUG}const sRoutine = 'TdmDirectoryWatcher.dmDirectoryMonitorDestroy';{$ENDIF}
var
  iCount: Integer;
  FileItem: TFileItem;
begin
  {$IFDEF DEBUG} CodeSite.EnterMethod(sRoutine); {$ENDIF}
  DirWatch.Enabled:= False;
  tmQueueCheck.Enabled:= False;
  for iCount:= 0 to FileQueue.Count - 1 do
  begin
    FileItem:= FileQueue.List[iCount];
    FileItem.Free;
  end;
  FileQueue.Free;
  NoConvertList.Free;
  CriticalSection.Free;
  {$IFDEF DEBUG} CodeSite.ExitMethod(sRoutine); {$ENDIF}
end;


function TdmDirectoryWatcher.GetDirectoryToWatch: string;
begin
  Result:= DirWatch.Directory;
end;

procedure TdmDirectoryWatcher.SetDirectoryToWatch(const Value: string);
begin
  DirWatch.Directory:= Value;
end;

procedure TdmDirectoryWatcher.SetTextExtension(const Value: string);
begin
  FsTextExtension:= LowerCase(Value);
end;

function TdmDirectoryWatcher.GetDirWatchEnabled: Boolean;
begin
  Result:= DirWatch.Enabled;
end;

procedure TdmDirectoryWatcher.SetDirWatchEnabled(const Value: Boolean);
begin
  DirWatch.Enabled:= Value;
  tmQueueCheck.Enabled:= Value;
end;

{ Notification that a file has changed from the DirWatch component }
procedure TdmDirectoryWatcher.DirWatchNotify(Sender: TObject; Action: Integer;
        const FileName: String);
{$IFDEF DEBUG}const sRoutine = 'TdmDirectoryWatcher.DirWatchNotify';{$ENDIF}
var
  sFileName, sExtension: string;
  FileItem: TFileItem;
  iLength: Integer;
begin
  {$IFDEF DEBUG} CodeSite.EnterMethod(sRoutine);{$ENDIF}
  try
    { can't process files that don't exist or don't exist by that name }
    case Action of
      FILE_ACTION_REMOVED:
      begin
        CriticalSection.Enter;
        try
          bNoConvertListEmpty:= False;
          NoConvertList.Add(FileName);
        finally
          CriticalSection.Leave;
        end;
        Exit;
      end;
      FILE_ACTION_RENAMED_OLD_NAME: Exit;
    end;
    sFileName:= FileName;
    sExtension:= LowerCase(ExtractFileExt(sFileName));
    { Only care about text files and form files }
    if (sExtension <> sFORM_FILE_EXTENSION) and (sExtension <> FsTextExtension) then Exit;
    FileItem:= TFileItem.Create;
    { FileItem.FileName includes the path relative to  DirWatch.Directory + FileName - FileExt }
    iLength:= Length(sFileName) - Length(sExtension);
    FileItem.FileName:= Copy(sFileName, 1, iLength);
    FileItem.Extension:= sExtension;
    FileItem.Valid:= True;
    CriticalSection.Enter;
    try
      FileQueue.Add(FileItem);
      {$IFDEF DEBUG} CodeSite.SendMsg(sFileName + ' added to queue'); {$ENDIF}
      iQueueCount:= FileQueue.Count;
    finally
      CriticalSection.Leave;
    end;
  finally
    {$IFDEF DEBUG} CodeSite.ExitMethod(sRoutine); {$ENDIF}
  end;
end;

{ removes invalid and redundant items form queue }
procedure TdmDirectoryWatcher.CleanUpFileQueue;
{$IFDEF DEBUG}const sRoutine = 'TdmDirectoryWatcher.CleanUpFileQueue';{$ENDIF}
var
  sFileName, sFileNameToCheck, sNoConvertFile: string;
  iFileQueueCount, iCount, iCount2: Integer;
  FileItem, FileItemToCheck: TFileItem;
begin
  {$IFDEF DEBUG} CodeSite.EnterMethod(sRoutine); {$ENDIF}
  iFileQueueCount:= FileQueue.Count;
  for iCount:= 0 to FileQueue.Count - 1 do
  begin
    FileItem:= FileQueue.Items[iCount];
    sFileName:= FileItem.FileName;
    for iCount2:= iCount + 1 to iFileQueueCount - 1 do
    begin
      FileItemToCheck:= FileQueue.Items[iCount2];
      if FileItemToCheck.Valid then
      begin
        sFileNameToCheck:= FileItemToCheck.FileName;
        if CompareText(sFileNameToCheck, sFileName) = 0 then
          FileItemToCheck.Valid:= False;
      end;
    end;
    if FileItem.Valid then
      for iCount2:= 0 to NoConvertList.Count - 1 do
      begin
        sNoConvertFile:= NoConvertList[iCount2];
        if CompareText(sNoConvertFile, sFileName) = 0 then
          FileItem.Valid:= False;
      end;
  end;
  {$IFDEF DEBUG} CodeSite.ExitMethod(sRoutine); {$ENDIF}
end;

function TdmDirectoryWatcher.GetFullPath(const sFileName: string): string;
begin
   Result:= DirWatch.Directory + '\' + sFileName;
end;

{ Converts a text to DFM or vice versa }
procedure TdmDirectoryWatcher.ConvertFile(FileItem: TFileItem);
{$IFDEF DEBUG}const sRoutine = 'TdmDirectoryWatcher.ConvertFile';{$ENDIF}
var
  sFileName, sNewFileName, sFullPathName: string;
begin
  {$IFDEF DEBUG} CodeSite.EnterMethod(sRoutine); {$ENDIF}
  bFileConverted:= True;
  sFullPathName:= GetFullPath(FileItem.FileName);
  sFileName:=  sFullPathName + FileItem.Extension;
  NoConvertList.Add(FileItem.FileName);
  bNoConvertListEmpty:= False;
  if FileItem.Extension = sFORM_FILE_EXTENSION then
  begin
    {$IFDEF DEBUG} CodeSite.SendMsg(sFileName + ' preconvert from DFM to text'); {$ENDIF}
    sNewFileName:=  sFullPathName + FsTextExtension;
    try
      TFileUtils.DFM2TXT(sFileName, sNewFileName);
      {$IFDEF DEBUG} CodeSite.SendMsg(sFileName + ' converted from DFM to Text'); {$ENDIF}
    except
      on E: Exception do
      begin
        {$IFDEF DEBUG} CodeSite.SendError('Error on converting DFM to Text: ' + E.Message); {$ENDIF}
        raise;
      end;
    end;
  end
  else { Text Extension }
  begin
    sNewFileName:= sFullPathName + sFORM_FILE_EXTENSION;
    {$IFDEF DEBUG} CodeSite.SendMsg(sFileName + ' preconvert from Text to DFM'); {$ENDIF}
    try
      TFileUtils.TXT2DFM(sFileName, sNewFileName);
      {$IFDEF DEBUG} CodeSite.SendMsg(sFileName + ' converted from Text to DFM'); {$ENDIF}
    except
      on E: Exception do
      begin
        {$IFDEF DEBUG} CodeSite.SendError('Error on converting Text to DFM: ' + E.Message); {$ENDIF}
        raise;
      end;
    end;
  end;
  {$IFDEF DEBUG} CodeSite.ExitMethod(sRoutine); {$ENDIF}
end;

{ iterates thru queue, elimiates redundant/invalid items, then does proper conversions }
function TdmDirectoryWatcher.ProcessQueue: Boolean;
{$IFDEF DEBUG}const sRoutine = 'TdmDirectoryWatcher.ProcessQueue';{$ENDIF}
var
  sFileName: string;
  iCount: Integer;
  FileItem: TFileItem;
begin
  {$IFDEF DEBUG} CodeSite.EnterMethod(sRoutine); {$ENDIF}
  Result:= False;
  CleanUpFileQueue;
  for iCount:= 0 to FileQueue.Count - 1 do
  begin
    FileItem:= FileQueue[iCount];
    sFileName:= FileItem.FileName;
    if FileItem.Valid then
    begin
      Result:= True;
      ConvertFile(FileItem);
    end;
    FileItem.Free;
    FileQueue[iCount]:= nil;
  end;
  FileQueue.Clear;
  iQueueCount:= 0;
  iOldQueueCount:= 0;
  {$IFDEF DEBUG} CodeSite.ExitMethod(sRoutine); {$ENDIF}
end;

procedure TdmDirectoryWatcher.tmQueueCheckTimer(Sender: TObject);
{$IFDEF DEBUG}const sRoutine = 'TdmDirectoryWatcher.tmQueueCheckTimer';{$ENDIF}
begin
  {$IFDEF DEBUG} CodeSite.EnterMethod(sRoutine); {$ENDIF}
  CriticalSection.Enter;
  try
    if iQueueCount <> 0 then
    begin
      if (iOldQueueCount = iQueueCount) then
        ProcessQueue
      else
        iOldQueueCount:= iQueueCount;
    end
    else
    begin
      if not bNoConvertListEmpty then
      begin
        NoConvertList.Clear;
        bNoConvertListEmpty:= True;
        {$IFDEF DEBUG} CodeSite.SendWarning('Clear convert list.'); {$ENDIF}
      end;
    end;
  finally
    CriticalSection.Leave;
  end;
  {$IFDEF DEBUG} CodeSite.ExitMethod(sRoutine); {$ENDIF}
end;



initialization
  {$IFDEF DEBUG}CodeSite.Clear;{$ENDIF}
end.
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1348628
well i have no idea why this doesn't work...maybe something with the WinNT. o O

Why don't you try using Handled := True; where you terminate the app...
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 3

Expert Comment

by:philipleighs
ID: 1348629
There was a question posted a while back about an app that prevented windows from shutting down.
The problem turned out to be that the window state of the main form was set to wsMinimised.
By replacing the code with
Application.Minimize;
everything was fine.
Is WindowState set to wsMinimised in the object inspector? If so, try setting it to wsNormal and put Application.Minimize in the FormCreate event.

Cheers, Phil.

0
 
LVL 7

Expert Comment

by:ahalya
ID: 1348630
Another possibility is that "Application.Terminate" only sets the variable Application.terminated to true.  Unless your code goes to a loop where the delphi (or you) issue a

if application.terminated then close;

the app will look like "not responding" to windows.  You can check this very easily by using a Halt(0) instead of Application.Terminate in your message handler.

0
 
LVL 7

Expert Comment

by:jconde
ID: 1348631
Hmm...I didn't check your code out...too big for a small netscape screen :)

check the following out, it might help you:
http://www.experts-exchange.com/Q.10085856
0
 

Author Comment

by:pswenson
ID: 1348632
ahalya:  Application.Terminate posts a WM_QUIT to the app.  Check
the help.  I tried a Halt, it doesn't work either.

jconde:  that question was the same, but the solution didn't apply.

I have also tried doing an application.hookmainwindow and intercepting a wm_endsession there to no avail...

I really think that the threads are screwing things up, I just don't know why...
0
 

Author Comment

by:pswenson
ID: 1348633
Adjusted points to 300
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1348634
well if the threads are screwing up things, then do something like this...

OnMessageHandle()
begin
  case Msg.Message of
    WM_QUIT, WM_CLOSE, WM_ENDSESSION, WM_QUERYENDSESSION :
    begin
      StopAllTheThreads; //This is some kind of function that stops the threads... you can also               //destroy the threads and free them here, and then do the Application.Terminate;
      Application.Terminate;
    end;
  end;
end;

Hope this helps,,,

Cheers,
Viktor
0
 

Author Comment

by:pswenson
ID: 1348635
viktornet:  In effect that is what is happening in my code.  I call freeallwatches on the close event of the form.  FreeAllWatches will stop and free all the threads.  The close call never happens though because the message is never received.

The problem is the message doesn't get through to begin with.  I tried something that worked:  I subclassed the Application's window (that is intercepted it's WndProc) and made the main window so it was visible (got rid of Application.ShowMainWindow:= False in the project source)...this caused it to work.  Only doing one of the two didn't solve the problem, it had to be both.  This solution is not acceptable though...I don't want my main window showing.  If I minimize my main window and then try shutting down windows, it fails to close the program...For whatever reason, the application appears not to be processing messages when the main window is not visible.. I don't get it!
0
 
LVL 10

Expert Comment

by:viktornet
ID: 1348636
How about putting Application.ProcessMessages;
somewhere in your code after you do the Application.ShowMainForm := False; ??? Do you think that would work?? I'll ask you to try to put the FreeAllWatches; where you check for the messages with the case statement, other than in the Close() handler...

case msg.message of
//Messages :
begin
  FreeAllWatches;
  Application.Terminate;
end;
end;

and something similar to this,.
0
 

Author Comment

by:pswenson
ID: 1348637
I figured it out!  One of the components was allocating it's own windows (AllocateHwnd) and in the wndproc it wasn't calling "DefWindowProc(FWndHandle, M.Msg, M.wParam, M.lParam);".  I'm not sure why this only had an effect at shut-down, but that's the only place it ever caused a problem.
0
 
LVL 1

Expert Comment

by:Romanian
ID: 1348638
If you use TTrayIcon component you must correct this procedure
=====
procedure TTrayIcon.WndProc(var msg : TMessage);
var MouseCo: Tpoint;
begin
   with msg do
      if (msg = WM_RESETTOOLTIP) then
         SetToolTip( fToolTip )
      else if (msg = WM_TOOLTRAYICON) then begin
         case lParam of
            WM_LBUTTONDBLCLK   : if assigned (FOnDblClick) then FOnDblClick(self);
            WM_LBUTTONUP       : if assigned(FOnClick)then FOnClick(self);
            WM_RBUTTONUP       : if assigned (FOnRightClick)then
                                 begin
                                   GetCursorPos(MouseCo);
                                   FOnRightClick(self,mbRight,[],MouseCo.x,MouseCo.y);
                                 end;
         end;
      end
//I add next code. may be it usefull for you
else if (msg = WM_QUERYENDSESSION) then
                 Result := Longint(True)
               else if (msg = WM_ENDSESSION) then
                 Application.Terminate;

end;
====
in constructor
====
constructor TTrayIcon.create(aOwner : Tcomponent);
begin
  inherited create(aOwner);
  FWindowHandle := AllocateHWnd( WndProc );
  FIcon := TIcon.Create;
end;

This code tested under NT 4.0

0
 
LVL 7

Accepted Solution

by:
linda101698 earned 300 total points
ID: 1348639
I am posting the solution found by so it can be saved in the previously asked questions.  Please see your customer service question for an explanation.

Linda Gardner
Customer Service @ Experts Exchange

Comment
     From: pswenson
                                 Date: Thursday, December 03 1998 - 01:32PM PST

     I figured it out!  One of the components was allocating it's own windows
     (AllocateHwnd) and in the wndproc it wasn't calling
     "DefWindowProc(FWndHandle, M.Msg, M.wParam, M.lParam);".  I'm not
     sure why this only had an effect at shut-down, but that's the only place it ever
     caused a problem.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

757 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

18 Experts available now in Live!

Get 1:1 Help Now