昨天用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

名品推荐:牧玛尼 妙丽 华芬

转载于:https://www.cnblogs.com/personnel/p/4583168.html

Windows 服务程序、窗口界面、桌面交互、与远程桌面相关推荐

  1. Windows内网穿透远程桌面:公网远程桌面控制内网电脑 2/3

    系列文章 Windows内网穿透远程桌面:启用Windows远程桌面 1/3 Windows内网穿透远程桌面:公网远程桌面控制内网电脑 2/3 Windows内网穿透远程桌面:配置固定的远程桌面公网T ...

  2. WIN7远程桌面连接方法!远程控制教程!XP远程桌面连接教程!如何设置远程桌面连接?远程桌面连接设置!

    WIN7远程桌面连接方法! 首先,我们要在被连接的计算机上进行设置.使用鼠标右键单击"计算机"图标,选择"属性"  在打开的"系统&quo ...

  3. WIN7远程桌面连接方法!远程控制教程!XP远程桌面连接教程!如何设置远程桌面连接?远程桌面连接设置...

    WIN7远程桌面连接方法! 首先,我们要在被连接的计算机上进行设置.使用鼠标右键单击"计算机"图标,选择"属性" 在打开的"系统"窗口点击& ...

  4. 远程桌面管理_IIS7远程桌面连接工具使用方法

    一个公司里,都会有多台服务器,为了方便管理,使用IIS7远程桌面管理,大大提高你的工作效率.IIS7远程桌面连接工具更新了原来09网络远程桌面管理的功能和界面,使操作更加方便简单,可以同时远程多台服务 ...

  5. 计算机远程桌面修复,让远程桌面管理恢复顺畅稳定

    为了方便远程治理服务器或非凡工作站,相信不少网络治理人员都喜欢使用Windows 2000以上版本系统内置的远程桌面连接功能,来远程访问服务器或目标工作站,远程连接成功后只要正确输入帐号与密码就能登录 ...

  6. xp计算机远程桌面设置密码,win7远程桌面连接xp 图解win7远程管理xp桌面

    作为网管,除了保证网络的正常运行外,还必须维护各个办公室的电脑,解答同事使用电脑中遇到的问题,因此常常在各个科室间来回穿梭,忙的像个陀 螺.其实只要用好Windows远程桌面连接,很多小问题都可以在自 ...

  7. 两种远程桌面连接方法--远程桌面连接工具

    第一种.用远程桌面连接工具 各种远程桌面连接工具,比如 1.iis7远程桌面:http://yczm.iis7.com/?lxmd 2.Teamviewer:https://www.teamviewe ...

  8. 远程桌面大师android,远程桌面大师iPad版

    远程桌面大师iPad版是从iPhone.iPad.iPod访问电脑系统最方便的App.用户可以通过远程桌面大师iPad版在本地网络查看和编辑Word.Excel.PPT文档和PDF文档,用浏览器来浏览 ...

  9. win7计算机远程桌面连接,Win7远程桌面要怎么连接 Win7中连接远程桌面有诀窍

    远程控制是电脑的一个特殊功能,有时候电脑出现什么问题,不会解决,可以拜托朋友,利用远程控制来解决.这就涉及到一个问题,远程桌面要怎么连接?下面小编就讲讲Win7远程桌面连接设置方法: 第一步:首先,我 ...

  10. 系统没有远程桌面,如何安装远程桌面

    From: http://blog.sina.com.cn/s/blog_53657b280100avdb.html 系统没有远程桌面,如何安装远程桌面 可能是远程桌面对应的组件文件被删除,或是相关服 ...

最新文章

  1. 从零开始系列-Project 2010视频教程 (102课时)
  2. Swift3.0语言教程查找字符集和子字符串
  3. Inf2Cat应用的参数使用详细介绍
  4. A-Frame 简介03
  5. android开发 交换方向,Android实现去哪儿携程地址互换效果
  6. 案例分析: SAP BRF+ rule不工作的原因
  7. javafx属性_JavaFX技巧11:更新只读属性
  8. 5 LInux系统目录结构
  9. 乘法逆元(洛谷-P3811)
  10. Android 按钮选择状态,如何修改Android中的默认按钮状态而不影响按下和选择的状态?...
  11. c语言编程阿拉伯数字转中文,阿拉伯数字转中文大(小)写的函数
  12. 如何在JSP里添加删除cookie
  13. pycharm的使用技巧
  14. BCD码和ASCII码的区别
  15. 60、在Visual Studio 2019 环境下,使用C#调用C++生成的dll实现yolov5的图片检测
  16. Error starting ApplicationContext. To display the conditions report re-run your application with ‘de
  17. 从产品模式到生活方式,苏宁小Biu车联网迈过了哪些坎?
  18. DirectX示例翻译和解析StateManager Sample
  19. ssm+Vue计算机毕业设计虚拟问诊系统(程序+LW文档)
  20. java中创建dvd_JAVA简单模拟DVD功能

热门文章

  1. 一把巴枪,和被改变的菜鸟驿站站长们
  2. 高频炒股软件是一种什么软件?
  3. 空指针异常Exception in thread “main“ java.lang.NullPointerException
  4. Python爬取链家成都小区信息
  5. python核心基础笔记(自总结,根据个人看书思路来写,收藏起来没事看看)
  6. Mac上各版本office哪家强?
  7. Unicode入门与剖析——从一个越南文的案例说起
  8. 小迪安全-Day2数据包拓展
  9. Origin | 绘制三元图
  10. java读取PDF页数