2009-01-14 21:40:30 +00:00
using System ;
using System.Collections.Generic ;
using System.ComponentModel ;
using System.Data ;
using System.Diagnostics ;
2009-01-19 00:41:57 +00:00
using System.Runtime.InteropServices ;
2009-01-14 21:40:30 +00:00
using System.ServiceProcess ;
using System.Text ;
using System.IO ;
2009-02-13 19:01:06 +00:00
using System.Net ;
2009-01-14 21:40:30 +00:00
using WMI ;
using System.Xml ;
using System.Threading ;
using Microsoft.Win32 ;
2013-06-21 13:43:45 +00:00
using System.Management ;
2009-01-14 21:40:30 +00:00
namespace winsw
{
2011-10-27 16:43:55 +00:00
public class WrapperService : ServiceBase , EventLogger
2009-01-14 21:40:30 +00:00
{
2009-01-19 00:41:57 +00:00
private SERVICE_STATUS wrapperServiceStatus ;
2009-01-14 21:40:30 +00:00
private Process process = new Process ( ) ;
private ServiceDescriptor descriptor ;
private Dictionary < string , string > envs ;
/// <summary>
/// Indicates to the watch dog thread that we are going to terminate the process,
/// so don't try to kill us when the child exits.
/// </summary>
private bool orderlyShutdown ;
private bool systemShuttingdown ;
public WrapperService ( )
{
this . descriptor = new ServiceDescriptor ( ) ;
this . ServiceName = descriptor . Id ;
this . CanShutdown = true ;
this . CanStop = true ;
this . CanPauseAndContinue = false ;
this . AutoLog = true ;
this . systemShuttingdown = false ;
}
/// <summary>
/// Process the file copy instructions, so that we can replace files that are always in use while
/// the service runs.
/// </summary>
private void HandleFileCopies ( )
{
var file = descriptor . BasePath + ".copies" ;
if ( ! File . Exists ( file ) )
return ; // nothing to handle
try
{
using ( var tr = new StreamReader ( file , Encoding . UTF8 ) )
{
string line ;
while ( ( line = tr . ReadLine ( ) ) ! = null )
{
LogEvent ( "Handling copy: " + line ) ;
string [ ] tokens = line . Split ( '>' ) ;
if ( tokens . Length > 2 )
{
LogEvent ( "Too many delimiters in " + line ) ;
continue ;
}
CopyFile ( tokens [ 0 ] , tokens [ 1 ] ) ;
}
}
}
finally
{
File . Delete ( file ) ;
}
}
2010-12-27 17:03:40 +00:00
/// <summary>
/// File replacement.
/// </summary>
2009-01-14 21:40:30 +00:00
private void CopyFile ( string sourceFileName , string destFileName )
{
try
{
File . Delete ( destFileName ) ;
File . Move ( sourceFileName , destFileName ) ;
}
catch ( IOException e )
{
LogEvent ( "Failed to copy :" + sourceFileName + " to " + destFileName + " because " + e . Message ) ;
}
}
2010-12-27 17:03:40 +00:00
/// <summary>
/// Starts a thread that protects the execution with a try/catch block.
/// It appears that in .NET, unhandled exception in any thread causes the app to terminate
/// http://msdn.microsoft.com/en-us/library/ms228965.aspx
/// </summary>
private void StartThread ( ThreadStart main )
{
new Thread ( delegate ( ) {
try
{
main ( ) ;
}
catch ( Exception e )
{
WriteEvent ( "Thread failed unexpectedly" , e ) ;
}
} ) . Start ( ) ;
}
2009-01-14 21:40:30 +00:00
/// <summary>
/// Handle the creation of the logfiles based on the optional logmode setting.
/// </summary>
private void HandleLogfiles ( )
{
string logDirectory = descriptor . LogDirectory ;
if ( ! Directory . Exists ( logDirectory ) )
{
Directory . CreateDirectory ( logDirectory ) ;
}
2011-10-27 16:43:55 +00:00
LogHandler logAppender = descriptor . LogHandler ;
logAppender . EventLogger = this ;
logAppender . log ( process . StandardOutput . BaseStream , process . StandardError . BaseStream ) ;
2009-01-14 21:40:30 +00:00
}
2011-10-27 16:43:55 +00:00
public void LogEvent ( String message )
2009-01-14 21:40:30 +00:00
{
if ( systemShuttingdown )
{
/* NOP - cannot call EventLog because of shutdown. */
}
else
{
2014-09-06 23:19:11 +00:00
try
{
EventLog . WriteEntry ( message ) ;
}
catch ( Exception e )
{
WriteEvent ( "Failed to log event in Windows Event Log: " + message + "; Reason: " , e ) ;
}
2009-01-14 21:40:30 +00:00
}
}
2011-10-27 16:43:55 +00:00
public void LogEvent ( String message , EventLogEntryType type )
2009-01-14 21:40:30 +00:00
{
if ( systemShuttingdown )
{
/* NOP - cannot call EventLog because of shutdown. */
}
else
{
2014-09-06 23:19:11 +00:00
try
{
EventLog . WriteEntry ( message , type ) ;
}
catch ( Exception e )
{
WriteEvent ( "Failed to log event in Windows Event Log. Reason: " , e ) ;
}
2009-01-14 21:40:30 +00:00
}
}
2010-12-27 17:03:40 +00:00
private void WriteEvent ( Exception exception )
{
WriteEvent ( exception . Message + "\nStacktrace:" + exception . StackTrace ) ;
}
2009-01-19 22:13:18 +00:00
private void WriteEvent ( String message , Exception exception )
{
WriteEvent ( message + "\nMessage:" + exception . Message + "\nStacktrace:" + exception . StackTrace ) ;
}
2009-01-14 21:40:30 +00:00
private void WriteEvent ( String message )
{
2009-01-19 00:41:57 +00:00
string logfilename = Path . Combine ( descriptor . LogDirectory , descriptor . BaseName + ".wrapper.log" ) ;
2009-01-14 21:40:30 +00:00
StreamWriter log = new StreamWriter ( logfilename , true ) ;
2009-01-31 14:04:12 +00:00
log . WriteLine ( DateTime . Now . ToString ( "yyyy-MM-dd HH:mm:ss" ) + " - " + message ) ;
2009-01-14 21:40:30 +00:00
log . Flush ( ) ;
log . Close ( ) ;
}
2010-11-18 06:04:49 +00:00
protected override void OnStart ( string [ ] _ )
2009-01-14 21:40:30 +00:00
{
envs = descriptor . EnvironmentVariables ;
foreach ( string key in envs . Keys )
{
LogEvent ( "envar " + key + '=' + envs [ key ] ) ;
}
2009-02-13 19:01:06 +00:00
2009-01-14 21:40:30 +00:00
HandleFileCopies ( ) ;
2009-02-13 19:01:06 +00:00
// handle downloads
foreach ( Download d in descriptor . Downloads )
{
LogEvent ( "Downloading: " + d . From + " to " + d . To ) ;
try
{
d . Perform ( ) ;
}
catch ( Exception e )
{
2009-02-13 20:16:15 +00:00
LogEvent ( "Failed to download " + d . From + " to " + d . To + "\n" + e . Message ) ;
WriteEvent ( "Failed to download " + d . From + " to " + d . To , e ) ;
2009-02-13 19:01:06 +00:00
// but just keep going
}
}
2009-01-14 21:40:30 +00:00
string startarguments = descriptor . Startarguments ;
if ( startarguments = = null )
{
startarguments = descriptor . Arguments ;
}
else
{
startarguments + = " " + descriptor . Arguments ;
}
LogEvent ( "Starting " + descriptor . Executable + ' ' + startarguments ) ;
2009-01-31 14:04:12 +00:00
WriteEvent ( "Starting " + descriptor . Executable + ' ' + startarguments ) ;
2009-01-14 21:40:30 +00:00
StartProcess ( process , startarguments , descriptor . Executable ) ;
// send stdout and stderr to its respective output file.
HandleLogfiles ( ) ;
process . StandardInput . Close ( ) ; // nothing for you to read!
}
protected override void OnShutdown ( )
{
2009-01-31 14:04:12 +00:00
// WriteEvent("OnShutdown");
2009-01-14 21:40:30 +00:00
try
{
this . systemShuttingdown = true ;
StopIt ( ) ;
}
catch ( Exception ex )
{
2009-01-19 22:13:18 +00:00
WriteEvent ( "Shutdown exception" , ex ) ;
2009-01-14 21:40:30 +00:00
}
}
protected override void OnStop ( )
{
2009-01-31 14:04:12 +00:00
// WriteEvent("OnStop");
2009-01-19 00:41:57 +00:00
try
{
StopIt ( ) ;
}
catch ( Exception ex )
{
2009-01-19 22:13:18 +00:00
WriteEvent ( "Stop exception" , ex ) ;
2009-01-19 00:41:57 +00:00
}
2009-01-14 21:40:30 +00:00
}
2014-01-09 05:34:12 +00:00
/// <summary>
/// Called when we are told by Windows SCM to exit.
/// </summary>
2009-01-14 21:40:30 +00:00
private void StopIt ( )
{
string stoparguments = descriptor . Stoparguments ;
LogEvent ( "Stopping " + descriptor . Id ) ;
2009-01-31 14:04:12 +00:00
WriteEvent ( "Stopping " + descriptor . Id ) ;
2009-01-14 21:40:30 +00:00
orderlyShutdown = true ;
if ( stoparguments = = null )
{
try
{
2009-01-31 14:04:12 +00:00
WriteEvent ( "ProcessKill " + process . Id ) ;
2013-06-21 13:43:45 +00:00
StopProcessAndChildren ( process . Id ) ;
2009-01-14 21:40:30 +00:00
}
catch ( InvalidOperationException )
{
// already terminated
}
}
else
{
2009-02-08 19:50:19 +00:00
SignalShutdownPending ( ) ;
2009-01-14 21:40:30 +00:00
stoparguments + = " " + descriptor . Arguments ;
Process stopProcess = new Process ( ) ;
String executable = descriptor . StopExecutable ;
if ( executable = = null )
{
executable = descriptor . Executable ;
}
StartProcess ( stopProcess , stoparguments , executable ) ;
2009-01-19 00:41:57 +00:00
2009-01-31 14:04:12 +00:00
WriteEvent ( "WaitForProcessToExit " + process . Id + "+" + stopProcess . Id ) ;
2009-01-19 00:41:57 +00:00
WaitForProcessToExit ( process ) ;
WaitForProcessToExit ( stopProcess ) ;
2009-01-31 14:04:12 +00:00
SignalShutdownComplete ( ) ;
2009-02-08 19:50:19 +00:00
}
if ( systemShuttingdown & & descriptor . BeepOnShutdown )
{
2009-01-28 21:28:10 +00:00
Console . Beep ( ) ;
2009-01-14 21:40:30 +00:00
}
2009-01-31 14:04:12 +00:00
WriteEvent ( "Finished " + descriptor . Id ) ;
2009-01-14 21:40:30 +00:00
}
2013-06-21 13:43:45 +00:00
private void StopProcessAndChildren ( int pid )
2014-06-20 10:43:19 +00:00
{
var childPids = GetChildPids ( pid ) ;
if ( descriptor . StopParentProcessFirst )
{
StopProcess ( pid ) ;
foreach ( var childPid in childPids )
{
StopProcessAndChildren ( childPid ) ;
}
}
else
{
foreach ( var childPid in childPids )
{
StopProcessAndChildren ( childPid ) ;
}
StopProcess ( pid ) ;
}
}
private List < int > GetChildPids ( int pid )
2013-06-21 13:43:45 +00:00
{
var searcher = new ManagementObjectSearcher ( "Select * From Win32_Process Where ParentProcessID=" + pid ) ;
2014-06-20 10:43:19 +00:00
var childPids = new List < int > ( ) ;
2013-06-21 13:43:45 +00:00
foreach ( var mo in searcher . Get ( ) )
{
2014-06-20 10:43:19 +00:00
var childProcessId = mo [ "ProcessID" ] ;
WriteEvent ( "Found child process: " + childProcessId + " Name: " + mo [ "Name" ] ) ;
childPids . Add ( Convert . ToInt32 ( childProcessId ) ) ;
2013-06-21 13:43:45 +00:00
}
2014-06-20 10:43:19 +00:00
return childPids ;
}
2013-06-21 13:43:45 +00:00
2014-06-20 10:43:19 +00:00
private void StopProcess ( int pid )
{
WriteEvent ( "Stopping process " + pid ) ;
Process proc ;
try
{
proc = Process . GetProcessById ( pid ) ;
}
catch ( ArgumentException )
{
WriteEvent ( "Process " + pid + " is already stopped" ) ;
return ;
}
2014-05-11 16:39:47 +00:00
WriteEvent ( "Send SIGINT " + pid ) ;
2014-06-20 10:43:19 +00:00
bool successful = SigIntHelper . SendSIGINTToProcess ( proc , descriptor . StopTimeout ) ;
2014-01-09 05:27:53 +00:00
if ( successful )
{
2014-05-11 16:39:47 +00:00
WriteEvent ( "SIGINT to" + pid + " successful" ) ;
2014-01-09 05:27:53 +00:00
}
else
2013-06-21 13:43:45 +00:00
{
2014-01-09 05:27:53 +00:00
try
2014-01-02 19:00:34 +00:00
{
2014-05-11 16:39:47 +00:00
WriteEvent ( "SIGINT to " + pid + " failed - Killing as fallback" ) ;
2014-01-09 05:27:53 +00:00
proc . Kill ( ) ;
2014-01-02 19:00:34 +00:00
}
2014-01-09 05:27:53 +00:00
catch ( ArgumentException )
2014-01-02 19:00:34 +00:00
{
2014-01-09 05:27:53 +00:00
// Process already exited.
2014-01-02 19:00:34 +00:00
}
2013-06-21 13:43:45 +00:00
}
}
2009-01-19 00:41:57 +00:00
private void WaitForProcessToExit ( Process process )
{
SignalShutdownPending ( ) ;
try
{
2009-01-31 14:04:12 +00:00
// WriteEvent("WaitForProcessToExit [start]");
2013-04-21 01:08:35 +00:00
while ( ! process . WaitForExit ( descriptor . SleepTime . Milliseconds ) )
2009-01-19 00:41:57 +00:00
{
SignalShutdownPending ( ) ;
2009-01-31 14:04:12 +00:00
// WriteEvent("WaitForProcessToExit [repeat]");
2009-01-19 00:41:57 +00:00
}
}
2009-01-31 14:04:12 +00:00
catch ( InvalidOperationException )
2009-01-19 00:41:57 +00:00
{
// already terminated
}
2009-01-28 21:28:10 +00:00
2009-01-31 14:04:12 +00:00
// WriteEvent("WaitForProcessToExit [finished]");
2009-01-19 00:41:57 +00:00
}
private void SignalShutdownPending ( )
{
IntPtr handle = this . ServiceHandle ;
wrapperServiceStatus . checkPoint + + ;
2013-04-21 01:08:35 +00:00
wrapperServiceStatus . waitHint = descriptor . WaitHint . Milliseconds ;
2009-01-31 14:04:12 +00:00
// WriteEvent("SignalShutdownPending " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
2009-01-28 21:28:10 +00:00
wrapperServiceStatus . currentState = ( int ) State . SERVICE_STOP_PENDING ;
2014-04-01 21:27:34 +00:00
Advapi32 . SetServiceStatus ( handle , ref wrapperServiceStatus ) ;
2009-01-28 21:28:10 +00:00
}
private void SignalShutdownComplete ( )
{
IntPtr handle = this . ServiceHandle ;
wrapperServiceStatus . checkPoint + + ;
2009-01-31 14:04:12 +00:00
// WriteEvent("SignalShutdownComplete " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
2009-01-28 21:28:10 +00:00
wrapperServiceStatus . currentState = ( int ) State . SERVICE_STOPPED ;
2014-04-01 21:27:34 +00:00
Advapi32 . SetServiceStatus ( handle , ref wrapperServiceStatus ) ;
2009-01-19 00:41:57 +00:00
}
2009-01-14 21:40:30 +00:00
private void StartProcess ( Process process , string arguments , String executable )
{
var ps = process . StartInfo ;
ps . FileName = executable ;
ps . Arguments = arguments ;
2013-03-17 14:07:27 +00:00
ps . WorkingDirectory = descriptor . WorkingDirectory ;
2009-01-14 21:40:30 +00:00
ps . CreateNoWindow = false ;
ps . UseShellExecute = false ;
ps . RedirectStandardInput = true ; // this creates a pipe for stdin to the new process, instead of having it inherit our stdin.
ps . RedirectStandardOutput = true ;
ps . RedirectStandardError = true ;
foreach ( string key in envs . Keys )
System . Environment . SetEnvironmentVariable ( key , envs [ key ] ) ;
// ps.EnvironmentVariables[key] = envs[key]; // bugged (lower cases all variable names due to StringDictionary being used, see http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=326163)
process . Start ( ) ;
2009-01-31 14:04:12 +00:00
WriteEvent ( "Started " + process . Id ) ;
2009-01-14 21:40:30 +00:00
2014-01-09 06:30:17 +00:00
var priority = descriptor . Priority ;
if ( priority ! = ProcessPriorityClass . Normal )
process . PriorityClass = priority ;
2009-01-14 21:40:30 +00:00
// monitor the completion of the process
2010-12-27 17:03:40 +00:00
StartThread ( delegate ( )
2009-01-14 21:40:30 +00:00
{
string msg = process . Id + " - " + process . StartInfo . FileName + " " + process . StartInfo . Arguments ;
process . WaitForExit ( ) ;
try
{
if ( orderlyShutdown )
{
LogEvent ( "Child process [" + msg + "] terminated with " + process . ExitCode , EventLogEntryType . Information ) ;
}
else
{
2014-01-09 05:34:12 +00:00
LogEvent ( "Child process [" + msg + "] finished with " + process . ExitCode , EventLogEntryType . Warning ) ;
// if we finished orderly, report that to SCM.
// by not reporting unclean shutdown, we let Windows SCM to decide if it wants to
// restart the service automatically
if ( process . ExitCode = = 0 )
SignalShutdownComplete ( ) ;
2009-01-14 21:40:30 +00:00
Environment . Exit ( process . ExitCode ) ;
}
}
catch ( InvalidOperationException ioe )
{
LogEvent ( "WaitForExit " + ioe . Message ) ;
}
try
{
process . Dispose ( ) ;
}
catch ( InvalidOperationException ioe )
{
LogEvent ( "Dispose " + ioe . Message ) ;
}
2010-12-27 17:03:40 +00:00
} ) ;
2009-01-14 21:40:30 +00:00
}
2013-04-21 00:38:49 +00:00
public static int Main ( string [ ] args )
2009-01-14 21:40:30 +00:00
{
try
{
Run ( args ) ;
return 0 ;
}
catch ( WmiException e )
{
Console . Error . WriteLine ( e ) ;
return ( int ) e . ErrorCode ;
}
catch ( Exception e )
{
Console . Error . WriteLine ( e ) ;
return - 1 ;
}
}
private static void ThrowNoSuchService ( )
{
throw new WmiException ( ReturnValue . NoSuchService ) ;
}
2010-11-18 06:04:49 +00:00
public static void Run ( string [ ] _args )
2009-01-14 21:40:30 +00:00
{
2010-11-18 06:04:49 +00:00
if ( _args . Length > 0 )
2009-01-14 21:40:30 +00:00
{
var d = new ServiceDescriptor ( ) ;
Win32Services svc = new WmiRoot ( ) . GetCollection < Win32Services > ( ) ;
Win32Service s = svc . Select ( d . Id ) ;
2010-11-18 06:04:49 +00:00
var args = new List < string > ( Array . AsReadOnly ( _args ) ) ;
if ( args [ 0 ] = = "/redirect" )
{
// Redirect output
// One might ask why we support this when the caller
// can redirect the output easily. The answer is for supporting UAC.
// On UAC-enabled Windows such as Vista, SCM operation requires
// elevated privileges, thus winsw.exe needs to be launched
// accordingly. This in turn limits what the caller can do,
// and among other things it makes it difficult for the caller
// to read stdout/stderr. Thus redirection becomes handy.
var f = new FileStream ( args [ 1 ] , FileMode . Create ) ;
var w = new StreamWriter ( f ) ;
w . AutoFlush = true ;
Console . SetOut ( w ) ;
Console . SetError ( w ) ;
var handle = f . Handle ;
2014-04-01 21:27:34 +00:00
Kernel32 . SetStdHandle ( - 11 , handle ) ; // set stdout
Kernel32 . SetStdHandle ( - 12 , handle ) ; // set stder
2010-11-18 06:04:49 +00:00
args = args . GetRange ( 2 , args . Count - 2 ) ;
}
2009-01-14 21:40:30 +00:00
args [ 0 ] = args [ 0 ] . ToLower ( ) ;
if ( args [ 0 ] = = "install" )
{
2013-07-02 17:41:52 +00:00
string username = null , password = null ;
2013-07-17 12:18:04 +00:00
if ( args . Count > 1 & & args [ 1 ] = = "/p" )
{
2013-07-01 16:59:41 +00:00
// we expected username/password on stdin
Console . Write ( "Username: " ) ;
2013-07-02 17:41:52 +00:00
username = Console . ReadLine ( ) ;
2013-07-01 16:59:41 +00:00
Console . Write ( "Password: " ) ;
2013-07-02 17:41:52 +00:00
password = ReadPassword ( ) ;
2013-07-01 16:59:41 +00:00
}
2013-07-17 12:18:04 +00:00
else
{
if ( d . HasServiceAccount ( ) )
{
username = d . ServiceAccountUser ;
password = d . ServiceAccountPassword ;
}
}
2013-07-02 17:41:52 +00:00
svc . Create (
d . Id ,
d . Caption ,
2013-07-17 12:18:04 +00:00
"\"" + d . ExecutablePath + "\"" ,
2013-07-02 17:41:52 +00:00
WMI . ServiceType . OwnProcess ,
ErrorControl . UserNotified ,
StartMode . Automatic ,
d . Interactive ,
username ,
password ,
d . ServiceDependencies ) ;
2009-01-14 21:40:30 +00:00
// update the description
/ * Somehow this doesn ' t work , even though it doesn ' t report an error
Win32Service s = svc . Select ( d . Id ) ;
s . Description = d . Description ;
s . Commit ( ) ;
* /
// so using a classic method to set the description. Ugly.
Registry . LocalMachine . OpenSubKey ( "System" ) . OpenSubKey ( "CurrentControlSet" ) . OpenSubKey ( "Services" )
. OpenSubKey ( d . Id , true ) . SetValue ( "Description" , d . Description ) ;
2013-04-21 01:08:35 +00:00
var actions = d . FailureActions ;
if ( actions . Count > 0 )
{ // set the failure actions
2014-04-01 21:27:34 +00:00
using ( ServiceManager scm = new ServiceManager ( ) )
2013-04-21 01:08:35 +00:00
{
2014-04-01 21:27:34 +00:00
using ( Service sc = scm . Open ( d . Id ) )
2013-04-21 01:08:35 +00:00
{
sc . ChangeConfig ( d . ResetFailureAfter , actions ) ;
}
}
}
2009-01-14 21:40:30 +00:00
}
if ( args [ 0 ] = = "uninstall" )
{
if ( s = = null )
return ; // there's no such service, so consider it already uninstalled
try
{
s . Delete ( ) ;
}
catch ( WmiException e )
{
if ( e . ErrorCode = = ReturnValue . ServiceMarkedForDeletion )
return ; // it's already uninstalled, so consider it a success
throw e ;
}
}
if ( args [ 0 ] = = "start" )
{
if ( s = = null ) ThrowNoSuchService ( ) ;
s . StartService ( ) ;
}
if ( args [ 0 ] = = "stop" )
{
if ( s = = null ) ThrowNoSuchService ( ) ;
s . StopService ( ) ;
}
2014-04-01 20:21:27 +00:00
if ( args [ 0 ] = = "restart" )
2009-01-14 21:40:30 +00:00
{
if ( s = = null )
ThrowNoSuchService ( ) ;
if ( s . Started )
s . StopService ( ) ;
while ( s . Started )
{
Thread . Sleep ( 1000 ) ;
s = svc . Select ( d . Id ) ;
}
s . StartService ( ) ;
}
2014-04-01 20:21:27 +00:00
if ( args [ 0 ] = = "restart!" )
2014-04-01 19:54:29 +00:00
{
2014-04-01 20:21:27 +00:00
// run restart from another process group. see README.md for why this is useful.
2014-04-01 19:54:29 +00:00
2014-04-01 20:21:27 +00:00
STARTUPINFO si = new STARTUPINFO ( ) ;
PROCESS_INFORMATION pi = new PROCESS_INFORMATION ( ) ;
2014-04-01 21:27:34 +00:00
bool result = Kernel32 . CreateProcess ( null , d . ExecutablePath + " restart" , IntPtr . Zero , IntPtr . Zero , false , 0x200 /*CREATE_NEW_PROCESS_GROUP*/ , IntPtr . Zero , null , ref si , out pi ) ;
2014-04-01 20:21:27 +00:00
if ( ! result )
{
throw new Exception ( "Failed to invoke restart: " + Marshal . GetLastWin32Error ( ) ) ;
}
2014-04-01 19:54:29 +00:00
}
2009-01-14 21:40:30 +00:00
if ( args [ 0 ] = = "status" )
{
if ( s = = null )
Console . WriteLine ( "NonExistent" ) ;
else if ( s . Started )
Console . WriteLine ( "Started" ) ;
else
Console . WriteLine ( "Stopped" ) ;
}
if ( args [ 0 ] = = "test" )
{
WrapperService wsvc = new WrapperService ( ) ;
2010-11-18 06:04:49 +00:00
wsvc . OnStart ( args . ToArray ( ) ) ;
2009-01-14 21:40:30 +00:00
Thread . Sleep ( 1000 ) ;
wsvc . OnStop ( ) ;
}
return ;
}
ServiceBase . Run ( new WrapperService ( ) ) ;
}
2013-07-02 17:41:52 +00:00
private static string ReadPassword ( )
{
StringBuilder buf = new StringBuilder ( ) ;
ConsoleKeyInfo key ;
while ( true )
{
key = Console . ReadKey ( true ) ;
if ( key . Key = = ConsoleKey . Enter )
{
return buf . ToString ( ) ;
}
else if ( key . Key = = ConsoleKey . Backspace )
{
buf . Remove ( buf . Length - 1 , 1 ) ;
Console . Write ( "\b \b" ) ;
}
else
{
Console . Write ( '*' ) ;
buf . Append ( key . KeyChar ) ;
}
}
}
2009-01-14 21:40:30 +00:00
}
}