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;
Related
I Have a dll project. I have to get host application handle. I Can't pass handle from host application to dll project because the host application is not mine.
The host application runs on second monitor but when the host application calls my form (dll) the form shown in first monitor. I have to detect host application screen coordinates or i have to detech the host application runs on first monitor or second monitor.
You are looking for top-level windows in your process. Find them like so:
Call GetCurrentProcessId to obtain your process ID.
Call EnumWindows to enumerate all top level windows.
In the enumeration callback, for each top level window, call GetWindowThreadProcessId to obtain the process ID that owns the window. Any that match the process ID found in step 1 are from your process.
The problem that you face is that step 3 might identify multiple such windows. You can call GetWindow passing GW_OWNER to obtain the owner of the window and use that to trim down the field of candidates. What you perceive as being the main window is likely to have no owner, but the other top level windows may well be owned. Even this cannot be guaranteed to trim the field down to a single candidate and you very likely will need to come up with some additional logic.
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.
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..
I am preparing a Delphi module, which sets a hook in a thread to record a macro:
FHandleRec := SetWindowsHookEx(WH_JOURNALRECORD, FRecordProc, HInstance, 0);
FHandlePlay := SetWindowsHookEx(WH_JOURNALPLAYBACK, FPlayProc, HInstance, 0);
That works fine on WinXP, but on Vista/Windows 7 fails with ERROR_ACCESS_DENIED.
I have found in Google (this) referring (that). The quote:
A lower privilege process cannot: … Use Journal hooks to monitor a
higher privilege process.
Tried without success:
Run application as administrator. Probably the thread is started
with lower privileges than the main thread (though I am not 100%
sure)
Impersonating the thread with administrator security context
doesn’t help either.
The code sample:
if LogonUser(PWideChar(sAdminUser), PWideChar(sDomain), PWideChar(sPwd),
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, hToken) then
begin
if not ImpersonateLoggedOnUser(hToken) then
raise Exception.Create('Error impersonating the user');
end;
FHandleRec := SetWindowsHookEx(WH_JOURNALRECORD, FRecordProc, HInstance, 0);
LogonUser and ImpersonateLoggedOnUser execute without errors.
Other possibilities to try:
Turn UAC OFF permanently. This helps, but I cannot force the module
users to do that.
A module customer signs an application and put it in a trusted
location. Not tried that, but that radically complicates the module
usage for the users.
Put the module into some signed application and distribute EXE. That
will break some core functionality.
Could you please show the code that is setting the hook under Visa / Windows 7 or suggest the working solution ?
Read the "User Interface Privilege Isolation" section of that article again more carefully. It is referring to integrity levels, not user permissions. That is why impersonating another user does not solve the problem. The integrity level is established when the process first starts and cannot be changed dynamically in code.
User Interface Privilege Isolation (UIPI) is one of the mechanisms
that helps isolate processes running as a full administrator from
processes running as an account lower than an administrator on the
same interactive desktop. UIPI is specific to the windowing and
graphics subsystem, known as USER, that supports windows and user
interface controls. UIPI prevents a lower privilege application from
using Windows messages to send input from one process to a higher
privilege process. Sending input from one process to another allows a
process to inject input into another process without the user
providing keyboard or mouse actions.
Windows Vista implements UIPI by defining a set of user interface
privilege levels in a hierarchical fashion. The nature of the levels
is such that higher privilege levels can send window messages to
applications running at lower levels. However, lower levels cannot
send window messages to application windows running at higher levels.
The user interface privilege level is at the process level. When a
process is initialized, the User subsystem calls into the security
subsystem to determine the desktop integrity level assigned in the
process’s security access token. The desktop integrity level is set by
the security subsystem when the process is created and does not
change. Therefore, the user interface privilege level is also set by
the User subsystem when the process is created and does not change.
All applications run by a standard user have the same user interface
privilege level. UIPI does not interfere or change the behavior of
window messaging between applications at the same privilege level.
UIPI comes into effect for a user who is a member of the
administrators group and may be running applications as a standard
user (sometimes referred to as a process with a filtered access token)
and also processes running with a full administrator access token on
the same desktop. UIPI prevents lower privilege processes from
accessing higher privilege processes by blocking the behavior listed
below.
Use Journal hooks to monitor a higher privilege process.
According to this article, your app needs a UAC manifest that specifies both requestedExecutionLevel=requireAdministrator and uiAccess=True. The UIAccess right is important:
By specifying UIAccess=”true” in the requestedPrivileges attribute,
the application is stating a requirement to bypass UIPI restrictions
...
A process that is launched with UIAccess rights:
Can set journal hooks.
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.