Solved

Application not closing when Windows shut down

Posted on 1998-11-30
21
359 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
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
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
 
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

Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi selector screen 2 84
LAN or WAN ? 11 95
SUM 2 INTEGER ARRAYS INTO 1 10 108
PHP preg_replace code convert to Delphi 14 68
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
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…
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…

830 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