在服务程序中弹出对话框

Win7交互式服务编程,不弹出交互式服务检测 第一次写Windows服务程序,XP下一个MessageBox都弹不出来,在Services.msc中允许其与桌面交互后,MessageBox就能正常弹出。但在Win7下总是弹出[Windows交互式服务检测]的对话框,即使选择显示消息,也完全是在另一个环境下显示的,这是在Win7下交互式服务所面临的共同问题。 在百度上查了一下,知道交互式服务检测由Interactive Services De 阅读详情

最近一个项目中,客户一定要在服务程序中弹出对话框。跟客户好说歹说,说我们已经记了Log,弹对话框没有意义,反而可能由于弹框后没有人管,造成程序停滞在那里的情况。但是,客户不管这些,就要弹对话框。

没辙,弹吧,弹个框还能多费事?没想到,还真挺费事。WinXP和Windows2003下问题不大,上网找找方法,框就弹出来了。但是,Vista和Windows2008下,这个框死活弹不出来。

 

先说说在WinXP和Windows2003下用的方法。

 

第一种方法是在服务进程中启动一个子进程。用该子进程弹出对话框。.NET的C#代码大致如下:

public static void Show(string msg, string cap, MessageBoxButtons buttons, MessageBoxIcon icon)

{

try

     {

Process proc = new Process();

proc.StartInfo.FileName = EXE_NAME;

proc.StartInfo.Arguments = string.Format(ARG_FMT, msg, cap, buttons, icon);

proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

proc.Start();

}

catch

{ }

}

这段代码是启动一个进程。该进程唯一的目的是显示一个对话框,大致的代码如下:

 

static class Program

{

    /// <summary>

    /// The main entry point for the application.

    /// </summary>

    [STAThread]

    static void Main(string[] args)

    {

        try

        {

            string strMsg = args[0];

            string strCap = args[1];

            MessageBoxButtons btn = (MessageBoxButtons)Enum.Parse(typeof(MessageBoxButtons), args[2]);

            MessageBoxIcon icon = (MessageBoxIcon)Enum.Parse(typeof(MessageBoxIcon), args[3]);

MessageBox.Show(strMsg, strCap, btn, icon, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);

        }

        catch

        { }

    }

}

 

这里的做法是指定子进程的线程模型为STAThread。这就意味着线程的消息是靠一个隐含的窗口来分发。也正因为有这个隐含的窗口,该子进程获得了交互能力,可以弹出对话框。

 

不幸的是,在Vista和Windows2008下,用这种方法时,子进程无法成功创建。

 

还有另一种方法,可以不创建子进程,直接在服务进程中显示对话框。代码大致如下,由于主要是调用API,这里直接展示C++形式的代码:

   HDESK   hdeskCurrent;
    HDESK   hdesk;
    HWINSTA hwinstaCurrent;
    HWINSTA hwinsta;
 
    hwinstaCurrent = GetProcessWindowStation();
    hdeskCurrent = GetThreadDesktop(GetCurrentThreadId());
 
// Open winsta0
    hwinsta = OpenWindowStation("winsta0", FALSE,                          
                                  WINSTA_ACCESSCLIPBOARD   |
                                  WINSTA_ACCESSGLOBALATOMS |
                                  WINSTA_CREATEDESKTOP     |
                                  WINSTA_ENUMDESKTOPS      |
                                  WINSTA_ENUMERATE         |
                                  WINSTA_EXITWINDOWS       |
                                  WINSTA_READATTRIBUTES    |
                                  WINSTA_READSCREEN        |
                                  WINSTA_WRITEATTRIBUTES);
    SetProcessWindowStation(hwinsta);
 
// Open default desktop
    hdesk = OpenDesktop("default", 0, FALSE,                
                            DESKTOP_CREATEMENU |
                            DESKTOP_CREATEWINDOW |
                            DESKTOP_ENUMERATE    |
                            DESKTOP_HOOKCONTROL  |
                            DESKTOP_JOURNALPLAYBACK |
                            DESKTOP_JOURNALRECORD |
                            DESKTOP_READOBJECTS |
                            DESKTOP_SWITCHDESKTOP |
                            DESKTOP_WRITEOBJECTS);
    SetThreadDesktop(hdesk);
 
// Show the dialog
    CMsgDlg dlgMsg;
    dlgMsg.DoModal();              

 

可以看到,这种方法的关键是OpenWindowStation、SetProcessWindowStation、OpenDesktop和SetThreadDesktop这四个函数。这种方法的思路是:当前进程所处于的Session必须有界面交互能力,这样才能显示出对话框。由于第一个交互式用户会登录到拥有WinSta0的Session 0,所以,强制性地把服务所在的进程与WinSta0关联起来,并且打开当前的桌面,把工作线程挂到该桌面上,就可以显示出对话框。

这种方法在WinXP和Windows2003下工作得不错,很遗憾,在Vista和Windows2008下,一旦执行到OpenWindowStation,试图代开WinSta0工作站时,程序就会出异常。

 

为什么会这样?看来还有一些深层的东西在制约着Vista和Windows2008,使得服务程序无法显示对话框。

 

首先了解一下程序要具备怎样的条件才能与界面交互。Windows提供了三类对象:用户界面对象(User Interface)、GDI对象和内核对象。内核对象有安全性,而前两者没有。为了对前两者提供安全性,通过工作站对象(Window station)和桌面对象(Desktop)来管理用户界面对象,因为工作站对象和桌面对象有安全特性。简单说来,工作站是一个带有安全特性的对象,它与进程相关联,包含了一个或多个桌面对象。当工作站对象被创建时,它被关联到调用进程上,并且被赋给当前Session。交互式工作站WinSta0,是唯一一个可以显示用户界面,接受用户输入的工作站。它被赋给交互式用户的登录Session,包含了键盘、鼠标和显示设备。所有其他工作站都是非交互式的,这就意味着它们不能显示用户界面,不能接受用户的输入。当用户登录到一台启用了终端服务的计算机上时,每个用户都会启动一个Session。每个Session都会与自己的交互式工作站相联系。桌面是一个带有安全特性的对象,被包含在一个窗口工作站对象中。一个桌面对象有一个逻辑的显示区域,包含了诸如窗口、菜单、钩子等等这样的用户界面对象。

 

在Vista之前,之所以可以通过打开Winsta0和缺省桌面显示对话框,是因为不管是服务还是第一个登录的交互式用户,都是登录到Session 0中。因此,服务程序可以通过强制打开WinSta0和桌面来获得交互能力。

然而,在Vista和Windows2008中,Session 0专用于服务和其他不与用户交互的应用程序。第一个登录进来,可以进行交互式操作的用户被连到Session 1上。第二个登录进行的用户被分配给Session 2,以此类推。Session 0完全不支持要与用户交互的进程。如果采取在服务进程中启动子进程来显示对话框,子对话框将无法显示;如果采取用OpenWindowStation系统API打开WinSta0的方法,函数调用会失败。总之,Vista和Windows2008已经堵上了在Session 0中产生界面交互的路。这就是原因所在。

 

那么,是否真的没法在服务中弹出对话框了呢?对于服务进程自身来说,确实如此,操作系统已经把这条路堵上了。但是,我们想要的并不是“在服务进程中弹出对话框”,我们想要的不过是“当服务出现某些状况的时候,在桌面上弹出对话框”。既然在Session 0中无法弹出对话框,而我们看到的桌面是Session X,并非Session 0,很自然的一个想法是:能不能让Session 0通知其他的Session,让当前桌面正显示着的Session弹一个对话框呢?

幸运的是,还真可以这样做。一个Session中的进程可以用WTSSendMessage,让另一个Session弹出对话框。WTSSendMessage的一个参数是SessionID,目的是指定要弹出对话框的Session。为了获得当前显示的桌面所在的SessionID,可以用WTSGetActiveConsoleSessionId得到这个SessionID。代码大致类似于:

 

public static bool Show(string msg, string cap, MessageBoxButtons buttons, MessageBoxIcon icon)

{

    try

    {

        Int32 sessionId = WTSGetActiveConsoleSessionId();

        Int32 result = 0;

 

        bool bSuccess = WTSSendMessage((IntPtr)0, sessionId, cap, cap.Length, msg, msg.Length, Convert.ToInt32(buttons) + Convert.ToInt32(icon), 0, ref result, true);

 

        return bSuccess;

    }

    catch

    {

        return false;

    }

}

 

要弹个框还真挺费劲!

保姆级教程:在RK3588开发板上编译带MPP硬件加速的FFmpeg(含完整依赖库配置) 本文提供在RK3588开发板上编译支持MPP硬件加速的FFmpeg的详细教程,涵盖交叉编译环境搭建、MPP框架及依赖库配置,最终实现4K视频硬件编解码性能优化。通过实战步骤和性能对比,展示如何充分发挥RK3588的硬件加速能力。 阅读详情

相关推荐

ELK 企业级日志分析系统(1)

ELK平台是一套完整的日志集中处理解决方案,将、Logstash和Kiabana三个开源工具配合使用, 完成更强大的用户对日志的查询、排序、统计需求。ElasticSearch:是基于Lucene(一个全文检索引擎的架构)开发的分布式存储检索引擎,用来存储各类日志。Elasticsearch 是用 Java 开发的,可通过 RESTful Web 接口,让用户可以通过浏览器与 Elasticsearch 通信。

云计算运维工程师的成长之路 1864

win7 下服务程序弹出对话框 win7 session 隔离

关于win7与vista下session隔离的文章网上已经有很多文章,大家可以自己google。 这里主要讲win7与vista下服务程序如何弹出对话框。 这个问题也是我自己遇到过,需要服务程序与用户进行简单的交互比如说弹出个对话框。 但是在win7与vista下直接使用messagebox将会出现一个交互式对话框提示用户是否查看消息,如果用户点击否则服务程序就阻塞在那里了。 于是到网上找

LD_CSU_EDU的专栏 1191

Unity机械拆装实战:5步搞定发动机模型交互式装配(附完整代码)

本文详细介绍了在Unity中实现高交互性机械拆装仿真的完整流程。以发动机模型为例,通过5个核心步骤:项目初始化与模型准备、核心交互实现、智能装配逻辑、场景管理与相机控制、进阶优化与扩展,系统讲解了从零构建交互式装配功能的方法,并提供了完整的代码示例。

weixin_28049429的博客 215

如何在SYSTEM权限下实现屏幕监控

屏幕监控是远控软件的基本功能之一。 版权声明 作者:iprowq 现在很多远控程序的服务端通常为DLL形式,通过远程线程注入等方法插入到services、svchost等SYSTEM权限的进程中去,而此时常规的屏幕监控就会失效(这是因为与SYSTEM权限进程关联的窗口站、桌面与普通进程不同)。 如何才能在SYSTEM权限下实现屏幕监控呢? 一、 屏幕监控的基本原理 屏幕监控简单

ccx_john的专栏 1912

【HCIA学习记录】WLAN配置实验

HCIA-WLAN

寸先生的AI道路 3874

TX 的 LOL(Local Oscillator Leakage,本振泄露)

项目内容LOL 是什么本振残留在 TX 输出中心频率上的杂散主要原因IQ 失衡、硬件不完美、零中频架构影响杂散、干扰、性能劣化、安全问题解决方法初始化校准 + 跟踪校准(AD9371 支持)检测手段频谱仪、回环检测、ADC ILA 抓取。

weixin_41230430的博客 2046

在Windows服务程序中弹出信息提示框

只需要把已经安装的服务“右键->属性->勾选允许服务于桌面交互”

CoCoLait 6747

MOS五类漏电流与优化策略

分析了五种主要漏电流机制:1)反偏结泄漏,由PN结热激发和隧

硬核科技 442

系统服务程序弹出对话框

BOOL ShowMSGBox(string msg, string cap) {  try  {   int sessionId = WTSGetActiveConsoleSessionId();   DWORD result = 0;   BOOL bSuccess = WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, sessionId, (ch

255

论文必备 - 绘制YOLOv8模型在训练过程中,精准率,召回率,mAP_0.5,mAP_0.5:0.95,以及各种损失的变化曲线

文件是模型在训练过程中,实时记录训练的结果,和当时控制台输出的信息一致。当然还包含一些验证损失,学习率变化等数据。epoch:记录训练的轮次,总轮次为训练文件中设置的epochs大小。:边界框损失。在训练过程中,此值逐渐变小,越小表示模型预测的边界框与真实边界框之间的差异越小。:分类损失。在训练过程中,此值逐渐变小,越小表示模型对目标类别的预测越准确。:分布焦点损失。将边界框的回归问题转化为对边界框四个边的分布预测问题,越小表示预测越准确。:精确率也称为查准率。

Limiiiing的博客 1407

乐企归集能力说明文档V2.0006

纳税人销售货物、提供服务开具的增值税发票及购进货物、接受服务取得的增值税发票、海关缴款书(含出口转内销证明)、代扣代缴完税凭证,可以通过本能力进行归集。纳税人可将本能力中的各类规则和接口嵌入本单位信息化系统中(如:销售、报销、财务等),实现发票自动化归集,便于纳税人完成发票入账、抵扣、退税以及代办退税等操作,有效提升涉税业务办理效率。

记录点滴 573

Windows service 界面问题

1、VC2008中编写“Windows服务”(Windows Service)程序 vc2008下新建一个 ATL 项目-》 选择创建一个“服务”类型的ATL 项目TestService,将生成如下代码, class CTestServiceModule : public CAtlServiceModuleT CTestServiceModule, IDS_SERVICENAM

v2nero的专栏 843

基于Python的全卷积网络(FCN)实现路径损耗预测

本文提出一种基于全卷积网络(FCN)的无线信道路径损耗预测方法。通过合成数据生成模块构建包含房间布局和发射点坐标的训练数据集,采用双分支FCN架构融合空间特征与坐标信息,引入空间注意力机制增强关键区域提取。实验表明,该方法相比传统模型能更准确地预测复杂环境下的路径损耗,平均绝对误差降低约35%。系统支持端到端训练,可扩展融合多模态数据,为5G网络规划等应用提供高效预测工具。

huanghm88的专栏 577

眼睛保护程序

近来,由于面对屏幕时间过长,眼睛很是不舒服,想写个自动提示工作时间的服务程序来提醒自己.于是上网搜索一通,找到了一位仁兄写的03代码,移植下,就这样的剽窃了他的成果,在此先谢过了.不要追究责任哦.其实很简单的一个服务程序.就是隔一小时弹出个信息框告诫下自己要注意休息下.大概步骤是:创建一个WINDOWS服务程序,命名为:EyeService.引用下 System.Windows.Forms;用以弹

中尉 1245

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

IIS+.Net运行环境问题

一、win2000+iis5.1+.net2003环境        iis已经启动,建立一个c#的asp.net web应用程序或者服务程序失败,弹出“Vusia Studio.net已检测到指定的Web服务器运行的不是ASP.net1.1版,您将无法运行ASP.net Web应用程序或服务”对话框。分析:是先装.Net 框架,后装的IIS,.Net 框架没注册好 有命令可以注册,或者卸载fra

慧慧的Blog 1063

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Windows服务初探

作者:文斌主页:文斌程序网 http://www.wenbinweb.com Windows服务是独立于登录用户而工作的Windows应用程序,它通常在计算机启动时开始执行,且常常连续执行,直到计算机关闭为止。像Exchange Server,IIS和杀毒软件等都使用这种方式,这样就可以独立于某一用户而且可以在任何用户登录前来运行,同时也可以服务于所有的进程,从而以一种服务的形式存在。 正因为Wi...

buliedian 95

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

windows服务程序弹出有界面的MessageBox

WTSSendMessage可以在指定的用户会话中弹出对话框,获取用户会话可以用WTSGetActiveConsoleSessionId获取当前活动用户的会话id OE_UINT32 sessionId = WTSGetActiveConsoleSessionId(); DWORD dwRespon = 0xff; if(!WTSSendMessage((HANDLE)0, se

youyudexiaowangzi的专栏 3256

windows服务程序一

Windows 服务程序(一) </h1> <div class="clear"></div> <div class="postBody"> <div id="cnblogs_post_body" class="blogpost-body blogpost-body-html"> Wi...

宇之日记 1835
上一篇: 风中有朵雨做的云
hellothere
博客等级 码龄21年 176粉丝 9原创
评论 9
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值