请教C# window服务启动窗体

烟和雾 2012-09-02 01:44:15
老问题了,在网上搜了一些方法,但还是不行。
window服务是装载着WCF服务的,窗体是用来观察和控制停止或再启动WCF服务。
要求在winXP、Win2003、Win2008下能弹出窗体。
问题:
1、如何在服务启动时,把窗体也show出来?另做一个EXE也行。(但Process.Start("notepad.exe"); //记事本也调不出来!)
2、如何实在不能Show窗体的前提,window服务启动时,如何让WCF服务也不中止在启动着?停止服务时,WCF也停止。

我原先的做法部分代码如下。

服务启动时用了线程:

/// <summary>
/// 启动服务
/// </summary>
/// <param name="args"></param>
protected override void OnStart(string[] args)
{
uiThread = new Thread(new ThreadStart(StartService.FormShow));
uiThread.Start();
//this.StartProcessor();
}


线程里的方法:

#region 服务启动窗体

public static void FormShow()
{

GetDesktopWindow();
IntPtr hwinstaSave = GetProcessWindowStation();
IntPtr dwThreadId = GetCurrentThreadId();
IntPtr hdeskSave = GetThreadDesktop(dwThreadId);
IntPtr hwinstaUser = OpenWindowStation("WinSta0", false, 33554432);
if (hwinstaUser == IntPtr.Zero)
{
RpcRevertToSelf();
return;
}
SetProcessWindowStation(hwinstaUser);
IntPtr hdeskUser = OpenDesktop("Default", 0, false, 33554432);
RpcRevertToSelf();
if (hdeskUser == IntPtr.Zero)
{
SetProcessWindowStation(hwinstaSave);
CloseWindowStation(hwinstaUser);
return;
}
SetThreadDesktop(hdeskUser);

IntPtr dwGuiThreadId = dwThreadId;

CtrlForm f = new CtrlForm();
System.Windows.Forms.Application.Run(f);


dwGuiThreadId = IntPtr.Zero;
SetThreadDesktop(hdeskSave);
SetProcessWindowStation(hwinstaSave);
CloseDesktop(hdeskUser);
CloseWindowStation(hwinstaUser);
}

[DllImport("user32.dll")]
static extern int GetDesktopWindow();

[DllImport("user32.dll")]
static extern IntPtr GetProcessWindowStation();

[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentThreadId();

[DllImport("user32.dll")]
static extern IntPtr GetThreadDesktop(IntPtr dwThread);

[DllImport("user32.dll")]
static extern IntPtr OpenWindowStation(string a, bool b, int c);

[DllImport("user32.dll")]
static extern IntPtr OpenDesktop(string lpszDesktop, uint dwFlags,
bool fInherit, uint dwDesiredAccess);

[DllImport("user32.dll")]
static extern IntPtr CloseDesktop(IntPtr p);

[DllImport("rpcrt4.dll", SetLastError = true)]
static extern IntPtr RpcImpersonateClient(int i);


[DllImport("rpcrt4.dll", SetLastError = true)]
static extern IntPtr RpcRevertToSelf();

[DllImport("user32.dll")]
static extern IntPtr SetThreadDesktop(IntPtr a);

[DllImport("user32.dll")]
static extern IntPtr SetProcessWindowStation(IntPtr a);
[DllImport("user32.dll")]
static extern IntPtr CloseWindowStation(IntPtr a);

#endregion


窗体Load时启动WCF服务:

#region 启动WCF服务

private void LoadService()
{
if (dicHost == null || dicHost.Count == 0)
{
dicHost = new Dictionary<string, ServiceHost>();

Configuration conf = ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location);
ServiceModelSectionGroup svcmod = (ServiceModelSectionGroup)conf.GetSectionGroup("system.serviceModel");

foreach (ServiceElement el in svcmod.Services.Services)
{
Type svcType = Type.GetType(el.Name + "," + "Services");
//Type svcType = Type.GetType(el.Name + "," + el.Name.Split('.')[0]);

ListViewItem lvItem = new ListViewItem(el.Name);
if (svcType == null)
{
lvItem.SubItems.Add("已停止");
lvItem.SubItems.Add("服务类型无效" + el.Name + "配置文件中。");
}
else
{
ServiceHost aServiceHost = new ServiceHost(svcType);
aServiceHost.Open();
dicHost.Add(el.Name, aServiceHost); //启动的服务保存在字典
lvItem.SubItems.Add("已启动");
lvItem.SubItems.Add("");
}
this.lvList.Items.Add(lvItem);
}
}
else
{
HG.WinAPI.Win32.ShowWindow(this.Handle, HG.WinAPI.Win32.SW_SHOWNORMAL);
SetMid(this);
HG.WinAPI.Win32.SetForegroundWindow(this.Handle);
//HG.WinAPI.Win32.SendMessage(this.Handle, HG.WinAPI.Win32.WM_NCACTIVATE, HG.WinAPI.Win32.WA_ACTIVE, 0);
}
}

#endregion
...全文
1154 19 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
烟和雾 2012-09-11
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 的回复:]

可以做到的,我们项目的存储服务就是可以调窗体来检测数据库数据,VS2010项目属性中有个命令行参数设置,可以实现的。
[/Quote]
请教一下是怎么做的?能说具体一些吗?
starwar7 2012-09-10
  • 打赏
  • 举报
回复
可以做到的,我们项目的存储服务就是可以调窗体来检测数据库数据,VS2010项目属性中有个命令行参数设置,可以实现的。
烟和雾 2012-09-08
  • 打赏
  • 举报
回复
过了这周末没人回答就结帖了
qldsrx 2012-09-07
  • 打赏
  • 举报
回复
什么叫不可取?你先看看其它著名的软件是如何实现的吧。比如诺顿杀毒软件,常驻服务别说了,开机自启动,但是管理界面是另一个exe程序,在开机启动项里面注册的,如果那个启动项删除,杀毒服务还是工作的,但是右下角少了一个监视用的管理窗口,也可以后期单独打开那个窗口。
如果按照你原先的做法,设置服务于桌面交互,并在服务里面开启窗口,虽然是可以做到的,但是这样就意味着服务将随着窗口的关闭一起关闭了,参考pcAnywhere就是这样,右下角图片关了,服务就消失了,那样才叫不可取。
qldsrx 2012-09-06
  • 打赏
  • 举报
回复
是你的理解有问题,窗口之所以不能在服务里面开启,因为服务不是由当前用户启动的,未登录系统的时候,服务就先开启了,自然无法带用户界面了。(但是可以勾选服务的一个选项,启用用户交互,但不推荐)
正确的做法是,窗口通过开启启动项注册,服务和窗口分别两个EXE程序。如果只是简单的监视服务状态,只要用DOS命令查看即可,如果需要精确控制服务,你必须在WCF服务内提供管理用的方法,对服务进行消息控制。
烟和雾 2012-09-06
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 的回复:]
是你的理解有问题,窗口之所以不能在服务里面开启,因为服务不是由当前用户启动的,未登录系统的时候,服务就先开启了,自然无法带用户界面了。(但是可以勾选服务的一个选项,启用用户交互,但不推荐)
[/Quote]
这个问题我知道,服务程序一般使用的是LocalSystem帐户,拥有自己的window station,和Default桌面,这个window station是不能于用户交互的,也就是说,你不能在上面显示窗口,它也不接受用户的鼠标、键盘等输入。
C# window服务启动窗体相关文章,一个是博客园的,一个是CSDN的,
http://www.cnblogs.com/vic_lu/archive/2011/02/18/1957842.html
http://topic.csdn.net/u/20080513/10/9967ed75-c572-4825-9dbd-7bc487e13dc5.html
这两个比较有帮助的资料。我上面的代码就是根据这些资料改动的。

[Quote=引用 13 楼 的回复:]
正确的做法是,窗口通过开启启动项注册,服务和窗口分别两个EXE程序。如果只是简单的监视服务状态,只要用DOS命令查看即可,如果需要精确控制服务,你必须在WCF服务内提供管理用的方法,对服务进行消息控制。
[/Quote]
这方法不可取,公司要求是用WINDOWS服务启动WCF,退一步就是那窗体界面不要了。
烟和雾 2012-09-06
  • 打赏
  • 举报
回复
顶起来呀,不是我想要的答案
SocketUpEx 2012-09-03
  • 打赏
  • 举报
回复
        public void FormShow()
{
Form1 StartService = new Form1();
StartService.ShowDialog(); //不要用Show
}

protected override void OnStart(string[] args)
{
Thread uiThread = new Thread(new ThreadStart(() => FormShow()));
//Thread uiThread = new Thread(new ThreadStart(FormShow));
uiThread.Start();
}



qlzf11140820 2012-09-03
  • 打赏
  • 举报
回复
/// <summary>
/// Windows服务类
/// </summary>
/// <summary>
/// 检查服务存在的存在性
/// </summary>
/// <param name=" NameService ">服务名</param>
/// <returns>存在返回 true,否则返回 false;</returns>
public static bool isServiceIsExisted(string NameService)
{
ServiceController[] services = ServiceController.GetServices();
foreach (ServiceController s in services)
{
if (s.ServiceName.ToLower() == NameService.ToLower())
{
return true;
}
}
return false;
}

/// <summary>
/// 安装Windows服务
/// </summary>
/// <param name="stateSaver">集合</param>
/// <param name="filepath">程序文件路径</param>
public static void InstallmyService(IDictionary stateSaver, string filepath)
{
AssemblyInstaller AssemblyInstaller1 = new AssemblyInstaller();
AssemblyInstaller1.UseNewContext = true;
AssemblyInstaller1.Path = filepath;
AssemblyInstaller1.Install(stateSaver);
AssemblyInstaller1.Commit(stateSaver);
AssemblyInstaller1.Dispose();
}

/// <summary>
/// 卸载Windows服务
/// </summary>
/// <param name="filepath">程序文件路径</param>
public static void UnInstallmyService(string filepath)
{
AssemblyInstaller AssemblyInstaller1 = new AssemblyInstaller();
AssemblyInstaller1.UseNewContext = true;
AssemblyInstaller1.Path = filepath;
AssemblyInstaller1.Uninstall(null);
AssemblyInstaller1.Dispose();
}

/// <summary>
/// 检查Windows服务是否在运行
/// </summary>
/// <param name="name">程序的服务名</param>
public static bool IsRunning(string name)
{
bool IsRun = false;
try
{
if (!isServiceIsExisted(name))
{
return false;
}
ServiceController sc = new ServiceController(name);
if (sc.Status == ServiceControllerStatus.StartPending ||
sc.Status == ServiceControllerStatus.Running)
{
IsRun = true;
}
sc.Close();
}
catch
{
IsRun = false;
}
return IsRun;
}

/// <summary>
/// 启动Windows服务
/// </summary>
/// <param name="name">程序的服务名</param>
/// <returns>启动成功返回 true,否则返回 false;</returns>
public static bool StarmyService(string name)
{
ServiceController sc = new ServiceController(name);
if (sc.Status == ServiceControllerStatus.Stopped || sc.Status == ServiceControllerStatus.StopPending
)
{
sc.Start();
sc.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 10));
}
else
{
}
sc.Close();
return true;
}

/// <summary>
/// 停止Windows服务
/// </summary>
/// <param name="name">程序的服务名</param>
/// <returns>停止成功返回 true,否则返回 false;</returns>
public static bool StopmyService(string name)
{
ServiceController sc = new ServiceController(name);
if (sc.Status == ServiceControllerStatus.Running ||
sc.Status == ServiceControllerStatus.StartPending)
{
sc.Stop();
sc.WaitForStatus(ServiceControllerStatus.Stopped, new TimeSpan(0, 0, 10));
}
else
{
}
sc.Close();
return true;
}

/// <summary>
/// 重启Windows服务
/// </summary>
/// <param name="name">程序的服务名</param>
/// <returns>重启成功返回 true,否则返回 false;</returns>
public static bool RefreshmyService(string name)
{
return StopmyService(name) && StarmyService(name);
}
烟和雾 2012-09-03
  • 打赏
  • 举报
回复
高手都去哪了?都在忙啥呀,帮忙解决问题吧
烟和雾 2012-09-03
  • 打赏
  • 举报
回复
上班了,先顶起帖子!!!
jiang580617 2012-09-03
  • 打赏
  • 举报
回复
额,你的意思就是说,在windows服务里面启动,在界面上显示出来嘛,写个启动小软件,把你需要的启动的软件的路径放进去,再直接监视服务里面如果没有启动,就启动起来啥
wangderong83899 2012-09-03
  • 打赏
  • 举报
回复
顶,等高手出现~
烟和雾 2012-09-02
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]

uiThread = new Thread(new ThreadStart(StartService.FormShow));
uiThread.Start();

线程内直接调用UI
报错了吧
[/Quote]

uiThread线程里调用UI
SocketUpEx 2012-09-02
  • 打赏
  • 举报
回复
uiThread = new Thread(new ThreadStart(StartService.FormShow));
uiThread.Start();

线程内直接调用UI
报错了吧


烟和雾 2012-09-02
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]

1、如何在服务启动时,把窗体也show出来?另做一个EXE也行。(但Process.Start("notepad.exe"); //记事本也调不出来!)

但代码太长没看,只针对你这个问题:
要在服务里show出窗体有两个必要的条件:
1. 允许服务与桌面交互,打勾
2. serviceProcessInstaller1的Account属性要选择LocalSystem
[/Quote]
你说的都做了的,就是不见窗体出来
SocketUpEx 2012-09-02
  • 打赏
  • 举报
回复
1、如何在服务启动时,把窗体也show出来?另做一个EXE也行。(但Process.Start("notepad.exe"); //记事本也调不出来!)

但代码太长没看,只针对你这个问题:
要在服务里show出窗体有两个必要的条件:
1. 允许服务与桌面交互,打勾
2. serviceProcessInstaller1的Account属性要选择LocalSystem


烟和雾 2012-09-02
  • 打赏
  • 举报
回复
昨晚发的,先顶起来,请会的朋友们帮忙解决

111,101

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧