Unexpected calling of form destroy - delphi

I have a service running on a customer and specifically that I've noticed a strange behavior. Always before closing the service, closing routines (OnStop) are executed, after that enter in FormDestroy. However, in this customer, service is terminated unexpectedly (I know this because FormDestroy have been calling), but without entering into the routines of service shutdown.
Looking at the stack, everything seems normal:
01388f14 ****.exe Main****. 32766 TF****.FormDestroy
00506cbd ****.exe Forms TCustomForm.DoDestroy
00506b23 ****.exe Forms TCustomForm.BeforeDestruction
00404c95 ****.exe System #BeforeDestruction
007a6a02 ****.exe dxRibbonForm 445 TdxCustomRibbonForm.Destroy
00487eaa ****.exe Classes TComponent.DestroyComponents
00504a33 ****.exe Forms DoneApplication
0045da9d ****.exe SysUtils DoExitProc
00405683 ****.exe System #Halt0
01435465 ****.exe Main**** 289 initialization
75773388 kernel32.dll BaseThreadInitThunk
I could see this message in the Windows Event Viewer:
The description for Event ID 0 from source *** cannot be found. Either the component that raises this event is not installed on your local computer or the installation is corrupted. You can install or repair the component on the local computer.
If the event originated on another computer, the display information had to be saved with the event.
The following information was included with the event:
Extended handler is registered
Could you give me a hint to find out what might be happening?

The message in the Event Viewer is meaningless. That is simply the standard error text for an event where the application which is the source of the event has not provided a DLL containing appropriate error messages to describe particular events.
Since your service appears to attempt to run interactively (with a UI), you presumably have set the Interactive property of your service to TRUE. This means that your service starts with the SERVICE_INTERACTIVE_PROCESS flag set. Services started with this flag are liable to be prevented from running by the system, based on a system setting, as described in this MSDN article.
In summary, in the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows key of the registry, if the NoInteractiveServices value is set to 1 (zero), then such services are prevented from running. In the case of a Delphi implemented service this means that the service process is started but will be terminated when it attempts to register the service itself, which may then cause problems in your UI destruction code if it contains assumptions that the initialisation of your service UI was successful.
On your affected customers system, change this registry value to a 0 (zero) to allow interactive services. If your service is then able to start then this confirms that this is the source of your problem.
However, your customer may have specifically chosen to disallow such services for valid reasons (see the notes in that article for starters).
If that is the case and this is indeed the cause of your problem, them you will be forced to find an alternative approach to the UI needs of your service/application. In the meantime, if the use of your service is important to that customer then this may provide a temporary solution if they are prepared to enable this setting on affected systems for a limited time while you make necessary changes to your application architecture.

Related

call to postmessage returns "access denied"

Using Delphi 2007...
I have an application which uses a mutex to enforce one running instance only. In the dpr unit, if the mutex already exists, I get a handle to the running instance with FindWindow, no problem so far. A second instance is commonly started by a virtual printer driver with reference to a filename on the command line. If there is a command line file reference then I want to simply post a message to the running instance and halt the new instance.
I'm using this...
PostMessage(hwnd,WM_STARTUP_MESSAGE,0,0); //hwnd as returned by FindWindow
WM_STARTUP_MESSAGE is defined as WM_APP + 6057
I have one user with the problem that the WM_STARTUP_MESSAGE is not processed in the main thread. From logging startup information in the dpr unit it was shown that the PostMessage returned false and SysErrorMessage(GetLastError) is:
Zugriff verweigert (his windows german translation is Access Denied).
I have many, many users of this application and I have only had 2 reports of this problem and cannot reproduce here. On Windows 10 here and so is at least 1 of the problem users, the other one I'm not sure of.
I am using ChangeWindowMessageFilterEx in the main form's OnCreate to allow WM_COPYDATA. I had the idea of simply including WM_STARTUP_MESSAGE there as well but that leads to a crash as that function does not like that message index value, so I presume it is reserved for a specific range of message values.
Has anyone seen this before and can offer some guidance?
Per the PostMessage() documentation:
When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied).
What is User Interface Privilege Isolation (UIPI) on Vista
This is also known as UI Privilege Level Isolation (UIPI).
As part of the secure initiatuve in Vista, applications with UI will run in three different levels of privilege. Application windows can interact with others windows of the same or lower levels, but cannot interact with applications at higher level/permission.
Lower privilege modes can send messages to higher privileged applications only if explicitly allowed by the higher privilege application with a message calling ChangeWindowMessageFilter(). Also lower privileged applications can only read a HWND owned by a higher privileged application.
Internet Explorer is an example process that runs at the lowest privilege level.
Windows Integrity Mechanism Design
User Interface Privilege Isolation (UIPI) implements restrictions in the windows subsystem that prevents lower-privilege applications from sending window messages or installing hooks in higher-privilege processes. Higher-privilege applications are permitted to send window messages to lower-privilege processes. The restrictions are implemented in the SendMessage and related window message functions. Not all window messages that are sent from a lower-privilege process to a higher-privilege process are blocked. Generally, “read” type messages, for example WM_GETTEXT, can be sent from a lower-privilege to a higher-privilege window. However, write type messages, such as WM_SETTEXT, are blocked.
...
UIPI does not interfere with or change the behavior of window messaging between applications at the same privilege (or integrity) level. UIPI prevents lower-privilege processes from accessing higher-privilege processes by blocking the following behavior. A lower-privilege process cannot:
Perform a window handle validation of a process running with higher rights.
Use SendMessage or PostMessage to application windows running with higher rights. These APIs return success but silently drop the window message.
Use thread hooks to attach to a process running with higher rights.
Use journal hooks to monitor a process running with higher rights.
Perform dynamic link library (DLL) injection to a process running with higher rights.
So clearly, when the error occurs, the HWND you are posting to belongs to a process that is running at a higher integrity/privilege level than the process that is posting the message. You can use SysInternals' Process Explorer to check that.
You said the second instance of your app is being run by a virtual printer driver, so the driver is likely running at a lower integrity level than an instance of the app that is started by the user.
ChangeWidowMessageFilter/Ex() does not have any restrictions on non-system message IDs (some system messages cannot be filtered). It will certainly not crash on a user-defined message ID. If you do not have permission to change the message filter for a given HWND/MsgID, the function will simply return FALSE instead, and GetLastError() will tell you why.
If you are experiencing a crash, it is related to something else in your code.
Also, the Form's OnCreate event is not the best place to call ChangeWindowMessageFilterEx(). During the course of the program's lifetime, the Form may have to recreate its HWND dynamically, maybe even more than once. Every time a new HWND is created, you have to call ChangeWindowMessageFilterEx() again. The best way to account for that is to override the Form's virtual CreateWnd() method, eg:
type
TMyForm = class(TForm)
protected
procedure CreateWnd; override;
end;
procedure TMyForm.CreateWnd;
begin
inherited;
ChangeWindowMessageFilterEx(Handle, WM_STARTUP_MESSAGE, MSGFLT_ALLOW, nil);
end;

How can I detect Applications Focus Changes?

I know how to get the title and exe name of the foreground window application that is running now, but I use a TTimer to verify when it changes.
Is there a way to detect events triggered by Alt+Tab, taskbar application selection or even the start of a new program?
I use Delphi 2006 and Windows 7 64 bits.
One option is to install a global hook. With a CBT hook, the system will call the hook procedure whenever a window is activated (among other things). A global hook callback is to be placed in a dll which gets loaded in the address space of processes, hence it can get mapped into only processes having the same 'bit'ness (using Delphi 2006, the callback will be called only by 32 bit processes). Moreover, it cannot be mapped into address space of a process that is created with a higher privilege (i.e. an application that is run as administrator if the process installing the hook is not). You also have to devise some kind of interprocess communication mechanism since your callback runs in other applications. You use SetWindowsHookEx to install a global hook.
One other option is using event hooks, that's SetWinEventHook. There are two kinds, in-context and out-of-context. The former one, like a global hook, is placed in a dll to be mapped into address spaces of other processes, so you'll suffer from same downsides. Out-of-context events are the most relaxed of all. They wouldn't be prompt as global hooks or in-context events when notifying but I believe that could still be better then a timer. One disadvantage of events to hooks in your context is that, you would have to code a bit more in the callback, f.i. you'll receive a window focus notification even for child windows and you would have to resolve which application it belongs to etc..

Converting a Delphi application to run as a service - is it necessary?

I have a delphi app that logs data from various places and writes the data to a file. The app has quite an extensive GUI to allow display of the data, configuration of the options, etc.
One user has requested that the app be changed to that it can be run as a service. His reasoning is that the app could then be started at boot time and run without any user being logged in and would be available regardless of who was logged in.
My question is this: Is there any other solution that would enable me to install the app as it now exists so that it would still run with no user logged in and still be available to all users?
My gut feeling is that converting the app to run as a service is not trivial. I assume you would need 2 apps - the "headless" service application, and a GUI that was run by users on demand that could interact with the service (comments welcome here also).
I usually create my application in such a way that it can be started as a service or as a GUI, via a commandline switch /GUI.
When the application runs with a GUI, I instantiate and start the service class "manually".
Advantages:
It'll run the same code, making it very easy to debug the service. You can just put breakpoints and step through your code without having to "attach" to a running application.
Because of the GUI, you can see what your service would be doing, and interact with it, via listviews and buttons, even on remote servers where you don't have a debugger. Having to interact with your service via logs and configurations is crappy and slow.
Example dpr, from a project that works like this:
program xxxx;
uses
SysUtils,
SvcMgr,
.......;
{$R *.res}
begin
GlobalAppId := 1;
MapMatcherController := TMapMatcherController.Create(nil);
try
if FindCmdLineSwitch('GUI',['/','-'],True) then
begin
Forms.Application.Initialize;
Forms.Application.MainFormOnTaskbar := True;
Forms.Application.CreateForm(TfrmMain, frmMain);
Forms.Application.Run;
end
else
begin
SvcMgr.Application.Initialize;
SvcMgr.Application.CreateForm(TsrvMapMatcher2, srvMapMatcher2);
SvcMgr.Application.Run;
end;
finally
MapMatcherController.Free;
end;
end.
Oh, another thing to keep in mind is that services usually run as a "system" user, which means you'll have different privileges and settings (for example drive letter mappings).
There are commercial (and free) solutions like Firedaemon, which will run (almost) any application as a service.
On a sidenote, it shouldn't really be hard to separate logic and user interface - you should've done that already when you developed the application. Just because Delphi makes it easy to write business logic in the code behind associated with the user interface, that doesn't mean you should really do it. Have a look at the presentation pattern's at Martin Fowler's site.
In general is possible to have a mixed single exe which in turn runs as a service or runs as a full GUI standard application.
How much effort your application needs to fit this category is matter of how is it designed, specially in the kind of coupling it have between business logic and user interface logic.
One great example of this kind of application comes with Delphi itself: scktsrvr.exe in your $DELPHI\bin directory runs as a GUI application or as a service (run scktsrvr.exe /install to auto-register the service and use management console to start/stop it.
in folder $DELPHI\source\db you will find the project files (scktsrvr.dpr/res, ScktCnst.pas, ScktMain.pas/dfm). Take your time to inspect how is it done and, who knows... maybe this is what you're looking for your application.
Take in account since Windows Vista interactive services are not allowed to interact with the user at his/her desktop. An administrator have to enable the interactive services detection and the user have to change to session 0 desktop in order to interact with your service (by interact it means to see and interact with your service forms)
You can try to use svrany, a tools to run an application as service.
It's parts of Server Resource Kit Tools.
try this link for 2003 server resource kit download.
It depends a little on your application, but generally it is achievable. Try this: http://iain.cx/src/nssm. Don't forget to start all services that you application depends on BEFORE you start your application as a service. Google around for info on how to do that.
You could write a simple service that starts your application. But if you care about your app future, I would go the service way. Yes, you would have to split the application in two pieces, the client/GUI part and the service itself, especially since Vista and 7 made much more difficult for a service to display a user interface for security reasons.
Services have several advantages, they run in their separate session, they can be set to run with a given user that could be different from the logged-on one, only user with proper privileges can control them, Windows can automatically restart them (or perfom other actions) when they fail.

TService won’t process messages

I have created a windows service that uses Windows Messaging System. When I test the app from the debugger the Messages go through nicely but when I install it my messag … asked 14 mins ago
vladimir
1tuga
Services don't generally receive window messages. They don't necessarily have window handles at all. Even if they do, they run in a separate desktop. Programs cannot send messages from one desktop to another, so a service can only receive messages from another service, or from a program started by a service.
Before Windows Vista, you could have configured your service to interact with the desktop. That makes the service run on the same desktop as a logged-in user, so a program running as that user could send messages to your service's windows. Windows Vista isolates services, though; they can't interact with any user's desktop anymore.
There are many other ways to communicate with services. They include named pipes, mailslots, memory-mapped files, semaphores, events, and sockets.
With a socket, for instance, your service could listen on an open port, and programs that need to communicate with it could connect to that port. This could open the door to remote administration, but you can also restrict the service to listen only for local connections.
All the above is trying to tell you that you're taking the wrong approach. But there's also the matter of the problem at hand. Your program behaves one way in the debugger and another way outside it. How are you debugging the service in the first place, if it's not installed? What user account is your service running as? Your debugger? What debugging techniques have you tried that don't involve the debugger (e.g. writeln to a log file to track your program's actions)?
What do you mean when you say it "uses" Windows Messaging System? Are you consuming or sending Windows Messages?
If you send a Windows message, you need ensure you are doing it correctly. I'd suggest writing a message loop to ensure your messages are being dispatched properly. I'd also suggest reading up on message loops and how they work.
What is a Message Loop (click the title to be taken to the source of this info)
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
The message loop calls GetMessage(),
which looks in your message queue.
If the message queue is empty your
program basically stops and waits
for one (it Blocks).
When an event occures causing a
message to be added to the queue
(for example the system registers a
mouse click) GetMessages() returns a
positive value indicating there is a
message to be processed, and that it
has filled in the members of the MSG
structure we passed it. It returns 0
if it hits WM_QUIT, and a negative
value if an error occured.
We take the message (in the Msg
variable) and pass it to
TranslateMessage(), this does a bit
of additional processing,
translating virtual key messages
into character messages. This step
is actually optional, but certain
things won't work if it's not there.
Once that's done we pass the message
to DispatchMessage(). What
DispatchMessage() does is take the
message, checks which window it is
for and then looks up the Window
Procedure for the window. It then
calls that procedure, sending as
parameters the handle of the window,
the message, and wParam and lParam.
In your window procedure you check
the message and it's parameters, and
do whatever you want with them! If
you aren't handling the specific
message, you almost always call
DefWindowProc() which will perform
the default actions for you (which
often means it does nothing).
Once you have finished processing
the message, your windows procedure
returns, DispatchMessage() returns,
and we go back to the beginning of
the loop.
Thank you all for the answers,
the issue was the operating system (vista), i tested the with my windows 2000 and everything works.
thanks for the light Rob.

Why do forms fail in Windows Services

I understand that Window's Services have no desktop, and can't access any of the user's desktops directly (indeed, they can run when there is no desktop loaded). Why is it though that launching a form in a Window's Service causes an error?
A service should run without any user interaction, so there is no need for a form. If a service has to wait around for user feedback then it probably isn't going to be doing what it is supposed to.
You have to understand three related concepts: sessions, windows stations and desktops. But because there's a one-to-one relationships between sessions and stations, we can broadly ignore stations for this discussion. A session contains a station (winSta0 being the only interactive station) and stations contain one or more desktops.
Now session architecture differs according to Windows version. For NT <= 5 (XP/2003 and everything before them) services execute in session 0 along with the interactive user's apps. This is why you can configure services to interact with the desktop in these Windows NT versions - they are in the same session. For NT >= 6 (Vista, Server 2008 going forwards), services exists in session 0 but the interactive desktop is in another session. This is what's known as "service hardening", and is basically a security fix.
So since session 0 apps cannot get at the interactive console, it makes no sense for them to attempt to display a user interface of any kind.
Just to make this more confusing, Vista has a temporary kludge to cater for this situation: if an app in session 0 tries to create a dialog, Windows will trap this and present a warning to the user so they switch to a (I presume temporary) desktop where they can interact with the dialog. However this measure is explicitly temporary and you cannot rely upon it being in future Windows releases. I've seen this working in native code, but I suspect you are in managed code and the runtime is being smart enough to catch your behaviour and deliver a metaphorical slap to the hindquarters :-).
Ummm... what and whose desktop is that form going to appear on, exactly? A 'desktop' is an operating system concept: each window handle is owned by a specific desktop within a window station belonging to a single (interactive) user. The process within which the service is executing isn't going to find the user's visible desktop in its window station. For a rather dry reference, look at MSDN.
Actually, it's even nastier. You might be able to configure permissions for the service to be able to create a desktop -- but then nobody will see it! Alternatively, you could grant the process the rights to switch desktops, and confuse the heck out of the user!
There's a setting you must enable in order to allow your Windows Service to access certain folders directly (like desktop) or show forms (including MessageBox pop-ups): "Allow service to interact with desktop"
To see this, right click on My Computer => Manage => Services and Applications => Services. Double-click on a service to access its properties. On the "Log On" tab there is a checkbox for this setting.
Here is an article for how to set it programmatically in C#
[Edit] As Stephen Martin points out in the comments: this is only valid advice for pre-Vista versions of Windows.
Because if nobody is going to see the Form, nobody is going to dismiss it - running a modal dialog is a recipe for a hang - so you want it to complain loudly when this happens rather than sit there quietly until you kill the process (or look at a stack trace to determine what'd going on). (The other obvious problem is, who is going to pick the DialogResult if there is more than one possibility?) You want to know when this is happening. (Assert dialogs that dont throw if they cant show anything are a fun way of making people mad.).
In other words, because you want to know when things are confused enough in your code that a dialog is being shown within a service context.
(I'm assuming you're using Windows Forms on .NET, eve though you didnt tag it as such)
(If you have correctly configured things such that the service is allowed to interact with the desktop, you won't get an Exception)
When a Windows Service is started it is assigned to a Window Station and Desktop according to well documented, though somewhat obscure rules. As mentioned elsewhere it is not assigned to the interactive desktop (unless it is set to interact with the desktop on a pre-Vista OS) but it definitely runs in a desktop.
It is a common misconception that services cannot use UI elements. In fact many services (such as SQL Server) have in the past used hidden windows and windows messages for thread synchronization and work distribution purposes. There is no reason that a Form cannot be shown in a service. If you are getting an error it is due to something you are doing with the form or some component that is on the form. The most likely issues have to do with whether or not you need an STA thread for your form or are you creating a message pump for your form or something similar.
While you certainly can use a form in a Windows Service you almost certainly shouldn't. There will be threading issues, cross apartment call issues, possible blocking UI issues, etc. There are a very few situations where using a window in a service is a good choice but there is a better way, with no UI, in 99.99% of all cases.
Because at the time when the operating system needs to paint the window there is nothing to draw the form on.

Resources