A kinder way than TerminateProcess? - delphi

I have a backup app that will close user-defined running programs before the backup so that open data files can be closed and flushed before the backup. After the backup is complete it restarts the programs in the list.
I have no problem getting the window Handle using the Caption and PostMessage(AppHandle,WM_CLOSE,0,0); That works fine for most apps, but not for ones running in the Notification Area (System Tray)
Currently I am using TerminateProcess( and it works for those Notification Area apps, but it leaves files open as Windows bypasses any Close instructions and just slams those apps down.
I have searched long and hard and I cannot find a nicer way to shut down Notification Area apps. Can anyone please help?
Thanks

In order to close a program gracefully, you need to know something about how that program expects to be closed. If closing the main window accomplishes it, then you need to know how to recognize the "main" window.
Programs don't run "in" the notification area. They display icons there. Any program with a notification icon must also have a window (because the shell tells the program that the icon has been clicked by sending messages to the window). Even if the window isn't visible, it still must exist. If you can determine some set of properties that identify the window associated with a particular notification icon, then you could close it. There is no standard set of attributes to look for, though; each program can do it differently.
And even if you find the window you're looking for, closing it might not be the way the program expects to be terminated, either. It might expect a certain command from the notification icon's menu instead, or some message sent by a dialog box that the program displays.

If your application is running on Windows Vista or Windows 7, don't shut down programs - instead use the Volume Shadow Copy service to access a snapshot of the files while they are still in use. This is what the Windows 7 built-in backup program does.
If you're on an earlier version of Windows, there's no foolproof solution. If the program has a systray icon, it will have a hidden window as well, and you can try sending WM_QUERYENDSESSION and WM_ENDSESSION to it. However, there is no guarentee that the program will shut down, and if it does shut down, since you may be bypassing parts of its normal shutdown process, it may not complete its normal cleanup. There may also be programs running with no associated windows at all. The best approach would probably be to simply log off the user, and perform the backup from a service process. Of course, you'll still have sharing issues with files opened by other services...

Related

How to write a "child" application in Delphi like Office does?

Office 2016 behaves like an MDI application, although it isn't: if you open many files in Taskmgr.exe there is one EXCEL.EXE process running (tab "Details"):
But there are multiple entries in the tab "Processes" (which actually lists windows):
When I open the first file Excel starts slow. But when I open the second and third file Excel is faster than first.
How to do this in a Delphi program?
Windows' Task Manager unneedingly uses misleading terms to what actually happens:
The tab "Processes" actually lists windows for its category "Apps" and either succeeds in listing multiple windows for one process or doesn't. In older versions of Windows the Task Manager listed the windows this way, already having the suspicious tab title "Applications", but without grouping and associating multiple windows to one process:
The tab "Details" lists the actual processes that run, unbound to how many windows they have or display. In previous versions this tab was titled "Processes":
Which situation do we have? One process displaying multiple windows. This can be accomplished easily just like ages ago: you just ensure only running one instance which handles multiple documents. Does not even need to be a true MDI for that.
What you want on top is, that the Task Manager also groups multiple windows. How does Excel achieve this? Look at your taskbar: for each document a separate button exists, not only one in general for Excel itself. In your Delphi program you must ensure that each window must also appear on the taskbar: How to correctly have modeless form appear in taskbar along with its answer has evaluated many ways of doing so.
In Delphi you program one single application. It will have several secondary windows. The main window and the secondary windows shall have an MDI style.
When the application is started, it first looks if a copy of itself is already running. If not, it simply continues; if a previous copy is running, it sends to it the document (filename) that should be opened and then quits. The previously running application will open the passed document in a new secondary window.
This is the overall way of doing it. If there is something you don't know how to do then please open separate questions for each topic.
Please read the help pages, take the SO tour, read How to Ask, as well as this question checklist.

PCSCConnector and Windows 7

I'm using PCSCConnector from http://nobbi.com, last update - April 2004.
All work fine with Windows XP but with Windows 7 there has been some trouble.
When I press CTRL+F2 in the Delphi IDE (terminate) and a card connection had been opened by my software then any software (including my own) can't open a new connection to the card. I need to physically reconnect the card (USB in my case) to be able to create new connections to it.
I try to change dwScope in SCardEstablishContext to SCARD_SCOPE_SYSTEM (from SCARD_SCOPE_USER) and dwDisposition in SCardDisconnect to SCARD_LEAVE_CARD (from SCARD_RESET_CARD) but the problem persists.
When you use Ctrl+F2, it's a forceful termination. No code gets a chance to properly clean up, close things, or free anything - it's just shut down. No changes you make to the library's exit code is going to help, because it never gets a chance to run. You've stopped that from happening by forcefully terminating the app.
The solution: Don't use Ctrl+F2 for anything except runaway code you can't stop any other way. Close down your application normally the way it's supposed to be closed down, so it has a chance to clean things up and call finalization code and so forth.

"Call Rejected By Callee"

We're in the process of moving a slew of our applications from Windows XP to Windows 7 and have run into an old problem with Word Automation.
We had an issue in one of our applications where we would get "Call rejected by Callee" when trying to connect to Word, unless it was already open. We worked around it in Delphi 2000 / Windows XP with the following code:
WordApp.Connect;
WordApp.Visible := True;
WordApp.Documents.Add(Template, EmptyParam, EmptyParam, EmptyParam);
WordApp.ChangeFileOpenDirectory(jdir);
WordApp.Visible := False;
WordDoc.ConnectTo(WordApp.ActiveDocument);
This no longer does the trick under Windows 7 - and recompiling under XE2 doesn't seem to help.
I've seen a related question here which pertains to Visual Studio - anyone know how to apply that to Delphi (XE2 would be fine at this stage)
Dan
"Call rejected by callee" errors happen when the instance that you are connected/connecting to is currently in an interactive mode: an open dialog for example. Or, in Excel, a cell being edited, or even being in a state where a cell being edited was interrupted by the user switching away from the application - when (s)he returns it may look that the edit was completed, but the interactive mode is not ended until a different cell is selected.
Because of this I don't understand why you were getting this error when connecting unless another instance was already open. If there is no instance open (and visible), Word cannot be in interactive mode and you shouldn't have been getting the error. Is it possible your remedy merely circumvented the real problem?
No matter what though, you are in a situation where you are trying to connect to an instance that is in interactive mode. Either beforehand, or caused by your code. As you switched from XP to Windows 7, UAC does come to mind as a possible culprit.
I'd do away with the work-around, and see where that takes you.
For Word automation I always make sure that:
I connect to a dedicated instance by using a ConnectKind of ckNewInstance and
make sure I do not make my dedicated instance visible or
make sure I only make it visible after I am all done and can turn the instance over to the user.
If you have no option but to automate against a visible (and thus non-dedicated) Word instance, you will simply have to deal with the possibility of this error coming up. When it does, alert the user to what is happening and make sure you offer a retry.
Update
The thread on the Embarcadero forums mentioned in the comments by #Hendra includes a link to some very useful MSDN documentation: Fixing 'Application is Busy' and 'Call was Rejected By Callee' Errors

Problem with "unwanted" exception dialogs in Delphi

I've problem with exception dialogs: I'm using RemObjects SDK for Client/Server -application. When there's connection problem, the client starts throwing "simple" exceptions dialogs, just text and a button. When I'm running the application on my development machine the exceptions dialogs are not shown (as expected). The text on the dialog is simple "Timeout", "Connection refused" etc. That kind of exceptions are raised AND handled inside RemObjects code inside worker thread. I've also EurekaLog activated, but it doesn't help at all.
Any ideas why it works on development machine, but not on "vanilla" client machine? How I can get rid of all exception popups?
I've following
Delphi 2007
RemObjects SDK "Winter 2009"
EurekaLog 6.0.22
I would do the following:
compile your app with debug info (.map file) and copy both to the client
start your app on the "vanilla" client machine
wait till a popup appears
start my sampling profiler:
http://asmprofiler.googlecode.com/files/AsmProfiler_Sampling%20v1.0.6.12.zip
use the "Stack view of process" button and choose your app in the process list
double click or press the "Live view" button
http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer
you can now view the stack of the main thread, so you should see where the popup comes from...
Good luck!
You're going to have to do some debugging. If it's handled inside the worker thread, then it won't raise that dialog. Something's happening that causes the exception objects to escape to a higher level of the call stack.
Try installing on a vanilla machine of your own and trying to reproduce it yourself. You might notice some detail that the client didn't notice or didn't bother to report to you. Once you're able to reproduce it, you can try to figure out what's causing it with remote debugging or a handful of other ways.
A first step would be to use the remote debugger and start or attach to the process on the client machine.
You may have the IDE set to ignore these exceptions. You can check by looking in the debugger options. See Menu Tools/Options and then look in Debugger Options/Language exceptions.
If so, you can uncheck the option to get the exceptions back on the development machine and then use try/except to handle the exceptions programmatically.

Delphi Form Drag Lockup

Make a Delphi 2007 application, TForm as main window.
Run application. Try to drag the form using the caption bar. The debugger shows an unending stream of error messages, complaining it can't find some unnamed routine. Escape and Break don't work. 3 finger salute doesn't work.
Clicking in some other window and then back to the Delphi application stops the avalanche of error messages and allows the application to function in its original location (the form itself hasn't moved).
Strangely, on occasion I've had related behavior using Firefox -- clicking in the browser window doesn't work 'til I click in some non-Firefox window, after which the browser window is active again.
Anyone seen related behavior? Suggestions? Might it be a mouse driver problem? Toshiba laptop with ALPS touchpad mouse.
This doesn't sound related to Delphi specifically. The "stream of error messages, complaining it can't find some unnamed routine" sounds very odd. Could you post one or two of the actual messages, please?
In the meanwhile, my guess is some form of hook or injected code. Try looking for programs that do that kind of thing and disable them one by one:
Mouse drivers (as a poster above
said)
Antivirus, especially the "big ones"
like Norton etc
Some display driver "enhancement"
utilities
If you have two screens and you're
running a second taskbar program, try
that
and so forth.
It's probably worth doing a virus scan too, you never know :)
I know there was a Logitech driver hook problem when starting a Delphi project in Delphi: it gave an exception on the first line of the .dpr. Outside Delphi it worked OK.
So do you get those exceptions/problems only in Delphi? What kind of error/exceptions?

Resources