我在visual studio 2010中创建了一个桌面控制台应用程序。如何将其转换为Windows服务?基本上在调试模式我想要它作为普通的应用程序,但在发布模式,我想要一个服务构建输出
答案 0 :(得分:1)
你可以这样做:
namespace Program
{
static class Program
{
public static bool Stopped = false;
[STAThread]
static void Main(string[] args)
{
Interactive.Initialize();
Interactive.OnStopped += new Interactive.StopedDelegate(OnStopped);
Interactive.Title = Path.GetFileNameWithoutExtension(
Assembly.GetExecutingAssembly().Location);
if (args.Length == 0) Interactive.Run(RunProc);
else if (args[0] == "-svc") ServiceBase.Run(new Service());
}
public static void RunProc() { yourConsoleMain(); }
public static void OnStopped() { Stopped = true; exitFromMain(); }
}
public class Service : ServiceBase
{
public static string Name = Path.GetFileNameWithoutExtension(
Assembly.GetExecutingAssembly().Location);
public static string CmdLineSwitch = "-svc";
public static ServiceStartMode StartMode = ServiceStartMode.Automatic;
public static bool DesktopInteract = true;
public bool Stopped = false;
public Service() { ServiceName = Name; }
public void Start() { OnStart(null); }
protected override void OnStart(string[] args)
{
System.Diagnostics.EventLog.WriteEntry(
ServiceName, ServiceName + " service started.");
Thread thread = new Thread(MainThread);
thread.Start();
}
protected override void OnStop()
{
System.Diagnostics.EventLog.WriteEntry(
ServiceName, ServiceName + " service stopped.");
Stopped = true;
Application.Exit();
}
private void MainThread()
{
Interactive.Run(Program.RunProc);
if (!Stopped) Stop();
}
}
}
让我解释一下......基本上,在Main
中,如果以程序'-svc'
启动,则定义您的程序作为服务启动。
将RunProc()
通常在main()
和OnStopped()
事件处理程序中执行的操作放入main()
将导致ServiceBase
退出的代码。
然后,覆盖using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
namespace ProgramIO.Control
{
public delegate void WriteDelegate(string value, int x, int y);
public delegate void ReadDelegate(out string value, bool readLine);
public delegate void EnableInputDelegate(bool enable);
public partial class InteractiveForm : Form
{
private delegate void ClearInputBufferDelegate();
public enum EIOOperation { None = 0, Write, Read }
private EventWaitHandle eventInvoke =
new EventWaitHandle(false, EventResetMode.AutoReset);
private EventWaitHandle eventInput =
new EventWaitHandle(false, EventResetMode.AutoReset);
private bool readLine = false;
private string inputBuffer = "";
private int inputPosition = 0;
private int inputBufferPosition = 0;
private EIOOperation IOOperation;
private int bufferSize = 0x10000;
private bool CaretShown = false;
private delegate object DoInvokeDelegate(Delegate method, params object[] args);
private delegate void SetTitleDelegate(string value);
private delegate void SetForegroundcolorDelegate(Color value);
public string Title {
get { return Text; }
set {
if (InvokeRequired) InvokeEx(
(SetTitleDelegate)delegate(string title) { Text = title; },
1000, new object[] { value });
else Text = value; }}
public Color ForegroundColor {
get { return ForeColor; }
set {
if (InvokeRequired) InvokeEx(
(SetForegroundcolorDelegate)delegate(Color color) { ForeColor = color; },
1000, new object[] { value });
else ForeColor = value; }}
public InteractiveForm()
{
InitializeComponent();
DoubleBuffered = true;
}
#region Asynchronous Methods
private bool InvokeEx(Delegate method, int timeout, params object[] args)
{
BeginInvoke((DoInvokeDelegate)DoInvoke, new object[] { method, args });
if (eventInvoke.WaitOne(timeout)) return true;
else return false;
}
private void EnableInput(bool enable)
{
if (InvokeRequired)
InvokeEx((EnableInputDelegate)DoEnableInput, 1000, new object[] { enable });
else DoEnableInput(enable);
}
private void ClearInputBuffer()
{
if (InvokeRequired)
InvokeEx((ClearInputBufferDelegate)DoClearInputBuffer, 1000, new object[0]);
else DoClearInputBuffer();
}
public void Write(string value, int x = -1, int y = -1)
{
lock (this) {
IOOperation = EIOOperation.Write;
if (InvokeRequired)
InvokeEx((WriteDelegate)DoWrite, 1000, new object[] { value, x, y });
else DoWrite(value, x, y);
IOOperation = EIOOperation.None; }
}
public string Read(bool readLine)
{
lock (this) {
EnableInput(true);
IOOperation = EIOOperation.Read; this.readLine = readLine; string value = "";
ClearInputBuffer(); eventInput.WaitOne();
object[] args = new object[] { value, readLine };
if (InvokeRequired) {
InvokeEx((ReadDelegate)DoRead, 1000, args); value = (string) args[0]; }
else DoRead(out value, readLine);
//inputPosition = textBox.Text.Length; inputBuffer = "";
ClearInputBuffer();
IOOperation = EIOOperation.None;
EnableInput(false);
return value;
}
}
#endregion //Asynchronous Methods
#region Synchronous Methods
protected override void OnShown(EventArgs e) { base.OnShown(e); textBox.Focus(); }
public object DoInvoke(Delegate method, params object[] args)
{
object obj = method.DynamicInvoke(args);
eventInvoke.Set();
return obj;
}
private void CorrectSelection()
{
if (textBox.SelectionStart < inputPosition) {
if (textBox.SelectionLength > (inputPosition - textBox.SelectionStart))
textBox.SelectionLength -= inputPosition - textBox.SelectionStart;
else textBox.SelectionLength = 0;
textBox.SelectionStart = inputPosition; }
}
protected void DoClearInputBuffer()
{
inputPosition = textBox.Text.Length; inputBuffer = "";
}
protected void DoEnableInput(bool enable)
{
if (enable) { textBox.ReadOnly = false; textBox.SetCaret(true); }
else { textBox.ReadOnly = true; textBox.SetCaret(false); }
}
protected void DoWrite(string value, int x, int y)
{
string[] lines = textBox.Text.Split(new string[] { "\r\n" }, StringSplitOptions.None);
string[] addLines = new string[0];
if (y == -1) y = lines.Length - 1;
if (lines.Length - 1 < y) addLines = new string[y - lines.Length - 1];
if (y < lines.Length) {
if (x == -1) x = lines[y].Length;
if (lines[y].Length < x)
lines[y] += new String(' ', x - lines[y].Length) + value;
else
lines[y] = lines[y].Substring(0, x) + value +
((x + value.Length) < lines[y].Length ?
lines[y].Substring(x + value.Length) : ""); }
else {
y -= lines.Length;
if (x == -1) x = addLines[y].Length;
addLines[y] += new String(' ', x - addLines[y].Length) + value; }
textBox.Text = (string.Join("\r\n", lines) +
(addLines.Length > 0 ? "\r\n" : "") + string.Join("\r\n", addLines));
textBox.Select(textBox.Text.Length, 0); textBox.ScrollToCaret();
inputBuffer = "";
}
protected void DoRead(out string value, bool readLine)
{
value = "";
if (readLine) {
int count = inputBuffer.IndexOf("\r\n");
if (count > 0) { value = inputBuffer.Substring(0, count); }}
else if (inputBuffer.Length > 0) {
value = inputBuffer.Substring(0, 1); }
inputBuffer = "";
}
private void textBox_TextChanged(object sender, EventArgs e)
{
if (IOOperation == EIOOperation.Read) {
inputBuffer = textBox.Text.Substring(inputPosition);
if (!readLine || inputBuffer.Contains("\r\n")) eventInput.Set(); }
if (textBox.Text.Length > bufferSize) { textBox.Text =
textBox.Text.Substring(textBox.Text.Length - bufferSize, bufferSize);
textBox.Select(textBox.Text.Length, 0); textBox.ScrollToCaret(); }
}
private void textBox_KeyDown(object sender, KeyEventArgs e)
{
if (IOOperation != EIOOperation.Read ||
(e.KeyCode == Keys.Back && inputBuffer.Length == 0))
e.SuppressKeyPress = true;
}
private void textBox_MouseUp(object sender, MouseEventArgs e)
{
CorrectSelection();
}
private void textBox_KeyUp(object sender, KeyEventArgs e)
{
if (!(IOOperation == EIOOperation.Read) ||
((e.KeyCode == Keys.Left || e.KeyCode == Keys.Up) &&
textBox.SelectionStart < inputPosition))
CorrectSelection();
}
private void InteractiveForm_FormClosing(object sender, FormClosingEventArgs e)
{
eventInput.Set();
lock (this) { }
}
#endregion //Synchronous Methods
}
public class InteractiveWindow : TextBox
{
[DllImport("user32.dll")]
static extern bool HideCaret(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool ShowCaret(IntPtr hWnd);
private delegate void SetCaretDelegate(bool visible);
private const int WM_SETFOCUS = 0x0007;
private bool CaretVisible = true;
public void SetCaret(bool visible)
{
if (InvokeRequired) Invoke((SetCaretDelegate)DoSetCaret, new object[] { visible });
else DoSetCaret(visible);
}
private void DoSetCaret(bool visible)
{
if (CaretVisible != visible)
{
CaretVisible = visible;
if (CaretVisible) ShowCaret(Handle);
else HideCaret(Handle);
}
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_SETFOCUS)
{
if (CaretVisible) { ShowCaret(Handle); }
else HideCaret(Handle);
}
}
}
}
namespace ProgramIO
{
using ProgramIO.Control;
public static class Interactive
{
public delegate void StopedDelegate();
public delegate void RunDelegate();
public static bool Initialized = false;
private static InteractiveForm frmIO = null;
private static Thread IOThread = null;
private static EventWaitHandle EventStarted =
new EventWaitHandle(false, EventResetMode.AutoReset);
public static string Title {
get { return frmIO.Title; }
set { frmIO.Title = value; } }
public static Color ForegroundColor {
get {return frmIO.ForeColor; }
set { frmIO.ForeColor = value; } }
public static event StopedDelegate OnStopped = null;
private static void form_Show(object sender, EventArgs e)
{
frmIO = sender as InteractiveForm;
EventStarted.Set();
}
private static void form_FormClosed(object sender, FormClosedEventArgs e)
{
lock (frmIO) {
frmIO = null;
Application.Exit(); }
}
public static void Initialize()
{
IOThread = new Thread(IOThreadProc);
IOThread.Name = "Interactive Thread"; IOThread.Start();
EventStarted.WaitOne();
Initialized = true;
}
public static void Run(RunDelegate runProc = null)
{
if (!Initialized) Initialize();
if (runProc != null) runProc();
Application.Run();
if (OnStopped != null) OnStopped();
}
public static void IOThreadProc()
{
InteractiveForm form = new InteractiveForm();
form.Shown += new EventHandler(form_Show);
form.FormClosed += new FormClosedEventHandler(form_FormClosed);
Application.Run(form);
}
public static void Write(string value, int x = -1, int y = -1)
{
if (frmIO != null) lock (frmIO) { frmIO.Write(value, x, y); }
}
public static void WriteLine(string value)
{
if (frmIO != null) lock (frmIO) {
Interactive.Write(value); Interactive.Write("\r\n"); }
}
public static int Read()
{
if (frmIO != null) lock (frmIO) {
string input = frmIO.Read(false);
if (input.Length > 0) return input[0]; }
return 0;
}
public static string ReadLine()
{
if (frmIO != null) lock (frmIO) { return frmIO.Read(true); }
else return "";
}
}
}
并执行一些基本的启动/停止服务。
在Windows 7及更高版本中,如果要查看某些输出,则必须明确定义您的服务可以与桌面交互。但是还有另一个问题,控制台窗口无法显示。所以我创建了这个控制台模拟器,它可以写入并读取输入。
Interactive
最后一个类Main()
实际上充当异步方法的调用者,并且在开始时在InteractiveForm
中使用它。
如果您不希望在程序作为Windows服务运行时看到控制台窗口,则可以跳过整个第二部分代码。
我还为此创建了一个Installer类,但这个页面上只有很多代码。
编辑:这个Form
实际上是一个包含设计师类的表单,但非常简单,只包含填充其区域的EditBox
和{{1}}。
答案 1 :(得分:0)
基本上,您的解决方案中需要3个项目:
因此,您的应用必须使用某种Start()
方法,例如无限循环完成所有工作,可能Stop()
方法停止处理。
Winservice项目必须包含派生自ServiceBase
的类,它有OnStart
方法调用应用程序的Start
和OnStop
调用应用程序的Stop
方法
接下来,在控制台应用程序中,你做的几乎一样 - 在控制台的入口点调用Start
方法。
到目前为止,您可以运行控制台应用程序进行调试,然后发布您的winservice项目
Winservice类可能如下所示:
<强> UPD 强>
Winservice codez:
public class MyWinService : ServiceBase
{
IMyApplicationService _myApplicationService;
//constructor - resolve dependencies here
public MyWinService()
{
_myApplicationService = new MyApplicationService();
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
try
{
_myApplicationService.Start();
}
catch (Exception exception)
{
//log exception
}
}
protected override void OnStop()
{
base.OnStop();
try
{
_myApplicationService.Stop();
}
catch (Exception exception)
{
//log exception
}
}
}
申请服务:
public class MyApplicationService : IMyApplicationService
{
public MyApplicationService()
{
//some initializations
}
public Start()
{
//do work here
}
public Stop()
{
//...
}
}