Windows 服务程序、窗口界面、桌面交互、与远程桌面

昨天用c写了一个windows服务(服务内部带一个gui窗口+系统托盘),在windows xp sp3上测试,启动服务后,系统托盘显示正常。

但在另一台windows 2003 sp2 上测试(通过远程桌面登录),晕了,服务是启动了(在进程管理器中能看到),但系统托盘看不到,也就是在桌面的右下角看不到系统托盘的图标。

到网上找原因,找到这么几篇:

http://blog.s135.com/windows_mstsc/

http://chenjava.blog.51cto.com/374566/80250

http://www.sldd.cn/web/bbsxp/ShowPost.asp?id=45110

http://hi.baidu.com/since2006bitlove/blog/item/81555e4cdc52c5f3d62afc71.html

http://topic.csdn.net/u/20090320/17/84ac2e8e-cdff-4ca8-908a-fe7e6854deb6.html

一开始,我参照:http://topic.csdn.net/u/20090320/17/84ac2e8e-cdff-4ca8-908a-fe7e6854deb6.html 在c的代码中显示窗口的前、后面加了这么一段代码:

HDESK   hdeskCurrent;
    HDESK   hdesk;
    HWINSTA hwinstaCurrent;
    HWINSTA hwinsta;

hwinstaCurrent = GetProcessWindowStation();
    if (hwinstaCurrent == NULL)
    {
        //LogEvent(_T("get window station err"));
        return;
    }

hdeskCurrent = GetThreadDesktop(GetCurrentThreadId());
    if (hdeskCurrent == NULL)
    {
        //LogEvent(_T("get window desktop err"));
        return;
    }

//打开winsta0
    hwinsta = OpenWindowStation("winsta0", FALSE,
                                WINSTA_ACCESSCLIPBOARD   |
                                WINSTA_ACCESSGLOBALATOMS |
                                WINSTA_CREATEDESKTOP     |
                                WINSTA_ENUMDESKTOPS      |
                                WINSTA_ENUMERATE         |
                                WINSTA_EXITWINDOWS       |
                                WINSTA_READATTRIBUTES    |
                                WINSTA_READSCREEN        |
                                WINSTA_WRITEATTRIBUTES);
    if (hwinsta == NULL)
    {
        //LogEvent(_T("open window station err"));

return;
    }

if (!SetProcessWindowStation(hwinsta))
    {
        //LogEvent(_T("Set window station err"));

return;
    }

//打开desktop
    hdesk = OpenDesktop("default", 0, FALSE,
                        DESKTOP_CREATEMENU |
                        DESKTOP_CREATEWINDOW |
                        DESKTOP_ENUMERATE    |
                        DESKTOP_HOOKCONTROL  |
                        DESKTOP_JOURNALPLAYBACK |
                        DESKTOP_JOURNALRECORD |
                        DESKTOP_READOBJECTS |
                        DESKTOP_SWITCHDESKTOP |
                        DESKTOP_WRITEOBJECTS);
    if (hdesk == NULL)
    {
        //LogEvent(_T("Open desktop err"));

return;
    }

SetThreadDesktop(hdesk);

//到这一步,我们获取了和用户交互(如显示窗口)的权利

//显示窗口的代码写在这里

.....................................

SetProcessWindowStation(hwinstaCurrent);
    SetThreadDesktop(hdeskCurrent);
    CloseWindowStation(hwinsta);
    CloseDesktop(hdesk);

编译后,在另一台 windows 2003 sp2 上启动服务,然后在 windows xp sp3 上,运行  mstsc /console,吊用没有。

为什么没效果呢?

接着搜索,找到一篇:

远程桌面mstsc /console(/admin) 的运用 -> http://lcq225.blog.163.com/blog/static/16978498201171252623326/

原来:如果系统是WINXP SP3,是不支持 /console这个参数的,需要使用mstsc /admin。经测试,vista 也不支持 mstsc  /console模式,看了一下帮助,是没有/console这个参数的。

windows xp升级到sp3后,命令换成mstsc /admin即可实现winXp2中MSTSC /console的功能。

我试着使用 mstsc /admin 登录,在Java 6 环境,发现系统托盘区还是没有显示图标。

但是,如果手动启动服务,系统托盘就能显示图标了。

我试着使用 mstsc /admin 登录,在Java 7 环境,发现系统托盘区可以正常显示图标。

难道不成,java 6 与 java 7在系统托盘(SystemTray)方面的底层实现有所不同???

 

我接着把上面的代码删除,再启动服务,系统托盘也会显示图标,看来上面的代码是不需要了。

当然,windows服务需要与桌面交互,还是需要设置一下服务的属性:

打开控制面板->服务,查看服务的属性->[登录]-[允许服务与桌面交互],打上钩后,系统托盘就能显示在任务栏。

至于为什么不能显示系统托盘的原因,看了这个介绍才明白

我们的软件在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中的 桌面交互了, 。
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中启动我们的用户界面程序了。

2012-01-21

时间: 2025-01-17 17:54:53

Windows 服务程序、窗口界面、桌面交互、与远程桌面的相关文章

mac远程桌面连接windows 8.1 update,提示: 远程桌面连接无法验证您希望连接的计算机的身份

在网上找到解决方案: SolutionEnable RDP security layer in Group Policy on the machine: Verify that the firewall allows remote desktop connections with RDP (Port 3389)Click Start>RunType gpedit.msc and click "OK"Result: The Group Policy Editor will open

远程桌面连接开启远程桌面功能

一.开启远程桌面功能 计算机右键→属性 左侧导航栏点击"远程设置" 勾选"允许远程协助连接这台计算机".下面三个选项分别是: 1.? 关闭远程桌面功能 2.? 开启远程桌面功能,实现相同操作系统版本或不同操作系统版本间远程桌面控制 3.? 如果不做改动,不同操作系统版本间远程桌面控制无法进行远程桌面连接器:进入远程桌面连接,输入"远程计算机名称"点击"连接".步骤:1计算机右键→属性 2左侧导航栏点击"远程设置&qu

Win7系统怎么开启远程桌面?Win7远程桌面怎么用(转)

远程桌面服务开启之后,可以方便的远程管理服务器或计算机.为生活和工作带来不少便利呢,很多小伙伴还不知道怎么开启win7远程桌面吧(下面咗嚛以内网远程桌面为例) 工具/原料 Win7 Win7远程桌面怎么开启 Win7如何开启远程桌面服务 首先打开桌面“计算机”图标,右键属性打开计算机属性菜单,如下图   打开计算机属性(控制面板----系统和安全---系统选项)找到左侧的“远程设置”功能,如图   出现的“系统属性”菜单中,找到“远程‘选项卡,其中下方的“远程桌面”选项,选择其中一个(注意 远程

MacOS远程桌面 VS 微软远程桌面

MacOS远程桌面 VS 微软远程桌面 当你维护这众多机器时候会由于维护需要经常需要进行主机间的文件传输,如果是Windows系统可以采用远程桌面.虽然远程桌面程序内置了映射磁盘的功能,可以实现远程登录服务器时自动将本地计算机的磁盘映射到服务器上但设置过程对于一些人还是有些复杂. 如果是MacOS系统下远程桌面上相互共享文件变得如此简单,高效率.你只需要懂得拖拽鼠标,其他设置都不用关心. 视频演示: http://edu.51cto.com/index.php?do=lesson&id=1533

浅谈delphi创建Windows服务程序与窗体实现交互

我想实现的功能是创建一个服务程序,然后在服务Start时动态创建一个窗体Form,然后把Form缩小时变成TrayIcon放在Windows托盘上. 我在服务程序的OnStart事件中写到 Started := True; writeWorkLog('serve2 start'); // 写日志 Svcmgr.Application.CreateForm(TForm1, Form1); Form1.show; 日志过程为: procedure writeWorkLog(sqlstr: strin

Windows Server 2008 R2开启新端口远程桌面

[要求] 1.修改默认端口. 2.不用关闭防火墙. [步骤] 1.在注册表中修改端口值: [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp] PortNumber  [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp] PortNumber 2.控制

远程桌面连接命令 远程桌面管理

远程桌面命令主要用于登陆远程的电脑桌面,操作上与本地电脑相同.更多的远程桌面命令主要用于登陆远程服务器,现在市面上很多服务器商都是提高服务器的,列入腾讯云与阿里云是最出名的. 远程桌面命令是什么那首先要知道远程链接的命令是什么,不需要任何软件,mstsc命令即可实现.要想使用 mstsc 这个远程桌面命令,首先要确保对方的电脑上安装了运行此服务的软件,一般微软windows自身携带这个软件,这个功能附带安装在win2000server.win2003server.win2008server上.电

win10 桌面设置为远程桌面

主要原理:利用路由器的虚拟服务器功能,将内网的Ip地址通过端口映射提供给外网,使得外网能够访问到目的主机. 1. 配置路由器上的虚拟服务器,假设目的主机内网的ip为192.168.1.100,则配置如下: 端口3389是远程桌面连接默认的端口号 2. 在目的主机上启用远程桌面连接功能 3. 在目的主机上添加用户 这和win7不一样,需要邮箱注册微软的账号,这里不详细展开叙述了,自己注册一个就好. 4. 假设我们已经在目的主机上添加了新用户,接下来需要将该新用户添加到允许远程桌面连接的用户组中去

windows 2008 R2错误点击禁用远程桌面连接后的解决方法

一.错误操作截图: 二.解决步骤: 1.与该机器建立ipc$连接 net use\\192.168.99.230\ipc$"Password" /user:administrator ----需要知道administrator用户密码,用具体密码代替双引号中的Password ----命令成功执行后,可以通过net use查看 2.确定机器的时间 net time\\192.168.99.230 3.通过计划任务修改注册表 at \\192.168.99.230 15:39 cmd /

windows远程桌面服务器端连接

Windows 系统均自带了远程桌面功能,你不需要额外安装软件即可通过支持「 RDP 协议 」的工具对它们进行远程控制.服务器端: 1.我的电脑->管理->本地用户和组->用户->新建用户设置账号密码,隶属于administrator和remote user 2.我的电脑->属性->远程设置->允许用户远程操作 3.远程桌面连接-选项->本地资源->详细信息->驱动器(选择) 用于复制粘贴功能这就是iis7远程桌面,IIS7远程桌面管理工具(33