我在Vista中使用Vista UAC(C Windows)在CreateDesktop()中提出这个问题。我设置了一个赏金,但是在尝试拒绝唯一的答案时,错误地按下了“接受”(我已经醒了超过48小时)。 所以我再问一遍。
我正在使用CreateDesktop()创build一个应用程序将运行的临时桌面,执行清理操作(同时保持原状)并终止。 一旦应用程序消失,我正在closures桌面。 使用Windows XP甚至Vista时,一切都很好。 当启用(令人讨厌的)UAC时,问题就出现了。
当您创build桌面时,一切正常,但是当您调用CreateProcess()在该桌面上打开程序时,它会导致打开的应用程序崩溃,同时在User32.dll上发生exception。
我一直在阅读很多有关Windows上不同的桌面和图层以及内存的限制。 但是,我打开的大多数程序(作为testing场景)都可以,但是一些(如IE,记事本,Calc和我自己的应用程序)会导致崩溃。
任何人都有任何想法为什么这种情况发生在UAC的Vista上,或者更具体地说,这些特定的程序? 以及如何解决这个问题?
任何人都有一个很好的例子,如何创build一个桌面,并打开一个应用程序没有切换到Vista下与UAC?
代码表示赞赏。
谢谢
使用的代码是
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;
在与UAC交互时,您似乎遇到了IE中的一个错误。 如果保护模式设置为打开,则不能在除默认用户之外的任何桌面以普通用户身份运行IE。 为了在备用桌面上运行IE,您必须以管理员身份运行或将保护模式设置为关闭。 Vista,W2K8和Win7都是如此。
至于其他程序,你不能运行,不幸的是我不能确认任何东西。 我尝试了超过30个不同的程序,包括记事本,计算机,所有的办公应用程序,Visual Studio 2005,2008和2010年,MSDN的帮助和其他一些和所有预期的IE浏览器。 有没有什么真正的不寻常的应用程序,可能会以一种意想不到的方式?
一个注意事项 – 如果您尝试运行需要提升的应用程序(如注册表等),它将在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; }
上面的ChristianWimmer作为一个简短的评论给出了正确的解决方案:
桌面必须有一个安全描述符,允许像IE一样访问较低的完整性级别。 否则,GUI不能访问桌面。 – ChristianWimmer 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:谢谢你提供正确的解决方案的提示。 这节省了我很多时间!