diff --git a/README.markdown b/README.markdown
index ee36f76..91bee02 100644
--- a/README.markdown
+++ b/README.markdown
@@ -171,6 +171,9 @@ Long human-readable description of the service. This gets displayed in Windows s
### executable
This element specifies the executable to be launched. It can be either absolute path, or you can just specify the executable name and let it be searched from `PATH` (although note that the services often run in a different user account and therefore it might have different `PATH` than your shell does.)
+### startmode - Optional Element
+This element specifies the start mode of the Windows service. It can be one of the following values: Boot, System, Automatic, or Manual. See [MSDN](https://msdn.microsoft.com/en-us/library/aa384896%28v=vs.85%29.aspx) for details. The default is Automatic.
+
### depend
Specify IDs of other services that this service depends on. When service X depends on service Y, X can only run if Y is running.
@@ -305,6 +308,17 @@ Optionally specify the order of service shutdown. If true, the parent process is
Developer info
----------------------
+### Project status
+
+* WinSW 1.x - Maintenance only
+ * [winsw-1.17] fixes the most of active issues
+ * [winsw-1.17-beta.2] is available for the evaluation
+ * New versions may be released on-demand
+ * All new fixes will be ported to WinSW-2.x
+* WinSW 2.x - Active development, no stable releases available
+ * [winsw-2.0] - Current development branch
+ * API stability is not guaranteed till the first release, the project structure is in flux
+
### Build Environment
* IDE: [Visual Studio Community 2013][MVS2013] (free for open-source projects)
@@ -313,3 +327,6 @@ Developer info
* The certificate is in .gitignore
list. Please do not add it to the repository
[MVS2013]: http://www.visualstudio.com/en-us/news/vs2013-community-vs.aspx
+[winsw-1.17]: https://github.com/kohsuke/winsw/milestones/winsw-1.17
+[winsw-1.17-beta.2]: https://github.com/kohsuke/winsw/releases/tag/1.17-beta.2
+[WinSW-2.0]: https://github.com/kohsuke/winsw/milestones/winsw-2.0
diff --git a/packages/repositories.config b/packages/repositories.config
new file mode 100644
index 0000000..939c169
--- /dev/null
+++ b/packages/repositories.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/Core/ServiceWrapper/Main.cs b/src/Core/ServiceWrapper/Main.cs
index 4eef94e..bf29bbf 100644
--- a/src/Core/ServiceWrapper/Main.cs
+++ b/src/Core/ServiceWrapper/Main.cs
@@ -16,6 +16,7 @@ using log4net.Repository.Hierarchy;
using Microsoft.Win32;
using WMI;
using ServiceType = WMI.ServiceType;
+using System.Reflection;
namespace winsw
{
@@ -36,9 +37,20 @@ namespace winsw
private bool _orderlyShutdown;
private bool _systemShuttingdown;
- public WrapperService()
+ ///
+ /// Version of Windows service wrapper
+ ///
+ ///
+ /// The version will be taken from
+ ///
+ public static Version Version
{
- _descriptor = new ServiceDescriptor();
+ get { return Assembly.GetExecutingAssembly().GetName().Version; }
+ }
+
+ public WrapperService(ServiceDescriptor descriptor)
+ {
+ _descriptor = descriptor;
ServiceName = _descriptor.Id;
CanShutdown = true;
CanStop = true;
@@ -47,6 +59,10 @@ namespace winsw
_systemShuttingdown = false;
}
+ public WrapperService() : this (new ServiceDescriptor())
+ {
+ }
+
///
/// Process the file copy instructions, so that we can replace files that are always in use while
/// the service runs.
@@ -517,17 +533,17 @@ namespace winsw
}
// ReSharper disable once InconsistentNaming
- public static void Run(string[] _args)
+ public static void Run(string[] _args, ServiceDescriptor descriptor = null)
{
bool isCLIMode = _args.Length > 0;
- var d = new ServiceDescriptor();
+ var d = descriptor ?? new ServiceDescriptor();
// Configure the wrapper-internal logging
// STDIN and STDOUT of the child process will be handled independently
InitLoggers(d, isCLIMode);
if (isCLIMode) // CLI mode
- {
+ {
Log.Debug("Starting ServiceWrapper in CLI mode");
// Get service info for the future use
@@ -560,6 +576,14 @@ namespace winsw
args[0] = args[0].ToLower();
if (args[0] == "install")
{
+ // Check if the service exists
+ if (s != null)
+ {
+ Console.WriteLine("Service with id '" + d.Id + "' already exists");
+ Console.WriteLine("To install the service, delete the existing one or change service Id in the configuration file");
+ throw new Exception("Installation failure: Service with id '" + d.Id + "' already exists");
+ }
+
string username=null, password=null;
bool setallowlogonasaserviceright = false;
if (args.Count > 1 && args[1] == "/p")
@@ -599,7 +623,7 @@ namespace winsw
"\"" + d.ExecutablePath + "\"",
ServiceType.OwnProcess,
ErrorControl.UserNotified,
- StartMode.Automatic,
+ d.StartMode,
d.Interactive,
username,
password,
@@ -627,11 +651,15 @@ namespace winsw
}
}
}
+ return;
}
if (args[0] == "uninstall")
{
if (s == null)
+ {
+ Console.WriteLine("Warning! The service with id '" + d.Id + "' does not exist. Nothing to uninstall");
return; // there's no such service, so consider it already uninstalled
+ }
try
{
s.Delete();
@@ -642,16 +670,19 @@ namespace winsw
return; // it's already uninstalled, so consider it a success
throw e;
}
+ return;
}
if (args[0] == "start")
{
if (s == null) ThrowNoSuchService();
s.StartService();
+ return;
}
if (args[0] == "stop")
{
if (s == null) ThrowNoSuchService();
s.StopService();
+ return;
}
if (args[0] == "restart")
{
@@ -668,6 +699,7 @@ namespace winsw
}
s.StartService();
+ return;
}
if (args[0] == "restart!")
{
@@ -681,6 +713,7 @@ namespace winsw
{
throw new Exception("Failed to invoke restart: "+Marshal.GetLastWin32Error());
}
+ return;
}
if (args[0] == "status")
{
@@ -691,6 +724,7 @@ namespace winsw
Console.WriteLine("Started");
else
Console.WriteLine("Stopped");
+ return;
}
if (args[0] == "test")
{
@@ -698,8 +732,24 @@ namespace winsw
wsvc.OnStart(args.ToArray());
Thread.Sleep(1000);
wsvc.OnStop();
+ return;
}
- return;
+ if (args[0] == "help" || args[0] == "--help" || args[0] == "-h"
+ || args[0] == "-?" || args[0] == "/?")
+ {
+ printHelp();
+ return;
+ }
+ if (args[0] == "version")
+ {
+ printVersion();
+ return;
+ }
+
+ Console.WriteLine("Unknown command: " + args[0]);
+ printAvailableCommandsInfo();
+ throw new Exception("Unknown command: " + args[0]);
+
}
Run(new WrapperService());
}
@@ -764,5 +814,43 @@ namespace winsw
}
}
}
+
+ private static void printHelp()
+ {
+ Console.WriteLine("A wrapper binary that can be used to host executables as Windows services");
+ Console.WriteLine("");
+ Console.WriteLine("Usage: winsw [/redirect file] []");
+ Console.WriteLine(" Missing arguments trigger the service mode");
+ Console.WriteLine("");
+ printAvailableCommandsInfo();
+ Console.WriteLine("");
+ Console.WriteLine("Extra options:");
+ Console.WriteLine("- '/redirect' - redirect the wrapper's STDOUT and STDERR to the specified file");
+ Console.WriteLine("");
+ printVersion();
+ Console.WriteLine("More info: https://github.com/kohsuke/winsw");
+ Console.WriteLine("Bug tracker: https://github.com/kohsuke/winsw/issues");
+ }
+
+ //TODO: Rework to enum in winsw-2.0
+ private static void printAvailableCommandsInfo()
+ {
+ Console.WriteLine("Available commands:");
+ Console.WriteLine("- 'install' - install the service to Windows Service Controller");
+ Console.WriteLine("- 'uninstall' - uninstall the service");
+ Console.WriteLine("- 'start' - start the service (must be installed before)");
+ Console.WriteLine("- 'stop' - stop the service");
+ Console.WriteLine("- 'restart' - restart the service");
+ Console.WriteLine("- 'restart!' - self-restart (can be called from child processes)");
+ Console.WriteLine("- 'status' - check the current status of the service");
+ Console.WriteLine("- 'test' - check if the service can be started and then stopped");
+ Console.WriteLine("- 'version' - print the version info");
+ Console.WriteLine("- 'help' - print the help info (aliases: -h,--help,-?,/?)");
+ }
+
+ private static void printVersion()
+ {
+ Console.WriteLine("WinSW " + Version);
+ }
}
}
diff --git a/src/Core/ServiceWrapper/Properties/AssemblyInfo.cs b/src/Core/ServiceWrapper/Properties/AssemblyInfo.cs
index 0a13fa9..1531349 100644
--- a/src/Core/ServiceWrapper/Properties/AssemblyInfo.cs
+++ b/src/Core/ServiceWrapper/Properties/AssemblyInfo.cs
@@ -28,5 +28,5 @@ using System.Runtime.InteropServices;
// 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.1.0.0")]
-[assembly: AssemblyFileVersion("1.1.0.0")]
+[assembly: AssemblyVersion("1.17.0.0")]
+[assembly: AssemblyFileVersion("1.17.0.0")]
diff --git a/src/Core/ServiceWrapper/ServiceDescriptor.cs b/src/Core/ServiceWrapper/ServiceDescriptor.cs
index 0949bd5..1263087 100755
--- a/src/Core/ServiceWrapper/ServiceDescriptor.cs
+++ b/src/Core/ServiceWrapper/ServiceDescriptor.cs
@@ -5,6 +5,7 @@ using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Xml;
+using WMI;
namespace winsw
{
@@ -36,8 +37,7 @@ namespace winsw
// 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(AppDomain.CurrentDomain.BaseDirectory, p);
-
+ return Path.GetFullPath(p);
}
}
@@ -45,18 +45,24 @@ namespace winsw
{
// 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)
+ //Get the first parent to go into the recursive loop
string p = ExecutablePath;
string baseName = Path.GetFileNameWithoutExtension(p);
if (baseName.EndsWith(".vshost")) baseName = baseName.Substring(0, baseName.Length - 7);
+ DirectoryInfo d = new DirectoryInfo(Path.GetDirectoryName(p));
while (true)
{
- p = Path.GetDirectoryName(p);
- if (File.Exists(Path.Combine(p, baseName + ".xml")))
+ if (File.Exists(Path.Combine(d.FullName, baseName + ".xml")))
break;
+
+ if (d.Parent == null)
+ throw new FileNotFoundException("Unable to locate "+baseName+".xml file within executable directory or any parents");
+
+ d = d.Parent;
}
BaseName = baseName;
- BasePath = Path.Combine(p, BaseName);
+ BasePath = Path.Combine(d.FullName, BaseName);
dom.Load(BasePath + ".xml");
@@ -393,6 +399,31 @@ namespace winsw
}
}
+ ///
+ /// Start mode of the Service
+ ///
+ public StartMode StartMode
+ {
+ get
+ {
+ var p = SingleElement("startmode", true);
+ if (p == null) return StartMode.Automatic; // default value
+ try
+ {
+ return (StartMode)Enum.Parse(typeof(StartMode), p, true);
+ }
+ catch
+ {
+ Console.WriteLine("Start mode in XML must be one of the following:");
+ foreach (string sm in Enum.GetNames(typeof(StartMode)))
+ {
+ Console.WriteLine(sm);
+ }
+ throw;
+ }
+ }
+ }
+
///
/// True if the service should when finished on shutdown.
/// This doesn't work on some OSes. See http://msdn.microsoft.com/en-us/library/ms679277%28VS.85%29.aspx
diff --git a/src/Core/ServiceWrapper/winsw.csproj b/src/Core/ServiceWrapper/winsw.csproj
index b4fda6c..0844ff4 100644
--- a/src/Core/ServiceWrapper/winsw.csproj
+++ b/src/Core/ServiceWrapper/winsw.csproj
@@ -45,7 +45,7 @@
full
false
bin\Debug\
- DEBUG;TRACE
+ TRACE;DEBUG
prompt
4
true
@@ -58,6 +58,8 @@
prompt
4
true
+
+
diff --git a/src/Test/winswTests/MainTest.cs b/src/Test/winswTests/MainTest.cs
new file mode 100644
index 0000000..6bf8402
--- /dev/null
+++ b/src/Test/winswTests/MainTest.cs
@@ -0,0 +1,48 @@
+using NUnit.Framework;
+using winsw;
+using winswTests.Util;
+
+namespace winswTests
+{
+ [TestFixture]
+ class MainTest
+ {
+
+ [Test]
+ public void PrintVersion()
+ {
+ string expectedVersion = WrapperService.Version.ToString();
+ string cliOut = CLITestHelper.CLITest(new[] { "version" });
+ StringAssert.Contains(expectedVersion, cliOut, "Expected that version contains " + expectedVersion);
+ }
+
+ [Test]
+ public void PrintHelp()
+ {
+ string expectedVersion = WrapperService.Version.ToString();
+ string cliOut = CLITestHelper.CLITest(new[] { "help" });
+
+ StringAssert.Contains(expectedVersion, cliOut, "Expected that help contains " + expectedVersion);
+ StringAssert.Contains("start", cliOut, "Expected that help refers start command");
+ StringAssert.Contains("help", cliOut, "Expected that help refers help command");
+ StringAssert.Contains("version", cliOut, "Expected that help refers version command");
+ //TODO: check all commands after the migration of ccommands to enum
+
+ // Extra options
+ StringAssert.Contains("/redirect", cliOut, "Expected that help message refers the redirect message");
+ }
+
+ [Test]
+ public void FailOnUnsupportedCommand()
+ {
+ const string commandName = "nonExistentCommand";
+ string expectedMessage = "Unknown command: " + commandName.ToLower();
+ CLITestResult res = CLITestHelper.CLIErrorTest(new[] {commandName});
+
+ Assert.True(res.HasException, "Expected an exception due to the wrong command");
+ StringAssert.Contains(expectedMessage, res.Out, "Expected the message about unknown command");
+ // ReSharper disable once PossibleNullReferenceException
+ StringAssert.Contains(expectedMessage, res.Exception.Message, "Expected the message about unknown command");
+ }
+ }
+}
diff --git a/src/Test/winswTests/ServiceDescriptorTests.cs b/src/Test/winswTests/ServiceDescriptorTests.cs
index 9c0e5ab..7b7ebb1 100644
--- a/src/Test/winswTests/ServiceDescriptorTests.cs
+++ b/src/Test/winswTests/ServiceDescriptorTests.cs
@@ -5,6 +5,9 @@ using winsw;
namespace winswTests
{
+ using System;
+ using WMI;
+
[TestFixture]
public class ServiceDescriptorTests
{
@@ -41,6 +44,66 @@ namespace winswTests
_extendedServiceDescriptor = ServiceDescriptor.FromXML(seedXml);
}
+ [Test]
+ public void DefaultStartMode()
+ {
+ Assert.That(_extendedServiceDescriptor.StartMode, Is.EqualTo(StartMode.Automatic));
+ }
+
+ [Test]
+ [ExpectedException(typeof(System.ArgumentException))]
+ public void IncorrectStartMode()
+ {
+ const string SeedXml = ""
+ + "service.exe"
+ + "Service"
+ + "The service."
+ + "node.exe"
+ + "My Arguments"
+ + "rotate"
+ + "rotate"
+ + ""
+ + "" + Domain + ""
+ + "" + Username + ""
+ + "" + Password + ""
+ + "" + AllowServiceAccountLogonRight + ""
+ + ""
+ + ""
+ + ExpectedWorkingDirectory
+ + ""
+ + @"C:\logs"
+ + "";
+
+ _extendedServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
+ Assert.That(_extendedServiceDescriptor.StartMode, Is.EqualTo(StartMode.Manual));
+ }
+
+ [Test]
+ public void ChangedStartMode()
+ {
+ const string SeedXml = ""
+ + "service.exe"
+ + "Service"
+ + "The service."
+ + "node.exe"
+ + "My Arguments"
+ + "manual"
+ + "rotate"
+ + ""
+ + "" + Domain + ""
+ + "" + Username + ""
+ + "" + Password + ""
+ + "" + AllowServiceAccountLogonRight + ""
+ + ""
+ + ""
+ + ExpectedWorkingDirectory
+ + ""
+ + @"C:\logs"
+ + "";
+
+ _extendedServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
+ Assert.That(_extendedServiceDescriptor.StartMode, Is.EqualTo(StartMode.Manual));
+ }
[Test]
public void VerifyWorkingDirectory()
{
diff --git a/src/Test/winswTests/Util/CLITestHelper.cs b/src/Test/winswTests/Util/CLITestHelper.cs
new file mode 100644
index 0000000..193c6b7
--- /dev/null
+++ b/src/Test/winswTests/Util/CLITestHelper.cs
@@ -0,0 +1,116 @@
+using System;
+using System.IO;
+using JetBrains.Annotations;
+using winsw;
+
+namespace winswTests.Util
+{
+ ///
+ /// Helper for WinSW CLI testing
+ ///
+ public static class CLITestHelper
+ {
+ private const string SeedXml = ""
+ + "service.exe"
+ + "Service"
+ + "The service."
+ + "node.exe"
+ + "My Arguments"
+ + "rotate"
+ + ""
+ + @"C:\winsw\workdir"
+ + ""
+ + @"C:\winsw\logs"
+ + "";
+ private static readonly ServiceDescriptor DefaultServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
+
+ ///
+ /// Runs a simle test, which returns the output CLI
+ ///
+ /// CLI arguments to be passed
+ /// Optional Service descriptor (will be used for initializationpurposes)
+ /// STDOUT if there's no exceptions
+ /// Command failure
+ [NotNull]
+ public static string CLITest(String[] args, ServiceDescriptor descriptor = null)
+ {
+ using (StringWriter sw = new StringWriter())
+ {
+ TextWriter tmp = Console.Out;
+ Console.SetOut(sw);
+ WrapperService.Run(args, descriptor ?? DefaultServiceDescriptor);
+ Console.SetOut(tmp);
+ Console.Write(sw.ToString());
+ return sw.ToString();
+ }
+ }
+
+ ///
+ /// Runs a simle test, which returns the output CLI
+ ///
+ /// CLI arguments to be passed
+ /// Optional Service descriptor (will be used for initializationpurposes)
+ /// Test results
+ [NotNull]
+ public static CLITestResult CLIErrorTest(String[] args, ServiceDescriptor descriptor = null)
+ {
+ StringWriter swOut, swErr;
+ Exception testEx = null;
+ TextWriter tmpOut = Console.Out;
+ TextWriter tmpErr = Console.Error;
+
+ using (swOut = new StringWriter())
+ using (swErr = new StringWriter())
+ try
+ {
+ Console.SetOut(swOut);
+ Console.SetError(swErr);
+ WrapperService.Run(args, descriptor ?? DefaultServiceDescriptor);
+ }
+ catch (Exception ex)
+ {
+ testEx = ex;
+ }
+ finally
+ {
+ Console.SetOut(tmpOut);
+ Console.SetError(tmpErr);
+ Console.WriteLine("\n>>> Output: ");
+ Console.Write(swOut.ToString());
+ Console.WriteLine("\n>>> Error: ");
+ Console.Write(swErr.ToString());
+ if (testEx != null)
+ {
+ Console.WriteLine("\n>>> Exception: ");
+ Console.WriteLine(testEx);
+ }
+ }
+
+ return new CLITestResult(swOut.ToString(), swErr.ToString(), testEx);
+ }
+ }
+
+ ///
+ /// Aggregated test report
+ ///
+ public class CLITestResult
+ {
+ [NotNull]
+ public String Out { get; private set; }
+
+ [NotNull]
+ public String Err { get; private set; }
+
+ [CanBeNull]
+ public Exception Exception { get; private set; }
+
+ public bool HasException { get { return Exception != null; } }
+
+ public CLITestResult(String output, String err, Exception exception = null)
+ {
+ Out = output;
+ Err = err;
+ Exception = exception;
+ }
+ }
+}
diff --git a/src/Test/winswTests/packages.config b/src/Test/winswTests/packages.config
index c29756e..cba033f 100644
--- a/src/Test/winswTests/packages.config
+++ b/src/Test/winswTests/packages.config
@@ -1,4 +1,5 @@
+
\ No newline at end of file
diff --git a/src/Test/winswTests/winswTests.csproj b/src/Test/winswTests/winswTests.csproj
index 507e9d0..83bddf7 100644
--- a/src/Test/winswTests/winswTests.csproj
+++ b/src/Test/winswTests/winswTests.csproj
@@ -37,18 +37,25 @@
prompt
4
-
+
+
+ False
+ ..\..\packages\JetBrains.Annotations.8.0.5.0\lib\net20\JetBrains.Annotations.dll
+
False
..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll
+
+
+
diff --git a/src/winsw.sln b/src/winsw.sln
index c608641..15d09bd 100644
--- a/src/winsw.sln
+++ b/src/winsw.sln
@@ -16,34 +16,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6BDF40
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 = Release|Any CPU
- {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Mixed Platforms.Build.0 = Release|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}.Debug|Win32.Build.0 = Debug|Any CPU
{0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Win32.ActiveCfg = Release|Any CPU
- {93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
- {93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Win32.Build.0 = Release|Any CPU
{93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Win32.ActiveCfg = Debug|Any CPU
- {93843402-842B-44B4-B303-AEE829BE0B43}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {93843402-842B-44B4-B303-AEE829BE0B43}.Release|Any CPU.Build.0 = Release|Any CPU
- {93843402-842B-44B4-B303-AEE829BE0B43}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
- {93843402-842B-44B4-B303-AEE829BE0B43}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Win32.Build.0 = Debug|Any CPU
{93843402-842B-44B4-B303-AEE829BE0B43}.Release|Win32.ActiveCfg = Release|Any CPU
+ {93843402-842B-44B4-B303-AEE829BE0B43}.Release|Win32.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE