可以启动另一个程序,CreateProcessAsUser等来让这个进程跑到user session,然后执行相关动作

解决方案 »

  1.   

    SHELL跟SESSION完全不相干,不是同一个层面的东西,对楼主的问题没有帮助。先理解一下SHELL的概念:
    1.操作系统本来可以不需要SHELL,比如服务器在正常运行的时候不存在SHELL,只有需要进入桌面环境的帐户才会启动SHELL(桌面本身就是SHELL提供的),桌面应用软件可以无障碍地执行任何SHELL函数。
    2.SHELL是绑定账号的,也就是说SHELL必须以某个桌面帐户身份运行。服务不同,服务没有桌面(或者说服务的桌面是CONSOLE),电脑登录进入桌面之前没有SHELL在执行,但是服务已经运行了,服务中不能使用任何SHELL函数。其次,服务是以system帐户身份运行的,system是内置帐户,不是桌面帐户,不能启用桌面。
    即使服务被设置成能跟桌面交互,那也只是系统开的一个后门,不代表能显示窗口就能使用SHELL函数。
    某些服务可以以桌面帐户身份执行,但同样不能使用SHELL,所以不要以为桌面帐户运行的程序就一定能用SHELL函数。说得有点绕,总结一下:只有桌面帐户在桌面环境下的应用才能使用SHELL函数;所有服务程序(包括桌面帐户身份运行的服务程序)都不能使用SHELL函数。所以:找其它API替代吧。
      

  2.   


    首先,服务中一些SHELL函数是绝对可以用的,因为我试过了很多次了,只是涉及到用户桌面相关的路径时无法获取到。
    然后,虽然我没有什么官方依据,但从网上的一些资料来看,服务是有桌面的,只是跟用户桌面不在同一个域里,尤其的win7中。服务是可以有窗口的,只是显示在了看不见的区域而已。
    还有,Shell部分虽然我不太精通,但我感觉桌面只是一个UI显示的东西而已,我把explorer这个进程结束掉就不能调用Shell函数了么?
      

  3.   

    楼主找到解决方法吗
    我也碰到了一个类似的问题
    带UI的服务调用SHBrowseForFolder无法显示窗口就直接返回
      

  4.   

    没解决
    自己写一个仿SHBrowseForFolder功能的UI
      

  5.   

    这个问题搞定了,
    分几步:
    得到当前登录用户的会话ID
    通过会话ID得到令牌
    模仿成当前登录用户
    就可以获取到当前用户的桌面的特殊目录,例如开始菜单,快速启动栏,桌面等
    代码如下:int getcuruserdir(TCHAR lpPath[], int i) // i表示获取不同值标志..1,开始菜单,2桌面,3开始启动栏
    {
    BOOL bRes = FALSE;
    // char lpPath[MAX_PATH];
    DWORD RetVal = 0;
    DWORD ErrCode = 0;
    DWORD ConsoleSessionId = 0;
    // 函数的句柄
    HMODULE hInstKernel32 = NULL;
    HMODULE hInstWtsapi32 = NULL;
    // Token的句柄
    HANDLE hTokenUser = NULL;
    HANDLE hTokenThisProcess = NULL;
    HANDLE hTokenThis = NULL;
    // WTSGetActiveConsoleSessionId 函数,得到当前登录用户的会话ID
    // 这里的代码用的是VC6,新版的SDK已经包括此函数,无需LoadLibrary了。
    typedef DWORD(WINAPI * WTSGetActiveConsoleSessionIdPROC)();
    WTSGetActiveConsoleSessionIdPROC WTSGetActiveConsoleSessionId = NULL;
    hInstKernel32 = LoadLibrary("Kernel32.dll");
    if (!hInstKernel32) {
    return FALSE;
    }
    WTSGetActiveConsoleSessionId = (WTSGetActiveConsoleSessionIdPROC)
    GetProcAddress(hInstKernel32, "WTSGetActiveConsoleSessionId");
    if (!WTSGetActiveConsoleSessionId) {
    return FALSE;
    }
    // WTSQueryUserToken 函数,通过会话ID得到令牌
    typedef BOOL(WINAPI * WTSQueryUserTokenPROC)(ULONG SessionId,
    PHANDLE phToken);
    WTSQueryUserTokenPROC WTSQueryUserToken = NULL;
    hInstWtsapi32 = LoadLibrary("Wtsapi32.dll");
    if (!hInstWtsapi32) {
    return FALSE;
    }
    WTSQueryUserToken = (WTSQueryUserTokenPROC)GetProcAddress(hInstWtsapi32,
    "WTSQueryUserToken");
    if (!WTSQueryUserToken) {
    return FALSE;
    }
    // 得到当前激活用户的会话ID
    ConsoleSessionId = WTSGetActiveConsoleSessionId();
    // 得到当前登录用户的令牌
    bRes = WTSQueryUserToken(ConsoleSessionId, &hTokenUser);
    if (!bRes) {
    return FALSE;
    }
    // 模仿成当前登录用户
    bRes = ImpersonateLoggedOnUser(hTokenUser);
    if (!bRes) {
    return FALSE;
    } // 取得当前用户的Startup文件夹路径 if (i == 1) // 开始菜单
    bRes = SHGetSpecialFolderPath(NULL, lpPath, CSIDL_STARTMENU, TRUE);
    else if (i == 2) // 桌面
    bRes = SHGetSpecialFolderPath(NULL, lpPath, CSIDL_DESKTOPDIRECTORY,
    TRUE);
    else if (i == 3) // 启动栏
    bRes = SHGetSpecialFolderPath(NULL, lpPath, CSIDL_STARTUP, TRUE);
    // 终止模拟,返回
    RevertToSelf();
    }