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.

[Update #2]

I checked again, with results:

OSK Test IDE/n.u. IDE/admin Explorer/nu Explorer/admin Explorer/comp.mode
n.u. (XPSP2)
x x
Delphi 7 binary w. XPMan (asInvoker) manifest
“OSKTest Delphi7 XPMan manifest.exe”
success success failure failure success x x
Delphi 7 b. w/o manifest
“OSKTest Delphi7 no manifest.exe”
success success failure failure success x x
VStudio 2008 w. manifest
“OSKTestVScpp2008 debug manifest.exe”
“OSKTestVScpp2008 release manifest.exe”
failure failure failure failure failure x x
VStudio 2008 w/o manifest^ release
“OSKTestVScpp2008 release no manifest.exe”/
“OSKTestVScpp2008 release stripped manifest.exe”
failure failure failure/
success x x
VStudio 2008 w/o manifest^ debug
“OSKTestVScpp2008 debug no manifest.exe”/
“OSKTestVScpp2008 debug stripped manifest.exe”
failure failure failure/
success + success (as admin) x x
VStudio 2005 w/o vista manifest release
“OSKTestVScpp2005 release stripped manifest.exe”
success success success# failure/
success x x
VStudio 2005 w/o vista manifest debug
“OSKTestVScpp2005 debug stripped manifest.exe”
failure failure success# failure/
success x x
Delphi 2007 w. XPMan (asInvoker) manifest
“OSKTest Delphi2007 XPMan manifest.exe”
failure failure failure failure failure x x
Delphi 2007 w/o manifest
“OSKTest Delphi2007 no manifest.exe”
success success failure/
success x x


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.

What can I tell about the results the table gives us?

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.

[Update #3]

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!!

[Update #4]

The way Osk.exe is started (probably):

  1. run osk.exe as normal user. Osk.exe is elevated in any way
  2. <no idea>
  3. winlogon runs utilman.exe /DEBUG
  4. utilman.exe runs osk.exe

[Update #5]

Did you know? Osk.exe is the only process that can be elevated without showing up the UAC prompt.

Case still open…

Any suggestions?

Run this program in a Delphi that was started by RunAsSys.

program OSKTest;
uses JwaWindows, Forms, Dialogs, SysUtils;

function StartProcess(const PathName : WideString) : THandle;
    StartInfo : TStartupInfoW;
  ZeroMemory(@StartInfo, sizeof(StartInfo));
  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 := ;
    result := IncludeTrailingBackslash(Path);  //Oopps, may convert unicode to ansicode


Do you think, it is a Delphi problem? I have the same problem with C++:


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

#include "stdafx.h"
#include "windows.h"
#include <iostream>
using namespace std;

int _tmain(int argc, _TCHAR* argv[])

   ZeroMemory(&amp;si, sizeof(si));
   si.cb = sizeof(si);

   if (!CreateProcessA("C:\\Windows\\System32\\osk.exe",
        &amp;si, π) != 0)
      cout << GetLastError();
      char s;
      cin >> s;//wait

   return 0;


I created a new Download package with different versions of the source. Download it here. Warning! You need the Visual2008 Redist Installation for some files.