Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

initial import

git-svn-id: https://svn.kenai.com/svn/winsw~subversion/trunk@2 c8b2a3fe-9b5b-6a51-a37e-dc31b0e308fa
  • Loading branch information...
commit e94628badf55ef4dae431abb0b8c5692e495ebe7 1 parent 08eed56
kohsuke authored
View
348 DynamicProxy.cs
@@ -0,0 +1,348 @@
+using System;
+using System.Reflection;
+using System.Collections;
+using System.Reflection.Emit;
+using System.Threading;
+
+namespace DynamicProxy
+{
+ /// <summary>
+ /// Interface that a user defined proxy handler needs to implement. This interface
+ /// defines one method that gets invoked by the generated proxy.
+ /// </summary>
+ public interface IProxyInvocationHandler
+ {
+ /// <param name="proxy">The instance of the proxy</param>
+ /// <param name="method">The method info that can be used to invoke the actual method on the object implementation</param>
+ /// <param name="parameters">Parameters to pass to the method</param>
+ /// <returns>Object</returns>
+ object Invoke(object proxy, MethodInfo method, object[] parameters);
+ }
+
+ /// <summary>
+ /// Factory class used to cache Types instances
+ /// </summary>
+ public class MetaDataFactory
+ {
+ private static Hashtable typeMap = new Hashtable();
+
+ /// <summary>
+ /// Class constructor. Private because this is a static class.
+ /// </summary>
+ private MetaDataFactory()
+ {
+ }
+
+ ///<summary>
+ /// Method to add a new Type to the cache, using the type's fully qualified
+ /// name as the key
+ ///</summary>
+ ///<param name="interfaceType">Type to cache</param>
+ public static void Add(Type interfaceType)
+ {
+ if (interfaceType != null)
+ {
+ lock (typeMap.SyncRoot)
+ {
+ if (!typeMap.ContainsKey(interfaceType.FullName))
+ {
+ typeMap.Add(interfaceType.FullName, interfaceType);
+ }
+ }
+ }
+ }
+
+ ///<summary>
+ /// Method to return the method of a given type at a specified index.
+ ///</summary>
+ ///<param name="name">Fully qualified name of the method to return</param>
+ ///<param name="i">Index to use to return MethodInfo</param>
+ ///<returns>MethodInfo</returns>
+ public static MethodInfo GetMethod(string name, int i)
+ {
+ Type type = null;
+ lock (typeMap.SyncRoot)
+ {
+ type = (Type)typeMap[name];
+ }
+
+ return type.GetMethods()[i];
+ }
+
+ public static PropertyInfo GetProperty(string name, int i)
+ {
+ Type type = null;
+ lock (typeMap.SyncRoot)
+ {
+ type = (Type)typeMap[name];
+ }
+
+ return type.GetProperties()[i];
+ }
+ }
+
+ /// <summary>
+ /// </summary>
+ public class ProxyFactory
+ {
+ private static ProxyFactory instance;
+ private static Object lockObj = new Object();
+
+ private Hashtable typeMap = Hashtable.Synchronized(new Hashtable());
+ private static readonly Hashtable opCodeTypeMapper = new Hashtable();
+
+ private const string PROXY_SUFFIX = "Proxy";
+ private const string ASSEMBLY_NAME = "ProxyAssembly";
+ private const string MODULE_NAME = "ProxyModule";
+ private const string HANDLER_NAME = "handler";
+
+ // Initialize the value type mapper. This is needed for methods with intrinsic
+ // return types, used in the Emit process.
+ static ProxyFactory()
+ {
+ opCodeTypeMapper.Add(typeof(System.Boolean), OpCodes.Ldind_I1);
+ opCodeTypeMapper.Add(typeof(System.Int16), OpCodes.Ldind_I2);
+ opCodeTypeMapper.Add(typeof(System.Int32), OpCodes.Ldind_I4);
+ opCodeTypeMapper.Add(typeof(System.Int64), OpCodes.Ldind_I8);
+ opCodeTypeMapper.Add(typeof(System.Double), OpCodes.Ldind_R8);
+ opCodeTypeMapper.Add(typeof(System.Single), OpCodes.Ldind_R4);
+ opCodeTypeMapper.Add(typeof(System.UInt16), OpCodes.Ldind_U2);
+ opCodeTypeMapper.Add(typeof(System.UInt32), OpCodes.Ldind_U4);
+ }
+
+ private ProxyFactory()
+ {
+ }
+
+ public static ProxyFactory GetInstance()
+ {
+ if (instance == null)
+ {
+ CreateInstance();
+ }
+
+ return instance;
+ }
+
+ private static void CreateInstance()
+ {
+ lock (lockObj)
+ {
+ if (instance == null)
+ {
+ instance = new ProxyFactory();
+ }
+ }
+ }
+
+ public Object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface)
+ {
+ string typeName = objType.FullName + PROXY_SUFFIX;
+ Type type = (Type)typeMap[typeName];
+
+ // check to see if the type was in the cache. If the type was not cached, then
+ // create a new instance of the dynamic type and add it to the cache.
+ if (type == null)
+ {
+ if (isObjInterface)
+ {
+ type = CreateType(handler, new Type[] { objType }, typeName);
+ }
+ else
+ {
+ type = CreateType(handler, objType.GetInterfaces(), typeName);
+ }
+
+ typeMap.Add(typeName, type);
+ }
+
+ // return a new instance of the type.
+ return Activator.CreateInstance(type, new object[] { handler });
+ }
+
+ public Object Create(IProxyInvocationHandler handler, Type objType)
+ {
+ return Create(handler, objType, false);
+ }
+
+ private Type CreateType(IProxyInvocationHandler handler, Type[] interfaces, string dynamicTypeName)
+ {
+ Type retVal = null;
+
+ if (handler != null && interfaces != null)
+ {
+ Type objType = typeof(System.Object);
+ Type handlerType = typeof(IProxyInvocationHandler);
+
+ AppDomain domain = Thread.GetDomain();
+ AssemblyName assemblyName = new AssemblyName();
+ assemblyName.Name = ASSEMBLY_NAME;
+ assemblyName.Version = new Version(1, 0, 0, 0);
+
+ // create a new assembly for this proxy, one that isn't presisted on the file system
+ AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(
+ assemblyName, AssemblyBuilderAccess.Run);
+ // assemblyName, AssemblyBuilderAccess.RunAndSave,"."); // to save it to the disk
+
+ // create a new module for this proxy
+ ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(MODULE_NAME);
+
+ // Set the class to be public and sealed
+ TypeAttributes typeAttributes =
+ TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed;
+
+ // Gather up the proxy information and create a new type builder. One that
+ // inherits from Object and implements the interface passed in
+ TypeBuilder typeBuilder = moduleBuilder.DefineType(
+ dynamicTypeName, typeAttributes, objType, interfaces);
+
+ // Define a member variable to hold the delegate
+ FieldBuilder handlerField = typeBuilder.DefineField(
+ HANDLER_NAME, handlerType, FieldAttributes.Private);
+
+
+ // build a constructor that takes the delegate object as the only argument
+ //ConstructorInfo defaultObjConstructor = objType.GetConstructor( new Type[0] );
+ ConstructorInfo superConstructor = objType.GetConstructor(new Type[0]);
+ ConstructorBuilder delegateConstructor = typeBuilder.DefineConstructor(
+ MethodAttributes.Public, CallingConventions.Standard, new Type[] { handlerType });
+
+ #region( "Constructor IL Code" )
+ ILGenerator constructorIL = delegateConstructor.GetILGenerator();
+
+ // Load "this"
+ constructorIL.Emit(OpCodes.Ldarg_0);
+ // Load first constructor parameter
+ constructorIL.Emit(OpCodes.Ldarg_1);
+ // Set the first parameter into the handler field
+ constructorIL.Emit(OpCodes.Stfld, handlerField);
+ // Load "this"
+ constructorIL.Emit(OpCodes.Ldarg_0);
+ // Call the super constructor
+ constructorIL.Emit(OpCodes.Call, superConstructor);
+ // Constructor return
+ constructorIL.Emit(OpCodes.Ret);
+ #endregion
+
+ // for every method that the interfaces define, build a corresponding
+ // method in the dynamic type that calls the handlers invoke method.
+ foreach (Type interfaceType in interfaces)
+ {
+ GenerateMethod(interfaceType, handlerField, typeBuilder);
+ }
+
+ retVal = typeBuilder.CreateType();
+
+ // assemblyBuilder.Save(dynamicTypeName + ".dll");
+ }
+
+ return retVal;
+ }
+
+ private static readonly MethodInfo INVOKE_METHOD = typeof(IProxyInvocationHandler).GetMethod("Invoke");
+ private static readonly MethodInfo GET_METHODINFO_METHOD = typeof(MetaDataFactory).GetMethod("GetMethod", new Type[] { typeof(string), typeof(int) });
+
+ private void GenerateMethod( Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder ) {
+ MetaDataFactory.Add( interfaceType );
+ MethodInfo[] interfaceMethods = interfaceType.GetMethods();
+ PropertyInfo[] props = interfaceType.GetProperties();
+
+ for ( int i = 0; i < interfaceMethods.Length; i++ ) {
+ MethodInfo methodInfo = interfaceMethods[i];
+
+ // Get the method parameters since we need to create an array
+ // of parameter types
+ ParameterInfo[] methodParams = methodInfo.GetParameters();
+ int numOfParams = methodParams.Length;
+ Type[] methodParameters = new Type[ numOfParams ];
+
+ // convert the ParameterInfo objects into Type
+ for ( int j = 0; j < numOfParams; j++ ) {
+ methodParameters[j] = methodParams[j].ParameterType;
+ }
+
+ // create a new builder for the method in the interface
+ MethodBuilder methodBuilder = typeBuilder.DefineMethod(
+ methodInfo.Name,
+ /*MethodAttributes.Public | MethodAttributes.Virtual | */ methodInfo.Attributes&~MethodAttributes.Abstract,
+ CallingConventions.Standard,
+ methodInfo.ReturnType, methodParameters );
+
+ #region( "Handler Method IL Code" )
+ ILGenerator methodIL = methodBuilder.GetILGenerator();
+
+ // load "this"
+ methodIL.Emit( OpCodes.Ldarg_0 );
+ // load the handler
+ methodIL.Emit( OpCodes.Ldfld, handlerField );
+ // load "this" since its needed for the call to invoke
+ methodIL.Emit( OpCodes.Ldarg_0 );
+ // load the name of the interface, used to get the MethodInfo object
+ // from MetaDataFactory
+ methodIL.Emit( OpCodes.Ldstr, interfaceType.FullName );
+ // load the index, used to get the MethodInfo object
+ // from MetaDataFactory
+ methodIL.Emit( OpCodes.Ldc_I4, i );
+ // invoke GetMethod in MetaDataFactory
+ methodIL.Emit( OpCodes.Call, GET_METHODINFO_METHOD);
+
+ // load the number of parameters onto the stack
+ methodIL.Emit( OpCodes.Ldc_I4, numOfParams );
+ // create a new array, using the size that was just pused on the stack
+ methodIL.Emit( OpCodes.Newarr, typeof(object) );
+
+ // if we have any parameters, then iterate through and set the values
+ // of each element to the corresponding arguments
+ for ( int j = 0; j < numOfParams; j++ ) {
+ methodIL.Emit( OpCodes.Dup ); // this copies the array
+ methodIL.Emit( OpCodes.Ldc_I4, j );
+ methodIL.Emit( OpCodes.Ldarg, j + 1 );
+ if ( methodParameters[j].IsValueType ) {
+ methodIL.Emit( OpCodes.Box, methodParameters[j] );
+ }
+ methodIL.Emit( OpCodes.Stelem_Ref );
+ }
+
+ // call the Invoke method
+ methodIL.Emit( OpCodes.Callvirt, INVOKE_METHOD );
+
+ if ( methodInfo.ReturnType != typeof(void) ) {
+ // if the return type if a value type, then unbox the return value
+ // so that we don't get junk.
+ if ( methodInfo.ReturnType.IsValueType ) {
+ methodIL.Emit( OpCodes.Unbox, methodInfo.ReturnType );
+ if ( methodInfo.ReturnType.IsEnum ) {
+ methodIL.Emit( OpCodes.Ldind_I4 );
+ } else if ( !methodInfo.ReturnType.IsPrimitive ) {
+ methodIL.Emit( OpCodes.Ldobj, methodInfo.ReturnType );
+ } else {
+ methodIL.Emit( (OpCode) opCodeTypeMapper[ methodInfo.ReturnType ] );
+ }
+ }
+ } else {
+ // pop the return value that Invoke returned from the stack since
+ // the method's return type is void.
+ methodIL.Emit( OpCodes.Pop );
+ }
+
+ // Return
+ methodIL.Emit( OpCodes.Ret );
+ #endregion
+ }
+
+ //for (int i = 0; i < props.Length; i++)
+ //{
+ // PropertyInfo p = props[i];
+
+ // PropertyBuilder pb = typeBuilder.DefineProperty(p.Name, p.Attributes, p.PropertyType, new Type[] { p.PropertyType });
+ // pb.SetGetMethod((MethodBuilder)methodTable[p.GetGetMethod()]);
+ // pb.SetSetMethod((MethodBuilder)methodTable[p.GetSetMethod()]);
+ //}
+
+ // Iterate through the parent interfaces and recursively call this method
+ foreach ( Type parentType in interfaceType.GetInterfaces() ) {
+ GenerateMethod( parentType, handlerField, typeBuilder );
+ }
+ }
+ }
+}
View
335 Main.cs
@@ -0,0 +1,335 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Diagnostics;
+using System.ServiceProcess;
+using System.Text;
+using System.IO;
+using WMI;
+using System.Xml;
+using System.Threading;
+using Microsoft.Win32;
+
+namespace winsw
+{
+ /// <summary>
+ /// In-memory representation of the configuration file.
+ /// </summary>
+ public class ServiceDescriptor
+ {
+ private readonly XmlDocument dom = new XmlDocument();
+
+ /// <summary>
+ /// Where did we find the configuration file?
+ /// </summary>
+ public readonly string BasePath;
+
+ public static string ExecutablePath
+ {
+ get
+ {
+ // this returns the executable name as given by the calling process, so
+ // it needs to be absolutized.
+ string p = Environment.GetCommandLineArgs()[0];
+ return Path.Combine(Environment.CurrentDirectory, p);
+
+ }
+ }
+
+ public ServiceDescriptor()
+ {
+ // find co-located configuration xml. We search up to the ancestor directories to simplify debugging,
+ // as well as trimming off ".vshost" suffix (which is used during debugging)
+ string p = ExecutablePath;
+ string baseName = Path.GetFileNameWithoutExtension(p);
+ if (baseName.EndsWith(".vshost")) baseName = baseName.Substring(0, baseName.Length - 7);
+ while (true)
+ {
+ p = Path.GetDirectoryName(p);
+ if (File.Exists(Path.Combine(p, baseName + ".xml")))
+ break;
+ }
+
+ // register the base directory as environment variable so that future expansions can refer to this.
+ Environment.SetEnvironmentVariable("BASE", p);
+
+ BasePath = Path.Combine(p, baseName);
+
+ dom.Load(BasePath+".xml");
+ }
+
+ private string SingleElement(string tagName)
+ {
+ var n = dom.SelectSingleNode("//" + tagName);
+ if (n == null) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");
+ return Environment.ExpandEnvironmentVariables(n.InnerText);
+ }
+
+ /// <summary>
+ /// Path to the executable.
+ /// </summary>
+ public string Executable
+ {
+ get
+ {
+ return SingleElement("executable");
+ }
+ }
+
+ /// <summary>
+ /// Arguments
+ /// </summary>
+ public string Arguments
+ {
+ get
+ {
+ return SingleElement("arguments");
+ }
+ }
+
+ public string Id
+ {
+ get
+ {
+ return SingleElement("id");
+ }
+ }
+
+ public string Caption
+ {
+ get
+ {
+ return SingleElement("name");
+ }
+ }
+
+ public string Description
+ {
+ get
+ {
+ return SingleElement("description");
+ }
+ }
+
+ /// <summary>
+ /// True if the service can interact with the desktop.
+ /// </summary>
+ public bool Interactive
+ {
+ get
+ {
+ return dom.SelectSingleNode("//interactive") != null;
+ }
+ }
+
+ /// <summary>
+ /// Environment variable overrides
+ /// </summary>
+ public Dictionary<string, string> EnvironmentVariables
+ {
+ get
+ {
+ Dictionary<string, string> map = new Dictionary<string, string>();
+ foreach (XmlNode n in dom.SelectNodes("//env"))
+ {
+ map[n.Attributes["name"].Value] = Environment.ExpandEnvironmentVariables(n.Attributes["value"].Value);
+ }
+ return map;
+ }
+ }
+ }
+
+ public class WrapperService : ServiceBase
+ {
+ private Process process = new Process();
+ private ServiceDescriptor descriptor;
+
+ /// <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;
+
+ public WrapperService()
+ {
+ this.descriptor = new ServiceDescriptor();
+ this.ServiceName = descriptor.Id;
+ this.CanStop = true;
+ this.CanPauseAndContinue = false;
+ this.AutoLog = true;
+ }
+
+ /// <summary>
+ /// Copy stuff from StreamReader to StreamWriter
+ /// </summary>
+ private void CopyStream(StreamReader i, StreamWriter o)
+ {
+ char[] buf = new char[1024];
+ while (true)
+ {
+ int sz = i.Read(buf, 0, buf.Length);
+ if (sz == 0) break;
+ o.Write(buf, 0, sz);
+ o.Flush();
+ }
+ i.Close();
+ o.Close();
+ }
+
+ protected override void OnStart(string[] args)
+ {
+ EventLog.WriteEntry("Starting "+descriptor.Executable+' '+descriptor.Arguments);
+ string baseName = descriptor.BasePath;
+
+ var ps = process.StartInfo;
+ ps.FileName = descriptor.Executable;
+ ps.Arguments = descriptor.Arguments;
+ 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;
+
+ var envs = descriptor.EnvironmentVariables;
+ foreach (string key in envs.Keys)
+ ps.EnvironmentVariables[key] = envs[key];
+
+ process.Start();
+
+ // send stdout and stderr to its respective output file.
+ new Thread(delegate() { CopyStream(process.StandardOutput, new StreamWriter(new FileStream(baseName + ".out.log", FileMode.Append))); }).Start();
+ new Thread(delegate() { CopyStream(process.StandardError, new StreamWriter(new FileStream(baseName + ".err.log", FileMode.Append))); }).Start();
+
+ // monitor the completion of the process
+ new Thread(delegate()
+ {
+ process.WaitForExit();
+ if (!orderlyShutdown)
+ {
+ EventLog.WriteEntry("Child process terminated with " + process.ExitCode,EventLogEntryType.Warning);
+ Environment.Exit(process.ExitCode);
+ }
+ }).Start();
+
+ process.StandardInput.Close(); // nothing for you to read!
+ }
+
+ protected override void OnStop()
+ {
+ try
+ {
+ EventLog.WriteEntry("Stopping "+descriptor.Id);
+ orderlyShutdown = true;
+ process.Kill();
+ }
+ catch (InvalidOperationException)
+ {
+ // already terminated
+ }
+ process.Dispose();
+ }
+
+
+
+ public static int Main(string[] args)
+ {
+ 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);
+ }
+
+ public static void Run(string[] args)
+ {
+ if (args.Length > 0)
+ {
+ var d = new ServiceDescriptor();
+ Win32Services svc = new WmiRoot().GetCollection<Win32Services>();
+ Win32Service s = svc.Select(d.Id);
+
+ args[0] = args[0].ToLower();
+ if (args[0] == "install")
+ {
+ svc.Create(
+ d.Id,
+ d.Caption,
+ ServiceDescriptor.ExecutablePath,
+ WMI.ServiceType.OwnProcess,
+ ErrorControl.UserNotified,
+ StartMode.Automatic,
+ d.Interactive);
+ // 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);
+ }
+ 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();
+ }
+ 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();
+ wsvc.OnStart(args);
+ Thread.Sleep(1000);
+ wsvc.OnStop();
+ }
+ return;
+ }
+ ServiceBase.Run(new WrapperService());
+ }
+ }
+}
View
33 Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Windows Service Wrapper")]
+[assembly: AssemblyDescription("Allows arbitrary process to run as a Windows service by wrapping it")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Sun Microsystems, Inc.")]
+[assembly: AssemblyProduct("Windows Service Wrapper")]
+[assembly: AssemblyCopyright("Copyright 2008 Sun Micorsystems, Inc.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("59ce18df-cacb-4360-bb80-798bd6459ca3")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
View
216 Wmi.cs
@@ -0,0 +1,216 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection;
+using System.Management;
+using DynamicProxy;
+
+namespace WMI
+{
+ //Reference: http://msdn2.microsoft.com/en-us/library/aa389390(VS.85).aspx
+
+ public enum ReturnValue
+ {
+ Success = 0,
+ NotSupported = 1,
+ AccessDenied = 2,
+ DependentServicesRunning = 3,
+ InvalidServiceControl = 4,
+ ServiceCannotAcceptControl = 5,
+ ServiceNotActive = 6,
+ ServiceRequestTimeout = 7,
+ UnknownFailure = 8,
+ PathNotFound = 9,
+ ServiceAlreadyRunning = 10,
+ ServiceDatabaseLocked = 11,
+ ServiceDependencyDeleted = 12,
+ ServiceDependencyFailure = 13,
+ ServiceDisabled = 14,
+ ServiceLogonFailure = 15,
+ ServiceMarkedForDeletion = 16,
+ ServiceNoThread = 17,
+ StatusCircularDependency = 18,
+ StatusDuplicateName = 19,
+ StatusInvalidName = 20,
+ StatusInvalidParameter = 21,
+ StatusInvalidServiceAccount = 22,
+ StatusServiceExists = 23,
+ ServiceAlreadyPaused = 24,
+
+ NoSuchService = 200
+ }
+
+ /// <summary>
+ /// Signals a problem in WMI related operations
+ /// </summary>
+ public class WmiException : Exception
+ {
+ public readonly ReturnValue ErrorCode;
+
+ public WmiException(string msg, ReturnValue code)
+ : base(msg)
+ {
+ ErrorCode = code;
+ }
+
+ public WmiException(ReturnValue code)
+ : this(code.ToString(), code)
+ {
+ }
+ }
+
+ /// <summary>
+ /// Associated a WMI class name to the proxy interface (which should extend from IWmiCollection)
+ /// </summary>
+ public class WmiClassName : Attribute
+ {
+ public readonly string Name;
+ public WmiClassName(string name) { this.Name = name; }
+ }
+
+ /// <summary>
+ /// Marker interface to denote a collection in WMI.
+ /// </summary>
+ public interface IWmiCollection {}
+
+ /// <summary>
+ /// Marker interface to denote an individual managed object
+ /// </summary>
+ public interface IWmiObject
+ {
+ /// <summary>
+ /// Reflect updates made to this object to the WMI provider.
+ /// </summary>
+ void Commit();
+ }
+
+ public class WmiRoot
+ {
+ private readonly ManagementScope scope;
+
+ public WmiRoot() : this(null) { }
+
+ public WmiRoot(string machineName)
+ {
+ ConnectionOptions options = new ConnectionOptions();
+
+ string path;
+
+ if (machineName != null)
+ path = String.Format(@"\\{0}\root\cimv2", machineName);
+ else
+ path = @"\root\cimv2";
+ scope = new ManagementScope(path, options);
+ scope.Connect();
+ }
+
+ private static string capitalize(string s)
+ {
+ return char.ToUpper(s[0]) + s.Substring(1);
+ }
+
+ abstract class BaseHandler : IProxyInvocationHandler
+ {
+ public abstract object Invoke(object proxy, MethodInfo method, object[] args);
+
+ protected void CheckError(ManagementBaseObject result)
+ {
+ int code = Convert.ToInt32(result["returnValue"]);
+ if (code != 0)
+ throw new WmiException((ReturnValue)code);
+ }
+ }
+
+ class InstanceHandler : BaseHandler, IWmiObject
+ {
+ private readonly ManagementObject mo;
+
+ public InstanceHandler(ManagementObject o) { this.mo = o; }
+
+ public override object Invoke(object proxy, MethodInfo method, object[] args)
+ {
+ if (method.DeclaringType == typeof(IWmiObject))
+ {
+ return method.Invoke(this, args);
+ }
+
+ // TODO: proper property support
+ if (method.Name.StartsWith("set_"))
+ {
+ mo[method.Name.Substring(4)] = args[0];
+ return null;
+ }
+ if (method.Name.StartsWith("get_"))
+ {
+ return mo[method.Name.Substring(4)];
+ }
+
+ // method invocations
+ ParameterInfo[] methodArgs = method.GetParameters();
+
+ ManagementBaseObject wmiArgs = mo.GetMethodParameters(method.Name);
+ for (int i = 0; i < args.Length; i++)
+ wmiArgs[capitalize(methodArgs[i].Name)] = args[i];
+
+ CheckError(mo.InvokeMethod(method.Name, wmiArgs, null));
+ return null;
+ }
+
+ public void Commit()
+ {
+ mo.Put();
+ }
+ }
+
+ class ClassHandler : BaseHandler
+ {
+ private readonly ManagementClass mc;
+ private readonly string wmiClass;
+
+ public ClassHandler(ManagementClass mc, string wmiClass) { this.mc = mc; this.wmiClass = wmiClass; }
+
+ public override object Invoke(object proxy, MethodInfo method, object[] args)
+ {
+ ParameterInfo[] methodArgs = method.GetParameters();
+
+ if (method.Name.StartsWith("Select"))
+ {
+ // select method to find instances
+ string query = "SELECT * FROM " + wmiClass + " WHERE ";
+ for (int i = 0; i < args.Length; i++)
+ {
+ if (i != 0) query += " AND ";
+ query += ' ' + capitalize(methodArgs[i].Name) + " = '" + args[i] + "'";
+ }
+
+ ManagementObjectSearcher searcher = new ManagementObjectSearcher(mc.Scope, new ObjectQuery(query));
+ ManagementObjectCollection results = searcher.Get();
+ // TODO: support collections
+ foreach (ManagementObject manObject in results)
+ return ProxyFactory.GetInstance().Create(new InstanceHandler(manObject), method.ReturnType, true);
+ return null;
+ }
+
+ ManagementBaseObject wmiArgs = mc.GetMethodParameters(method.Name);
+ for (int i = 0; i < args.Length; i++)
+ wmiArgs[capitalize(methodArgs[i].Name)] = args[i];
+
+ CheckError(mc.InvokeMethod(method.Name, wmiArgs, null));
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Obtains an object that corresponds to a table in WMI, which is a collection of a managed object.
+ /// </summary>
+ public T GetCollection<T>() where T : IWmiCollection
+ {
+ WmiClassName cn = (WmiClassName)typeof(T).GetCustomAttributes(typeof(WmiClassName), false)[0];
+
+ ObjectGetOptions getOptions = new ObjectGetOptions();
+ ManagementPath path = new ManagementPath(cn.Name);
+ ManagementClass manClass = new ManagementClass(scope, path, getOptions);
+ return (T)ProxyFactory.GetInstance().Create(new ClassHandler(manClass, cn.Name), typeof(T), true);
+ }
+ }
+}
View
64 WmiSchema.cs
@@ -0,0 +1,64 @@
+
+namespace WMI
+{
+ public enum ServiceType
+ {
+ KernalDriver = 1,
+ FileSystemDriver = 2,
+ Adapter = 4,
+ RecognizerDriver = 8,
+ OwnProcess = 16,
+ ShareProcess = 32,
+ InteractiveProcess = 256,
+ }
+
+ public enum ErrorControl
+ {
+ UserNotNotified = 0,
+ UserNotified = 1,
+ SystemRestartedWithLastKnownGoodConfiguration = 2,
+ SystemAttemptsToStartWithAGoodConfiguration = 3
+ }
+
+ public enum StartMode
+ {
+ /// <summary>
+ /// Device driver started by the operating system loader. This value is valid only for driver services.
+ /// </summary>
+ Boot,
+ /// <summary>
+ /// Device driver started by the operating system initialization process. This value is valid only for driver services.
+ /// </summary>
+ System,
+ /// <summary>
+ /// Service to be started automatically by the Service Control Manager during system startup.
+ /// </summary>
+ Automatic,
+ /// <summary>
+ /// Service to be started by the Service Control Manager when a process calls the StartService method.
+ /// </summary>
+ Manual,
+ /// <summary>
+ /// Service that can no longer be started.
+ /// </summary>
+ Disabled,
+ }
+
+ [WmiClassName("Win32_Service")]
+ public interface Win32Services : IWmiCollection
+ {
+ // ReturnValue Create(bool desktopInteract, string displayName, int errorControl, string loadOrderGroup, string loadOrderGroupDependencies, string name, string pathName, string serviceDependencies, string serviceType, string startMode, string startName, string startPassword);
+ void Create(string name, string displayName, string pathName, ServiceType serviceType, ErrorControl errorControl, StartMode startMode, bool desktopInteract);
+
+ Win32Service Select(string name);
+ }
+
+ public interface Win32Service : IWmiObject
+ {
+ string Description { get; set; }
+ bool Started { get; }
+ void Delete();
+ void StartService();
+ void StopService();
+ }
+}
View
63 pom.xml
@@ -0,0 +1,63 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.sun.winsw</groupId>
+ <artifactId>winsw</artifactId>
+ <packaging>pom</packaging>
+ <version>1.0</version>
+ <name>Windows service wrapper</name>
+
+ <distributionManagement>
+ <repository>
+ <id>java.net-m2-repository</id>
+ <url>java-net:/maven2-repository/trunk/www/repository/</url>
+ </repository>
+ </distributionManagement>
+
+ <build>
+ <plugins>
+ <!-- fake out maven and install the binary artifact -->
+ <plugin>
+ <groupId>org.jvnet.maven-antrun-extended-plugin</groupId>
+ <artifactId>maven-antrun-extended-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ <configuration>
+ <tasks>
+ <attachArtifact file="bin/Debug/winsw.exe" type="exe" classifier="bin" />
+ </tasks>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ <extensions>
+ <extension>
+ <groupId>org.jvnet.wagon-svn</groupId>
+ <artifactId>wagon-svn</artifactId>
+ <version>1.8</version>
+ </extension>
+ </extensions>
+ </build>
+
+ <repositories>
+ <repository>
+ <id>maven2-repository.dev.java.net</id>
+ <name>Java.net Repository for Maven</name>
+ <url>http://download.java.net/maven/2/</url>
+ </repository>
+ </repositories>
+
+ <pluginRepositories>
+ <pluginRepository>
+ <id>maven2-repository.dev.java.net</id>
+ <name>Java.net Repository for Maven</name>
+ <url>http://download.java.net/maven/2/</url>
+ </pluginRepository>
+ </pluginRepositories>
+</project>
View
64 winsw.csproj
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{0DE77F55-ADE5-43C1-999A-0BC81153B039}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>winsw</RootNamespace>
+ <AssemblyName>winsw</AssemblyName>
+ <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <StartupObject>
+ </StartupObject>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Management" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.ServiceProcess" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="DynamicProxy.cs" />
+ <Compile Include="Main.cs">
+ <SubType>Component</SubType>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Wmi.cs" />
+ <Compile Include="WmiSchema.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="winsw.xml" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
View
30 winsw.sln
@@ -0,0 +1,30 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winsw", "winsw.csproj", "{0DE77F55-ADE5-43C1-999A-0BC81153B039}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|Mixed Platforms = Debug|Mixed Platforms
+ Debug|Win32 = Debug|Win32
+ Release|Any CPU = Release|Any CPU
+ Release|Mixed Platforms = Release|Mixed Platforms
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Win32.ActiveCfg = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
View
7 winsw.xml
@@ -0,0 +1,7 @@
+<configuration>
+ <id>winsw</id>
+ <name>Winsw test service(2)</name>
+ <description>This service is a do-nothing test app. Really.</description>
+ <executable>C:\development\jdk6u7\bin\java.exe</executable>
+ <arguments>-classpath c:\cygwin\home\kohsuke\ws\hello-world\out\production\hello-world test.Main</arguments>
+</configuration>
Please sign in to comment.
Something went wrong with that request. Please try again.