Added Unit Tests.

Signed-off-by: Michele Cattafesta <michele.cattafesta@mesta-automation.com>
This commit is contained in:
Michele Cattafesta
2014-12-22 14:31:52 +01:00
parent fc5429b703
commit 73437f9ea3
11 changed files with 2710 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
namespace S7.Net.UnitTest.Helpers
{
[SuppressUnmanagedCodeSecurity]
public static class ConsoleManager
{
public static bool HasConsole
{
get { return NativeMethods.GetConsoleWindow() != IntPtr.Zero; }
}
/// <summary>
/// Creates a new console instance if the process is not attached to a console already.
/// </summary>
public static void Show()
{
//#if DEBUG
if (!HasConsole)
{
NativeMethods.AllocConsole();
InvalidateOutAndError();
}
//#endif
}
/// <summary>
/// If the process has a console attached to it, it will be detached and no longer visible. Writing to the System.Console is still possible, but no output will be shown.
/// </summary>
public static void Hide()
{
//#if DEBUG
if (HasConsole)
{
SetOutAndErrorNull();
NativeMethods.FreeConsole();
}
//#endif
}
public static void Toggle()
{
if (HasConsole)
{
Hide();
}
else
{
Show();
}
}
static void InvalidateOutAndError()
{
Type type = typeof(System.Console);
System.Reflection.FieldInfo _out = type.GetField("_out",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
System.Reflection.FieldInfo _error = type.GetField("_error",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
System.Reflection.MethodInfo _InitializeStdOutError = type.GetMethod("InitializeStdOutError",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
System.Diagnostics.Debug.Assert(_out != null);
System.Diagnostics.Debug.Assert(_error != null);
System.Diagnostics.Debug.Assert(_InitializeStdOutError != null);
_out.SetValue(null, null);
_error.SetValue(null, null);
_InitializeStdOutError.Invoke(null, new object[] { true });
}
static void SetOutAndErrorNull()
{
Console.SetOut(TextWriter.Null);
Console.SetError(TextWriter.Null);
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace S7.Net.UnitTest.Helpers
{
internal static class NativeMethods
{
[StructLayout(LayoutKind.Sequential)]
public struct CURSORINFO
{
public Int32 cbSize;
public Int32 flags;
public IntPtr hCursor;
public POINTAPI ptScreenPos;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINTAPI
{
public int x;
public int y;
}
[DllImport("user32.dll")]
public static extern int BringWindowToTop(IntPtr hwnd);
[DllImport("kernel32.dll")]
public static extern bool AllocConsole();
[DllImport("kernel32.dll")]
public static extern bool FreeConsole();
[DllImport("kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("kernel32.dll")]
public static extern int GetConsoleOutputCP();
[DllImport("user32.dll")]
public static extern bool GetCursorInfo(out CURSORINFO pci);
[DllImport("user32.dll")]
public static extern bool DrawIcon(IntPtr hDC, int X, int Y, IntPtr hIcon);
}
}

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Snap7;
namespace S7.Net.UnitTest.Helpers
{
class S7TestServer
{
static S7Server Server;
static private byte[] DB1 = new byte[512]; // Our DB1
static private byte[] DB2 = new byte[1028]; // Our DB2
static private byte[] DB3 = new byte[1024]; // Our DB3
private static S7Server.TSrvCallback TheEventCallBack; // <== Static var containig the callback
private static S7Server.TSrvCallback TheReadCallBack; // <== Static var containig the callback
// Here we use the callback to show the log, this is not the best choice since
// the callback is synchronous with the client access, i.e. the server cannot
// handle futher request from that client until the callback is complete.
// The right choice is to use the log queue via the method PickEvent.
static void EventCallback(IntPtr usrPtr, ref S7Server.USrvEvent Event, int Size)
{
Console.WriteLine(Server.EventText(ref Event));
}
static void ReadEventCallback(IntPtr usrPtr, ref S7Server.USrvEvent Event, int Size)
{
Console.WriteLine(Server.EventText(ref Event));
}
public static void Start()
{
Server = new S7Server();
// Share some resources with our virtual PLC
Server.RegisterArea(S7Server.srvAreaDB, // We are registering a DB
1, // Its number is 1 (DB1)
DB1, // Our buffer for DB1
DB1.Length); // Its size
// Do the same for DB2 and DB3
Server.RegisterArea(S7Server.srvAreaDB, 2, DB2, DB2.Length);
Server.RegisterArea(S7Server.srvAreaDB, 3, DB3, DB3.Length);
// Exclude read event to avoid the double report
// Set the callbacks (using the static var to avoid the garbage collect)
TheEventCallBack = new S7Server.TSrvCallback(EventCallback);
TheReadCallBack = new S7Server.TSrvCallback(ReadEventCallback);
Server.EventMask = ~S7Server.evcDataRead;
Server.SetEventsCallBack(TheEventCallBack, IntPtr.Zero);
Server.SetReadEventsCallBack(TheReadCallBack, IntPtr.Zero);
// Uncomment next line if you don't want to see wrapped messages
// (Note : Doesn't work in Mono 2.10)
// Console.SetBufferSize(100, Int16.MaxValue - 1);
// Start the server onto the default adapter.
// To select an adapter we have to use Server->StartTo("192.168.x.y").
// Start() is the same of StartTo("0.0.0.0");
int Error = Server.Start();
//if (Error == 0)
//{
// // Now the server is running ... wait a key to terminate
// //Console.ReadKey();
// Server.Stop();
//}
//else
// Console.WriteLine(Server.ErrorText(Error));
// If you got a start error:
// Windows - most likely you ar running the server in a pc on wich is
// installed step 7 : open a command prompt and type
// "net stop s7oiehsx" (Win32) or
// "net stop s7oiehsx64" (Win64)
// And after this test :
// "net start s7oiehsx" (Win32) or
// "net start s7oiehsx64" (Win64)
// Unix - you need root rights :-( because the isotcp port (102) is
// low and so it's considered "privileged".
}
public static void Stop()
{
int Error = Server.Stop();
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace S7.Net.UnitTest.Helpers
{
class TestClass
{
/// <summary>
/// DB1.DBX0.0
/// </summary>
public bool BitVariable00 { get; set; }
public bool BitVariable01 { get; set; }
public bool BitVariable02 { get; set; }
public bool BitVariable03 { get; set; }
public bool BitVariable04 { get; set; }
public bool BitVariable05 { get; set; }
public bool BitVariable06 { get; set; }
public bool BitVariable07 { get; set; }
/// <summary>
/// DB1.DBX1.0
/// </summary>
public bool BitVariable10 { get; set; }
public bool BitVariable11 { get; set; }
public bool BitVariable12 { get; set; }
public bool BitVariable13 { get; set; }
public bool BitVariable14 { get; set; }
public bool BitVariable15 { get; set; }
public bool BitVariable16 { get; set; }
public bool BitVariable17 { get; set; }
/// <summary>
/// DB1.DBW2
/// </summary>
public short IntVariable { get; set; }
/// <summary>
/// DB1.DBD4
/// </summary>
public double RealVariable { get; set; }
/// <summary>
/// DB1.DBD8
/// </summary>
public int DIntVariable { get; set; }
/// <summary>
/// DB1.DBD12
/// </summary>
public ushort DWordVariable { get; set; }
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace S7.Net.UnitTest.Helpers
{
public struct TestStruct
{
/// <summary>
/// DB1.DBX0.0
/// </summary>
public bool BitVariable00;
public bool BitVariable01;
public bool BitVariable02;
public bool BitVariable03;
public bool BitVariable04;
public bool BitVariable05;
public bool BitVariable06;
public bool BitVariable07;
/// <summary>
/// DB1.DBX1.0
/// </summary>
public bool BitVariable10;
public bool BitVariable11;
public bool BitVariable12;
public bool BitVariable13;
public bool BitVariable14;
public bool BitVariable15;
public bool BitVariable16;
public bool BitVariable17;
/// <summary>
/// DB1.DBW2
/// </summary>
public short IntVariable;
/// <summary>
/// DB1.DBD4
/// </summary>
public double RealVariable;
/// <summary>
/// DB1.DBD8
/// </summary>
public int DIntVariable;
/// <summary>
/// DB1.DBD12
/// </summary>
public ushort DWordVariable;
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("S7.Net.UnitTest")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("S7Net.UnitTest")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[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("6f73e1b1-301b-471e-9f38-3dcbddbcfc21")]
// 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 File

@@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{303CCED6-9ABC-4899-A509-743341AAA804}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>S7.UnitTest</RootNamespace>
<AssemblyName>S7Net.UnitTest</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
</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>
</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>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="Helpers\ConsoleManager.cs" />
<Compile Include="Helpers\NativeMethods.cs" />
<Compile Include="Helpers\S7TestServer.cs" />
<Compile Include="Snap7\snap7.net.cs" />
<Compile Include="Helpers\TestClass.cs" />
<Compile Include="Helpers\TestStruct.cs" />
<Compile Include="S7NetTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="snap7.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\S7.Net\S7.Net.csproj">
<Project>{bfd484f9-3f04-42a2-bf2a-60a189a25dcf}</Project>
<Name>S7.Net</Name>
</ProjectReference>
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<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 File

@@ -0,0 +1,207 @@
#region Using
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using S7.Net;
using S7.Net.UnitTest.Helpers;
using S7.Net.UnitTest;
using System.ServiceProcess;
#endregion
/**
* About the tests:
* ---------------------------------------------------------------------------
* The tests were written to show how to use this library to read and write
* different types of values, how to box and unbox values and of course to
* address some of the bugs of the library.
* These tests are not meant to cover 100% the code, but to check that once a
* variable is written, it stores the correct value.
* ----------------------------------------------------------------------------
* The plc used for the tests is the S7 "server" provided by Snap7 opensource
* library, that you can get for free here:http://snap7.sourceforge.net/
* The implementation of the server will not be discussed here, but there are
* some issues with the interop that cause the server, and unit test, to fail
* under some circumstances, like "click on Run all tests" too much.
* This doesn't mean that S7.Net has bugs, but that the implementation of the
* server has problems.
*
*/
namespace S7.Net.UnitTest
{
[TestClass]
public class S7NetTests
{
#region Constants
const int DB2 = 2;
#endregion
#region Private fields
Plc plc;
#endregion
#region Constructor
/// <summary>
/// Create a plc that will connect to localhost (Snap 7 server) and connect to it
/// </summary>
public S7NetTests()
{
plc = new Plc(CpuType.S7300, "127.0.0.1", 0, 2);
//ConsoleManager.Show();
ShutDownServiceS7oiehsx64();
S7TestServer.Start();
plc.Open();
}
#endregion
#region Tests
[TestMethod]
public void T00_TestConnection()
{
if (plc.IsConnected == false)
{
var error = plc.Open();
Assert.AreEqual(ErrorCode.NoError, error, "If you have s7 installed you must close s7oiehsx64 service.");
}
}
/// <summary>
/// Read/Write a single Int16 or UInt16 with a single request.
/// Test that writing a UInt16 (ushort) and reading it gives the correct value.
/// Test also that writing a Int16 (short) and reading it gives the correct value.
/// </summary>
[TestMethod]
public void T01_WriteAndReadInt16Variable()
{
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
// To write a ushort i don't need any cast, only unboxing must be done
ushort val = 40000;
plc.Write("DB1.DBW0", val);
ushort result = (ushort)plc.Read("DB1.DBW0");
Assert.AreEqual(val, result, "A ushort goes from 0 to 64512");
// To write a short i need to convert it to UShort, then i need to reconvert the readed value to get
// the negative sign back
// Depending if i'm writing on a DWORD or on a DEC, i will see ushort or short value in the plc
short value = -100;
Assert.IsTrue(plc.IsConnected, "After connecting, IsConnected must be set to true");
plc.Write("DB1.DBW0", value.ConvertToUshort());
short result2 = ((ushort)plc.Read("DB1.DBW0")).ConvertToShort();
Assert.AreEqual(value, result2, "A short goes from -32767 to 32766");
}
/// <summary>
/// Read/Write a single Int32 or UInt32 with a single request.
/// Test that writing a UInt32 (uint) and reading it gives the correct value.
/// Test also that writing a Int32 (int) and reading it gives the correct value.
/// </summary>
[TestMethod]
public void T02_WriteAndReadInt32Variable()
{
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
// To write a uint I don't need any cast, only unboxing must be done
uint val = 1000;
plc.Write("DB1.DBD40", val);
uint result = (uint)plc.Read("DB1.DBD40");
Assert.AreEqual(val, result);
// To write a int I need to convert it to uint, then I need to reconvert the readed value to get
// the negative sign back
// Depending if I'm writing on a DBD or on a LONG, I will see uint or int value in the plc
int value = -60000;
plc.Write("DB1.DBD60", value);
int result2 = ((uint)plc.Read("DB1.DBD60")).ConvertToInt();
Assert.AreEqual(value, result2);
}
/// <summary>
/// Read/Write a single REAL with a single request.
/// Test that writing a double and reading it gives the correct value.
/// </summary>
[TestMethod]
public void T03_WriteAndReadRealVariables()
{
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
// Reading and writing a double is quite complicated, because it needs to be converted to DWord before the write,
// then reconvert to double after the read.
double val = 35.687;
plc.Write("DB1.DBD40", val.ConvertToUInt());
double result = ((uint)plc.Read("DB1.DBD40")).ConvertToDouble();
Assert.AreEqual(val, Math.Round(result, 3)); // float lose precision, so i need to round it
}
/// <summary>
/// Read/Write a class that has the same properties of a DB with the same field in the same order
/// </summary>
[TestMethod]
public void T04_ReadAndWriteClass()
{
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
TestClass tc = new TestClass();
tc.BitVariable00 = true;
tc.BitVariable10 = true;
tc.DIntVariable = -100000;
tc.IntVariable = -15000;
tc.RealVariable = -154.789;
tc.DWordVariable = 850;
plc.WriteClass(tc, DB2);
TestClass tc2 = new TestClass();
// Values that are read from a class are stored inside the class itself, that is passed by reference
plc.ReadClass(tc2, DB2);
Assert.AreEqual(tc.BitVariable00, tc2.BitVariable00);
Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10);
Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable);
Assert.AreEqual(tc.IntVariable, tc2.IntVariable);
Assert.AreEqual(tc.RealVariable, Math.Round(tc2.RealVariable, 3));
Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable);
}
/// <summary>
/// Read/Write a struct that has the same properties of a DB with the same field in the same order
/// </summary>
[TestMethod]
public void T05_ReadAndWriteStruct()
{
Assert.IsTrue(plc.IsConnected, "Before executing this test, the plc must be connected. Check constructor.");
TestStruct tc = new TestStruct();
tc.BitVariable00 = true;
tc.BitVariable10 = true;
tc.DIntVariable = -100000;
tc.IntVariable = -15000;
tc.RealVariable = -154.789;
tc.DWordVariable = 850;
plc.WriteStruct(tc, DB2);
// Values that are read from a struct are stored in a new struct, returned by the funcion ReadStruct
TestStruct tc2 = (TestStruct)plc.ReadStruct(typeof(TestStruct), DB2);
Assert.AreEqual(tc.BitVariable00, tc2.BitVariable00);
Assert.AreEqual(tc.BitVariable10, tc2.BitVariable10);
Assert.AreEqual(tc.DIntVariable, tc2.DIntVariable);
Assert.AreEqual(tc.IntVariable, tc2.IntVariable);
Assert.AreEqual(tc.RealVariable, Math.Round(tc2.RealVariable, 3));
Assert.AreEqual(tc.DWordVariable, tc2.DWordVariable);
}
#endregion
#region Private methods
private static void ShutDownServiceS7oiehsx64()
{
ServiceController sc = new ServiceController("s7oiehsx64");
switch (sc.Status)
{
case ServiceControllerStatus.Running:
sc.Stop();
break;
}
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

BIN
S7.Net.UnitTest/snap7.dll Normal file

Binary file not shown.

6
S7.sln
View File

@@ -8,6 +8,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "S7.Net.UnitTest", "S7.Net.UnitTest\S7.Net.UnitTest.csproj", "{303CCED6-9ABC-4899-A509-743341AAA804}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -18,6 +20,10 @@ Global
{BFD484F9-3F04-42A2-BF2A-60A189A25DCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BFD484F9-3F04-42A2-BF2A-60A189A25DCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BFD484F9-3F04-42A2-BF2A-60A189A25DCF}.Release|Any CPU.Build.0 = Release|Any CPU
{303CCED6-9ABC-4899-A509-743341AAA804}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{303CCED6-9ABC-4899-A509-743341AAA804}.Debug|Any CPU.Build.0 = Debug|Any CPU
{303CCED6-9ABC-4899-A509-743341AAA804}.Release|Any CPU.ActiveCfg = Release|Any CPU
{303CCED6-9ABC-4899-A509-743341AAA804}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE