服务(Service)对于大家来说一定不会陌生,它是Windows 操作系统重要的组成部分。我们可以把服务想像成一种特殊的应用程序,它随系统的“开启~关闭”而“开始~停止”其工作内容,在这期间无需任何用户参与。Windows 服务在后台执行着各种各样任务,支持着我们日常的桌面操作。有时候可能需要服务与用户进行信息或界面交互操作,这种方式在XP 时代是没有问题的,但自从Vista 开始你会发现这种方式似乎已不起作用。

现在有个需求需要服务程序弹框提示和启动包含复杂UI的桌面程序,"穿透Session 0 隔离"这篇文章已经写得很好了,看了之后非常有帮助,但是在最后启动了cmd之后发现就只能启动cmd,启动其他类型的程序都会报错。仔细看了评论发现还是没有解决,只是照着抄了一遍,发现不仔细看还是不是自己的东西(知识)啊。

原文链接:

穿透Session 0 隔离(一)

穿透Session 0 隔离(二)

最后修改了一下程序,解决了问题。跟原博主李敬然写的稍微有点区别。我的是抄的msdn的代码。总之就是 CreateProcessAsUser 函数的申明和调用有些区别。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Principal; namespace WindowsService1
{
public class WinAPI_Interop
{
public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
/// <summary>
/// 服务程序执行消息提示,前台MessageBox.Show
/// </summary>
/// <param name="message">消息内容</param>
/// <param name="title">标题</param>
public static void ShowServiceMessage(string message, string title)
{
int resp = ;
WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTSGetActiveConsoleSessionId(), title, title.Length, message, message.Length, , , out resp, false);
} [DllImport("kernel32.dll", SetLastError = true)]
public static extern int WTSGetActiveConsoleSessionId(); [DllImport("wtsapi32.dll", SetLastError = true)]
public static extern bool WTSSendMessage(IntPtr hServer, int SessionId, String pTitle, int TitleLength, String pMessage, int MessageLength,int Style, int Timeout, out int pResponse, bool bWait);
#region P/Invoke WTS APIs
private enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
} [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct WTS_SESSION_INFO
{
public UInt32 SessionID;
public string pWinStationName;
public WTS_CONNECTSTATE_CLASS State;
} [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool WTSEnumerateSessions(
IntPtr hServer,
[MarshalAs(UnmanagedType.U4)] UInt32 Reserved,
[MarshalAs(UnmanagedType.U4)] UInt32 Version,
ref IntPtr ppSessionInfo,
[MarshalAs(UnmanagedType.U4)] ref UInt32 pSessionInfoCount
); [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
static extern void WTSFreeMemory(IntPtr pMemory); [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token);
#endregion #region P/Invoke CreateProcessAsUser
/// <summary>
/// Struct, Enum and P/Invoke Declarations for CreateProcessAsUser.
/// </summary>
/// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
} [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
} /// <summary>
/// 以当前登录的windows用户(角色权限)运行指定程序进程
/// </summary>
/// <param name="hToken"></param>
/// <param name="lpApplicationName">指定程序(全路径)</param>
/// <param name="lpCommandLine">参数</param>
/// <param name="lpProcessAttributes">进程属性</param>
/// <param name="lpThreadAttributes">线程属性</param>
/// <param name="bInheritHandles"></param>
/// <param name="dwCreationFlags"></param>
/// <param name="lpEnvironment"></param>
/// <param name="lpCurrentDirectory"></param>
/// <param name="lpStartupInfo">程序启动属性</param>
/// <param name="lpProcessInformation">最后返回的进程信息</param>
/// <returns>是否调用成功</returns>
[DllImport("ADVAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CreateProcessAsUser(IntPtr hToken,string lpApplicationName,string lpCommandLine,IntPtr lpProcessAttributes,IntPtr lpThreadAttributes,
bool bInheritHandles,uint dwCreationFlags,string lpEnvironment,string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,out PROCESS_INFORMATION lpProcessInformation); [DllImport("KERNEL32.DLL", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool CloseHandle(IntPtr hHandle);
#endregion /// <summary>
/// 以当前登录系统的用户角色权限启动指定的进程
/// </summary>
/// <param name="ChildProcName">指定的进程(全路径)</param>
public static void CreateProcess(string ChildProcName)
{
IntPtr ppSessionInfo = IntPtr.Zero;
UInt32 SessionCount = ;
if (WTSEnumerateSessions(
(IntPtr)WTS_CURRENT_SERVER_HANDLE, // Current RD Session Host Server handle would be zero.
, // This reserved parameter must be zero.
, // The version of the enumeration request must be 1.
ref ppSessionInfo, // This would point to an array of session info.
ref SessionCount // This would indicate the length of the above array.
))
{
for (int nCount = ; nCount < SessionCount; nCount++)
{
WTS_SESSION_INFO tSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure(ppSessionInfo + nCount * Marshal.SizeOf(typeof(WTS_SESSION_INFO)), typeof(WTS_SESSION_INFO));
if (WTS_CONNECTSTATE_CLASS.WTSActive == tSessionInfo.State)
{
IntPtr hToken = IntPtr.Zero;
if (WTSQueryUserToken(tSessionInfo.SessionID, out hToken))
{
PROCESS_INFORMATION tProcessInfo;
STARTUPINFO tStartUpInfo = new STARTUPINFO();
tStartUpInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
bool ChildProcStarted = CreateProcessAsUser(
hToken, // Token of the logged-on user.
ChildProcName, // Name of the process to be started.
null, // Any command line arguments to be passed.
IntPtr.Zero, // Default Process' attributes.
IntPtr.Zero, // Default Thread's attributes.
false, // Does NOT inherit parent's handles.
, // No any specific creation flag.
null, // Default environment path.
null, // Default current directory.
ref tStartUpInfo, // Process Startup Info.
out tProcessInfo // Process information to be returned.
);
if (ChildProcStarted)
{
CloseHandle(tProcessInfo.hThread);
CloseHandle(tProcessInfo.hProcess);
}
else
{
ShowServiceMessage("CreateProcessAsUser失败", "CreateProcess");
}
CloseHandle(hToken);
break;
}
}
}
WTSFreeMemory(ppSessionInfo);
}
}
}
}

调用:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Windows.Forms; namespace WindowsService1
{
public partial class AlertService : ServiceBase
{
public AlertService()
{
InitializeComponent();
} protected override void OnStart(string[] args)
{
//Interop.ShowMessageBox("This a message from AlertService.","AlertService Message");
WinAPI_Interop.CreateProcess(@"E:\work\box\GreenlandBox\BinFiles\ClientBin\BufferBox.exe");
//Interop.CreateProcess("cmd.exe", @"C:\Windows\System32\");
} protected override void OnStop()
{
}
}
}

CreateProcessAsUser,C#写的windows服务弹框提示消息或者启动子进程的更多相关文章

  1. Windows服务弹出MessageBox对话框

    Windows服务弹出MessageBox对话框 自从Windows升级到Vista版本后,系统服务就不在允许弹出那些惨绝人寰的MessageBox了(至于为什么不让弹出,原理有点小复杂,我也不是很门 ...

  2. Dynamics CRM2016 关闭错误报告弹框提示

    在之前的版本中错误报告的弹框提示是可以在隐私首选项中设置关闭的,如下图所示 但是在2016中这个设置没了 有人说在右上角的选项中设置,但那个只能是设置个人的无法修改系统级别的.在系统中找了半天还是没有 ...

  3. 解决IE弹框提示“是否停止运行此脚本”问题

    有少数情况因为js处理内容较多,系统计算标红和刷新页面较慢,IE可能会弹框提示“是否停止运行此脚本”,若想要继续,点击“否”即可.并同时按照下面的设置更改一下注册表,即可解决弹框问题. http:// ...

  4. Windows服务调试状态下用Console启动

    最近一直在用服务,发现服务也没有那么难调试. Windows服务调试状态下用Console启动:步骤分两步 第一步改Program,启动代码 static class Program { /// &l ...

  5. Eric6中编译窗体时,弹出提示:无法启动pyuic5的解决方案

    用 Eric6 与 PyQt5 结合,非常方便的实现界面与逻辑分离,满足python的极速GUI编程,不需要在界面上花很多时间. 这是一对GUI开发完美的组合! Eric6中设计窗体时,弹出提示:‘无 ...

  6. (转)C# Windows服务 弹出消息提醒框

    出处:http://blog.csdn.net/donghui6116773/article/details/53467069 服务(Service)对于大家来说一定不会陌生,它是Windows 操作 ...

  7. 仿写confirm和alert弹框

    在工作中,我们常常会遇到原生的样式感觉比较丑,又和我们做的项目风格不搭.于是就有了仿写原生一些组件的念头,今天我就带大家仿写一下confirm和alert样式都可以自己修改. 有些的不好的地方请指出来 ...

  8. 如何优雅的写一个Vue 的弹框

    写Vue或者是react 都会遇见弹框的问题.也尝试了多种办法来写弹框,一直都不太满意,今天特地看了一下 Element UI 的源码,模仿着写了一个简易版. 大概有一下几个问题: 1.弹框的层级问题 ...

  9. 写一个Windows服务

    做了两个和Windows服务有关的项目了,最开始的时候没做过,不懂,现在明白了许多.需要注意的是,如果不想登录什么的,最后在添加安装程序的那里选择那个字长的右键属性,把启动方式改为local syst ...

随机推荐

  1. 为什么要设置getter和setter?

    面向对象语言中,通常把属性设置为私有,然后添加getter和setter方法来访问.有人说,这本质上和设置属性为公有没有区别,干脆把属性public算了.也有人反驳,这样做破坏了封装.但是,破坏了封装 ...

  2. 如何试用Office 365 及 SharePoint Online(美版)

    Office 365已经在国外运营一段时间了,本文主要帮助大家注册一个试用账户.废话少说按步骤来: 进入注册页面,链接地址 . 1. 对于不同的企业,提供了不同的套餐,这里我们试用这个中等企业的套餐, ...

  3. 深入浅出OOP(六): 理解C#的Enums

    MSDN定义:枚举类型(也称为枚举)为定义一组可以赋给变量的命名整数常量提供了一种有效的方法.  例如,假设您必须定义一个变量,该变量的值表示一周中的一天. 该变量只能存储七个有意义的值. 若要定义这 ...

  4. .net使用FluentValidation进行服务端验证。

          背景 最近使用asp.mvc 做一个在线口语系统项目,在服务端验证问题遇到了一些小问题. 自己根据数据库表user定义一个数据库表实体对象UserDbEntity [Table(" ...

  5. paip.提升分词---准确度--常用量词表

    paip.提升分词---准确度--常用量词表 作者Attilax  艾龙,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blog.csdn.ne ...

  6. 详解Bootstrap按钮组件(二)

    按钮下拉菜单 按钮下拉菜单仅从外观上看和下拉菜单效果基本上是一样的.它们唯一的不同是外部容器div.dropdown换成了div.btn-group <div class="btn-g ...

  7. 开发ERP软件应该遵守的22条规则

    总结一下做管理软件,有哪些项是经过检验的条款,必须遵守的. 界面篇 1  要保存用户的偏号(profile/favourite). ASP.NET 2.0引入此功能,当用户修改默认的控件的属性时,框架 ...

  8. 编写高质量代码改善C#程序的157个建议——导航开篇

    前言 由于最近工作重心的转移,原来和几个同事一起开发的项目也已经上线了,而新项目就是在现有的项目基础上进行优化延伸扩展.打个比方,现在已经上线的项目行政案件的Web管理网站(代码还没那么多相比较即将要 ...

  9. 报错:LINQ to Entities 不识别方法

    大致是: var products = db.Products.Select(new ProductVm{Name=SomeMethod() }); 针对IQueryable集合的查询操作会被LINQ ...

  10. 【高德地图API】如何设置Icon的imageSize?

    在地图开发中,我们需要把标注换成各种各样的图片,以突显个性.    在高分辨率的手机下,图片尺寸需要压缩至一半,以保持图片清晰.让我们来看一看,应该如何实现. 有开发者为了改变图片的尺寸,直接写成了 ...