简体   繁体   English

Visual Studio 2010-发布模式下的应用程序即服务

[英]Visual studio 2010- Application as a service in release mode

I have an desktop console application created in visual studio 2010.How do i convert it to windows service?. 我在Visual Studio 2010中创建了一个桌面控制台应用程序。如何将其转换为Windows服务? basically in debug mode i want it as normal app , but in release mode i want a service build output 基本上在调试模式下,我希望它像普通应用程序一样,但是在发布模式下,我希望服务构建输出

You can do it this way: 您可以这样操作:

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();
        }
    }
}

Let me explain this... Basically, in Main you define that your program starts as a service if it is started with argument '-svc' . 让我解释一下...基本上,在Main ,如果程序以参数'-svc'启动,则将其定义为服务启动。

Put in RunProc() what you normally do in main() , and in OnStopped() event handler some code that will cause main() to exit. 将通常在main()执行的操作放入RunProc()中,并在OnStopped()事件处理程序中OnStopped()一些导致main()退出的代码。

Then, override ServiceBase and perform some basic start/stop service. 然后,重写ServiceBase并执行一些基本的启动/停止服务。

In Windows 7 and later you must explicitly define that your service can interact with desktop if you want to see some output. 在Windows 7及更高版本中,如果要查看某些输出,则必须明确定义服务可以与桌面交互。 But there is another problem, console window cannot be shown. 但是还有另一个问题,控制台窗口无法显示。 So I created this console simulator which can write and also read input. 因此,我创建了这个控制台模拟器,它可以编写和读取输入。

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 "";
        }
    }
}

This last class, Interactive , actually serve as invoker for asynchronous methods, and it is used in Main() at the beginning. 最后一个类Interactive是实际上充当异步方法的调用者,并且在一开始就在Main()中使用。 You can skip this whole second section of code if you don't want to see console window when program is run as a windows service. 如果您不想在将程序作为Windows服务运行时看到控制台窗口,则可以跳过整个第二部分代码。 I have also created an Installer class for this, but it would be just to much code on this page. 我还为此创建了一个Installer类,但这只是该页面上的许多代码。

EDIT: This InteractiveForm is actually a form with designer class, but very simple, consisting only of Form and EditBox inside filling its area. 编辑:此InteractiveForm实际上是具有设计器类的表单,但非常简单,仅由FormEditBox组成,并填充其区域。

Basicallly you need 3 projects in your solution: 基本上,您的解决方案中需要3个项目:

  1. Application itself 应用程序本身
  2. WinService for production WinService生产
  3. Console Application for test purposes 用于测试目的的控制台应用程序

So your application must have some kind of Start() method with eg infinite loop that does all work and maybe Stop() method to stop processing. 因此,您的应用程序必须具有某种Start()方法(例如可以完成所有工作的无限循环Stop()以及Stop()方法来停止处理。

Winservice project must contain class derived from ServiceBase , it'l have OnStart method that calls your application's Start and OnStop that calls application's Stop method. Winservice项目必须包含从ServiceBase派生的类,它具有调用应用程序的Start OnStart方法和调用应用程序的Stop方法的OnStop

Next, in console application you do pretty much same - calling Start method in console's entry point. 接下来,在控制台应用程序中,您执行的操作几乎相同-在控制台的入口点调用Start方法。

So far for debug you run your console app, and for release you publish your winservice project 到目前为止,对于调试,您可以运行控制台应用程序,对于发布,您可以发布Winservice项目

Winservice class might look like: Winservice类可能类似于:

upd UPD

Winservice codez: Winservice编码:

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             
        }
    }
}

Application service: 申请服务:

public class MyApplicationService : IMyApplicationService
{
    public MyApplicationService()
    {
        //some initializations
    }

    public Start()
    {
        //do work here
    }

    public Stop()
    {
        //...
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM