Posted by: Christian Wimmer in: Common
Did you know?
ShellExecuteEx ignores the active desktop (the one that has input). It just starts the application on the default desktop (winsta0\default). However ShellExecute (without Ex) works fine with multiple desktops. Unfortunately, the last function isn’t that powerful.
I encountered this problem (on Vista with active UAC) while I tried to create an application on a separate desktop which should also be used by disabled people. So the magnifier and the on-screen keyboard (osk.exe) are good tools on the separate desktop. However while the magnifier works fine with CreateProcess, the osk does not! The function even ignores the fact that the caller has the SYSTEM integrity level (since it is SYSTEM), all privileges and token groups. I ran my test application with RunAsSys.
We know that CreateProcess returns an error 740 if the new process needs to be elevated. ShellExecuteEx however runs the osk on the default (not visible) desktop without problems. ShellExecute runs the program on the input desktop (any other thing than default) but it does not return a process handle/ID! So it is not really useful.
I did not manage to find another file in the system32 folder which (like osk.exe) fails to load with CreateProcess.
There is also a really strange fact when I start a cmd.exe with RunAsSys and then call osk.exe, It works fine!? If I use RunAsSys.exe directly to start osk.exe (of course with full path) it fails miserably.
It also works if I start Delphi as an Administrator and run the application below.
I checked again, with results:
|Delphi 7 binary w. XPMan (asInvoker) manifest
“OSKTest Delphi7 XPMan manifest.exe”
|Delphi 7 b. w/o manifest
“OSKTest Delphi7 no manifest.exe”
|VStudio 2008 w. manifest
“OSKTestVScpp2008 debug manifest.exe”
“OSKTestVScpp2008 release manifest.exe”
|VStudio 2008 w/o manifest^ release
“OSKTestVScpp2008 release no manifest.exe”/
“OSKTestVScpp2008 release stripped manifest.exe”
|VStudio 2008 w/o manifest^ debug
“OSKTestVScpp2008 debug no manifest.exe”/
“OSKTestVScpp2008 debug stripped manifest.exe”
|success + success (as admin)||x||x|
|VStudio 2005 w/o vista manifest release
“OSKTestVScpp2005 release stripped manifest.exe”
|VStudio 2005 w/o vista manifest debug
“OSKTestVScpp2005 debug stripped manifest.exe”
|Delphi 2007 w. XPMan (asInvoker) manifest
“OSKTest Delphi2007 XPMan manifest.exe”
|Delphi 2007 w/o manifest
“OSKTest Delphi2007 no manifest.exe”
|failure||this failure should not happen because the process is already elevated.|
|n.u.||normal user mode|
|^||removed the manifest completely through project options|
|#||the program compatibility assistant showed up. The first time the test was a failure but resulted in a success afterwards. It was repeated if the filename changed. If the XP compatibility mode was activated the result was always a success.|
|+||The binary doesn’t work if the name is changed. The program compatibility assistant (pca) should pop up but it doesn’t. It believe this happens because I didn’t recognize the pca accidentally.|
|*||removed only trustinfo xml tag manually since vs binaries need the manifest for the rtl.|
Well, I can tell you that it is mostly about virtualization! Everytime the virtualization is online (check in property sheet “Security” of Process explorer) it works perfectly. On the other hand if virtualization is offline, the whole CreateProcess story fails even with administrative rights.
So is it a Windows Bug? …. I don’t know yet.
I found out that osk runs with elevated privileges. Try to run it from your account without elevation. What do you encounter? Althout you are not an admin, the osk.exe is started elevated. You don’t get an UAC Prompt. Process Explorer shows the known Dllhost.exe and consent.exe. But Consent.exe is only shown for a short time. There is no UAC Prompt!!
The way Osk.exe is started (probably):
Did you know? Osk.exe is the only process that can be elevated without showing up the UAC prompt.
Case still open…
Run this program in a Delphi that was started by RunAsSys.
function StartProcess(const PathName : WideString) : THandle;
var ProcInfo: PROCESS_INFORMATION;
StartInfo : TStartupInfoW;
StartInfo.cb := sizeof(StartInfo);
// StartInfo.lpDesktop := ‘winsta0\default’;
StartInfo.wShowWindow := SW_SHOW;
if not CreateProcessW(PWideChar(PathName),nil, nil,nil,false, CREATE_NEW_CONSOLE, nil, nil, StartInfo, ProcInfo) then
//or: //if not CreateProcessW(nil,PWideChar(PathName), nil,nil,false, CREATE_NEW_CONSOLE, nil, nil, StartInfo, ProcInfo) then
ShowMessage(Format(‘The application could not be started: (%d) %s’,[GetLastError,SysErrorMessage(GetLastError)]));
//omit anything else!!
result := ProcInfo.hProcess;
function GetSystem32Path : WideString;
var Path : Array[0..MAX_PATH] of Widechar;
Result := ”;
if SUCCEEDED(SHGetFolderPathW(0,CSIDL_SYSTEM,0,SHGFP_TYPE_DEFAULT, @Path)) then
result := IncludeTrailingBackslash(Path); //Oopps, may convert unicode to ansicode
The Visual Studio (2005) is started with administrative rights (as shown in Process Explorer’s property dialog). The code given here creates the shown command prompt with the error 740 (Elevation required).
int _tmain(int argc, _TCHAR* argv)
si.cb = sizeof(si);
CREATE_NEW_CONSOLE, NULL, NULL,
&si, π) != 0)
cout << GetLastError();
cin >> s;//wait