`
vanadies10
  • 浏览: 82433 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Windows Vista 交互式服务编程

 
阅读更多
Windows Vista 对快速用户切换,用户账户权限,以及服务程序所运行的会话空间都作了很大的改动,致使一些原本可以工作的程序不再能够正常工作了,我们不得不进行一些改进以跟上 Vista 的步伐。
我们的软件在Windows NT/2000/XP/Vista 系统中安装了一个系统服务,这个服务负责以 SYSTEM 权限启动我们的主程序。我们的主程序启动后会在系统托盘添加一个图标,点击此图标可以弹出控制菜单,通过这个菜单也可以激活配置程序首选项的对话框。在 Windows NT/2000/XP 下我们的程序都可以正常工作。哦不,当 XP 具备了快速用户切换功能的时候我们的问题已经出现了。XP 启动后我们以用户 A 登录,我们的图标出现在系统托盘,一切工作都正常,可当我们使用快速用户切换,切换到用户B后(用户A此时也是已登录状态,并没有注销),虽然用户B已经是本地控制台会话(Session 属性为 Console)但我们的图标已经无法出现了,自然菜单和对话框更无从谈起了。我们的程序是和本机控制台桌面相关的,这种情况无疑是个缺陷。再来看一下在 Vista 平台是怎么样吧,系统启动后以用户A登录,我们的图标更本就没有出现,查看进程管理器中的进程列表发现我们的程序已经启动了,当我们从远端检查我们的服务,发现已经正常工作,尝试远程登录我们的服务,Vista 会在本机控制台弹出一个消息框,提示有交互式服务消息,是否查看这个消息,点击立刻查看发现切换到另外一个桌面去了。
于是开始分析这种情况发生的原因。在 Windows NT/2000 中系统服务进程和本机控制台交互式登录的用户都运行于Session0 中,默认用户桌面运行于 WinSta0 窗口站,所以我们的程序由服务程序启动时依然是和本机用户处于同一个Session中,即使在某些情况下出现不能弹出对话框或者无法添加系统托盘图标的情况也只需要修改一下进程桌面到 WinSta0\Default 就可以了(可以参考 MSDN 中 OpenInputDesktop, SetThreadDesktop 等API的说明)。
XP为我们带来了快速用户切换,也让我们所采用的软件架构问题浮现出来。当我们快速切换到用户B的时候,用户A仍然在会话中(Session0),而用户B则处于新启动的会话中(Session1或者其他),此时服务程序和本机控制台程序就不在处于同一会话了,OpenInputDesktop,SetThreadDesktop 等API的工作范围仅限于本Session,用户A没有退出,Session0也依然存在但是已经是 Disconnected 状态,当进程所处的Session是 Disconnected 状态的时候调用 OpenInputDesktop 会返回错误“无效的API”。进程及线程所属的Session 是由他们的Token 结构中的 TokenSessionId 决定的(参见MSDN中SetTokenInformation 和 TOKEN_INFORMATION_CLASS的说明),我尝试以微软提供的相关API修改运行中的进程和线程的TokenSessionId 信息从而达到修改桌面环境的目的,到目前还没有成功过(或许可以尝试参考RootKit 技术,不过即使修改成功到底能不能实现我们的需求也不确定)。我们的进程无法跨越Session的界限,自然无法与当前活动的另外一个Session中的桌面交互了,L 。
Vista中又是如何的一番景象呢?处于安全方面及其他因素的考虑,Vista以及将所有的服务程序置于Session0中,而为本机第一个交互登录的用户创建了Session1,快速切换到用户B后则是 Session2,无论是本机登录的用户,快速切换后的用户,还是远程桌面登录的用户再也没有谁和服务进程处于同一个Session中了,我们的程序还运行在Session0中,自然我们的托盘图标是没有用户能看到了。事实上这个图标还是可以出现的。Session0因为不是一个交互式会话所以没有象其他用户环境初始化的时候一样启动Explorer程序,但是我们开始可以手工启动他,在Session0中启动 Explorer 后任务栏出现后我们还是看到了我们的图标(具体启动Explorer的方法我们不在此文中讨论),菜单、对话框也可以使用。
既然我们的程序必须运行在Session0而我们又没有办法把我们的图标、对话框一下子就抛到隔壁Session的用户桌面上去,只能想其他的办法了。微软也不提倡我们这种服务程序直接提供GUI与用户直接交互的方式,而他们建议使用C/S架构,Client/Server之间用Socket/Pipe/RPC等方式通讯,这样我们只要把Client整个进程放到用户Session去和用户交互,然后将配置信息等内容通过上述途径传递给Server,服务端在作出相应的响应即可。
把GUI分离出来并不是那么困难,然后在以前直接调用的地方加上一个通过Pipe通讯的接口,这样GUI(Client)的运行就可以灵活的掌握了。
最初我想把用户界面程序放到 Startup(启动)中随用户登录自动启动。这样当用户A和B都登录后将有两个用户界面程序在运行,而我们的服务只是和当前活动的控制台登录用户交互,所以这样并不符合需求。
接下来我们需要看看如何判定当前的活动Session是哪个,然后如何在这个活动Session中启动我们的用户界面程序了。
微软从XP/2003开始为我们提供了一套Windows Terminal Service 的相关API,这些API都以WTS开头(请安装MSDN2005以查阅相关说明),要获得活动Session也不止一个途径,最简单的就是直接使用
DWORD WTSGetActiveConsoleSessionId(void);
来获得活动Session Id 。要在程序中使用这些API需要最新的Platform SDK(如果你正在使用Visual Studio 2005那么它已经具备了相关头文件和库文件可以直接使用了),如果你在使用VC++ 6.0 你也没有或者不打算安装最新的SDK那么你可以直接使用LoadLibrary() 装载wtsapi32.dll然后使用GetProcAddress()获得相关函数的地址以调用它们。我们获得了活动SessionId后就可以使用
BOOL WTSQueryUserToken(
ULONG SessionId,
PHANDLE phToken
);
来获取当前活动Session中的用户令牌(Token),有了这个Token我们的就可以在活动Session中创建新进程了,
BOOL CreateProcessAsUser(
HANDLE hToken,
LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
将我们获得的Token作为此API的第一个参数即可,你可以先尝试一下运行一个notepad.exe看看,怎么样?你可以在控制台桌面上看到新进程了。再查看一下进程列表,该进程的用户名是当前控制台登录的用户。可是这里我们又遇到一个问题,我们需要收集当前交本机互式登录用户的一些信息,而有些操作需要很高的权限才能完成,而Vista下即使是Administraotrs用户组成员默认也是以Users权限启动进程的,所以我们创建的新进程只有Users权限,无法完成一些操作,当然我们可以使用Vista所提供的UI来询问用户以提升至管理员权限,可有些操作甚至是管理员Token也无法完成的,而且需要用户确认实在在易用性上大打折扣,所以我决定在活动Session中以SYSTEM权限启动我们的用户交互程序。显然 WTSQueryUserToken() 是不好用了。
之前,我们提到过进程所属的Session是由进程Token中的TokenSessionId来决定的,那么我们是不是可以复制服务进程的Token然后修改其中的TokenSessionId,从而在用户桌面上创建一个具有SYSTEM权限的新进程呢?答案是肯定的。一下是实现这个操作的代码,为了缩小篇幅我删除了异常处理代码
HANDLEhTokenThis = NULL;
HANDLEhTokenDup = NULL;
HANDLEhThisProcess = GetCurrentProcess();
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, &hTokenDup);
DWORDdwSessionId = WTSGetActiveConsoleSessionId();
SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD));

STARTUPINFOsi;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";

LPVOIDpEnv = NULL;
DWORDdwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;

CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE);

CreateProcessAsUser(
              hTokenDup,
              NULL,
              (char *)"notepad",
              NULL,
              NULL,
              FALSE,
              dwCreationFlag,
              pEnv,
              NULL,
              &si,
              &pi);
 


到这里我们的大部分工作已经完成了,我们还需要做的就是监控活动Session的变化,就是用户的登录、注销、快速切换。WTS系列API以及为我们提供了具备这些能力的API了,大致可以用一下几种方法实现:
1.              设置一个定时器,使用WTSGetActiveConsoleSessionId()轮询活动桌面id,当检测到变化的时候让用户交互程序的前一个实例退出,在新活动Session中创建新进程。
2.              使用WTSRegisterSessionNotification()函数注册一个窗口来接收WTSSESSION_NOTIFICATION消息,来判断Session变化。
3.              使用 WTSEnumerateSessions枚举所有Session然后根据返回的WTS_SESSION_INFO结构中的State成员来判断Session状态,找到处于 Active状态的Session.
结合你的其他需求选择其中之一,然后作出响应就可以了。
分享到:
评论

相关推荐

    windows Vista交互式服务编程

    windows vista交互式服务编程JavaEye技术网站

    Windows Vista Gadgets Programming Dec.2007.pdf

    《Windows Vista Gadgets Programming》一书由Wei-Meng Lee撰写,深入探讨了Windows Vista系统下Gadgets(小工具)的编程技术与应用。本书共分为两个主要部分:第一部分专注于Windows Sidebar Gadgets,第二部分则...

    Windows Vista培训系列课程(12):WPFE 编程

    **Windows Vista培训系列课程(12):WPFE 编程** Windows Presentation Foundation (WPF),也称为Windows Vista中的Avalon,是Microsoft为.NET Framework 3.0引入的一个核心组件,它彻底改变了Windows应用程序的设计...

    C++ 学习资料大全 C++编程思想 WINDOWS 核心编程 WINDOWS程序设计第5版 深入浅出MFC简体中文版 C++ Primer 3rd Edition 中文完美版

    接着,《深入浅出MFC》教你如何利用MFC创建交互式Windows应用程序;《WINDOWS程序设计》和《WINDOWS核心编程》则让你掌握Windows系统的底层知识。这样的学习顺序既有助于理论与实践的结合,也能逐步提升你的编程技能...

    Windows Vista培训系列课程(9):WPF之多媒体编程

    **Windows Vista培训系列课程(9): WPF之多媒体编程** Windows Presentation Foundation (WPF),是Microsoft在Windows Vista中引入的一种全新的用户界面框架,它极大地扩展了.NET Framework的应用开发能力,尤其是在...

    Windows Vista 内核结构大典

    这本书基于Windows Vista内核的符号表,详细解析了内核级别的数据结构,为那些进行Windows内核编程的开发者提供了宝贵的指导。以下是该书涉及的一些核心知识点: 1. **进程与线程管理**:Windows Vista内核中的进程...

    Windows Vista培训系列课程(12):WPF.E 编程

    Windows Vista中的WPF.E(Windows Presentation Foundation Everywhere)是微软推出的一种跨平台的富客户端应用程序开发框架,旨在为开发者提供一个统一的编程模型,以便创建具有丰富图形、媒体和交互性的应用程序。...

    Windows Vista培训系列课程(5):WPF之控件编程

    其中,Windows Presentation Foundation(WPF),又称为Avalon,是Vista中引入的一个革命性的图形子系统,用于构建丰富的、交互式的桌面应用程序。本节我们将深入探讨“Windows Vista培训系列课程(5):WPF之控件编程...

    Windows Vista培训系列课程(8):WPF之文档编程

    这一模型允许开发者创建包含文本、图像、图表、视频等多种元素的交互式文档,且这些元素能够与应用程序的其他部分无缝集成。 首先,WPF的文档模型主要由两种类型的文档支持:Flow Documents和Fixed Documents。Flow...

    Windows Vista培训系列课程(2):Windows Presentation Foundation概要

    Windows Presentation Foundation (WPF),是Microsoft在Windows Vista操作系统中引入的一项重要技术,它是.NET Framework 3.0的一部分,旨在为开发者提供一个统一的编程模型来构建丰富的、交互式桌面应用程序。...

    Windows Vista 黄金周系列课程(1):WinFX----下一代的开发平台

    **Windows Vista 黄金周系列课程(1):WinFX——下一代的开发平台** Windows Vista 黄金周系列课程是针对微软操作系统Windows Vista的一次深入学习活动,旨在帮助开发者理解和掌握Vista中的新特性和开发工具。首讲...

    Professional.Windows.Vista.Gadgets.Programming

    《专业Windows Vista小工具编程》一书由Wei-Meng Lee撰写,由Wiley Publishing, Inc.出版,深入探讨了在Windows Vista操作系统下开发小工具(Gadgets)的技术与实践。本书不仅覆盖了Windows Sidebar小工具的编程,还...

    Windows Vista 领航系列课程(6):开发基于RSS的应用程序

    - WPF提供了丰富的UI设计工具,而WCF则用于服务间的通信,包括与RSS源的交互。 - XML编程接口,如System.Xml命名空间下的类,可以帮助解析和创建RSS feed。 4. 示例和教程: - 压缩包中的PPT可能包含RSS开发的...

    迷你asp服务器2000/xp/vista

    ASP是一种由微软开发的服务器端脚本语言,它允许开发者创建交互式的、动态的Web内容。通过ASP,程序员可以将HTML、VBScript(Visual Basic Script)或JScript代码与数据库、XML文件或其他Web服务集成,生成动态页面...

    Wrox - Professional Windows Vista Gadgets Programming (Dec 2007)

    《精通Windows Vista Gadgets编程》是一本专注于Windows Vista操作系统中Gadgets开发的专业书籍,出版于2007年。Gadgets是Windows Vista引入的一种桌面小工具,它们提供了便捷的方式来展示信息或执行简单的功能,...

    Wiley.Windows.Vista.Secrets.SP1.Edition.Oct.2008.eBook-DDU

    3. **AJAX (Asynchronous JavaScript and XML)**:AJAX是一种用于创建交互式网页应用的技术,允许网页在不重新加载整个页面的情况下异步地与服务器通信,从而提供更流畅、更响应式的用户体验。 4. **ASP.NET**:这...

    Windows Vista培训系列课程(7):WPF之互操作

    在Windows Vista中,WPF引入了丰富的图形渲染、XAML(Extensible Application Markup Language)用于声明式编程,以及强大的数据绑定和控件库,为开发者提供了构建现代桌面应用的强大工具。 在“WPF之互操作”这个...

Global site tag (gtag.js) - Google Analytics