From 85ea1738dcdf7baa73ac741f5e6019c2a825469a Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Sat, 3 Feb 2024 20:20:00 -0800 Subject: [PATCH] Port RandRect, Bezier, and Blokout2 samples from WInterop --- src/samples/Petzold/5th/Bezier/Bezier.csproj | 10 ++ src/samples/Petzold/5th/Bezier/Program.cs | 97 ++++++++++++++ .../Petzold/5th/Blokout2/Blokout2.csproj | 10 ++ src/samples/Petzold/5th/Blokout2/Program.cs | 98 ++++++++++++++ src/samples/Petzold/5th/RandRect/Program.cs | 121 ++++++++++++++++++ .../Petzold/5th/RandRect/RandRect.csproj | 10 ++ src/thirtytwo/DeviceContextExtensions.cs | 28 ++++ src/thirtytwo/NativeMethods.txt | 23 ++-- .../Win32/UI/WindowsAndMessaging/HCURSOR.cs | 1 + src/thirtytwo/WrapperEnums/PenMixMode.cs | 93 ++++++++++++++ .../WrapperEnums/WrapperEnumExtensions.cs | 1 + thirtytwo.sln | 21 +++ 12 files changed, 504 insertions(+), 9 deletions(-) create mode 100644 src/samples/Petzold/5th/Bezier/Bezier.csproj create mode 100644 src/samples/Petzold/5th/Bezier/Program.cs create mode 100644 src/samples/Petzold/5th/Blokout2/Blokout2.csproj create mode 100644 src/samples/Petzold/5th/Blokout2/Program.cs create mode 100644 src/samples/Petzold/5th/RandRect/Program.cs create mode 100644 src/samples/Petzold/5th/RandRect/RandRect.csproj create mode 100644 src/thirtytwo/WrapperEnums/PenMixMode.cs diff --git a/src/samples/Petzold/5th/Bezier/Bezier.csproj b/src/samples/Petzold/5th/Bezier/Bezier.csproj new file mode 100644 index 0000000..265b404 --- /dev/null +++ b/src/samples/Petzold/5th/Bezier/Bezier.csproj @@ -0,0 +1,10 @@ + + + + WinExe + True + + + + + \ No newline at end of file diff --git a/src/samples/Petzold/5th/Bezier/Program.cs b/src/samples/Petzold/5th/Bezier/Program.cs new file mode 100644 index 0000000..176f0d0 --- /dev/null +++ b/src/samples/Petzold/5th/Bezier/Program.cs @@ -0,0 +1,97 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Drawing; +using Windows; +using Windows.Win32.Foundation; + +namespace Bezier; + +/// +/// Sample from Programming Windows, 5th Edition. +/// Original (c) Charles Petzold, 1998 +/// Figure 5-16, Pages 156-159. +/// +internal static class Program +{ + [STAThread] + private static void Main() => Application.Run(new Bezier("Bezier Splines")); +} + +internal class Bezier : MainWindow +{ + private readonly Point[] _apt = new Point[4]; + + public Bezier(string title) : base(title) + { + } + + protected override LRESULT WindowProcedure(HWND window, MessageType message, WPARAM wParam, LPARAM lParam) + { + switch (message) + { + case MessageType.Size: + int cxClient = lParam.LOWORD; + int cyClient = lParam.HIWORD; + + _apt[0].X = cxClient / 4; + _apt[0].Y = cyClient / 2; + _apt[1].X = cxClient / 2; + _apt[1].Y = cyClient / 4; + _apt[2].X = cxClient / 2; + _apt[2].Y = 3 * cyClient / 4; + _apt[3].X = 3 * cxClient / 4; + _apt[3].Y = cyClient / 2; + + return (LRESULT)0; + + case MessageType.LeftButtonDown: + case MessageType.RightButtonDown: + case MessageType.MouseMove: + MouseKey mk = (MouseKey)wParam.LOWORD; + if ((mk & (MouseKey.LeftButton | MouseKey.RightButton)) != 0) + { + using DeviceContext dc = window.GetDeviceContext(); + dc.SelectObject(StockPen.White); + DrawBezier(dc, _apt); + + if ((mk & MouseKey.LeftButton) != 0) + { + _apt[1].X = lParam.LOWORD; + _apt[1].Y = lParam.HIWORD; + } + + if ((mk & MouseKey.RightButton) != 0) + { + _apt[2].X = lParam.LOWORD; + _apt[2].Y = lParam.HIWORD; + } + + dc.SelectObject(StockPen.Black); + DrawBezier(dc, _apt); + } + + return (LRESULT)0; + + case MessageType.Paint: + window.Invalidate(true); + using (DeviceContext dc = window.BeginPaint()) + { + DrawBezier(dc, _apt); + } + + return (LRESULT)0; + } + + static void DrawBezier(DeviceContext dc, Point[] apt) + { + dc.PolyBezier(apt); + dc.MoveTo(apt[0]); + dc.LineTo(apt[1]); + dc.MoveTo(apt[2]); + dc.LineTo(apt[3]); + } + + return base.WindowProcedure(window, message, wParam, lParam); + } +} diff --git a/src/samples/Petzold/5th/Blokout2/Blokout2.csproj b/src/samples/Petzold/5th/Blokout2/Blokout2.csproj new file mode 100644 index 0000000..265b404 --- /dev/null +++ b/src/samples/Petzold/5th/Blokout2/Blokout2.csproj @@ -0,0 +1,10 @@ + + + + WinExe + True + + + + + \ No newline at end of file diff --git a/src/samples/Petzold/5th/Blokout2/Program.cs b/src/samples/Petzold/5th/Blokout2/Program.cs new file mode 100644 index 0000000..6b7bb6e --- /dev/null +++ b/src/samples/Petzold/5th/Blokout2/Program.cs @@ -0,0 +1,98 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Drawing; +using Windows; +using Windows.Win32; +using Windows.Win32.Foundation; + +namespace Blokout2; + +/// +/// Sample from Programming Windows, 5th Edition. +/// Original (c) Charles Petzold, 1998 +/// Figure 7-11, Pages 314-317. +/// +internal static class Program +{ + [STAThread] + private static void Main() => Application.Run(new Blockout2("Mouse Button & Capture Demo")); +} + +internal class Blockout2 : MainWindow +{ + private bool _fBlocking, _fValidBox; + private Point _ptBeg, _ptEnd, _ptBoxBeg, _ptBoxEnd; + + public Blockout2(string title) : base(title) + { + } + + protected override LRESULT WindowProcedure(HWND window, MessageType message, WPARAM wParam, LPARAM lParam) + { + switch (message) + { + case MessageType.LeftButtonDown: + _ptBeg.X = _ptEnd.X = lParam.LOWORD; + _ptBeg.Y = _ptEnd.Y = lParam.HIWORD; + DrawBoxOutline(window, _ptBeg, _ptEnd); + Interop.SetCapture(window); + CursorId.Cross.SetCursor(); + _fBlocking = true; + return (LRESULT)0; + case MessageType.MouseMove: + if (_fBlocking) + { + CursorId.Cross.SetCursor(); + DrawBoxOutline(window, _ptBeg, _ptEnd); + _ptEnd.X = lParam.LOWORD; + _ptEnd.Y = lParam.HIWORD; + DrawBoxOutline(window, _ptBeg, _ptEnd); + } + + return (LRESULT)0; + case MessageType.LeftButtonUp: + if (_fBlocking) + { + DrawBoxOutline(window, _ptBeg, _ptEnd); + _ptBoxBeg = _ptBeg; + _ptBoxEnd.X = lParam.LOWORD; + _ptBoxEnd.Y = lParam.HIWORD; + Interop.ReleaseCapture(); + CursorId.Arrow.SetCursor(); + _fBlocking = false; + _fValidBox = true; + window.Invalidate(true); + } + + return (LRESULT)0; + case MessageType.Paint: + using (DeviceContext dc = window.BeginPaint()) + { + if (_fValidBox) + { + dc.SelectObject(StockBrush.Black); + dc.Rectangle(_ptBoxBeg.X, _ptBoxBeg.Y, _ptBoxEnd.X, _ptBoxEnd.Y); + } + if (_fBlocking) + { + dc.SetRasterOperation(PenMixMode.Not); + dc.SelectObject(StockBrush.Null); + dc.Rectangle(_ptBeg.X, _ptBeg.Y, _ptEnd.X, _ptEnd.Y); + } + } + + return (LRESULT)0; + } + + static void DrawBoxOutline(HWND window, Point ptBeg, Point ptEnd) + { + using DeviceContext dc = window.GetDeviceContext(); + dc.SetRasterOperation(PenMixMode.Not); + dc.SelectObject(StockBrush.Null); + dc.Rectangle(Rectangle.FromLTRB(ptBeg.X, ptBeg.Y, ptEnd.X, ptEnd.Y)); + } + + return base.WindowProcedure(window, message, wParam, lParam); + } +} diff --git a/src/samples/Petzold/5th/RandRect/Program.cs b/src/samples/Petzold/5th/RandRect/Program.cs new file mode 100644 index 0000000..10a9e8e --- /dev/null +++ b/src/samples/Petzold/5th/RandRect/Program.cs @@ -0,0 +1,121 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Drawing; +using System.Runtime.InteropServices; +using Windows; +using Windows.Win32; +using Windows.Win32.Foundation; +using Windows.Win32.Graphics.Gdi; +using Windows.Win32.UI.WindowsAndMessaging; + +namespace RandRect; + +/// +/// Sample from Programming Windows, 5th Edition. +/// Original (c) Charles Petzold, 1998 +/// Figure 5-26, Pages 200-202. +/// +internal unsafe static class Program +{ + [STAThread] + private static void Main() + { + const string szAppName = "RandRect"; + + WindowProcedure wndProc = WindowProcedure; + HMODULE module; + Interop.GetModuleHandleEx(0, (PCWSTR)null, &module); + + HWND hwnd; + + fixed (char* appName = szAppName) + fixed (char* title = "Random Rectangles") + { + WNDCLASSEXW wndClass = new() + { + cbSize = (uint)sizeof(WNDCLASSEXW), + style = WNDCLASS_STYLES.CS_HREDRAW | WNDCLASS_STYLES.CS_VREDRAW, + lpfnWndProc = (WNDPROC)Marshal.GetFunctionPointerForDelegate(wndProc), + hInstance = module, + hIcon = Interop.LoadIcon(default, Interop.IDI_APPLICATION), + hCursor = Interop.LoadCursor(default, Interop.IDC_ARROW), + hbrBackground = (HBRUSH)Interop.GetStockObject(GET_STOCK_OBJECT_FLAGS.WHITE_BRUSH), + lpszClassName = appName + }; + + ATOM atom = Interop.RegisterClassEx(&wndClass); + + hwnd = Interop.CreateWindowEx( + WINDOW_EX_STYLE.WS_EX_OVERLAPPEDWINDOW, + appName, + title, + WINDOW_STYLE.WS_OVERLAPPEDWINDOW, + Interop.CW_USEDEFAULT, Interop.CW_USEDEFAULT, Interop.CW_USEDEFAULT, Interop.CW_USEDEFAULT, + HWND.Null, + HMENU.Null, + module, + null); + + + } + + Interop.ShowWindow(hwnd, SHOW_WINDOW_CMD.SW_SHOWDEFAULT); + Interop.UpdateWindow(hwnd); + + while (true) + { + if (Interop.PeekMessage(out MSG message, HWND.Null, 0, uint.MaxValue, PEEK_MESSAGE_REMOVE_TYPE.PM_REMOVE)) + { + if (message.message == Interop.WM_QUIT) + { + break; + } + + Interop.TranslateMessage(message); + Interop.DispatchMessage(message); + } + + // We're crazy fast over 25 years past the source sample, + // sleeping to make this a bit more interesting. + Thread.Sleep(100); + DrawRectangle(hwnd); + } + } + + private static int s_cxClient, s_cyClient; + private static readonly Random s_rand = new(); + + private static LRESULT WindowProcedure(HWND window, uint message, WPARAM wParam, LPARAM lParam) + { + switch ((MessageType)message) + { + case MessageType.Size: + s_cxClient = lParam.LOWORD; + s_cyClient = lParam.HIWORD; + return (LRESULT)0; + case MessageType.Destroy: + Interop.PostQuitMessage(0); + return (LRESULT)0; + } + + return Interop.DefWindowProc(window, message, wParam, lParam); + } + + private static void DrawRectangle(HWND window) + { + if (s_cxClient == 0 || s_cyClient == 0) + return; + + Rectangle rect = Rectangle.FromLTRB( + s_rand.Next() % s_cxClient, + s_rand.Next() % s_cyClient, + s_rand.Next() % s_cxClient, + s_rand.Next() % s_cyClient); + + using HBRUSH brush = HBRUSH.CreateSolid( + Color.FromArgb((byte)(s_rand.Next() % 256), (byte)(s_rand.Next() % 256), (byte)(s_rand.Next() % 256))); + using DeviceContext dc = window.GetDeviceContext(); + dc.FillRectangle(rect, brush); + } +} diff --git a/src/samples/Petzold/5th/RandRect/RandRect.csproj b/src/samples/Petzold/5th/RandRect/RandRect.csproj new file mode 100644 index 0000000..265b404 --- /dev/null +++ b/src/samples/Petzold/5th/RandRect/RandRect.csproj @@ -0,0 +1,10 @@ + + + + WinExe + True + + + + + \ No newline at end of file diff --git a/src/thirtytwo/DeviceContextExtensions.cs b/src/thirtytwo/DeviceContextExtensions.cs index d2bad6d..c6db3a5 100644 --- a/src/thirtytwo/DeviceContextExtensions.cs +++ b/src/thirtytwo/DeviceContextExtensions.cs @@ -306,6 +306,19 @@ public static bool Ellipse(this T context, int left, int top, int right, int return success; } + public static unsafe bool PolyBezier(this T context, params Point[] points) where T : IHandle => + PolyBezier(context, points.AsSpan()); + + public static unsafe bool PolyBezier(this T context, ReadOnlySpan points) where T : IHandle + { + fixed (Point* p = points) + { + bool success = Interop.PolyBezier(context.Handle, p, (uint)points.Length); + GC.KeepAlive(context.Wrapper); + return success; + } + } + public static bool FillRectangle(this T context, Rectangle rectangle, HBRUSH hbrush) where T : IHandle { @@ -314,4 +327,19 @@ public static bool FillRectangle(this T context, Rectangle rectangle, HBRUSH GC.KeepAlive(context.Wrapper); return success; } + + public static PenMixMode SetRasterOperation(this T context, PenMixMode foregroundMixMode) + where T : IHandle + { + PenMixMode result = (PenMixMode)Interop.SetROP2(context.Handle, (R2_MODE)foregroundMixMode); + GC.KeepAlive(context.Wrapper); + return result; + } + + public static PenMixMode GetRasterOperation(this T context) where T : IHandle + { + PenMixMode result = (PenMixMode)Interop.GetROP2(context.Handle); + GC.KeepAlive(context.Wrapper); + return result; + } } \ No newline at end of file diff --git a/src/thirtytwo/NativeMethods.txt b/src/thirtytwo/NativeMethods.txt index 6f8b5d9..935a7e3 100644 --- a/src/thirtytwo/NativeMethods.txt +++ b/src/thirtytwo/NativeMethods.txt @@ -32,6 +32,7 @@ CreateErrorInfo CreateFont CreateFontIndirect CreateRectRgn +CreateSolidBrush CreateStdAccessibleObject CreateStdAccessibleProxy CreateStdDispatch @@ -64,6 +65,7 @@ E_INVALIDARG E_NOINTERFACE E_NOTIMPL E_POINTER +Ellipse EM_* EmptyClipboard EnableWindow @@ -84,6 +86,7 @@ FONT_PITCH FONT_QUALITY FONT_WEIGHT FormatMessage +FrameRect FVE_E_LOCKED_VOLUME GET_MODULE_HANDLE_EX_FLAG* GET_STOCK_OBJECT_FLAGS @@ -115,6 +118,7 @@ GetParent GetProcAddress GetProcessDpiAwareness GetRgnBox +GetROP2 GetStockObject GetSysColorBrush GetThreadDpiAwarenessContext @@ -188,6 +192,7 @@ IUnknown KEY_INFORMATION_CLASS KEY_NAME_INFORMATION KF_* +KillTimer LIBFLAGS LineTo LoadCursor @@ -200,6 +205,7 @@ LPtoDP LsaNtStatusToWinError MapWindowPoints MEMBERID_NIL +MessageBeep MessageBoxEx METHODDATA MODIFIERKEYS_FLAGS @@ -220,11 +226,13 @@ PARAMDATA PeekMessage PlaySound POINTS +PolyBezier Polygon PostMessage PostQuitMessage PROPVARIANT PropVariantClear +Rectangle RegCloseKey RegEnumValue RegisterClassEx @@ -232,9 +240,11 @@ RegisterClipboardFormat RegOpenKeyEx RegQueryInfoKey RegQueryValueEx +ReleaseCapture ReleaseDC RemoveClipboardFormatListener ROLE_SYSTEM_* +RoundRect S_FALSE S_OK SAFEARRAY @@ -248,13 +258,16 @@ SelectObject SELFLAG_* SendMessage SetActiveWindow +SetCapture SetClipboardData +SetCoalescableTimer SetCursor SetFocus SetGraphicsMode SetLayeredWindowAttributes SetMapMode SetPolyFillMode +SetROP2 SetThreadDpiAwarenessContext SetViewportOrgEx SetWindowLong @@ -300,12 +313,4 @@ VIRTUAL_KEY WIN32_ERROR WINDOWPOS WM_* -XFORMCOORDS -FrameRect -Rectangle -Ellipse -RoundRect -MessageBeep -CreateSolidBrush -SetCoalescableTimer -KillTimer \ No newline at end of file +XFORMCOORDS \ No newline at end of file diff --git a/src/thirtytwo/Win32/UI/WindowsAndMessaging/HCURSOR.cs b/src/thirtytwo/Win32/UI/WindowsAndMessaging/HCURSOR.cs index b5cc8ff..80eeea1 100644 --- a/src/thirtytwo/Win32/UI/WindowsAndMessaging/HCURSOR.cs +++ b/src/thirtytwo/Win32/UI/WindowsAndMessaging/HCURSOR.cs @@ -12,6 +12,7 @@ public unsafe partial struct HCURSOR : IDisposable public static implicit operator HCURSOR(CursorId id) => Interop.LoadCursor(default, (PCWSTR)(char*)(uint)id); public SetScope SetCursorScope() => new(this); + public HCURSOR SetCursor() => Interop.SetCursor(this); public void Dispose() { diff --git a/src/thirtytwo/WrapperEnums/PenMixMode.cs b/src/thirtytwo/WrapperEnums/PenMixMode.cs new file mode 100644 index 0000000..c45ab70 --- /dev/null +++ b/src/thirtytwo/WrapperEnums/PenMixMode.cs @@ -0,0 +1,93 @@ +// Copyright (c) Jeremy W. Kuhne. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Windows; + +/// +/// Pen pixel mix modes (ROP2) +/// +public enum PenMixMode : int +{ + // https://learn.microsoft.com/openspecs/windows_protocols/ms-mnpr/1f681fd4-8379-4312-8bf9-138e69f4f12b + // https://learn.microsoft.com/windows/win32/gdi/binary-raster-operations?redirectedfrom=MSDN + + /// + /// Pixel is always drawn black. [R2_BLACK] + /// + Black = R2_MODE.R2_BLACK, + + /// + /// Inverse of result of MergePen. [R2_NOTMERGEPEN] + /// + NotMergePen = R2_MODE.R2_NOTMERGEPEN, + + /// + /// The pixel is a combination of the colors that are common to both the screen and the inverse of the pen. [R2_MASKNOTPEN] + /// + MaskNotPen = R2_MODE.R2_MASKNOTPEN, + + /// + /// The pixel is the inverse of the pen color. [R2_NOTCOPYPEN] + /// + NotCopyPen = R2_MODE.R2_NOTCOPYPEN, + + /// + /// The pixel is a combination of the colors that are common to both the pen and the inverse of the screen. [R2_MASKPENNOT] + /// + MaskPenNot = R2_MODE.R2_MASKPENNOT, + + /// + /// The pixel is the inverse of the screen color. [R2_NOT] + /// + Not = R2_MODE.R2_NOT, + + /// + /// The pixel is a combination of the colors in the pen and in the screen, but not in both. [R2_XORPEN] + /// + XOrPen = R2_MODE.R2_XORPEN, + + /// + /// Inverse of the result of MaskPen. [R2_NOTMASKPEN] + /// + NotMaskPen = R2_MODE.R2_NOTMASKPEN, + + /// + /// The pixel is a combination of the colors that are common to both the pen and the screen. [R2_MASKPEN] + /// + MaskPen = R2_MODE.R2_MASKPEN, + + /// + /// Inverse of the result of XOrPen. [R2_NOTXORPEN] + /// + NotXOrPen = R2_MODE.R2_NOTXORPEN, + + /// + /// The pixel remains unchanged. [R2_NOP] + /// + Nop = R2_MODE.R2_NOP, + + /// + /// The pixel is a combination of the screen color and the inverse of the pen color. [R2_MERGENOTPEN] + /// + MergeNotPen = R2_MODE.R2_MERGENOTPEN, + + /// + /// The pixel always has the color of the pen. [R2_COPYPEN] + /// + CopyPen = R2_MODE.R2_COPYPEN, + + /// + /// The pixel is a combination of the pen color and the inverse of the screen color. [R2_MERGEPENNOT] + /// + MergePenNot = R2_MODE.R2_MERGEPENNOT, + + /// + /// The pixel is a combination of the pen color and the screen color. [R2_MERGEPEN] + /// + MergePen = R2_MODE.R2_MERGEPEN, + + /// + /// The pixel is always drawn as white. [R2_WHITE] + /// + White = R2_MODE.R2_WHITE +} \ No newline at end of file diff --git a/src/thirtytwo/WrapperEnums/WrapperEnumExtensions.cs b/src/thirtytwo/WrapperEnums/WrapperEnumExtensions.cs index 237c48e..5f9aabd 100644 --- a/src/thirtytwo/WrapperEnums/WrapperEnumExtensions.cs +++ b/src/thirtytwo/WrapperEnums/WrapperEnumExtensions.cs @@ -6,4 +6,5 @@ namespace Windows; public static class WrapperEnumExtensions { public static HCURSOR.SetScope SetCursorScope(this CursorId cursor) => ((HCURSOR)cursor).SetCursorScope(); + public static HCURSOR SetCursor(this CursorId cursor) => ((HCURSOR)cursor).SetCursor(); } \ No newline at end of file diff --git a/thirtytwo.sln b/thirtytwo.sln index d89f076..4dc4f72 100644 --- a/thirtytwo.sln +++ b/thirtytwo.sln @@ -43,6 +43,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LineDemo", "src\samples\Pet EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Beeper", "src\samples\Petzold\5th\Beeper\Beeper.csproj", "{8AD31AA4-0997-4338-93EF-691E948F7FA8}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RandRect", "src\samples\Petzold\5th\RandRect\RandRect.csproj", "{1EABEAF9-CEE7-4415-98B9-466982727848}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bezier", "src\samples\Petzold\5th\Bezier\Bezier.csproj", "{751D8704-4AF9-46E4-AD24-B43DD011ED11}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blokout2", "src\samples\Petzold\5th\Blokout2\Blokout2.csproj", "{F52C0159-AFFE-431D-BC46-1AA6C8381400}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -101,6 +107,18 @@ Global {8AD31AA4-0997-4338-93EF-691E948F7FA8}.Debug|x64.Build.0 = Debug|x64 {8AD31AA4-0997-4338-93EF-691E948F7FA8}.Release|x64.ActiveCfg = Release|x64 {8AD31AA4-0997-4338-93EF-691E948F7FA8}.Release|x64.Build.0 = Release|x64 + {1EABEAF9-CEE7-4415-98B9-466982727848}.Debug|x64.ActiveCfg = Debug|x64 + {1EABEAF9-CEE7-4415-98B9-466982727848}.Debug|x64.Build.0 = Debug|x64 + {1EABEAF9-CEE7-4415-98B9-466982727848}.Release|x64.ActiveCfg = Release|x64 + {1EABEAF9-CEE7-4415-98B9-466982727848}.Release|x64.Build.0 = Release|x64 + {751D8704-4AF9-46E4-AD24-B43DD011ED11}.Debug|x64.ActiveCfg = Debug|x64 + {751D8704-4AF9-46E4-AD24-B43DD011ED11}.Debug|x64.Build.0 = Debug|x64 + {751D8704-4AF9-46E4-AD24-B43DD011ED11}.Release|x64.ActiveCfg = Release|x64 + {751D8704-4AF9-46E4-AD24-B43DD011ED11}.Release|x64.Build.0 = Release|x64 + {F52C0159-AFFE-431D-BC46-1AA6C8381400}.Debug|x64.ActiveCfg = Debug|x64 + {F52C0159-AFFE-431D-BC46-1AA6C8381400}.Debug|x64.Build.0 = Debug|x64 + {F52C0159-AFFE-431D-BC46-1AA6C8381400}.Release|x64.ActiveCfg = Release|x64 + {F52C0159-AFFE-431D-BC46-1AA6C8381400}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -118,6 +136,9 @@ Global {FE627283-6848-44D9-B17D-F483625ED43F} = {13110246-EBE1-441B-B721-B0614D62B13B} {A2B09DA8-98E7-42FE-95EF-DF43258AEF4C} = {13110246-EBE1-441B-B721-B0614D62B13B} {8AD31AA4-0997-4338-93EF-691E948F7FA8} = {13110246-EBE1-441B-B721-B0614D62B13B} + {1EABEAF9-CEE7-4415-98B9-466982727848} = {13110246-EBE1-441B-B721-B0614D62B13B} + {751D8704-4AF9-46E4-AD24-B43DD011ED11} = {13110246-EBE1-441B-B721-B0614D62B13B} + {F52C0159-AFFE-431D-BC46-1AA6C8381400} = {13110246-EBE1-441B-B721-B0614D62B13B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3761BFC9-DBEF-4186-BB8B-BC0D84ED9AE5}