关于在windows服务程序中调用与用户桌面相关的shell函数的问题

woshinia 2012-11-08 04:33:21
首先,windows服务相关的资料非常少,网上流传的都是msdn上一些极为简单的服务编程的代码。

然后,由于现在都使用windows 7了,通过一些网上的资料,知道win7中服务使用的桌面session0,而用户使用的桌面是session1,session2,...虽然我对这个设定理解不是很深,但也大概知道在服务中很多与用户桌面相关的操作会有限制。之前看了一个把服务的权限令牌复制给用户权限令牌,然后用这个权限令牌可以成功的从服务中打开一个UI窗口,并显示在用户桌面上。

现在我遇到的问题的是,很多操作需要用到shell函数,但服务中使用这些函数时就会出错,如SHGetFolderLocation(0,CSIDL_DESKTOP,0,0,&pidl);用getlasterror获得的错误码为2,即无法找到文件。我试过了很多办法,网上最多的可能是SetProcessWindowStation,SetThreadDesktop,SwitchDesktop,但是我试过了,全部都行不通。错误码依然是2.

我想这类问题可能有2种方法解决。
1,有某种方法,把服务的桌面切换到用户的界面,所有的shell函数问题均能引刃而解。不是到有没有这种方法呢?
2,用其他方法代替shell方法,如SHGetFolderLocation是否可以用其他方法获取到pidl的值呢。

希望服务方面比较懂的大神们给点指导,总的项目是一个服务程序,现在编出来的功能经常有这种问题,不得不又另找方法,太悲剧了。
...全文
356 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
renshinn 2014-11-14
  • 打赏
  • 举报
回复
这样,在服务中也能获取到当前用户的桌面信息
renshinn 2014-11-14
  • 打赏
  • 举报
回复
引用
xiaobi_zhi003
这个问题搞定了, 分几步: 得到当前登录用户的会话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(); }
跑步的IT人 2013-12-19
  • 打赏
  • 举报
回复
没解决 自己写一个仿SHBrowseForFolder功能的UI
guxinglei 2013-11-29
  • 打赏
  • 举报
回复
引用 8 楼 xiaobi_zhi003 的回复:
楼主找到解决方法吗 我也碰到了一个类似的问题 带UI的服务调用SHBrowseForFolder无法显示窗口就直接返回
哥们。。 这个问题你解决了吗???
跑步的IT人 2013-06-28
  • 打赏
  • 举报
回复
楼主找到解决方法吗 我也碰到了一个类似的问题 带UI的服务调用SHBrowseForFolder无法显示窗口就直接返回
lqfcu2 2012-11-13
  • 打赏
  • 举报
回复
引用 3 楼 oyljerry 的回复:
可以启动另一个程序,CreateProcessAsUser等来让这个进程跑到user session,然后执行相关动作
这个也是一种解决方法呀,服务实在不行,先用这种方法顶上喽~服务你再慢慢研究呗~
woshinia 2012-11-13
  • 打赏
  • 举报
回复
又3天了,再顶一次看看
woshinia 2012-11-09
  • 打赏
  • 举报
回复
引用 4 楼 redui 的回复:
SHELL跟SESSION完全不相干,不是同一个层面的东西,对楼主的问题没有帮助。 先理解一下SHELL的概念: 1.操作系统本来可以不需要SHELL,比如服务器在正常运行的时候不存在SHELL,只有需要进入桌面环境的帐户才会启动SHELL(桌面本身就是SHELL提供的),桌面应用软件可以无障碍地执行任何SHELL函数。 2.SHELL是绑定账号的,也就是说SH……
首先,服务中一些SHELL函数是绝对可以用的,因为我试过了很多次了,只是涉及到用户桌面相关的路径时无法获取到。 然后,虽然我没有什么官方依据,但从网上的一些资料来看,服务是有桌面的,只是跟用户桌面不在同一个域里,尤其的win7中。服务是可以有窗口的,只是显示在了看不见的区域而已。 还有,Shell部分虽然我不太精通,但我感觉桌面只是一个UI显示的东西而已,我把explorer这个进程结束掉就不能调用Shell函数了么?
redui 2012-11-09
  • 打赏
  • 举报
回复
SHELL跟SESSION完全不相干,不是同一个层面的东西,对楼主的问题没有帮助。 先理解一下SHELL的概念: 1.操作系统本来可以不需要SHELL,比如服务器在正常运行的时候不存在SHELL,只有需要进入桌面环境的帐户才会启动SHELL(桌面本身就是SHELL提供的),桌面应用软件可以无障碍地执行任何SHELL函数。 2.SHELL是绑定账号的,也就是说SHELL必须以某个桌面帐户身份运行。 服务不同,服务没有桌面(或者说服务的桌面是CONSOLE),电脑登录进入桌面之前没有SHELL在执行,但是服务已经运行了,服务中不能使用任何SHELL函数。其次,服务是以system帐户身份运行的,system是内置帐户,不是桌面帐户,不能启用桌面。 即使服务被设置成能跟桌面交互,那也只是系统开的一个后门,不代表能显示窗口就能使用SHELL函数。 某些服务可以以桌面帐户身份执行,但同样不能使用SHELL,所以不要以为桌面帐户运行的程序就一定能用SHELL函数。 说得有点绕,总结一下:只有桌面帐户在桌面环境下的应用才能使用SHELL函数;所有服务程序(包括桌面帐户身份运行的服务程序)都不能使用SHELL函数。所以:找其它API替代吧。
oyljerry 2012-11-09
  • 打赏
  • 举报
回复
可以启动另一个程序,CreateProcessAsUser等来让这个进程跑到user session,然后执行相关动作
admlnl 2012-11-09
  • 打赏
  • 举报
回复
SHGetKnownFolderIDList
woshinia 2012-11-09
  • 打赏
  • 举报
回复
好吧,挂了一天没人理了,来个人我散分吧。

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧