我在CreateDesktop() with Vista UAC (C Windows)中问了这个问题 我设定了一笔赏金,但在试图拒绝唯一的答案时,“接受”被错误地按下了(我已经醒了超过48小时)。所以我再问一遍。
我正在使用CreateDesktop()来创建一个临时桌面,其中应用程序将运行,执行清理操作(同时保持不受影响)并终止。一旦应用程序消失,我就关闭了桌面。使用Windows XP甚至Vista时,一切都很好。启用(恼人的)UAC时会出现问题。
创建桌面时一切正常,但是当您调用CreateProcess()在该桌面上打开程序时,会导致打开的应用程序崩溃,并在User32.dll上出现异常。
我一直在阅读很多有关Windows上不同桌面和图层以及内存限制的内容。但是,我打开的大多数程序(作为测试场景)都可以,但是一些程序(如IE,Notepad,Calc和我自己的应用程序)会导致崩溃。
任何人都知道为什么会在使用UAC的Vista上发生这种情况,或者更具体地针对这些特定程序?以及如何解决这个问题?
任何人都有一个很好的例子来说明如何创建一个桌面并在那里打开一个应用程序,而无需在使用UAC的Vista下切换到它?
感谢代码。
由于
使用的代码是
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;
答案 0 :(得分:9)
正确的解决方案由ChristianWimmer在上面作为简短评论给出:
桌面必须具有安全描述符,允许访问IE所具有的较低完整性级别。否则GUI无法访问桌面。 - ChristianWimmer 2010年7月22日17:00
由于答案有点隐藏且没有源代码示例,请允许我在此明确说明:
如果IE在受保护模式下运行,则浏览器选项卡将创建为低完整性进程。如果桌面没有低完整性强制标签,则低完整性选项卡进程将无法初始化。
因此,主IE流程也会终止。一个有趣的观察是,如果你启动IE从安全区域提供命令行URL,那么IE将成功启动,因为安全区域默认禁用保护模式。
我检查了默认桌面的完整性级别,实际上我能够验证默认桌面的完整性级别是否很低!因此,解决该问题的最简单方法是(1)创建新桌面,(2)从默认桌面获取强制标签,以及(3)将其复制到新桌面。对于(2)和(3),您可以使用以下代码
PACL pSacl;
PSECURITY_DESCRIPTOR pSecurityDescriptor;
DWORD dwResult;
dwResult = GetSecurityInfo(hDefaultDesktop, SE_WINDOW_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, &pSacl, &pSecurityDescriptor);
if (dwResult == ERROR_SUCCESS) {
if (pSacl != NULL) {
dwResult = SetSecurityInfo(hNewDesktop, SE_WINDOW_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, pSacl);
if (dwResult != ERROR_SUCCESS)
_tprintf(_T("SetSecurityInfo(hNewDesktop) failed, error = %d"), dwResult);
}
LocalFree(pSecurityDescriptor);
} else {
_tprintf(_T("GetSecurityInfo(hDefaultDesktop) failed, error = %d"), dwResult);
}
@CristianWimmer:感谢您提供正确解决方案的提示。这节省了我很多时间!!
答案 1 :(得分:4)
您似乎在IE中遇到了与UAC交互的错误。如果保护模式设置为on,则无法在任何桌面中以普通用户身份运行IE(默认用户除外)。要在备用桌面中运行IE,您必须以管理员身份运行或将保护模式设置为关闭。这适用于Vista,W2K8和Win7。
至于你无法运行的其他程序,遗憾的是我无法确认。我尝试了三十多种不同的程序,包括记事本,计算,所有办公应用程序,Visual Studio 2005,2008和2010,MSDN帮助以及其他一些程序,并且除了IE之外,所有程序都按预期工作。您的应用程序是否存在一些可能使其以意外方式运行的异常情况?
一个注意事项 - 如果您尝试运行这样需要提升的应用程序(例如regedit等),它将在CreateProcess中失败,并将最后一个错误设置为ERROR_ELEVATION_REQUIRED。
供我参考,如果我做了与你不同的事情,我使用的代码是:
#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;
}