Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: PostMessage / GetLastError shows Access Denied



Permlink Replies: 5 - Last Post: Jul 26, 2016 10:36 AM Last Post By: Remy Lebeau (Te... Threads: [ Previous | Next ]
John Taylor

Posts: 9
Registered: 7/22/01
PostMessage / GetLastError shows Access Denied
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 14, 2016 8:02 AM
I hope someone here can help me with this, I'm literally pulling my hair out! :-)

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?

TIA
JT
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: PostMessage / GetLastError shows Access Denied
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 14, 2016 1:34 PM   in response to: John Taylor in response to: John Taylor
John wrote:

I hope someone here can help me with this, I'm literally pulling my
hair out! :-)

You asked the same question on StackOverflow:

call to postmessage returns “access denied”
http://stackoverflow.com/questions/38378977/

I'll re-iterate the same answer here.

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

Per the PostMessage() documentation:

When a message is blocked by UIPI the last error, retrieved with GetLastError,
is set to 5 (access denied).

UIPI "prevents lower-privilege applications from sending window messages
or installing hooks in higher-privilege processes".

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:

https://technet.microsoft.com/en-us/sysinternals/processexplorer.aspx

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.

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;


--
Remy Lebeau (TeamB)
John Taylor

Posts: 9
Registered: 7/22/01
Re: PostMessage / GetLastError shows Access Denied
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 15, 2016 7:47 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
John wrote:

I hope someone here can help me with this, I'm literally pulling my
hair out! :-)

You asked the same question on StackOverflow:

call to postmessage returns “access denied”
http://stackoverflow.com/questions/38378977/

I'll re-iterate the same answer here.

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

Per the PostMessage() documentation:

When a message is blocked by UIPI the last error, retrieved with GetLastError,
is set to 5 (access denied).

UIPI "prevents lower-privilege applications from sending window messages
or installing hooks in higher-privilege processes".

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:

https://technet.microsoft.com/en-us/sysinternals/processexplorer.aspx

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.

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;


--
Remy Lebeau (TeamB)

Remy,

I don't do anything (no knowledge of how) to change the execution level of the application. I am using an external manifest as follows:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
type="win32"
name="DelphiApplication"
version="1.0.0.0"
processorArchitecture="*"/>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
publicKeyToken="6595b64144ccf1df"
language="*"
processorArchitecture="*"/>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>

<!-- UAC Manifest Options
If you want to change the Windows User Account Control level replace the
requestedExecutionLevel node with one of the following.

<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />

If you want to utilize File and Registry Virtualization for backward
compatibility then delete the requestedExecutionLevel node.
-->

</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
</application>
</compatibility>
</assembly>

As you can see the requestedexecutionlevel doesn't contain anything but comments.
Is there a problem with the manifest ?

I did find out that my usage of ChangeWindowMessageFilterEx was incorrect. I used a code fragment I found via google and it was clearly wrong, thank you for showing me the correct way. The call was failing. It nows exeutes properly but I'm curious as to why it is even necessary and why I have only 2 users that have this problem. Many, many others have no issue at all and that always troubles me :-(

John

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: PostMessage / GetLastError shows Access Denied
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 16, 2016 5:08 PM   in response to: John Taylor in response to: John Taylor
John wrote:

As you can see the requestedexecutionlevel doesn't contain
anything but comments. Is there a problem with the manifest ?

Commenting out the requestedExecutionLevel is the same as not having a UAC
manifest at all. The default execution level is "asInvoker", which means
the process will have medium integrity if run by a standard user, and high
integrity if run by an admin.

I did find out that my usage of ChangeWindowMessageFilterEx was
incorrect. I used a code fragment I found via google and it was
clearly wrong, thank you for showing me the correct way. The call
was failing. It nows exeutes properly but I'm curious as to why it is
even necessary

Because you clearly have separate app processes that are running at different
integrity levels, where the lower integrity process is trying to send a window
message to the higher integrity process. UIPI kicks in and blocks the window
message unless ChangeWindowMessageFilter/Ex() is used. So you need to figure
out why your first process is running with a higher integrity level then
your second process.

--
Remy Lebeau (TeamB)
John Taylor

Posts: 9
Registered: 7/22/01
Re: PostMessage / GetLastError shows Access Denied
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 26, 2016 6:07 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
John wrote:

As you can see the requestedexecutionlevel doesn't contain
anything but comments. Is there a problem with the manifest ?

Commenting out the requestedExecutionLevel is the same as not having a UAC
manifest at all. The default execution level is "asInvoker", which means
the process will have medium integrity if run by a standard user, and high
integrity if run by an admin.

I did find out that my usage of ChangeWindowMessageFilterEx was
incorrect. I used a code fragment I found via google and it was
clearly wrong, thank you for showing me the correct way. The call
was failing. It nows exeutes properly but I'm curious as to why it is
even necessary

Because you clearly have separate app processes that are running at different
integrity levels, where the lower integrity process is trying to send a window
message to the higher integrity process. UIPI kicks in and blocks the window
message unless ChangeWindowMessageFilter/Ex() is used. So you need to figure
out why your first process is running with a higher integrity level then
your second process.

--
Remy Lebeau (TeamB)

Exactly! I just wish I knew how to do that :-(

John
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: PostMessage / GetLastError shows Access Denied
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 26, 2016 10:36 AM   in response to: John Taylor in response to: John Taylor
John wrote:

Exactly! I just wish I knew how to do that :-(

Well, you need to track down who is running your app's first instance to
begin with. That someone is running at a higher integrity than you are expecting.

--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02