Windows – CreateDesktop() with vista and UAC on (C, windows)

cuacwindowswindows-vista

I asked this in CreateDesktop() with Vista UAC (C Windows)
I set a bounty but in trying to vote down the only answer the "accept" was pressed by mistake (i've been awake for more than 48 hs). so I am asking it again.

I'm using CreateDesktop() to create a temporary desktop where an application will run, perform a cleanup action (while remaining out of the way) and terminate. I'm closing that desktop once the application is gone. Everything is fine when using Windows XP and even Vista. The problem arises when you enable the (annoying) UAC.

Everything is OK when you create a desktop, but when you call CreateProcess() to open a program on that desktop it causes the opened application to crash with an exception on User32.dll.

I've been reading a lot about the different desktops and layers on Windows and the restrictions of memory. However, most of the programs I open (as test scenarios) are OK, but a few (like IE, Notepad, Calc and my own application) cause the crash.

Anyone has any idea why this happen on Vista with UAC, or more specifically for those specific programs? and how to fix this?

Anyone has a good solid example on how to create a desktop and open an application there without switching to it under Vista with UAC on?

Code is appreciated.

Thanks

The code used is

SECURITY_ATTRIBUTES sa;

HDESK dOld;
HDESK dNew;

BOOL switchdesk, switchdesk2, closedesk;
int AppPid;

sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);

//Get handle to current desktop
dOld = OpenDesktopA("default", 0, TRUE, DESKTOP_SWITCHDESKTOP| 
                                        DESKTOP_WRITEOBJECTS|
                                        DESKTOP_READOBJECTS|
                                        DESKTOP_ENUMERATE|
                                        DESKTOP_CREATEWINDOW|
                                        DESKTOP_CREATEMENU);
if(!dOld)
{
    printf("Failed to get current desktop handle !!\n\n");
    return 0;
}

//Make a new desktop
dNew = CreateDesktopA("kaka", 0, 0, 0, DESKTOP_SWITCHDESKTOP|
                                          DESKTOP_WRITEOBJECTS|
                                          DESKTOP_READOBJECTS|
                                          DESKTOP_ENUMERATE|
                                          DESKTOP_CREATEWINDOW|
                                          DESKTOP_CREATEMENU, &sa);

if(!dNew)
{
    printf("Failed to create new desktop !!\n\n");
    return 0;
}

AppPid = PerformOpenApp(SomeAppPath);
if(AppPid == 0)
{
    printf("failed to open app, err = %d\n", GetLastError());
}
else
{
    printf("App pid = %d\n", AppPid);
}


closedesk = CloseDesktop(dNew);

if(!closedesk)
{
    printf("Failed to close new desktop !!\n\n");
    return 0;
}


return 0;

Best Answer

You appear to have come across a bug in IE as it interacts with UAC. If protected mode is set to on you cannot run IE as an ordinary user in any desktop except the default one. In order to run IE in an alternate desktop you must be running as administrator or have protected mode set to off. This is true for Vista, W2K8 and Win7.

As to the other programs that you cannot run, unfortunately I can't confirm anything. I tried upwards of thirty different programs including notepad, calc, all the office apps, visual studio 2005, 2008 and 2010, MSDN help and a number of others and all worked as expected with the noted exception of IE. Is there something truly unusual about your app that might make it behave in an unexpected manner?

One note - if you attempt to run an application like this that needs elevation (such as regedit, etc.) it will fail in CreateProcess with the last error set to ERROR_ELEVATION_REQUIRED.

For your reference, in case I'm doing something different from you, the code I used is:

#ifndef _WIN32_WINNT            // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600     // Change this to the appropriate value to target other versions of Windows.
#endif

#include <stdio.h>
#include <tchar.h>

#include "windows.h"

HANDLE PerformOpenApp(TCHAR* appPath);

int _tmain(int argc, _TCHAR* argv[])
{
    HDESK dNew;
    BOOL closedesk;
    HANDLE hApp;

    //Make a new desktop
    dNew = CreateDesktop(_T("kaka"), 0, 0, 0, DESKTOP_SWITCHDESKTOP|
                                              DESKTOP_WRITEOBJECTS|
                                              DESKTOP_READOBJECTS|
                                              DESKTOP_ENUMERATE|
                                              DESKTOP_CREATEWINDOW|
                                              DESKTOP_CREATEMENU, NULL);

    if(!dNew)
    {
        _tprintf(_T("Failed to create new desktop !!\n\n"));
        return 0;
    }

    TCHAR path[MAX_PATH];
    _putts(_T("Enter the path of a program to run in the new desktop:\n"));
    _getts(path);

    while(_tcslen(path) > 0)
    {
        hApp = PerformOpenApp(path);
        if(hApp == 0)
        {
            _tprintf(_T("Failed to open app, err = %d\n"), GetLastError());
        }
        else
        {
            _tprintf(_T("App pid = %d\n"), GetProcessId(hApp));
            _putts(_T("Press any key to close the app.\n"));
            _gettchar();
            TerminateProcess(hApp, 0);
            CloseHandle(hApp);
         }
         _putts(_T("Enter the path of a program to run in the new desktop:\n"));
         _getts(path);
    }

    closedesk = CloseDesktop(dNew);

    if(!closedesk)
    {
        _tprintf(_T("Failed to close new desktop !!\n\n"));
        return 0;
    }
    return 0;
}

HANDLE PerformOpenApp(TCHAR* appPath)
{
    STARTUPINFO si = {0};
    PROCESS_INFORMATION pi;

    si.cb = sizeof(si);
    si.lpDesktop = _T("kaka");

    BOOL retVal = CreateProcess(NULL, appPath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL,
        NULL, &si, &pi);

    if (retVal)
    {
        CloseHandle(pi.hThread);
    }
    return pi.hProcess;
}