diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1bc915c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,156 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+
+[Dd]ebug/
+[Rr]elease/
+x64/
+build/
+[Bb]in/
+[Oo]bj/
+
+# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
+!packages/*/build/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.log
+*.scc
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.Publish.xml
+
+# NuGet Packages Directory
+## TODO: If you have NuGet Package Restore enabled, uncomment the next line
+#packages/
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.[Pp]ublish.xml
+*.pfx
+*.publishsettings
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+App_Data/*.mdf
+App_Data/*.ldf
+
+
+#LightSwitch generated files
+GeneratedArtifacts/
+_Pvt_Extensions/
+ModelManifest.xml
+
+# =========================
+# Windows detritus
+# =========================
+
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Mac desktop service store files
+.DS_Store
diff --git a/AddIns/AddIn.Common/AddIn.Common.csproj b/AddIns/AddIn.Common/AddIn.Common.csproj
new file mode 100644
index 0000000..8d5aef2
--- /dev/null
+++ b/AddIns/AddIn.Common/AddIn.Common.csproj
@@ -0,0 +1,65 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {D32C4454-9334-47AA-9A3F-456B8B12220A}
+ Library
+ Properties
+ Foo.AddIn.Common
+ Foo.AddIn.Common
+ v3.5
+ 512
+
+
+ true
+ full
+ false
+ ..\..\Target\Debug\AddIns\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\..\Target\Release\AddIns\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ 3.5
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AddIns/AddIn.Common/CommonFunctions.cs b/AddIns/AddIn.Common/CommonFunctions.cs
new file mode 100644
index 0000000..415b7eb
--- /dev/null
+++ b/AddIns/AddIn.Common/CommonFunctions.cs
@@ -0,0 +1,399 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections.Generic;
+using System.Runtime.InteropServices.ComTypes;
+using System.Runtime.InteropServices;
+using System.Drawing;
+using System.Diagnostics;
+
+namespace Foo.AddIn.Common
+{
+ #region Structs
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int left;
+ public int top;
+ public int right;
+ public int bottom;
+
+ public Rectangle AsRectangle
+ {
+ get
+ {
+ return new Rectangle(this.left, this.top, this.right - this.left, this.bottom - this.top);
+ }
+ }
+
+ public static RECT FromXYWH(int x, int y, int width, int height)
+ {
+ RECT rect = new RECT();
+ rect.left = x;
+ rect.top = y;
+ rect.right = x + width;
+ rect.bottom = y + height;
+ return rect;
+ }
+
+ public static RECT FromRectangle(Rectangle rectangle)
+ {
+ RECT rect = new RECT();
+ rect.left = rectangle.Left;
+ rect.top = rectangle.Top;
+ rect.right = rectangle.Right;
+ rect.bottom = rectangle.Bottom;
+ return rect;
+ }
+ }
+
+ #endregion
+
+ public static class Functions
+ {
+ #region Enums
+
+ public static class FuncEnum
+ {
+ public enum WindowAction : int
+ {
+ SW_HIDE = 0,
+ SW_SHOWNORMAL = 1,
+ SW_NORMAL = 1,
+ SW_SHOWMINIMIZED = 2,
+ SW_SHOWMAXIMIZED = 3,
+ SW_MAXIMIZE = 3,
+ SW_SHOWNOACTIVATE = 4,
+ SW_SHOW = 5,
+ SW_MINIMIZE = 6,
+ SW_SHOWMINNOACTIVE = 7,
+ SW_SHOWNA = 8,
+ SW_RESTORE = 9,
+ SW_SHOWDEFAULT = 10,
+ SW_FORCEMINIMIZE = 11,
+ SW_MAX = 11
+ }
+
+ public enum WindowMessage : int
+ {
+ WM_NULL = 0x0000,
+ WM_CREATE = 0x0001,
+ WM_DESTROY = 0x0002,
+ WM_MOVE = 0x0003,
+ WM_SIZE = 0x0005,
+ WM_ACTIVATE = 0x0006,
+ WM_SETFOCUS = 0x0007,
+ WM_KILLFOCUS = 0x0008,
+ WM_ENABLE = 0x000A,
+ WM_SETREDRAW = 0x000B,
+ WM_SETTEXT = 0x000C,
+ WM_GETTEXT = 0x000D,
+ WM_GETTEXTLENGTH = 0x000E,
+ WM_PAINT = 0x000F,
+ WM_CLOSE = 0x0010,
+ WM_QUERYENDSESSION = 0x0011,
+ WM_QUIT = 0x0012,
+ WM_QUERYOPEN = 0x0013,
+ WM_ERASEBKGND = 0x0014,
+ WM_SYSCOLORCHANGE = 0x0015,
+ WM_ENDSESSION = 0x0016,
+ WM_SHOWWINDOW = 0x0018,
+ WM_CTLCOLOR = 0x0019,
+ WM_WININICHANGE = 0x001A,
+ WM_SETTINGCHANGE = 0x001A,
+ WM_DEVMODECHANGE = 0x001B,
+ WM_ACTIVATEAPP = 0x001C,
+ WM_FONTCHANGE = 0x001D,
+ WM_TIMECHANGE = 0x001E,
+ WM_CANCELMODE = 0x001F,
+ WM_SETCURSOR = 0x0020,
+ WM_MOUSEACTIVATE = 0x0021,
+ WM_CHILDACTIVATE = 0x0022,
+ WM_QUEUESYNC = 0x0023,
+ WM_GETMINMAXINFO = 0x0024,
+ WM_PAINTICON = 0x0026,
+ WM_ICONERASEBKGND = 0x0027,
+ WM_NEXTDLGCTL = 0x0028,
+ WM_SPOOLERSTATUS = 0x002A,
+ WM_DRAWITEM = 0x002B,
+ WM_MEASUREITEM = 0x002C,
+ WM_DELETEITEM = 0x002D,
+ WM_VKEYTOITEM = 0x002E,
+ WM_CHARTOITEM = 0x002F,
+ WM_SETFONT = 0x0030,
+ WM_GETFONT = 0x0031,
+ WM_SETHOTKEY = 0x0032,
+ WM_GETHOTKEY = 0x0033,
+ WM_QUERYDRAGICON = 0x0037,
+ WM_COMPAREITEM = 0x0039,
+ WM_GETOBJECT = 0x003D,
+ WM_COMPACTING = 0x0041,
+ WM_COMMNOTIFY = 0x0044,
+ WM_WINDOWPOSCHANGING = 0x0046,
+ WM_WINDOWPOSCHANGED = 0x0047,
+ WM_POWER = 0x0048,
+ WM_COPYDATA = 0x004A,
+ WM_CANCELJOURNAL = 0x004B,
+ WM_NOTIFY = 0x004E,
+ WM_INPUTLANGCHANGEREQUEST = 0x0050,
+ WM_INPUTLANGCHANGE = 0x0051,
+ WM_TCARD = 0x0052,
+ WM_HELP = 0x0053,
+ WM_USERCHANGED = 0x0054,
+ WM_NOTIFYFORMAT = 0x0055,
+ WM_CONTEXTMENU = 0x007B,
+ WM_STYLECHANGING = 0x007C,
+ WM_STYLECHANGED = 0x007D,
+ WM_DISPLAYCHANGE = 0x007E,
+ WM_GETICON = 0x007F,
+ WM_SETICON = 0x0080,
+ WM_NCCREATE = 0x0081,
+ WM_NCDESTROY = 0x0082,
+ WM_NCCALCSIZE = 0x0083,
+ WM_NCHITTEST = 0x0084,
+ WM_NCPAINT = 0x0085,
+ WM_NCACTIVATE = 0x0086,
+ WM_GETDLGCODE = 0x0087,
+ WM_SYNCPAINT = 0x0088,
+ WM_NCMOUSEMOVE = 0x00A0,
+ WM_NCLBUTTONDOWN = 0x00A1,
+ WM_NCLBUTTONUP = 0x00A2,
+ WM_NCLBUTTONDBLCLK = 0x00A3,
+ WM_NCRBUTTONDOWN = 0x00A4,
+ WM_NCRBUTTONUP = 0x00A5,
+ WM_NCRBUTTONDBLCLK = 0x00A6,
+ WM_NCMBUTTONDOWN = 0x00A7,
+ WM_NCMBUTTONUP = 0x00A8,
+ WM_NCMBUTTONDBLCLK = 0x00A9,
+ WM_KEYDOWN = 0x0100,
+ WM_KEYUP = 0x0101,
+ WM_CHAR = 0x0102,
+ WM_DEADCHAR = 0x0103,
+ WM_SYSKEYDOWN = 0x0104,
+ WM_SYSKEYUP = 0x0105,
+ WM_SYSCHAR = 0x0106,
+ WM_SYSDEADCHAR = 0x0107,
+ WM_KEYLAST = 0x0108,
+ WM_IME_STARTCOMPOSITION = 0x010D,
+ WM_IME_ENDCOMPOSITION = 0x010E,
+ WM_IME_COMPOSITION = 0x010F,
+ WM_IME_KEYLAST = 0x010F,
+ WM_INITDIALOG = 0x0110,
+ WM_COMMAND = 0x0111,
+ WM_SYSCOMMAND = 0x0112,
+ WM_TIMER = 0x0113,
+ WM_HSCROLL = 0x0114,
+ WM_VSCROLL = 0x0115,
+ WM_INITMENU = 0x0116,
+ WM_INITMENUPOPUP = 0x0117,
+ WM_MENUSELECT = 0x011F,
+ WM_MENUCHAR = 0x0120,
+ WM_ENTERIDLE = 0x0121,
+ WM_MENURBUTTONUP = 0x0122,
+ WM_MENUDRAG = 0x0123,
+ WM_MENUGETOBJECT = 0x0124,
+ WM_UNINITMENUPOPUP = 0x0125,
+ WM_MENUCOMMAND = 0x0126,
+ WM_CTLCOLORMSGBOX = 0x0132,
+ WM_CTLCOLOREDIT = 0x0133,
+ WM_CTLCOLORLISTBOX = 0x0134,
+ WM_CTLCOLORBTN = 0x0135,
+ WM_CTLCOLORDLG = 0x0136,
+ WM_CTLCOLORSCROLLBAR = 0x0137,
+ WM_CTLCOLORSTATIC = 0x0138,
+ WM_MOUSEMOVE = 0x0200,
+ WM_LBUTTONDOWN = 0x0201,
+ WM_LBUTTONUP = 0x0202,
+ WM_LBUTTONDBLCLK = 0x0203,
+ WM_RBUTTONDOWN = 0x0204,
+ WM_RBUTTONUP = 0x0205,
+ WM_RBUTTONDBLCLK = 0x0206,
+ WM_MBUTTONDOWN = 0x0207,
+ WM_MBUTTONUP = 0x0208,
+ WM_MBUTTONDBLCLK = 0x0209,
+ WM_MOUSEWHEEL = 0x020A,
+ WM_PARENTNOTIFY = 0x0210,
+ WM_ENTERMENULOOP = 0x0211,
+ WM_EXITMENULOOP = 0x0212,
+ WM_NEXTMENU = 0x0213,
+ WM_SIZING = 0x0214,
+ WM_CAPTURECHANGED = 0x0215,
+ WM_MOVING = 0x0216,
+ WM_DEVICECHANGE = 0x0219,
+ WM_MDICREATE = 0x0220,
+ WM_MDIDESTROY = 0x0221,
+ WM_MDIACTIVATE = 0x0222,
+ WM_MDIRESTORE = 0x0223,
+ WM_MDINEXT = 0x0224,
+ WM_MDIMAXIMIZE = 0x0225,
+ WM_MDITILE = 0x0226,
+ WM_MDICASCADE = 0x0227,
+ WM_MDIICONARRANGE = 0x0228,
+ WM_MDIGETACTIVE = 0x0229,
+ WM_MDISETMENU = 0x0230,
+ WM_ENTERSIZEMOVE = 0x0231,
+ WM_EXITSIZEMOVE = 0x0232,
+ WM_DROPFILES = 0x0233,
+ WM_MDIREFRESHMENU = 0x0234,
+ WM_IME_SETCONTEXT = 0x0281,
+ WM_IME_NOTIFY = 0x0282,
+ WM_IME_CONTROL = 0x0283,
+ WM_IME_COMPOSITIONFULL = 0x0284,
+ WM_IME_SELECT = 0x0285,
+ WM_IME_CHAR = 0x0286,
+ WM_IME_REQUEST = 0x0288,
+ WM_IME_KEYDOWN = 0x0290,
+ WM_IME_KEYUP = 0x0291,
+ WM_MOUSEHOVER = 0x02A1,
+ WM_MOUSELEAVE = 0x02A3,
+ WM_CUT = 0x0300,
+ WM_COPY = 0x0301,
+ WM_PASTE = 0x0302,
+ WM_CLEAR = 0x0303,
+ WM_UNDO = 0x0304,
+ WM_RENDERFORMAT = 0x0305,
+ WM_RENDERALLFORMATS = 0x0306,
+ WM_DESTROYCLIPBOARD = 0x0307,
+ WM_DRAWCLIPBOARD = 0x0308,
+ WM_PAINTCLIPBOARD = 0x0309,
+ WM_VSCROLLCLIPBOARD = 0x030A,
+ WM_SIZECLIPBOARD = 0x030B,
+ WM_ASKCBFORMATNAME = 0x030C,
+ WM_CHANGECBCHAIN = 0x030D,
+ WM_HSCROLLCLIPBOARD = 0x030E,
+ WM_QUERYNEWPALETTE = 0x030F,
+ WM_PALETTEISCHANGING = 0x0310,
+ WM_PALETTECHANGED = 0x0311,
+ WM_HOTKEY = 0x0312,
+ WM_PRINT = 0x0317,
+ WM_PRINTCLIENT = 0x0318,
+ WM_HANDHELDFIRST = 0x0358,
+ WM_HANDHELDLAST = 0x035F,
+ WM_AFXFIRST = 0x0360,
+ WM_AFXLAST = 0x037F,
+ WM_PENWINFIRST = 0x0380,
+ WM_PENWINLAST = 0x038F,
+ WM_APP = 0x8000,
+ WM_USER = 0x0400,
+ WM_REFLECT = WM_USER + 0x1c00,
+ WM_CHANGEUISTATE = 0x0127,
+ WM_UPDATEUISTATE = 0x0128,
+ WM_QUERYUISTATE = 0x0129
+ }
+ }
+
+ #endregion
+
+ #region DLLImports
+
+ [DllImport("ole32.dll")]
+ public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);
+
+ [DllImport("user32.dll")]
+ extern public static bool GetWindowRect(IntPtr hWnd, out RECT rect);
+
+ [DllImport("user32.dll")]
+ extern public static bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
+
+ [DllImport("User32.dll")]
+ extern public static bool IsWindow(IntPtr hwnd);
+
+ [DllImport("User32.dll")]
+ extern public static bool IsWindowVisible(IntPtr hwnd);
+
+ [DllImport("user32.dll")]
+ extern public static int ShowWindow(IntPtr hwnd, FuncEnum.WindowAction nCmdShow);
+
+ [DllImport("User32.dll")]
+ extern public static int GetWindowThreadProcessId(IntPtr hWnd, ref int lpdwProcessId);
+
+ [DllImport("User32.dll")]
+ extern public static int SendMessage(IntPtr hWnd, FuncEnum.WindowMessage Msg, IntPtr wParam, IntPtr lParam);
+
+ #endregion
+
+ #region Functions
+
+ ///
+ /// Returns the .Net Process Object that owns the passed in hWnd
+ ///
+ public static Process GetProcessFromHandle(IntPtr hWnd)
+ {
+ int currentPid = 0;
+ GetWindowThreadProcessId(hWnd, ref currentPid);
+
+ Process process;
+ process = Process.GetProcessById(currentPid);
+ return process;
+ }
+
+ ///
+ /// Attaches to instance of COM object matching progid
+ /// and returns an object. Client must cast and know
+ /// expected type.
+ ///
+ public static Object GetCOMObject(string progId)
+ {
+ Object app = null;
+ try
+ {
+ app = Marshal.GetActiveObject(progId);
+ }
+ catch (SystemException) { /* ignore */ }
+ return app;
+ }
+
+ ///
+ /// Use this to Get A specific type of Object from the ROT
+ ///
+ public static List GetRunningObjectsOfType()
+ {
+ // Get the table.
+ var res = new List();
+ IBindCtx bc;
+
+ CreateBindCtx(0, out bc);
+ IRunningObjectTable runningObjectTable;
+
+ bc.GetRunningObjectTable(out runningObjectTable);
+ IEnumMoniker monikerEnumerator;
+ runningObjectTable.EnumRunning(out monikerEnumerator);
+ monikerEnumerator.Reset();
+
+ // Enumerate and fill our nice dictionary.
+ IMoniker[] monikers = new IMoniker[1];
+ IntPtr numFetched = IntPtr.Zero;
+
+ while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
+ {
+ object o;
+ runningObjectTable.GetObject(monikers[0], out o);
+
+ if (o is T)
+ {
+ res.Add((T)o);
+ }
+ o = null;
+ }
+ return res;
+ }
+
+ ///
+ /// Get a windows rectangle in a .NET structure
+ ///
+ /// The window handle to look up
+ /// The rectangle
+ public static Rectangle GetWindowRect(IntPtr hwnd)
+ {
+ RECT rect = new RECT();
+ GetWindowRect(hwnd, out rect);
+ return rect.AsRectangle;
+ }
+
+ #endregion
+ }
+
+
+}
diff --git a/AddIns/AddIn.Common/CommonTypes.cs b/AddIns/AddIn.Common/CommonTypes.cs
new file mode 100644
index 0000000..a7338f9
--- /dev/null
+++ b/AddIns/AddIn.Common/CommonTypes.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Foo.AddIn.Common
+{
+ ///
+ /// Common Return Value for Addins
+ ///
+ public class FuncRetVal
+ {
+ public FuncRetValEnum Type { get; set; }
+ public string Message { get; set; }
+ }
+
+ ///
+ /// Useful for Returns where we
+ /// need more information on failures
+ ///
+ public enum FuncRetValEnum
+ {
+ Action_Succeeded,
+ Action_Failed,
+ NoAction_Needed,
+ ParameterInvalid,
+ ArtifactUnavailable,
+ FunctionallityNotSupported,
+ ErrorThrown
+ }
+}
diff --git a/AddIns/AddIn.Common/CommonValidations.cs b/AddIns/AddIn.Common/CommonValidations.cs
new file mode 100644
index 0000000..48ad9e1
--- /dev/null
+++ b/AddIns/AddIn.Common/CommonValidations.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace Foo.AddIn.Common
+{
+ public static class Validate
+ {
+ ///
+ /// Validate ArtifactLocation * We could later do much more work here *
+ ///
+ ///
+ public static bool IsValidArtifactLocation(string strArtifactLocation, ref FuncRetVal retVal)
+ {
+ // All URLs should contain that character (Files aren't allowed to contain it)
+ bool bIsUrl = strArtifactLocation.Contains('/');
+
+ if (String.IsNullOrEmpty(strArtifactLocation))
+ {
+ retVal.Type = FuncRetValEnum.ParameterInvalid;
+ return false;
+ }
+ else if (!bIsUrl && !File.Exists(strArtifactLocation))
+ {
+ // Check File existence (if it doesn't return false)
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ }
+}
diff --git a/AddIns/AddIn.Common/IAddIn.cs b/AddIns/AddIn.Common/IAddIn.cs
new file mode 100644
index 0000000..d11504d
--- /dev/null
+++ b/AddIns/AddIn.Common/IAddIn.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Foo.AddIn.Common
+{
+ public interface IAddIn
+ {
+ // I
+
+
+ }
+}
diff --git a/AddIns/AddIn.Common/IDynResolve.cs b/AddIns/AddIn.Common/IDynResolve.cs
new file mode 100644
index 0000000..b045e82
--- /dev/null
+++ b/AddIns/AddIn.Common/IDynResolve.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Foo.AddIn.Common
+{
+ public interface IDynResolve
+ {
+ // I
+
+
+ }
+}
diff --git a/AddIns/AddIn.Common/IWorkspace.cs b/AddIns/AddIn.Common/IWorkspace.cs
new file mode 100644
index 0000000..53b75ac
--- /dev/null
+++ b/AddIns/AddIn.Common/IWorkspace.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Foo.AddIn.Common
+{
+ public interface IWorkspace
+ {
+ // Launchers
+ FuncRetVal Launch(string strArtifactLocation, int WindowHeight, int WindowWidth, int WindowTop, int WindowLeft);
+ FuncRetVal Launch(string strArtifactLocation);
+
+ // ShowNHiders
+ FuncRetVal Show(string strArtifactLocation);
+ FuncRetVal Hide(string strArtifactLocation);
+
+ // Closers
+ FuncRetVal QueryClose(string strArtifactLocation);
+ FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact, out int WindowHeight, out int WindowWidth, out int WindowTop, out int WindowLeft);
+ FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact);
+ FuncRetVal Close(string strArtifactLocation);
+ }
+}
diff --git a/AddIns/AddIn.Common/Properties/AssemblyInfo.cs b/AddIns/AddIn.Common/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..166cc13
--- /dev/null
+++ b/AddIns/AddIn.Common/Properties/AssemblyInfo.cs
@@ -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("AddIn.Common")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AddIn.Common")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
+[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("39d7351f-149f-4d32-a3ae-d07ec27515af")]
+
+// 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")]
diff --git a/AddIns/Addin.Office/Access.cs b/AddIns/Addin.Office/Access.cs
new file mode 100644
index 0000000..b0ce159
--- /dev/null
+++ b/AddIns/Addin.Office/Access.cs
@@ -0,0 +1,324 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Foo.AddIn.Common;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Drawing;
+
+// Ignore 'Ambiguity' warning message, seems like no way around those
+#pragma warning disable 0467
+
+namespace Foo.Addin.Office
+{
+ public class Access_Workspace : IWorkspace
+ {
+ public const string Access_ProgId = "Access.Application";
+
+ public FuncRetVal Launch(string strArtifactLocation, int WindowHeight, int WindowWidth, int WindowTop, int WindowLeft)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ Microsoft.Office.Interop.Access.Application app = new Microsoft.Office.Interop.Access.Application();
+ app.Visible = true;
+
+ // Must test the following here:
+ // - open both .mdb and .adp (access project files with this)
+ // - how does this behave when db is password protected?
+ app.OpenCurrentDatabase(strArtifactLocation, true, "");
+
+ // ToDo: Check if a new process got created? / or if hWnd exists???
+ // - Also PERFORM Window Positioning
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Launch(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ Microsoft.Office.Interop.Access.Application app = new Microsoft.Office.Interop.Access.Application();
+ app.Visible = true;
+
+ // Must test the following here:
+ // - open both .mdb and .adp (access project files with this)
+ // - how does this behave when db is password protected?
+ app.OpenCurrentDatabase(strArtifactLocation, true, "");
+
+ // ToDo: Check if a new process got created? / or if hWnd exists???
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Show(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningAccessApps = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Access.Application app in RunningAccessApps)
+ {
+ if (app.CurrentProject.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ IntPtr hWnd = (IntPtr)app.hWndAccessApp();
+ if (!Functions.IsWindowVisible(hWnd))
+ {
+ Functions.ShowWindow(hWnd, Functions.FuncEnum.WindowAction.SW_SHOW);
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.NoAction_Needed;
+ return retVal;
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Hide(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningAccessApps = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Access.Application app in RunningAccessApps)
+ {
+ if (app.CurrentProject.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ IntPtr hWnd = (IntPtr)app.hWndAccessApp();
+ if (Functions.IsWindowVisible(hWnd))
+ {
+ Functions.ShowWindow(hWnd, Functions.FuncEnum.WindowAction.SW_HIDE);
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.NoAction_Needed;
+ return retVal;
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal QueryClose(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningAccessApps = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Access.Application app in RunningAccessApps)
+ {
+ if (app.CurrentProject.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ IntPtr hWnd = (IntPtr) app.hWndAccessApp();
+ if (Functions.SendMessage(hWnd, Functions.FuncEnum.WindowMessage.WM_QUERYENDSESSION, IntPtr.Zero, IntPtr.Zero) != 0)
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ return retVal;
+ }
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact, out int WindowHeight, out int WindowWidth, out int WindowTop, out int WindowLeft)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ WindowTop = 0;
+ WindowLeft = 0;
+ WindowWidth = 0;
+ WindowHeight = 0;
+
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningAccessApps = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Access.Application app in RunningAccessApps)
+ {
+ if (app.CurrentProject.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Get Handle and Process
+ IntPtr hWnd = (IntPtr)app.hWndAccessApp();
+ Process process = Functions.GetProcessFromHandle((IntPtr)hWnd);
+
+ // Get the Window properties
+ Rectangle rect = Functions.GetWindowRect(hWnd);
+ WindowHeight = rect.Height;
+ WindowWidth = rect.Width;
+ WindowLeft = rect.Left;
+ WindowTop = rect.Top;
+
+ // Close the database
+ //app.CloseCurrentDatabase();
+ if (bAutoSaveArtifact)
+ app.Quit(Microsoft.Office.Interop.Access.AcQuitOption.acQuitSaveAll);
+ else
+ app.Quit(Microsoft.Office.Interop.Access.AcQuitOption.acQuitSaveNone);
+ Marshal.FinalReleaseComObject(app); // force clean-up
+
+ // Kill the process
+ process.Kill();
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningAccessApps = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Access.Application app in RunningAccessApps)
+ {
+ if (app.CurrentProject.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Get Handle and Process
+ IntPtr hWnd = (IntPtr)app.hWndAccessApp();
+ Process process = Functions.GetProcessFromHandle((IntPtr)hWnd);
+
+ // Close the database
+ //app.CloseCurrentDatabase();
+ if(bAutoSaveArtifact)
+ app.Quit(Microsoft.Office.Interop.Access.AcQuitOption.acQuitSaveAll);
+ else
+ app.Quit(Microsoft.Office.Interop.Access.AcQuitOption.acQuitSaveNone);
+ Marshal.FinalReleaseComObject(app); // force clean-up
+
+ // Kill the process
+ process.Kill();
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningAccessApps = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Access.Application app in RunningAccessApps)
+ {
+ if (app.CurrentProject.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Get Handle and Process
+ IntPtr hWnd = (IntPtr)app.hWndAccessApp();
+ Process process = Functions.GetProcessFromHandle((IntPtr)hWnd);
+
+ // Close the database
+ //app.CloseCurrentDatabase();
+ app.Quit(Microsoft.Office.Interop.Access.AcQuitOption.acQuitSaveAll);
+ Marshal.FinalReleaseComObject(app); // force clean-up
+
+ // Kill the process
+ process.Kill();
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ }
+}
diff --git a/AddIns/Addin.Office/AddIn.cs b/AddIns/Addin.Office/AddIn.cs
new file mode 100644
index 0000000..7f834bd
--- /dev/null
+++ b/AddIns/Addin.Office/AddIn.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Foo.AddIn.Common;
+
+namespace Foo.Addin.Office
+{
+ public class AddIn : IAddIn
+ {
+
+ }
+}
diff --git a/AddIns/Addin.Office/Addin.Office.csproj b/AddIns/Addin.Office/Addin.Office.csproj
new file mode 100644
index 0000000..83e97bc
--- /dev/null
+++ b/AddIns/Addin.Office/Addin.Office.csproj
@@ -0,0 +1,106 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {0CA1DD2E-2752-4587-ADB4-77194411648B}
+ Library
+ Properties
+ Foo.Addin.Office
+ Foo.Addin.Office
+ v3.5
+ 512
+
+
+ true
+ full
+ false
+ ..\..\Target\Debug\AddIns\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\..\Target\Release\AddIns\
+ TRACE
+ prompt
+ 4
+
+
+
+ False
+ False
+
+
+ False
+ False
+
+
+ False
+ False
+
+
+ False
+ False
+
+
+ False
+ False
+
+
+ False
+ False
+
+
+
+ 3.5
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {D32C4454-9334-47AA-9A3F-456B8B12220A}
+ AddIn.Common
+
+
+
+
+ {2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}
+ 2
+ 3
+ 0
+ primary
+ False
+
+
+
+
+
\ No newline at end of file
diff --git a/AddIns/Addin.Office/Excel.cs b/AddIns/Addin.Office/Excel.cs
new file mode 100644
index 0000000..5d003e3
--- /dev/null
+++ b/AddIns/Addin.Office/Excel.cs
@@ -0,0 +1,383 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+using System.Reflection;
+
+using Foo.AddIn.Common;
+using System.Drawing;
+
+// Ignore 'Ambiguity' warning message, seems like no way around those
+#pragma warning disable 0467
+
+namespace Foo.Addin.Office
+{
+ public class Excel_Workspace : IWorkspace
+ {
+ public const string Excel_ProgId = "Excel.Application";
+
+ public FuncRetVal Launch(string strArtifactLocation, int WindowHeight, int WindowWidth, int WindowTop, int WindowLeft)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ Microsoft.Office.Interop.Excel.Application app = null;
+ app = new Microsoft.Office.Interop.Excel.Application();
+
+ // Mark the Application as visible
+ app.Visible = true;
+
+ // Position the Window
+ IntPtr hWnd = (IntPtr)app.Hwnd;
+ Functions.SetWindowPos(hWnd, IntPtr.Zero, WindowLeft, WindowTop, WindowHeight, WindowWidth, 0);
+
+ // Open/Load the Document
+ Microsoft.Office.Interop.Excel.Workbook workbook = app.Workbooks.Open(strArtifactLocation, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
+ Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
+ Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
+ if (workbook != null)
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ }
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Launch(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ Microsoft.Office.Interop.Excel.Application app = null;
+ app = new Microsoft.Office.Interop.Excel.Application();
+
+ // Mark the Application as visible
+ app.Visible = true;
+
+ Microsoft.Office.Interop.Excel.Workbook workbook = app.Workbooks.Open(strArtifactLocation, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
+ Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
+ Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
+ if (workbook != null)
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ }
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Show(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningExcelWorkbooks = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
+ {
+ if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ var app = book.Application;
+ bool bIsTheOnlyDocumentInApp = (app.Workbooks.Count == 1);
+
+ // If For some reason the App is visible
+ if (app.Visible)
+ {
+ // Make Sure that this Workbook is activated
+ if (!bIsTheOnlyDocumentInApp)
+ {
+ book.Activate();
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.NoAction_Needed;
+ }
+ return retVal;
+ }
+
+ app.Visible = true;
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Hide(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningExcelWorkbooks = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
+ {
+ if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ var app = book.Application;
+ bool bIsTheOnlyDocumentInApp = (app.Workbooks.Count == 1);
+
+ if (!app.Visible)
+ {
+ retVal.Type = FuncRetValEnum.NoAction_Needed;
+ return retVal;
+ }
+
+ // If this is NOT the Only open workbook in this App
+ // ~Activate the other workbook
+ if (!bIsTheOnlyDocumentInApp)
+ {
+ foreach (Microsoft.Office.Interop.Excel.Workbook book2 in app.Workbooks)
+ {
+ if (book2.FullName.ToLower() != strArtifactLocation.ToLower())
+ {
+ book2.Activate();
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+ }
+ else
+ {
+ app.Visible = false;
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal QueryClose(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningExcelWorkbooks = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
+ {
+ if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if (book.Saved)
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ return retVal;
+ }
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact, out int WindowHeight, out int WindowWidth, out int WindowTop, out int WindowLeft)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ WindowTop = 0;
+ WindowLeft = 0;
+ WindowWidth = 0;
+ WindowHeight = 0;
+
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningExcelWorkbooks = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
+ {
+ if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // In case there is a running rogue excel process left open,
+ // we can always force it to close by closing the process
+ // int hWnd = app.Hwnd;
+ // Process process = Win32Functions.GetProcessFromHandle((IntPtr) hWnd);
+ var app = book.Application;
+
+ // Get the Window properties
+ IntPtr hWnd = (IntPtr)app.Hwnd;
+ Rectangle rect = Functions.GetWindowRect(hWnd);
+ WindowHeight = rect.Height;
+ WindowWidth = rect.Width;
+ WindowLeft = rect.Left;
+ WindowTop = rect.Top;
+
+ // Close the Workbook
+ book.Close(bAutoSaveArtifact, strArtifactLocation, false);
+ Marshal.FinalReleaseComObject(book); // force clean-up
+
+ // Close Excel if this is the last Workbook
+ if (app.Workbooks.Count == 0)
+ {
+ app.Quit();
+ Marshal.FinalReleaseComObject(app); // force clean-up, should clean up excel process
+ //process.Close();
+ }
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningExcelWorkbooks = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
+ {
+ if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // In case there is a running rogue excel process left open,
+ // we can always force it to close by closing the process
+ // int hWnd = app.Hwnd;
+ // Process process = Win32Functions.GetProcessFromHandle((IntPtr) hWnd);
+ var app = book.Application;
+
+ // Close the Workbook
+ book.Close(bAutoSaveArtifact, strArtifactLocation, false);
+ Marshal.FinalReleaseComObject(book); // force clean-up
+
+ // Close Excel if this is the last Workbook
+ if (app.Workbooks.Count == 0)
+ {
+ app.Quit();
+ Marshal.FinalReleaseComObject(app); // force clean-up, should clean up excel process
+ //process.Close();
+ }
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningExcelWorkbooks = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
+ {
+ if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // In case there is a running rogue excel process left open,
+ // we can always force it to close by closing the process
+ // int hWnd = app.Hwnd;
+ // Process process = Win32Functions.GetProcessFromHandle((IntPtr) hWnd);
+ var app = book.Application;
+
+ // Close the Workbook
+ book.Close(true, strArtifactLocation, false);
+ Marshal.FinalReleaseComObject(book); // force clean-up
+
+ // Close Excel if this is the last Workbook
+ if (app.Workbooks.Count == 0)
+ {
+ app.Quit();
+ Marshal.FinalReleaseComObject(app); // force clean-up, should clean up excel process
+ //process.Close();
+ }
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ }
+}
diff --git a/AddIns/Addin.Office/PowerPoint.cs b/AddIns/Addin.Office/PowerPoint.cs
new file mode 100644
index 0000000..6cd41af
--- /dev/null
+++ b/AddIns/Addin.Office/PowerPoint.cs
@@ -0,0 +1,379 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Foo.AddIn.Common;
+using System.Runtime.InteropServices;
+
+// Ignore 'Ambiguity' warning message, seems like no way around those
+#pragma warning disable 0467
+
+namespace Foo.Addin.Office
+{
+ public class PowerPoint_Workspace : IWorkspace
+ {
+ public const string PowerPoint_ProgId = "PowerPoint.Application";
+
+ public FuncRetVal Launch(string strArtifactLocation, int WindowHeight, int WindowWidth, int WindowTop, int WindowLeft)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ Microsoft.Office.Interop.PowerPoint.Application app = null;
+ app = Functions.GetCOMObject(PowerPoint_ProgId) as Microsoft.Office.Interop.PowerPoint.Application;
+
+ // If no existing PowerPoint App is open, open a new one
+ if (app == null)
+ {
+ app = new Microsoft.Office.Interop.PowerPoint.Application();
+ app.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
+ }
+
+ // If there is an existing presentation, don't position the window
+ bool bThereIsAnExistingPresentation = (app.Presentations.Count > 0);
+
+ // Open the PowerPoint Presentation
+ Microsoft.Office.Interop.PowerPoint.Presentation presentation = null;
+ presentation = app.Presentations.Open(strArtifactLocation, Microsoft.Office.Core.MsoTriState.msoFalse,
+ Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue);
+
+ if (presentation != null)
+ {
+ // Position the Window
+ if (!bThereIsAnExistingPresentation)
+ {
+ IntPtr hWnd = (IntPtr) app.HWND;
+ Functions.SetWindowPos(hWnd, IntPtr.Zero, WindowLeft, WindowTop, WindowHeight, WindowWidth, 0);
+ }
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ }
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Launch(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ Microsoft.Office.Interop.PowerPoint.Application app = null;
+ app = Functions.GetCOMObject(PowerPoint_ProgId) as Microsoft.Office.Interop.PowerPoint.Application;
+
+ // If no existing PowerPoint App is open, open a new one
+ if (app == null)
+ {
+ app = new Microsoft.Office.Interop.PowerPoint.Application();
+ app.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
+ }
+
+ // Open the PowerPoint Presentation
+ Microsoft.Office.Interop.PowerPoint.Presentation presentation = null;
+ presentation = app.Presentations.Open(strArtifactLocation, Microsoft.Office.Core.MsoTriState.msoFalse,
+ Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue);
+
+ if (presentation != null)
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ }
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Show(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningPowerPoints = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints)
+ {
+ if (presentation.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ switch (presentation.Application.Visible)
+ {
+ case Microsoft.Office.Core.MsoTriState.msoTrue:
+ {
+ retVal.Type = FuncRetValEnum.NoAction_Needed;
+ return retVal;
+ }
+
+ case Microsoft.Office.Core.MsoTriState.msoFalse:
+ {
+ presentation.Application.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
+
+ //Functions.ShowWindow((IntPtr)presentation.Application.HWND, (int)Functions.WindowAction.SW_SHOW);
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Hide(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningPowerPoints = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints)
+ {
+ if (presentation.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ switch (presentation.Application.Visible)
+ {
+ case Microsoft.Office.Core.MsoTriState.msoTrue:
+ {
+ presentation.Application.Visible = Microsoft.Office.Core.MsoTriState.msoFalse;
+
+ //Functions.ShowWindow((IntPtr)presentation.Application.HWND, (int)Functions.WindowAction.SW_HIDE);
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+
+ case Microsoft.Office.Core.MsoTriState.msoFalse:
+ {
+ retVal.Type = FuncRetValEnum.NoAction_Needed;
+ return retVal;
+ }
+ }
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal QueryClose(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningPowerPoints = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints)
+ {
+ if (presentation.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ switch (presentation.Saved)
+ {
+ case Microsoft.Office.Core.MsoTriState.msoTrue:
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+
+ case Microsoft.Office.Core.MsoTriState.msoFalse:
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ return retVal;
+ }
+ }
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact, out int WindowHeight, out int WindowWidth, out int WindowTop, out int WindowLeft)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ WindowTop = 0;
+ WindowLeft = 0;
+ WindowWidth = 0;
+ WindowHeight = 0;
+
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningPowerPoints = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints)
+ {
+ if (presentation.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ var app = presentation.Application;
+
+ // Save this Presentation
+ if (bAutoSaveArtifact)
+ presentation.Save();
+
+ // Pass out the Window Information
+ WindowTop = (int) presentation.Application.Top;
+ WindowLeft = (int) presentation.Application.Left;
+ WindowHeight = (int) presentation.Application.Height;
+ WindowWidth = (int)presentation.Application.Width;
+
+ // Close this Presentation
+ presentation.Close();
+
+ Marshal.FinalReleaseComObject(presentation); // force clean-up
+
+ // Close PowerPoint if there are no more Presentations
+ if (app.Presentations.Count == 0)
+ {
+ app.Quit();
+ Marshal.FinalReleaseComObject(app); // force clean-up, kill application for sure
+ }
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningPowerPoints = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints)
+ {
+ if (presentation.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ var app = presentation.Application;
+
+ // Save this Presentation
+ if(bAutoSaveArtifact)
+ presentation.Save();
+
+ // Close this Presentation
+ presentation.Close();
+
+ Marshal.FinalReleaseComObject(presentation); // force clean-up
+
+ // Close PowerPoint if there are no more Presentations
+ if (app.Presentations.Count == 0)
+ {
+ app.Quit();
+ Marshal.FinalReleaseComObject(app); // force clean-up, kill application for sure
+ }
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningPowerPoints = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints)
+ {
+ if (presentation.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ var app = presentation.Application;
+
+ // Save this Presentation
+ presentation.Save();
+
+ // Close this Presentation
+ presentation.Close();
+
+ Marshal.FinalReleaseComObject(presentation); // force clean-up
+
+ // Close PowerPoint if there are no more Presentations
+ if (app.Presentations.Count == 0)
+ {
+ app.Quit();
+ Marshal.FinalReleaseComObject(app); // force clean-up, kill application for sure
+ }
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ }
+}
diff --git a/AddIns/Addin.Office/Properties/AssemblyInfo.cs b/AddIns/Addin.Office/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..7a95a77
--- /dev/null
+++ b/AddIns/Addin.Office/Properties/AssemblyInfo.cs
@@ -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("Addin.Office")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Addin.Office")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
+[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("79a22796-d344-456e-90a3-9e28c0f31d31")]
+
+// 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")]
diff --git a/AddIns/Addin.Office/Publisher.cs b/AddIns/Addin.Office/Publisher.cs
new file mode 100644
index 0000000..ed0abbc
--- /dev/null
+++ b/AddIns/Addin.Office/Publisher.cs
@@ -0,0 +1,361 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Foo.AddIn.Common;
+using System.Diagnostics;
+
+// Ignore 'Ambiguity' warning message, seems like no way around those
+#pragma warning disable 0467
+
+namespace Foo.Addin.Office
+{
+ public class Publisher_Workspace : IWorkspace
+ {
+ public const string Publisher_ProgId = "Publisher.Application";
+
+ public FuncRetVal Launch(string strArtifactLocation, int WindowHeight, int WindowWidth, int WindowTop, int WindowLeft)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ Microsoft.Office.Interop.Publisher.Application app = new Microsoft.Office.Interop.Publisher.Application();
+
+ // Opens Publisher
+ Microsoft.Office.Interop.Publisher.Document doc = null;
+ doc = app.Open(strArtifactLocation, false, false, Microsoft.Office.Interop.Publisher.PbSaveOptions.pbSaveChanges);
+
+ // Position the Window
+ IntPtr hWnd = (IntPtr)doc.ActiveWindow.Hwnd;
+ Functions.SetWindowPos(hWnd, IntPtr.Zero, WindowLeft, WindowTop, WindowHeight, WindowWidth, 0);
+
+ if (doc != null)
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ }
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Launch(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ Microsoft.Office.Interop.Publisher.Application app = new Microsoft.Office.Interop.Publisher.Application();
+
+ // Opens Publisher
+ Microsoft.Office.Interop.Publisher.Document doc = null;
+ doc = app.Open(strArtifactLocation, false, false, Microsoft.Office.Interop.Publisher.PbSaveOptions.pbSaveChanges);
+
+ if (doc != null)
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ }
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Show(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningPublisherApps = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps)
+ {
+ foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents)
+ {
+ if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+
+ if (pubDoc.ActiveWindow.Visible)
+ {
+ retVal.Type = FuncRetValEnum.NoAction_Needed;
+ return retVal;
+ }
+ else
+ {
+ pubDoc.ActiveWindow.Visible = true;
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Hide(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningPublisherApps = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps)
+ {
+ foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents)
+ {
+ if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+
+ if (!pubDoc.ActiveWindow.Visible)
+ {
+ retVal.Type = FuncRetValEnum.NoAction_Needed;
+ return retVal;
+ }
+ else
+ {
+ pubDoc.ActiveWindow.Visible = false;
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal QueryClose(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningPublisherApps = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps)
+ {
+ foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents)
+ {
+ if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if (pubDoc.Saved)
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact, out int WindowHeight, out int WindowWidth, out int WindowTop, out int WindowLeft)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ WindowTop = 0;
+ WindowLeft = 0;
+ WindowWidth = 0;
+ WindowHeight = 0;
+
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningPublisherApps = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps)
+ {
+ foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents)
+ {
+ if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Save the Document
+ if (bAutoSaveArtifact)
+ pubDoc.Save();
+
+ // Get the Window properties
+ WindowTop = pubDoc.ActiveWindow.Top;
+ WindowLeft = pubDoc.ActiveWindow.Left;
+ WindowWidth = pubDoc.ActiveWindow.Width;
+ WindowHeight = pubDoc.ActiveWindow.Height;
+
+ // Get the Handle
+ IntPtr hWnd = (IntPtr)pubDoc.ActiveWindow.Hwnd;
+ Process process = Functions.GetProcessFromHandle(hWnd);
+
+ // Send Close Message
+ if (Functions.SendMessage((IntPtr)hWnd, Functions.FuncEnum.WindowMessage.WM_CLOSE, IntPtr.Zero, IntPtr.Zero) == 0)
+ {
+ process.Kill();
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ return retVal;
+ }
+ }
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningPublisherApps = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps)
+ {
+ foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents)
+ {
+ if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Save the Document
+ if(bAutoSaveArtifact)
+ pubDoc.Save();
+
+ // Get the Handle
+ IntPtr hWnd = (IntPtr)pubDoc.ActiveWindow.Hwnd;
+ Process process = Functions.GetProcessFromHandle(hWnd);
+
+ // Send Close Message
+ if (Functions.SendMessage((IntPtr)hWnd, Functions.FuncEnum.WindowMessage.WM_CLOSE, IntPtr.Zero, IntPtr.Zero) == 0)
+ {
+ process.Kill();
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ return retVal;
+ }
+ }
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningPublisherApps = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps)
+ {
+ foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents)
+ {
+ if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Save the Document
+ pubDoc.Save();
+
+ // Get the Handle
+ IntPtr hWnd = (IntPtr)pubDoc.ActiveWindow.Hwnd;
+ Process process = Functions.GetProcessFromHandle(hWnd);
+
+ // Send Close Message
+ if (Functions.SendMessage((IntPtr)hWnd, Functions.FuncEnum.WindowMessage.WM_CLOSE, IntPtr.Zero, IntPtr.Zero) == 0)
+ {
+ process.Kill();
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ return retVal;
+ }
+ }
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ }
+}
diff --git a/AddIns/Addin.Office/Visio.cs b/AddIns/Addin.Office/Visio.cs
new file mode 100644
index 0000000..1275022
--- /dev/null
+++ b/AddIns/Addin.Office/Visio.cs
@@ -0,0 +1,320 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Foo.AddIn.Common;
+using System.Runtime.InteropServices;
+
+// Ignore 'Ambiguity' warning message, seems like no way around those
+#pragma warning disable 0467
+
+namespace Foo.Addin.Office
+{
+ public class Visio_Workspace : IWorkspace
+ {
+ public const string Visio_ProgId = "Visio.Application";
+
+ public FuncRetVal Launch(string strArtifactLocation, int WindowHeight, int WindowWidth, int WindowTop, int WindowLeft)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ Microsoft.Office.Interop.Visio.Application app = null;
+ app = new Microsoft.Office.Interop.Visio.Application();
+
+ // Mark the Application as visible
+ app.Visible = true;
+
+ app.Documents.Open(strArtifactLocation);
+
+ // ToDo: Check if a new process got created? / or if hWnd exists???
+ // - Also PERFORM Window Positioning
+ app.ActiveWindow.SetWindowRect(WindowLeft, WindowTop, WindowWidth, WindowHeight);
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Launch(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+
+ Microsoft.Office.Interop.Visio.Application app = null;
+ app = new Microsoft.Office.Interop.Visio.Application();
+
+ // Mark the Application as visible
+ app.Visible = true;
+
+ app.Documents.Open(strArtifactLocation);
+
+ // Keep Track of all our Excel Instances -- not needed in visio?
+ ///WorkspaceState.Launched_ExcelInstances.Add(app);
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+
+ //if (!String.IsNullOrEmpty(strArtifactLocation) && (strArtifactLocation.Length > 3))
+ //{
+ // Process.Start(strArtifactLocation);
+ //}
+ //return FuncDepBoolType.ParametersInvalid;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Show(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningVisioDocs = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // TO DO - (doc.Application.Documents.Count == 1); not working, why?!?!? odd
+ bool bIsTrue = (doc.Application.Documents.Count == 1); // not working, why?!?!? odd
+ //bool bIsTheOnlyDocumentInApp = true;
+
+ if (!doc.Application.Visible) // && bIsTheOnlyDocumentInApp)
+ {
+ doc.Application.Visible = true;
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.NoAction_Needed;
+ return retVal;
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Hide(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningVisioDocs = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // TO DO - (doc.Application.Documents.Count == 1); not working, why?!?!? odd
+ bool bIsTrue = (doc.Application.Documents.Count == 1); // not working, why?!?!? odd
+ //bool bIsTheOnlyDocumentInApp = true;
+
+ if (doc.Application.Visible) // && bIsTheOnlyDocumentInApp)
+ {
+ doc.Application.Visible = false;
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.NoAction_Needed;
+ return retVal;
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal QueryClose(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningVisioDocs = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if (doc.Saved)
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ return retVal;
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact, out int WindowHeight, out int WindowWidth, out int WindowTop, out int WindowLeft)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ WindowTop = 0;
+ WindowLeft = 0;
+ WindowWidth = 0;
+ WindowHeight = 0;
+
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningVisioDocs = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if (bAutoSaveArtifact)
+ doc.Save();
+
+ var app = doc.Application;
+
+ // Get the Window properties
+ app.ActiveWindow.GetWindowRect(out WindowLeft, out WindowTop, out WindowWidth, out WindowHeight);
+
+ doc.Close();
+ Marshal.FinalReleaseComObject(doc); // Force Clean-up
+
+ if (app.Documents.Count == 0)
+ {
+ app.Quit();
+ Marshal.FinalReleaseComObject(app); // force clean-up
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningVisioDocs = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if(bAutoSaveArtifact)
+ doc.Save();
+
+ var app = doc.Application;
+
+ doc.Close();
+ Marshal.FinalReleaseComObject(doc); // Force Clean-up
+
+ if (app.Documents.Count == 0)
+ {
+ app.Quit();
+ Marshal.FinalReleaseComObject(app); // force clean-up
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningVisioDocs = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ doc.Save();
+
+ var app = doc.Application;
+
+ doc.Close();
+ Marshal.FinalReleaseComObject(doc); // Force Clean-up
+
+ if (app.Documents.Count == 0)
+ {
+ app.Quit();
+ Marshal.FinalReleaseComObject(app); // force clean-up
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ }
+}
diff --git a/AddIns/Addin.Office/Word.cs b/AddIns/Addin.Office/Word.cs
new file mode 100644
index 0000000..b5ab8de
--- /dev/null
+++ b/AddIns/Addin.Office/Word.cs
@@ -0,0 +1,424 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Foo.AddIn.Common;
+using System.Runtime.InteropServices;
+using System.Reflection;
+
+// Ignore 'Ambiguity' warning message, seems like no way around those
+#pragma warning disable 0467
+
+namespace Foo.Addin.Office
+{
+ public class Word_Workspace : IWorkspace
+ {
+ public const string Word_ProgId = "Word.Application";
+
+ public FuncRetVal Launch(string strArtifactLocation, int WindowHeight, int WindowWidth, int WindowTop, int WindowLeft)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ Microsoft.Office.Interop.Word.Application app = null;
+ app = Functions.GetCOMObject(Word_ProgId) as Microsoft.Office.Interop.Word.Application;
+
+ // If no existing Word App is open, open a new one
+ if (app == null)
+ {
+ app = new Microsoft.Office.Interop.Word.Application();
+ app.Visible = true;
+ }
+
+ object fileName = strArtifactLocation;
+ object missing = Missing.Value;
+ Microsoft.Office.Interop.Word.Document doc = null;
+ doc = app.Documents.Open(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
+ ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
+
+ if (doc != null)
+ {
+ // Find the correct Window and position it
+ foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
+ {
+ if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ window.Top = WindowTop;
+ window.Left = WindowLeft;
+ window.Height = WindowHeight;
+ window.Width = WindowWidth;
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ }
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Launch(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ Microsoft.Office.Interop.Word.Application app = null;
+ app = Functions.GetCOMObject(Word_ProgId) as Microsoft.Office.Interop.Word.Application;
+
+ // If no existing Word App is open, open a new one
+ if (app == null)
+ {
+ app = new Microsoft.Office.Interop.Word.Application();
+ app.Visible = true;
+ }
+
+ object fileName = strArtifactLocation;
+ object missing = Missing.Value;
+ Microsoft.Office.Interop.Word.Document doc = null;
+ doc = app.Documents.Open(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
+ ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
+
+ if (doc != null)
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ }
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Show(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningWordDocuments = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
+ {
+ foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
+ {
+ if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if (!window.Visible)
+ {
+ window.Visible = true;
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.NoAction_Needed;
+ return retVal;
+ }
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Hide(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningWordDocuments = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
+ {
+ foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
+ {
+ if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if (window.Visible)
+ {
+ window.Visible = false;
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.NoAction_Needed;
+ return retVal;
+ }
+ }
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal QueryClose(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningWordDocuments = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if (doc.Saved)
+ {
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ else
+ {
+ retVal.Type = FuncRetValEnum.Action_Failed;
+ return retVal;
+ }
+ }
+ }
+
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact, out int WindowHeight, out int WindowWidth, out int WindowTop, out int WindowLeft)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ WindowTop = 0;
+ WindowLeft = 0;
+ WindowWidth = 0;
+ WindowHeight = 0;
+
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningWordDocuments = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Found the document to close * Close it Without Prompting *
+ object saveOption = null;
+ if (bAutoSaveArtifact)
+ saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdSaveChanges;
+ else
+ saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdDoNotSaveChanges;
+
+ object originalFormat = Microsoft.Office.Interop.Word.WdOriginalFormat.wdOriginalDocumentFormat;
+ object routeDocument = false;
+ var app = doc.Application;
+
+ // Let's get the Window that belongs to this document
+ Microsoft.Office.Interop.Word.Window docWindow = null;
+ foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
+ {
+ if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
+ docWindow = window;
+ }
+
+ // Get the Window properties
+ WindowTop = docWindow.Top;
+ WindowLeft = docWindow.Left;
+ WindowWidth = docWindow.Width;
+ WindowHeight = docWindow.Height;
+
+ //Object missing = Missing.Value;
+ doc.Close(ref saveOption, ref originalFormat, ref routeDocument);
+ Marshal.FinalReleaseComObject(doc); // force clean-up
+
+ // Close the Window
+ if (docWindow != null)
+ docWindow.Close(ref saveOption, ref routeDocument);
+
+ // Close Word if this is the Last Document Instance
+ if (app.Documents.Count == 0)
+ {
+ app.Quit(ref saveOption, ref originalFormat, ref routeDocument);
+
+ Marshal.FinalReleaseComObject(docWindow);
+ Marshal.FinalReleaseComObject(app); // force clean-up, closes Process for sure
+ }
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningWordDocuments = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Found the document to close * Close it Without Prompting *
+ object saveOption = null;
+ if (bAutoSaveArtifact)
+ saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdSaveChanges;
+ else
+ saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdDoNotSaveChanges;
+
+ object originalFormat = Microsoft.Office.Interop.Word.WdOriginalFormat.wdOriginalDocumentFormat;
+ object routeDocument = false;
+ var app = doc.Application;
+
+ // Let's get the Window that belongs to this document
+ Microsoft.Office.Interop.Word.Window docWindow = null;
+ foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
+ {
+ if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
+ docWindow = window;
+ }
+
+ //Object missing = Missing.Value;
+ doc.Close(ref saveOption, ref originalFormat, ref routeDocument);
+ Marshal.FinalReleaseComObject(doc); // force clean-up
+
+ // Close the Window
+ if (docWindow != null)
+ docWindow.Close(ref saveOption, ref routeDocument);
+
+ // Close Word if this is the Last Document Instance
+ if (app.Documents.Count == 0)
+ {
+ app.Quit(ref saveOption, ref originalFormat, ref routeDocument);
+
+ Marshal.FinalReleaseComObject(docWindow);
+ Marshal.FinalReleaseComObject(app); // force clean-up, closes Process for sure
+ }
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ public FuncRetVal Close(string strArtifactLocation)
+ {
+ FuncRetVal retVal = new FuncRetVal();
+ if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
+ return retVal;
+
+ try
+ {
+ var RunningWordDocuments = Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Found the document to close * Close it Without Prompting *
+ object saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdSaveChanges;
+ object originalFormat = Microsoft.Office.Interop.Word.WdOriginalFormat.wdOriginalDocumentFormat;
+ object routeDocument = false;
+ var app = doc.Application;
+
+ // Let's get the Window that belongs to this document
+ Microsoft.Office.Interop.Word.Window docWindow = null;
+ foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
+ {
+ if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
+ docWindow = window;
+ }
+
+ //Object missing = Missing.Value;
+ doc.Close(ref saveOption, ref originalFormat, ref routeDocument);
+ Marshal.FinalReleaseComObject(doc); // force clean-up
+
+ // Close the Window
+ if (docWindow != null)
+ docWindow.Close(ref saveOption, ref routeDocument);
+
+ // Close Word if this is the Last Document Instance
+ if (app.Documents.Count == 0)
+ {
+ app.Quit(ref saveOption, ref originalFormat, ref routeDocument);
+
+ Marshal.FinalReleaseComObject(docWindow);
+ Marshal.FinalReleaseComObject(app); // force clean-up, closes Process for sure
+ }
+
+ retVal.Type = FuncRetValEnum.Action_Succeeded;
+ return retVal;
+ }
+ }
+ retVal.Type = FuncRetValEnum.ArtifactUnavailable;
+ }
+ catch (Exception e)
+ {
+ retVal.Message = e.Message;
+ retVal.Type = FuncRetValEnum.ErrorThrown;
+ }
+ return retVal;
+ }
+
+ }
+}
diff --git a/Client Services/ButtonWPForm/ButtonForm.xaml b/Client Services/ButtonWPForm/ButtonForm.xaml
new file mode 100644
index 0000000..0ea6367
--- /dev/null
+++ b/Client Services/ButtonWPForm/ButtonForm.xaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client Services/ButtonWPForm/ButtonForm.xaml.cs b/Client Services/ButtonWPForm/ButtonForm.xaml.cs
new file mode 100644
index 0000000..024ec88
--- /dev/null
+++ b/Client Services/ButtonWPForm/ButtonForm.xaml.cs
@@ -0,0 +1,211 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Runtime.InteropServices;
+using System.Drawing;
+using System.Reflection;
+using SnapshotImage = System.Drawing.Image;
+
+// Ooganizer namespaces
+using Foo.ClientServices.ButtonWPForm.ButtonFormPages;
+using Foo.Platform;
+using Foo.Platform.Win32;
+using Foo.Platform.ErrorReporting;
+using Foo.Platform.Interacters;
+using System.Windows.Interop;
+
+namespace Foo.ClientServices.ButtonWPForm
+{
+ ///
+ /// Interaction logic for ButtonWindow Form
+ ///
+ [ComVisible(false)]
+ public partial class ButtonForm : Window
+ {
+ ////
+ // Public Properties
+ ////
+ public IntPtr HookedWindow { get { return _hHookedWnd; } set { _hHookedWnd = value; } } // Passed in by FormMgr
+ public System.Drawing.Image SnapShot { get { return _SnapShot; } set { _SnapShot = value; } } // Passed in by FormMgr
+ //public Artifact Artifact { get { return _Artifact; } }
+ //public string ArtifactTitle { get { return _ArtifactTitle; } }
+ //public string ArtifactLocation { get { return _ArtifactLocation; } }
+ //public string CurrentWorkspaceName { get { return _CurrentWorkspaceName; } }
+
+ ////
+ // Private Member Variables
+ ////
+ private IntPtr _hHookedWnd = IntPtr.Zero;
+ private System.Drawing.Image _SnapShot = null;
+ private bool _PerformanceCache = false;
+ private static ButtonForm s_PerfCacheButtonFormObj = null;
+ private bool _PerfCacheLoadedHidden = false;
+ //private Artifact _Artifact;
+ //private string _ArtifactTitle;
+ //private string _ArtifactLocation;
+ //private string _CurrentWorkspaceName;
+
+ ////
+ // ButtonFormPages
+ ////
+ IButtonFormPage[] m_ButtonFormPages = new IButtonFormPage[1];
+
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// Construct WPF ButtonForm :)
+ ///
+ public ButtonForm()
+ {
+ InitializeComponent();
+ }
+
+ ///
+ /// Construct WPF ButtonForm (Performance Cache)
+ ///
+ public ButtonForm(bool bPerformanceCache)
+ {
+ if (bPerformanceCache && (s_PerfCacheButtonFormObj == null))
+ {
+ _PerformanceCache = bPerformanceCache;
+ s_PerfCacheButtonFormObj = this;
+ }
+
+ InitializeComponent();
+ }
+
+ ///
+ /// As part of Performance Caching (load one instance of this form
+ /// hidden and not visible to the user (called by FormMgr) ~also
+ /// allows to hide and existing one
+ /// ~Should only be called by FormMgr when creating the first object
+ ///
+ public void LoadHideButtonFormPerfCache()
+ {
+ if (!_PerfCacheLoadedHidden && _PerformanceCache && (s_PerfCacheButtonFormObj != null))
+ {
+ s_PerfCacheButtonFormObj.Opacity = 0;
+ s_PerfCacheButtonFormObj.WindowState = WindowState.Minimized;
+ s_PerfCacheButtonFormObj.ShowInTaskbar = false;
+ s_PerfCacheButtonFormObj.Show();
+ s_PerfCacheButtonFormObj.Hide();
+ _PerfCacheLoadedHidden = true;
+ }
+ }
+
+ ///
+ /// Window Load Event. We want all object loading to happen in the Load Event,
+ /// because we construct the WPFForm and show it right away, so this is called right at
+ /// start up, so put all the object loading in here to be cleaner and simplify FormObject Creator
+ ///
+ private void OnLoad(object sender, RoutedEventArgs args)
+ {
+ try
+ {
+ if (_PerformanceCache && (this == s_PerfCacheButtonFormObj)) // Preload child pages
+ {
+ PreloadAllChildPages();
+
+ // Add Message Hook for performance WPForm * To make sure it is always invisible *
+ HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
+ source.AddHook(new HwndSourceHook(MessageHook));
+ }
+ else if (!_PerformanceCache && (HookedWindow != IntPtr.Zero) && (this != s_PerfCacheButtonFormObj))
+ {
+ ////
+ // Resolve the Window and set the properties accordingly,
+ // our child pages depend on this information
+ ////
+ //ResolverDispatch resolver = new ResolverDispatch();
+ //ArtifactGroup artifacts = resolver.GetArtifacts(HookedWindow);
+
+ //if (artifacts.Length > 0)
+ //{
+ // _Artifact = artifacts.GetPrimary;
+ // _ArtifactTitle = _Artifact.Name;
+ // _ArtifactLocation = _Artifact.Location;
+
+ // // Workspace
+ // _CurrentWorkspaceName = SrvrCommon.GetCurrentWorkspaceName();
+
+ // // Now Load the Page
+ // LoadPageAccordingToState();
+ //}
+ //else
+ //{
+ // // Somemething went wrong Resolving
+ // UserError.Show("Document not Found", "Failed to accurately find the document for the Window");
+ // Close(); //~imp, we must close this Form
+ //}
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - A fatal error occured loading ButtonForm", MethodBase.GetCurrentMethod().Name), e);
+ Close(); //~imp, we must close this Form
+ }
+ }
+
+ ///
+ /// This Message Hook is for the Hidden WPForm that we use for better performance,
+ /// We want to make sure that it is never displayed *It can occur that explore can show it, without this*
+ ///
+ private IntPtr MessageHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
+ {
+ // force opacity at all times
+ if (Opacity == 1.0)
+ Opacity = 0.0;
+
+ // force minimized at all times
+ if (WindowState != WindowState.Minimized)
+ WindowState = WindowState.Minimized;
+
+ // force Not to be seen in taskbar
+ if (ShowInTaskbar == true)
+ ShowInTaskbar = false;
+
+ return System.IntPtr.Zero;
+ }
+
+ ///
+ /// For Performance, we need to preload all Child Pages
+ ///
+ private void PreloadAllChildPages()
+ {
+ m_ButtonFormPages[0] = (IButtonFormPage) new Page_AddEdit();
+ m_ButtonFormPages[0].ParentWPFContainer = this;
+ }
+
+ ///
+ /// Show different pages depending on the state we are in. (Currently only 1 state)
+ ///
+ private void LoadPageAccordingToState()
+ {
+ m_ButtonFormPages[0] = (IButtonFormPage) new Page_AddEdit();
+ m_ButtonFormPages[0].ParentWPFContainer = this;
+
+ if (!frmButtonForm.Navigate((Page) m_ButtonFormPages[0]))
+ Log.Info(string.Format("{0}() - ButtonForm could not navigate to Page_AddEdit", MethodBase.GetCurrentMethod().Name));
+ }
+
+ ///
+ /// When this window closes position the Hooked Window back to it's original position
+ ///
+ private void Window_Closed(object sender, EventArgs e)
+ {
+ // GUICommon.PositionWindowBackToWhereItWas(HookedWindow, true);
+ BHInteracter.SetAsActiveWindow(HookedWindow);
+ }
+ }
+}
diff --git a/Client Services/ButtonWPForm/ButtonFormMgr.cs b/Client Services/ButtonWPForm/ButtonFormMgr.cs
new file mode 100644
index 0000000..ee6ae40
--- /dev/null
+++ b/Client Services/ButtonWPForm/ButtonFormMgr.cs
@@ -0,0 +1,324 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Drawing;
+using System.Threading;
+using System.Windows.Interop;
+using System.EnterpriseServices;
+using System.Windows;
+using System.IO;
+using System.Windows.Threading;
+using System.Collections;
+using System.Reflection;
+
+// Ooganizer Namespaces
+using Foo.Platform;
+using Foo.Platform.Win32;
+
+namespace Foo.ClientServices.ButtonWPForm
+{
+ ///
+ /// This class manages the creation/deletion and actions of (1 - n) ButtonForms
+ ///
+ [ComVisible(false)]
+ internal class ButtonFormMgr
+ {
+ private const int INITIAL_OBJECT_CAPACITY = 30;
+ private Hashtable m_ObjectList = null;
+ private Dispatcher m_Dispatcher = null;
+
+ // we have one btnForm loaded (hidden) always, as a performance cache
+ private ButtonForm m_btnForm = null;
+ private bool m_IsBtnFormCached = false;
+
+ // Imp! - allows external caller to run any action on a ButtonForm
+ public delegate void _Action(ButtonForm btnForm);
+
+ //custom private delegates
+ private delegate void delegate_Create(int hParentWND, Image snapshot);
+ private delegate void delegate_Delete(int hParentWND);
+ private delegate int delegate_CreateWindow(int hParentWND);
+ private delegate void delegate_Action(int hParentWND, _Action action);
+
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public ButtonFormMgr(Dispatcher disp)
+ {
+ m_ObjectList = new Hashtable();
+ m_Dispatcher = disp;
+
+ if (!m_IsBtnFormCached)
+ BetterPerformance();
+ }
+
+ ///
+ /// Calls Create_ButtonForm via Dispatcher if neccessary
+ ///
+ /// handle to Parent/Owner Window
+ public void Create_ButtonFormDISP(int hParentWND, Image snapshot)
+ {
+ if (hParentWND != 0)
+ {
+ if (m_Dispatcher.Thread == Thread.CurrentThread)
+ {
+ Create_ButtonForm(hParentWND, snapshot);
+ }
+ else
+ {
+ object[] parameters = new object[] { hParentWND, snapshot };
+ m_Dispatcher.Invoke((delegate_Create)Create_ButtonFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
+ }
+ }
+ }
+
+ ///
+ /// Calls Create_ButtonFormWindow via Dispatcher if neccessary
+ ///
+ /// handle to Parent/Owner Window
+ public int Create_ButtonFormWindowDISP(int hParentWND)
+ {
+ if (hParentWND != 0)
+ {
+ if (m_Dispatcher.Thread == Thread.CurrentThread)
+ {
+ return Create_ButtonFormWindow(hParentWND);
+ }
+ else
+ {
+ object[] parameters = new object[] { hParentWND };
+ return (int)m_Dispatcher.Invoke((delegate_CreateWindow)Create_ButtonFormWindowDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
+ }
+ }
+ return 0;
+ }
+
+ ///
+ /// Calls Delete_ButtonForm via Dispatcher if neccessary
+ ///
+ /// handle to Parent/Owner Window
+ public void Delete_ButtonFormDISP(int hParentWND)
+ {
+ if (hParentWND != 0)
+ {
+ if (m_Dispatcher.Thread == Thread.CurrentThread)
+ {
+ Delete_ButtonForm(hParentWND);
+ }
+ else
+ {
+ object[] parameters = new object[] { hParentWND };
+ m_Dispatcher.Invoke((delegate_Delete)Delete_ButtonFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
+ }
+ }
+ }
+
+ ///
+ /// Use this Dispatching Action Function to run any _Action on the ButtonForm
+ ///
+ /// handle to Parent/Owner Window
+ public void RunAction_ButtonFormDISP(int hParentWND, _Action action)
+ {
+ if (hParentWND != 0)
+ {
+ if (m_Dispatcher.Thread == Thread.CurrentThread)
+ {
+ RunAction_ButtonForm(hParentWND, action);
+ }
+ else
+ {
+ object[] parameters = new object[] { hParentWND, action };
+ m_Dispatcher.Invoke((delegate_Action)RunAction_ButtonFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
+ }
+ }
+ }
+
+ ///
+ /// Calls Terminate via Dispatcher if neccessary
+ ///
+ /// handle to Parent/Owner Window
+ public void TerminateDISP()
+ {
+ if (m_Dispatcher.Thread == Thread.CurrentThread)
+ {
+ Terminate();
+ }
+ else
+ {
+ m_Dispatcher.Invoke((Action)TerminateDISP, System.Windows.Threading.DispatcherPriority.Normal, null);
+ }
+ }
+
+ ///
+ /// Creates a new ButtonForm object into the ObjectList
+ ///
+ /// handle to Parent/Owner Window
+ private void Create_ButtonForm(int hParentWND, Image snapshot)
+ {
+ try
+ {
+ if (!m_IsBtnFormCached)
+ BetterPerformance();
+
+ m_ObjectList[hParentWND] = new ButtonForm();
+ ButtonForm btnForm = (ButtonForm)m_ObjectList[hParentWND];
+
+ if (btnForm != null)
+ {
+ // We use the InteropHelper to set the Owner Property
+ WindowInteropHelper InteropHelper = new WindowInteropHelper(btnForm);
+ InteropHelper.Owner = (IntPtr)hParentWND;
+
+ // Set the important Fields into the Button Form
+ btnForm.HookedWindow = (IntPtr)hParentWND; // give it the handle to the hooked window
+ btnForm.SnapShot = snapshot; // give it the snapshot of the window
+
+ RECT ParentWndRect = new RECT();
+ Win32Functions.GetWindowRect((IntPtr)hParentWND, out ParentWndRect);
+
+ // Get Initial Location for the form
+ btnForm.Top = ParentWndRect.top;
+ btnForm.Left = ParentWndRect.left;
+
+ // Get Initial Height and Width of the form
+ btnForm.Height = (ParentWndRect.bottom - ParentWndRect.top);
+ btnForm.Width = (ParentWndRect.right - ParentWndRect.left);
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ }
+
+ ///
+ /// Use this function to delete the ButtonForm Object
+ ///
+ /// handle to Parent/Owner Window
+ private void Delete_ButtonForm(int hParentWND)
+ {
+ try
+ {
+ if (m_ObjectList.ContainsKey(hParentWND))
+ {
+ ButtonForm btnForm = (ButtonForm)m_ObjectList[hParentWND];
+ if (btnForm != null)
+ {
+ m_ObjectList.Remove(hParentWND);
+ btnForm.Close();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ }
+
+ ///
+ /// Use this to run void() function actions on the specified buttonform
+ ///
+ /// handle to Parent/Owner Window
+ /// a pointer to a delegate (action function) to run
+ private void RunAction_ButtonForm(int hParentWND, _Action action)
+ {
+ try
+ {
+ if (m_ObjectList.ContainsKey(hParentWND))
+ {
+ ButtonForm btnForm = (ButtonForm)m_ObjectList[hParentWND];
+ if (btnForm != null)
+ action(btnForm);
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ }
+
+ ///
+ /// Use this to actually create the Window, call this after calling Create_ButtonForm
+ /// This will create the window by calling Show(), this will also show the window
+ ///
+ /// handle to Parent/Owner Window
+ /// the Handle to the newly created window object
+ private int Create_ButtonFormWindow(int hParentWND)
+ {
+ try
+ {
+ if (m_ObjectList.ContainsKey(hParentWND))
+ {
+ ButtonForm btnForm = (ButtonForm)m_ObjectList[hParentWND];
+
+ // We use the InteropHelper to see if this WPFForm has been created previously
+ WindowInteropHelper InteropHelper = new WindowInteropHelper(btnForm);
+ if (InteropHelper.Handle == IntPtr.Zero)
+ {
+ btnForm.Show();
+ }
+ return (int)InteropHelper.Handle;
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ return 0;
+ }
+
+ ///
+ /// Kills all ButtonForm Instances (STOPS ALL)
+ ///
+ private void Terminate()
+ {
+ try
+ {
+ foreach (object o in m_ObjectList)
+ {
+ if ((o != null) && (o is ButtonForm))
+ {
+ ButtonForm btnForm = (ButtonForm)o;
+ btnForm.Close();
+ }
+ }
+ m_ObjectList.Clear();
+
+ if (m_IsBtnFormCached)
+ {
+ m_btnForm.Close();
+ m_IsBtnFormCached = false;
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ }
+
+ ///
+ /// In order to improve first WPForm performance we have one
+ /// WPForm ButtonForm loaded at all times. (opacity set to 0).
+ /// ~it has no parent setting so it is just a form of the desktop
+ ///
+ private void BetterPerformance()
+ {
+ if (!m_IsBtnFormCached)
+ {
+ try
+ {
+ // Performance Cache (keeps a window loaded always)
+ m_btnForm = new ButtonForm(true);
+ m_btnForm.LoadHideButtonFormPerfCache();
+ m_IsBtnFormCached = true;
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ }
+ }
+ }
+}
diff --git a/Client Services/ButtonWPForm/ButtonFormPages/Page_AddEdit.xaml b/Client Services/ButtonWPForm/ButtonFormPages/Page_AddEdit.xaml
new file mode 100644
index 0000000..0ca688a
--- /dev/null
+++ b/Client Services/ButtonWPForm/ButtonFormPages/Page_AddEdit.xaml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client Services/ButtonWPForm/ButtonFormPages/Page_AddEdit.xaml.cs b/Client Services/ButtonWPForm/ButtonFormPages/Page_AddEdit.xaml.cs
new file mode 100644
index 0000000..379dd39
--- /dev/null
+++ b/Client Services/ButtonWPForm/ButtonFormPages/Page_AddEdit.xaml.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Reflection;
+
+// Ooganizer Namespaces
+using Foo.Platform;
+using Foo.Platform.Interacters;
+
+namespace Foo.ClientServices.ButtonWPForm.ButtonFormPages
+{
+ ///
+ /// Interaction logic for ButtonFormPage_AddEdit.xaml
+ ///
+ public partial class Page_AddEdit : Page, IButtonFormPage
+ {
+ #region IButtonFormPage
+ public ButtonForm ParentWPFContainer { get { return _ButtonForm; } set { _ButtonForm = value; } }
+ private ButtonForm _ButtonForm = null;
+ #endregion
+
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public Page_AddEdit()
+ {
+ InitializeComponent();
+ }
+
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (ParentWPFContainer == null)
+ {
+ Log.Debug(string.Format("{0}() - ParentWPFContainer is null this should never happen", MethodBase.GetCurrentMethod().Name));
+ return;
+ }
+
+ // Set the Artifact Properties
+ //txtTitle.Text = ParentWPFContainer.ArtifactTitle;
+
+ // se
+ //txtLocation.Text = ParentWPFContainer.ArtifactLocation;
+ //txtLocation.ScrollToEnd();
+
+ // Add all workspaces to the combo selection
+ //foreach (Ooganizer.API.Workspace wspace in SrvrCommon.Workspaces)
+ // comboWorkspaces.Items.Add(wspace.Name);
+
+ ////
+ // Default to the current Workspace or 0 if none are loaded
+ ////
+ //if (ParentWPFContainer.CurrentWorkspaceName == "")
+ // comboWorkspaces.SelectedIndex = 0;
+ //else
+ // comboWorkspaces.SelectedValue = ParentWPFContainer.CurrentWorkspaceName;
+ }
+
+ private void btnCancel_Click(object sender, RoutedEventArgs e)
+ {
+ BHInteracter.SetW32ButtonToNewState(ParentWPFContainer.HookedWindow, BHInteracter.BUTTON_HOOK_STATE.BUTTON_ADD);
+ ParentWPFContainer.Close();
+ }
+
+ private void btnAdd_Click(object sender, RoutedEventArgs e)
+ {
+ //SrvrCommon.AddArtifactToWorkspace(txtTitle.Text, txtLocation.Text, ParentWPFContainer.SnapShot, ParentWPFContainer.CurrentWorkspaceName);
+ //BHInteracter.SetW32ButtonToNewState(ParentWPFContainer.HookedWindow, BHInteracter.BUTTON_HOOK_STATE.BUTTON_DELETE);
+ ParentWPFContainer.Close();
+ }
+ }
+}
diff --git a/Client Services/ButtonWPForm/ButtonWPForm.csproj b/Client Services/ButtonWPForm/ButtonWPForm.csproj
new file mode 100644
index 0000000..4da5816
--- /dev/null
+++ b/Client Services/ButtonWPForm/ButtonWPForm.csproj
@@ -0,0 +1,156 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {E179DF39-539A-407F-94DE-C21F690E02C4}
+ Library
+ Properties
+ Foo.ClientServices.ButtonWPForm
+ ButtonWPForm
+ v3.5
+ 512
+ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 4
+
+
+
+
+
+
+
+
+
+
+ true
+ MyKeyFile.SNK
+
+
+ true
+ full
+ false
+ ..\..\Target\Debug\
+ TRACE;DEBUG
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\..\Target\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ False
+ ..\..\Components\log4net.dll
+
+
+
+ 3.5
+
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+ 3.0
+
+
+ 3.0
+
+
+ 3.0
+
+
+ 3.0
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+ Designer
+ MSBuild:Compile
+
+
+ ButtonForm.xaml
+ Code
+
+
+
+
+
+ Page_AddEdit.xaml
+
+
+
+
+
+
+
+
+
+ Code
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
+
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}
+ DataAccessLayer
+
+
+ {C1282050-455B-44F4-8520-1C005E38EFB2}
+ GUILib
+
+
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}
+ Platform
+
+
+
+
+
+ $(FrameworkDir)\regasm.exe "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /unregister
+$(FrameworkDir)\regasm.exe "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /tlb:$(TargetName).tlb /codebase
+REM $(FrameworkDir)\regsvcs.exe /reconfig "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /appdir:"$(SolutionDir)target\$(ConfigurationName)"
+
+
\ No newline at end of file
diff --git a/Client Services/ButtonWPForm/ButtonWPFormCCW.cs b/Client Services/ButtonWPForm/ButtonWPFormCCW.cs
new file mode 100644
index 0000000..7b18ef1
--- /dev/null
+++ b/Client Services/ButtonWPForm/ButtonWPFormCCW.cs
@@ -0,0 +1,249 @@
+
+// For GUIDebugStepExe Debugging Only - Uncomment this #define
+#define GUIDEBUGSTEPEXE
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Drawing;
+using System.Threading;
+using System.Windows.Interop;
+using System.EnterpriseServices;
+using System.Windows;
+using System.IO;
+using System.Windows.Threading;
+using System.Collections;
+using System.Reflection;
+
+// Ooganizer Namespaces
+using Foo.GUILib;
+using Foo.Platform;
+using Foo.Platform.Win32;
+using Foo.Platform.Interacters;
+using Foo.Platform.ErrorReporting;
+
+namespace Foo.ClientServices.ButtonWPForm
+{
+
+ ///
+ /// ButtonWPFormCCW - Com Callable Wrapper Class exposed to ButtonHook.
+ /// This class is responsible for creating the ButtonWPForm (a form created in response to a ButtonHook W32 Click)
+ ///
+ [Guid("6F108F0B-9CEB-4d3d-B1D9-7685F9F39E50")]
+ [ClassInterface(ClassInterfaceType.None)]
+ [ProgId("Foo.ClientServices.ButtonWPFormCCW")]
+ [ComVisible(true)]
+ [ObjectPooling(Enabled = true, MinPoolSize = 1, MaxPoolSize = 2500, CreationTimeout = 5000)]
+#if GUIDEBUGSTEPEXE
+ public class ButtonWPFormCCW : IButtonForm, IClientEvents
+#else
+ public class ButtonWPFormCCW : ServicedComponent, IButtonForm, IClientEvents, IProcessInitializer
+#endif
+ {
+
+ ////
+ // Member Variables
+ ////
+ private IntPtr m_hWnd = IntPtr.Zero;
+ private IntPtr m_hWndParent = IntPtr.Zero;
+ private IntPtr m_hWndButton = IntPtr.Zero;
+
+ BHInteracter.BUTTON_HOOK_STATE m_ButtonState = BHInteracter.BUTTON_HOOK_STATE.BUTTON_NONE;
+
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ #region Construction / Destruction
+ public ButtonWPFormCCW() {}
+ ~ButtonWPFormCCW() {}
+ #endregion
+
+#if GUIDEBUGSTEPEXE
+ #region GuiDebugStepCustomStarterStopers
+ public void Start()
+ {
+ Log.Info(string.Format("{0}() - ComponentState Application Is being started", MethodBase.GetCurrentMethod().Name));
+ ComponentState.ApplicationIsRunning = true;
+ }
+ public void Stop()
+ {
+ Log.Info(string.Format("{0}() - ComponentState Application Is being stopped", MethodBase.GetCurrentMethod().Name));
+ ComponentState.ApplicationIsRunning = false;
+ }
+ #endregion
+#else
+ #region IProcessInitializer Members
+ public void Startup(object punkProcessControl)
+ {
+ Log.Info(string.Format("{0}() - ComponentState Application Is being started", MethodBase.GetCurrentMethod().Name));
+ ComponentState.ApplicationIsRunning = true;
+ }
+
+ public void Shutdown()
+ {
+ Log.Info(string.Format("{0}() - ComponentState Application Is being stopped", MethodBase.GetCurrentMethod().Name));
+ ComponentState.ApplicationIsRunning = false;
+ }
+ #endregion
+#endif
+
+ #region ButtonHook Activation/Deactivation
+ ///
+ /// This is called first time when the buttonhook is attaching into a Window. It passes us
+ /// important handle information that we need or may need to communicate back state information.
+ ///
+ /// the handle to the window the buttonhook is hooked into
+ /// the handle to the button Window (we need it if we want to communicat with it)
+ public void WPFThreadProc_ButtonWPForm_Activated(int hParentWND, int hButtonWND)
+ {
+ // Store the handle information for later use
+ m_hWndParent = (IntPtr)hParentWND;
+ m_hWndButton = (IntPtr)hButtonWND;
+ }
+
+ ///
+ /// Called when the buttonhook is unattaching itself from a Window.
+ /// Here, we can do any cleanup that we may have to do.
+ ///
+ public void WPFThreadProc_ButtonWPForm_Deactivated()
+ {
+ try
+ {
+ if ((m_hWndParent != IntPtr.Zero) && (ComponentState.ButtonFormMgr != null))
+ ComponentState.ButtonFormMgr.Delete_ButtonFormDISP((int)m_hWndParent);
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ }
+ #endregion
+
+ #region Custom Events
+ ///
+ /// This function is called when the Win32 button is clicked. This function should
+ /// handle the creation of the wpfform and display it over the window
+ ///
+ /// the window handle to the newly created wpfform to be stored by the caller
+ public int W32BUTTONCLICKED()
+ {
+ try
+ {
+ // Let's Position the Window and snapshot it...
+ Image snapshot = null;
+ try
+ {
+ BHInteracter.SetW32ButtonToNewState(m_hWndParent, BHInteracter.BUTTON_HOOK_STATE.BUTTON_NONE);
+ System.Threading.Thread.Sleep(100);
+ snapshot = GUICommon.PositionWindowToGoldenPosAndTakeSnapshot(m_hWndParent, true);
+ }
+ catch (Exception e)
+ {
+ UserError.Show("Snapshot Failed", "Obtaining a Snaphot for the Window Failed.");
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ return 0;
+ }
+
+ if (snapshot != null)
+ {
+ // Create the WpfForm object and then create the wpfform window and show it.
+ ComponentState.ButtonFormMgr.Create_ButtonFormDISP((int)m_hWndParent, snapshot);
+ m_hWnd = (IntPtr) ComponentState.ButtonFormMgr.Create_ButtonFormWindowDISP((int)m_hWndParent);
+ return (int)m_hWnd;
+ }
+ else
+ {
+ UserError.Show("Snapshot Failed", "Obtaining a Snaphot for the Window Failed.");
+ Log.Error(string.Format("{0}() - UserError.Show() - Obtaining a Snapshot Failed", MethodBase.GetCurrentMethod().Name));
+ return 0;
+ }
+ }
+ catch (Exception e)
+ {
+ UserError.Show("Snapshot Failed", "Obtaining a Snaphot for the Window Failed.");
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ return 0;
+ }
+ }
+ #endregion
+
+ #region Window Events we can extend on
+ public void WindowEvent_MaximizeOccured(int nHeight, int nWidth)
+ {
+ }
+
+ public void WindowEvent_MinimizeOccured()
+ {
+ }
+
+ public void WindowEvent_WindowActivated()
+ {
+ }
+
+ public void WindowEvent_WindowDeactivated()
+ {
+ }
+ #endregion
+
+ #region Resolver Client Events
+ public void ReResolve(int pid, IntPtr hWnd)
+ {
+ Log.Debug(string.Format("{0}() - Debug - ReResolve is called for {0} and {1}", pid, hWnd));
+ }
+
+ public void hWndInitialActivate(int pid, IntPtr hWnd, string ProcessStartUpPrms)
+ {
+ try
+ {
+
+ m_ButtonState = BHInteracter.SetW32ButtonToNewState(m_hWndParent, BHInteracter.BUTTON_HOOK_STATE.BUTTON_ADD);
+
+ Log.Debug(string.Format("{0}() - --- TEST --- ProcessStartUpPrms", ProcessStartUpPrms));
+
+ //// We need to resolve the window here
+ //ResolverDispatch resolver = new Resolver.ResolverDispatch();
+ //ArtifactGroup artifacts = resolver.GetArtifacts((IntPtr)hWnd);
+
+ //// If we can resolve this window then we want to be checking
+ //if (artifacts.Length >= 1)
+ //{
+ // Artifact curArtifact = artifacts.GetPrimary;
+ // bool bFound = SrvrCommon.IsArtifactInCurrentWorkspace(curArtifact);
+
+ // if (bFound)
+ // m_ButtonState = BHInteracter.SetW32ButtonToNewState(m_hWndParent, BHInteracter.BUTTON_HOOK_STATE.BUTTON_DELETE);
+ // else
+ // m_ButtonState = BHInteracter.SetW32ButtonToNewState(m_hWndParent, BHInteracter.BUTTON_HOOK_STATE.BUTTON_ADD);
+ //}
+ //else
+ //{
+ // Log.Error(string.Format("{0}() - WPForm could not resolve this Window - disabling the Caption Button", MethodBase.GetCurrentMethod().Name));
+ // m_ButtonState = BHInteracter.SetW32ButtonToNewState(m_hWndParent, BHInteracter.BUTTON_HOOK_STATE.BUTTON_NONE);
+ //}
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - WPForm could not resolve this Window - disabling the Caption Button", MethodBase.GetCurrentMethod().Name), e);
+ }
+ }
+
+ public void hWndLastDeactivate(int pid, IntPtr hWnd)
+ {
+ Log.Debug(string.Format("{0}() - Debug - hWndLastDeactivate is called for {0} and {1}", pid, hWnd));
+ }
+
+ public void DragNDropOccured(int pid, IntPtr hWnd, int nFiles, string SemiColonSepFileNames)
+ {
+ Log.Debug(string.Format("{0}() - Debug - DragNDropOccured is called with {0} and {1} and {2}", pid, hWnd, nFiles, SemiColonSepFileNames));
+ }
+
+ public void OpenOrSaveFileDialogOccured(int pid, IntPtr hWnd, string possibleLocAndFileName, string FileTypes)
+ {
+ Log.Debug(string.Format("{0}() - Debug - DragNDropOccured is called with {0} and {1} and {2}", pid, hWnd, possibleLocAndFileName, FileTypes));
+ }
+ #endregion
+
+ }
+}
diff --git a/Client Services/ButtonWPForm/CaptionButtonStarter.cs b/Client Services/ButtonWPForm/CaptionButtonStarter.cs
new file mode 100644
index 0000000..8f2c8f6
--- /dev/null
+++ b/Client Services/ButtonWPForm/CaptionButtonStarter.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Reflection;
+
+// Ooganizer Namespaces
+using Foo.Platform;
+using Foo.Platform.Interacters;
+
+namespace Foo.ClientServices.ButtonWPForm
+{
+ ///
+ /// This class manages the creation/deletion of a Oogy CaptionButton Instance Exe.
+ /// A CaptionButton Instance hosts the ButtonHook.dll
+ ///
+ [ComVisible(false)]
+ internal class CaptionButtonStarter
+ {
+
+ // CaptionButton (ButtonHook.dll) Startup Delay
+ private const int CAPTIONBUTTON_STARTUP_DELAY_MILISECONDS = 4000;
+
+ // Member Variables
+ private static Thread s_ButtonHookKeepAliveThread = null;
+ private static bool s_ButtonHookKeepAliveThreadIsInitialized = false;
+
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// Constructor by default will launch the thread if needed
+ ///
+ static CaptionButtonStarter()
+ {
+ StartButtonHookKeepAliveThreadIfNeeded();
+ }
+
+ ///
+ /// Use this property to set the CaptionButton to running / not running
+ ///
+ public static bool Run
+ {
+ get { return s_ButtonHookKeepAliveThreadIsInitialized; }
+ set
+ {
+ if (!value)
+ TerminateButtonHookKeepAliveThreadIfNeeded();
+
+ s_ButtonHookKeepAliveThreadIsInitialized = value;
+ }
+ }
+
+ ///
+ /// ButtonHookKeepAliveThread Thread for ButtonHook.dll - handled internally
+ ///
+ private static void ButtonHookKeepAliveThreadProc()
+ {
+ Thread.Sleep(CAPTIONBUTTON_STARTUP_DELAY_MILISECONDS);
+ while (true) // Make Sure ButtonHook stays alive (No User kills it for any reason)
+ {
+ if (!BHInteracter.IsCaptionButtonRunning())
+ {
+ Log.Info(string.Format("{0}() - ButtonHookKeepAliveThread - About to call StartCaptionButton()", MethodBase.GetCurrentMethod().Name));
+
+ // Launch OogyCaptionButton Process EXE
+ BHInteracter.StartCaptionButton();
+
+ // wait a little before checking again...
+ Thread.Sleep(100);
+
+ if (BHInteracter.IsCaptionButtonRunning())
+ Log.Info(string.Format("{0}() - StartCaptionButton() Succeeded", MethodBase.GetCurrentMethod().Name));
+ else
+ Log.Error(string.Format("{0}() - StartCaptionButton() Failed", MethodBase.GetCurrentMethod().Name));
+ }
+
+ if (!s_ButtonHookKeepAliveThreadIsInitialized)
+ {
+ s_ButtonHookKeepAliveThreadIsInitialized = true;
+ Log.Info(string.Format("{0}() - ButtonWPForm ButtonHookKeepAliveThread is initialized s_ButtonHookKeepAliveThreadIsInitialized is True", MethodBase.GetCurrentMethod().Name));
+ }
+
+ // Checking every 30 seconds (quickly) should be more than enough
+ Thread.Sleep(30000);
+ }
+ }
+
+ ///
+ /// Use this function to start ThreadProc(above) if needed. COM+ can shutdown the thread anytime,
+ /// we need to make sure that the thread is alive BEFORE calling ButtonForms
+ ///
+ private static void StartButtonHookKeepAliveThreadIfNeeded()
+ {
+ if (s_ButtonHookKeepAliveThread != null && s_ButtonHookKeepAliveThread.IsAlive)
+ {
+ return;
+ }
+ else
+ {
+ s_ButtonHookKeepAliveThreadIsInitialized = false;
+
+ // Start a new Thread so it can become the Message Loop
+ s_ButtonHookKeepAliveThread = new Thread(new ThreadStart(CaptionButtonStarter.ButtonHookKeepAliveThreadProc));
+
+ // GUI components require the thread to be STA; otherwise throws an error
+ s_ButtonHookKeepAliveThread.SetApartmentState(ApartmentState.STA);
+ s_ButtonHookKeepAliveThread.Start();
+ }
+ }
+
+ ///
+ /// Terminate the ButtonHook.dll by killing the Process
+ ///
+ private static void TerminateButtonHookKeepAliveThreadIfNeeded()
+ {
+ if (s_ButtonHookKeepAliveThreadIsInitialized)
+ {
+ s_ButtonHookKeepAliveThread.Abort();
+ s_ButtonHookKeepAliveThreadIsInitialized = false;
+ Log.Info(string.Format("{0}() - ButtonWPForm is ButtonHookKeepAliveThread shutdown s_ButtonHookKeepAliveThreadIsInitialized is False", MethodBase.GetCurrentMethod().Name));
+
+ // Kill the OogyCaptionButton Process EXE
+ BHInteracter.StopCaptionButton();
+ }
+ }
+
+ }
+}
diff --git a/Client Services/ButtonWPForm/ComponentState.cs b/Client Services/ButtonWPForm/ComponentState.cs
new file mode 100644
index 0000000..af033ec
--- /dev/null
+++ b/Client Services/ButtonWPForm/ComponentState.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Reflection;
+using System.Threading;
+
+// Ooganizer Namespaces
+using Foo.Platform;
+using Foo.DataAccessLayer;
+using Foo.DataAccessLayer.DataTypes;
+using System.Runtime.InteropServices;
+
+namespace Foo.ClientServices.ButtonWPForm
+{
+ ///
+ /// This class is responsible for launch all secondary threads required for this application as
+ /// well as hold any variables that are needed by all classes
+ /// created.
+ ///
+ [ComVisible(false)]
+ internal class ComponentState
+ {
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// This class manages the state / main variables of the COM+ that maybe needed by multiple classes.
+ /// It is responsible for starting and stopping any secondary threads.
+ ///
+ static ComponentState()
+ {
+ // We must subscribe to assembly resolver
+ Log.Info(string.Format("{0}() - ButtonWPFormCCW ComponentState() called. Application is starting...", MethodBase.GetCurrentMethod().Name));
+
+ // Let's Preload the Database *Right here, right now* that should be good for all of us
+ Data.Artifacts.DoesArtifactExistInSystem(DataTypeHelpers.CreateLocationOnlyArtifact("C:\\Dummy.file"));
+
+ // Start Dispatcher Thread
+ Log.Info(string.Format("{0}() - ButtonWPFormCCW ComponentState() called. Activating DispatcherThread", MethodBase.GetCurrentMethod().Name));
+ DispatcherThread.Run = true;
+
+ // Start ButtonHookKeepAlive Thread
+ if (!DebugSpec.SkipCaptionButtonStarter)
+ {
+ Log.Info(string.Format("{0}() - ButtonWPFormCCW ComponentState() called. Calling CaptionButtonStarter", MethodBase.GetCurrentMethod().Name));
+ CaptionButtonStarter.Run = true;
+ }
+ else
+ {
+ Log.Info(string.Format("{0}() - ButtonWPFormCCW ComponentState() called. Skipping CaptionButtonStarter due to DebugSpec Settings", MethodBase.GetCurrentMethod().Name));
+ }
+ }
+
+ ///
+ /// Private Variables
+ ///
+ private static bool s_bApplicationIsRunning = false;
+
+ ///
+ /// Use this to enable/disable all threads and variables for
+ /// the component states
+ ///
+ public static bool ApplicationIsRunning
+ {
+ get { return s_bApplicationIsRunning; }
+ set
+ {
+ if (!value)
+ {
+ Log.Info(string.Format("{0}() - ComponentState() sApplicationRunning set to False", MethodBase.GetCurrentMethod().Name));
+ DispatcherThread.Run = false;
+ CaptionButtonStarter.Run = false;
+ }
+
+ s_bApplicationIsRunning = value;
+ }
+ }
+
+ ///
+ /// Use this to access the ButtonFormMgr Object in order to
+ /// communicate to ButtonForms (Setter should only be called by
+ /// DispatcherThread)
+ ///
+ public static ButtonFormMgr ButtonFormMgr
+ {
+ get { return DispatcherThread.s_ButtonFormMgr; }
+ }
+ }
+}
diff --git a/Client Services/ButtonWPForm/DispatcherThread.cs b/Client Services/ButtonWPForm/DispatcherThread.cs
new file mode 100644
index 0000000..f9439e8
--- /dev/null
+++ b/Client Services/ButtonWPForm/DispatcherThread.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Reflection;
+
+// Ooganizer Namespaces
+using Foo.Platform;
+using System.Windows.Threading;
+
+namespace Foo.ClientServices.ButtonWPForm
+{
+ ///
+ /// This class is responsible for creation and deltion of ButtonFormMgr.cs on a
+ /// Dispatcher Thread. ~The Dispatcher is responsible for all the messages being passed
+ /// for the Form Objects, it must be running at all times and created before any forms get
+ /// created.
+ ///
+ [ComVisible(false)]
+ class DispatcherThread
+ {
+
+ // Member Variables
+ private static Thread s_DispatcherThread = null;
+ private static bool s_DispatcherThreadIsInitialized = false;
+ internal static ButtonFormMgr s_ButtonFormMgr = null;
+
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// Constructor by default will launch the thread if needed
+ ///
+ static DispatcherThread()
+ {
+ Log.Info(string.Format("{0}() - DispatcherThread() called", MethodBase.GetCurrentMethod().Name));
+ StartDispatcherThreadIfNeeded();
+ }
+
+ ///
+ /// Use this property to set the Dispatcher to running / not running
+ ///
+ public static bool Run
+ {
+ get { return s_DispatcherThreadIsInitialized; }
+ set
+ {
+ if (!value)
+ TerminateDispatcherThreadIfNeeded();
+
+ s_DispatcherThreadIsInitialized = value;
+ }
+ }
+
+ ///
+ /// Message Loop Thread for ButtonForm
+ ///
+ private static void DispatcherThreadProc()
+ {
+ // Create ButtonFormMgr Object on this thread *Allow global access to the object*
+ Log.Info(string.Format("{0}() - About to new ButtonFormMgr via DispatcherThread", MethodBase.GetCurrentMethod().Name));
+ s_ButtonFormMgr = new ButtonFormMgr(Dispatcher.CurrentDispatcher);
+
+ Log.Info(string.Format("{0}() - ButtonWPForm DispatcherThread is initialized s_DispatcherThreadIsInitialized is True", MethodBase.GetCurrentMethod().Name));
+ s_DispatcherThreadIsInitialized = true; // always set to true to allow caller to exit out
+
+ if (s_ButtonFormMgr != null)
+ {
+ Log.Info(string.Format("{0}() - ButtonFormMgr Launched via DispatcherThread", MethodBase.GetCurrentMethod().Name));
+
+ //Enter Dispatcher Message Loop
+ System.Windows.Threading.Dispatcher.Run();
+ }
+ else
+ {
+ Log.Error(string.Format("{0}() - ButtonFormMgr Launch Failed! Exiting Thread - Major Error must have occured", MethodBase.GetCurrentMethod().Name));
+ // exit thread - no need to stay here
+ }
+ }
+
+ ///
+ /// Use this function to start ThreadProc(above) if needed. COM+ can shutdown the thread anytime,
+ /// we need to make sure that the thread is alive BEFORE calling ButtonForms
+ ///
+ private static void StartDispatcherThreadIfNeeded()
+ {
+ if (s_DispatcherThread != null && s_DispatcherThread.IsAlive)
+ {
+ return;
+ }
+ else
+ {
+ s_DispatcherThreadIsInitialized = false;
+
+ // Start a new Thread so it can become the Message Loop
+ s_DispatcherThread = new Thread(new ThreadStart(DispatcherThread.DispatcherThreadProc));
+
+ // GUI components require the thread to be STA; otherwise throws an error
+ s_DispatcherThread.SetApartmentState(ApartmentState.STA);
+ Log.Info(string.Format("{0}() - Starting DispatcherThread...", MethodBase.GetCurrentMethod().Name));
+ s_DispatcherThread.Start();
+ Log.Info(string.Format("{0}() - DispatcherThread Started.", MethodBase.GetCurrentMethod().Name));
+
+ // Make sure the Application Object is running
+ // (COM will eventually just time out otherwise)
+ //while (!s_DispatcherThreadIsInitialized)
+ // System.Threading.Thread.Sleep(20); // Syncronous call
+ }
+ }
+
+ ///
+ /// Terminates all ButtonForm Objects and the Message Dispatcher Thread *do this only on shutdown*
+ ///
+ private static void TerminateDispatcherThreadIfNeeded()
+ {
+ if (s_DispatcherThreadIsInitialized)
+ {
+ // Delete ButtonFormMgr and all ButtonForms from this thread
+ s_ButtonFormMgr.TerminateDISP();
+ s_ButtonFormMgr = null;
+
+ s_DispatcherThread.Abort();
+ s_DispatcherThreadIsInitialized = false;
+ Log.Info(string.Format("{0}() - ButtonWPForm is DispatcherThread shutdown s_DispatcherThreadIsInitialized is False", MethodBase.GetCurrentMethod().Name));
+ }
+ }
+
+ }
+}
diff --git a/Client Services/ButtonWPForm/IButtonForm.cs b/Client Services/ButtonWPForm/IButtonForm.cs
new file mode 100644
index 0000000..ff6bf29
--- /dev/null
+++ b/Client Services/ButtonWPForm/IButtonForm.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace Foo.ClientServices.ButtonWPForm
+{
+ ///
+ /// Button Hook uses the IButtonForm Interface to call into ButtonFormCCW.
+ /// This allows ButtonHook to communicate to us the state ButtonFormCCW should take.
+ /// ButtonForm will handle the methods/Events below and respond as needed.
+ /// ~We use the hParentWND to track which ButtonForm Instance we are talking with
+ /// (this is why all calls below have it in the method call ~it works better that way in COM+)
+ ///
+ [Guid("2CF9E641-57B7-436f-80E1-EF3127CB5C0A")]
+ [InterfaceType(ComInterfaceType.InterfaceIsDual)]
+ [ComVisible(true)]
+ public interface IButtonForm
+ {
+ // Custom Events
+ int W32BUTTONCLICKED();
+
+ // Called when ButtonHook activates/deactivates the COM Object
+ void WPFThreadProc_ButtonWPForm_Activated(int hParentWND, int hButtonWND);
+ void WPFThreadProc_ButtonWPForm_Deactivated();
+
+ // Hooked Window Events
+ void WindowEvent_MaximizeOccured(int nHeight, int nWidth);
+ void WindowEvent_MinimizeOccured();
+ void WindowEvent_WindowActivated();
+ void WindowEvent_WindowDeactivated();
+ }
+}
diff --git a/Client Services/ButtonWPForm/IButtonFormPage.cs b/Client Services/ButtonWPForm/IButtonFormPage.cs
new file mode 100644
index 0000000..bfd8475
--- /dev/null
+++ b/Client Services/ButtonWPForm/IButtonFormPage.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace Foo.ClientServices.ButtonWPForm
+{
+ ///
+ /// This interface defines the communication from ButtonForm to
+ /// it's ButtonFormPage Client
+ ///
+ [ComVisible(false)]
+ public interface IButtonFormPage
+ {
+ ButtonForm ParentWPFContainer { get; set; }
+ }
+}
diff --git a/Client Services/ButtonWPForm/IClientEvents.cs b/Client Services/ButtonWPForm/IClientEvents.cs
new file mode 100644
index 0000000..e0c87c4
--- /dev/null
+++ b/Client Services/ButtonWPForm/IClientEvents.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace Foo.ClientServices.ButtonWPForm
+{
+ ///
+ /// Button Hook uses the IClientEvents Interface to let us know of certain events
+ /// which may require us to re-resolve the Window.
+ /// ~This is an important feature we need to do be accurate with all our artifacts.
+ /// We are piggy-backing on ButtonWPForm in order to have less components
+ ///
+ [Guid("F1AF5CAD-B9AB-4a20-80F1-EB68C577ABC4")]
+ [InterfaceType(ComInterfaceType.InterfaceIsDual)]
+ [ComVisible(true)]
+ public interface IClientEvents
+ {
+ // An Event occured that could potentially have made artifact changes
+ void ReResolve(int pid, IntPtr hWnd);
+
+ // First and Last Activation Events
+ void hWndInitialActivate(int pid, IntPtr hWnd, string ProcessStartUpPrms);
+ void hWndLastDeactivate(int pid, IntPtr hWnd);
+
+ // User File Events
+ void DragNDropOccured(int pid, IntPtr hWnd, int nFiles, string SemiColonSepFileNames);
+ void OpenOrSaveFileDialogOccured(int pid, IntPtr hWnd, string possibleLocAndFileName, string FileTypes);
+ }
+}
\ No newline at end of file
diff --git a/Client Services/ButtonWPForm/MyKeyFile.SNK b/Client Services/ButtonWPForm/MyKeyFile.SNK
new file mode 100644
index 0000000..8bc8162
Binary files /dev/null and b/Client Services/ButtonWPForm/MyKeyFile.SNK differ
diff --git a/Client Services/ButtonWPForm/Properties/AssemblyInfo.cs b/Client Services/ButtonWPForm/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..9542feb
--- /dev/null
+++ b/Client Services/ButtonWPForm/Properties/AssemblyInfo.cs
@@ -0,0 +1,62 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+using System.EnterpriseServices;
+
+// 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("ButtonWPForm")]
+[assembly: AssemblyDescription("Performance Caching for ButtonWPForm")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Ooganizer Corporation")]
+[assembly: AssemblyProduct("ButtonWPForm")]
+[assembly: AssemblyCopyright("Copyright © Ooganizer Corporation 2009")]
+[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(true)]
+[assembly: ApplicationID("E6A84616-5ED1-4679-B26D-64F80A5E41CD")]
+[assembly: ApplicationActivation(ActivationOption.Server)]
+[assembly: ApplicationAccessControl(Value = false, Authentication = AuthenticationOption.None)]
+[assembly: ApplicationName("Foo.ClientServices")]
+[assembly: Description("Provides Data Access and Performance Caching for Ooganizer Components")]
+
+
+//In order to begin building localizable applications, set
+//CultureYouAreCodingWith in your .csproj file
+//inside a . For example, if you are using US english
+//in your source files, set the to en-US. Then uncomment
+//the NeutralResourceLanguage attribute below. Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
+
+
+// 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")]
diff --git a/Client Services/ButtonWPForm/Properties/Resources.Designer.cs b/Client Services/ButtonWPForm/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..743dbbe
--- /dev/null
+++ b/Client Services/ButtonWPForm/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.ClientServices.ButtonWPForm.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Foo.ClientServices.ButtonWPForm.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Client Services/ButtonWPForm/Properties/Resources.resx b/Client Services/ButtonWPForm/Properties/Resources.resx
new file mode 100644
index 0000000..ffecec8
--- /dev/null
+++ b/Client Services/ButtonWPForm/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Client Services/ButtonWPForm/Properties/Settings.Designer.cs b/Client Services/ButtonWPForm/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..0f75067
--- /dev/null
+++ b/Client Services/ButtonWPForm/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.ClientServices.ButtonWPForm.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Client Services/ButtonWPForm/Properties/Settings.settings b/Client Services/ButtonWPForm/Properties/Settings.settings
new file mode 100644
index 0000000..8f2fd95
--- /dev/null
+++ b/Client Services/ButtonWPForm/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Client Services/GUIDebugStepExe/App.xaml b/Client Services/GUIDebugStepExe/App.xaml
new file mode 100644
index 0000000..55c4112
--- /dev/null
+++ b/Client Services/GUIDebugStepExe/App.xaml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/Client Services/GUIDebugStepExe/App.xaml.cs b/Client Services/GUIDebugStepExe/App.xaml.cs
new file mode 100644
index 0000000..47a3fa2
--- /dev/null
+++ b/Client Services/GUIDebugStepExe/App.xaml.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Windows;
+
+namespace Foo.ClientServices.GUIDebugStepExe
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ }
+}
diff --git a/Client Services/GUIDebugStepExe/GUIDebugStepExe.csproj b/Client Services/GUIDebugStepExe/GUIDebugStepExe.csproj
new file mode 100644
index 0000000..e15a00a
--- /dev/null
+++ b/Client Services/GUIDebugStepExe/GUIDebugStepExe.csproj
@@ -0,0 +1,112 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {4C81A790-31CA-4A71-99AD-339D3837A5C6}
+ WinExe
+ Properties
+ Foo.ClientServices.GUIDebugStepExe
+ GUIDebugStepExe
+ v3.5
+ 512
+ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 4
+
+
+ true
+ full
+ false
+ ..\..\Target\Debug\
+ TRACE;DEBUG
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\..\Target\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+ MSBuild:Compile
+ Designer
+
+
+ App.xaml
+ Code
+
+
+ GUIDebugStepTestForm.xaml
+ Code
+
+
+
+
+ Code
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
+
+ {E179DF39-539A-407F-94DE-C21F690E02C4}
+ ButtonWPForm
+
+
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}
+ GUIWPForms
+
+
+
+
+
\ No newline at end of file
diff --git a/Client Services/GUIDebugStepExe/GUIDebugStepTestForm.xaml b/Client Services/GUIDebugStepExe/GUIDebugStepTestForm.xaml
new file mode 100644
index 0000000..19c2360
--- /dev/null
+++ b/Client Services/GUIDebugStepExe/GUIDebugStepTestForm.xaml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client Services/GUIDebugStepExe/GUIDebugStepTestForm.xaml.cs b/Client Services/GUIDebugStepExe/GUIDebugStepTestForm.xaml.cs
new file mode 100644
index 0000000..42ee850
--- /dev/null
+++ b/Client Services/GUIDebugStepExe/GUIDebugStepTestForm.xaml.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+// Foo Namespaces
+using Foo.ClientServices.ButtonWPForm;
+using Foo.ClientServices.GUIWPForms;
+
+namespace Foo.ClientServices.GUIDebugStepExe
+{
+ ///
+ /// Interaction logic for Window1.xaml
+ ///
+ public partial class GUIDebugStepTestForm : Window
+ {
+
+ // Private Members
+ GUIWPForms.GUIWPForms m_Gui = null;
+ ButtonWPForm.ButtonWPFormCCW m_ButtonForm = null;
+
+ public GUIDebugStepTestForm()
+ {
+ InitializeComponent();
+ }
+
+ private void btnLaunchArtifactWall_Click(object sender, RoutedEventArgs e)
+ {
+ m_Gui.LaunchArtifactWall(IntPtr.Zero);
+ }
+
+ private void btnWorkspaceSelector_Click(object sender, RoutedEventArgs e)
+ {
+ m_Gui.LaunchWorkspaceSelector(IntPtr.Zero);
+ }
+
+ private void btnSettingsNMain_Click(object sender, RoutedEventArgs e)
+ {
+ m_Gui.LaunchSettingsNAboutUs(IntPtr.Zero);
+ }
+
+ private void btnButtonForm_Click(object sender, RoutedEventArgs e)
+ {
+ }
+
+ private void wvGUIDebugStepTestForm_Loaded(object sender, RoutedEventArgs e)
+ {
+ // Instantiate the objects
+ m_Gui = new GUIWPForms.GUIWPForms();
+ //m_ButtonForm = new ButtonWPForm.ButtonWPFormCCW();
+
+ // instantiate any dependent threads, etc
+ m_Gui.Start();
+ //m_ButtonForm.Start();
+ }
+
+ private void wvGUIDebugStepTestForm_Closed(object sender, EventArgs e)
+ {
+ // close any dependent threads
+ m_Gui.Stop();
+ //m_ButtonForm.Stop();
+
+ // delete objects
+ m_Gui = null;
+ //m_ButtonForm = null;
+ }
+ }
+}
diff --git a/Client Services/GUIDebugStepExe/Properties/AssemblyInfo.cs b/Client Services/GUIDebugStepExe/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d549f5b
--- /dev/null
+++ b/Client Services/GUIDebugStepExe/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// 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("GUIDebugStepExe")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("GUIDebugStepExe")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
+[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)]
+
+//In order to begin building localizable applications, set
+//CultureYouAreCodingWith in your .csproj file
+//inside a . For example, if you are using US english
+//in your source files, set the to en-US. Then uncomment
+//the NeutralResourceLanguage attribute below. Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
+
+
+// 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")]
diff --git a/Client Services/GUIDebugStepExe/Properties/Resources.Designer.cs b/Client Services/GUIDebugStepExe/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..8728cf7
--- /dev/null
+++ b/Client Services/GUIDebugStepExe/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.ClientServices.GUIDebugStepExe.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Foo.ClientServices.GUIDebugStepExe.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Client Services/GUIDebugStepExe/Properties/Resources.resx b/Client Services/GUIDebugStepExe/Properties/Resources.resx
new file mode 100644
index 0000000..ffecec8
--- /dev/null
+++ b/Client Services/GUIDebugStepExe/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Client Services/GUIDebugStepExe/Properties/Settings.Designer.cs b/Client Services/GUIDebugStepExe/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..7f1368d
--- /dev/null
+++ b/Client Services/GUIDebugStepExe/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.ClientServices.GUIDebugStepExe.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Client Services/GUIDebugStepExe/Properties/Settings.settings b/Client Services/GUIDebugStepExe/Properties/Settings.settings
new file mode 100644
index 0000000..8f2fd95
--- /dev/null
+++ b/Client Services/GUIDebugStepExe/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Client Services/GUIWPForms/ComponentState.cs b/Client Services/GUIWPForms/ComponentState.cs
new file mode 100644
index 0000000..9f7509a
--- /dev/null
+++ b/Client Services/GUIWPForms/ComponentState.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Reflection;
+
+// Ooganizer Namespaces
+using Foo.Platform;
+using Foo.DataAccessLayer;
+using Foo.DataAccessLayer.DataTypes;
+
+namespace Foo.ClientServices.GUIWPForms
+{
+ ///
+ /// This class is responsible for launch all secondary threads required for this application as
+ /// well as hold any variables that are needed by all classes
+ /// created.
+ ///
+ [ComVisible(false)]
+ internal class ComponentState
+ {
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// This class manages the state / main variables of the COM+ that maybe needed by multiple classes.
+ /// It is responsible for starting and stopping any secondary threads.
+ ///
+ static ComponentState()
+ {
+ // We must subscribe to assembly resolver
+ Log.Info(string.Format("{0}() - GUIWPForms ComponentState() called. Application is starting...", MethodBase.GetCurrentMethod().Name));
+
+ // Let's Preload the Database *Right here, right now* that should be good for all of us
+ Data.Artifacts.DoesArtifactExistInSystem(DataTypeHelpers.CreateLocationOnlyArtifact("C:\\Dummy.file"));
+
+ // Start GUI Dispatcher Thread
+ Log.Info(string.Format("{0}() - GUIWPForms ComponentState() called. Activating DispatcherThread", MethodBase.GetCurrentMethod().Name));
+ DispatcherThread.Run = true;
+ }
+
+ ///
+ /// Private Variables
+ ///
+ private static bool s_bApplicationIsRunning = false;
+
+ ///
+ /// Use this to enable/disable all threads and variables for
+ /// the component states
+ ///
+ public static bool ApplicationIsRunning
+ {
+ get { return s_bApplicationIsRunning; }
+ set
+ {
+ if (!value)
+ {
+ Log.Info(string.Format("{0}() - ComponentState() sApplicationRunning set to False", MethodBase.GetCurrentMethod().Name));
+ DispatcherThread.Run = false;
+ }
+
+ s_bApplicationIsRunning = value;
+ }
+ }
+
+ ///
+ /// Use this to access the GUIFormsMgr Object in order to
+ /// communicate to wpfForms (Setter should only be called by
+ /// DispatcherThread)
+ ///
+ public static GUIFormsMgr GUIFormsMgr
+ {
+ get { return DispatcherThread.s_GUIFormsMgr; }
+ }
+ }
+}
diff --git a/Client Services/GUIWPForms/DispatcherThread.cs b/Client Services/GUIWPForms/DispatcherThread.cs
new file mode 100644
index 0000000..c53fada
--- /dev/null
+++ b/Client Services/GUIWPForms/DispatcherThread.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Reflection;
+
+// Ooganizer Namespaces
+using Foo.Platform;
+using System.Windows.Threading;
+
+namespace Foo.ClientServices.GUIWPForms
+{
+ ///
+ /// This class is responsible for creation and deltion of ButtonFormMgr.cs on a
+ /// Dispatcher Thread. ~The Dispatcher is responsible for all the messages being passed
+ /// for the Form Objects, it must be running at all times and created before any forms get
+ /// created.
+ ///
+ [ComVisible(false)]
+ class DispatcherThread
+ {
+
+ // Member Variables
+ private static Thread s_DispatcherThread = null;
+ private static bool s_DispatcherThreadIsInitialized = false;
+ internal static GUIFormsMgr s_GUIFormsMgr = null;
+
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// Constructor by default will launch the thread if needed
+ ///
+ static DispatcherThread()
+ {
+ Log.Info(string.Format("{0}() - DispatcherThread() called", MethodBase.GetCurrentMethod().Name));
+ StartDispatcherThreadIfNeeded();
+ }
+
+ ///
+ /// Use this property to set the Dispatcher to running / not running
+ ///
+ public static bool Run
+ {
+ get { return s_DispatcherThreadIsInitialized; }
+ set
+ {
+ if (!value)
+ TerminateDispatcherThreadIfNeeded();
+
+ s_DispatcherThreadIsInitialized = value;
+ }
+ }
+
+ ///
+ /// Message Loop Thread for wpfGUIForms
+ ///
+ private static void DispatcherThreadProc()
+ {
+ // Create ButtonFormMgr Object on this thread *Allow global access to the object*
+ Log.Info(string.Format("{0}() - About to new GUIFormsMgr via DispatcherThread", MethodBase.GetCurrentMethod().Name));
+ s_GUIFormsMgr = new GUIFormsMgr(Dispatcher.CurrentDispatcher);
+
+ Log.Info(string.Format("{0}() - GUIFormsMgr DispatcherThread is initialized s_DispatcherThreadIsInitialized is True", MethodBase.GetCurrentMethod().Name));
+ s_DispatcherThreadIsInitialized = true; // always set to true to allow caller to exit out
+
+ if (s_GUIFormsMgr != null)
+ {
+ Log.Info(string.Format("{0}() - GUIFormsMgr Launched via DispatcherThread", MethodBase.GetCurrentMethod().Name));
+
+ //Enter Dispatcher Message Loop
+ System.Windows.Threading.Dispatcher.Run();
+ }
+ else
+ {
+ Log.Error(string.Format("{0}() - GUIFormsMgr Launch Failed! Exiting Thread - Major Error must have occured", MethodBase.GetCurrentMethod().Name));
+ // exit thread - no need to stay here
+ }
+ }
+
+ ///
+ /// Use this function to start ThreadProc(above) if needed. COM+ can shutdown the thread anytime,
+ /// we need to make sure that the thread is alive BEFORE calling ButtonForms
+ ///
+ private static void StartDispatcherThreadIfNeeded()
+ {
+ if (s_DispatcherThread != null && s_DispatcherThread.IsAlive)
+ {
+ return;
+ }
+ else
+ {
+ s_DispatcherThreadIsInitialized = false;
+
+ // Start a new Thread so it can become the Message Loop
+ s_DispatcherThread = new Thread(new ThreadStart(DispatcherThread.DispatcherThreadProc));
+
+ // GUI components require the thread to be STA; otherwise throws an error
+ s_DispatcherThread.SetApartmentState(ApartmentState.STA);
+ Log.Info(string.Format("{0}() - Starting DispatcherThread...", MethodBase.GetCurrentMethod().Name));
+ s_DispatcherThread.Start();
+ Log.Info(string.Format("{0}() - DispatcherThread Started.", MethodBase.GetCurrentMethod().Name));
+
+ // Make sure the Application Object is running
+ // (COM will eventually just time out otherwise)
+ //while (!s_DispatcherThreadIsInitialized)
+ // System.Threading.Thread.Sleep(20); // Syncronous call
+ }
+ }
+
+ ///
+ /// Terminates all ButtonForm Objects and the Message Dispatcher Thread *do this only on shutdown*
+ ///
+ private static void TerminateDispatcherThreadIfNeeded()
+ {
+ if (s_DispatcherThreadIsInitialized)
+ {
+ // Delete s_GUIFormsMgr and all wpfForms from this thread
+ s_GUIFormsMgr.TerminateDISP();
+ s_GUIFormsMgr = null;
+
+ s_DispatcherThread.Abort();
+ s_DispatcherThreadIsInitialized = false;
+ Log.Info(string.Format("{0}() - GUIFormsMgr is DispatcherThread shutdown s_DispatcherThreadIsInitialized is False", MethodBase.GetCurrentMethod().Name));
+ }
+ }
+
+ }
+}
diff --git a/Client Services/GUIWPForms/GUIFormsMgr.cs b/Client Services/GUIWPForms/GUIFormsMgr.cs
new file mode 100644
index 0000000..ed06472
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIFormsMgr.cs
@@ -0,0 +1,381 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Drawing;
+using System.Threading;
+using System.Windows.Interop;
+using System.EnterpriseServices;
+using System.Windows;
+using System.IO;
+using System.Windows.Threading;
+using System.Collections;
+using System.Reflection;
+
+using Foo.Platform;
+using Foo.GUILib;
+
+namespace Foo.ClientServices.GUIWPForms
+{
+ internal enum WPForms
+ {
+ ArtifactWall,
+ WorkspaceSelector,
+ SettingsNAboutUs,
+ }
+
+ ///
+ /// Object Factory Creator for WPForms above
+ ///
+ internal class GUIWPFormsObjectFactory
+ {
+ ///
+ /// Object Form Factory for all our GUI Forms
+ ///
+ /// a WPF form object to create
+ /// true if to create a performanceCache window, should be false all other times
+ ///
+ public static Window CreateWPFormWindow(WPForms form, bool bPerformanceCache)
+ {
+ Window wpfForm = null;
+ switch (form)
+ {
+ case WPForms.ArtifactWall:
+ wpfForm = new ArtifactWall(bPerformanceCache);
+ break;
+
+ case WPForms.WorkspaceSelector:
+ wpfForm = new WorkspaceSelector(bPerformanceCache);
+ break;
+
+ case WPForms.SettingsNAboutUs:
+ wpfForm = new SettingsNAboutUs(bPerformanceCache);
+ break;
+ }
+
+ // Imp! - if this is being loaded for performance we must handle it
+ WPFHiddenWindow.ExecuteShowOnAHiddenWindow(wpfForm, bPerformanceCache);
+
+ return wpfForm;
+ }
+ }
+
+ ///
+ /// This class manages the creation/deletion and actions of (1 - n) ButtonForms
+ ///
+ [ComVisible(false)]
+ internal class GUIFormsMgr
+ {
+
+ private const int INITIAL_OBJECT_CAPACITY = 30;
+ private Hashtable m_ObjectList = null;
+ private Dispatcher m_Dispatcher = null;
+
+ // load one instance of all wpforms (hidden) cached always, as a performance cache
+ private Window[] m_wpfCachedForms = null;
+ private bool m_AreWpfFormsCached = false;
+
+ // Imp! - allows external caller to run any action on a Window
+ public delegate void _Action(Window wpfForm);
+
+ //custom private delegates
+ private delegate bool delegate_Create(WPForms wpfFormType);
+ private delegate bool delegate_Show(WPForms wpfFormType);
+ private delegate bool delegate_Delete(WPForms wpfFormType);
+ private delegate bool delegate_Action(WPForms wpfFormType, _Action action);
+
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// GUIFormsMgr - Responsible for managing the GUI Window Messaging Threads
+ ///
+ /// Dispatcher Thread Context
+ public GUIFormsMgr(Dispatcher disp)
+ {
+ m_ObjectList = new Hashtable();
+ m_Dispatcher = disp;
+
+ if (!m_AreWpfFormsCached)
+ BetterPerformance();
+ }
+
+ ///
+ /// Calls Create_WpfForm via Dispatcher if neccessary
+ ///
+ /// Object type to create
+ public bool Create_WpfFormDISP(WPForms wpfFormType)
+ {
+ if (m_Dispatcher.Thread == Thread.CurrentThread)
+ {
+ return Create_WpfForm(wpfFormType);
+ }
+ else
+ {
+ object[] parameters = new object[] { wpfFormType };
+ return (bool) m_Dispatcher.Invoke((delegate_Create)Create_WpfFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
+ }
+ }
+
+ ///
+ /// Calls Show_WpfForm via Dispatcher if neccessary
+ ///
+ /// Object type to create
+ public bool Show_WpfFormDISP(WPForms wpfFormType)
+ {
+ if (m_Dispatcher.Thread == Thread.CurrentThread)
+ {
+ return Show_WpfForm(wpfFormType);
+ }
+ else
+ {
+ object[] parameters = new object[] { wpfFormType };
+ return (bool) m_Dispatcher.Invoke((delegate_Create)Show_WpfFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
+ }
+ }
+
+ ///
+ /// Calls Delete_WpfForm via Dispatcher if neccessary
+ ///
+ /// Object type to delete
+ public bool Delete_WpfFormDISP(WPForms wpfFormType)
+ {
+ if (m_Dispatcher.Thread == Thread.CurrentThread)
+ {
+ return Delete_WpfForm(wpfFormType);
+ }
+ else
+ {
+ object[] parameters = new object[] { wpfFormType };
+ return (bool)m_Dispatcher.Invoke((delegate_Delete)Delete_WpfFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
+ }
+ }
+
+ ///
+ /// Use this Dispatching Action Function to run any _Action on the WpfForm
+ ///
+ /// Object type to run action on
+ public bool RunAction_WpfFormDISP(WPForms wpfFormType, _Action action)
+ {
+ if (m_Dispatcher.Thread == Thread.CurrentThread)
+ {
+ return RunAction_WpfForm(wpfFormType, action);
+ }
+ else
+ {
+ object[] parameters = new object[] { wpfFormType, action };
+ return (bool) m_Dispatcher.Invoke((delegate_Action)RunAction_WpfFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
+ }
+ }
+
+ ///
+ /// Calls Terminate via Dispatcher if neccessary
+ ///
+ public void TerminateDISP()
+ {
+ if (m_Dispatcher.Thread == Thread.CurrentThread)
+ {
+ Terminate();
+ }
+ else
+ {
+ m_Dispatcher.Invoke((Action)TerminateDISP, System.Windows.Threading.DispatcherPriority.Normal, null);
+ }
+ }
+
+ ///
+ /// Creates a new WpfForm object into the ObjectList
+ ///
+ /// Object type to run action on
+ private bool Create_WpfForm(WPForms wpfFormType)
+ {
+ try
+ {
+ if (!m_AreWpfFormsCached)
+ BetterPerformance();
+
+ // we only allow one object * so delete the previous one if exists *
+ if (m_ObjectList[wpfFormType] != null)
+ Delete_WpfForm(wpfFormType);
+
+ m_ObjectList[wpfFormType] = GUIWPFormsObjectFactory.CreateWPFormWindow(wpfFormType, false);
+ Window wpfForm = (Window) m_ObjectList[wpfFormType];
+
+ if (wpfForm == null)
+ {
+ Log.Error(string.Format("{0}() - Some Type of Error Occured. wpfForm is null", MethodBase.GetCurrentMethod().Name));
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ return false;
+ }
+
+ ///
+ /// Show a WpfForm object in the ObjectList
+ ///
+ /// Object type to run action on
+ private bool Show_WpfForm(WPForms wpfFormType)
+ {
+ try
+ {
+ Window wpfForm = (Window)m_ObjectList[wpfFormType];
+
+ if (wpfForm == null)
+ {
+ Log.Error(string.Format("{0}() - Some Type of Error Occured. wpfForm is null", MethodBase.GetCurrentMethod().Name));
+ return false;
+ }
+ else
+ {
+ // We use the InteropHelper to see if this WPFForm has been created previously
+ WindowInteropHelper InteropHelper = new WindowInteropHelper(wpfForm);
+ if (InteropHelper.Handle == IntPtr.Zero)
+ {
+ wpfForm.Show();
+ return true;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ return false;
+ }
+
+ ///
+ /// Use this function to delete the WpfForm Object
+ ///
+ /// Object type to run action on
+ private bool Delete_WpfForm(WPForms wpfFormType)
+ {
+ try
+ {
+ if (m_ObjectList.ContainsKey(wpfFormType))
+ {
+ Window wpfForm = (Window)m_ObjectList[wpfFormType];
+ if (wpfForm != null)
+ {
+ m_ObjectList.Remove(wpfFormType);
+ wpfForm.Close();
+ return true;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ return false;
+ }
+
+ ///
+ /// Use this to run void() function actions on the specified wpfForm
+ ///
+ /// Object type to run action on
+ /// a pointer to a delegate (action function) to run
+ private bool RunAction_WpfForm(WPForms wpfFormType, _Action action)
+ {
+ try
+ {
+ if (m_ObjectList.ContainsKey(wpfFormType))
+ {
+ Window wpfForm = (Window)m_ObjectList[wpfFormType];
+ if (wpfForm != null && action != null)
+ {
+ action(wpfForm);
+ return true;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ return false;
+ }
+
+ ///
+ /// Kills all ButtonForm Instances (STOPS ALL)
+ ///
+ private void Terminate()
+ {
+ try
+ {
+ foreach (object o in m_ObjectList)
+ {
+ if ((o != null) && (o is Window))
+ {
+ Window WpfForm = (Window)o;
+ WpfForm.Close();
+ }
+ }
+ m_ObjectList.Clear();
+
+ if (m_AreWpfFormsCached)
+ {
+ foreach (Window window in m_wpfCachedForms)
+ {
+ if (window != null)
+ window.Close();
+ }
+
+ // Caching is incomplete
+ m_AreWpfFormsCached = false;
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ }
+
+ ///
+ /// In order to improve WPForm performance we have one set of forms
+ /// loaded at all times. (opacity set to 0).
+ /// ~it has no parent setting so it is just a form of the desktop
+ ///
+ private void BetterPerformance()
+ {
+ if (!m_AreWpfFormsCached && (m_wpfCachedForms == null))
+ {
+ try
+ {
+ lock (this)
+ {
+ int nForms = Enum.GetValues(typeof(WPForms)).Length;
+ if (nForms > 0)
+ {
+ // Allocate the cached forms array
+ m_wpfCachedForms = new Window[nForms];
+
+ // Iterate thru enums and create the corresponding objects in the Cache
+ for (int i = 0; i < nForms; ++i)
+ {
+ WPForms form = (WPForms)Enum.ToObject(typeof(WPForms), i);
+ m_wpfCachedForms[i] = GUIWPFormsObjectFactory.CreateWPFormWindow(form, true);
+ }
+
+ // Caching is complete
+ m_AreWpfFormsCached = true;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+ }
+ }
+
+ }
+}
diff --git a/Client Services/GUIWPForms/GUIState.cs b/Client Services/GUIWPForms/GUIState.cs
new file mode 100644
index 0000000..77642e2
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIState.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+// Foo Namespaces
+using Foo.DataAccessLayer;
+using Foo.DataAccessLayer.DataTypes;
+using System.Windows;
+
+namespace Foo.ClientServices.GUIWPForms
+{
+
+ ///
+ /// Used to save GUI State Information for all of GUIWPForms,
+ /// such as last selected SortOrder etc. ~very useful for having multiple forms
+ /// communicate with each other * C# Singleton #
+ ///
+ public static class GUIState
+ {
+ // WorkspaceSelector_StandardPage comboBox Workspace SortOrder
+ public static SortOrderForWorkspaces LastSelectedSotOrderWorkspaces { get; set; }
+ public static int LastSelectedSotOrderWorkspacesIndex { get; set; }
+
+ // WorkspaceSelector_StandardPage dataGrid Selected WorkspaceName
+ public static string LastSelectedWorkspaceName { get; set; }
+
+ // ArtifactWall
+ public static SortOrderForArtifacts LastSelectedSotOrderArtifacts { get; set; }
+ public static int LastSelectedSotOrderArtifactsIndex { get; set; }
+
+ // Keeping track of launched WPF GUI's
+ public static Window CurrentlyShowingWPFWindow { get; set; }
+
+ ///
+ /// Defaults
+ ///
+ static GUIState()
+ {
+ // Defaults for comboBox Workspace SortOrder
+ LastSelectedSotOrderWorkspaces = SortOrderForWorkspaces.Ascending;
+ LastSelectedSotOrderWorkspacesIndex = 0;
+
+ // Defaults for Selected WorkspaceName
+ LastSelectedWorkspaceName = String.Empty;
+
+ // Artifact Wall
+ LastSelectedSotOrderArtifacts = SortOrderForArtifacts.Ascending;
+ LastSelectedSotOrderArtifactsIndex = 0;
+
+ // Keeping track of launched WPF GUI's
+ CurrentlyShowingWPFWindow = null;
+ }
+ }
+}
diff --git a/Client Services/GUIWPForms/GUIWPFPages/PageImages/AddWorkspace.png b/Client Services/GUIWPForms/GUIWPFPages/PageImages/AddWorkspace.png
new file mode 100644
index 0000000..01bdc88
Binary files /dev/null and b/Client Services/GUIWPForms/GUIWPFPages/PageImages/AddWorkspace.png differ
diff --git a/Client Services/GUIWPForms/GUIWPFPages/PageImages/Close.png b/Client Services/GUIWPForms/GUIWPFPages/PageImages/Close.png
new file mode 100644
index 0000000..21f27ff
Binary files /dev/null and b/Client Services/GUIWPForms/GUIWPFPages/PageImages/Close.png differ
diff --git a/Client Services/GUIWPForms/GUIWPFPages/PageImages/CloseAll.png b/Client Services/GUIWPForms/GUIWPFPages/PageImages/CloseAll.png
new file mode 100644
index 0000000..d758b0c
Binary files /dev/null and b/Client Services/GUIWPForms/GUIWPFPages/PageImages/CloseAll.png differ
diff --git a/Client Services/GUIWPForms/GUIWPFPages/PageImages/DeleteWorkspace.png b/Client Services/GUIWPForms/GUIWPFPages/PageImages/DeleteWorkspace.png
new file mode 100644
index 0000000..2471d6a
Binary files /dev/null and b/Client Services/GUIWPForms/GUIWPFPages/PageImages/DeleteWorkspace.png differ
diff --git a/Client Services/GUIWPForms/GUIWPFPages/PageImages/EditWorkspace.png b/Client Services/GUIWPForms/GUIWPFPages/PageImages/EditWorkspace.png
new file mode 100644
index 0000000..6a98752
Binary files /dev/null and b/Client Services/GUIWPForms/GUIWPFPages/PageImages/EditWorkspace.png differ
diff --git a/Client Services/GUIWPForms/GUIWPFPages/PageImages/Hide.png b/Client Services/GUIWPForms/GUIWPFPages/PageImages/Hide.png
new file mode 100644
index 0000000..961c312
Binary files /dev/null and b/Client Services/GUIWPForms/GUIWPFPages/PageImages/Hide.png differ
diff --git a/Client Services/GUIWPForms/GUIWPFPages/PageImages/House.png b/Client Services/GUIWPForms/GUIWPFPages/PageImages/House.png
new file mode 100644
index 0000000..17bb9ed
Binary files /dev/null and b/Client Services/GUIWPForms/GUIWPFPages/PageImages/House.png differ
diff --git a/Client Services/GUIWPForms/GUIWPFPages/PageImages/Launch.png b/Client Services/GUIWPForms/GUIWPFPages/PageImages/Launch.png
new file mode 100644
index 0000000..288a59a
Binary files /dev/null and b/Client Services/GUIWPForms/GUIWPFPages/PageImages/Launch.png differ
diff --git a/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_DeleteWorkspacePage.xaml b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_DeleteWorkspacePage.xaml
new file mode 100644
index 0000000..7581305
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_DeleteWorkspacePage.xaml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_DeleteWorkspacePage.xaml.cs b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_DeleteWorkspacePage.xaml.cs
new file mode 100644
index 0000000..2781d2e
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_DeleteWorkspacePage.xaml.cs
@@ -0,0 +1,158 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+using Foo.DataAccessLayer;
+using Foo.DataAccessLayer.DataTypes;
+using System.Windows.Threading;
+
+namespace Foo.ClientServices.GUIWPForms
+{
+ ///
+ /// Interaction logic for WorkspaceSelector_DeleteWorkspacePage.xaml
+ ///
+ public partial class WorkspaceSelector_DeleteWorkspacePage : Page
+ {
+ // passed to us by parent
+ private WorkspaceSelector m_WorkspaceSelectorObj = null;
+ private bool m_bPerformanceCache = false;
+
+ // private state variables
+ private string m_strWorkspaceName;
+
+ public WorkspaceSelector_DeleteWorkspacePage(bool bPerformanceCache)
+ {
+ m_strWorkspaceName = String.Empty;
+ m_bPerformanceCache = bPerformanceCache;
+ if (!m_bPerformanceCache)
+ {
+ }
+ InitializeComponent();
+ }
+
+ ///
+ /// Occurs when page gets loaded
+ ///
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (!m_bPerformanceCache)
+ {
+ // Make sure that the Selector Frame is big enough to hold this page
+ m_WorkspaceSelectorObj = (WorkspaceSelector)this.Tag;
+
+ // Make sure that we have a workspace Name to work with otherwise Navigate Back
+ if (String.IsNullOrEmpty(GUIState.LastSelectedWorkspaceName))
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+ else
+ m_strWorkspaceName = GUIState.LastSelectedWorkspaceName;
+
+ // Set Height and Width
+ m_WorkspaceSelectorObj.Height = this.Height + m_WorkspaceSelectorObj.MarginTopBottom;
+ m_WorkspaceSelectorObj.Width = this.Width;
+
+ // Set the Warning Label for this Particular Workspace
+ ConstructAreYouSureMessage();
+ }
+ }
+
+ ///
+ /// Constructs a thorough Warning Message to be displayed to the user in the label
+ /// Iterates and warns the user of exactly the number of changes that will occur in the system
+ ///
+ private void ConstructAreYouSureMessage()
+ {
+ int nArtifactsCount = Data.Artifacts.GetArtifactLinkCountForWorkspace(m_strWorkspaceName);
+ int nUniqueArtifactsCount = Data.Artifacts.GetUniqureArtifactsCountForWorkspace(m_strWorkspaceName);
+ if (nArtifactsCount >= 0 && nUniqueArtifactsCount >= 0)
+ {
+ StringBuilder sr = new StringBuilder();
+ sr.Append(String.Format("Are you Sure you want to Delete Workspace '{0}'? \n\n", m_strWorkspaceName));
+ sr.Append(String.Format("This Workspace contains {0} Artifact Links ", (nArtifactsCount - nUniqueArtifactsCount)));
+ sr.Append(String.Format("and {0} Artifacts. ", nUniqueArtifactsCount));
+ sr.Append(String.Format("\n\n In Total: {0} Items will be deleted. There is no way to undo this operation.", nArtifactsCount));
+ txtAreYouSure.Text = sr.ToString();
+ }
+ else
+ {
+ // an error occured
+ Foo.Platform.ErrorReporting.UserError.Show("An Error Occurred", "Navigating you back to the WorkspaceSelector");
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+ }
+ }
+
+ ///
+ /// Button Yes Event Handler - Go ahead and delete the workspace
+ ///
+ private void btnYes_Click(object sender, RoutedEventArgs e)
+ {
+ if (Data.Workspace.DeleteWorkspace(GUIState.LastSelectedWorkspaceName))
+ {
+
+ // Show Confirm Delete Message and Go Back
+ StringBuilder sr = new StringBuilder();
+ sr.Append(String.Format("The Workspace '{0}' was deleted successfully. \n\n", m_strWorkspaceName));
+ sr.Append("You will no longer be able to access this Workspace and any Artifacts that were exclusive to it.");
+ ShowMessageAndNavigateBack(sr.ToString());
+
+ // Set GUI State
+ GUIState.LastSelectedWorkspaceName = String.Empty;
+ }
+ else
+ {
+ // an error occured
+ Foo.Platform.ErrorReporting.UserError.Show("An Error Occurred", String.Format("An Error occured while deleting the Workspace {0}. Navigating you back to the WorkspaceSelector", m_strWorkspaceName));
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+ }
+ }
+
+ ///
+ /// Shows the passed in message in the text box and then navigates back to the main page
+ ///
+ ///
+ private void ShowMessageAndNavigateBack(string strMessage)
+ {
+ // Hide the buttons
+ btnYes.Visibility = Visibility.Hidden;
+ btnNo.Visibility = Visibility.Hidden;
+
+ // Show Message
+ txtAreYouSure.Text = strMessage;
+
+ // Pause for 2 second and Navigate Back
+ DispatcherTimer dispatcherTimer = new DispatcherTimer();
+ dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
+ dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1, 500);
+ dispatcherTimer.Start();
+ }
+
+ ///
+ /// Timer set specifically to allow the message to be seen for a little bit before navigating back
+ ///
+ void dispatcherTimer_Tick(object sender, EventArgs e)
+ {
+ DispatcherTimer dispatcherTimer = (DispatcherTimer) sender;
+ dispatcherTimer.Stop();
+
+ // Navigate Back
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+ }
+
+ ///
+ /// Button No Event Handler - Go back to parent
+ ///
+ private void btnNo_Click(object sender, RoutedEventArgs e)
+ {
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+ }
+ }
+}
diff --git a/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_NewWorkspacePage.xaml b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_NewWorkspacePage.xaml
new file mode 100644
index 0000000..c118703
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_NewWorkspacePage.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_NewWorkspacePage.xaml.cs b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_NewWorkspacePage.xaml.cs
new file mode 100644
index 0000000..d342aab
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_NewWorkspacePage.xaml.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Windows.Threading;
+using System.Windows.Forms;
+using System.Drawing;
+
+namespace Foo.ClientServices.GUIWPForms
+{
+ ///
+ /// Interaction logic for WorkspaceSelector_NewWorkspacePage.xaml
+ ///
+ public partial class WorkspaceSelector_NewWorkspacePage : Page
+ {
+ // passed to us by parent
+ private WorkspaceSelector m_WorkspaceSelectorObj = null;
+ private bool m_bPerformanceCache = false;
+
+ // private state variables
+ private bool m_bIsValidName;
+
+ public WorkspaceSelector_NewWorkspacePage(bool bPerformanceCache)
+ {
+ m_bPerformanceCache = bPerformanceCache;
+ if (!m_bPerformanceCache)
+ {
+ }
+ InitializeComponent();
+ }
+
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (!m_bPerformanceCache)
+ {
+ // Make sure that the Selector Frame is big enough to hold this page
+ m_WorkspaceSelectorObj = (WorkspaceSelector)this.Tag;
+ m_WorkspaceSelectorObj.Height = this.Height + m_WorkspaceSelectorObj.MarginTopBottom;
+ m_WorkspaceSelectorObj.Width = this.Width;
+
+ // Set the Warning Label for this Particular Workspace
+ ConstructAreYouSureMessage();
+
+ // Set intial Error Message
+ SetWarningMessage("Enter Characters");
+ m_bIsValidName = false;
+
+ // Set intial focus
+ txtNewName.Focus();
+ }
+ }
+
+ ///
+ /// Constructs a renaming Message to be displayed to the user
+ ///
+ private void ConstructAreYouSureMessage()
+ {
+ StringBuilder sr = new StringBuilder();
+ sr.Append("Create New Workspace \n");
+ txtCreateWorkspaceTitle.Text = sr.ToString();
+ }
+
+ ///
+ /// Sets the validator label to a warning message
+ ///
+ ///
+ private void SetWarningMessage(string strMessage)
+ {
+ lblWarningMessage.Foreground = new SolidColorBrush(Colors.OrangeRed);
+ lblWarningMessage.Content = strMessage;
+ }
+
+ ///
+ /// Sets the validator label to a success message
+ ///
+ ///
+ private void SetSuccessMessage(string strMessage)
+ {
+ lblWarningMessage.Foreground = new SolidColorBrush(Colors.RoyalBlue);
+ lblWarningMessage.Content = strMessage;
+ }
+
+ ///
+ /// Button Yes Event Handler - Go ahead and Create the new WorkspaceName
+ ///
+ private void btnYes_Click(object sender, RoutedEventArgs e)
+ {
+ if (m_bIsValidName)
+ {
+ if (!DataAccessLayer.Data.Workspace.InsertWorkspaceName(txtNewName.Text))
+ {
+ // an error occured
+ Foo.Platform.ErrorReporting.UserError.Show("An Error Occurred", "Creating the Workspace Failed! Navigating you back to the WorkspaceSelector");
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+ }
+ else
+ {
+ // Set GUI State
+ GUIState.LastSelectedWorkspaceName = txtNewName.Text;
+
+ // Show Success Message
+ ShowMessageAndNavigateBack(String.Format("Workspace '{0}' has been successfully created", txtNewName.Text));
+ }
+ }
+ }
+
+ ///
+ /// Shows the passed in message in the text box and then navigates back to the main page
+ ///
+ ///
+ private void ShowMessageAndNavigateBack(string strMessage)
+ {
+ // Hide the buttons
+ btnYes.Visibility = Visibility.Hidden;
+ btnNo.Visibility = Visibility.Hidden;
+
+ // Hide the textbox and Labels
+ lblEnterNewName.Visibility = Visibility.Hidden;
+ txtNewName.Visibility = Visibility.Hidden;
+ lblWarningMessage.Visibility = Visibility.Hidden;
+
+ // Show Message
+ txtCreateWorkspaceTitle.Text = strMessage;
+
+ // Dynamically calculate the height of the textbox * No need to do this in this case *
+ // System.Drawing.Size sz = new System.Drawing.Size((int)this.Width, int.MaxValue);
+ // Font font = new Font(txtRenameWorkspaceTitle.FontFamily.ToString(), (float)txtRenameWorkspaceTitle.FontSize);
+ // sz = TextRenderer.MeasureText(txtRenameWorkspaceTitle.Text, font, sz, TextFormatFlags.WordBreak);
+ // Change Height as needed
+ // lblRenameWorkspaceTitle.Height = sz.Height;
+ // txtRenameWorkspaceTitle.Height = sz.Height;
+
+ // default to change height to Max available space
+ lblCreateWorkspaceTitle.Height = this.Height - m_WorkspaceSelectorObj.MarginTopBottom;
+ txtCreateWorkspaceTitle.Height = this.Height - m_WorkspaceSelectorObj.MarginTopBottom;
+
+ // Pause for 1.5 second and Navigate Back
+ DispatcherTimer dispatcherTimer = new DispatcherTimer();
+ dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
+ dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1, 500);
+ dispatcherTimer.Start();
+ }
+
+ ///
+ /// Timer set specifically to allow the message to be seen for a little bit before navigating back
+ ///
+ void dispatcherTimer_Tick(object sender, EventArgs e)
+ {
+ DispatcherTimer dispatcherTimer = (DispatcherTimer)sender;
+ dispatcherTimer.Stop();
+
+ // Navigate Back
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+ }
+
+ ///
+ /// Button No Event Handler - Go back to parent
+ ///
+ private void btnNo_Click(object sender, RoutedEventArgs e)
+ {
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+ }
+
+ ///
+ /// Perform NewWorkspaceName TextBox Validation
+ ///
+ private void txtNewName_TextChanged(object sender, TextChangedEventArgs e)
+ {
+ System.Windows.Controls.TextBox textBox = (System.Windows.Controls.TextBox)sender;
+ if (String.IsNullOrEmpty(textBox.Text))
+ {
+ SetWarningMessage("Enter Characters");
+ m_bIsValidName = false;
+ }
+ else if (!DataAccessLayer.DataTypes.DataTypeValidation.IsValidWorkspaceName(textBox.Text))
+ {
+ SetWarningMessage("Invalid Workspace Name");
+ m_bIsValidName = false;
+ }
+ else if (DataAccessLayer.Data.Workspace.DoesWorkspaceNameExist(textBox.Text))
+ {
+ SetWarningMessage("Workspace Name Already Exists");
+ m_bIsValidName = false;
+ }
+ else
+ {
+ SetSuccessMessage("Valid Workspace Name");
+ m_bIsValidName = true;
+ }
+ }
+ }
+}
diff --git a/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_RenameWorkspacePage.xaml b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_RenameWorkspacePage.xaml
new file mode 100644
index 0000000..d56356f
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_RenameWorkspacePage.xaml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_RenameWorkspacePage.xaml.cs b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_RenameWorkspacePage.xaml.cs
new file mode 100644
index 0000000..d951b1b
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_RenameWorkspacePage.xaml.cs
@@ -0,0 +1,210 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Windows.Threading;
+using System.Windows.Forms;
+using System.Drawing;
+
+namespace Foo.ClientServices.GUIWPForms
+{
+ ///
+ /// Interaction logic for WorkspaceSelector_RenameWorkspacePage.xaml
+ ///
+ public partial class WorkspaceSelector_RenameWorkspacePage : Page
+ {
+ // passed to us by parent
+ private WorkspaceSelector m_WorkspaceSelectorObj = null;
+ private bool m_bPerformanceCache = false;
+
+ // private state variables
+ private string m_strWorkspaceName;
+ private bool m_bIsValidName;
+
+ public WorkspaceSelector_RenameWorkspacePage(bool bPerformanceCache)
+ {
+ m_bPerformanceCache = bPerformanceCache;
+ if (!m_bPerformanceCache)
+ {
+ }
+ InitializeComponent();
+ }
+
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (!m_bPerformanceCache)
+ {
+ // Make sure that the Selector Frame is big enough to hold this page
+ m_WorkspaceSelectorObj = (WorkspaceSelector)this.Tag;
+
+ // Make sure that we have a workspace Name to work with otherwise Navigate Back
+ if (String.IsNullOrEmpty(GUIState.LastSelectedWorkspaceName))
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+ else
+ m_strWorkspaceName = GUIState.LastSelectedWorkspaceName;
+
+ // Set Height and Width
+ m_WorkspaceSelectorObj.Height = this.Height + m_WorkspaceSelectorObj.MarginTopBottom;
+ m_WorkspaceSelectorObj.Width = this.Width;
+
+ // Set the Warning Label for this Particular Workspace
+ ConstructAreYouSureMessage();
+
+ // Set intial Error Message
+ SetWarningMessage("Enter Characters");
+ m_bIsValidName = false;
+
+ // Set intial focus
+ txtNewName.Focus();
+ }
+ }
+
+ ///
+ /// Constructs a renaming Message to be displayed to the user
+ ///
+ private void ConstructAreYouSureMessage()
+ {
+ StringBuilder sr = new StringBuilder();
+ sr.Append(String.Format("Rename Workspace '{0}'\n", m_strWorkspaceName));
+ txtRenameWorkspaceTitle.Text = sr.ToString();
+ }
+
+ ///
+ /// Sets the validator label to a warning message
+ ///
+ ///
+ private void SetWarningMessage(string strMessage)
+ {
+ lblWarningMessage.Foreground = new SolidColorBrush(Colors.OrangeRed);
+ lblWarningMessage.Content = strMessage;
+ }
+
+ ///
+ /// Sets the validator label to a success message
+ ///
+ ///
+ private void SetSuccessMessage(string strMessage)
+ {
+ lblWarningMessage.Foreground = new SolidColorBrush(Colors.RoyalBlue);
+ lblWarningMessage.Content = strMessage;
+ }
+
+ ///
+ /// Button Yes Event Handler - Go ahead and Rename the WorkspaceName
+ ///
+ private void btnYes_Click(object sender, RoutedEventArgs e)
+ {
+ if (m_bIsValidName)
+ {
+ if (!DataAccessLayer.Data.Workspace.RenameWorkspace(m_strWorkspaceName, txtNewName.Text))
+ {
+ // an error occured
+ Foo.Platform.ErrorReporting.UserError.Show("An Error Occurred", "Renaming the Workspace Failed! Navigating you back to the WorkspaceSelector");
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+ }
+ else
+ {
+ // Set GUI State
+ GUIState.LastSelectedWorkspaceName = txtNewName.Text;
+
+ // Show Success Message
+ ShowMessageAndNavigateBack(String.Format("'{0}' has been successfully renamed to '{1}'", m_strWorkspaceName, txtNewName.Text));
+ }
+ }
+ }
+
+ ///
+ /// Shows the passed in message in the text box and then navigates back to the main page
+ ///
+ ///
+ private void ShowMessageAndNavigateBack(string strMessage)
+ {
+ // Hide the buttons
+ btnYes.Visibility = Visibility.Hidden;
+ btnNo.Visibility = Visibility.Hidden;
+
+ // Hide the textbox and Labels
+ lblEnterNewName.Visibility = Visibility.Hidden;
+ txtNewName.Visibility = Visibility.Hidden;
+ lblWarningMessage.Visibility = Visibility.Hidden;
+
+ // Show Message
+ txtRenameWorkspaceTitle.Text = strMessage;
+
+ // Dynamically calculate the height of the textbox * No need to do this in this case *
+ // System.Drawing.Size sz = new System.Drawing.Size((int)this.Width, int.MaxValue);
+ // Font font = new Font(txtRenameWorkspaceTitle.FontFamily.ToString(),(float) txtRenameWorkspaceTitle.FontSize);
+ // sz = TextRenderer.MeasureText(txtRenameWorkspaceTitle.Text, font, sz, TextFormatFlags.WordBreak);
+ // Change Height as needed
+ // lblRenameWorkspaceTitle.Height = sz.Height;
+ // txtRenameWorkspaceTitle.Height = sz.Height;
+
+ // default to change height to Max available space
+ lblRenameWorkspaceTitle.Height = this.Height - m_WorkspaceSelectorObj.MarginTopBottom;
+ txtRenameWorkspaceTitle.Height = this.Height - m_WorkspaceSelectorObj.MarginTopBottom;
+
+ // Pause for 1.5 second and Navigate Back
+ DispatcherTimer dispatcherTimer = new DispatcherTimer();
+ dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
+ dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1, 500);
+ dispatcherTimer.Start();
+ }
+
+ ///
+ /// Timer set specifically to allow the message to be seen for a little bit before navigating back
+ ///
+ void dispatcherTimer_Tick(object sender, EventArgs e)
+ {
+ DispatcherTimer dispatcherTimer = (DispatcherTimer)sender;
+ dispatcherTimer.Stop();
+
+ // Navigate Back
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+ }
+
+ ///
+ /// Button No Event Handler - Go back to parent
+ ///
+ private void btnNo_Click(object sender, RoutedEventArgs e)
+ {
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+ }
+
+ ///
+ /// Perform NewWorkspaceName TextBox Validation
+ ///
+ private void txtNewName_TextChanged(object sender, TextChangedEventArgs e)
+ {
+ System.Windows.Controls.TextBox textBox = (System.Windows.Controls.TextBox)sender;
+ if (String.IsNullOrEmpty(textBox.Text))
+ {
+ SetWarningMessage("Enter Characters");
+ m_bIsValidName = false;
+ }
+ else if (!DataAccessLayer.DataTypes.DataTypeValidation.IsValidWorkspaceName(textBox.Text))
+ {
+ SetWarningMessage("Invalid Workspace Name");
+ m_bIsValidName = false;
+ }
+ else if (DataAccessLayer.Data.Workspace.DoesWorkspaceNameExist(textBox.Text))
+ {
+ SetWarningMessage("Workspace Name Already Exists");
+ m_bIsValidName = false;
+ }
+ else
+ {
+ SetSuccessMessage("Valid Workspace Name");
+ m_bIsValidName = true;
+ }
+ }
+ }
+}
diff --git a/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_StandardPage.xaml b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_StandardPage.xaml
new file mode 100644
index 0000000..c5b5c68
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_StandardPage.xaml
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_StandardPage.xaml.cs b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_StandardPage.xaml.cs
new file mode 100644
index 0000000..ece8dc3
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPFPages/WorkspaceSelector_StandardPage.xaml.cs
@@ -0,0 +1,418 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Collections.ObjectModel;
+using Microsoft.Windows.Controls;
+using System.Data;
+using System.ComponentModel;
+
+// Foo Namespace
+using Foo.WorkspaceMgr;
+using Foo.DataAccessLayer;
+using Foo.DataAccessLayer.DataTypes;
+using Foo.GUILib;
+
+namespace Foo.ClientServices.GUIWPForms
+{
+ ///
+ /// Interaction logic for WorkspaceSelector_StandardPage.xaml
+ ///
+ public partial class WorkspaceSelector_StandardPage : Page
+ {
+ // passed to us by parent
+ private WorkspaceSelector m_WorkspaceSelectorObj = null;
+ private bool m_bPerformanceCache = false;
+
+ // WorkspaceMgr - Imp
+ private WorkspaceMgr.WorkspaceMgr m_WorkspaceMgr = null;
+
+ // private DT holds all information needed for the DataGrid
+ public DataTable WorkspacesDT { get; private set; }
+
+ ///
+ /// Constructor
+ ///
+ ///
+ public WorkspaceSelector_StandardPage(bool bPerformanceCache)
+ {
+ // We preload & require the WorkspaceMgr in this class
+ m_WorkspaceMgr = new WorkspaceMgr.WorkspaceMgr();
+
+ // Preload Database call - to make sure it is fast when the user sees it
+ String[] workspaceNames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+
+ m_bPerformanceCache = bPerformanceCache;
+ if (!m_bPerformanceCache)
+ {
+ }
+
+ InitializeComponent();
+ }
+
+ ///
+ /// Called when we want to Update the DataGrid with new DataTable Items
+ /// ~Responsible for reloading the WorkspacesDT
+ ///
+ private void UpdateWorkspaceGridItems(SortOrderForWorkspaces sortOrder)
+ {
+ // First Step - Clear the Grid
+ WorkspacesDT.Rows.Clear();
+
+ // Second Step - Fill the Grid with the WorkspaceNames
+ String[] workspaceNames = Data.Workspace.GetAllWorkspaceNames(sortOrder);
+
+ int i = 0;
+ int selectedIndex = -1;
+ foreach (string workspaceName in workspaceNames)
+ {
+ var row = WorkspacesDT.NewRow();
+ WorkspacesDT.Rows.Add(row);
+ row["WorkspaceName"] = workspaceName;
+ row["ButtonResUri"] = "PageImages/Launch.png";//"PageImages/Launch.png";
+ row["ButtonToolTipText"] = "Launch This Workspace";
+
+ // Let's Determine which index is supposed to be selected
+ if (!String.IsNullOrEmpty(GUIState.LastSelectedWorkspaceName) &&
+ (workspaceName == GUIState.LastSelectedWorkspaceName))
+ selectedIndex = i;
+
+ i = i + 1; // incr.
+ }
+
+ // Third Step - Refresh The DataGrid
+ dataGridWorkspaces.ItemsSource = WorkspacesDT.DefaultView;
+ // Other ways to refresh * appears to not be needed here * could be useful later
+ //dataGridWorkspaces.ItemsSource = (WorkspacesDT as IListSource).GetList();
+ //dataGridWorkspaces.Items.Refresh();
+
+ // Fourth Step - Reset the ColumnWidth of the WorkspaceName if no Scrollbar is visible
+ if (workspaceNames.Length <= 13)
+ {
+ // scrollbar not visible
+ DataGridLength gridbuffer = new DataGridLength(188 + 18);
+ dataGridWorkspaces.Columns[0].Width = gridbuffer;
+ }
+ else
+ {
+ // scrollbar visible
+ DataGridLength gridbuffer = new DataGridLength(188);
+ dataGridWorkspaces.Columns[0].Width = gridbuffer;
+ }
+
+ // Fifth Step - Set the Selected Index of the DataGrid to the last set
+ // Workspace Or 0 if not found
+ if (selectedIndex >= 0)
+ dataGridWorkspaces.SelectedIndex = selectedIndex;
+ else
+ dataGridWorkspaces.SelectedIndex = 0;
+ }
+
+ #region Page Events
+
+ ///
+ /// Called when the Page is loaded
+ ///
+ private void Page_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (!m_bPerformanceCache)
+ {
+ // Make sure that the Selector Frame is big enough to hold this page
+ m_WorkspaceSelectorObj = (WorkspaceSelector)this.Tag;
+ m_WorkspaceSelectorObj.Height = this.Height + m_WorkspaceSelectorObj.MarginTopBottom;
+ m_WorkspaceSelectorObj.Width = this.Width;
+
+ // InitializeWorkspaceDT
+ WorkspacesDT = new DataTable("WorkspaceData");
+ WorkspacesDT.Columns.Add(new DataColumn("WorkspaceName", typeof(string)));
+ WorkspacesDT.Columns.Add(new DataColumn("ButtonResUri", typeof(string)));
+ WorkspacesDT.Columns.Add(new DataColumn("ButtonToolTipText", typeof(string)));
+
+ // Set Workspaces Label
+ lblCurrentWorkspace.Content = "Workspaces";
+
+ // Load ComboBox Sort Orders
+ comboBoxSortBy.Items.Add(WPFHelper.CreateAComboBoxItem("Sort By Last Accessed", SortOrderForWorkspaces.LastAccessedDescending));
+ comboBoxSortBy.Items.Add(WPFHelper.CreateAComboBoxItem("Sort By Most Frequently Used", SortOrderForWorkspaces.MostFrequentlyAccessedDescending));
+ comboBoxSortBy.Items.Add(WPFHelper.CreateAComboBoxItem("Sort By Name", SortOrderForWorkspaces.Ascending));
+
+ // Load GUI State (or Default Index)
+ comboBoxSortBy.SelectedIndex = GUIState.LastSelectedSotOrderWorkspacesIndex;
+
+ // Assign ToolTips for the Buttons
+ btnNew.ToolTip = WPFHelper.CreateNewStringToolTip("New Workspace", 0, 120);
+ btnEdit.ToolTip = WPFHelper.CreateNewStringToolTip("Rename Workspace", 0, 120);
+ btnDelete.ToolTip = WPFHelper.CreateNewStringToolTip("Delete Workspace", 0, 120);
+ btnCloseAll.ToolTip = WPFHelper.CreateNewStringToolTip("Close All Workspaces", 0, 120);
+ }
+ }
+
+ #endregion
+
+ #region ComboBox Events
+
+ ///
+ /// Combo Box - SortBy - Selection Change Event * Deal with repopulating the Workspace Datagrid
+ ///
+ private void comboBoxSortBy_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ ComboBox combobox = sender as ComboBox;
+ if (combobox != null)
+ {
+ ComboBoxItem item = (ComboBoxItem)combobox.SelectedItem;
+ string Content = item.Content.ToString();
+ SortOrderForWorkspaces sortOrder = (SortOrderForWorkspaces)item.Tag;
+
+ // Save the State Information * Last SortOrder and Last SortOrder Index *
+ GUIState.LastSelectedSotOrderWorkspaces = sortOrder;
+ GUIState.LastSelectedSotOrderWorkspacesIndex = combobox.SelectedIndex;
+
+ // Update The Grid
+ UpdateWorkspaceGridItems(sortOrder);
+ }
+ }
+
+ #endregion
+
+ #region DataGrid Events
+
+ ///
+ /// Upon double-click we should be launching the Workspace (unload any previously loaded ones)
+ ///
+ private void dataGridWorkspaces_MouseDoubleClick(object sender, MouseButtonEventArgs e)
+ {
+ string strWorkspaceName = dataGrid_GetSelectedWorkspaceIfThereIsOne();
+ if (!String.IsNullOrEmpty(strWorkspaceName))
+ {
+
+ }
+ }
+
+ ///
+ /// Selection changed - Keep track of last selected workspace in GUIState
+ ///
+ private void dataGridWorkspaces_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
+ {
+ string strWorkspaceName = dataGrid_GetSelectedWorkspaceIfThereIsOne();
+ if (!String.IsNullOrEmpty(strWorkspaceName))
+ GUIState.LastSelectedWorkspaceName = strWorkspaceName;
+ }
+
+ ///
+ /// Get Whatever Workspace the User currently has selected in the Grid
+ ///
+ /// Selected Workpsace Or Empty String if there is none
+ private string dataGrid_GetSelectedWorkspaceIfThereIsOne()
+ {
+ String strWorkspaceName = String.Empty;
+
+ // We only allow single selection
+ IList cells = dataGridWorkspaces.SelectedCells;
+ if (cells.Count > 0)
+ {
+ DataGridCellInfo cell = cells[0];
+ DataRowView row = (DataRowView)cell.Item;
+ strWorkspaceName = row["WorkspaceName"].ToString();
+ }
+ return strWorkspaceName;
+ }
+
+ ///
+ /// Creates the DataGrid Context Menu according to the Selected Workspace State
+ ///
+ /// valid Context Menu or Null
+ private ContextMenu dataGrid_CreateDataGridContextMenu()
+ {
+ string strWorkspaceName = dataGrid_GetSelectedWorkspaceIfThereIsOne();
+ if (!String.IsNullOrEmpty(strWorkspaceName))
+ {
+ // We also want to load the state of the workspace here
+ ContextMenu menu = new ContextMenu();
+ menu.PlacementTarget = this;
+
+ // Load all the MenuItems
+ MenuItem m1 = new MenuItem();
+ m1.Header = "Launch";
+ m1.Click += new RoutedEventHandler(ContextMenu_Item_Click);
+ m1.FontWeight = FontWeights.Bold;
+ m1.Icon = WPFHelper.CreateWPFImageFromRelativeResourceUri("PageImages/Launch.png", 16, 16);
+ menu.Items.Add(m1);
+
+ MenuItem m2 = new MenuItem();
+ m2.Header = "Show";
+ m2.Click += new RoutedEventHandler(ContextMenu_Item_Click);
+ m2.Icon = WPFHelper.CreateWPFImageFromRelativeResourceUri("PageImages/Hide.png", 16, 16);
+ menu.Items.Add(m2);
+
+ MenuItem m3 = new MenuItem();
+ m3.Header = "Hide";
+ m3.Click += new RoutedEventHandler(ContextMenu_Item_Click);
+ m3.Icon = WPFHelper.CreateWPFImageFromRelativeResourceUri("PageImages/Hide.png", 16, 16);
+ menu.Items.Add(m3);
+
+ MenuItem m4 = new MenuItem();
+ m4.Header = "Close";
+ m4.Click += new RoutedEventHandler(ContextMenu_Item_Click);
+ m4.Icon = WPFHelper.CreateWPFImageFromRelativeResourceUri("PageImages/Close.png", 16, 16);
+ menu.Items.Add(m4);
+
+ // Load all the Events
+ menu.Closed += new RoutedEventHandler(ContextMenu_Closed);
+ menu.MouseLeave += new MouseEventHandler(ContextMenu_MouseLeave);
+ return menu;
+ }
+ return null;
+ }
+
+ ///
+ /// We need to manually implement the context menu upon right click and not use wpf,
+ /// because of the mouse leave event
+ ///
+ private void dataGridWorkspaces_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
+ {
+ ContextMenu menu = dataGrid_CreateDataGridContextMenu();
+ if (menu != null)
+ {
+ // Make sure that leave doesn't work
+ m_WorkspaceSelectorObj.DontCloseOnMouseLeave = true;
+
+ // Show the Context Menu
+ menu.IsOpen = true;
+ }
+ }
+
+ #endregion
+
+ #region ContextMenu Events
+
+ ///
+ /// Context Menu - Closed Event
+ ///
+ void ContextMenu_Closed(object sender, RoutedEventArgs e)
+ {
+ // Make sure that navigator leave works again
+ m_WorkspaceSelectorObj.DontCloseOnMouseLeave = false;
+
+ // Close the Navigation Form *if the mouse is NOT over it*
+ if (!WPFHelper.IsMouseCursorOverWPFormWindow(m_WorkspaceSelectorObj))
+ m_WorkspaceSelectorObj.Close();
+ }
+
+ ///
+ /// Context Menu - Mouse Leave Event
+ ///
+ void ContextMenu_MouseLeave(object sender, MouseEventArgs e)
+ {
+ // On Leave just close the Menu
+ ContextMenu menu = (ContextMenu)sender;
+ menu.IsOpen = false;
+ }
+
+ ///
+ /// Context Menu - Menu Item Clicked Event
+ ///
+ void ContextMenu_Item_Click(object sender, RoutedEventArgs e)
+ {
+ MenuItem m = (MenuItem)sender;
+
+ string strWorkspaceName = dataGrid_GetSelectedWorkspaceIfThereIsOne();
+ if (!String.IsNullOrEmpty(strWorkspaceName))
+ {
+ bool bSuccess = false;
+ switch (m.Header.ToString())
+ {
+ case "Launch":
+ {
+ bSuccess = m_WorkspaceMgr.LaunchWorkspace(strWorkspaceName);
+ }
+ break;
+
+ case "Show":
+ {
+ bSuccess = m_WorkspaceMgr.HideShowWorkspace(strWorkspaceName, true);
+ }
+ break;
+
+ case "Hide":
+ {
+ bSuccess = m_WorkspaceMgr.HideShowWorkspace(strWorkspaceName, false);
+ }
+ break;
+
+ case "Close":
+ {
+ bSuccess = m_WorkspaceMgr.CloseWorkspace(strWorkspaceName);
+ }
+ break;
+ }
+ }
+ }
+
+ #endregion
+
+ #region Button Click Events
+
+ ///
+ /// New Button - Event Handler
+ ///
+ private void btnNew_Click(object sender, RoutedEventArgs e)
+ {
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_NewWorkspacePage);
+ }
+
+ ///
+ /// Edit Button - Event Handler
+ ///
+ private void btnEdit_Click(object sender, RoutedEventArgs e)
+ {
+ string strWorkspaceName = dataGrid_GetSelectedWorkspaceIfThereIsOne();
+ if (!String.IsNullOrEmpty(strWorkspaceName))
+ {
+ GUIState.LastSelectedWorkspaceName = strWorkspaceName;
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_RenameWorkspacePage);
+ }
+ }
+
+ ///
+ /// Delete Button - Event Handler
+ ///
+ private void btnDelete_Click(object sender, RoutedEventArgs e)
+ {
+ string strWorkspaceName = dataGrid_GetSelectedWorkspaceIfThereIsOne();
+ if (!String.IsNullOrEmpty(strWorkspaceName))
+ {
+ GUIState.LastSelectedWorkspaceName = strWorkspaceName;
+ m_WorkspaceSelectorObj.NavigateToChildPage(ChildPages.WorkspaceSelector_DeleteWorkspacePage);
+ }
+ }
+
+ ///
+ /// CloseAll Button - Event Handler
+ ///
+ private void btnCloseAll_Click(object sender, RoutedEventArgs e)
+ {
+ MessageBox.Show("Does Nothing");
+ }
+
+ ///
+ /// Button on the Grid is being clicked - Event Handler
+ ///
+ private void ButtonGrid_Click(object sender, RoutedEventArgs e)
+ {
+ string strWorkspaceName = dataGrid_GetSelectedWorkspaceIfThereIsOne();
+ if (String.IsNullOrEmpty(strWorkspaceName))
+ return;
+ }
+
+ #endregion
+ }
+}
diff --git a/Client Services/GUIWPForms/GUIWPForms.cs b/Client Services/GUIWPForms/GUIWPForms.cs
new file mode 100644
index 0000000..f72febb
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPForms.cs
@@ -0,0 +1,237 @@
+// For GUIDebugStepExe Debugging Only - Uncomment this #define
+#define GUIDEBUGSTEPEXE
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Runtime.InteropServices;
+using System.Windows.Interop;
+using System.EnterpriseServices;
+using System.Reflection;
+
+using Foo.Platform;
+using Foo.Platform.Win32;
+using System.Windows;
+
+namespace Foo.ClientServices.GUIWPForms
+{
+ ///
+ /// GUIWPForms - Com Callable Wrapper Class exposed to ButtonHook.
+ /// This class is responsible for creating the ButtonWPForm (a form created in response to a ButtonHook W32 Click)
+ ///
+ [Guid("481C24F8-D619-460b-955A-22055571430C")]
+ [ClassInterface(ClassInterfaceType.None)]
+ [ProgId("Foo.ClientServices.GUIWPForms")]
+ [ComVisible(true)]
+ [ObjectPooling(Enabled = true, MinPoolSize = 1, MaxPoolSize = 2500, CreationTimeout = 5000)]
+#if GUIDEBUGSTEPEXE
+ public class GUIWPForms : IGUIPWPForms
+#else
+ public class GUIWPForms : ServicedComponent, IProcessInitializer, IGUIPWPForms
+#endif
+ {
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ #region Construction / Destruction
+ public GUIWPForms() {}
+ ~GUIWPForms() { }
+ #endregion
+
+#if GUIDEBUGSTEPEXE
+ #region GuiDebugStepCustomStarterStopers
+ public void Start()
+ {
+ Log.Info(string.Format("{0}() - ComponentState Application Is being started", MethodBase.GetCurrentMethod().Name));
+ ComponentState.ApplicationIsRunning = true;
+ }
+
+ public void Stop()
+ {
+ Log.Info(string.Format("{0}() - ComponentState Application Is being stopped", MethodBase.GetCurrentMethod().Name));
+ ComponentState.ApplicationIsRunning = false;
+ }
+ #endregion
+#else
+ #region IProcessInitializer Members
+ public void Startup(object punkProcessControl)
+ {
+ Log.Info(string.Format("{0}() - ComponentState Application Is being started", MethodBase.GetCurrentMethod().Name));
+ ComponentState.ApplicationIsRunning = true;
+ }
+
+ public void Shutdown()
+ {
+ Log.Info(string.Format("{0}() - ComponentState Application Is being stopped", MethodBase.GetCurrentMethod().Name));
+ ComponentState.ApplicationIsRunning = false;
+ }
+ #endregion
+#endif
+
+ #region IGUIPWPForms Members
+
+ ///
+ /// Launches the ArtifactWall WPForm (if one already exists, relaunches)
+ ///
+ /// handle to the Button on the Deskband (used for positioning)
+ /// true if successful, false otherwise
+ public bool LaunchArtifactWall(IntPtr hDeskbandButtonWnd)
+ {
+ try
+ {
+ RECT rect;
+ bool bFillRect = false;
+ if (hDeskbandButtonWnd != IntPtr.Zero)
+ bFillRect = Win32Functions.GetWindowRect(hDeskbandButtonWnd, out rect);
+
+ // First Step - Create the WpfForm
+ ComponentState.GUIFormsMgr.Create_WpfFormDISP(WPForms.ArtifactWall);
+
+ // Second Step - If we have a Rect, set the location
+ if (bFillRect)
+ {
+ //GUIFormsMgr._Action action = new GUIFormsMgr._Action(delegate(Window wpfForm)
+ //{
+ // wpfForm.Height = nHeight;
+ // wpfForm.Width = nWidth;
+ //});
+ //ComponentState.GUIFormsMgr.RunAction_WpfFormDISP(WPForms.ArtifactWall, action);
+ }
+
+ // Third Step - Show the WpfForm
+ ComponentState.GUIFormsMgr.Show_WpfFormDISP(WPForms.ArtifactWall);
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - Error Occured", MethodBase.GetCurrentMethod().Name), e);
+ }
+ return true;
+ }
+
+ ///
+ /// Closes the ArtifactWall if exists
+ ///
+ /// true if closed, false if not existent
+ public bool CloseArtifactWall()
+ {
+ try
+ {
+ return ComponentState.GUIFormsMgr.Delete_WpfFormDISP(WPForms.ArtifactWall);
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - Error Occured", MethodBase.GetCurrentMethod().Name), e);
+ }
+ return false;
+ }
+
+ ///
+ /// Launches the WorkspaceSelector WPForm (if one already exists, relaunches)
+ ///
+ /// handle to the Button on the Deskband (used for positioning)
+ /// true if successful, false otherwise
+ public bool LaunchWorkspaceSelector(IntPtr hDeskbandButtonWnd)
+ {
+ try
+ {
+ RECT rect = new RECT();
+ rect.top = 0;
+ rect.left = 0;
+ bool bSuccess = false;
+ bool bFillRect = false;
+ if (hDeskbandButtonWnd != IntPtr.Zero)
+ bFillRect = Win32Functions.GetWindowRect(hDeskbandButtonWnd, out rect);
+
+ // First Step - Create the WpfForm
+ bSuccess = ComponentState.GUIFormsMgr.Create_WpfFormDISP(WPForms.WorkspaceSelector);
+ if (!bSuccess)
+ return false;
+
+ // Second Step - If we have a Rect, set the location of the Workspace Selector
+ if (bFillRect)
+ {
+ GUIFormsMgr._Action action = new GUIFormsMgr._Action(delegate(Window wpfForm)
+ {
+ wpfForm.Top = rect.top + rect.AsRectangle.Height + 2;
+ wpfForm.Left = rect.left - 200;
+ });
+ bSuccess = ComponentState.GUIFormsMgr.RunAction_WpfFormDISP(WPForms.WorkspaceSelector, action);
+ if (!bSuccess)
+ return false;
+ }
+
+ // Third Step - Show the WpfForm
+ bSuccess = ComponentState.GUIFormsMgr.Show_WpfFormDISP(WPForms.WorkspaceSelector);
+ if (!bSuccess)
+ return false;
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - Error Occured", MethodBase.GetCurrentMethod().Name), e);
+ return false;
+ }
+ return true;
+ }
+
+ ///
+ /// Closes the WorkspaceSelector if exists
+ ///
+ ///
+ /// true if closed, false if not existent
+ public bool CloseWorkspaceSelector()
+ {
+ try
+ {
+ return ComponentState.GUIFormsMgr.Delete_WpfFormDISP(WPForms.WorkspaceSelector);
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - Error Occured", MethodBase.GetCurrentMethod().Name), e);
+ }
+ return false;
+ }
+
+ ///
+ /// Launches the Settings and Abouts WPForm (if one already exists, relaunches)
+ ///
+ /// handle to the Button on the Deskband (used for positioning)
+ /// true if successful, false otherwise
+ public bool LaunchSettingsNAboutUs(IntPtr hDeskbandButtonWnd)
+ {
+ try
+ {
+ // First Step - Create the WpfForm
+ ComponentState.GUIFormsMgr.Create_WpfFormDISP(WPForms.SettingsNAboutUs);
+
+ // Second Step - Show the WpfForm
+ ComponentState.GUIFormsMgr.Show_WpfFormDISP(WPForms.SettingsNAboutUs);
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - Error Occured", MethodBase.GetCurrentMethod().Name), e);
+ }
+ return true;
+ }
+
+ ///
+ /// Closes the Settings And About us
+ ///
+ /// true if closed, false if not existent
+ public bool CloseSettingsNAboutUs()
+ {
+ try
+ {
+ return ComponentState.GUIFormsMgr.Delete_WpfFormDISP(WPForms.WorkspaceSelector);
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - Error Occured", MethodBase.GetCurrentMethod().Name), e);
+ }
+ return false;
+ }
+
+ #endregion
+ }
+}
diff --git a/Client Services/GUIWPForms/GUIWPForms.csproj b/Client Services/GUIWPForms/GUIWPForms.csproj
new file mode 100644
index 0000000..da59d58
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPForms.csproj
@@ -0,0 +1,212 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}
+ Library
+ Properties
+ Foo.ClientServices.GUIWPForms
+ GUIWPForms
+ v3.5
+ 512
+ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 4
+
+
+
+
+
+
+
+
+
+
+ true
+ MyKeyFile.SNK
+
+
+ true
+ full
+ false
+ ..\..\Target\Debug\
+ TRACE;DEBUG
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\..\Target\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ False
+ ..\..\Components\log4net.dll
+
+
+ 3.0
+
+
+ 3.0
+
+
+
+ 3.5
+
+
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+ 3.0
+
+
+ 3.0
+
+
+
+
+
+
+
+
+
+ ArtifactWall.xaml
+
+
+ SettingsNAboutUs.xaml
+
+
+ WorkspaceSelector.xaml
+
+
+
+ WorkspaceSelector_DeleteWorkspacePage.xaml
+
+
+ WorkspaceSelector_NewWorkspacePage.xaml
+
+
+ WorkspaceSelector_RenameWorkspacePage.xaml
+
+
+ WorkspaceSelector_StandardPage.xaml
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ True
+ Settings.settings
+
+
+
+
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}
+ DataAccessLayer
+
+
+ {C1282050-455B-44F4-8520-1C005E38EFB2}
+ GUILib
+
+
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}
+ Platform
+
+
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}
+ WorkspaceMgr
+
+
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(FrameworkDir)\regasm.exe "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /unregister
+$(FrameworkDir)\regasm.exe "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /tlb:$(TargetName).tlb /codebase
+REM $(FrameworkDir)\regsvcs.exe /reconfig "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /appdir:"$(SolutionDir)target\$(ConfigurationName)"
+
+
+
\ No newline at end of file
diff --git a/Client Services/GUIWPForms/GUIWPForms.csproj.bak b/Client Services/GUIWPForms/GUIWPForms.csproj.bak
new file mode 100644
index 0000000..4cea55f
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPForms.csproj.bak
@@ -0,0 +1,129 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}
+ Library
+ Properties
+ Foo.ClientServices.GUIWPForms
+ GUIWPForms
+ v3.5
+ 512
+ true
+ MyKeyFile.SNK
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ False
+ ..\..\Components\log4net.dll
+
+
+ 3.0
+
+
+ 3.0
+
+
+
+ 3.5
+
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+ 3.0
+
+
+ 3.0
+
+
+
+
+
+
+
+
+ ArtifactWall.xaml
+
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ True
+ Settings.settings
+
+
+
+
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}
+ Platform
+
+
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+
+ copy "$(TargetDir)$(TargetFileName)" "$(SolutionDir)target\$(ConfigurationName)" /Y
+copy "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)target\$(ConfigurationName)" /Y
+$(FrameworkDir)\regasm.exe "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /unregister
+$(FrameworkDir)\regasm.exe "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /tlb:$(TargetName).tlb /codebase
+$(FrameworkDir)\regsvcs.exe /reconfig "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /appdir:"$(SolutionDir)target\$(ConfigurationName)"
+
+
+
\ No newline at end of file
diff --git a/Client Services/GUIWPForms/GUIWPForms/ArtifactWall.xaml b/Client Services/GUIWPForms/GUIWPForms/ArtifactWall.xaml
new file mode 100644
index 0000000..69cd747
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPForms/ArtifactWall.xaml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client Services/GUIWPForms/GUIWPForms/ArtifactWall.xaml.cs b/Client Services/GUIWPForms/GUIWPForms/ArtifactWall.xaml.cs
new file mode 100644
index 0000000..455a4dd
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPForms/ArtifactWall.xaml.cs
@@ -0,0 +1,269 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Windows.Interop;
+using System.Windows.Threading;
+using System.Threading;
+
+using Foo.Platform;
+using Foo.GUILib;
+using Foo.DataAccessLayer;
+using Foo.DataAccessLayer.DataTypes;
+using System.Data;
+
+namespace Foo.ClientServices.GUIWPForms
+{
+ ///
+ /// Interaction logic for Window1.xaml
+ ///
+ public partial class ArtifactWall : Window
+ {
+ private bool m_bPerformanceCache = false;
+
+ // Height and Width Settings
+ private int m_ItemHeight = 0;
+ private int m_ItemWidth = 0;
+ private int m_ImageHeight = 0;
+ private int m_ImageWidth = 0;
+ private int m_StackPanelHeight = 0;
+ private int m_StackPanelWidth = 0;
+
+ // Hard-coded Settings
+ private const int ITEM_BORDER_THICKNESS = 2;
+ private const int SELECTION_BORDER_SIZE_MARGIN = 10;
+
+
+ // private DT holds all information needed for the DataGrid
+ public DataTable ArtifactsDT { get; private set; }
+
+ //object CreateImage(string Path)
+ //{
+ // Image myImage1 = new Image();
+ // myImage1.Height = HEIGHT;
+ // myImage1.Width = WIDTH;
+ // BitmapImage myBitmapImage1 = new BitmapImage();
+ // myBitmapImage1.BeginInit();
+ // myBitmapImage1.UriSource = new Uri(Path);
+ // myBitmapImage1.DecodePixelHeight = HEIGHT;
+ // myBitmapImage1.DecodePixelWidth = WIDTH;
+ // myBitmapImage1.EndInit();
+ // myImage1.Source = myBitmapImage1;
+
+ // //myImage1.Margin = new Thickness(25);
+ // return myImage1;
+ //}
+
+ Path CreatePath()
+ {
+ LineGeometry myLineGeometry = new LineGeometry();
+ myLineGeometry.StartPoint = new Point(10, 50);
+ myLineGeometry.EndPoint = new Point(1600,50);
+
+ Path myPath = new Path();
+ myPath.Stroke = Brushes.Black;
+ myPath.StrokeThickness = 1;
+ myPath.Data = myLineGeometry;
+ return myPath;
+ }
+
+ void AddWorkspaceArtifacts(string workspaceName)
+ {
+ //using (OoganizerState oogyState = new OoganizerState())
+ //{
+ // oogyState.SetCurrentWorkspace(workspaceName);
+
+ // using (OoganizerAPIProxy proxy = oogyState.GetAPIProxy())
+ // {
+ // Workspace workspace = proxy.API.GetWorkspace(workspaceName);
+
+ // foreach (OoganizerDAL.Artifact artifact in workspace.Artifacts)
+ // {
+ // xamCarouselPanel1.ChildElements.Add(CreateImage(artifact.Snapshot_Path));
+ // }
+ // }
+ //}
+ }
+
+ private void CalculateHeightAndWidthSettings()
+ {
+
+ // Image Settings
+ m_ImageHeight = 627;
+ m_ImageWidth = 400;
+
+ // StackPanel Settings
+ const int STACK_PANEL_ITEMS_HEIGHT = 84; // add together the other StackPanel items
+ m_StackPanelHeight = m_ImageHeight + STACK_PANEL_ITEMS_HEIGHT;
+ m_StackPanelWidth = m_ImageWidth;
+
+ // Item settings
+ m_ItemHeight = m_StackPanelHeight + SELECTION_BORDER_SIZE_MARGIN;
+ m_ItemWidth = m_StackPanelWidth + SELECTION_BORDER_SIZE_MARGIN;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ private void UpdateArtifactsWall(SortOrderForWorkspaces sortOrder)
+ {
+ // First Step - Clear the DT
+ ArtifactsDT.Rows.Clear();
+
+ // Second Step - Calculate Height/Width Settings
+ CalculateHeightAndWidthSettings();
+
+ // Third Step - Fill the DT with Artifact Information
+ ArtifactItem[] artifacts = Data.Artifacts.GetAllArtifactsInTheSystem(SortOrderForArtifacts.MostFrequentlyAccessedAscending);
+ foreach (ArtifactItem artifact in artifacts)
+ {
+ var row = ArtifactsDT.NewRow();
+ ArtifactsDT.Rows.Add(row);
+
+ // Border Settings
+ row["BorderBrush"] = "Aqua";
+ row["BorderThickness"] = ITEM_BORDER_THICKNESS;
+
+ // StackPanel Settings
+ row["StackPanelHeight"] = m_StackPanelHeight;
+ row["StackPanelWidth"] = m_StackPanelWidth;
+ row["StackPanelBackground"] = "Transparent";
+
+ // Image Settings
+ row["ImagePath"] = artifact.SnapshotFile;
+ row["ImageHeight"] = m_ImageHeight;
+ row["ImageWidth"] = m_ImageWidth;
+
+ // Artifact Information
+ if(artifact.IsFile)
+ row["Title"] = artifact.Name + " (" + artifact.FileName + ")";
+ else if(artifact.IsUrl)
+ row["Title"] = artifact.Name + " (" + artifact.Location + ")";
+
+ row["LastLaunch"] = "Last Accessed: " + artifact.LastAccessed.ToString();
+ row["FreqLaunch"] = "No. Times Accessed: " + artifact.AccessCounter.ToString();
+ row["Notes"] = artifact.Note;
+ }
+
+ // Third Step - Set xmlCarousel's Item Size
+ xamCarouselPanel1.ViewSettings.ItemSize = new Size(m_ItemWidth, m_ItemHeight);
+
+ // Fourth Step - Set the number of items * we could change this later*
+ xamCarouselPanel1.ViewSettings.ItemsPerPage = 3;
+
+ // Fifth Step - Refresh The xmlCarousel
+ xamCarouselPanel1.ItemsSource = ArtifactsDT.DefaultView;
+ }
+
+ public ArtifactWall(bool bPerformanceCache)
+ {
+ InitializeComponent();
+
+ // * For Performance Caching *
+ if (WPFHiddenWindow.HiddenWindowConstructor(this, bPerformanceCache))
+ {
+ m_bPerformanceCache = true;
+ }
+ else
+ {
+ // Set Window Position Here
+ WindowState = WindowState.Maximized;
+ WindowStartupLocation = WindowStartupLocation.CenterScreen;
+
+ xamCarouselPanel1.ViewSettings.ItemPath = CreatePath();
+ xamCarouselPanel1.ViewSettings.ItemHorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
+ xamCarouselPanel1.ViewSettings.ItemVerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
+ xamCarouselPanel1.ViewSettings.AutoScaleItemContentsToFit = true;
+ xamCarouselPanel1.Focus();
+ }
+
+ //WindowInteropHelper hInter = new WindowInteropHelper(this);
+ //int width = System.Windows.Forms.Screen.FromHandle(hInter.Handle).Bounds.Width;
+ //int height = System.Windows.Forms.Screen.FromHandle(hInter.Handle).Bounds.Height;
+ }
+
+ #region Page Events
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ // * For Performance Caching *
+ if (WPFHiddenWindow.HiddenWindowOnLoad(this, m_bPerformanceCache))
+ {
+ // Do anything you would like to load
+ }
+ else
+ {
+ // InitializeArtifactsDT
+ ArtifactsDT = new DataTable("ArtifactsData");
+
+ // Border Related Settings
+ ArtifactsDT.Columns.Add(new DataColumn("BorderBrush", typeof(string)));
+ ArtifactsDT.Columns.Add(new DataColumn("BorderThickness", typeof(string)));
+
+ // Image related Settings
+ ArtifactsDT.Columns.Add(new DataColumn("ImagePath", typeof(string)));
+ ArtifactsDT.Columns.Add(new DataColumn("ImageHeight", typeof(string)));
+ ArtifactsDT.Columns.Add(new DataColumn("ImageWidth", typeof(string)));
+
+ // StackPanel Settings
+ ArtifactsDT.Columns.Add(new DataColumn("StackPanelHeight", typeof(string)));
+ ArtifactsDT.Columns.Add(new DataColumn("StackPanelWidth", typeof(string)));
+ ArtifactsDT.Columns.Add(new DataColumn("StackPanelBackground", typeof(string)));
+
+ // Artifact Settings
+ ArtifactsDT.Columns.Add(new DataColumn("Title", typeof(string)));
+ ArtifactsDT.Columns.Add(new DataColumn("LastLaunch", typeof(string)));
+ ArtifactsDT.Columns.Add(new DataColumn("FreqLaunch", typeof(string)));
+ ArtifactsDT.Columns.Add(new DataColumn("Notes", typeof(string)));
+
+ //
+ UpdateArtifactsWall(SortOrderForWorkspaces.Ascending);
+ }
+ }
+
+ private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
+ {
+ // * For Performance Caching *
+ if (WPFHiddenWindow.HiddenWindowClosing(this, m_bPerformanceCache))
+ {
+ // Do anything you would like to load
+ }
+ else
+ {
+
+ }
+ }
+
+ #endregion
+
+ # region Button Click Events
+
+ private void btnClose_Click(object sender, RoutedEventArgs e)
+ {
+ this.Close();
+ }
+
+ private void btnUp_Click(object sender, RoutedEventArgs e)
+ {
+
+ }
+
+ private void btnDown_Click(object sender, RoutedEventArgs e)
+ {
+
+ }
+
+ #endregion
+ }
+}
+
diff --git a/Client Services/GUIWPForms/GUIWPForms/SettingsNAboutUs.xaml b/Client Services/GUIWPForms/GUIWPForms/SettingsNAboutUs.xaml
new file mode 100644
index 0000000..f2be67e
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPForms/SettingsNAboutUs.xaml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Auto-Hide Workspaces
+
+ Auto-Save Office Documents
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client Services/GUIWPForms/GUIWPForms/SettingsNAboutUs.xaml.cs b/Client Services/GUIWPForms/GUIWPForms/SettingsNAboutUs.xaml.cs
new file mode 100644
index 0000000..90117ee
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPForms/SettingsNAboutUs.xaml.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+using Foo.GUILib;
+using Foo.Platform.Satellite;
+
+namespace Foo.ClientServices.GUIWPForms
+{
+ ///
+ /// Interaction logic for SettingsNAboutUs.xaml
+ ///
+ public partial class SettingsNAboutUs : Window
+ {
+ private bool m_bPerformanceCache = false;
+
+ public SettingsNAboutUs(bool bPerformanceCache)
+ {
+ InitializeComponent();
+
+ // * For Performance Caching *
+ if (WPFHiddenWindow.HiddenWindowConstructor(this, bPerformanceCache))
+ {
+ m_bPerformanceCache = true;
+ }
+ else
+ {
+ // Set Window Position Here
+ WindowStartupLocation = WindowStartupLocation.CenterScreen;
+ }
+ }
+
+ #region Internationalization
+
+ private void LoadAllTexts_Internationalization()
+ {
+ // Load Tab Headers
+ tabSettings.Header = GUIResx.GetString("TAB_SETTINGSNABOUTUS_SETTINGS");
+ tabHelp.Header = GUIResx.GetString("TAB_SETTINGSNABOUTUS_HELP");
+ tabAboutUs.Header = GUIResx.GetString("TAB_SETTINGSNABOUTUS_ABOUTUS");
+
+ // Load Group Labels
+ groupBoxWorkspaceSelector.Header = GUIResx.GetString("GROUPBOX_SETTINGABOUTUS_WORKSPACESELECTOR");
+ groupBoxArtifactWall.Header = GUIResx.GetString("GROUPBOX_SETTINGABOUTUS_ARTIFACTWALL");
+
+ // Load Labels
+
+
+
+
+ }
+
+ #endregion
+
+
+ #region Window Events
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ // * For Performance Caching *
+ if (WPFHiddenWindow.HiddenWindowOnLoad(this, m_bPerformanceCache))
+ {
+
+ }
+ else
+ {
+ // Load Texts
+ LoadAllTexts_Internationalization();
+ }
+ }
+
+ private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
+ {
+ // * For Performance Caching *
+ if (WPFHiddenWindow.HiddenWindowClosing(this, m_bPerformanceCache))
+ {
+
+ }
+ else
+ {
+
+ }
+ }
+
+ #endregion
+
+ private void btnClose_Click(object sender, RoutedEventArgs e)
+ {
+ this.Close();
+ }
+ }
+}
diff --git a/Client Services/GUIWPForms/GUIWPForms/WorkspaceSelector.xaml b/Client Services/GUIWPForms/GUIWPForms/WorkspaceSelector.xaml
new file mode 100644
index 0000000..7e0fefe
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPForms/WorkspaceSelector.xaml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client Services/GUIWPForms/GUIWPForms/WorkspaceSelector.xaml.cs b/Client Services/GUIWPForms/GUIWPForms/WorkspaceSelector.xaml.cs
new file mode 100644
index 0000000..c3deb69
--- /dev/null
+++ b/Client Services/GUIWPForms/GUIWPForms/WorkspaceSelector.xaml.cs
@@ -0,0 +1,249 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+using System.Windows.Interop;
+using System.Reflection;
+using System.Windows.Threading;
+
+using Foo.Platform;
+using Foo.GUILib;
+
+
+namespace Foo.ClientServices.GUIWPForms
+{
+ public enum ChildPages
+ {
+ WorkspaceSelector_StandardPage,
+ WorkspaceSelector_NewWorkspacePage,
+ WorkspaceSelector_RenameWorkspacePage,
+ WorkspaceSelector_DeleteWorkspacePage,
+ }
+
+ ///
+ /// Interaction logic for WorkspaceSelector.xaml
+ ///
+ public partial class WorkspaceSelector : Window
+ {
+ private bool m_bPerformanceCache = false;
+ private Page[] m_ChildPages = null;
+
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ // Allow Childresn access to the Frame
+ public Frame WorkspaceSelectorFrm { get { return frmWorkspaceSelector; } }
+
+ // Allow Children to overwrite MouseLeave Close Behavior
+ public bool DontCloseOnMouseLeave { get; set; }
+
+ // Allow Children access to margin top/bottom
+ public int MarginTopBottom { get; set; }
+
+ // internal flags
+ private bool m_bMouseFirstTimeEnter = false;
+ private bool m_bMouseHasEnteredBack = false;
+ private bool m_bMouseLeaveTimerCreated = false;
+
+ ///
+ /// Child Page Creation Factory * should only be called internally *
+ ///
+ /// the page to instantiate
+ /// a new page object or null
+ private Page CreateChildPage(ChildPages page)
+ {
+ Page pageObj = null;
+ switch (page)
+ {
+ case ChildPages.WorkspaceSelector_NewWorkspacePage:
+ pageObj = new WorkspaceSelector_NewWorkspacePage(m_bPerformanceCache);
+ break;
+
+ case ChildPages.WorkspaceSelector_RenameWorkspacePage:
+ pageObj = new WorkspaceSelector_RenameWorkspacePage(m_bPerformanceCache);
+ break;
+
+ case ChildPages.WorkspaceSelector_DeleteWorkspacePage:
+ pageObj = new WorkspaceSelector_DeleteWorkspacePage(m_bPerformanceCache);
+ break;
+
+ case ChildPages.WorkspaceSelector_StandardPage:
+ pageObj = new WorkspaceSelector_StandardPage(m_bPerformanceCache);
+ break;
+ }
+ return pageObj;
+ }
+
+ ///
+ /// Use this to actually navigate to a child page object on the WorkspaceSelector
+ ///
+ /// a page to navigate to
+ public void NavigateToChildPage(ChildPages page)
+ {
+ try
+ {
+ Page pageObj = CreateChildPage(page);
+ if (pageObj != null)
+ {
+ pageObj.Tag = this; // pass out this object
+ if (!frmWorkspaceSelector.Navigate(pageObj))
+ Log.Info(string.Format("{0}() - WorkspaceSelector could not navigate to ChildPage {1}", MethodBase.GetCurrentMethod().Name, (int)page));
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - Error Thrown", MethodBase.GetCurrentMethod().Name, e));
+ }
+ }
+
+ ///
+ /// WorkspaceSelector Constructor - set's default values for the object
+ /// Instantiates all child pages when in Performance Mode
+ ///
+ /// true if this is a cached form for performance, false every other time
+ public WorkspaceSelector(bool bPerformanceCache)
+ {
+ InitializeComponent();
+
+ // * For Performance Caching *
+ if (WPFHiddenWindow.HiddenWindowConstructor(this, bPerformanceCache))
+ {
+ m_bPerformanceCache = true;
+
+ // Performance Load the Child Pages as well
+ int n = Enum.GetValues(typeof(ChildPages)).Length;
+ m_ChildPages = new Page[n];
+
+ // Iterate thru enums and create the corresponding objects in the Cache
+ for (int i = 0; i < n; ++i)
+ {
+ ChildPages page = (ChildPages)Enum.ToObject(typeof(ChildPages), i);
+ m_ChildPages[i] = CreateChildPage(page);
+ }
+ }
+
+ // By default allow mouse leave to close the form
+ DontCloseOnMouseLeave = false;
+
+ // MarginTopBottom is the space up and below the frame 2 * 6 = 12 (but we want 2 pixels trimmed)
+ MarginTopBottom = 10;
+ }
+
+ #region Window Events
+
+ ///
+ /// Window Load Event - Hook into MessageHook if in performance mode,
+ /// otherwise load default child
+ ///
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ // * For Performance Caching *
+ if (WPFHiddenWindow.HiddenWindowOnLoad(this, m_bPerformanceCache))
+ {
+ // To Anything her you may want to do
+ }
+ else
+ {
+ // Navigate to the Default Page
+ NavigateToChildPage(ChildPages.WorkspaceSelector_StandardPage);
+
+ // Set the GUI State to this object
+ GUIState.CurrentlyShowingWPFWindow = this;
+
+ // Start the Load Mouse Enter Timer for 1.5 seconds
+ DispatcherTimer dispatcherTimer = new DispatcherTimer();
+ dispatcherTimer.Tick += new EventHandler(dispatcherTimerOnLoadMouseEnter_Tick);
+ dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1, 500);
+ dispatcherTimer.Start();
+ }
+ }
+
+ ///
+ /// keep track of window closed
+ ///
+ private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
+ {
+ // * For Performance Caching *
+ if (WPFHiddenWindow.HiddenWindowClosing(this, m_bPerformanceCache))
+ {
+ // To Anything her you may want to do
+ }
+ else
+ {
+ // Set the GUI State to this object
+ GUIState.CurrentlyShowingWPFWindow = null;
+ }
+ }
+
+ ///
+ /// Keep track of mouse enter
+ ///
+ private void Window_MouseEnter(object sender, MouseEventArgs e)
+ {
+ m_bMouseFirstTimeEnter = true;
+ m_bMouseHasEnteredBack = true;
+ }
+
+ ///
+ /// General Standard behavior - Close the form on Mouse Leave, except when
+ /// children overwrite this behavior via DontCloseOnMouseLeave
+ ///
+ private void Window_MouseLeave(object sender, MouseEventArgs e)
+ {
+ m_bMouseHasEnteredBack = false;
+ if (!m_bMouseLeaveTimerCreated)
+ {
+ // Start Mouse Leave Timer for 1.5 seconds
+ DispatcherTimer dispatcherTimer = new DispatcherTimer();
+ dispatcherTimer.Tick += new EventHandler(dispatcherTimerMouseLeave_Tick);
+ dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 1, 500);
+ dispatcherTimer.Start();
+
+ // Set flag
+ m_bMouseLeaveTimerCreated = true;
+ }
+ }
+
+ #endregion
+
+ ///
+ /// Run One Time - after Mouse Leaves. Closes Form if Mouse has not entered
+ ///
+ void dispatcherTimerMouseLeave_Tick(object sender, EventArgs e)
+ {
+ // Turn off the timer
+ DispatcherTimer dispatcherTimer = (DispatcherTimer)sender;
+ dispatcherTimer.Stop();
+ m_bMouseLeaveTimerCreated = false;
+
+ // Close this window, but only if the mouse has not entered back ||
+ // we are told not to do it
+ if (!m_bMouseHasEnteredBack && !DontCloseOnMouseLeave)
+ this.Close();
+ }
+
+ ///
+ /// Run One Time - Upon Load. Closes form if mouse has not entered
+ ///
+ void dispatcherTimerOnLoadMouseEnter_Tick(object sender, EventArgs e)
+ {
+ // We only want to run this timer Once * Always *
+ DispatcherTimer dispatcherTimer = (DispatcherTimer)sender;
+ dispatcherTimer.Stop();
+
+ // Close this window, but only if the mouse has not entered back
+ // Close this Form *always*
+ if (!m_bMouseFirstTimeEnter && !DontCloseOnMouseLeave)
+ this.Close();
+ }
+
+ }
+}
diff --git a/Client Services/GUIWPForms/IGUIWPForms.cs b/Client Services/GUIWPForms/IGUIWPForms.cs
new file mode 100644
index 0000000..ea6875a
--- /dev/null
+++ b/Client Services/GUIWPForms/IGUIWPForms.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace Foo.ClientServices.GUIWPForms
+{
+ ///
+ /// GUIPWPForms uses IGUIPWPForms Interface. It exposes functions to external
+ /// callers regarding the type of GUIWPForms we can launch.
+ /// ~Most functions require an hWnd which is the DeskbandButton to properly Position the form.
+ /// ~However if hWnd is Zero and we are in Debug we just center it. * For Debugging Purpose *
+ ///
+ [Guid("652DDE0A-D3FA-4525-8272-1616127819D2")]
+ [InterfaceType(ComInterfaceType.InterfaceIsDual)]
+ [ComVisible(true)]
+ public interface IGUIPWPForms
+ {
+ // ArtifactWall
+ bool LaunchArtifactWall(IntPtr hDeskbandButtonWnd);
+ bool CloseArtifactWall();
+
+ // WorkspaceSelector
+ bool LaunchWorkspaceSelector(IntPtr hDeskbandButtonWnd);
+ bool CloseWorkspaceSelector();
+
+ // Settings N' About Us Page
+ bool LaunchSettingsNAboutUs(IntPtr hDeskbandButtonWnd);
+ bool CloseSettingsNAboutUs();
+ }
+}
diff --git a/Client Services/GUIWPForms/MyKeyFile.SNK b/Client Services/GUIWPForms/MyKeyFile.SNK
new file mode 100644
index 0000000..8bc8162
Binary files /dev/null and b/Client Services/GUIWPForms/MyKeyFile.SNK differ
diff --git a/Client Services/GUIWPForms/Properties/AssemblyInfo.cs b/Client Services/GUIWPForms/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..8a9f4bf
--- /dev/null
+++ b/Client Services/GUIWPForms/Properties/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+using System.EnterpriseServices;
+
+// 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("GUIWPForms")]
+[assembly: AssemblyDescription("Performance Caching for GUIWPForms")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Ooganizer Corporation")]
+[assembly: AssemblyProduct("GUIWPForms")]
+[assembly: AssemblyCopyright("Copyright © Ooganizer Corporation 2009")]
+[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(true)]
+[assembly: ApplicationID("E6A84616-5ED1-4679-B26D-64F80A5E41CD")]
+[assembly: ApplicationActivation(ActivationOption.Server)]
+[assembly: ApplicationAccessControl(Value = false, Authentication = AuthenticationOption.None)]
+[assembly: ApplicationName("Foo.ClientServices")]
+[assembly: Description("Provides Data Access and Performance Caching for Ooganizer Components")]
+
+//In order to begin building localizable applications, set
+//CultureYouAreCodingWith in your .csproj file
+//inside a . For example, if you are using US english
+//in your source files, set the to en-US. Then uncomment
+//the NeutralResourceLanguage attribute below. Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
+
+// 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")]
diff --git a/Client Services/GUIWPForms/Properties/Resources.Designer.cs b/Client Services/GUIWPForms/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..2a780dd
--- /dev/null
+++ b/Client Services/GUIWPForms/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.ClientServices.GUIWPForms.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Foo.ClientServices.GUIWPForms.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Client Services/GUIWPForms/Properties/Resources.resx b/Client Services/GUIWPForms/Properties/Resources.resx
new file mode 100644
index 0000000..85c9090
--- /dev/null
+++ b/Client Services/GUIWPForms/Properties/Resources.resx
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.3
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Client Services/GUIWPForms/Properties/Settings.Designer.cs b/Client Services/GUIWPForms/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..d100d52
--- /dev/null
+++ b/Client Services/GUIWPForms/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.ClientServices.GUIWPForms.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Client Services/GUIWPForms/Properties/Settings.settings b/Client Services/GUIWPForms/Properties/Settings.settings
new file mode 100644
index 0000000..15034e7
--- /dev/null
+++ b/Client Services/GUIWPForms/Properties/Settings.settings
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/Client Services/GUIWPForms/Properties/licenses.licx b/Client Services/GUIWPForms/Properties/licenses.licx
new file mode 100644
index 0000000..e8ba8ea
--- /dev/null
+++ b/Client Services/GUIWPForms/Properties/licenses.licx
@@ -0,0 +1 @@
+Infragistics.Windows.Controls.XamCarouselListBox, Infragistics3.Wpf.v8.2, Version=8.2.20082.1002, Culture=neutral, PublicKeyToken=7dd5c3163f2cd0cb
diff --git a/Components/log4net.dll b/Components/log4net.dll
new file mode 100644
index 0000000..ffc57e1
Binary files /dev/null and b/Components/log4net.dll differ
diff --git a/DataAccessLayer/DB.cs b/DataAccessLayer/DB.cs
new file mode 100644
index 0000000..248a863
--- /dev/null
+++ b/DataAccessLayer/DB.cs
@@ -0,0 +1,298 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Data;
+using System.Data.SqlServerCe;
+using System.Text;
+using System.IO;
+using System.Resources;
+using System.Reflection;
+
+namespace Foo.DataAccessLayer
+{
+ public class DB
+ {
+ ///
+ /// Private Properties
+ ///
+ private static string _dbPath = "C:\\_ROOT_\\TestANizer\\DataAccessLayer";
+ private static string _dbName = "OggyNize.sdf";
+ private static string _dbPassword = "1kso123!~~!@";
+ private static string _connString { get { return String.Format("Data Source={0}\\{1}; encryption mode=platform default; Password=\"{2}\"; Encrypt = TRUE;", Path.GetFullPath(_dbPath), _dbName, _dbPassword); } }
+
+ ///
+ /// Public Properties
+ ///
+ public static bool DoesDBExist { get { return (File.Exists(_dbPath + "\\" + _dbName)); } }
+
+ ///
+ /// Use this to create the Default Database
+ ///
+ public static void CreateDefaultDB()
+ {
+ CreateDB(_dbPath, _dbName, _dbPassword);
+ }
+
+ ///
+ /// Use this to delete the Default Database
+ ///
+ public static void DeleteDefaultDB()
+ {
+ if (!String.IsNullOrEmpty(_dbPath) &&
+ !String.IsNullOrEmpty(_dbName) &&
+ Directory.Exists(_dbPath) &&
+ File.Exists(_dbPath + "\\" + _dbName))
+ {
+ File.Delete(_dbPath + "\\" + _dbName);
+ }
+ }
+
+ ///
+ /// Use this function to create a New Database, if it doesn't already exist
+ ///
+ /// Path to the Database
+ /// Name of the Database
+ /// Password to use on the Database
+ internal static void CreateDB(string dbPath, string dbName, string dbPassword)
+ {
+ try
+ {
+ if (dbPath.Length > 3 && dbPath[dbPath.Length - 1] == '\\')
+ dbPath = dbPath.Remove(dbPath.Length - 1);
+
+ if (!String.IsNullOrEmpty(dbName) && !dbName.ToLower().Contains(".sdf"))
+ dbName = dbName + ".sdf";
+
+ if (!String.IsNullOrEmpty(dbPath) &&
+ !String.IsNullOrEmpty(dbName) &&
+ Directory.Exists(dbPath) &&
+ !File.Exists(dbPath + "\\" + dbName))
+ {
+ _dbPath = dbPath;
+ _dbName = dbName;
+ _dbPassword = dbPassword;
+ using (SqlCeEngine engine = new SqlCeEngine(_connString))
+ {
+ engine.CreateDatabase();
+ }
+
+ // This will now Construct all the necessary Tables
+ // we need ~very nice and automatic
+ CreateInitialDBTables();
+ }
+ }
+ catch (Exception) { /* ignore */ }
+ }
+
+ ///
+ /// Responsible for creating all the initial Tables for the database
+ ///
+ private static void CreateInitialDBTables()
+ {
+ foreach (string TableResourceName in ResourceHelper.GetTableResourceNames())
+ {
+ string strSQL = ResourceHelper.GetTextSqlFromResourceFile(TableResourceName);
+ string[] strCommands = strSQL.Split(';');
+
+ foreach (string strCommand in strCommands)
+ {
+ // Is there a Label
+ if (strCommand.Contains(':'))
+ {
+ string[] strLabelAndCommand = strCommand.Split(':');
+ string strLabel = strLabelAndCommand[0];
+ string strCommand2 = strLabelAndCommand[1];
+
+ // Save the Label in the Version Map
+ string strTableName = ResourceHelper.GetTableNameFromTableResourceName(TableResourceName);
+ ResourceHelper.s_VersioningTablesMap[strTableName] = strLabel;
+
+ // Run the Command
+ RunSQLCommandTextExecuteNonQuery(strCommand2.Trim());
+ }
+ else
+ {
+ RunSQLCommandTextExecuteNonQuery(strCommand.Trim());
+ }
+ }
+ }
+
+ // Now that all Tables are created, we can now save the VersionMap into the Database
+ dVersioningTables versionTable = new dVersioningTables();
+ foreach (string key in ResourceHelper.s_VersioningTablesMap.Keys)
+ versionTable.AddUpdateVersionInformationForSpecifiedTable(key, ResourceHelper.s_VersioningTablesMap[key]);
+ }
+
+ ///
+ /// Use this to Run SQL with the ExecuteNonQuery() Command Object
+ ///
+ /// SQL Text/Commands to execute
+ /// the result of the ExecuteNonQuery() operation
+ internal static int RunSQLCommandTextExecuteNonQuery(string SqlCommandText)
+ {
+ int nResult = -1;
+ try
+ {
+ using (SqlCeConnection conn = new SqlCeConnection(_connString))
+ {
+ conn.Open();
+ using (SqlCeCommand cmd = conn.CreateCommand())
+ {
+ cmd.CommandText = SqlCommandText;
+ nResult = cmd.ExecuteNonQuery();
+ }
+ }
+ }
+ catch (Exception) { /* ignore */ }
+ return nResult;
+ }
+
+ ///
+ /// Use this to Run SQL with the ExecuteNonQuery() Command Object
+ ///
+ /// SQL Text/Commands to execute
+ /// Allows the use of sql parameters
+ /// the result of the ExecuteNonQuery() operation
+ internal static int RunSQLCommandTextExecuteNonQuery(string SqlCommandText, SqlCeParameter[] parameters)
+ {
+ int nResult = -1;
+ try
+ {
+ using (SqlCeConnection conn = new SqlCeConnection(_connString))
+ {
+ conn.Open();
+ using (SqlCeCommand cmd = conn.CreateCommand())
+ {
+ cmd.CommandText = SqlCommandText;
+ foreach (SqlCeParameter parameter in parameters)
+ cmd.Parameters.Add(parameter);
+ nResult = cmd.ExecuteNonQuery();
+ }
+ }
+ }
+ catch (Exception) { /* ignore */ }
+ return nResult;
+ }
+
+ ///
+ /// Use this to Run SQL with the ExecuteScalar() Command Object
+ ///
+ /// SQL Text/Commands to execute
+ /// the result of the ExecuteScalar() operation
+ internal static object RunSQLCommandTextExecuteScalar(string SqlCommandText)
+ {
+ object oResult = null;
+ try
+ {
+ using (SqlCeConnection conn = new SqlCeConnection(_connString))
+ {
+ conn.Open();
+ using (SqlCeCommand cmd = conn.CreateCommand())
+ {
+ cmd.CommandText = SqlCommandText;
+ oResult = cmd.ExecuteScalar();
+ }
+ }
+ }
+ catch (Exception) { /* ignore */ }
+
+ // Try Parsing the oResult, if an error occurs return null
+ try
+ {
+ if (String.IsNullOrEmpty(oResult.ToString()))
+ oResult = null;
+ }
+ catch (Exception) { oResult = null; }
+ return oResult;
+ }
+
+ ///
+ /// Use this to Run SQL with the ExecuteScalar() Command Object
+ ///
+ /// SQL Text/Commands to execute
+ /// Allows the use of sql parameters
+ /// the result of the ExecuteScalar() operation
+ internal static object RunSQLCommandTextExecuteScalar(string SqlCommandText, SqlCeParameter[] parameters)
+ {
+ object oResult = null;
+ try
+ {
+ using (SqlCeConnection conn = new SqlCeConnection(_connString))
+ {
+ conn.Open();
+ using (SqlCeCommand cmd = conn.CreateCommand())
+ {
+ cmd.CommandText = SqlCommandText;
+ foreach (SqlCeParameter parameter in parameters)
+ cmd.Parameters.Add(parameter);
+ oResult = cmd.ExecuteScalar();
+ }
+ }
+ }
+ catch (Exception) { /* ignore */ }
+
+ // Try Parsing the oResult, if an error occurs return null
+ try
+ {
+ if (String.IsNullOrEmpty(oResult.ToString()))
+ oResult = null;
+ }
+ catch (Exception) { oResult = null; }
+ return oResult;
+ }
+
+ ///
+ /// Use this to Run SQL with the DataAdapter Fill()
+ ///
+ /// SQL Text to execute
+ /// the result of the DataAdapter Fill() operation
+ internal static DataSet RunSQLTextFillDataSet(string SqlText)
+ {
+ DataSet dataset = new DataSet();
+ try
+ {
+ using (SqlCeConnection conn = new SqlCeConnection(_connString))
+ {
+ conn.Open();
+ using (SqlCeDataAdapter dataAdapter = new SqlCeDataAdapter(SqlText, conn))
+ {
+ dataAdapter.Fill(dataset);
+ }
+ }
+ }
+ catch (Exception) { /* ignore */ }
+ return dataset;
+ }
+
+ ///
+ /// Use this to Run SQL with the DataAdapter Fill()
+ ///
+ /// SQL Text to execute
+ /// Allows the use of sql parameters
+ /// the result of the DataAdapter Fill() operation
+ internal static DataSet RunSQLTextFillDataSet(string SqlText, SqlCeParameter[] parameters)
+ {
+ DataSet dataset = new DataSet();
+ try
+ {
+ using (SqlCeConnection conn = new SqlCeConnection(_connString))
+ {
+ conn.Open();
+ using (SqlCeCommand cmd = conn.CreateCommand())
+ {
+ cmd.CommandText = SqlText;
+ foreach (SqlCeParameter parameter in parameters)
+ cmd.Parameters.Add(parameter);
+
+ using (SqlCeDataAdapter dataAdapter = new SqlCeDataAdapter(cmd))
+ {
+ dataAdapter.Fill(dataset);
+ }
+ }
+ }
+ }
+ catch (Exception) { /* ignore */ }
+ return dataset;
+ }
+ }
+}
diff --git a/DataAccessLayer/Data.cs b/DataAccessLayer/Data.cs
new file mode 100644
index 0000000..86d1b84
--- /dev/null
+++ b/DataAccessLayer/Data.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Foo.DataAccessLayer
+{
+ public class Data
+ {
+ ///
+ /// Public Properties
+ ///
+ public static dArtifacts Artifacts { get { return _artifacts; } }
+ public static dWorkspace Workspace { get { return _workspace; } }
+ public static dState State { get { return _state; } }
+ public static dUserSettings UserSettings { get { return _UserSettings; } }
+
+ ///
+ /// Internal Properties
+ ///
+ internal static dVersioningTables VersioningTables { get { return _VersioningTables; } }
+
+ ///
+ /// Private Locations for above Properties
+ ///
+ private static dArtifacts _artifacts;
+ private static dWorkspace _workspace;
+ private static dState _state;
+ private static dVersioningTables _VersioningTables;
+ private static dUserSettings _UserSettings;
+
+ static Data()
+ {
+ // Upon First Instantiation of Data,
+ // ensure that the Default DB Exists
+ DB.CreateDefaultDB();
+
+ // Load All Public Data Types
+ _artifacts = new dArtifacts();
+ _workspace = new dWorkspace();
+ _state = new dState();
+ _UserSettings = new dUserSettings();
+
+ // Load All Internal Data Types
+ _VersioningTables = new dVersioningTables();
+ }
+ }
+}
diff --git a/DataAccessLayer/DataAccessLayer.csproj b/DataAccessLayer/DataAccessLayer.csproj
new file mode 100644
index 0000000..8c84f88
--- /dev/null
+++ b/DataAccessLayer/DataAccessLayer.csproj
@@ -0,0 +1,224 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}
+ Library
+ Properties
+ Foo.DataAccessLayer
+ DataAccessLayer
+ v3.5
+ 512
+ true
+ MyKeyFile.SNK
+
+
+ true
+ full
+ false
+ ..\Target\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\Target\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+ 3.5
+
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ True
+ Settings.settings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DataAccessLayer/DataTypes.cs b/DataAccessLayer/DataTypes.cs
new file mode 100644
index 0000000..3af222e
--- /dev/null
+++ b/DataAccessLayer/DataTypes.cs
@@ -0,0 +1,564 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using System.Data.SqlTypes;
+using System.Data;
+
+namespace Foo.DataAccessLayer.DataTypes
+{
+ // ArtifactTypes
+ public enum ArtifactTypes
+ {
+ File,
+ Url
+ }
+
+ // Artifacts
+ public enum SortOrderForArtifacts
+ {
+ None,
+ Ascending,
+ Descending,
+ LocationAscending,
+ LocationDescending,
+ LastAccessedAscending,
+ LastAccessedDescending,
+ MostFrequentlyAccessedAscending,
+ MostFrequentlyAccessedDescending
+ }
+
+ // Workspaces
+ public enum SortOrderForWorkspaces
+ {
+ None,
+ Ascending,
+ Descending,
+ LastAccessedAscending,
+ LastAccessedDescending,
+ MostFrequentlyAccessedAscending,
+ MostFrequentlyAccessedDescending
+ }
+
+ ///
+ /// This class holds the SortOrder Helper SQL functions for the SortOrder Enums listed above
+ ///
+ public class SortOrderSQLHelpers
+ {
+ ///
+ /// Use this to create the OrderBy Clause for the Workspace SortOrder Function
+ ///
+ /// sql string to add sortOrder to
+ /// the Workspace SortOrder Enum
+ /// modified SQL String
+ public static string SortOrderForArtifactsHelper(string sql, SortOrderForArtifacts sortOrder)
+ {
+ switch (sortOrder)
+ {
+ case SortOrderForArtifacts.None:
+ break;
+
+ case SortOrderForArtifacts.Ascending:
+ sql = sql + " ORDER BY [Artifacts].[Name] ASC";
+ break;
+
+ case SortOrderForArtifacts.Descending:
+ sql = sql + " ORDER BY [Artifacts].[Name] DESC";
+ break;
+
+ case SortOrderForArtifacts.LastAccessedAscending:
+ sql = sql + " ORDER BY [Artifacts].[LastAccessed] ASC";
+ break;
+
+ case SortOrderForArtifacts.LastAccessedDescending:
+ sql = sql + " ORDER BY [Artifacts].[LastAccessed] DESC";
+ break;
+
+ case SortOrderForArtifacts.LocationAscending:
+ sql = sql + " ORDER BY [Artifacts].[Location] ASC";
+ break;
+
+ case SortOrderForArtifacts.LocationDescending:
+ sql = sql + " ORDER BY [Artifacts].[Location] DESC";
+ break;
+
+ case SortOrderForArtifacts.MostFrequentlyAccessedAscending:
+ sql = sql + " ORDER BY [Artifacts].[AccessCounter] ASC";
+ break;
+
+ case SortOrderForArtifacts.MostFrequentlyAccessedDescending:
+ sql = sql + " ORDER BY [Artifacts].[AccessCounter] DESC";
+ break;
+ }
+ return sql;
+ }
+
+ ///
+ /// Use this to create the OrderBy Clause for the Workspace SortOrder Function
+ ///
+ /// sql string to add sortOrder to
+ /// the Workspace SortOrder Enum
+ /// modified SQL String
+ public static string SortOrderForWorkspacesHelper(string sql, SortOrderForWorkspaces sortOrder)
+ {
+ switch (sortOrder)
+ {
+ case SortOrderForWorkspaces.None:
+ break;
+
+ case SortOrderForWorkspaces.Ascending:
+ sql = sql + " ORDER BY [Workspaces].[Name] ASC";
+ break;
+
+ case SortOrderForWorkspaces.Descending:
+ sql = sql + " ORDER BY [Workspaces].[Name] DESC";
+ break;
+
+ case SortOrderForWorkspaces.LastAccessedAscending:
+ sql = sql + " ORDER BY [Workspaces].[LastAccessed] ASC";
+ break;
+
+ case SortOrderForWorkspaces.LastAccessedDescending:
+ sql = sql + " ORDER BY [Workspaces].[LastAccessed] DESC";
+ break;
+
+ case SortOrderForWorkspaces.MostFrequentlyAccessedAscending:
+ sql = sql + " ORDER BY [Workspaces].[AccessCounter] ASC";
+ break;
+
+ case SortOrderForWorkspaces.MostFrequentlyAccessedDescending:
+ sql = sql + " ORDER BY [Workspaces].[AccessCounter] DESC";
+ break;
+ }
+ return sql;
+ }
+ }
+
+ ///
+ /// Validation Classes
+ ///
+ public class DataTypeValidation
+ {
+ ///
+ /// Checks the logistics of the WorkspaceName (not the DB)
+ ///
+ /// true if valid logistically, false otherwise
+ public static bool IsValidWorkspaceName(string WorkspaceName)
+ {
+ if ((String.IsNullOrEmpty(WorkspaceName)) ||
+ (WorkspaceName.Length < 1) ||
+ (WorkspaceName.Length > 75))
+ return false;
+ else
+ return true;
+ }
+
+ ///
+ /// Use this to check the return of an ArtifactItemGroup
+ ///
+ /// ArtifactGroup
+ /// true if ArtifactItemGroup is Empty, false otherwise
+ public static bool IsEmptyArtifactItemGroup(ArtifactItem[] artifactItems)
+ {
+ if ((artifactItems.Length == 1) && !artifactItems[0].IsLocationValid)
+ return true;
+ else
+ return false;
+ }
+
+ ///
+ /// Use this to check the return of an WorkspaceItemGroup
+ ///
+ /// WorkspaceItemGroup
+ /// true if WorkspaceItemGroup is Empty, false otherwise
+ public static bool IsEmptyWorkspaceItemGroup(WorkspaceItem[] workspaceItems)
+ {
+ if ((workspaceItems.Length == 1) && !workspaceItems[0].IsValid)
+ return true;
+ else
+ return false;
+ }
+
+ ///
+ /// Uset this for quick and easy DataSet Validation
+ ///
+ /// a dataset object
+ /// true if dataset is empty, false otherwise
+ public static bool IsEmptyDataSet(DataSet dataset)
+ {
+ if ((dataset == null) ||
+ (dataset.Tables.Count == 0) ||
+ ((dataset.Tables.Count == 1) && (dataset.Tables[0].Rows.Count <= 0)))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// For internal use only - Check if the TableName entered is Valid
+ ///
+ /// a table name
+ /// true if valid logistically, false otherwise
+ internal static bool IsValidTableName(string TableName)
+ {
+ if ((String.IsNullOrEmpty(TableName)) ||
+ (TableName.Length < 1) ||
+ (TableName.Length > 75))
+ return false;
+ else
+ return true;
+ }
+
+ ///
+ /// For internal use only - Check to see if Version information is valid
+ ///
+ /// Version Information for a table
+ /// true if valid logistically, false otherwise
+ internal static bool IsValidVersionInformation(string VersionInformation)
+ {
+ bool bIsValid = (!String.IsNullOrEmpty(VersionInformation) && (VersionInformation.Length == 8));
+ if (bIsValid)
+ {
+ string[] versionEntities = VersionInformation.Split('.');
+ bIsValid = (versionEntities.Length == 3);
+ }
+ return (bIsValid);
+ }
+ }
+
+ ///
+ /// Helper Classes
+ ///
+ public class DataTypeHelpers
+ {
+ ///
+ /// Many Artifact Checking Functions (Except for Insert/modify) Only need the location,
+ /// So if you have a location, use this function to create a quick Artifact to use in those
+ /// checking functions
+ ///
+ ///
+ ///
+ public static ArtifactItem CreateLocationOnlyArtifact(string location)
+ {
+ ArtifactItem artifactItem = new ArtifactItem()
+ {
+ Location = location
+ };
+ return artifactItem;
+ }
+
+ ///
+ /// Use this to create an empty ArtifactItemGroup (should only be used internally)
+ ///
+ /// An Empty ArtifactItemGroups
+ internal static ArtifactItem[] EmptyArtifactItemGroup()
+ {
+ ArtifactItem[] artifactItems = new ArtifactItem[] { new ArtifactItem() { Location = "" } };
+ return artifactItems;
+ }
+
+ ///
+ /// Use this to create an empty WorkspaceItemGroup (should only be used internally)
+ ///
+ /// An Empty WorkspaceItemGroups
+ internal static WorkspaceItem[] EmptyWorkspaceItemGroup()
+ {
+ WorkspaceItem[] workspaceItems = new WorkspaceItem[] { new WorkspaceItem() { Name = "" } };
+ return workspaceItems;
+ }
+
+ }
+
+ ///
+ /// Use this class for some of our Workspace Methods. Holds Workspace Information as well
+ /// as performs Validation.
+ ///
+ public class WorkspaceItem
+ {
+ public string Name { get; set; }
+ public DateTime LastAccessed { get; private set; }
+ public int AccessCounter { get; set; }
+
+ // Needed to make sure that dateTime is within limits of SQL,
+ // Otherwise SQL stmt may generate an error
+ public bool SetLastAccessed(DateTime dateTime)
+ {
+ if (dateTime >= SqlDateTime.MinValue.Value &&
+ dateTime <= SqlDateTime.MaxValue.Value)
+ {
+ LastAccessed = dateTime;
+ return true;
+ }
+ return false;
+ }
+
+ // *Custom Tag Property * To be used by Callers to tag the object
+ public string Tag { get; set; }
+
+ // default
+ public WorkspaceItem()
+ {
+ Name = "";
+ LastAccessed = SqlDateTime.MinValue.Value;
+ AccessCounter = 0;
+
+ // Tag
+ Tag = "";
+ }
+
+ ///
+ /// Performs basic Type Validity Tests
+ ///
+ public bool IsValid
+ {
+ get
+ {
+ if ((Name.Length > 1) &&
+ (Name.Length <= 75) &&
+ (AccessCounter >= 0) &&
+ (LastAccessed != SqlDateTime.MinValue.Value)
+ )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ #region ICloneable Members
+ public object Clone()
+ {
+ return this.MemberwiseClone();
+ }
+ #endregion
+ }
+
+ ///
+ /// Use this Class for all our Artifact Methods. Holds Artifact Information as well
+ /// as performs Validation. Use IsValidFileIntegrity() for IO validation
+ ///
+ public class ArtifactItem : ICloneable
+ {
+ public String Name { get; set; }
+ public ArtifactTypes Type { get; set; }
+ public String Location { get; set; }
+ public String Note { get; set; }
+ public String SnapshotFile { get; set; }
+ public DateTime LastAccessed { get; private set; }
+ public int AccessCounter { get; set; }
+
+ // Needed to make sure that dateTime is within limits of SQL,
+ // Otherwise SQL stmt may generate an error
+ public bool SetLastAccessed(DateTime dateTime)
+ {
+ if (dateTime >= SqlDateTime.MinValue.Value &&
+ dateTime <= SqlDateTime.MaxValue.Value)
+ {
+ LastAccessed = dateTime;
+ return true;
+ }
+ return false;
+ }
+
+ // default
+ public ArtifactItem()
+ {
+ SetAsFileType();
+ Name = "";
+ Location = "";
+ Note = "";
+ SnapshotFile = "";
+
+ // LinkProperties
+ WindowTop = 0;
+ WindowLeft = 0;
+ WindowHeight = 0;
+ WindowWidth = 0;
+
+ // Access properties
+ LastAccessed = SqlDateTime.MinValue.Value;
+ AccessCounter = 0;
+
+ // Tag
+ Tag = "";
+ }
+
+ // Type Check
+ public bool IsUrl { get { return Type == ArtifactTypes.Url; } }
+ public bool IsFile { get { return Type == ArtifactTypes.File; } }
+
+ // Type Helpers
+ public string FileName
+ {
+ get
+ {
+ if (IsFile)
+ {
+ int nIndex = Location.LastIndexOf('\\');
+ if (nIndex > 0 && nIndex < Location.Length)
+ return Location.Substring((nIndex + 1));
+ }
+ return String.Empty;
+ }
+ }
+ public string FileLocation
+ {
+ get
+ {
+ if (IsFile)
+ {
+ int nIndex = Location.LastIndexOf('\\');
+ if (nIndex > 0 && nIndex < Location.Length)
+ return Location.Substring(0,nIndex);
+ }
+ return String.Empty;
+ }
+ }
+
+ // Type Setting
+ public void SetAsFileType() { Type = ArtifactTypes.File; }
+ public void SetAsUrlType() { Type = ArtifactTypes.Url; }
+ public bool SetType(string strType)
+ {
+ if (strType.ToUpper() == "FILE")
+ {
+ SetAsFileType();
+ return true;
+ }
+ else if (strType.ToUpper() == "URL")
+ {
+ SetAsUrlType();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Setters
+ public bool SetFile(string fileNameAndLocation)
+ {
+ if ((fileNameAndLocation.Length > 1) && File.Exists(fileNameAndLocation))
+ {
+ SetAsFileType();
+ Location = fileNameAndLocation;
+ return true;
+ }
+ return false;
+ }
+ public bool SetUrl(string Url)
+ {
+ if ((Url.Length > 1)) // To Do - Better Url Checking
+ {
+ SetAsUrlType();
+ Location = Url;
+ return true;
+ }
+ return false;
+ }
+
+ // *Custom Tag Property * To be used by Callers to tag the object
+ public string Tag { get; set; }
+
+ ///
+ /// This Information is used by the link in the Workspace.
+ /// ~This information is only filed in the artifact when being retrieved
+ /// from a workspace which has link information
+ ///
+ public int WindowTop { get; set; }
+ public int WindowLeft { get; set; }
+ public int WindowHeight { get; set; }
+ public int WindowWidth { get; set; }
+
+ ///
+ /// Use this function to do proper validation of the Link Properties
+ ///
+ public bool AreWorkspaceLinkPropertiesValid
+ {
+ get
+ {
+ if ((WindowHeight > 0) &&
+ (WindowWidth > 0))
+ return true;
+ else
+ return false;
+ }
+ }
+
+ ///
+ /// Performs basic Type Validity Tests
+ ///
+ public bool IsValid
+ {
+ get
+ {
+ if((Name.Length > 1) &&
+ (Name.Length <= 150) &&
+ (Location.Length > 1) &&
+ (Location.Length <= 300) &&
+ (Note.Length <= 3000) &&
+ (SnapshotFile.Length > 1) &&
+ (SnapshotFile.Length <= 300) &&
+ (AccessCounter >= 0) //&&
+ //(LastAccessed != SqlDateTime.MinValue.Value)
+ )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ ///
+ /// Since Artifact Location is our main source of determining
+ /// existence (this provides an easy check only for valid location)
+ ///
+ public bool IsLocationValid
+ {
+ get
+ {
+ if ((Location.Length > 1) &&
+ (Location.Length <= 300))
+ return true;
+ else
+ return false;
+ }
+ }
+
+ ///
+ /// Performs Advanced File Validity Tests
+ ///
+ public bool IsValidFileIntegrity
+ {
+ get
+ {
+ if (IsFile && !File.Exists(Location))
+ return false;
+
+ // To Do * Check if is Valid Url *
+
+ if (!File.Exists(SnapshotFile))
+ return false;
+
+ return true;
+ }
+ }
+
+ #region ICloneable Members
+ public object Clone()
+ {
+ return this.MemberwiseClone();
+ }
+ #endregion
+ }
+
+}
diff --git a/DataAccessLayer/MyKeyFile.SNK b/DataAccessLayer/MyKeyFile.SNK
new file mode 100644
index 0000000..8bc8162
Binary files /dev/null and b/DataAccessLayer/MyKeyFile.SNK differ
diff --git a/DataAccessLayer/Properties/AssemblyInfo.cs b/DataAccessLayer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d1bc0a6
--- /dev/null
+++ b/DataAccessLayer/Properties/AssemblyInfo.cs
@@ -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("DataAccessLayer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("DataAccessLayer")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
+[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("4eac069e-728a-48b2-989e-0be548d211ef")]
+
+// 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")]
diff --git a/DataAccessLayer/Properties/Resources.Designer.cs b/DataAccessLayer/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..7458a06
--- /dev/null
+++ b/DataAccessLayer/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.DataAccessLayer.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Foo.DataAccessLayer.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/DataAccessLayer/Properties/Resources.resx b/DataAccessLayer/Properties/Resources.resx
new file mode 100644
index 0000000..5ea0895
--- /dev/null
+++ b/DataAccessLayer/Properties/Resources.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/DataAccessLayer/Properties/Settings.Designer.cs b/DataAccessLayer/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..d7fe635
--- /dev/null
+++ b/DataAccessLayer/Properties/Settings.Designer.cs
@@ -0,0 +1,37 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.DataAccessLayer.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.ConnectionString)]
+ [global::System.Configuration.DefaultSettingValueAttribute("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\\TestData\\Files\\DupF" +
+ "iles2\\DatabaseBills.accdb;Persist Security Info=True")]
+ public string DatabaseBillsConnectionString {
+ get {
+ return ((string)(this["DatabaseBillsConnectionString"]));
+ }
+ }
+ }
+}
diff --git a/DataAccessLayer/Properties/Settings.settings b/DataAccessLayer/Properties/Settings.settings
new file mode 100644
index 0000000..cf1ae0b
--- /dev/null
+++ b/DataAccessLayer/Properties/Settings.settings
@@ -0,0 +1,14 @@
+
+
+
+
+
+ <?xml version="1.0" encoding="utf-16"?>
+<SerializableConnectionString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <ConnectionString>Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\TestData\Files\DupFiles2\DatabaseBills.accdb;Persist Security Info=True</ConnectionString>
+ <ProviderName>System.Data.OleDb</ProviderName>
+</SerializableConnectionString>
+ Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\TestData\Files\DupFiles2\DatabaseBills.accdb;Persist Security Info=True
+
+
+
\ No newline at end of file
diff --git a/DataAccessLayer/ResourceHelper.cs b/DataAccessLayer/ResourceHelper.cs
new file mode 100644
index 0000000..ac9adf3
--- /dev/null
+++ b/DataAccessLayer/ResourceHelper.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Reflection;
+using System.IO;
+using System.Collections.Specialized;
+
+namespace Foo.DataAccessLayer
+{
+ class ResourceHelper
+ {
+ // Used by DB to keep track of labels and Versioning
+ public static StringDictionary s_VersioningTablesMap = new StringDictionary();
+
+ ///
+ /// Get All Sql Table Resource Names
+ ///
+ ///
+ public static string[] GetTableResourceNames()
+ {
+ List tableResources = new List();
+
+ string[] resourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
+ foreach (string ResourceName in resourceNames)
+ {
+ if(ResourceName.Contains("DataAccessLayer.Sql.Tables."))
+ tableResources.Add(ResourceName);
+ }
+
+ return tableResources.ToArray();
+ }
+
+ ///
+ /// Gives you just the Table Name without the Resource string before and after
+ ///
+ /// a table Resource name
+ /// the table name
+ public static string GetTableNameFromTableResourceName(string TableResouceName)
+ {
+ // First trim the sqlce
+ TableResouceName = TableResouceName.Replace(".sqlce", "");
+
+ // Now find the last dot and trim from there
+ int index = TableResouceName.LastIndexOf('.');
+ return TableResouceName.Substring(index + 1);
+ }
+
+ ///
+ /// Get the Text/SQL String from a specified ResourceFileName
+ ///
+ /// a specific ResourceFileName
+ ///
+ public static string GetTextSqlFromResourceFile(string resourceFileName)
+ {
+ StreamReader stream = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceFileName));
+ if (stream != null)
+ {
+ string strText = stream.ReadToEnd();
+ strText = strText.Replace('\r', ' ');
+ strText = strText.Replace('\n', ' ');
+ return strText;
+ }
+ else
+ return string.Empty;
+ }
+ }
+}
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Albin likes apples.doc b/DataAccessLayer/TestData/Files/DupFiles1/Albin likes apples.doc
new file mode 100644
index 0000000..07ad7bc
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Albin likes apples.doc differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Book1.xls b/DataAccessLayer/TestData/Files/DupFiles1/Book1.xls
new file mode 100644
index 0000000..c851022
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Book1.xls differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Book1.xlsx b/DataAccessLayer/TestData/Files/DupFiles1/Book1.xlsx
new file mode 100644
index 0000000..150de4a
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Book1.xlsx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Book2.xls b/DataAccessLayer/TestData/Files/DupFiles1/Book2.xls
new file mode 100644
index 0000000..1d776a4
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Book2.xls differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Book2.xlsx b/DataAccessLayer/TestData/Files/DupFiles1/Book2.xlsx
new file mode 100644
index 0000000..715c15d
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Book2.xlsx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Book3.xls b/DataAccessLayer/TestData/Files/DupFiles1/Book3.xls
new file mode 100644
index 0000000..82831c1
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Book3.xls differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Book4.xls b/DataAccessLayer/TestData/Files/DupFiles1/Book4.xls
new file mode 100644
index 0000000..cfb1128
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Book4.xls differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/DatabaseBills.accdb b/DataAccessLayer/TestData/Files/DupFiles1/DatabaseBills.accdb
new file mode 100644
index 0000000..90679ba
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/DatabaseBills.accdb differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/DatabaseReceits.accdb b/DataAccessLayer/TestData/Files/DupFiles1/DatabaseReceits.accdb
new file mode 100644
index 0000000..c0e3c70
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/DatabaseReceits.accdb differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Doc1.rtf b/DataAccessLayer/TestData/Files/DupFiles1/Doc1.rtf
new file mode 100644
index 0000000..ca783c7
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles1/Doc1.rtf
@@ -0,0 +1,154 @@
+{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;}
+{\f34\fbidi \froman\fcharset1\fprq2{\*\panose 02040503050406030204}Cambria Math;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;}
+{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}
+{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f39\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f40\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\f42\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f43\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f44\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f45\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\f46\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f47\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f49\fbidi \fswiss\fcharset238\fprq2 Arial CE;}{\f50\fbidi \fswiss\fcharset204\fprq2 Arial Cyr;}
+{\f52\fbidi \fswiss\fcharset161\fprq2 Arial Greek;}{\f53\fbidi \fswiss\fcharset162\fprq2 Arial Tur;}{\f54\fbidi \fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f55\fbidi \fswiss\fcharset178\fprq2 Arial (Arabic);}
+{\f56\fbidi \fswiss\fcharset186\fprq2 Arial Baltic;}{\f57\fbidi \fswiss\fcharset163\fprq2 Arial (Vietnamese);}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhimajor\f31528\fbidi \froman\fcharset238\fprq2 Cambria CE;}
+{\fhimajor\f31529\fbidi \froman\fcharset204\fprq2 Cambria Cyr;}{\fhimajor\f31531\fbidi \froman\fcharset161\fprq2 Cambria Greek;}{\fhimajor\f31532\fbidi \froman\fcharset162\fprq2 Cambria Tur;}
+{\fhimajor\f31535\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}
+{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}
+{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;
+\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;
+\red192\green192\blue192;}{\*\defchp \fs22\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
+\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033
+\snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
+\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa200\sl276\slmult1
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033
+\snext11 \ssemihidden \sunhideused \sqformat Normal Table;}}{\*\rsidtbl \rsid5513996}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\operator HPinvent}
+{\creatim\yr2010\mo1\dy18\hr14\min23}{\revtim\yr2010\mo1\dy18\hr14\min23}{\version2}{\edmins0}{\nofpages1}{\nofwords1}{\nofchars8}{\nofcharsws8}{\vern32771}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}
+\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect
+\widowctrl\ftnbj\aenddoc\trackmoves1\trackformatting1\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120\dghorigin1701
+\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale100\rsidroot5513996 \fet0{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2
+\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6
+\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang
+{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033 {
+\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\insrsid5513996 \hich\af1\dbch\af31505\loch\f1 Doc1.Rtf}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\insrsid5513996
+\par }{\*\themedata 504b030414000600080000002100828abc13fa0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb6ac3301045f785fe83d0b6d8
+72ba28a5d8cea249777d2cd20f18e4b12d6a8f843409c9df77ecb850ba082d74231062ce997b55ae8fe3a00e1893f354e9555e6885647de3a8abf4fbee29bbd7
+2a3150038327acf409935ed7d757e5ee14302999a654e99e393c18936c8f23a4dc072479697d1c81e51a3b13c07e4087e6b628ee8cf5c4489cf1c4d075f92a0b
+44d7a07a83c82f308ac7b0a0f0fbf90c2480980b58abc733615aa2d210c2e02cb04430076a7ee833dfb6ce62e3ed7e14693e8317d8cd0433bf5c60f53fea2fe7
+065bd80facb647e9e25c7fc421fd2ddb526b2e9373fed4bb902e182e97b7b461e6bfad3f010000ffff0300504b030414000600080000002100a5d6a7e7c00000
+00360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4fc7060abb08
+84a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b63095120f88d94fbc
+52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462a1a82fe353
+bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f7468656d652f7468
+656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b4b0d592c9c
+070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b4757e8d3f7
+29e245eb2b260a0238fd010000ffff0300504b03041400060008000000210096b5ade296060000501b0000160000007468656d652f7468656d652f7468656d65
+312e786d6cec594f6fdb3614bf0fd87720746f6327761a07758ad8b19b2d4d1bc46e871e698996d850a240d2497d1bdae38001c3ba618715d86d87615b8116d8
+a5fb34d93a6c1dd0afb0475292c5585e9236d88aad3e2412f9e3fbff1e1fa9abd7eec70c1d1221294fda5efd72cd4324f1794093b0eddd1ef62fad79482a9c04
+98f184b4bd2991deb58df7dfbb8ad755446282607d22d771db8b944ad79796a40fc3585ee62949606ecc458c15bc8a702910f808e8c66c69b9565b5d8a314d3c
+94e018c8de1a8fa94fd05093f43672e23d06af89927ac06762a049136785c10607758d9053d965021d62d6f6804fc08f86e4bef210c352c144dbab999fb7b471
+7509af678b985ab0b6b4ae6f7ed9ba6c4170b06c788a705430adf71bad2b5b057d03606a1ed7ebf5babd7a41cf00b0ef83a6569632cd467faddec9699640f671
+9e76b7d6ac355c7c89feca9cccad4ea7d36c65b258a206641f1b73f8b5da6a6373d9c11b90c537e7f08dce66b7bbeae00dc8e257e7f0fd2badd5868b37a088d1
+e4600ead1ddaef67d40bc898b3ed4af81ac0d76a197c86826828a24bb318f3442d8ab518dfe3a20f000d6458d104a9694ac6d88728eee2782428d60cf03ac1a5
+193be4cbb921cd0b495fd054b5bd0f530c1931a3f7eaf9f7af9e3f45c70f9e1d3ff8e9f8e1c3e3073f5a42ceaa6d9c84e5552fbffdeccfc71fa33f9e7ef3f2d1
+17d57859c6fffac327bffcfc793510d26726ce8b2f9ffcf6ecc98baf3efdfdbb4715f04d814765f890c644a29be408edf3181433567125272371be15c308d3f2
+8acd249438c19a4b05fd9e8a1cf4cd296699771c393ac4b5e01d01e5a30a787d72cf1178108989a2159c77a2d801ee72ce3a5c545a6147f32a99793849c26ae6
+6252c6ed637c58c5bb8b13c7bfbd490a75330f4b47f16e441c31f7184e140e494214d273fc80900aedee52ead87597fa824b3e56e82e451d4c2b4d32a423279a
+668bb6690c7e9956e90cfe766cb37b077538abd27a8b1cba48c80acc2a841f12e698f13a9e281c57911ce298950d7e03aba84ac8c154f8655c4f2af074481847
+bd804859b5e696007d4b4edfc150b12addbecba6b18b148a1e54d1bc81392f23b7f84137c2715a851dd0242a633f900710a218ed715505dfe56e86e877f0034e
+16bafb0e258ebb4faf06b769e888340b103d3311da9750aa9d0a1cd3e4efca31a3508f6d0c5c5c398602f8e2ebc71591f5b616e24dd893aa3261fb44f95d843b
+5974bb5c04f4edafb95b7892ec1108f3f98de75dc97d5772bdff7cc95d94cf672db4b3da0a6557f70db629362d72bcb0431e53c6066acac80d699a6409fb44d0
+8741bdce9c0e4971624a2378cceaba830b05366b90e0ea23aaa241845368b0eb9e2612ca8c742851ca251ceccc70256d8d87265dd96361531f186c3d9058edf2
+c00eafe8e1fc5c509031bb4d680e9f39a3154de0accc56ae644441edd76156d7429d995bdd88664a9dc3ad50197c38af1a0c16d684060441db02565e85f3b966
+0d0713cc48a0ed6ef7dedc2dc60b17e92219e180643ed27acffba86e9c94c78ab90980d8a9f0913ee49d62b512b79626fb06dccee2a432bbc60276b9f7dec44b
+7904cfbca4f3f6443ab2a49c9c2c41476dafd55c6e7ac8c769db1bc399161ee314bc2e75cf8759081743be1236ec4f4d6693e5336fb672c5dc24a8c33585b5fb
+9cc24e1d4885545b58463634cc5416022cd19cacfccb4d30eb45296023fd35a458598360f8d7a4003bbaae25e331f155d9d9a5116d3bfb9a95523e51440ca2e0
+088dd844ec6370bf0e55d027a012ae264c45d02f708fa6ad6da6dce29c255df9f6cae0ec38666984b372ab5334cf640b37795cc860de4ae2816e95b21be5ceaf
+8a49f90b52a51cc6ff3355f47e0237052b81f6800fd7b802239daf6d8f0b1571a8426944fdbe80c6c1d40e8816b88b8569082ab84c36ff0539d4ff6dce591a26
+ade1c0a7f669880485fd484582903d284b26fa4e2156cff62e4b9265844c4495c495a9157b440e091bea1ab8aaf7760f4510eaa69a6465c0e04ec69ffb9e65d0
+28d44d4e39df9c1a52ecbd3607fee9cec7263328e5d661d3d0e4f62f44acd855ed7ab33cdf7bcb8ae889599bd5c8b3029895b6825696f6af29c239b75a5bb1e6
+345e6ee6c28117e73586c1a2214ae1be07e93fb0ff51e133fb65426fa843be0fb515c187064d0cc206a2fa926d3c902e907670048d931db4c1a44959d366ad93
+b65abe595f70a75bf03d616c2dd959fc7d4e6317cd99cbcec9c58b34766661c7d6766ca1a9c1b327531486c6f941c638c67cd22a7f75e2a37be0e82db8df9f30
+254d30c1372581a1f51c983c80e4b71ccdd28dbf000000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f74
+68656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f24
+51eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198
+720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528
+a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100828abc13fa0000001c0200001300000000000000000000000000
+000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b000000000000000000000000
+002b0100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000140200007468
+656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d001400060008000000210096b5ade296060000501b000016000000000000000000
+00000000d10200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b010000270000000000
+00000000000000009b0900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000960a00000000}
+{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d
+617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
+6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
+656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
+{\*\latentstyles\lsdstimax267\lsdlockeddef0\lsdsemihiddendef1\lsdunhideuseddef1\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
+\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;
+\lsdpriority39 \lsdlocked0 toc 1;\lsdpriority39 \lsdlocked0 toc 2;\lsdpriority39 \lsdlocked0 toc 3;\lsdpriority39 \lsdlocked0 toc 4;\lsdpriority39 \lsdlocked0 toc 5;\lsdpriority39 \lsdlocked0 toc 6;\lsdpriority39 \lsdlocked0 toc 7;
+\lsdpriority39 \lsdlocked0 toc 8;\lsdpriority39 \lsdlocked0 toc 9;\lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdpriority1 \lsdlocked0 Default Paragraph Font;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority59 \lsdlocked0 Table Grid;\lsdunhideused0 \lsdlocked0 Placeholder Text;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdunhideused0 \lsdlocked0 Revision;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdpriority37 \lsdlocked0 Bibliography;\lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;}}{\*\datastore 010500000200000018000000
+4d73786d6c322e534158584d4c5265616465722e352e3000000000000000000000060000
+d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffffec69d9888b8b3d4c859eaf6cd158be0f0000000000000000000000002068
+d7b37398ca01feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000105000000000000}}
\ No newline at end of file
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Doc2.rtf b/DataAccessLayer/TestData/Files/DupFiles1/Doc2.rtf
new file mode 100644
index 0000000..f6b7f34
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles1/Doc2.rtf
@@ -0,0 +1,154 @@
+{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f34\fbidi \froman\fcharset1\fprq2{\*\panose 02040503050406030204}Cambria Math;}
+{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;}
+{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}
+{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f39\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f40\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\f42\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f43\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f44\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f45\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\f46\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f47\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f409\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f410\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}
+{\f412\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f413\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f416\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\fhimajor\f31528\fbidi \froman\fcharset238\fprq2 Cambria CE;}{\fhimajor\f31529\fbidi \froman\fcharset204\fprq2 Cambria Cyr;}{\fhimajor\f31531\fbidi \froman\fcharset161\fprq2 Cambria Greek;}{\fhimajor\f31532\fbidi \froman\fcharset162\fprq2 Cambria Tur;}
+{\fhimajor\f31535\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}
+{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}
+{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;
+\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;
+\red192\green192\blue192;}{\*\defchp \fs22\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
+\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033
+\snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
+\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa200\sl276\slmult1
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033
+\snext11 \ssemihidden \sunhideused \sqformat Normal Table;}}{\*\rsidtbl \rsid15009392}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\operator HPinvent}
+{\creatim\yr2010\mo1\dy18\hr14\min23}{\revtim\yr2010\mo1\dy18\hr14\min23}{\version2}{\edmins0}{\nofpages1}{\nofwords1}{\nofchars8}{\nofcharsws8}{\vern32771}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}
+\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect
+\widowctrl\ftnbj\aenddoc\trackmoves1\trackformatting1\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120\dghorigin1701
+\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale100\rsidroot15009392 \fet0{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2
+\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6
+\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang
+{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid15009392 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0
+\fs22\lang1033\langfe1033\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af31507\afs20 \ltrch\fcs0 \insrsid15009392 \hich\af31506\dbch\af31505\loch\f31506 Doc2.rtf}{\rtlch\fcs1 \af31507\afs20 \ltrch\fcs0
+\insrsid15009392\charrsid15009392
+\par }{\*\themedata 504b030414000600080000002100828abc13fa0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb6ac3301045f785fe83d0b6d8
+72ba28a5d8cea249777d2cd20f18e4b12d6a8f843409c9df77ecb850ba082d74231062ce997b55ae8fe3a00e1893f354e9555e6885647de3a8abf4fbee29bbd7
+2a3150038327acf409935ed7d757e5ee14302999a654e99e393c18936c8f23a4dc072479697d1c81e51a3b13c07e4087e6b628ee8cf5c4489cf1c4d075f92a0b
+44d7a07a83c82f308ac7b0a0f0fbf90c2480980b58abc733615aa2d210c2e02cb04430076a7ee833dfb6ce62e3ed7e14693e8317d8cd0433bf5c60f53fea2fe7
+065bd80facb647e9e25c7fc421fd2ddb526b2e9373fed4bb902e182e97b7b461e6bfad3f010000ffff0300504b030414000600080000002100a5d6a7e7c00000
+00360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4fc7060abb08
+84a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b63095120f88d94fbc
+52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462a1a82fe353
+bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f7468656d652f7468
+656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b4b0d592c9c
+070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b4757e8d3f7
+29e245eb2b260a0238fd010000ffff0300504b03041400060008000000210096b5ade296060000501b0000160000007468656d652f7468656d652f7468656d65
+312e786d6cec594f6fdb3614bf0fd87720746f6327761a07758ad8b19b2d4d1bc46e871e698996d850a240d2497d1bdae38001c3ba618715d86d87615b8116d8
+a5fb34d93a6c1dd0afb0475292c5585e9236d88aad3e2412f9e3fbff1e1fa9abd7eec70c1d1221294fda5efd72cd4324f1794093b0eddd1ef62fad79482a9c04
+98f184b4bd2991deb58df7dfbb8ad755446282607d22d771db8b944ad79796a40fc3585ee62949606ecc458c15bc8a702910f808e8c66c69b9565b5d8a314d3c
+94e018c8de1a8fa94fd05093f43672e23d06af89927ac06762a049136785c10607758d9053d965021d62d6f6804fc08f86e4bef210c352c144dbab999fb7b471
+7509af678b985ab0b6b4ae6f7ed9ba6c4170b06c788a705430adf71bad2b5b057d03606a1ed7ebf5babd7a41cf00b0ef83a6569632cd467faddec9699640f671
+9e76b7d6ac355c7c89feca9cccad4ea7d36c65b258a206641f1b73f8b5da6a6373d9c11b90c537e7f08dce66b7bbeae00dc8e257e7f0fd2badd5868b37a088d1
+e4600ead1ddaef67d40bc898b3ed4af81ac0d76a197c86826828a24bb318f3442d8ab518dfe3a20f000d6458d104a9694ac6d88728eee2782428d60cf03ac1a5
+193be4cbb921cd0b495fd054b5bd0f530c1931a3f7eaf9f7af9e3f45c70f9e1d3ff8e9f8e1c3e3073f5a42ceaa6d9c84e5552fbffdeccfc71fa33f9e7ef3f2d1
+17d57859c6fffac327bffcfc793510d26726ce8b2f9ffcf6ecc98baf3efdfdbb4715f04d814765f890c644a29be408edf3181433567125272371be15c308d3f2
+8acd249438c19a4b05fd9e8a1cf4cd296699771c393ac4b5e01d01e5a30a787d72cf1178108989a2159c77a2d801ee72ce3a5c545a6147f32a99793849c26ae6
+6252c6ed637c58c5bb8b13c7bfbd490a75330f4b47f16e441c31f7184e140e494214d273fc80900aedee52ead87597fa824b3e56e82e451d4c2b4d32a423279a
+668bb6690c7e9956e90cfe766cb37b077538abd27a8b1cba48c80acc2a841f12e698f13a9e281c57911ce298950d7e03aba84ac8c154f8655c4f2af074481847
+bd804859b5e696007d4b4edfc150b12addbecba6b18b148a1e54d1bc81392f23b7f84137c2715a851dd0242a633f900710a218ed715505dfe56e86e877f0034e
+16bafb0e258ebb4faf06b769e888340b103d3311da9750aa9d0a1cd3e4efca31a3508f6d0c5c5c398602f8e2ebc71591f5b616e24dd893aa3261fb44f95d843b
+5974bb5c04f4edafb95b7892ec1108f3f98de75dc97d5772bdff7cc95d94cf672db4b3da0a6557f70db629362d72bcb0431e53c6066acac80d699a6409fb44d0
+8741bdce9c0e4971624a2378cceaba830b05366b90e0ea23aaa241845368b0eb9e2612ca8c742851ca251ceccc70256d8d87265dd96361531f186c3d9058edf2
+c00eafe8e1fc5c509031bb4d680e9f39a3154de0accc56ae644441edd76156d7429d995bdd88664a9dc3ad50197c38af1a0c16d684060441db02565e85f3b966
+0d0713cc48a0ed6ef7dedc2dc60b17e92219e180643ed27acffba86e9c94c78ab90980d8a9f0913ee49d62b512b79626fb06dccee2a432bbc60276b9f7dec44b
+7904cfbca4f3f6443ab2a49c9c2c41476dafd55c6e7ac8c769db1bc399161ee314bc2e75cf8759081743be1236ec4f4d6693e5336fb672c5dc24a8c33585b5fb
+9cc24e1d4885545b58463634cc5416022cd19cacfccb4d30eb45296023fd35a458598360f8d7a4003bbaae25e331f155d9d9a5116d3bfb9a95523e51440ca2e0
+088dd844ec6370bf0e55d027a012ae264c45d02f708fa6ad6da6dce29c255df9f6cae0ec38666984b372ab5334cf640b37795cc860de4ae2816e95b21be5ceaf
+8a49f90b52a51cc6ff3355f47e0237052b81f6800fd7b802239daf6d8f0b1571a8426944fdbe80c6c1d40e8816b88b8569082ab84c36ff0539d4ff6dce591a26
+ade1c0a7f669880485fd484582903d284b26fa4e2156cff62e4b9265844c4495c495a9157b440e091bea1ab8aaf7760f4510eaa69a6465c0e04ec69ffb9e65d0
+28d44d4e39df9c1a52ecbd3607fee9cec7263328e5d661d3d0e4f62f44acd855ed7ab33cdf7bcb8ae889599bd5c8b3029895b6825696f6af29c239b75a5bb1e6
+345e6ee6c28117e73586c1a2214ae1be07e93fb0ff51e133fb65426fa843be0fb515c187064d0cc206a2fa926d3c902e907670048d931db4c1a44959d366ad93
+b65abe595f70a75bf03d616c2dd959fc7d4e6317cd99cbcec9c58b34766661c7d6766ca1a9c1b327531486c6f941c638c67cd22a7f75e2a37be0e82db8df9f30
+254d30c1372581a1f51c983c80e4b71ccdd28dbf000000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f74
+68656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f24
+51eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198
+720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528
+a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100828abc13fa0000001c0200001300000000000000000000000000
+000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b000000000000000000000000
+002b0100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000140200007468
+656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d001400060008000000210096b5ade296060000501b000016000000000000000000
+00000000d10200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b010000270000000000
+00000000000000009b0900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000960a00000000}
+{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d
+617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
+6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
+656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
+{\*\latentstyles\lsdstimax267\lsdlockeddef0\lsdsemihiddendef1\lsdunhideuseddef1\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
+\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;
+\lsdpriority39 \lsdlocked0 toc 1;\lsdpriority39 \lsdlocked0 toc 2;\lsdpriority39 \lsdlocked0 toc 3;\lsdpriority39 \lsdlocked0 toc 4;\lsdpriority39 \lsdlocked0 toc 5;\lsdpriority39 \lsdlocked0 toc 6;\lsdpriority39 \lsdlocked0 toc 7;
+\lsdpriority39 \lsdlocked0 toc 8;\lsdpriority39 \lsdlocked0 toc 9;\lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdpriority1 \lsdlocked0 Default Paragraph Font;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority59 \lsdlocked0 Table Grid;\lsdunhideused0 \lsdlocked0 Placeholder Text;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdunhideused0 \lsdlocked0 Revision;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdpriority37 \lsdlocked0 Bibliography;\lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;}}{\*\datastore 010500000200000018000000
+4d73786d6c322e534158584d4c5265616465722e352e3000000000000000000000060000
+d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffffec69d9888b8b3d4c859eaf6cd158be0f000000000000000000000000f00c
+7fba7398ca01feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000105000000000000}}
\ No newline at end of file
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Document1.docx b/DataAccessLayer/TestData/Files/DupFiles1/Document1.docx
new file mode 100644
index 0000000..94dcb41
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Document1.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Document2.doc b/DataAccessLayer/TestData/Files/DupFiles1/Document2.doc
new file mode 100644
index 0000000..97b5bf0
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Document2.doc differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Document3.docx b/DataAccessLayer/TestData/Files/DupFiles1/Document3.docx
new file mode 100644
index 0000000..07313b9
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Document3.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Document4.doc b/DataAccessLayer/TestData/Files/DupFiles1/Document4.doc
new file mode 100644
index 0000000..b58cabf
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Document4.doc differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Document5.docx b/DataAccessLayer/TestData/Files/DupFiles1/Document5.docx
new file mode 100644
index 0000000..b8c0b62
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Document5.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Document6.docx b/DataAccessLayer/TestData/Files/DupFiles1/Document6.docx
new file mode 100644
index 0000000..75e8bad
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Document6.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Document7.docx b/DataAccessLayer/TestData/Files/DupFiles1/Document7.docx
new file mode 100644
index 0000000..4f8c401
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Document7.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Doris likes apples.doc b/DataAccessLayer/TestData/Files/DupFiles1/Doris likes apples.doc
new file mode 100644
index 0000000..ececba8
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Doris likes apples.doc differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Doris.xlsx b/DataAccessLayer/TestData/Files/DupFiles1/Doris.xlsx
new file mode 100644
index 0000000..0672cc5
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Doris.xlsx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Drawing1.vsd b/DataAccessLayer/TestData/Files/DupFiles1/Drawing1.vsd
new file mode 100644
index 0000000..85e0a90
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Drawing1.vsd differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Drawing2.vsd b/DataAccessLayer/TestData/Files/DupFiles1/Drawing2.vsd
new file mode 100644
index 0000000..e36bdbf
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Drawing2.vsd differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Map1.mmap b/DataAccessLayer/TestData/Files/DupFiles1/Map1.mmap
new file mode 100644
index 0000000..14fb76e
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Map1.mmap differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Map2.mmap b/DataAccessLayer/TestData/Files/DupFiles1/Map2.mmap
new file mode 100644
index 0000000..14fb76e
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Map2.mmap differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/MoreDefects.TXT b/DataAccessLayer/TestData/Files/DupFiles1/MoreDefects.TXT
new file mode 100644
index 0000000..b9bbe1c
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles1/MoreDefects.TXT
@@ -0,0 +1,5 @@
+
+
+
+[ButtonHook]
+- When W32Window get's a message and ::IsWindow(::GetParent(hWnd)) is false Close down everything!!!
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/New Mindmap1.mm b/DataAccessLayer/TestData/Files/DupFiles1/New Mindmap1.mm
new file mode 100644
index 0000000..e88a40f
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles1/New Mindmap1.mm
@@ -0,0 +1,4 @@
+
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/New Mindmap2.mm b/DataAccessLayer/TestData/Files/DupFiles1/New Mindmap2.mm
new file mode 100644
index 0000000..e88a40f
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles1/New Mindmap2.mm
@@ -0,0 +1,4 @@
+
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/OogyKeepInMind.txt b/DataAccessLayer/TestData/Files/DupFiles1/OogyKeepInMind.txt
new file mode 100644
index 0000000..1e3616f
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles1/OogyKeepInMind.txt
@@ -0,0 +1,27 @@
+[ShellExecuteLauncher.cs]
+-------------------------
+Right now ShellExecuteLauncher iterates thru all top level windows
+until it finds the name of the file in the title bar.
+
+comments:
+-to avoid collisions with duplicate file names (hold a map of
+ previous window handles), so if the file name is in the title and
+ it is not already mapped it's the new window.
+
+-maybe invoke bh or resolvers to do the work and skip title search
+ all together.
+
+Workspace launching (more testing to do with new resolver events)
+~but one possibility could be:
+-------------------------
+launcher calls BH -> AboutToLaunchWorkspace(), button hook disables
+all newly created buttons and listens for WM_CREATE and parentNotify_WM_CREATES...
+... in order... that is our in order handle table.
+
+launcher calls BH -> LaunchDone(artifacts), we use the artifacts in order
+in our table and launcher gets the list of handles.
+
+~this would work if launcher accurately launches in order and all windows
+are created in order. ~launcher should wait till resolve event occurs?
+~before launching next???
+--------------------------------------------
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Presentation1.ppt b/DataAccessLayer/TestData/Files/DupFiles1/Presentation1.ppt
new file mode 100644
index 0000000..390ef09
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Presentation1.ppt differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Presentation2.ppt b/DataAccessLayer/TestData/Files/DupFiles1/Presentation2.ppt
new file mode 100644
index 0000000..a8c747b
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Presentation2.ppt differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Publication1.pub b/DataAccessLayer/TestData/Files/DupFiles1/Publication1.pub
new file mode 100644
index 0000000..18d0764
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Publication1.pub differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/Publication2.pub b/DataAccessLayer/TestData/Files/DupFiles1/Publication2.pub
new file mode 100644
index 0000000..b75dfb8
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/Publication2.pub differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/doris.docx b/DataAccessLayer/TestData/Files/DupFiles1/doris.docx
new file mode 100644
index 0000000..26d3bd5
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/doris.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/doris2.docx b/DataAccessLayer/TestData/Files/DupFiles1/doris2.docx
new file mode 100644
index 0000000..124e9b5
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles1/doris2.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles1/textfile1.txt b/DataAccessLayer/TestData/Files/DupFiles1/textfile1.txt
new file mode 100644
index 0000000..de850da
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles1/textfile1.txt
@@ -0,0 +1,11 @@
+WM_ENTERIDLE fuSource:MSGF_DIALOGBOX hwnd:001b11dc
+WN_SETTEXT lpsz:000BEF18("SHELLY TO DO.txt - Notepad")
+
+[Open dialog sends the following things]
+WM_COMMAND wNotifyCode:BN_CLICKED wID:IDOK hwndCtrl:004F092E
+WM_NOTIFY idCtrl:1148 pnmh:000BEB30
+WM_NOTIFY idCtrl:1148 pnmh:000BEB6C
+
+[Tada!]
+Use ::GetOpenFileName or ::GetSaveFileName passing pointer to a OPENFILENAME structure.
+
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Albin likes apples.doc b/DataAccessLayer/TestData/Files/DupFiles2/Albin likes apples.doc
new file mode 100644
index 0000000..07ad7bc
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Albin likes apples.doc differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Book1.xls b/DataAccessLayer/TestData/Files/DupFiles2/Book1.xls
new file mode 100644
index 0000000..13be6fb
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Book1.xls differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Book1.xlsx b/DataAccessLayer/TestData/Files/DupFiles2/Book1.xlsx
new file mode 100644
index 0000000..150de4a
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Book1.xlsx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Book2.xls b/DataAccessLayer/TestData/Files/DupFiles2/Book2.xls
new file mode 100644
index 0000000..1adb97f
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Book2.xls differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Book2.xlsx b/DataAccessLayer/TestData/Files/DupFiles2/Book2.xlsx
new file mode 100644
index 0000000..715c15d
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Book2.xlsx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Book3.xls b/DataAccessLayer/TestData/Files/DupFiles2/Book3.xls
new file mode 100644
index 0000000..7b14cfb
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Book3.xls differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Book4.xls b/DataAccessLayer/TestData/Files/DupFiles2/Book4.xls
new file mode 100644
index 0000000..45a95f0
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Book4.xls differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/DatabaseBills.accdb b/DataAccessLayer/TestData/Files/DupFiles2/DatabaseBills.accdb
new file mode 100644
index 0000000..427bf49
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/DatabaseBills.accdb differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/DatabaseReceits.accdb b/DataAccessLayer/TestData/Files/DupFiles2/DatabaseReceits.accdb
new file mode 100644
index 0000000..77b797a
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/DatabaseReceits.accdb differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Doc1.rtf b/DataAccessLayer/TestData/Files/DupFiles2/Doc1.rtf
new file mode 100644
index 0000000..ca783c7
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles2/Doc1.rtf
@@ -0,0 +1,154 @@
+{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;}
+{\f34\fbidi \froman\fcharset1\fprq2{\*\panose 02040503050406030204}Cambria Math;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;}
+{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}
+{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f39\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f40\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\f42\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f43\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f44\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f45\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\f46\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f47\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f49\fbidi \fswiss\fcharset238\fprq2 Arial CE;}{\f50\fbidi \fswiss\fcharset204\fprq2 Arial Cyr;}
+{\f52\fbidi \fswiss\fcharset161\fprq2 Arial Greek;}{\f53\fbidi \fswiss\fcharset162\fprq2 Arial Tur;}{\f54\fbidi \fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f55\fbidi \fswiss\fcharset178\fprq2 Arial (Arabic);}
+{\f56\fbidi \fswiss\fcharset186\fprq2 Arial Baltic;}{\f57\fbidi \fswiss\fcharset163\fprq2 Arial (Vietnamese);}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhimajor\f31528\fbidi \froman\fcharset238\fprq2 Cambria CE;}
+{\fhimajor\f31529\fbidi \froman\fcharset204\fprq2 Cambria Cyr;}{\fhimajor\f31531\fbidi \froman\fcharset161\fprq2 Cambria Greek;}{\fhimajor\f31532\fbidi \froman\fcharset162\fprq2 Cambria Tur;}
+{\fhimajor\f31535\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}
+{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}
+{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;
+\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;
+\red192\green192\blue192;}{\*\defchp \fs22\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
+\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033
+\snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
+\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa200\sl276\slmult1
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033
+\snext11 \ssemihidden \sunhideused \sqformat Normal Table;}}{\*\rsidtbl \rsid5513996}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\operator HPinvent}
+{\creatim\yr2010\mo1\dy18\hr14\min23}{\revtim\yr2010\mo1\dy18\hr14\min23}{\version2}{\edmins0}{\nofpages1}{\nofwords1}{\nofchars8}{\nofcharsws8}{\vern32771}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}
+\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect
+\widowctrl\ftnbj\aenddoc\trackmoves1\trackformatting1\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120\dghorigin1701
+\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale100\rsidroot5513996 \fet0{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2
+\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6
+\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang
+{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033 {
+\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\insrsid5513996 \hich\af1\dbch\af31505\loch\f1 Doc1.Rtf}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\insrsid5513996
+\par }{\*\themedata 504b030414000600080000002100828abc13fa0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb6ac3301045f785fe83d0b6d8
+72ba28a5d8cea249777d2cd20f18e4b12d6a8f843409c9df77ecb850ba082d74231062ce997b55ae8fe3a00e1893f354e9555e6885647de3a8abf4fbee29bbd7
+2a3150038327acf409935ed7d757e5ee14302999a654e99e393c18936c8f23a4dc072479697d1c81e51a3b13c07e4087e6b628ee8cf5c4489cf1c4d075f92a0b
+44d7a07a83c82f308ac7b0a0f0fbf90c2480980b58abc733615aa2d210c2e02cb04430076a7ee833dfb6ce62e3ed7e14693e8317d8cd0433bf5c60f53fea2fe7
+065bd80facb647e9e25c7fc421fd2ddb526b2e9373fed4bb902e182e97b7b461e6bfad3f010000ffff0300504b030414000600080000002100a5d6a7e7c00000
+00360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4fc7060abb08
+84a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b63095120f88d94fbc
+52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462a1a82fe353
+bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f7468656d652f7468
+656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b4b0d592c9c
+070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b4757e8d3f7
+29e245eb2b260a0238fd010000ffff0300504b03041400060008000000210096b5ade296060000501b0000160000007468656d652f7468656d652f7468656d65
+312e786d6cec594f6fdb3614bf0fd87720746f6327761a07758ad8b19b2d4d1bc46e871e698996d850a240d2497d1bdae38001c3ba618715d86d87615b8116d8
+a5fb34d93a6c1dd0afb0475292c5585e9236d88aad3e2412f9e3fbff1e1fa9abd7eec70c1d1221294fda5efd72cd4324f1794093b0eddd1ef62fad79482a9c04
+98f184b4bd2991deb58df7dfbb8ad755446282607d22d771db8b944ad79796a40fc3585ee62949606ecc458c15bc8a702910f808e8c66c69b9565b5d8a314d3c
+94e018c8de1a8fa94fd05093f43672e23d06af89927ac06762a049136785c10607758d9053d965021d62d6f6804fc08f86e4bef210c352c144dbab999fb7b471
+7509af678b985ab0b6b4ae6f7ed9ba6c4170b06c788a705430adf71bad2b5b057d03606a1ed7ebf5babd7a41cf00b0ef83a6569632cd467faddec9699640f671
+9e76b7d6ac355c7c89feca9cccad4ea7d36c65b258a206641f1b73f8b5da6a6373d9c11b90c537e7f08dce66b7bbeae00dc8e257e7f0fd2badd5868b37a088d1
+e4600ead1ddaef67d40bc898b3ed4af81ac0d76a197c86826828a24bb318f3442d8ab518dfe3a20f000d6458d104a9694ac6d88728eee2782428d60cf03ac1a5
+193be4cbb921cd0b495fd054b5bd0f530c1931a3f7eaf9f7af9e3f45c70f9e1d3ff8e9f8e1c3e3073f5a42ceaa6d9c84e5552fbffdeccfc71fa33f9e7ef3f2d1
+17d57859c6fffac327bffcfc793510d26726ce8b2f9ffcf6ecc98baf3efdfdbb4715f04d814765f890c644a29be408edf3181433567125272371be15c308d3f2
+8acd249438c19a4b05fd9e8a1cf4cd296699771c393ac4b5e01d01e5a30a787d72cf1178108989a2159c77a2d801ee72ce3a5c545a6147f32a99793849c26ae6
+6252c6ed637c58c5bb8b13c7bfbd490a75330f4b47f16e441c31f7184e140e494214d273fc80900aedee52ead87597fa824b3e56e82e451d4c2b4d32a423279a
+668bb6690c7e9956e90cfe766cb37b077538abd27a8b1cba48c80acc2a841f12e698f13a9e281c57911ce298950d7e03aba84ac8c154f8655c4f2af074481847
+bd804859b5e696007d4b4edfc150b12addbecba6b18b148a1e54d1bc81392f23b7f84137c2715a851dd0242a633f900710a218ed715505dfe56e86e877f0034e
+16bafb0e258ebb4faf06b769e888340b103d3311da9750aa9d0a1cd3e4efca31a3508f6d0c5c5c398602f8e2ebc71591f5b616e24dd893aa3261fb44f95d843b
+5974bb5c04f4edafb95b7892ec1108f3f98de75dc97d5772bdff7cc95d94cf672db4b3da0a6557f70db629362d72bcb0431e53c6066acac80d699a6409fb44d0
+8741bdce9c0e4971624a2378cceaba830b05366b90e0ea23aaa241845368b0eb9e2612ca8c742851ca251ceccc70256d8d87265dd96361531f186c3d9058edf2
+c00eafe8e1fc5c509031bb4d680e9f39a3154de0accc56ae644441edd76156d7429d995bdd88664a9dc3ad50197c38af1a0c16d684060441db02565e85f3b966
+0d0713cc48a0ed6ef7dedc2dc60b17e92219e180643ed27acffba86e9c94c78ab90980d8a9f0913ee49d62b512b79626fb06dccee2a432bbc60276b9f7dec44b
+7904cfbca4f3f6443ab2a49c9c2c41476dafd55c6e7ac8c769db1bc399161ee314bc2e75cf8759081743be1236ec4f4d6693e5336fb672c5dc24a8c33585b5fb
+9cc24e1d4885545b58463634cc5416022cd19cacfccb4d30eb45296023fd35a458598360f8d7a4003bbaae25e331f155d9d9a5116d3bfb9a95523e51440ca2e0
+088dd844ec6370bf0e55d027a012ae264c45d02f708fa6ad6da6dce29c255df9f6cae0ec38666984b372ab5334cf640b37795cc860de4ae2816e95b21be5ceaf
+8a49f90b52a51cc6ff3355f47e0237052b81f6800fd7b802239daf6d8f0b1571a8426944fdbe80c6c1d40e8816b88b8569082ab84c36ff0539d4ff6dce591a26
+ade1c0a7f669880485fd484582903d284b26fa4e2156cff62e4b9265844c4495c495a9157b440e091bea1ab8aaf7760f4510eaa69a6465c0e04ec69ffb9e65d0
+28d44d4e39df9c1a52ecbd3607fee9cec7263328e5d661d3d0e4f62f44acd855ed7ab33cdf7bcb8ae889599bd5c8b3029895b6825696f6af29c239b75a5bb1e6
+345e6ee6c28117e73586c1a2214ae1be07e93fb0ff51e133fb65426fa843be0fb515c187064d0cc206a2fa926d3c902e907670048d931db4c1a44959d366ad93
+b65abe595f70a75bf03d616c2dd959fc7d4e6317cd99cbcec9c58b34766661c7d6766ca1a9c1b327531486c6f941c638c67cd22a7f75e2a37be0e82db8df9f30
+254d30c1372581a1f51c983c80e4b71ccdd28dbf000000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f74
+68656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f24
+51eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198
+720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528
+a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100828abc13fa0000001c0200001300000000000000000000000000
+000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b000000000000000000000000
+002b0100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000140200007468
+656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d001400060008000000210096b5ade296060000501b000016000000000000000000
+00000000d10200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b010000270000000000
+00000000000000009b0900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000960a00000000}
+{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d
+617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
+6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
+656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
+{\*\latentstyles\lsdstimax267\lsdlockeddef0\lsdsemihiddendef1\lsdunhideuseddef1\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
+\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;
+\lsdpriority39 \lsdlocked0 toc 1;\lsdpriority39 \lsdlocked0 toc 2;\lsdpriority39 \lsdlocked0 toc 3;\lsdpriority39 \lsdlocked0 toc 4;\lsdpriority39 \lsdlocked0 toc 5;\lsdpriority39 \lsdlocked0 toc 6;\lsdpriority39 \lsdlocked0 toc 7;
+\lsdpriority39 \lsdlocked0 toc 8;\lsdpriority39 \lsdlocked0 toc 9;\lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdpriority1 \lsdlocked0 Default Paragraph Font;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority59 \lsdlocked0 Table Grid;\lsdunhideused0 \lsdlocked0 Placeholder Text;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdunhideused0 \lsdlocked0 Revision;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdpriority37 \lsdlocked0 Bibliography;\lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;}}{\*\datastore 010500000200000018000000
+4d73786d6c322e534158584d4c5265616465722e352e3000000000000000000000060000
+d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffffec69d9888b8b3d4c859eaf6cd158be0f0000000000000000000000002068
+d7b37398ca01feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000105000000000000}}
\ No newline at end of file
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Doc2.rtf b/DataAccessLayer/TestData/Files/DupFiles2/Doc2.rtf
new file mode 100644
index 0000000..f6b7f34
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles2/Doc2.rtf
@@ -0,0 +1,154 @@
+{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f34\fbidi \froman\fcharset1\fprq2{\*\panose 02040503050406030204}Cambria Math;}
+{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;}
+{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}
+{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f39\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f40\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\f42\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f43\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f44\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f45\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\f46\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f47\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f409\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f410\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}
+{\f412\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f413\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f416\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\fhimajor\f31528\fbidi \froman\fcharset238\fprq2 Cambria CE;}{\fhimajor\f31529\fbidi \froman\fcharset204\fprq2 Cambria Cyr;}{\fhimajor\f31531\fbidi \froman\fcharset161\fprq2 Cambria Greek;}{\fhimajor\f31532\fbidi \froman\fcharset162\fprq2 Cambria Tur;}
+{\fhimajor\f31535\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}
+{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}
+{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;
+\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;
+\red192\green192\blue192;}{\*\defchp \fs22\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
+\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033
+\snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
+\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa200\sl276\slmult1
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033
+\snext11 \ssemihidden \sunhideused \sqformat Normal Table;}}{\*\rsidtbl \rsid15009392}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\operator HPinvent}
+{\creatim\yr2010\mo1\dy18\hr14\min23}{\revtim\yr2010\mo1\dy18\hr14\min23}{\version2}{\edmins0}{\nofpages1}{\nofwords1}{\nofchars8}{\nofcharsws8}{\vern32771}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}
+\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect
+\widowctrl\ftnbj\aenddoc\trackmoves1\trackformatting1\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120\dghorigin1701
+\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale100\rsidroot15009392 \fet0{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2
+\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6
+\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang
+{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid15009392 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0
+\fs22\lang1033\langfe1033\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af31507\afs20 \ltrch\fcs0 \insrsid15009392 \hich\af31506\dbch\af31505\loch\f31506 Doc2.rtf}{\rtlch\fcs1 \af31507\afs20 \ltrch\fcs0
+\insrsid15009392\charrsid15009392
+\par }{\*\themedata 504b030414000600080000002100828abc13fa0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb6ac3301045f785fe83d0b6d8
+72ba28a5d8cea249777d2cd20f18e4b12d6a8f843409c9df77ecb850ba082d74231062ce997b55ae8fe3a00e1893f354e9555e6885647de3a8abf4fbee29bbd7
+2a3150038327acf409935ed7d757e5ee14302999a654e99e393c18936c8f23a4dc072479697d1c81e51a3b13c07e4087e6b628ee8cf5c4489cf1c4d075f92a0b
+44d7a07a83c82f308ac7b0a0f0fbf90c2480980b58abc733615aa2d210c2e02cb04430076a7ee833dfb6ce62e3ed7e14693e8317d8cd0433bf5c60f53fea2fe7
+065bd80facb647e9e25c7fc421fd2ddb526b2e9373fed4bb902e182e97b7b461e6bfad3f010000ffff0300504b030414000600080000002100a5d6a7e7c00000
+00360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4fc7060abb08
+84a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b63095120f88d94fbc
+52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462a1a82fe353
+bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f7468656d652f7468
+656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b4b0d592c9c
+070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b4757e8d3f7
+29e245eb2b260a0238fd010000ffff0300504b03041400060008000000210096b5ade296060000501b0000160000007468656d652f7468656d652f7468656d65
+312e786d6cec594f6fdb3614bf0fd87720746f6327761a07758ad8b19b2d4d1bc46e871e698996d850a240d2497d1bdae38001c3ba618715d86d87615b8116d8
+a5fb34d93a6c1dd0afb0475292c5585e9236d88aad3e2412f9e3fbff1e1fa9abd7eec70c1d1221294fda5efd72cd4324f1794093b0eddd1ef62fad79482a9c04
+98f184b4bd2991deb58df7dfbb8ad755446282607d22d771db8b944ad79796a40fc3585ee62949606ecc458c15bc8a702910f808e8c66c69b9565b5d8a314d3c
+94e018c8de1a8fa94fd05093f43672e23d06af89927ac06762a049136785c10607758d9053d965021d62d6f6804fc08f86e4bef210c352c144dbab999fb7b471
+7509af678b985ab0b6b4ae6f7ed9ba6c4170b06c788a705430adf71bad2b5b057d03606a1ed7ebf5babd7a41cf00b0ef83a6569632cd467faddec9699640f671
+9e76b7d6ac355c7c89feca9cccad4ea7d36c65b258a206641f1b73f8b5da6a6373d9c11b90c537e7f08dce66b7bbeae00dc8e257e7f0fd2badd5868b37a088d1
+e4600ead1ddaef67d40bc898b3ed4af81ac0d76a197c86826828a24bb318f3442d8ab518dfe3a20f000d6458d104a9694ac6d88728eee2782428d60cf03ac1a5
+193be4cbb921cd0b495fd054b5bd0f530c1931a3f7eaf9f7af9e3f45c70f9e1d3ff8e9f8e1c3e3073f5a42ceaa6d9c84e5552fbffdeccfc71fa33f9e7ef3f2d1
+17d57859c6fffac327bffcfc793510d26726ce8b2f9ffcf6ecc98baf3efdfdbb4715f04d814765f890c644a29be408edf3181433567125272371be15c308d3f2
+8acd249438c19a4b05fd9e8a1cf4cd296699771c393ac4b5e01d01e5a30a787d72cf1178108989a2159c77a2d801ee72ce3a5c545a6147f32a99793849c26ae6
+6252c6ed637c58c5bb8b13c7bfbd490a75330f4b47f16e441c31f7184e140e494214d273fc80900aedee52ead87597fa824b3e56e82e451d4c2b4d32a423279a
+668bb6690c7e9956e90cfe766cb37b077538abd27a8b1cba48c80acc2a841f12e698f13a9e281c57911ce298950d7e03aba84ac8c154f8655c4f2af074481847
+bd804859b5e696007d4b4edfc150b12addbecba6b18b148a1e54d1bc81392f23b7f84137c2715a851dd0242a633f900710a218ed715505dfe56e86e877f0034e
+16bafb0e258ebb4faf06b769e888340b103d3311da9750aa9d0a1cd3e4efca31a3508f6d0c5c5c398602f8e2ebc71591f5b616e24dd893aa3261fb44f95d843b
+5974bb5c04f4edafb95b7892ec1108f3f98de75dc97d5772bdff7cc95d94cf672db4b3da0a6557f70db629362d72bcb0431e53c6066acac80d699a6409fb44d0
+8741bdce9c0e4971624a2378cceaba830b05366b90e0ea23aaa241845368b0eb9e2612ca8c742851ca251ceccc70256d8d87265dd96361531f186c3d9058edf2
+c00eafe8e1fc5c509031bb4d680e9f39a3154de0accc56ae644441edd76156d7429d995bdd88664a9dc3ad50197c38af1a0c16d684060441db02565e85f3b966
+0d0713cc48a0ed6ef7dedc2dc60b17e92219e180643ed27acffba86e9c94c78ab90980d8a9f0913ee49d62b512b79626fb06dccee2a432bbc60276b9f7dec44b
+7904cfbca4f3f6443ab2a49c9c2c41476dafd55c6e7ac8c769db1bc399161ee314bc2e75cf8759081743be1236ec4f4d6693e5336fb672c5dc24a8c33585b5fb
+9cc24e1d4885545b58463634cc5416022cd19cacfccb4d30eb45296023fd35a458598360f8d7a4003bbaae25e331f155d9d9a5116d3bfb9a95523e51440ca2e0
+088dd844ec6370bf0e55d027a012ae264c45d02f708fa6ad6da6dce29c255df9f6cae0ec38666984b372ab5334cf640b37795cc860de4ae2816e95b21be5ceaf
+8a49f90b52a51cc6ff3355f47e0237052b81f6800fd7b802239daf6d8f0b1571a8426944fdbe80c6c1d40e8816b88b8569082ab84c36ff0539d4ff6dce591a26
+ade1c0a7f669880485fd484582903d284b26fa4e2156cff62e4b9265844c4495c495a9157b440e091bea1ab8aaf7760f4510eaa69a6465c0e04ec69ffb9e65d0
+28d44d4e39df9c1a52ecbd3607fee9cec7263328e5d661d3d0e4f62f44acd855ed7ab33cdf7bcb8ae889599bd5c8b3029895b6825696f6af29c239b75a5bb1e6
+345e6ee6c28117e73586c1a2214ae1be07e93fb0ff51e133fb65426fa843be0fb515c187064d0cc206a2fa926d3c902e907670048d931db4c1a44959d366ad93
+b65abe595f70a75bf03d616c2dd959fc7d4e6317cd99cbcec9c58b34766661c7d6766ca1a9c1b327531486c6f941c638c67cd22a7f75e2a37be0e82db8df9f30
+254d30c1372581a1f51c983c80e4b71ccdd28dbf000000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f74
+68656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f24
+51eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198
+720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528
+a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100828abc13fa0000001c0200001300000000000000000000000000
+000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b000000000000000000000000
+002b0100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000140200007468
+656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d001400060008000000210096b5ade296060000501b000016000000000000000000
+00000000d10200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b010000270000000000
+00000000000000009b0900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000960a00000000}
+{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d
+617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
+6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
+656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
+{\*\latentstyles\lsdstimax267\lsdlockeddef0\lsdsemihiddendef1\lsdunhideuseddef1\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
+\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;
+\lsdpriority39 \lsdlocked0 toc 1;\lsdpriority39 \lsdlocked0 toc 2;\lsdpriority39 \lsdlocked0 toc 3;\lsdpriority39 \lsdlocked0 toc 4;\lsdpriority39 \lsdlocked0 toc 5;\lsdpriority39 \lsdlocked0 toc 6;\lsdpriority39 \lsdlocked0 toc 7;
+\lsdpriority39 \lsdlocked0 toc 8;\lsdpriority39 \lsdlocked0 toc 9;\lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdpriority1 \lsdlocked0 Default Paragraph Font;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority59 \lsdlocked0 Table Grid;\lsdunhideused0 \lsdlocked0 Placeholder Text;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdunhideused0 \lsdlocked0 Revision;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdpriority37 \lsdlocked0 Bibliography;\lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;}}{\*\datastore 010500000200000018000000
+4d73786d6c322e534158584d4c5265616465722e352e3000000000000000000000060000
+d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffffec69d9888b8b3d4c859eaf6cd158be0f000000000000000000000000f00c
+7fba7398ca01feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000105000000000000}}
\ No newline at end of file
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Document1.docx b/DataAccessLayer/TestData/Files/DupFiles2/Document1.docx
new file mode 100644
index 0000000..94dcb41
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Document1.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Document2.doc b/DataAccessLayer/TestData/Files/DupFiles2/Document2.doc
new file mode 100644
index 0000000..97b5bf0
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Document2.doc differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Document3.docx b/DataAccessLayer/TestData/Files/DupFiles2/Document3.docx
new file mode 100644
index 0000000..07313b9
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Document3.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Document4.doc b/DataAccessLayer/TestData/Files/DupFiles2/Document4.doc
new file mode 100644
index 0000000..b58cabf
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Document4.doc differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Document5.docx b/DataAccessLayer/TestData/Files/DupFiles2/Document5.docx
new file mode 100644
index 0000000..b8c0b62
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Document5.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Document6.docx b/DataAccessLayer/TestData/Files/DupFiles2/Document6.docx
new file mode 100644
index 0000000..75e8bad
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Document6.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Document7.docx b/DataAccessLayer/TestData/Files/DupFiles2/Document7.docx
new file mode 100644
index 0000000..4f8c401
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Document7.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Doris likes apples.doc b/DataAccessLayer/TestData/Files/DupFiles2/Doris likes apples.doc
new file mode 100644
index 0000000..ececba8
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Doris likes apples.doc differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Doris.xlsx b/DataAccessLayer/TestData/Files/DupFiles2/Doris.xlsx
new file mode 100644
index 0000000..0672cc5
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Doris.xlsx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Drawing1.vsd b/DataAccessLayer/TestData/Files/DupFiles2/Drawing1.vsd
new file mode 100644
index 0000000..f1a9e28
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Drawing1.vsd differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Drawing2.vsd b/DataAccessLayer/TestData/Files/DupFiles2/Drawing2.vsd
new file mode 100644
index 0000000..f1a9e28
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Drawing2.vsd differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Map1.mmap b/DataAccessLayer/TestData/Files/DupFiles2/Map1.mmap
new file mode 100644
index 0000000..14fb76e
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Map1.mmap differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Map2.mmap b/DataAccessLayer/TestData/Files/DupFiles2/Map2.mmap
new file mode 100644
index 0000000..14fb76e
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Map2.mmap differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/MoreDefects.TXT b/DataAccessLayer/TestData/Files/DupFiles2/MoreDefects.TXT
new file mode 100644
index 0000000..b9bbe1c
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles2/MoreDefects.TXT
@@ -0,0 +1,5 @@
+
+
+
+[ButtonHook]
+- When W32Window get's a message and ::IsWindow(::GetParent(hWnd)) is false Close down everything!!!
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/New Mindmap1.mm b/DataAccessLayer/TestData/Files/DupFiles2/New Mindmap1.mm
new file mode 100644
index 0000000..e88a40f
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles2/New Mindmap1.mm
@@ -0,0 +1,4 @@
+
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/New Mindmap2.mm b/DataAccessLayer/TestData/Files/DupFiles2/New Mindmap2.mm
new file mode 100644
index 0000000..e88a40f
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles2/New Mindmap2.mm
@@ -0,0 +1,4 @@
+
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/OogyKeepInMind.txt b/DataAccessLayer/TestData/Files/DupFiles2/OogyKeepInMind.txt
new file mode 100644
index 0000000..1e3616f
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles2/OogyKeepInMind.txt
@@ -0,0 +1,27 @@
+[ShellExecuteLauncher.cs]
+-------------------------
+Right now ShellExecuteLauncher iterates thru all top level windows
+until it finds the name of the file in the title bar.
+
+comments:
+-to avoid collisions with duplicate file names (hold a map of
+ previous window handles), so if the file name is in the title and
+ it is not already mapped it's the new window.
+
+-maybe invoke bh or resolvers to do the work and skip title search
+ all together.
+
+Workspace launching (more testing to do with new resolver events)
+~but one possibility could be:
+-------------------------
+launcher calls BH -> AboutToLaunchWorkspace(), button hook disables
+all newly created buttons and listens for WM_CREATE and parentNotify_WM_CREATES...
+... in order... that is our in order handle table.
+
+launcher calls BH -> LaunchDone(artifacts), we use the artifacts in order
+in our table and launcher gets the list of handles.
+
+~this would work if launcher accurately launches in order and all windows
+are created in order. ~launcher should wait till resolve event occurs?
+~before launching next???
+--------------------------------------------
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Presentation1.ppt b/DataAccessLayer/TestData/Files/DupFiles2/Presentation1.ppt
new file mode 100644
index 0000000..61d4880
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Presentation1.ppt differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Presentation2.ppt b/DataAccessLayer/TestData/Files/DupFiles2/Presentation2.ppt
new file mode 100644
index 0000000..ce7f006
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Presentation2.ppt differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Publication1.pub b/DataAccessLayer/TestData/Files/DupFiles2/Publication1.pub
new file mode 100644
index 0000000..215aa5b
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Publication1.pub differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/Publication2.pub b/DataAccessLayer/TestData/Files/DupFiles2/Publication2.pub
new file mode 100644
index 0000000..a0dda95
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/Publication2.pub differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/doris.docx b/DataAccessLayer/TestData/Files/DupFiles2/doris.docx
new file mode 100644
index 0000000..26d3bd5
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/doris.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/doris2.docx b/DataAccessLayer/TestData/Files/DupFiles2/doris2.docx
new file mode 100644
index 0000000..124e9b5
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles2/doris2.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles2/textfile1.txt b/DataAccessLayer/TestData/Files/DupFiles2/textfile1.txt
new file mode 100644
index 0000000..de850da
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles2/textfile1.txt
@@ -0,0 +1,11 @@
+WM_ENTERIDLE fuSource:MSGF_DIALOGBOX hwnd:001b11dc
+WN_SETTEXT lpsz:000BEF18("SHELLY TO DO.txt - Notepad")
+
+[Open dialog sends the following things]
+WM_COMMAND wNotifyCode:BN_CLICKED wID:IDOK hwndCtrl:004F092E
+WM_NOTIFY idCtrl:1148 pnmh:000BEB30
+WM_NOTIFY idCtrl:1148 pnmh:000BEB6C
+
+[Tada!]
+Use ::GetOpenFileName or ::GetSaveFileName passing pointer to a OPENFILENAME structure.
+
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Albin likes apples.doc b/DataAccessLayer/TestData/Files/DupFiles3/Albin likes apples.doc
new file mode 100644
index 0000000..07ad7bc
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Albin likes apples.doc differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Book1.xls b/DataAccessLayer/TestData/Files/DupFiles3/Book1.xls
new file mode 100644
index 0000000..21c4c80
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Book1.xls differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Book1.xlsx b/DataAccessLayer/TestData/Files/DupFiles3/Book1.xlsx
new file mode 100644
index 0000000..150de4a
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Book1.xlsx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Book2.xls b/DataAccessLayer/TestData/Files/DupFiles3/Book2.xls
new file mode 100644
index 0000000..7244f00
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Book2.xls differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Book2.xlsx b/DataAccessLayer/TestData/Files/DupFiles3/Book2.xlsx
new file mode 100644
index 0000000..715c15d
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Book2.xlsx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Book3.xls b/DataAccessLayer/TestData/Files/DupFiles3/Book3.xls
new file mode 100644
index 0000000..e6cf8d9
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Book3.xls differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Book4.xls b/DataAccessLayer/TestData/Files/DupFiles3/Book4.xls
new file mode 100644
index 0000000..45a95f0
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Book4.xls differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/DatabaseBills.accdb b/DataAccessLayer/TestData/Files/DupFiles3/DatabaseBills.accdb
new file mode 100644
index 0000000..427bf49
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/DatabaseBills.accdb differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/DatabaseReceits.accdb b/DataAccessLayer/TestData/Files/DupFiles3/DatabaseReceits.accdb
new file mode 100644
index 0000000..77b797a
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/DatabaseReceits.accdb differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Doc1.rtf b/DataAccessLayer/TestData/Files/DupFiles3/Doc1.rtf
new file mode 100644
index 0000000..ca783c7
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles3/Doc1.rtf
@@ -0,0 +1,154 @@
+{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;}
+{\f34\fbidi \froman\fcharset1\fprq2{\*\panose 02040503050406030204}Cambria Math;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;}
+{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}
+{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f39\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f40\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\f42\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f43\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f44\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f45\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\f46\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f47\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f49\fbidi \fswiss\fcharset238\fprq2 Arial CE;}{\f50\fbidi \fswiss\fcharset204\fprq2 Arial Cyr;}
+{\f52\fbidi \fswiss\fcharset161\fprq2 Arial Greek;}{\f53\fbidi \fswiss\fcharset162\fprq2 Arial Tur;}{\f54\fbidi \fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f55\fbidi \fswiss\fcharset178\fprq2 Arial (Arabic);}
+{\f56\fbidi \fswiss\fcharset186\fprq2 Arial Baltic;}{\f57\fbidi \fswiss\fcharset163\fprq2 Arial (Vietnamese);}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhimajor\f31528\fbidi \froman\fcharset238\fprq2 Cambria CE;}
+{\fhimajor\f31529\fbidi \froman\fcharset204\fprq2 Cambria Cyr;}{\fhimajor\f31531\fbidi \froman\fcharset161\fprq2 Cambria Greek;}{\fhimajor\f31532\fbidi \froman\fcharset162\fprq2 Cambria Tur;}
+{\fhimajor\f31535\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}
+{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}
+{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;
+\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;
+\red192\green192\blue192;}{\*\defchp \fs22\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
+\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033
+\snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
+\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa200\sl276\slmult1
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033
+\snext11 \ssemihidden \sunhideused \sqformat Normal Table;}}{\*\rsidtbl \rsid5513996}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\operator HPinvent}
+{\creatim\yr2010\mo1\dy18\hr14\min23}{\revtim\yr2010\mo1\dy18\hr14\min23}{\version2}{\edmins0}{\nofpages1}{\nofwords1}{\nofchars8}{\nofcharsws8}{\vern32771}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}
+\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect
+\widowctrl\ftnbj\aenddoc\trackmoves1\trackformatting1\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120\dghorigin1701
+\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale100\rsidroot5513996 \fet0{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2
+\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6
+\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang
+{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033 {
+\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\insrsid5513996 \hich\af1\dbch\af31505\loch\f1 Doc1.Rtf}{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\insrsid5513996
+\par }{\*\themedata 504b030414000600080000002100828abc13fa0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb6ac3301045f785fe83d0b6d8
+72ba28a5d8cea249777d2cd20f18e4b12d6a8f843409c9df77ecb850ba082d74231062ce997b55ae8fe3a00e1893f354e9555e6885647de3a8abf4fbee29bbd7
+2a3150038327acf409935ed7d757e5ee14302999a654e99e393c18936c8f23a4dc072479697d1c81e51a3b13c07e4087e6b628ee8cf5c4489cf1c4d075f92a0b
+44d7a07a83c82f308ac7b0a0f0fbf90c2480980b58abc733615aa2d210c2e02cb04430076a7ee833dfb6ce62e3ed7e14693e8317d8cd0433bf5c60f53fea2fe7
+065bd80facb647e9e25c7fc421fd2ddb526b2e9373fed4bb902e182e97b7b461e6bfad3f010000ffff0300504b030414000600080000002100a5d6a7e7c00000
+00360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4fc7060abb08
+84a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b63095120f88d94fbc
+52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462a1a82fe353
+bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f7468656d652f7468
+656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b4b0d592c9c
+070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b4757e8d3f7
+29e245eb2b260a0238fd010000ffff0300504b03041400060008000000210096b5ade296060000501b0000160000007468656d652f7468656d652f7468656d65
+312e786d6cec594f6fdb3614bf0fd87720746f6327761a07758ad8b19b2d4d1bc46e871e698996d850a240d2497d1bdae38001c3ba618715d86d87615b8116d8
+a5fb34d93a6c1dd0afb0475292c5585e9236d88aad3e2412f9e3fbff1e1fa9abd7eec70c1d1221294fda5efd72cd4324f1794093b0eddd1ef62fad79482a9c04
+98f184b4bd2991deb58df7dfbb8ad755446282607d22d771db8b944ad79796a40fc3585ee62949606ecc458c15bc8a702910f808e8c66c69b9565b5d8a314d3c
+94e018c8de1a8fa94fd05093f43672e23d06af89927ac06762a049136785c10607758d9053d965021d62d6f6804fc08f86e4bef210c352c144dbab999fb7b471
+7509af678b985ab0b6b4ae6f7ed9ba6c4170b06c788a705430adf71bad2b5b057d03606a1ed7ebf5babd7a41cf00b0ef83a6569632cd467faddec9699640f671
+9e76b7d6ac355c7c89feca9cccad4ea7d36c65b258a206641f1b73f8b5da6a6373d9c11b90c537e7f08dce66b7bbeae00dc8e257e7f0fd2badd5868b37a088d1
+e4600ead1ddaef67d40bc898b3ed4af81ac0d76a197c86826828a24bb318f3442d8ab518dfe3a20f000d6458d104a9694ac6d88728eee2782428d60cf03ac1a5
+193be4cbb921cd0b495fd054b5bd0f530c1931a3f7eaf9f7af9e3f45c70f9e1d3ff8e9f8e1c3e3073f5a42ceaa6d9c84e5552fbffdeccfc71fa33f9e7ef3f2d1
+17d57859c6fffac327bffcfc793510d26726ce8b2f9ffcf6ecc98baf3efdfdbb4715f04d814765f890c644a29be408edf3181433567125272371be15c308d3f2
+8acd249438c19a4b05fd9e8a1cf4cd296699771c393ac4b5e01d01e5a30a787d72cf1178108989a2159c77a2d801ee72ce3a5c545a6147f32a99793849c26ae6
+6252c6ed637c58c5bb8b13c7bfbd490a75330f4b47f16e441c31f7184e140e494214d273fc80900aedee52ead87597fa824b3e56e82e451d4c2b4d32a423279a
+668bb6690c7e9956e90cfe766cb37b077538abd27a8b1cba48c80acc2a841f12e698f13a9e281c57911ce298950d7e03aba84ac8c154f8655c4f2af074481847
+bd804859b5e696007d4b4edfc150b12addbecba6b18b148a1e54d1bc81392f23b7f84137c2715a851dd0242a633f900710a218ed715505dfe56e86e877f0034e
+16bafb0e258ebb4faf06b769e888340b103d3311da9750aa9d0a1cd3e4efca31a3508f6d0c5c5c398602f8e2ebc71591f5b616e24dd893aa3261fb44f95d843b
+5974bb5c04f4edafb95b7892ec1108f3f98de75dc97d5772bdff7cc95d94cf672db4b3da0a6557f70db629362d72bcb0431e53c6066acac80d699a6409fb44d0
+8741bdce9c0e4971624a2378cceaba830b05366b90e0ea23aaa241845368b0eb9e2612ca8c742851ca251ceccc70256d8d87265dd96361531f186c3d9058edf2
+c00eafe8e1fc5c509031bb4d680e9f39a3154de0accc56ae644441edd76156d7429d995bdd88664a9dc3ad50197c38af1a0c16d684060441db02565e85f3b966
+0d0713cc48a0ed6ef7dedc2dc60b17e92219e180643ed27acffba86e9c94c78ab90980d8a9f0913ee49d62b512b79626fb06dccee2a432bbc60276b9f7dec44b
+7904cfbca4f3f6443ab2a49c9c2c41476dafd55c6e7ac8c769db1bc399161ee314bc2e75cf8759081743be1236ec4f4d6693e5336fb672c5dc24a8c33585b5fb
+9cc24e1d4885545b58463634cc5416022cd19cacfccb4d30eb45296023fd35a458598360f8d7a4003bbaae25e331f155d9d9a5116d3bfb9a95523e51440ca2e0
+088dd844ec6370bf0e55d027a012ae264c45d02f708fa6ad6da6dce29c255df9f6cae0ec38666984b372ab5334cf640b37795cc860de4ae2816e95b21be5ceaf
+8a49f90b52a51cc6ff3355f47e0237052b81f6800fd7b802239daf6d8f0b1571a8426944fdbe80c6c1d40e8816b88b8569082ab84c36ff0539d4ff6dce591a26
+ade1c0a7f669880485fd484582903d284b26fa4e2156cff62e4b9265844c4495c495a9157b440e091bea1ab8aaf7760f4510eaa69a6465c0e04ec69ffb9e65d0
+28d44d4e39df9c1a52ecbd3607fee9cec7263328e5d661d3d0e4f62f44acd855ed7ab33cdf7bcb8ae889599bd5c8b3029895b6825696f6af29c239b75a5bb1e6
+345e6ee6c28117e73586c1a2214ae1be07e93fb0ff51e133fb65426fa843be0fb515c187064d0cc206a2fa926d3c902e907670048d931db4c1a44959d366ad93
+b65abe595f70a75bf03d616c2dd959fc7d4e6317cd99cbcec9c58b34766661c7d6766ca1a9c1b327531486c6f941c638c67cd22a7f75e2a37be0e82db8df9f30
+254d30c1372581a1f51c983c80e4b71ccdd28dbf000000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f74
+68656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f24
+51eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198
+720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528
+a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100828abc13fa0000001c0200001300000000000000000000000000
+000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b000000000000000000000000
+002b0100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000140200007468
+656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d001400060008000000210096b5ade296060000501b000016000000000000000000
+00000000d10200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b010000270000000000
+00000000000000009b0900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000960a00000000}
+{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d
+617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
+6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
+656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
+{\*\latentstyles\lsdstimax267\lsdlockeddef0\lsdsemihiddendef1\lsdunhideuseddef1\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
+\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;
+\lsdpriority39 \lsdlocked0 toc 1;\lsdpriority39 \lsdlocked0 toc 2;\lsdpriority39 \lsdlocked0 toc 3;\lsdpriority39 \lsdlocked0 toc 4;\lsdpriority39 \lsdlocked0 toc 5;\lsdpriority39 \lsdlocked0 toc 6;\lsdpriority39 \lsdlocked0 toc 7;
+\lsdpriority39 \lsdlocked0 toc 8;\lsdpriority39 \lsdlocked0 toc 9;\lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdpriority1 \lsdlocked0 Default Paragraph Font;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority59 \lsdlocked0 Table Grid;\lsdunhideused0 \lsdlocked0 Placeholder Text;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdunhideused0 \lsdlocked0 Revision;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdpriority37 \lsdlocked0 Bibliography;\lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;}}{\*\datastore 010500000200000018000000
+4d73786d6c322e534158584d4c5265616465722e352e3000000000000000000000060000
+d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffffec69d9888b8b3d4c859eaf6cd158be0f0000000000000000000000002068
+d7b37398ca01feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000105000000000000}}
\ No newline at end of file
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Doc2.rtf b/DataAccessLayer/TestData/Files/DupFiles3/Doc2.rtf
new file mode 100644
index 0000000..f6b7f34
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles3/Doc2.rtf
@@ -0,0 +1,154 @@
+{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f34\fbidi \froman\fcharset1\fprq2{\*\panose 02040503050406030204}Cambria Math;}
+{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;}
+{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}
+{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;}
+{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f39\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f40\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\f42\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f43\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f44\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f45\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\f46\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f47\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f409\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f410\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}
+{\f412\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f413\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f416\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\fhimajor\f31528\fbidi \froman\fcharset238\fprq2 Cambria CE;}{\fhimajor\f31529\fbidi \froman\fcharset204\fprq2 Cambria Cyr;}{\fhimajor\f31531\fbidi \froman\fcharset161\fprq2 Cambria Greek;}{\fhimajor\f31532\fbidi \froman\fcharset162\fprq2 Cambria Tur;}
+{\fhimajor\f31535\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
+{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
+{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}
+{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
+{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
+{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}
+{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}
+{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
+{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;
+\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;
+\red192\green192\blue192;}{\*\defchp \fs22\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{
+\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033
+\snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
+\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa200\sl276\slmult1
+\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033
+\snext11 \ssemihidden \sunhideused \sqformat Normal Table;}}{\*\rsidtbl \rsid15009392}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\operator HPinvent}
+{\creatim\yr2010\mo1\dy18\hr14\min23}{\revtim\yr2010\mo1\dy18\hr14\min23}{\version2}{\edmins0}{\nofpages1}{\nofwords1}{\nofchars8}{\nofcharsws8}{\vern32771}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}}
+\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect
+\widowctrl\ftnbj\aenddoc\trackmoves1\trackformatting1\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120\dghorigin1701
+\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale100\rsidroot15009392 \fet0{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2
+\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6
+\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang
+{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid15009392 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0
+\fs22\lang1033\langfe1033\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af31507\afs20 \ltrch\fcs0 \insrsid15009392 \hich\af31506\dbch\af31505\loch\f31506 Doc2.rtf}{\rtlch\fcs1 \af31507\afs20 \ltrch\fcs0
+\insrsid15009392\charrsid15009392
+\par }{\*\themedata 504b030414000600080000002100828abc13fa0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb6ac3301045f785fe83d0b6d8
+72ba28a5d8cea249777d2cd20f18e4b12d6a8f843409c9df77ecb850ba082d74231062ce997b55ae8fe3a00e1893f354e9555e6885647de3a8abf4fbee29bbd7
+2a3150038327acf409935ed7d757e5ee14302999a654e99e393c18936c8f23a4dc072479697d1c81e51a3b13c07e4087e6b628ee8cf5c4489cf1c4d075f92a0b
+44d7a07a83c82f308ac7b0a0f0fbf90c2480980b58abc733615aa2d210c2e02cb04430076a7ee833dfb6ce62e3ed7e14693e8317d8cd0433bf5c60f53fea2fe7
+065bd80facb647e9e25c7fc421fd2ddb526b2e9373fed4bb902e182e97b7b461e6bfad3f010000ffff0300504b030414000600080000002100a5d6a7e7c00000
+00360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4fc7060abb08
+84a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b63095120f88d94fbc
+52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462a1a82fe353
+bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f7468656d652f7468
+656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b4b0d592c9c
+070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b4757e8d3f7
+29e245eb2b260a0238fd010000ffff0300504b03041400060008000000210096b5ade296060000501b0000160000007468656d652f7468656d652f7468656d65
+312e786d6cec594f6fdb3614bf0fd87720746f6327761a07758ad8b19b2d4d1bc46e871e698996d850a240d2497d1bdae38001c3ba618715d86d87615b8116d8
+a5fb34d93a6c1dd0afb0475292c5585e9236d88aad3e2412f9e3fbff1e1fa9abd7eec70c1d1221294fda5efd72cd4324f1794093b0eddd1ef62fad79482a9c04
+98f184b4bd2991deb58df7dfbb8ad755446282607d22d771db8b944ad79796a40fc3585ee62949606ecc458c15bc8a702910f808e8c66c69b9565b5d8a314d3c
+94e018c8de1a8fa94fd05093f43672e23d06af89927ac06762a049136785c10607758d9053d965021d62d6f6804fc08f86e4bef210c352c144dbab999fb7b471
+7509af678b985ab0b6b4ae6f7ed9ba6c4170b06c788a705430adf71bad2b5b057d03606a1ed7ebf5babd7a41cf00b0ef83a6569632cd467faddec9699640f671
+9e76b7d6ac355c7c89feca9cccad4ea7d36c65b258a206641f1b73f8b5da6a6373d9c11b90c537e7f08dce66b7bbeae00dc8e257e7f0fd2badd5868b37a088d1
+e4600ead1ddaef67d40bc898b3ed4af81ac0d76a197c86826828a24bb318f3442d8ab518dfe3a20f000d6458d104a9694ac6d88728eee2782428d60cf03ac1a5
+193be4cbb921cd0b495fd054b5bd0f530c1931a3f7eaf9f7af9e3f45c70f9e1d3ff8e9f8e1c3e3073f5a42ceaa6d9c84e5552fbffdeccfc71fa33f9e7ef3f2d1
+17d57859c6fffac327bffcfc793510d26726ce8b2f9ffcf6ecc98baf3efdfdbb4715f04d814765f890c644a29be408edf3181433567125272371be15c308d3f2
+8acd249438c19a4b05fd9e8a1cf4cd296699771c393ac4b5e01d01e5a30a787d72cf1178108989a2159c77a2d801ee72ce3a5c545a6147f32a99793849c26ae6
+6252c6ed637c58c5bb8b13c7bfbd490a75330f4b47f16e441c31f7184e140e494214d273fc80900aedee52ead87597fa824b3e56e82e451d4c2b4d32a423279a
+668bb6690c7e9956e90cfe766cb37b077538abd27a8b1cba48c80acc2a841f12e698f13a9e281c57911ce298950d7e03aba84ac8c154f8655c4f2af074481847
+bd804859b5e696007d4b4edfc150b12addbecba6b18b148a1e54d1bc81392f23b7f84137c2715a851dd0242a633f900710a218ed715505dfe56e86e877f0034e
+16bafb0e258ebb4faf06b769e888340b103d3311da9750aa9d0a1cd3e4efca31a3508f6d0c5c5c398602f8e2ebc71591f5b616e24dd893aa3261fb44f95d843b
+5974bb5c04f4edafb95b7892ec1108f3f98de75dc97d5772bdff7cc95d94cf672db4b3da0a6557f70db629362d72bcb0431e53c6066acac80d699a6409fb44d0
+8741bdce9c0e4971624a2378cceaba830b05366b90e0ea23aaa241845368b0eb9e2612ca8c742851ca251ceccc70256d8d87265dd96361531f186c3d9058edf2
+c00eafe8e1fc5c509031bb4d680e9f39a3154de0accc56ae644441edd76156d7429d995bdd88664a9dc3ad50197c38af1a0c16d684060441db02565e85f3b966
+0d0713cc48a0ed6ef7dedc2dc60b17e92219e180643ed27acffba86e9c94c78ab90980d8a9f0913ee49d62b512b79626fb06dccee2a432bbc60276b9f7dec44b
+7904cfbca4f3f6443ab2a49c9c2c41476dafd55c6e7ac8c769db1bc399161ee314bc2e75cf8759081743be1236ec4f4d6693e5336fb672c5dc24a8c33585b5fb
+9cc24e1d4885545b58463634cc5416022cd19cacfccb4d30eb45296023fd35a458598360f8d7a4003bbaae25e331f155d9d9a5116d3bfb9a95523e51440ca2e0
+088dd844ec6370bf0e55d027a012ae264c45d02f708fa6ad6da6dce29c255df9f6cae0ec38666984b372ab5334cf640b37795cc860de4ae2816e95b21be5ceaf
+8a49f90b52a51cc6ff3355f47e0237052b81f6800fd7b802239daf6d8f0b1571a8426944fdbe80c6c1d40e8816b88b8569082ab84c36ff0539d4ff6dce591a26
+ade1c0a7f669880485fd484582903d284b26fa4e2156cff62e4b9265844c4495c495a9157b440e091bea1ab8aaf7760f4510eaa69a6465c0e04ec69ffb9e65d0
+28d44d4e39df9c1a52ecbd3607fee9cec7263328e5d661d3d0e4f62f44acd855ed7ab33cdf7bcb8ae889599bd5c8b3029895b6825696f6af29c239b75a5bb1e6
+345e6ee6c28117e73586c1a2214ae1be07e93fb0ff51e133fb65426fa843be0fb515c187064d0cc206a2fa926d3c902e907670048d931db4c1a44959d366ad93
+b65abe595f70a75bf03d616c2dd959fc7d4e6317cd99cbcec9c58b34766661c7d6766ca1a9c1b327531486c6f941c638c67cd22a7f75e2a37be0e82db8df9f30
+254d30c1372581a1f51c983c80e4b71ccdd28dbf000000ffff0300504b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f74
+68656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f24
+51eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198
+720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528
+a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100828abc13fa0000001c0200001300000000000000000000000000
+000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b000000000000000000000000
+002b0100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000000000140200007468
+656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d001400060008000000210096b5ade296060000501b000016000000000000000000
+00000000d10200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b010000270000000000
+00000000000000009b0900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000960a00000000}
+{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d
+617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
+6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
+656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
+{\*\latentstyles\lsdstimax267\lsdlockeddef0\lsdsemihiddendef1\lsdunhideuseddef1\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
+\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;
+\lsdpriority39 \lsdlocked0 toc 1;\lsdpriority39 \lsdlocked0 toc 2;\lsdpriority39 \lsdlocked0 toc 3;\lsdpriority39 \lsdlocked0 toc 4;\lsdpriority39 \lsdlocked0 toc 5;\lsdpriority39 \lsdlocked0 toc 6;\lsdpriority39 \lsdlocked0 toc 7;
+\lsdpriority39 \lsdlocked0 toc 8;\lsdpriority39 \lsdlocked0 toc 9;\lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdpriority1 \lsdlocked0 Default Paragraph Font;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority59 \lsdlocked0 Table Grid;\lsdunhideused0 \lsdlocked0 Placeholder Text;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdunhideused0 \lsdlocked0 Revision;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 2;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 5;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;
+\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdpriority37 \lsdlocked0 Bibliography;\lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;}}{\*\datastore 010500000200000018000000
+4d73786d6c322e534158584d4c5265616465722e352e3000000000000000000000060000
+d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffffec69d9888b8b3d4c859eaf6cd158be0f000000000000000000000000f00c
+7fba7398ca01feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000
+00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000
+000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000105000000000000}}
\ No newline at end of file
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Document1.docx b/DataAccessLayer/TestData/Files/DupFiles3/Document1.docx
new file mode 100644
index 0000000..94dcb41
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Document1.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Document2.doc b/DataAccessLayer/TestData/Files/DupFiles3/Document2.doc
new file mode 100644
index 0000000..97b5bf0
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Document2.doc differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Document3.docx b/DataAccessLayer/TestData/Files/DupFiles3/Document3.docx
new file mode 100644
index 0000000..07313b9
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Document3.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Document4.doc b/DataAccessLayer/TestData/Files/DupFiles3/Document4.doc
new file mode 100644
index 0000000..b58cabf
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Document4.doc differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Document5.docx b/DataAccessLayer/TestData/Files/DupFiles3/Document5.docx
new file mode 100644
index 0000000..b8c0b62
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Document5.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Document6.docx b/DataAccessLayer/TestData/Files/DupFiles3/Document6.docx
new file mode 100644
index 0000000..75e8bad
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Document6.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Document7.docx b/DataAccessLayer/TestData/Files/DupFiles3/Document7.docx
new file mode 100644
index 0000000..4f8c401
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Document7.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Doris likes apples.doc b/DataAccessLayer/TestData/Files/DupFiles3/Doris likes apples.doc
new file mode 100644
index 0000000..ececba8
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Doris likes apples.doc differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Doris.xlsx b/DataAccessLayer/TestData/Files/DupFiles3/Doris.xlsx
new file mode 100644
index 0000000..0672cc5
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Doris.xlsx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Drawing1.vsd b/DataAccessLayer/TestData/Files/DupFiles3/Drawing1.vsd
new file mode 100644
index 0000000..f1a9e28
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Drawing1.vsd differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Drawing2.vsd b/DataAccessLayer/TestData/Files/DupFiles3/Drawing2.vsd
new file mode 100644
index 0000000..f1a9e28
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Drawing2.vsd differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Map1.mmap b/DataAccessLayer/TestData/Files/DupFiles3/Map1.mmap
new file mode 100644
index 0000000..14fb76e
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Map1.mmap differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Map2.mmap b/DataAccessLayer/TestData/Files/DupFiles3/Map2.mmap
new file mode 100644
index 0000000..14fb76e
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Map2.mmap differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/MoreDefects.TXT b/DataAccessLayer/TestData/Files/DupFiles3/MoreDefects.TXT
new file mode 100644
index 0000000..b9bbe1c
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles3/MoreDefects.TXT
@@ -0,0 +1,5 @@
+
+
+
+[ButtonHook]
+- When W32Window get's a message and ::IsWindow(::GetParent(hWnd)) is false Close down everything!!!
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/New Mindmap1.mm b/DataAccessLayer/TestData/Files/DupFiles3/New Mindmap1.mm
new file mode 100644
index 0000000..e88a40f
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles3/New Mindmap1.mm
@@ -0,0 +1,4 @@
+
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/New Mindmap2.mm b/DataAccessLayer/TestData/Files/DupFiles3/New Mindmap2.mm
new file mode 100644
index 0000000..e88a40f
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles3/New Mindmap2.mm
@@ -0,0 +1,4 @@
+
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/OogyKeepInMind.txt b/DataAccessLayer/TestData/Files/DupFiles3/OogyKeepInMind.txt
new file mode 100644
index 0000000..1e3616f
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles3/OogyKeepInMind.txt
@@ -0,0 +1,27 @@
+[ShellExecuteLauncher.cs]
+-------------------------
+Right now ShellExecuteLauncher iterates thru all top level windows
+until it finds the name of the file in the title bar.
+
+comments:
+-to avoid collisions with duplicate file names (hold a map of
+ previous window handles), so if the file name is in the title and
+ it is not already mapped it's the new window.
+
+-maybe invoke bh or resolvers to do the work and skip title search
+ all together.
+
+Workspace launching (more testing to do with new resolver events)
+~but one possibility could be:
+-------------------------
+launcher calls BH -> AboutToLaunchWorkspace(), button hook disables
+all newly created buttons and listens for WM_CREATE and parentNotify_WM_CREATES...
+... in order... that is our in order handle table.
+
+launcher calls BH -> LaunchDone(artifacts), we use the artifacts in order
+in our table and launcher gets the list of handles.
+
+~this would work if launcher accurately launches in order and all windows
+are created in order. ~launcher should wait till resolve event occurs?
+~before launching next???
+--------------------------------------------
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Presentation1.ppt b/DataAccessLayer/TestData/Files/DupFiles3/Presentation1.ppt
new file mode 100644
index 0000000..61d4880
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Presentation1.ppt differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Presentation2.ppt b/DataAccessLayer/TestData/Files/DupFiles3/Presentation2.ppt
new file mode 100644
index 0000000..ce7f006
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Presentation2.ppt differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Publication1.pub b/DataAccessLayer/TestData/Files/DupFiles3/Publication1.pub
new file mode 100644
index 0000000..215aa5b
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Publication1.pub differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/Publication2.pub b/DataAccessLayer/TestData/Files/DupFiles3/Publication2.pub
new file mode 100644
index 0000000..a0dda95
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/Publication2.pub differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/doris.docx b/DataAccessLayer/TestData/Files/DupFiles3/doris.docx
new file mode 100644
index 0000000..26d3bd5
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/doris.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/doris2.docx b/DataAccessLayer/TestData/Files/DupFiles3/doris2.docx
new file mode 100644
index 0000000..124e9b5
Binary files /dev/null and b/DataAccessLayer/TestData/Files/DupFiles3/doris2.docx differ
diff --git a/DataAccessLayer/TestData/Files/DupFiles3/textfile1.txt b/DataAccessLayer/TestData/Files/DupFiles3/textfile1.txt
new file mode 100644
index 0000000..de850da
--- /dev/null
+++ b/DataAccessLayer/TestData/Files/DupFiles3/textfile1.txt
@@ -0,0 +1,11 @@
+WM_ENTERIDLE fuSource:MSGF_DIALOGBOX hwnd:001b11dc
+WN_SETTEXT lpsz:000BEF18("SHELLY TO DO.txt - Notepad")
+
+[Open dialog sends the following things]
+WM_COMMAND wNotifyCode:BN_CLICKED wID:IDOK hwndCtrl:004F092E
+WM_NOTIFY idCtrl:1148 pnmh:000BEB30
+WM_NOTIFY idCtrl:1148 pnmh:000BEB6C
+
+[Tada!]
+Use ::GetOpenFileName or ::GetSaveFileName passing pointer to a OPENFILENAME structure.
+
diff --git a/DataAccessLayer/TestData/Files/Snapshots/c9f487bd-7cef-4f45-8238-08a4be0a3ba3.png b/DataAccessLayer/TestData/Files/Snapshots/c9f487bd-7cef-4f45-8238-08a4be0a3ba3.png
new file mode 100644
index 0000000..a8c917e
Binary files /dev/null and b/DataAccessLayer/TestData/Files/Snapshots/c9f487bd-7cef-4f45-8238-08a4be0a3ba3.png differ
diff --git a/DataAccessLayer/TestData/TestData.cs b/DataAccessLayer/TestData/TestData.cs
new file mode 100644
index 0000000..ae7ea99
--- /dev/null
+++ b/DataAccessLayer/TestData/TestData.cs
@@ -0,0 +1,348 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Reflection;
+using Foo.DataAccessLayer;
+using Foo.DataAccessLayer.DataTypes;
+using DataAccessLayer.TestData;
+using System.Threading;
+using System.IO;
+using System.Diagnostics;
+
+namespace DataAccessLayer.TestData
+{
+ public static class TestData
+ {
+ // Project / Directory Constants
+ private const string PROJECT_NAME = "DataAccessLayer";
+ private const string TEST_DATADIR_NAME = "TestData";
+ private const string TEST_DATADIRFILES_NAME = "Files";
+ private const string TEST_DATADIREFILESSNAPSHOT_NAME = "Snapshots";
+ private const string TEST_DATADIRFILESDUPFILESDIR = "DupFiles";
+
+ // Internally calculated locations
+ private static string _TestDataDirFilesLocation = "";
+ private static string _TestDataDirFilesSnapshotLocation = "";
+
+ ///
+ /// Static Constructor is responsible for setting up the locationpaths
+ ///
+ static TestData()
+ {
+ _TestDataDirFilesLocation = GetTestDataFilesDirectoryFromRunningAssembly(Assembly.GetExecutingAssembly().Location);
+ if (!String.IsNullOrEmpty(_TestDataDirFilesLocation))
+ _TestDataDirFilesSnapshotLocation = _TestDataDirFilesLocation + "\\" + TEST_DATADIREFILESSNAPSHOT_NAME;
+
+ // Now Load our File Name Map
+ LoadTestDataFilesIntoOurList();
+ }
+
+ ///
+ /// Private Data struct useful for our TestData Files
+ ///
+ private class TestDataFile
+ {
+ public string Name { get; set; }
+ public string File { get; set; }
+ public string Type { get; set; }
+ public TestDataFile(string Name, string File, string Type)
+ {
+ this.Name = Name;
+ this.File = File;
+ this.Type = Type;
+ }
+ }
+
+ // Holds all our TestData Files
+ private static List _testDataFiles = new List();
+
+ // Get a new Random Number
+ private static int RandomNumber(int min, int max)
+ {
+ Random random = new Random();
+ return random.Next(min, max);
+ }
+
+ ///
+ /// Loads our TestFiles Into our Private Map
+ ///
+ private static void LoadTestDataFilesIntoOurList()
+ {
+ _testDataFiles.Add(new TestDataFile("Albin likes apples", "Albin likes apples.doc", "doc"));
+ _testDataFiles.Add(new TestDataFile("Book1", "Book1.xls", "xls"));
+ _testDataFiles.Add(new TestDataFile("Book1", "Book1.xlsx", "xlsx"));
+ _testDataFiles.Add(new TestDataFile("Book2", "Book2.xls", "xls"));
+ _testDataFiles.Add(new TestDataFile("Book2", "Book2.xlsx", "xlsx"));
+ _testDataFiles.Add(new TestDataFile("Book3", "Book3.xls", "xls"));
+ _testDataFiles.Add(new TestDataFile("Book3", "Book4.xls", "xls"));
+ _testDataFiles.Add(new TestDataFile("DatabaseBills", "DatabaseBills.accdb", "accdb"));
+ _testDataFiles.Add(new TestDataFile("DatabaseReceits", "DatabaseReceits.accdb", "accdb"));
+ _testDataFiles.Add(new TestDataFile("Doc1", "Doc1.rtf", "rtf"));
+ _testDataFiles.Add(new TestDataFile("Doc2", "Doc2.rtf", "rtf"));
+
+ //// Artifacts used in ThreadProc13 *Begin*
+ _testDataFiles.Add(new TestDataFile("Document1", "Document1.docx", "docx"));
+ _testDataFiles.Add(new TestDataFile("Document2", "Document2.doc", "doc"));
+ _testDataFiles.Add(new TestDataFile("Document3", "Document3.docx", "docx"));
+ _testDataFiles.Add(new TestDataFile("Document4", "Document4.doc", "doc"));
+ _testDataFiles.Add(new TestDataFile("Document5", "Document5.docx", "docx"));
+ _testDataFiles.Add(new TestDataFile("Document6", "Document6.docx", "docx"));
+ _testDataFiles.Add(new TestDataFile("Document7", "Document7.docx", "docx"));
+ _testDataFiles.Add(new TestDataFile("Doris liks apples", "Doris likes apples.doc", "doc"));
+ _testDataFiles.Add(new TestDataFile("Doris", "Doris.docx", "docx"));
+ _testDataFiles.Add(new TestDataFile("Doris", "Doris.xlsx", "xlsx"));
+ _testDataFiles.Add(new TestDataFile("Doris2", "Doris2.docx", "docx"));
+ _testDataFiles.Add(new TestDataFile("Drawing1", "Drawing1.vsd", "vsd"));
+ _testDataFiles.Add(new TestDataFile("Drawing2", "Drawing2.vsd", "vsd"));
+ _testDataFiles.Add(new TestDataFile("Map1", "Map1.mmap", "mmap"));
+ _testDataFiles.Add(new TestDataFile("Map2", "Map2.mmap", "mmap"));
+ //// Artifacts used in ThreadProc13 *End*
+
+ _testDataFiles.Add(new TestDataFile("MoreDefects", "MoreDefects.txt", "txt"));
+ _testDataFiles.Add(new TestDataFile("New Mindmap1", "New Mindmap1.mm", "mm"));
+ _testDataFiles.Add(new TestDataFile("New Mindmap2", "New Mindmap2.mm", "mm"));
+ _testDataFiles.Add(new TestDataFile("OogyKeepInMind", "OogyKeepInMind.txt", "txt"));
+ _testDataFiles.Add(new TestDataFile("Presentation1", "Presentation1.ppt", "ppt"));
+ _testDataFiles.Add(new TestDataFile("Presentation2", "Presentation2.ppt", "ppt"));
+ _testDataFiles.Add(new TestDataFile("Publication1", "Publication1.pub", "pub"));
+ _testDataFiles.Add(new TestDataFile("Publication2", "Publication2.pub", "pub"));
+ _testDataFiles.Add(new TestDataFile("textfile1", "textfile1.txt", "txt"));
+
+ // Sort the List by File Type
+ _testDataFiles.Sort(delegate(TestDataFile t1, TestDataFile t2) { return t1.Type.CompareTo(t2.Type); });
+ }
+
+ ///
+ /// Fills Default Database with Test Data
+ ///
+ public static void FillDBWithTestData()
+ {
+ if (!String.IsNullOrEmpty(_TestDataDirFilesLocation) && !String.IsNullOrEmpty(_TestDataDirFilesSnapshotLocation))
+ {
+
+ #region File Type Workspaces
+ ////
+ // First Let's Create a workspace for each file Type
+ ////
+ string FileType = String.Empty;
+ string strWorkspaceName = String.Empty;
+ foreach (TestDataFile dataFile in _testDataFiles)
+ {
+ bool bFileTypeIsSet = false;
+ if (String.IsNullOrEmpty(FileType))
+ {
+ FileType = dataFile.Type;
+ bFileTypeIsSet = true;
+ }
+ else if (FileType != dataFile.Type)
+ {
+ FileType = dataFile.Type;
+ bFileTypeIsSet = true;
+ }
+
+ // Create New FileType Based Workspace
+ if (bFileTypeIsSet)
+ {
+ strWorkspaceName = "FileType Workspace for ." + FileType;
+ Debug.Assert(Data.Workspace.InsertWorkspaceName(strWorkspaceName));
+ }
+
+ // Add the Artifact to the corresponding Workspace
+ Debug.Assert(AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, strWorkspaceName, 1));
+ }
+ #endregion
+
+ #region Simple Word and Excel
+ ////
+ // Let's create a Simple Word and Excel Workspace
+ ////
+ Debug.Assert(Data.Workspace.InsertWorkspaceName("Office Simple doc & xls"));
+ foreach (TestDataFile dataFile in _testDataFiles)
+ {
+ if (dataFile.Type == "doc" ||
+ dataFile.Type == "xls")
+ {
+ // Add the Artifact to the corresponding Workspace
+ Debug.Assert(AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, "Office Simple doc & xls", 1));
+ }
+ }
+ #endregion
+
+ #region Advanced Word and Excel
+ ////
+ // Let's create a Advanced Word and Excel Workspace
+ ////
+ Debug.Assert(Data.Workspace.InsertWorkspaceName("Office Advanced docx & xlsx"));
+ foreach (TestDataFile dataFile in _testDataFiles)
+ {
+ if (dataFile.Type == "docx" ||
+ dataFile.Type == "xlsx")
+ {
+ // Add the Artifact to the corresponding Workspace
+ Debug.Assert(AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, "Office Advanced docx & xlsx", 1));
+ }
+ }
+ #endregion
+
+ #region PowerPoint and Text Files
+ ////
+ // Let's create a Ppt and Txt files workspace for now
+ ////
+ Debug.Assert(Data.Workspace.InsertWorkspaceName("PowerPoint and Text Files"));
+ foreach (TestDataFile dataFile in _testDataFiles)
+ {
+ if (dataFile.Type == "ppt" ||
+ dataFile.Type == "txt")
+ {
+ // Add the Artifact to the corresponding Workspace
+ Debug.Assert(AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, "PowerPoint and Text Files", 1));
+ }
+ }
+ #endregion
+
+ #region ShuffleWorkspace1 - 7 Items
+ Debug.Assert(Data.Workspace.InsertWorkspaceName("ShuffleWorkspace1 - 7 Items"));
+ for (int i = 0; i < 7; ++i)
+ {
+ TestDataFile dataFile = _testDataFiles[RandomNumber(0, _testDataFiles.Count)];
+ AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, "ShuffleWorkspace1 - 7 Items", 1);
+ }
+ #endregion
+
+ #region ShuffleWorkspace2 - 6 Items
+ Debug.Assert(Data.Workspace.InsertWorkspaceName("ShuffleWorkspace2 - 6 Items"));
+ for (int i = 0; i < 6; ++i)
+ {
+ TestDataFile dataFile = _testDataFiles[RandomNumber(0, _testDataFiles.Count)];
+ AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, "ShuffleWorkspace2 - 6 Items", 1);
+ }
+ #endregion
+
+ #region ShuffleWorkspace3 - 5 Items
+ Debug.Assert(Data.Workspace.InsertWorkspaceName("ShuffleWorkspace3 - 5 Items"));
+ for (int i = 0; i < 5; ++i)
+ {
+ TestDataFile dataFile = _testDataFiles[RandomNumber(0, _testDataFiles.Count)];
+ AddTestArtifactToWorkspace(dataFile.Name, dataFile.File, "ShuffleWorkspace3 - 5 Items", 1);
+ }
+ #endregion
+
+ #region DuplicateWorkspace1
+ int nNumberOfArtifacts1 = RandomNumber(3, 10);
+ string strDupWkspace1 = "DuplicateWorkspace1 - " + nNumberOfArtifacts1.ToString() + " Items";
+ Debug.Assert(Data.Workspace.InsertWorkspaceName(strDupWkspace1));
+ for (int i = 0; i < nNumberOfArtifacts1; ++i )
+ {
+ int nDuplicates = RandomNumber(1, 3);
+ int nArtifact = RandomNumber(0, _testDataFiles.Count);
+
+ // Add Duplicates
+ for (int j = 1; j <= nDuplicates; ++j)
+ AddTestArtifactToWorkspace(_testDataFiles[nArtifact].Name, _testDataFiles[nArtifact].File, strDupWkspace1 , j);
+ }
+ #endregion
+
+ #region DuplicateWorkspace2
+ int nNumberOfArtifacts2 = RandomNumber(3, 10);
+ string strDupWkspace2 = "DuplicateWorkspace2 - " + nNumberOfArtifacts2.ToString() + " Items";
+ Debug.Assert(Data.Workspace.InsertWorkspaceName(strDupWkspace2));
+ for (int i = 0; i < nNumberOfArtifacts2; ++i)
+ {
+ int nDuplicates = RandomNumber(1, 3);
+ int nArtifact = RandomNumber(0, _testDataFiles.Count);
+
+ // Add Duplicates
+ for (int j = 1; j <= nDuplicates; ++j)
+ AddTestArtifactToWorkspace(_testDataFiles[nArtifact].Name, _testDataFiles[nArtifact].File, strDupWkspace2, j);
+ }
+ #endregion
+
+ #region DuplicateWorkspace3
+ int nNumberOfArtifacts3 = RandomNumber(3, 10);
+ string strDupWkspace3 = "DuplicateWorkspace3 - " + nNumberOfArtifacts3.ToString() + " Items";
+ Debug.Assert(Data.Workspace.InsertWorkspaceName(strDupWkspace3));
+ for (int i = 0; i < nNumberOfArtifacts3; ++i)
+ {
+ int nDuplicates = RandomNumber(1, 3);
+ int nArtifact = RandomNumber(0, _testDataFiles.Count);
+
+ // Add Duplicates
+ for (int j = 1; j <= nDuplicates; ++j)
+ AddTestArtifactToWorkspace(_testDataFiles[nArtifact].Name, _testDataFiles[nArtifact].File, strDupWkspace3, j);
+ }
+ #endregion
+ }
+ }
+
+ ///
+ /// Quick Helper Function to add Test Artifacts to a Workspace
+ ///
+ /// Name of the artifact you would like to give
+ /// name of the file such as File1.jpg
+ /// name of workspace to add to
+ /// pass in a number from 1 - 3 (i have 3 dup directories)
+ /// true, if successfully added, false otherwise
+ public static bool AddTestArtifactToWorkspace(string ArtifactName, string FileName, string WorkspaceName, int DupFileDirIndex)
+ {
+ if (!String.IsNullOrEmpty(_TestDataDirFilesLocation) && !String.IsNullOrEmpty(_TestDataDirFilesSnapshotLocation))
+ {
+ ArtifactItem artifactItem = new ArtifactItem()
+ {
+ Name = ArtifactName,
+ Location = _TestDataDirFilesLocation + "\\" + TEST_DATADIRFILESDUPFILESDIR + DupFileDirIndex.ToString() + "\\" + FileName,
+ SnapshotFile = _TestDataDirFilesSnapshotLocation + "\\" + "c9f487bd-7cef-4f45-8238-08a4be0a3ba3.png",
+ Note = "",
+ WindowLeft = 100,
+ WindowTop = 100,
+ WindowHeight = 400,
+ WindowWidth = 400,
+ };
+
+ artifactItem.SetAsFileType();
+ return Data.Artifacts.AddArtifactToWorkspace(WorkspaceName, artifactItem);
+ }
+ return false;
+ }
+
+ ///
+ /// Iterate and find the TestData Directory in the executing path
+ ///
+ /// location of currently executing assembly
+ /// valid path string to test data or "" if not found
+ private static string GetTestDataFilesDirectoryFromRunningAssembly(string AssemblyLocation)
+ {
+ DirectoryInfo directory = new DirectoryInfo(Path.GetDirectoryName(AssemblyLocation));
+
+ ////
+ // Iterate the executing Assembly Directory upward to find the testData or Project Directory
+ ////
+ bool bFindTestData = false;
+ while (!bFindTestData && (directory != null) && directory.Exists)
+ {
+
+ // First Check to see if this Directory has the ProjectName as a SubDir
+ DirectoryInfo[] dirProjectNameDirs = directory.GetDirectories(PROJECT_NAME, SearchOption.TopDirectoryOnly);
+
+ if(dirProjectNameDirs.Length == 1)
+ {
+ // Check if there is a TestData Dir Underneath (return if there is)
+ DirectoryInfo[] dirTestDataDirs = dirProjectNameDirs[0].GetDirectories(TEST_DATADIR_NAME, SearchOption.TopDirectoryOnly);
+
+ if(dirTestDataDirs.Length == 1)
+ {
+ // Now Check for the Files Directory
+ DirectoryInfo[] dirTestDataFilesDirs = dirTestDataDirs[0].GetDirectories(TEST_DATADIRFILES_NAME, SearchOption.TopDirectoryOnly);
+
+ if (dirTestDataFilesDirs.Length == 1)
+ return dirTestDataFilesDirs[0].FullName;
+ }
+ }
+
+ // Keep going up the chain
+ directory = directory.Parent;
+ }
+ return String.Empty;
+ }
+ }
+}
diff --git a/DataAccessLayer/Tests/StressTest.cs b/DataAccessLayer/Tests/StressTest.cs
new file mode 100644
index 0000000..f653d05
--- /dev/null
+++ b/DataAccessLayer/Tests/StressTest.cs
@@ -0,0 +1,572 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Foo.DataAccessLayer;
+using Foo.DataAccessLayer.DataTypes;
+using DataAccessLayer.TestData;
+using System.Threading;
+using System.IO;
+
+namespace DataAccessLayer.Tests
+{
+ ///
+ /// Use this class to do a ThreadStressTest on the DB
+ /// Launch this class via CommandLine app and Call RunStressTest()
+ ///
+ internal static class StressTest
+ {
+ const int THREAD_SLEEP_EACH_ITERATION = 5;
+
+ ///
+ /// Thread1 - Test ArtifactGroup Reading
+ ///
+ static private void ThreadProc1()
+ {
+ while (true)
+ {
+ string[] workspacenames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+ if (workspacenames.Length <= 1)
+ {
+ Console.WriteLine("Thread1 - Error : Workspacenames is wrong length");
+ continue;
+ }
+
+ foreach (string workspacename in workspacenames)
+ {
+ ArtifactItem[] artifactItems = Data.Artifacts.GetAllArtifactsForWorkspace(workspacename, SortOrderForArtifacts.Ascending);
+
+ if (DataTypeValidation.IsEmptyArtifactItemGroup(artifactItems))
+ {
+ Console.WriteLine("Thread1 - Error : ArtifactGroup is Empty");
+ }
+ }
+ Thread.Sleep(THREAD_SLEEP_EACH_ITERATION);
+ }
+ }
+
+ ///
+ /// Thread2 - Test ArtifactGroup Reading
+ ///
+ static private void ThreadProc2()
+ {
+ while (true)
+ {
+ string[] workspacenames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+ if (workspacenames.Length <= 1)
+ {
+ Console.WriteLine("Thread2 - Error : Workspacenames is wrong length");
+ continue;
+ }
+
+ foreach (string workspacename in workspacenames)
+ {
+ ArtifactItem[] artifactItems = Data.Artifacts.GetAllArtifactsForWorkspace(workspacename, SortOrderForArtifacts.Ascending);
+
+ if (DataTypeValidation.IsEmptyArtifactItemGroup(artifactItems))
+ {
+ Console.WriteLine("Thread2 - Error : ArtifactGroup is Empty");
+ }
+ }
+ Thread.Sleep(THREAD_SLEEP_EACH_ITERATION);
+ }
+ }
+
+ ///
+ /// Thread3 - Test ArtifactGroup Reading
+ ///
+ static private void ThreadProc3()
+ {
+ while (true)
+ {
+ string[] workspacenames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+ if (workspacenames.Length <= 1)
+ {
+ Console.WriteLine("Thread3 - Error : Workspacenames is wrong length");
+ continue;
+ }
+
+ foreach (string workspacename in workspacenames)
+ {
+ ArtifactItem[] artifactItems = Data.Artifacts.GetAllArtifactsForWorkspace(workspacename, SortOrderForArtifacts.Ascending);
+
+ if (DataTypeValidation.IsEmptyArtifactItemGroup(artifactItems))
+ {
+ Console.WriteLine("Thread3 - Error : ArtifactGroup is Empty");
+ }
+ }
+ Thread.Sleep(THREAD_SLEEP_EACH_ITERATION);
+ }
+ }
+
+ ///
+ /// Thread4 - Test ArtifactGroup Reading
+ ///
+ static private void ThreadProc4()
+ {
+ while (true)
+ {
+ string[] workspacenames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+ if (workspacenames.Length <= 1)
+ {
+ Console.WriteLine("Thread4 - Error : Workspacenames is wrong length");
+ continue;
+ }
+
+ foreach (string workspacename in workspacenames)
+ {
+ ArtifactItem[] artifactItems = Data.Artifacts.GetAllArtifactsForWorkspace(workspacename, SortOrderForArtifacts.Ascending);
+
+ if (DataTypeValidation.IsEmptyArtifactItemGroup(artifactItems))
+ {
+ Console.WriteLine("Thread4 - Error : ArtifactGroup is Empty");
+ }
+ }
+ Thread.Sleep(THREAD_SLEEP_EACH_ITERATION);
+ }
+ }
+
+ ///
+ /// Thread5 - Test ArtifactGroup Reading
+ ///
+ static private void ThreadProc5()
+ {
+ while (true)
+ {
+ string[] workspacenames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+ if (workspacenames.Length <= 1)
+ {
+ Console.WriteLine("Thread5 - Error : Workspacenames is wrong length");
+ continue;
+ }
+
+ foreach (string workspacename in workspacenames)
+ {
+ ArtifactItem[] artifactItems = Data.Artifacts.GetAllArtifactsForWorkspace(workspacename, SortOrderForArtifacts.Ascending);
+
+ if (DataTypeValidation.IsEmptyArtifactItemGroup(artifactItems))
+ {
+ Console.WriteLine("Thread5 - Error : ArtifactGroup is Empty");
+ }
+ }
+ Thread.Sleep(THREAD_SLEEP_EACH_ITERATION);
+ }
+ }
+
+ ///
+ /// Thread3 - Test ArtifactGroup Reading
+ ///
+ static private void ThreadProc6()
+ {
+ while (true)
+ {
+ string[] workspacenames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+ if (workspacenames.Length <= 1)
+ {
+ Console.WriteLine("Thread6 - Error : Workspacenames is wrong length");
+ continue;
+ }
+
+ foreach (string workspacename in workspacenames)
+ {
+ ArtifactItem[] artifactItems = Data.Artifacts.GetAllArtifactsForWorkspace(workspacename, SortOrderForArtifacts.Ascending);
+
+ if (DataTypeValidation.IsEmptyArtifactItemGroup(artifactItems))
+ {
+ Console.WriteLine("Thread6 - Error : ArtifactGroup is Empty");
+ }
+ }
+ Thread.Sleep(THREAD_SLEEP_EACH_ITERATION);
+ }
+ }
+
+ ///
+ /// Thread7 - Test Artifact part of a Workspace
+ ///
+ static private void ThreadProc7()
+ {
+ while (true)
+ {
+ string[] workspacenames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+ if (workspacenames.Length <= 1)
+ {
+ Console.WriteLine("Thread7 - Error : Workspacenames is wrong length");
+ continue;
+ }
+
+ ArtifactItem[] artifactItems = Data.Artifacts.GetAllArtifactsForWorkspace(workspacenames[0], SortOrderForArtifacts.Ascending);
+ if (DataTypeValidation.IsEmptyArtifactItemGroup(artifactItems))
+ {
+ Console.WriteLine("Thread7 - Error : ArtifactGroup is Empty");
+ }
+ else
+ {
+ foreach (ArtifactItem artifactItem in artifactItems)
+ {
+ if (!Data.Artifacts.IsArtifactPartOfWorkspace(workspacenames[0], artifactItem))
+ Console.WriteLine("Thread7 - Error: Artifact / Workspace Validation Error");
+ }
+ }
+
+ Thread.Sleep(THREAD_SLEEP_EACH_ITERATION);
+ }
+ }
+
+ ///
+ /// Thread8 - Test Artifact part of a Workspace
+ ///
+ static private void ThreadProc8()
+ {
+ while (true)
+ {
+ string[] workspacenames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+ if (workspacenames.Length <= 1)
+ {
+ Console.WriteLine("Thread8 - Error : Workspacenames is wrong length");
+ continue;
+ }
+
+ ArtifactItem[] artifactItems = Data.Artifacts.GetAllArtifactsForWorkspace(workspacenames[1], SortOrderForArtifacts.Ascending);
+ if (DataTypeValidation.IsEmptyArtifactItemGroup(artifactItems))
+ {
+ Console.WriteLine("Thread8 - Error : ArtifactGroup is Empty");
+ }
+ else
+ {
+ foreach (ArtifactItem artifactItem in artifactItems)
+ {
+ if (!Data.Artifacts.IsArtifactPartOfWorkspace(workspacenames[1], artifactItem))
+ Console.WriteLine("Thread8 - Error: Artifact / Workspace Validation Error");
+ }
+ }
+
+ Thread.Sleep(THREAD_SLEEP_EACH_ITERATION);
+ }
+ }
+
+ ///
+ /// Thread9 - Test Artifact part of a Workspace
+ ///
+ static private void ThreadProc9()
+ {
+ while (true)
+ {
+ string[] workspacenames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+ if (workspacenames.Length <= 1)
+ {
+ Console.WriteLine("Thread9 - Error : Workspacenames is wrong length");
+ continue;
+ }
+
+ ArtifactItem[] artifactItems = Data.Artifacts.GetAllArtifactsForWorkspace(workspacenames[2], SortOrderForArtifacts.Ascending);
+ if (DataTypeValidation.IsEmptyArtifactItemGroup(artifactItems))
+ {
+ Console.WriteLine("Thread9 - Error : ArtifactGroup is Empty");
+ }
+ else
+ {
+ foreach (ArtifactItem artifactItem in artifactItems)
+ {
+ if (!Data.Artifacts.IsArtifactPartOfWorkspace(workspacenames[2], artifactItem))
+ Console.WriteLine("Thread9 - Error: Artifact / Workspace Validation Error");
+ }
+ }
+
+ Thread.Sleep(THREAD_SLEEP_EACH_ITERATION);
+ }
+ }
+
+ ///
+ /// Thread10 - Test Artifact part of a Workspace
+ ///
+ static private void ThreadProc10()
+ {
+ while (true)
+ {
+ string[] workspacenames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+ if (workspacenames.Length <= 1)
+ {
+ Console.WriteLine("Thread10 - Error : Workspacenames is wrong length");
+ continue;
+ }
+
+ ArtifactItem[] artifactItems = Data.Artifacts.GetAllArtifactsForWorkspace(workspacenames[0], SortOrderForArtifacts.Ascending);
+ if (DataTypeValidation.IsEmptyArtifactItemGroup(artifactItems))
+ {
+ Console.WriteLine("Thread10 - Error : ArtifactGroup is Empty");
+ }
+ else
+ {
+ foreach (ArtifactItem artifactItem in artifactItems)
+ {
+ if (!Data.Artifacts.IsArtifactPartOfWorkspace(workspacenames[0], artifactItem))
+ Console.WriteLine("Thread10 - Error: Artifact / Workspace Validation Error");
+ }
+ }
+
+ Thread.Sleep(THREAD_SLEEP_EACH_ITERATION);
+ }
+ }
+
+ ///
+ /// Thread11 - Test Artifact part of a Workspace
+ ///
+ static private void ThreadProc11()
+ {
+ while (true)
+ {
+ string[] workspacenames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+ if (workspacenames.Length <= 1)
+ {
+ Console.WriteLine("Thread11 - Error : Workspacenames is wrong length");
+ continue;
+ }
+
+ ArtifactItem[] artifactItems = Data.Artifacts.GetAllArtifactsForWorkspace(workspacenames[1], SortOrderForArtifacts.Ascending);
+ if (DataTypeValidation.IsEmptyArtifactItemGroup(artifactItems))
+ {
+ Console.WriteLine("Thread11 - Error : ArtifactGroup is Empty");
+ }
+ else
+ {
+ foreach (ArtifactItem artifactItem in artifactItems)
+ {
+ if (!Data.Artifacts.IsArtifactPartOfWorkspace(workspacenames[1], artifactItem))
+ Console.WriteLine("Thread11 - Error: Artifact / Workspace Validation Error");
+ }
+ }
+
+ Thread.Sleep(THREAD_SLEEP_EACH_ITERATION);
+ }
+ }
+
+ ///
+ /// Thread12 - Test Artifact part of a Workspace
+ ///
+ static private void ThreadProc12()
+ {
+ while (true)
+ {
+ string[] workspacenames = Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending);
+ if (workspacenames.Length <= 1)
+ {
+ Console.WriteLine("Thread12 - Error : Workspacenames is wrong length");
+ continue;
+ }
+
+ ArtifactItem[] artifactItems = Data.Artifacts.GetAllArtifactsForWorkspace(workspacenames[2], SortOrderForArtifacts.Ascending);
+ if (DataTypeValidation.IsEmptyArtifactItemGroup(artifactItems))
+ {
+ Console.WriteLine("Thread12 - Error : ArtifactGroup is Empty");
+ }
+ else
+ {
+ foreach (ArtifactItem artifactItem in artifactItems)
+ {
+ if (!Data.Artifacts.IsArtifactPartOfWorkspace(workspacenames[2], artifactItem))
+ Console.WriteLine("Thread12 - Error: Artifact / Workspace Validation Error");
+ }
+ }
+
+ Thread.Sleep(THREAD_SLEEP_EACH_ITERATION);
+ }
+ }
+
+ ///
+ /// Thread13 - Create a Write Artifact Thread! (Let's see what happens)
+ ///
+ static private void ThreadProc13()
+ {
+ //while (true)
+ //{
+ // bool bSuccess = false;
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Document1", "Document1.docx", "ProjectNotes");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Document2", "Document2.doc", "ProjectNotes");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Document3", "Document3.docx", "Office");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Document4", "Document4.doc", "Presentations");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Document5", "Document5.docx", "Presentations");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Document6", "Document6.docx", "Presentations");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Document7", "Document7.docx", "Office");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Doris", "Doris.xlsx", "ProjectNotes");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Doris2", "Doris2.docx", "ProjectNotes");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Doris liks apples", "Doris likes apples.doc", "Office");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Drawing1", "Drawing1.vsd", "MyMindMaps");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Drawing2", "Drawing2.vsd", "MyMindMaps");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Map1", "Map1.mmap", "MyMindMaps");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+
+ // bSuccess = TestData.TestData.AddTestArtifactToWorkspace("Map2", "Map2.mmap", "MyMindMaps");
+ // if (!bSuccess)
+ // Console.WriteLine("Thread13 - Error: Adding Artifact Failed!");
+
+ // Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+ //}
+ }
+
+ ///
+ /// Thread14 - Create another Write Artifact Thread! (Let's see what happens)
+ ///
+ static private void ThreadProc14()
+ {
+ while (true)
+ {
+ foreach (string workspacename in Data.Workspace.GetAllWorkspaceNames(SortOrderForWorkspaces.Ascending))
+ {
+ ArtifactItem[] artifacts = Data.Artifacts.GetAllArtifactsForWorkspace(workspacename, SortOrderForArtifacts.Ascending);
+
+ if (!DataTypeValidation.IsEmptyArtifactItemGroup(artifacts))
+ {
+ foreach (ArtifactItem artifact in artifacts)
+ {
+ artifact.WindowHeight = 678;
+ if (!Data.Artifacts.ModifyExistingArtifactProperties(artifact, workspacename))
+ {
+ Console.WriteLine("Thread14 - Error: ModifyExistingArtifactProperties Failed");
+ }
+ }
+ }
+ else
+ {
+ Console.WriteLine("Thread14 - Error: artifactsgroup is empty");
+ }
+ }
+
+ Thread.Sleep((20 * THREAD_SLEEP_EACH_ITERATION));
+ }
+ }
+
+ ///
+ /// Entry Point for running all the thread tests
+ ///
+ static public void RunStressTest()
+ {
+ Console.WriteLine("TestDataAccessLayer");
+ Thread thread1 = new Thread(new ThreadStart(StressTest.ThreadProc1));
+ Thread thread2 = new Thread(new ThreadStart(StressTest.ThreadProc2));
+ Thread thread3 = new Thread(new ThreadStart(StressTest.ThreadProc3));
+ Thread thread4 = new Thread(new ThreadStart(StressTest.ThreadProc4));
+ Thread thread5 = new Thread(new ThreadStart(StressTest.ThreadProc5));
+ Thread thread6 = new Thread(new ThreadStart(StressTest.ThreadProc6));
+ Thread thread7 = new Thread(new ThreadStart(StressTest.ThreadProc7));
+ Thread thread8 = new Thread(new ThreadStart(StressTest.ThreadProc8));
+ Thread thread9 = new Thread(new ThreadStart(StressTest.ThreadProc9));
+ Thread thread10 = new Thread(new ThreadStart(StressTest.ThreadProc10));
+ Thread thread11 = new Thread(new ThreadStart(StressTest.ThreadProc11));
+ Thread thread12 = new Thread(new ThreadStart(StressTest.ThreadProc12));
+ Thread thread13 = new Thread(new ThreadStart(StressTest.ThreadProc13));
+ Thread thread14 = new Thread(new ThreadStart(StressTest.ThreadProc14));
+ Console.WriteLine("Threads Created");
+
+ ////
+ // Start All the Threads
+ ////
+ thread1.Start();
+ thread2.Start();
+ thread3.Start();
+ thread4.Start();
+ thread5.Start();
+ thread6.Start();
+ thread7.Start();
+ thread8.Start();
+ thread9.Start();
+ thread10.Start();
+ thread11.Start();
+ thread12.Start();
+ thread13.Start();
+ thread14.Start();
+
+ Console.WriteLine("Threads Started....");
+
+ Console.WriteLine("To Quit Press the 'Q' Key and then Enter");
+ while (true)
+ {
+ string str = Console.ReadLine();
+ if (str == "Q" || str == "q")
+ {
+ break;
+ }
+ System.Threading.Thread.Sleep(100);
+ }
+
+ Console.WriteLine("Stopping Threads....");
+ thread1.Abort();
+ thread2.Abort();
+ thread3.Abort();
+ thread4.Abort();
+ thread5.Abort();
+ thread6.Abort();
+ thread7.Abort();
+ thread8.Abort();
+ thread9.Abort();
+ thread10.Abort();
+ thread11.Abort();
+ thread12.Abort();
+ thread13.Abort();
+ thread14.Abort();
+ }
+ }
+}
diff --git a/DataAccessLayer/app.config b/DataAccessLayer/app.config
new file mode 100644
index 0000000..a515812
--- /dev/null
+++ b/DataAccessLayer/app.config
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DataAccessLayer/dArtifacts.cs b/DataAccessLayer/dArtifacts.cs
new file mode 100644
index 0000000..3c5f27d
--- /dev/null
+++ b/DataAccessLayer/dArtifacts.cs
@@ -0,0 +1,874 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Data;
+using System.Data.SqlServerCe;
+using System.IO;
+using Foo.DataAccessLayer.DataTypes;
+
+namespace Foo.DataAccessLayer
+{
+ public class dArtifacts
+ {
+ ///
+ /// Checks to see if this artifact is already in the system. The Location is the UniqueID
+ /// so no other artifact may exist that has the exact same location
+ ///
+ /// Artifact To Check (Location Needed Only)
+ /// true if found, false otherwise
+ public bool DoesArtifactExistInSystem(ArtifactItem artifactItem)
+ {
+ // Check Artifact Integrity
+ if ((artifactItem == null) ||
+ !artifactItem.IsLocationValid)
+ return false;
+
+ object obj = null;
+ lock (this)
+ {
+ string sql = "SELECT [UID] FROM Artifacts WHERE [Location] = @location";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
+ obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+ }
+ return (obj != null);
+ }
+
+ ///
+ /// Searches all Artifact's Names & Notes for the specified SearchQuery using SQL's Like stmt
+ ///
+ /// string to use in 'Like' (Must be less than 75 Characters)
+ /// Specify Sort Order
+ /// returns ArtifactItem[] of all found artifacts
+ public ArtifactItem[] SearchArtifactsInTheSystem(string SearchQuery, SortOrderForArtifacts SortOrder)
+ {
+ if (!String.IsNullOrEmpty(SearchQuery) && (SearchQuery.Length <= 75))
+ {
+ lock (this)
+ {
+ DataSet dataset = SearchArtifactsInTheSystemIntoDataSet(SearchQuery, SortOrder);
+ if (!DataTypeValidation.IsEmptyDataSet(dataset))
+ {
+ int nRows = dataset.Tables[0].Rows.Count;
+ ArtifactItem[] resultArtifacts = new ArtifactItem[nRows];
+
+ for (int i = 0; i < nRows; ++i)
+ {
+ DataRow datarow = dataset.Tables[0].Rows[i];
+ resultArtifacts[i] = new ArtifactItem();
+
+ // Add Artifact Fields
+ resultArtifacts[i].Name = datarow["Name"].ToString();
+ resultArtifacts[i].SetType(datarow["Type"].ToString());
+ resultArtifacts[i].Location = datarow["Location"].ToString();
+ resultArtifacts[i].Note = datarow["Note"].ToString();
+ resultArtifacts[i].SnapshotFile = datarow["SnapShotFile"].ToString();
+
+ if (!String.IsNullOrEmpty(datarow["LastAccessed"].ToString()))
+ resultArtifacts[i].SetLastAccessed(DateTime.Parse(datarow["LastAccessed"].ToString()));
+
+ if (!String.IsNullOrEmpty(datarow["AccessCounter"].ToString()))
+ resultArtifacts[i].AccessCounter = int.Parse(datarow["AccessCounter"].ToString());
+ }
+ return resultArtifacts;
+ }
+ }
+ }
+
+ // return Blank Item
+ return DataTypeHelpers.EmptyArtifactItemGroup();
+ }
+
+ ///
+ /// Searches all Artifact's Names & Notes for the specified SearchQuery using SQL's Like stmt
+ ///
+ /// string to use in 'Like' (Must be less than 75 Characters)
+ /// Specify Sort Order
+ /// returns DataSet of all found artifacts
+ public DataSet SearchArtifactsInTheSystemIntoDataSet(string SearchQuery, SortOrderForArtifacts SortOrder)
+ {
+ if (!String.IsNullOrEmpty(SearchQuery) && (SearchQuery.Length <= 75))
+ {
+ lock (this)
+ {
+ string sql = "SELECT [Name],[Type],[Location],[Note],[SnapShotFile],[LastAccessed],[AccessCounter] FROM Artifacts";
+ sql = sql + String.Format(" WHERE [Name] LIKE '%{0}%' OR [Note] LIKE '%{0}%' OR [Location] LIKE '%{0}%'", SearchQuery);
+ sql = SortOrderSQLHelpers.SortOrderForArtifactsHelper(sql, SortOrder);
+ DataSet dataset = DB.RunSQLTextFillDataSet(sql);
+ return dataset;
+ }
+ }
+ return new DataSet(); // empty dataset
+ }
+
+ ///
+ /// Returns an ArtifactItem[] of all Artifacts in the System (WorkspaceLinkProperties won't be filled in)
+ ///
+ /// Specify Sort Order
+ /// returns ArtifactItem[] of all artifacts
+ public ArtifactItem[] GetAllArtifactsInTheSystem(SortOrderForArtifacts SortOrder)
+ {
+ lock (this)
+ {
+ DataSet dataset = GetAllArtifactsInTheSystemIntoDataSet(SortOrder);
+ if (!DataTypeValidation.IsEmptyDataSet(dataset))
+ {
+ int nRows = dataset.Tables[0].Rows.Count;
+ ArtifactItem[] resultArtifacts = new ArtifactItem[nRows];
+
+ for (int i = 0; i < nRows; ++i)
+ {
+ DataRow datarow = dataset.Tables[0].Rows[i];
+ resultArtifacts[i] = new ArtifactItem();
+
+ // Add Artifact Fields
+ resultArtifacts[i].Name = datarow["Name"].ToString();
+ resultArtifacts[i].Type = (ArtifactTypes) Enum.Parse(typeof(ArtifactTypes), datarow["Type"].ToString(), true);
+ resultArtifacts[i].Location = datarow["Location"].ToString();
+ resultArtifacts[i].Note = datarow["Note"].ToString();
+ resultArtifacts[i].SnapshotFile = datarow["SnapShotFile"].ToString();
+
+ if (!String.IsNullOrEmpty(datarow["LastAccessed"].ToString()))
+ resultArtifacts[i].SetLastAccessed(DateTime.Parse(datarow["LastAccessed"].ToString()));
+
+ if (!String.IsNullOrEmpty(datarow["AccessCounter"].ToString()))
+ resultArtifacts[i].AccessCounter = int.Parse(datarow["AccessCounter"].ToString());
+ }
+ return resultArtifacts;
+ }
+ }
+
+ // return Blank Item
+ return DataTypeHelpers.EmptyArtifactItemGroup();
+ }
+
+ ///
+ /// Returns a DataSet of All Artifacts in the System (WorkspaceLinkProperties won't be filled in)
+ ///
+ /// Specify Sort Order
+ /// returns DataSet of all artifacts
+ public DataSet GetAllArtifactsInTheSystemIntoDataSet(SortOrderForArtifacts SortOrder)
+ {
+ lock (this)
+ {
+ string sql = "SELECT [Name],[Type],[Location],[Note],[SnapShotFile],[LastAccessed],[AccessCounter] FROM Artifacts";
+ sql = SortOrderSQLHelpers.SortOrderForArtifactsHelper(sql, SortOrder);
+ DataSet dataset = DB.RunSQLTextFillDataSet(sql);
+ return dataset;
+ }
+ }
+
+ ///
+ /// Increments the access counter and sets LastAccessed for the
+ /// specified artifact. Call this whenever you have launched an Artifact.
+ ///
+ /// Artifact To Check (Location Needed Only)
+ /// true if successful set the internal counters, false otherwise
+ public bool ArtifactWasLaunched(ArtifactItem artifactItem)
+ {
+ // Check Artifact Validity
+ if ((artifactItem == null) ||
+ !artifactItem.IsLocationValid)
+ return false;
+
+ lock (this)
+ {
+ // existence check
+ if (!DoesArtifactExistInSystem(artifactItem))
+ return false;
+
+ // First Step - is to get the AccessCounter already in the db
+ string sql = "SELECT [AccessCounter] FROM Artifacts WHERE [Location]=@location";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
+
+ int accesscount = 1;
+ object obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+ if (obj != null)
+ {
+ accesscount = int.Parse(obj.ToString());
+ accesscount = accesscount + 1; // increment by 1
+ }
+
+ // Second Step - is to set the access counter and today's date for the artifact
+ string sql2 = "UPDATE Artifacts SET [LastAccessed]=@lastaccessed,[AccessCounter]=@accesscounter WHERE [Location]=@location";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@lastaccessed", DateTime.Now),
+ new SqlCeParameter("@accesscounter", accesscount),
+ new SqlCeParameter("@location", artifactItem.Location),
+ };
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
+ return (nResult == 1);
+ }
+ }
+
+ ///
+ /// Check to see if the artifact is part of the workspace
+ ///
+ /// WorskpaceName to check the Artifact against
+ /// Artifact To Check (Location Needed Only)
+ /// true, if part of the specified workspace, false otherwise
+ public bool IsArtifactPartOfWorkspace(string WorkspaceName, ArtifactItem artifactItem)
+ {
+ // Check Artifact & Workspace Validity
+ if ((artifactItem == null) ||
+ !artifactItem.IsLocationValid ||
+ !DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
+ return false;
+
+ object obj = null;
+ lock (this)
+ {
+ // Check to make sure that this is a valid WorkspaceName
+ if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
+ return false;
+
+ // First Step - Get the UID of the Artifact to look up in the Links table
+ string sql = "SELECT [UID] FROM Artifacts WHERE [Location] = @location";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
+ obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+
+ if (obj != null)
+ {
+ int uid = int.Parse(obj.ToString());
+
+ // Second Step - Lookup if there is any item in the Links table that matches the uid and workspace name
+ string sql2 = "SELECT [UID] FROM WorkspaceLinks WHERE [AID] = @aid AND [WorkspaceName] = @workspacename";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@aid", uid),
+ new SqlCeParameter("@workspacename", WorkspaceName),
+ };
+
+ obj = DB.RunSQLCommandTextExecuteScalar(sql2, sqlparams2);
+ return (obj != null);
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Uses The workspace stored in the State Table and determines if the Artifact is part of that Workspace
+ ///
+ /// Artifact To Check (Location Needed Only)
+ /// true, if part of the current workspace in the state table, false otherwise
+ public bool IsArtifactPartOfCurrentWorkspaceState(ArtifactItem artifactItem)
+ {
+ // Check validity of the Artifact
+ if ((artifactItem == null) ||
+ !artifactItem.IsLocationValid)
+ return false;
+
+ lock(this)
+ {
+ string CurrentWorkspace = Data.State.GetCurrentWorkspaceName();
+ if (!String.IsNullOrEmpty(CurrentWorkspace))
+ {
+ return IsArtifactPartOfWorkspace(CurrentWorkspace, artifactItem);
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Use this when you have an Artifact that doesn't have any WorkspaceLink Properties and you
+ /// want to fill the Artifact's WorkspaceLink properties with the first artifact that matches the
+ /// specified workspace sort order
+ ///
+ /// artifactItem without WorkspaceLink Properties (Location Needed Only)
+ /// SortOrder of workspace to use when filling the first found artifact that matches
+ /// an artifact item with workspaceLink properties filled out if successfull
+ public ArtifactItem GetWorkspaceLinkPropertiesForArtifact(ArtifactItem artifactItem, SortOrderForWorkspaces sortOrder)
+ {
+ // ensure artifact integrity
+ if ((artifactItem == null) ||
+ !(artifactItem.IsLocationValid))
+ return artifactItem; // nothing filled out
+
+ lock (this)
+ {
+ // First Step - Get the UID of the artifact
+ string sql = "SELECT [UID] FROM Artifacts WHERE [Location] = @location";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
+ object obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+
+ if (obj != null)
+ {
+ int aid = int.Parse(obj.ToString());
+
+ // Second Step - is to get the WorkspaceLink that matches the artifact by the sort order
+ string sql2 = "SELECT [WorkspaceLinks].[WindowTop], [WorkspaceLinks].[WindowLeft],[WorkspaceLinks].[WindowHeight], [WorkspaceLinks].[WindowWidth]";
+ sql2 = sql2 + " FROM [WorkspaceLinks] , [Workspaces] WHERE [WorkspaceLinks].[WorkspaceName] = [Workspaces].[Name] AND [WorkspaceLinks].[AID]=@aid";
+
+ // Add WorkspacesSortOrder
+ sql2 = SortOrderSQLHelpers.SortOrderForWorkspacesHelper(sql2, sortOrder);
+
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[] { new SqlCeParameter("@aid", aid) };
+
+ DataSet dataset = DB.RunSQLTextFillDataSet(sql2, sqlparams2);
+ if (!DataTypeValidation.IsEmptyDataSet(dataset))
+ {
+ // Just get the first item
+ DataRow datarow = dataset.Tables[0].Rows[0];
+
+ // Clone the original artifact
+ ArtifactItem resultArtifact = (ArtifactItem) artifactItem.Clone();
+
+ // Add Artifact Fields
+ resultArtifact.WindowTop = int.Parse(datarow["WindowTop"].ToString());
+ resultArtifact.WindowLeft = int.Parse(datarow["WindowLeft"].ToString());
+ resultArtifact.WindowHeight = int.Parse(datarow["WindowHeight"].ToString());
+ resultArtifact.WindowWidth = int.Parse(datarow["WindowWidth"].ToString());
+ return resultArtifact;
+ }
+ }
+ }
+
+ // nothing filled out
+ return artifactItem;
+ }
+
+ ///
+ /// Retrieve all Artifacts associated with the specified Workspace (uses links table to determine which artifacts)
+ ///
+ /// The WorkspaceName for which to get all Artifacts
+ /// Specify Sort Order
+ /// Group of Artifact Items, Could be Empty, use DataTypeValidator to check for Empty ArtifactGroup
+ public ArtifactItem[] GetAllArtifactsForWorkspace(string WorkspaceName, SortOrderForArtifacts SortBy)
+ {
+ // Ensure Workspace Name Integrity
+ if (!DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
+ return DataTypeHelpers.EmptyArtifactItemGroup(); // return Blank Item
+
+ lock (this)
+ {
+ // Check to make sure that this is a valid WorkspaceName (in DB)
+ if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
+ return DataTypeHelpers.EmptyArtifactItemGroup(); // return Blank Item
+
+ // First Step - Use a Join to get all the matching artifacts
+ string sql = "SELECT [Artifacts].[Name], [Artifacts].[Type], [Artifacts].[Location], [Artifacts].[Note], [Artifacts].[SnapShotFile], [Artifacts].[LastAccessed], [Artifacts].[AccessCounter], [WorkspaceLinks].[WindowTop], ";
+ sql = sql + "[WorkspaceLinks].[WindowLeft], [WorkspaceLinks].[WindowHeight], [WorkspaceLinks].[WindowWidth], [WorkspaceLinks].[WorkspaceName] ";
+ sql = sql + "FROM [WorkspaceLinks] , [Artifacts] ";
+ sql = sql + "WHERE [WorkspaceLinks].[AID] = [Artifacts].[UID] AND [WorkspaceLinks].[WorkspaceName] = @workspacename ";
+
+ // Add ArtifactsSortOrder
+ sql = SortOrderSQLHelpers.SortOrderForArtifactsHelper(sql, SortBy);
+
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@workspacename", WorkspaceName) };
+
+ DataSet dataset = DB.RunSQLTextFillDataSet(sql, sqlparams);
+ if (!DataTypeValidation.IsEmptyDataSet(dataset))
+ {
+ int nRows = dataset.Tables[0].Rows.Count;
+ ArtifactItem[] resultArtifacts = new ArtifactItem[nRows];
+
+ for (int i = 0; i < nRows; ++i)
+ {
+ DataRow datarow = dataset.Tables[0].Rows[i];
+ resultArtifacts[i] = new ArtifactItem();
+
+ // Add Artifact Fields
+ resultArtifacts[i].Name = datarow["Name"].ToString();
+ resultArtifacts[i].Type = (ArtifactTypes)Enum.Parse(typeof(ArtifactTypes), datarow["Type"].ToString(), true);
+ resultArtifacts[i].Location = datarow["Location"].ToString();
+ resultArtifacts[i].Note = datarow["Note"].ToString();
+ resultArtifacts[i].SnapshotFile = datarow["SnapShotFile"].ToString();
+
+ if(!String.IsNullOrEmpty(datarow["LastAccessed"].ToString()))
+ resultArtifacts[i].SetLastAccessed(DateTime.Parse(datarow["LastAccessed"].ToString()));
+
+ if (!String.IsNullOrEmpty(datarow["AccessCounter"].ToString()))
+ resultArtifacts[i].AccessCounter = int.Parse(datarow["AccessCounter"].ToString());
+
+ resultArtifacts[i].WindowTop = int.Parse(datarow["WindowTop"].ToString());
+ resultArtifacts[i].WindowLeft = int.Parse(datarow["WindowLeft"].ToString());
+ resultArtifacts[i].WindowHeight = int.Parse(datarow["WindowHeight"].ToString());
+ resultArtifacts[i].WindowWidth = int.Parse(datarow["WindowWidth"].ToString());
+ }
+ return resultArtifacts;
+ }
+
+ }
+
+ // return Blank Item
+ return DataTypeHelpers.EmptyArtifactItemGroup();
+ }
+
+ ///
+ /// Get's the artifact link count for the passed in workspace
+ ///
+ /// The WorkspaceName for which to get all Artifact Links
+ /// 0 or positive number for the number of records, -1 if error occurs
+ public int GetArtifactLinkCountForWorkspace(string WorkspaceName)
+ {
+ // Ensure Workspace Name Integrity
+ if (!DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
+ return -1; // return error
+
+ lock (this)
+ {
+ // Check to make sure that this is a valid WorkspaceName (in DB)
+ if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
+ return -1; // return Blank Item
+
+ // First Step - Get the count of all artifacts for this workspace
+ string sql = "SELECT COUNT([WorkspaceLinks].[AID]) FROM [WorkspaceLinks] WHERE [WorkspaceLinks].[WorkspaceName] = @workspacename";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@workspacename", WorkspaceName) };
+
+ object obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+ if (obj != null)
+ {
+ int i = int.Parse(obj.ToString());
+ return i;
+ }
+ }
+ return -1; // return error
+ }
+
+ ///
+ /// Get's the unique artifact link count for the passed in workspace (this means only artifact links
+ /// that are unique to this workspace)
+ ///
+ /// The WorkspaceName for which to get all unique Artifact Links
+ /// 0 or positive number for the number of records, -1 if error occurs
+ public int GetUniqureArtifactsCountForWorkspace(string WorkspaceName)
+ {
+ // Ensure Workspace Name Integrity
+ if (!DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
+ return -1; // return Blank Item
+
+ lock (this)
+ {
+ // Check to make sure that this is a valid WorkspaceName (in DB)
+ if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
+ return -1; // return Blank Item
+
+ // First Step - We need all the links that are part of the workspace in the links table
+ string sql2 = "SELECT [AID] FROM WorkspaceLinks WHERE [WorkspaceName]=@workspacename";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[] { new SqlCeParameter("@workspacename", WorkspaceName) };
+
+ DataSet dataset = DB.RunSQLTextFillDataSet(sql2, sqlparams2);
+ List workspaceLinksListAIDs = new List();
+
+ if (!DataTypeValidation.IsEmptyDataSet(dataset))
+ {
+ foreach (DataRow row in dataset.Tables[0].Rows)
+ workspaceLinksListAIDs.Add(int.Parse(row[0].ToString()));
+ }
+
+ // Second Step - We now should check which AIDs are not referenced anywhere else, those AIDS are
+ // counted as being unique to this workspace
+ string sql4 = "SELECT [UID] FROM WorkspaceLinks WHERE [AID]=@aid AND [WorkspaceName]<>@workspacename";
+ List workspaceLinksListAIDsWithoutReferences = new List();
+
+ foreach (int aid in workspaceLinksListAIDs)
+ {
+ SqlCeParameter[] sqlparams4 = new SqlCeParameter[] { new SqlCeParameter("@aid", aid), new SqlCeParameter("@workspacename", WorkspaceName) };
+ object obj = DB.RunSQLCommandTextExecuteScalar(sql4, sqlparams4);
+
+ if (obj == null) // this aid has no references
+ workspaceLinksListAIDsWithoutReferences.Add(aid);
+ }
+
+ return workspaceLinksListAIDsWithoutReferences.Count;
+ }
+ }
+
+ ///
+ /// Adds an Artifact to a Workspace (shouldn't already be in that workspace)
+ /// If the artifact already exists and the only thing being done is that the artifact is
+ /// being added to a new workspace (a link will be created)
+ ///
+ /// WorkspaceName to insert Artifact into
+ /// the Artifact to Add (Must be complete - pass All Validations)
+ /// true if successful, false otherwise
+ public bool AddArtifactToWorkspace(string WorkspaceName, ArtifactItem artifactItem)
+ {
+ // ensure artifact and workspace integrity
+ if ((artifactItem == null) ||
+ !(artifactItem.IsValid) ||
+ !(artifactItem.IsLocationValid) ||
+ !(artifactItem.IsValidFileIntegrity) ||
+ !(artifactItem.AreWorkspaceLinkPropertiesValid) ||
+ !DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
+ return false;
+
+ lock (this)
+ {
+ // Check to make sure that this is a valid WorkspaceName
+ if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
+ return false;
+
+ ////
+ // Do a little more Integrity Checking, to know where we are at
+ ////
+ bool bExists = DoesArtifactExistInSystem(artifactItem);
+ bool bAlreadyInWorkspace = false;
+
+ if(bExists)
+ bAlreadyInWorkspace = IsArtifactPartOfWorkspace(WorkspaceName, artifactItem);
+
+ // If we already have it in this workspace, just modify the
+ // Artifact's Properties & Workspace Properties
+ if (bAlreadyInWorkspace)
+ return ModifyExistingArtifactProperties(artifactItem, WorkspaceName); // * also modify workspacelink properties *
+
+ // if it exists, but is not part of this workspace, then we should create a link for the artifact and
+ // update any of the artifact's properties
+ if (bExists && !bAlreadyInWorkspace)
+ {
+ // First Step - Get the UID of the artifact
+ string sql = "SELECT [UID] FROM Artifacts WHERE [Location] = @location";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
+ object obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+
+ if (obj != null)
+ {
+ int aid = int.Parse(obj.ToString());
+ int uid = 0;
+
+ // Second Step - Is to get the Max UID for the Links table to Insert to
+ string sql2 = "SELECT MAX (UID) FROM WorkspaceLinks";
+ object obj2 = DB.RunSQLCommandTextExecuteScalar(sql2);
+
+ if (obj2 != null)
+ {
+ uid = int.Parse(obj2.ToString());
+ uid = uid + 1; // incr. by one
+ }
+
+ // Third Step - Create a new Entry for this workspace in the Links Table
+ string sql3 = "INSERT INTO WorkspaceLinks ([UID],[AID],[WorkspaceName],[WindowTop],[WindowLeft],[WindowHeight],[WindowWidth])";
+ sql3 = sql3 + " VALUES (@uid,@aid,@workspacename,@windowtop,@windowleft,@windowheight,@windowwidth)";
+ SqlCeParameter[] sqlparams3 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@uid", uid),
+ new SqlCeParameter("@aid", aid),
+ new SqlCeParameter("@workspacename", WorkspaceName),
+ new SqlCeParameter("@windowtop", artifactItem.WindowTop),
+ new SqlCeParameter("@windowleft", artifactItem.WindowLeft),
+ new SqlCeParameter("@windowheight", artifactItem.WindowHeight),
+ new SqlCeParameter("@windowwidth", artifactItem.WindowWidth),
+ };
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql3, sqlparams3);
+ if (nResult != 1)
+ return false;
+
+ // Now we can just Modify the Artifact's Properties, in case they changed
+ return ModifyExistingArtifactProperties(artifactItem); // no need to modify workspace properties here - only modify artifact
+ }
+ }
+ else
+ {
+
+ // First Step - Is to get the Max UID for the Artifact table to Insert to
+ int uid = 0;
+ string sql = "SELECT MAX (UID) FROM Artifacts";
+ object obj = DB.RunSQLCommandTextExecuteScalar(sql);
+
+ if (obj != null)
+ {
+ uid = int.Parse(obj.ToString());
+ uid = uid + 1; // incr. by one
+ }
+
+ // Second Step - Is to Actually Insert the new Artifact into the Artifact Table
+ string sql3 = "INSERT INTO Artifacts ([UID],[Name],[Type],[Location],[Note],[SnapShotFile],[LastAccessed],[AccessCounter]) ";
+ sql3 = sql3 + "VALUES (@uid,@name,@type,@location,@note,@snapshotfile,@accessed,@counter)";
+ SqlCeParameter[] sqlparams3 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@uid", uid),
+ new SqlCeParameter("@name", artifactItem.Name),
+ new SqlCeParameter("@type", artifactItem.Type.ToString()),
+ new SqlCeParameter("@location", artifactItem.Location),
+ new SqlCeParameter("@note", artifactItem.Note),
+ new SqlCeParameter("@snapshotfile", artifactItem.SnapshotFile),
+ new SqlCeParameter("@accessed", DateTime.Now),
+ new SqlCeParameter("@counter", "0"),
+ };
+
+ int nResult = 0;
+ nResult = DB.RunSQLCommandTextExecuteNonQuery(sql3, sqlparams3);
+ if (nResult != 1)
+ return false;
+
+ // Third Step - Get the highest UID for the Link table
+ int aid = uid; // save the uid of the artifact as the aid
+ uid = 0;
+ string sql4 = "SELECT MAX (UID) FROM WorkspaceLinks";
+ object obj4 = DB.RunSQLCommandTextExecuteScalar(sql4);
+
+ if (obj != null)
+ {
+ uid = int.Parse(obj4.ToString());
+ uid = uid + 1; // incr. by one
+ }
+
+ // Fourth Step - Is to Now Insert the Link to the Workspace into the Links Table
+ string sql5 = "INSERT INTO WorkspaceLinks ([UID],[AID],[WorkspaceName],[WindowTop],[WindowLeft],[WindowHeight],[WindowWidth]) VALUES (@uid,@aid,@workspacename,@windowtop,@windowleft,@windowheight,@windowwidth)";
+ SqlCeParameter[] sqlparams5 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@uid", uid),
+ new SqlCeParameter("@aid", aid),
+ new SqlCeParameter("@workspacename", WorkspaceName),
+ new SqlCeParameter("@windowtop", artifactItem.WindowTop),
+ new SqlCeParameter("@windowleft", artifactItem.WindowLeft),
+ new SqlCeParameter("@windowheight", artifactItem.WindowHeight),
+ new SqlCeParameter("@windowwidth", artifactItem.WindowWidth),
+ };
+
+ nResult = DB.RunSQLCommandTextExecuteNonQuery(sql5, sqlparams5);
+ if (nResult != 1)
+ return false;
+ else
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Deletes Artifact from the workspace (if no more references exists),
+ /// will delete the artifact entirely (in best scenario only a link will be deleted)
+ ///
+ /// WorkspaceName to Delete Artifact From
+ /// Artifact To Delete (Location Needed Only)
+ /// true if successful, false otherwise
+ public bool DeleteArtifact(string WorkspaceName, ArtifactItem artifactItem)
+ {
+ // ensure artifact and workspace integrity
+ if ((artifactItem == null) ||
+ !(artifactItem.IsLocationValid) ||
+ !DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
+ return false;
+
+ lock (this)
+ {
+ // Check to make sure that this is a valid Artifact
+ if (!DoesArtifactExistInSystem(artifactItem))
+ return false;
+
+ // Check to make sure that this is a valid WorkspaceName
+ if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
+ return false;
+
+ // First Step - Is to get the UID of the Artifact
+ string sql1 = "SELECT [UID] FROM Artifacts WHERE [Location]=@location";
+ SqlCeParameter[] sqlparams1 = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
+
+ object obj = DB.RunSQLCommandTextExecuteScalar(sql1, sqlparams1);
+ if (obj != null)
+ {
+ int uid = int.Parse(obj.ToString());
+
+ // Second Step - Is to Delete the Link in the Link Table
+ string sql2 = "DELETE FROM WorkspaceLinks WHERE [WorkspaceName]=@workspacename AND [AID]=@aid";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@workspacename", WorkspaceName) ,
+ new SqlCeParameter("@aid", uid)
+ };
+
+ // We hope there at least one link in the links table (but we don't verify)
+ DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
+
+ // Third Step - Next is to see if there are any other Links Left with this AID
+ string sql3 = "SELECT [UID] FROM WorkspaceLinks WHERE [AID]=@aid";
+ SqlCeParameter[] sqlparams3 = new SqlCeParameter[] { new SqlCeParameter("@aid", uid) };
+
+ object obj3 = DB.RunSQLCommandTextExecuteScalar(sql3, sqlparams3);
+ if (obj3 == null)
+ {
+ // Fourth Step - Only if there are no other more links, Delete the Actually Artifact from the
+ // Artifact Table
+ string sql4 = "DELETE From Artifacts WHERE [UID]=@uid";
+ SqlCeParameter[] sqlparams4 = new SqlCeParameter[] { new SqlCeParameter("@uid", uid) };
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql4, sqlparams4);
+ if (nResult != 1)
+ return false;
+ else
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Forces Deletion of the Artifact and all Links / References in the System
+ ///
+ /// Artifact To Delete (Location Needed Only)
+ /// true if successful, false otherwise
+ public bool DeleteArtifact(ArtifactItem artifactItem)
+ {
+ // ensure artifact integrity
+ if ((artifactItem == null) ||
+ !(artifactItem.IsLocationValid))
+ return false;
+
+ lock (this)
+ {
+
+ // Check to make sure that this is a valid Artifact
+ if (!DoesArtifactExistInSystem(artifactItem))
+ return false;
+
+ // First Step - Is to get the UID of the Artifact
+ string sql1 = "SELECT [UID] FROM Artifacts WHERE [Location]=@location";
+ SqlCeParameter[] sqlparams1 = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
+
+ object obj = DB.RunSQLCommandTextExecuteScalar(sql1, sqlparams1);
+ if (obj != null)
+ {
+ int uid = int.Parse(obj.ToString());
+
+ // Second Step - Is to Delete all the Links refering to the Artifact in the Links Table
+ string sql2 = "DELETE FROM WorkspaceLinks WHERE [AID]=@aid";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[] { new SqlCeParameter("@aid", uid) };
+
+ DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
+
+ // Third Step - Delete the Artifact from the Artifact Table
+ string sql3 = "DELETE From Artifacts WHERE [UID]=@uid";
+ SqlCeParameter[] sqlparams3 = new SqlCeParameter[] { new SqlCeParameter("@uid", uid) };
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql3, sqlparams3);
+ if (nResult != 1)
+ return false;
+ else
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Modify Properties of an Artifact. Artifact's Location is the Unique Key,
+ /// it must already exist in the system for this update to work.
+ /// (this will only update Artifact Properties Not WorkspaceLink Properties)
+ ///
+ /// the Artifact to Modify (Must be complete - pass All Validations)
+ /// true if successful, false otherwise
+ public bool ModifyExistingArtifactProperties(ArtifactItem artifactItem)
+ {
+ // ensure artifact integrity
+ if ((artifactItem == null) ||
+ !(artifactItem.IsValid) ||
+ !(artifactItem.IsLocationValid) ||
+ !(artifactItem.IsValidFileIntegrity))
+ return false;
+
+ object obj = null;
+ lock (this)
+ {
+ // ensure existence
+ if (!DoesArtifactExistInSystem(artifactItem))
+ return false;
+
+ // First Step - Get the UID of the Artifact so that we can update it
+ string sql = "SELECT [UID] FROM Artifacts WHERE [Location] = @location";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
+ obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+
+ if (obj != null)
+ {
+ int uid = int.Parse(obj.ToString());
+
+ // Second Step - Is to Create the Update Statement to update the Artifact
+ string sql2 = "UPDATE Artifacts SET [Name]=@name,[Type]=@type,[Location]=@location,[Note]=@note,[SnapShotFile]=@snapshotfile, [LastAccessed]=@accessed, [AccessCounter]=@counter ";
+ sql2 = sql2 + "WHERE [UID]=@uid";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@uid", uid),
+ new SqlCeParameter("@name", artifactItem.Name),
+ new SqlCeParameter("@type", artifactItem.Type.ToString()),
+ new SqlCeParameter("@location", artifactItem.Location),
+ new SqlCeParameter("@note", artifactItem.Note),
+ new SqlCeParameter("@snapshotfile", artifactItem.SnapshotFile),
+ new SqlCeParameter("@accessed", artifactItem.LastAccessed),
+ new SqlCeParameter("@counter", artifactItem.AccessCounter),
+ };
+
+ int nResult = 0;
+ nResult = DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
+
+ if (nResult != 1)
+ return false;
+ else
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Modify Properties of an Artifact and the properties of a workspaceLink.
+ /// Artifact's Location is the Unique Key, it must already exist in the system.
+ ///
+ /// the Artifact to Modify (Must be complete - pass All Validations)
+ /// the workspaceName whose Link properties to modify
+ /// true if successful, false otherwise
+ public bool ModifyExistingArtifactProperties(ArtifactItem artifactItem, string WorkspaceName)
+ {
+ // ensure artifact and workspace integrity
+ if ((artifactItem == null) ||
+ !(artifactItem.IsValid) ||
+ !(artifactItem.IsLocationValid) ||
+ !(artifactItem.IsValidFileIntegrity) ||
+ !(artifactItem.AreWorkspaceLinkPropertiesValid) ||
+ !DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
+ return false;
+
+ lock (this)
+ {
+ // First Step - modify the Artifact's Properties *if fails, return*
+ if (!ModifyExistingArtifactProperties(artifactItem))
+ return false;
+
+ // Now Check Validity of the Workspace Properties before continuing
+ if (!artifactItem.AreWorkspaceLinkPropertiesValid)
+ return false;
+
+ // Ensure existence of WorkspaceName
+ if (!Data.Workspace.DoesWorkspaceNameExist(WorkspaceName))
+ return false;
+
+ // Second Step - get the AID for the Artifact
+ string sql = "SELECT [UID] FROM Artifacts WHERE [Location] = @location";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@location", artifactItem.Location) };
+ object obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+
+ if (obj != null)
+ {
+ int uid = int.Parse(obj.ToString());
+
+ // Third Step - Is to Update the Workspace Link Properties
+ string sql2 = "UPDATE WorkspaceLinks SET [WindowTop]=@windowtop,[WindowLeft]=@windowleft,[WindowHeight]=@windowheight,[WindowWidth]=@windowwidth ";
+ sql2 = sql2 + "WHERE [AID]=@uid AND [WorkspaceName] = @workspacename";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@windowtop", artifactItem.WindowTop),
+ new SqlCeParameter("@windowleft", artifactItem.WindowLeft),
+ new SqlCeParameter("@windowheight", artifactItem.WindowHeight),
+ new SqlCeParameter("@windowwidth", artifactItem.WindowWidth),
+ new SqlCeParameter("@uid", uid),
+ new SqlCeParameter("@workspacename", WorkspaceName),
+ };
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
+ if (nResult != 1)
+ return false;
+ else
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ }
+}
diff --git a/DataAccessLayer/dState.cs b/DataAccessLayer/dState.cs
new file mode 100644
index 0000000..c8465ad
--- /dev/null
+++ b/DataAccessLayer/dState.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Data;
+using System.Data.SqlServerCe;
+using Foo.DataAccessLayer.DataTypes;
+
+namespace Foo.DataAccessLayer
+{
+ public class dState
+ {
+ private const string EMPTY_WORKSPACE_NAME_STATE = "____CURRENT__WORKSPACE____IS___SET_TO__NIL__";
+
+ ///
+ /// Get the Current WorkspaceName in the State Table
+ ///
+ /// the name of the current's state workspace
+ public string GetCurrentWorkspaceName()
+ {
+ object obj = null;
+ lock (this)
+ {
+ string sql = "SELECT [CurrentWorkspaceName] FROM State";
+ obj = DB.RunSQLCommandTextExecuteScalar(sql);
+ }
+
+ if (obj != null)
+ {
+ if (obj.ToString() == EMPTY_WORKSPACE_NAME_STATE)
+ return string.Empty;
+ else
+ return obj.ToString();
+ }
+ else
+ return string.Empty;
+ }
+
+ ///
+ /// Set the Current WorkspaceName in the State Table
+ ///
+ /// the name of the new workspace name (Can NOT be String.Empty!, use ClearCurrentWorkspaceName() instead)
+ /// true if successful, false otherwise
+ public bool SetCurrentWorkspaceName(string currentWorkspaceName)
+ {
+ if (!String.IsNullOrEmpty(currentWorkspaceName) && DataTypeValidation.IsValidWorkspaceName(currentWorkspaceName))
+ {
+ lock (this)
+ {
+ // Existence Check
+ if ((currentWorkspaceName != EMPTY_WORKSPACE_NAME_STATE) &&
+ !Data.Workspace.DoesWorkspaceNameExist(currentWorkspaceName))
+ return false;
+
+ string currentWorkspaceNameInDB = GetCurrentWorkspaceName();
+
+ // check if different
+ bool bIsDifferent = (currentWorkspaceNameInDB.ToLower() != currentWorkspaceName.ToLower());
+ if (!bIsDifferent)
+ return false;
+
+ bool bInsert = !IsInEmptyWorkspaceNameState() && String.IsNullOrEmpty(currentWorkspaceNameInDB);
+ if (bInsert)
+ {
+ string sql = "INSERT INTO State ([CurrentWorkspaceName]) VALUES (@workspacename)";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@workspacename", currentWorkspaceName) };
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql, sqlparams);
+ if (nResult != 1)
+ return false;
+ else
+ return true;
+ }
+ else
+ {
+ string sql = "UPDATE State SET [CurrentWorkspaceName]=@newworkspacename WHERE [CurrentWorkspaceName]=@oldworkspacename";
+ SqlCeParameter[] sqlparams;
+
+ if (!IsInEmptyWorkspaceNameState())
+ {
+ sqlparams = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@oldworkspacename", currentWorkspaceNameInDB),
+ new SqlCeParameter("@newworkspacename", currentWorkspaceName),
+ };
+ }
+ else
+ {
+ sqlparams = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@oldworkspacename", EMPTY_WORKSPACE_NAME_STATE),
+ new SqlCeParameter("@newworkspacename", currentWorkspaceName),
+ };
+ }
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql, sqlparams);
+ if (nResult != 1)
+ return false;
+ else
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Mostly used internally for the Empty WorkspaceName State
+ ///
+ /// true if we are in this state, false otherwise
+ internal bool IsInEmptyWorkspaceNameState()
+ {
+ object obj = null;
+ lock (this)
+ {
+ string sql = "SELECT [CurrentWorkspaceName] FROM State";
+ obj = DB.RunSQLCommandTextExecuteScalar(sql);
+ }
+
+ if (obj != null)
+ {
+ if (obj.ToString() == EMPTY_WORKSPACE_NAME_STATE)
+ return true;
+ else
+ return false;
+ }
+ else
+ return false;
+ }
+
+ ///
+ /// Clears the current workspace in the State Table
+ ///
+ public void ClearCurrentWorkspaceName()
+ {
+ SetCurrentWorkspaceName(EMPTY_WORKSPACE_NAME_STATE);
+ }
+ }
+}
diff --git a/DataAccessLayer/dUserSettings.cs b/DataAccessLayer/dUserSettings.cs
new file mode 100644
index 0000000..cd66417
--- /dev/null
+++ b/DataAccessLayer/dUserSettings.cs
@@ -0,0 +1,183 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Data.SqlServerCe;
+using Foo.DataAccessLayer.DataTypes;
+
+namespace Foo.DataAccessLayer
+{
+ public enum UserSetting
+ {
+ ON_LAUNCH_CLOSEPREVIOUS_WORKSPACE,
+ }
+
+ public class dUserSettings
+ {
+ ///
+ /// Quick Check if there is already a Setting Information available for this Table
+ ///
+ /// a Setting enum
+ /// true if the DB has setting information for this setting
+ internal bool DoesSettingHaveAnEntry(UserSetting setting)
+ {
+ object obj = null;
+ lock (this)
+ {
+ string sql = "SELECT [SettingName] FROM UserSettings WHERE [SettingName] = @settingname";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@settingname", setting.ToString()) };
+ obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+ }
+ return (obj != null);
+ }
+
+ ///
+ /// Retrieve Setting Value for the Setting as a string
+ ///
+ /// a Setting enum
+ /// setting value string, or empty.string if not found
+ public string GetSettingValueStr(UserSetting setting)
+ {
+ object obj = null;
+ lock (this)
+ {
+ string sql = "SELECT [SettingValue] FROM UserSettings WHERE [SettingName] = @settingname";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@settingname", setting.ToString()) };
+
+ obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+ if (obj != null)
+ return obj.ToString();
+ }
+ return String.Empty;
+ }
+
+ ///
+ /// Set a Setting Value for the Setting as a string
+ ///
+ /// a Setting enum
+ /// a string value to store for a setting
+ /// true if successfully inserted or updated, false otherwise
+ public bool SetSettingValueStr(UserSetting setting, string strSettingValue)
+ {
+ // Ensure Value Integrity
+ if (String.IsNullOrEmpty(strSettingValue))
+ return false;
+
+ lock (this)
+ {
+ // First Determine if we need to update or insert
+ bool bUpdate = DoesSettingHaveAnEntry(setting);
+
+ if (!bUpdate) // we need to insert
+ {
+ string sql = "INSERT INTO UserSettings ([SettingName],[SettingValue]) VALUES (@settingname,@settingvalue)";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@settingname", setting.ToString()),
+ new SqlCeParameter("@settingvalue", strSettingValue),
+ };
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql, sqlparams);
+ return (nResult == 1);
+ }
+ else // we need to update
+ {
+ string sql2 = "UPDATE UserSettings SET [SettingValue]=@settingvalue WHERE [SettingName]=@settingname";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@settingname", setting.ToString()),
+ new SqlCeParameter("@settingvalue", strSettingValue),
+ };
+
+
+ int nResult2 = DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
+ return (nResult2 == 1);
+ }
+ }
+ }
+
+ #region Helper Getter/Setters
+
+ public bool GetSettingValueBool(UserSetting setting)
+ {
+ try
+ {
+ string strValue = GetSettingValueStr(setting);
+ if(!String.IsNullOrEmpty(strValue))
+ {
+ bool bRet = bool.Parse(strValue);
+ return bRet;
+ }
+ }
+ catch(Exception){ /* ignore */ }
+ return false;
+ }
+
+ public int GetSettingValueInt(UserSetting setting)
+ {
+ try
+ {
+ string strValue = GetSettingValueStr(setting);
+ if (!String.IsNullOrEmpty(strValue))
+ {
+ int bRet = int.Parse(strValue);
+ return bRet;
+ }
+ }
+ catch (Exception) { /* ignore */ }
+ return int.MinValue;
+ }
+
+ public DateTime GetSettingValueDateTime(UserSetting setting)
+ {
+ try
+ {
+ string strValue = GetSettingValueStr(setting);
+ if (!String.IsNullOrEmpty(strValue))
+ {
+ DateTime bRet = DateTime.Parse(strValue);
+ return bRet;
+ }
+ }
+ catch (Exception) { /* ignore */ }
+ return DateTime.MinValue;
+ }
+
+ public double GetSettingValueDouble(UserSetting setting)
+ {
+ try
+ {
+ string strValue = GetSettingValueStr(setting);
+ if (!String.IsNullOrEmpty(strValue))
+ {
+ double bRet = double.Parse(strValue);
+ return bRet;
+ }
+ }
+ catch (Exception) { /* ignore */ }
+ return double.MinValue;
+ }
+
+ public bool SetSettingValueBool(UserSetting setting, bool settingValue)
+ {
+ return SetSettingValueStr(setting, settingValue.ToString());
+ }
+
+ public bool SetSettingValueInt(UserSetting setting, int settingValue)
+ {
+ return SetSettingValueStr(setting, settingValue.ToString());
+ }
+
+ public bool SetSettingValueDateTime(UserSetting setting, DateTime settingValue)
+ {
+ return SetSettingValueStr(setting, settingValue.ToString());
+ }
+
+ public bool SetSettingValueDouble(UserSetting setting, double settingValue)
+ {
+ return SetSettingValueStr(setting, settingValue.ToString());
+ }
+
+ #endregion
+ }
+}
diff --git a/DataAccessLayer/dVersioningTables.cs b/DataAccessLayer/dVersioningTables.cs
new file mode 100644
index 0000000..0039fa8
--- /dev/null
+++ b/DataAccessLayer/dVersioningTables.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Data.SqlServerCe;
+using Foo.DataAccessLayer.DataTypes;
+
+namespace Foo.DataAccessLayer
+{
+ internal class dVersioningTables
+ {
+
+ ///
+ /// Quick Check if there is Version Information available for this Table
+ ///
+ /// a table name to check
+ /// true if the DB has version information for this Table
+ internal bool DoesTableHaveVersionEntry(string TableName)
+ {
+ // Check TableName Integrity
+ if (!DataTypeValidation.IsValidTableName(TableName))
+ return false;
+
+ object obj = null;
+ lock (this)
+ {
+ string sql = "SELECT [TableName] FROM VersioningTables WHERE [TableName] = @tablename";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@tablename", TableName) };
+
+ obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+ }
+ return (obj != null);
+ }
+
+ ///
+ /// Retrieve the Version information for the specified Table
+ ///
+ /// a table name to check
+ /// version information string, or empty.string if not found
+ internal string GetVersionInformationForTable(string TableName)
+ {
+ // Check TableName Integrity
+ if (!DataTypeValidation.IsValidTableName(TableName))
+ return String.Empty;
+
+ object obj = null;
+ lock (this)
+ {
+ string sql = "SELECT [Version] FROM VersioningTables WHERE [TableName] = @tablename";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@tablename", TableName) };
+
+ obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+ if (obj != null)
+ return obj.ToString();
+ }
+ return String.Empty;
+ }
+
+ ///
+ /// Use this most often to insert/update the version information of a table into the VersioningTables Table
+ ///
+ /// The table name for which to insert version information
+ /// the version information in the format of n.n.nnnn
+ /// true if successfully inserted or updated, false otherwise
+ internal bool AddUpdateVersionInformationForSpecifiedTable(string TableName, string VersionInformation)
+ {
+ // Check TableName Integrity
+ if (!DataTypeValidation.IsValidTableName(TableName))
+ return false;
+
+ // Check Version Integrity
+ if (!DataTypeValidation.IsValidVersionInformation(VersionInformation))
+ return false;
+
+ lock (this)
+ {
+ // First Determine if we need to update or insert
+ bool bUpdate = DoesTableHaveVersionEntry(TableName);
+
+ if (!bUpdate) // we need to insert
+ {
+ string sql = "INSERT INTO VersioningTables ([TableName],[Version]) VALUES (@tablename,@version)";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@tablename", TableName),
+ new SqlCeParameter("@version", VersionInformation),
+ };
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql, sqlparams);
+ return (nResult == 1);
+ }
+ else // we need to update
+ {
+ string sql2 = "UPDATE VersioningTables SET [Version]=@version WHERE [TableName]=@tablename";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@tablename", TableName),
+ new SqlCeParameter("@version", VersionInformation),
+ };
+
+
+ int nResult2 = DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
+ return (nResult2 == 1);
+ }
+ }
+ }
+ }
+}
diff --git a/DataAccessLayer/dWorkspace.cs b/DataAccessLayer/dWorkspace.cs
new file mode 100644
index 0000000..e2a46f6
--- /dev/null
+++ b/DataAccessLayer/dWorkspace.cs
@@ -0,0 +1,341 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Data;
+using System.Data.SqlServerCe;
+using Foo.DataAccessLayer.DataTypes;
+
+namespace Foo.DataAccessLayer
+{
+ public class dWorkspace
+ {
+
+ ///
+ /// Quick Check to see If the WorkspaceName already exists
+ ///
+ /// Name of Workspace
+ /// true if Name exists, false otherwise
+ public bool DoesWorkspaceNameExist(string WorkspaceName)
+ {
+ // Check WorkspaceName Integrity
+ if (!DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
+ return false;
+
+ object obj = null;
+ lock (this)
+ {
+ string sql = "SELECT [Name] FROM Workspaces WHERE [Name] = @workspacename";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@workspacename", WorkspaceName) };
+
+ obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+ }
+ return (obj != null);
+ }
+
+ ///
+ /// Retrieve a String list of all WorkspaceNames in the Database
+ ///
+ /// Specify the SortOrder of the List
+ /// a list of worspace names, or empty[] if none exist
+ public string[] GetAllWorkspaceNames(SortOrderForWorkspaces SortBy)
+ {
+ List resultList = new List();
+ lock (this)
+ {
+ string sql = "SELECT [Name] FROM Workspaces";
+
+ // Add WorkspaceSortOrder
+ sql = SortOrderSQLHelpers.SortOrderForWorkspacesHelper(sql, SortBy);
+
+ DataSet dataset = DB.RunSQLTextFillDataSet(sql);
+ if (!DataTypeValidation.IsEmptyDataSet(dataset))
+ {
+ foreach (DataRow row in dataset.Tables[0].Rows)
+ resultList.Add(row[0].ToString());
+ }
+ }
+ return resultList.ToArray();
+ }
+
+ ///
+ /// Retrieve a Workspace List of all Workspaces in the Database
+ ///
+ /// Specify the SortOrder of the List
+ /// a list of worspaces
+ public WorkspaceItem[] GetAllWorkspaces(SortOrderForWorkspaces SortBy)
+ {
+ List resultList = new List();
+ lock (this)
+ {
+ string sql = "SELECT [Name],[LastAccessed],[AccessCounter] FROM Workspaces";
+
+ // Add WorkspaceSortOrder
+ sql = SortOrderSQLHelpers.SortOrderForWorkspacesHelper(sql, SortBy);
+
+ DataSet dataset = DB.RunSQLTextFillDataSet(sql);
+ if (!DataTypeValidation.IsEmptyDataSet(dataset))
+ {
+ int nRows = dataset.Tables[0].Rows.Count;
+ WorkspaceItem[] resultWorkspaces = new WorkspaceItem[nRows];
+
+ for (int i = 0; i < nRows; ++i)
+ {
+ DataRow datarow = dataset.Tables[0].Rows[i];
+ resultWorkspaces[i] = new WorkspaceItem();
+
+ // Add Workspace Fields
+ resultWorkspaces[i].Name = datarow["Name"].ToString();
+
+ if (!String.IsNullOrEmpty(datarow["LastAccessed"].ToString()))
+ resultWorkspaces[i].SetLastAccessed(DateTime.Parse(datarow["LastAccessed"].ToString()));
+
+ if (!String.IsNullOrEmpty(datarow["AccessCounter"].ToString()))
+ resultWorkspaces[i].AccessCounter = int.Parse(datarow["AccessCounter"].ToString());
+ }
+
+ return resultWorkspaces;
+ }
+ }
+
+ // return Blank Item
+ return DataTypeHelpers.EmptyWorkspaceItemGroup();
+ }
+
+ ///
+ /// Use this to modify a workspace Item (allows you to modify a workspace's properties NOT the name)
+ ///
+ /// a workspaceItem whose properties you want to update (Must pass all validations)
+ /// true if succesfully updated, false otherwise
+ public bool ModifyWorkspaceItem(WorkspaceItem workspaceItem)
+ {
+ // Check WorkspaceName Integrity
+ if ((workspaceItem == null) ||
+ !workspaceItem.IsValid)
+ return false;
+
+ lock (this)
+ {
+ // existence check
+ if (!DoesWorkspaceNameExist(workspaceItem.Name))
+ return false;
+
+ // First Step - is to create the update statement to make the neccessary modifications
+ string sql2 = "UPDATE Workspaces SET [LastAccessed]=@lastaccessed,[AccessCounter]=@accesscounter WHERE [Name]=@workspacename";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@accesscounter", workspaceItem.AccessCounter),
+ new SqlCeParameter("@lastaccessed", workspaceItem.LastAccessed),
+ new SqlCeParameter("@workspacename", workspaceItem.Name),
+ };
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
+ return (nResult == 1);
+ }
+ }
+
+ ///
+ /// Increments the access counter and sets LastAccessed for the
+ /// specified workspace name. Call this whenever you have launched a workspace.
+ ///
+ /// an existing workspace Name
+ /// true if successful set the internal counters, false otherwise
+ public bool WorkspaceWasLaunched(string WorkspaceName)
+ {
+ // Check WorkspaceName Integrity
+ if (!DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
+ return false;
+
+ lock (this)
+ {
+ // existence check
+ if (!DoesWorkspaceNameExist(WorkspaceName))
+ return false;
+
+ // First Step - is to get the AccessCounter already in the db
+ string sql = "SELECT [AccessCounter] FROM Workspaces WHERE [Name]=@workspacename";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@workspacename", WorkspaceName) };
+
+ int accesscount = 1;
+ object obj = DB.RunSQLCommandTextExecuteScalar(sql, sqlparams);
+ if (obj != null)
+ {
+ accesscount = int.Parse(obj.ToString());
+ accesscount = accesscount + 1; // increment by 1
+ }
+
+ // Second Step - is to set the access counter and today's date for the workspace
+ string sql2 = "UPDATE Workspaces SET [LastAccessed]=@lastaccessed,[AccessCounter]=@accesscounter WHERE [Name]=@workspacename";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@lastaccessed", DateTime.Now),
+ new SqlCeParameter("@accesscounter", accesscount),
+ new SqlCeParameter("@workspacename", WorkspaceName),
+ };
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
+ return (nResult == 1);
+ }
+ }
+
+ ///
+ /// Inserts a new WorspaceName into the Workspace Table (if it not already exists)
+ ///
+ /// new non-existing unique workspace Name
+ /// true if successful, false otherwise
+ public bool InsertWorkspaceName(string WorkspaceName)
+ {
+ // Check WorkspaceName Integrity
+ if (!DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
+ return false;
+
+ int nResult = -1;
+ lock (this)
+ {
+ // ensure uniqueness
+ if (DoesWorkspaceNameExist(WorkspaceName))
+ return false;
+
+ string sql = "INSERT INTO Workspaces ([Name],[LastAccessed],[AccessCounter]) VALUES (@workspacename,@accessed,@count)";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@workspacename",WorkspaceName),
+ new SqlCeParameter("@accessed",DateTime.Now),
+ new SqlCeParameter("@count","0"),
+ };
+
+ nResult = DB.RunSQLCommandTextExecuteNonQuery(sql, sqlparams);
+ }
+ return (nResult == 1);
+ }
+
+ ///
+ /// Renames a Workspace to a new Name. In order to do so, we must also rename
+ /// all possible links that exists, so this process is a two-step process
+ ///
+ ///
+ ///
+ /// true if successful, false otherwise
+ public bool RenameWorkspace(string OldWorkspaceName, string NewWorkspaceName)
+ {
+ // Check WorkspaceName Integrity
+ if (!DataTypeValidation.IsValidWorkspaceName(OldWorkspaceName) ||
+ !DataTypeValidation.IsValidWorkspaceName(NewWorkspaceName))
+ return false;
+
+ lock (this)
+ {
+ // ensure existence
+ if (!DoesWorkspaceNameExist(OldWorkspaceName))
+ return false;
+
+ // First Step - update Workspace Table
+ string sql = "UPDATE Workspaces SET [Name]=@newworkspacename WHERE [Name]=@oldworkspacename";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@oldworkspacename", OldWorkspaceName),
+ new SqlCeParameter("@newworkspacename", NewWorkspaceName),
+ };
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql, sqlparams);
+ if (nResult != 1)
+ return false;
+
+ // Second Step - update Links Table (any links that point to this workspace)
+ string sql2 = "UPDATE WorkspaceLinks SET [WorkspaceName]=@newworkspacename WHERE [WorkspaceName]=@oldworkspacename";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[]
+ {
+ new SqlCeParameter("@oldworkspacename", OldWorkspaceName),
+ new SqlCeParameter("@newworkspacename", NewWorkspaceName),
+ };
+
+ int nResult2 = DB.RunSQLCommandTextExecuteNonQuery(sql2, sqlparams2);
+ if (nResult2 >= 0)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ ///
+ /// Deletes a Workspace. In order to do so, we must also delete and links
+ /// that the Workspace has. When Deleting links and encountering a link to
+ /// an artifact that is not references anywhere, we should delete the artifact
+ /// as well. So this is a five-step process.
+ ///
+ /// an existing workspace name
+ /// true if successful, false otherwise
+ public bool DeleteWorkspace(string WorkspaceName)
+ {
+ // Check WorkspaceName Integrity
+ if (!DataTypeValidation.IsValidWorkspaceName(WorkspaceName))
+ return false;
+
+ lock (this)
+ {
+ // ensure existence
+ if (!DoesWorkspaceNameExist(WorkspaceName))
+ return false;
+
+ // First Step - delete WorkspaceName from Workspace Table
+ string sql = "DELETE FROM Workspaces WHERE [Name]=@workspacename";
+ SqlCeParameter[] sqlparams = new SqlCeParameter[] { new SqlCeParameter("@workspacename", WorkspaceName) };
+
+ int nResult = DB.RunSQLCommandTextExecuteNonQuery(sql, sqlparams);
+ if (nResult != 1)
+ return false;
+
+ // Second Step - We need all the links that are part of the workspace in the links table
+ string sql2 = "SELECT [AID] FROM WorkspaceLinks WHERE [WorkspaceName]=@workspacename";
+ SqlCeParameter[] sqlparams2 = new SqlCeParameter[] { new SqlCeParameter("@workspacename", WorkspaceName) };
+
+ DataSet dataset = DB.RunSQLTextFillDataSet(sql2, sqlparams2);
+ List workspaceLinksListAIDs = new List();
+
+ if (!DataTypeValidation.IsEmptyDataSet(dataset))
+ {
+ foreach (DataRow row in dataset.Tables[0].Rows)
+ workspaceLinksListAIDs.Add(int.Parse(row[0].ToString()));
+ }
+
+ // Third Step - We now have all the AIDs to look later so we can now delete all the links for this
+ // workspace from the links table
+ string sql3 = "DELETE FROM WorkspaceLinks WHERE [WorkspaceName]=@workspacename";
+ SqlCeParameter[] sqlparams3 = new SqlCeParameter[] { new SqlCeParameter("@workspacename", WorkspaceName) };
+
+ nResult = DB.RunSQLCommandTextExecuteNonQuery(sql3, sqlparams3);
+ if (nResult == -1)
+ return false;
+
+ // Fourth Step - We now should check which AIDs are still referenced in the Link table, those that
+ // still have references, we keep, others we want to delete
+ string sql4 = "SELECT [UID] FROM WorkspaceLinks WHERE [AID]=@aid";
+ List workspaceLinksListAIDsWithoutReferences = new List();
+
+ foreach (int aid in workspaceLinksListAIDs)
+ {
+ SqlCeParameter[] sqlparams4 = new SqlCeParameter[] { new SqlCeParameter("@aid", aid) };
+ object obj = DB.RunSQLCommandTextExecuteScalar(sql4, sqlparams4);
+
+ if (obj == null) // this aid has no references
+ workspaceLinksListAIDsWithoutReferences.Add(aid);
+ }
+
+ // Fifth Step - Now we want to delete all artifacts in the artifact table that have no references
+ // Since we already deleted all links, and workspaces, we should just directly delete the dangling
+ // Artifacts here
+ string sql5 = "DELETE FROM Artifacts WHERE [UID]=@uid";
+ foreach (int aid in workspaceLinksListAIDsWithoutReferences)
+ {
+ SqlCeParameter[] sqlparam5 = new SqlCeParameter[]{ new SqlCeParameter("@uid", aid) };
+ nResult = DB.RunSQLCommandTextExecuteNonQuery(sql5, sqlparam5);
+
+ if (nResult != 1) // we expect there to be an artifact to delete
+ return false;
+ }
+ }
+ return true;
+ }
+
+ }
+}
diff --git a/DataAccessLayer/nUnitTests.cs b/DataAccessLayer/nUnitTests.cs
new file mode 100644
index 0000000..44e6211
--- /dev/null
+++ b/DataAccessLayer/nUnitTests.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using NUnit.Framework;
+
+using Foo.DataAccessLayer;
+using DataAccessLayer.TestData;
+
+namespace Foo.DataAccessLayer
+{
+ [TestFixture]
+ public class nUnitTests
+ {
+
+ [SetUp]
+ public void Setup()
+ {
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ }
+
+ [Test]
+ public void RecreateDatabaseAndLoadWithDefaultTestData()
+ {
+ // First Delete the DB, if it exists
+ DB.DeleteDefaultDB();
+
+ // Now Fill the DB with the Test Data
+ TestData.FillDBWithTestData();
+ }
+ }
+}
diff --git a/Deskband/BandObjectBase/Attributes.cs b/Deskband/BandObjectBase/Attributes.cs
new file mode 100644
index 0000000..7031052
--- /dev/null
+++ b/Deskband/BandObjectBase/Attributes.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection;
+
+namespace Foo.Deskband.BandObject
+{
+ ///
+ /// Represents different styles of a band object.
+ ///
+ [Flags]
+ [Serializable]
+ public enum BandObjectStyle : uint
+ {
+ Vertical = 1,
+ Horizontal = 2,
+ ExplorerToolbar = 4,
+ TaskbarToolBar = 8
+ }
+
+ ///
+ /// Specifies Style of the band object, its Name(displayed in explorer menu) and HelpText(displayed in status bar when menu command selected).
+ ///
+ [AttributeUsage(AttributeTargets.Class)]
+ public class BandObjectAttribute : System.Attribute
+ {
+ public BandObjectAttribute(){}
+
+ public BandObjectAttribute(string name, BandObjectStyle style)
+ {
+ Name = name;
+ Style = style;
+ }
+ public BandObjectStyle Style;
+ public string Name;
+ public string HelpText;
+ }
+}
\ No newline at end of file
diff --git a/Deskband/BandObjectBase/BandObject.cs b/Deskband/BandObjectBase/BandObject.cs
new file mode 100644
index 0000000..b96febe
--- /dev/null
+++ b/Deskband/BandObjectBase/BandObject.cs
@@ -0,0 +1,476 @@
+using System;
+using System.Windows.Forms;
+using System.Runtime.InteropServices;
+using SHDocVw;
+using System.Reflection;
+using System.Diagnostics;
+using System.Drawing;
+using System.ComponentModel;
+using Microsoft.Win32;
+
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyVersion("1.0.0.0")]
+
+namespace Foo.Deskband.BandObject
+{
+ ///
+ /// Contains main desk band functionality
+ ///
+ ///
+ ///
+ public class BandObjectBase : UserControl, IObjectWithSite, IDeskBand, IDeskBand2, IDockingWindow, IOleWindow, IInputObject
+ {
+ [DllImport("user32.dll")]
+ public static extern Int32 GetWindowLong(IntPtr hwnd, int nIndex);
+
+ [DllImport("user32.dll")]
+ public static extern Int32 SetWindowLong(IntPtr hwnd, int nIndex, Int32 dwNewLong);
+
+ [DllImport("user32.dll")]
+ public static extern bool SetLayeredWindowAttributes(IntPtr hwnd, Int32 crKey, int bAlpha, uint dwFlags);
+
+ public const int GWL_EXSTYLE = -20;
+ public const int LWA_COLORKEY = 0x00000001;
+ public const int WS_EX_LAYERED = 0x00080000;
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct COLORREF
+ {
+ public byte R;
+ public byte G;
+ public byte B;
+ }
+
+ public BandObjectBase()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ this.SuspendLayout();
+ //
+ // BandObjectBase
+ //
+ this.BackColor = System.Drawing.Color.Black;
+ this.Margin = new System.Windows.Forms.Padding(0);
+ this.Name = "BandObjectBase";
+ this.Size = new System.Drawing.Size(24, 24);
+ this.MinimumSize = new System.Drawing.Size(24, 24);
+ this.MaximumSize = new System.Drawing.Size(24, 24);
+ this.ResumeLayout(false);
+ this.HandleCreated += new System.EventHandler(Band_HandleCreated);
+ this.HandleDestroyed += new System.EventHandler(Band_HandleDestroyed);
+ }
+
+ private void Band_HandleCreated(object sender, EventArgs e)
+ {
+ IntPtr hWnd = this.Handle;
+ SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
+ SetLayeredWindowAttributes(hWnd, 0x00000000, 0, LWA_COLORKEY);
+ }
+
+ private void Band_HandleDestroyed(object sender, EventArgs e)
+ {
+
+ }
+
+ #region IObjectWithSite
+
+ public virtual void GetSite(ref Guid riid, out Object ppvSite)
+ {
+ ppvSite = BandObjectSite;
+ }
+
+ public virtual void SetSite(Object pUnkSite)
+ {
+ if (BandObjectSite != null)
+ Marshal.ReleaseComObject(BandObjectSite);
+
+ if (Explorer != null)
+ {
+ Marshal.ReleaseComObject(Explorer);
+ Explorer = null;
+ }
+
+ BandObjectSite = (IInputObjectSite)pUnkSite;
+ if (BandObjectSite != null)
+ {
+ //pUnkSite is a pointer to object that implements IOleWindowSite or something similar
+ //we need to get access to the top level object - explorer itself
+ //to allows this explorer objects also implement IServiceProvider interface
+ //(don't mix it with System.IServiceProvider!)
+ //we get this interface and ask it to find WebBrowserApp
+ _IServiceProvider sp = BandObjectSite as _IServiceProvider;
+ Guid guid = ExplorerGUIDs.IID_IWebBrowserApp;
+ Guid riid = ExplorerGUIDs.IID_IUnknown;
+
+ try
+ {
+ object w;
+ sp.QueryService(
+ ref guid,
+ ref riid,
+ out w);
+
+ //once we have interface to the COM object we can create RCW from it
+ Explorer = (WebBrowserClass)Marshal.CreateWrapperOfType(
+ w as IWebBrowser,
+ typeof(WebBrowserClass)
+ );
+
+ OnExplorerAttached(EventArgs.Empty);
+ }
+ catch (COMException)
+ {
+ //we anticipate this exception in case our object instantiated
+ //as a Desk Band. There is no web browser service available.
+ }
+ }
+ }
+
+ #endregion
+
+ #region IDeskband
+
+ public virtual void GetWindow(out System.IntPtr phwnd)
+ {
+ phwnd = Handle;
+ }
+
+ public virtual void ContextSensitiveHelp(bool fEnterMode){}
+
+ ///
+ /// Called by explorer when band object needs to be showed or hidden.
+ ///
+ ///
+ public virtual void ShowDW(bool fShow)
+ {
+ if (fShow)
+ Show();
+ else
+ Hide();
+ }
+
+ ///
+ /// Called by explorer when window is about to close.
+ ///
+ public virtual void CloseDW(UInt32 dwReserved)
+ {
+ Dispose(true);
+ }
+
+ ///
+ /// Not used.
+ ///
+ public virtual void ResizeBorderDW(IntPtr prcBorder, Object punkToolbarSite, bool fReserved) { }
+
+ public virtual void GetBandInfo(UInt32 dwBandID, UInt32 dwViewMode, ref DESKBANDINFO dbi)
+ {
+
+ if ((dbi.dwMask & DBIM.MINSIZE) != 0)
+ {
+ dbi.ptMinSize.X = MinSize.Width;
+ dbi.ptMinSize.Y = MinSize.Height;
+ }
+
+ if ((dbi.dwMask & DBIM.MAXSIZE) != 0)
+ {
+ dbi.ptMaxSize.X = MaxSize.Width;
+ dbi.ptMaxSize.Y = MaxSize.Height;
+ }
+
+ if ((dbi.dwMask & DBIM.INTEGRAL) != 0)
+ {
+ dbi.ptIntegral.X = IntegralSize.Width;
+ dbi.ptIntegral.Y = IntegralSize.Height;
+ }
+
+ if ((dbi.dwMask & DBIM.ACTUAL) != 0)
+ {
+ dbi.ptActual.X = Size.Width;
+ dbi.ptActual.Y = Size.Height;
+ }
+
+ if ((dbi.dwMask & DBIM.TITLE) != 0)
+ {
+ dbi.wszTitle = Title;
+ }
+
+ //Use the default background color by removing this flag
+ dbi.dwMask &= ~DBIM.BKCOLOR;
+
+ //COLORREF bkColor;
+ //bkColor.R = Color.Black.R;
+ //bkColor.G = Color.Black.G;
+ //bkColor.B = Color.Black.B;
+ //Color.to
+ //dbi.crBkgnd = Int32.MaxValue;
+ //dbi.crBkgnd = 0xDEDEDE;
+
+ dbi.dwModeFlags = (DBIMF)DBIM.TITLE | (DBIMF)DBIM.ACTUAL | (DBIMF)DBIM.MAXSIZE | (DBIMF)DBIM.MINSIZE | (DBIMF)DBIM.INTEGRAL;
+ dbi.dwModeFlags = dbi.dwModeFlags | DBIMF.ALWAYSGRIPPER | DBIMF.VARIABLEHEIGHT | DBIMF.ADDTOFRONT;
+ }
+
+ #endregion
+
+ #region IDeskBand2
+
+ public void CanRenderComposited(ref bool pfCanRenderComposited)
+ {
+ pfCanRenderComposited = true;
+ }
+
+ public void GetCompositionState(ref bool pfCompositionEnabled)
+ {
+ pfCompositionEnabled = _compositionEnabled;
+ }
+
+ public void SetCompositionState(bool fCompositionEnabled)
+ {
+ _compositionEnabled = fCompositionEnabled;
+ }
+
+ #endregion
+
+ #region IInputObject
+
+ ///
+ /// Called explorer when focus has to be chenged.
+ ///
+ public virtual void UIActivateIO(Int32 fActivate, ref MSG Msg)
+ {
+ if( fActivate != 0 )
+ {
+ Control ctrl = GetNextControl(this,true);//first
+ if( ModifierKeys == Keys.Shift )
+ ctrl = GetNextControl(ctrl,false );//last
+
+ if( ctrl != null ) ctrl.Select();
+ this.Focus();
+ }
+ }
+
+ public virtual Int32 HasFocusIO()
+ {
+ return this.ContainsFocus ? 0 : 1; //S_OK : S_FALSE;
+ }
+
+ ///
+ /// Called by explorer to process keyboard events. Undersatands Tab and F6.
+ ///
+ ///
+ /// S_OK if message was processed, S_FALSE otherwise.
+ public virtual Int32 TranslateAcceleratorIO(ref MSG msg)
+ {
+ if( msg.message == 0x100 )//WM_KEYDOWN
+ if( msg.wParam == (uint)Keys.Tab || msg.wParam == (uint)Keys.F6 )//keys used by explorer to navigate from control to control
+ if( SelectNextControl(
+ ActiveControl,
+ ModifierKeys == Keys.Shift ? false : true,
+ true,
+ true,
+ false )
+ )
+ return 0;//S_OK
+
+ return 1;//S_FALSE
+ }
+
+ #endregion
+
+ #region EventHandlers
+
+ ///
+ /// Override this method to handle ExplorerAttached event.
+ ///
+ ///
+ protected virtual void OnExplorerAttached(EventArgs ea)
+ {
+ if ( ExplorerAttached != null )
+ ExplorerAttached(this, ea);
+ }
+
+ ///
+ /// Notifies explorer of focus change.
+ ///
+ protected override void OnGotFocus(System.EventArgs e)
+ {
+ base.OnGotFocus(e);
+ BandObjectSite.OnFocusChangeIS(this as IInputObject, 1);
+ }
+ ///
+ /// Notifies explorer of focus change.
+ ///
+ protected override void OnLostFocus(System.EventArgs e)
+ {
+ base.OnLostFocus(e);
+ if( ActiveControl == null )
+ BandObjectSite.OnFocusChangeIS(this as IInputObject, 0);
+ }
+
+ #endregion
+
+ #region COM_Bookkeeping
+
+ ///
+ /// Called when derived class is registered as a COM server.
+ ///
+ [ComRegisterFunctionAttribute]
+ public static void Register(Type t)
+ {
+ string guid = t.GUID.ToString("B");
+
+ RegistryKey rkClass = Registry.ClassesRoot.CreateSubKey(@"CLSID\"+guid );
+ RegistryKey rkCat = rkClass.CreateSubKey("Implemented Categories");
+
+ BandObjectAttribute[] boa = (BandObjectAttribute[])t.GetCustomAttributes(
+ typeof(BandObjectAttribute),
+ false );
+
+ string name = t.Name;
+ string help = t.Name;
+ BandObjectStyle style = 0;
+ if( boa.Length == 1 )
+ {
+ if( boa[0].Name != null )
+ name = boa[0].Name;
+
+ if( boa[0].HelpText != null )
+ help = boa[0].HelpText;
+
+ style = boa[0].Style;
+ }
+
+ rkClass.SetValue(null, name );
+ rkClass.SetValue("MenuText", name );
+ rkClass.SetValue("HelpText", help );
+
+ if( 0 != (style & BandObjectStyle.Vertical) )
+ rkCat.CreateSubKey("{00021493-0000-0000-C000-000000000046}");
+
+ if( 0 != (style & BandObjectStyle.Horizontal) )
+ rkCat.CreateSubKey("{00021494-0000-0000-C000-000000000046}");
+
+ if( 0 != (style & BandObjectStyle.TaskbarToolBar) )
+ rkCat.CreateSubKey("{00021492-0000-0000-C000-000000000046}");
+
+ if( 0 != (style & BandObjectStyle.ExplorerToolbar) )
+ Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Internet Explorer\Toolbar").SetValue(guid,name);
+
+ }
+
+ ///
+ /// Called when derived class is unregistered as a COM server.
+ ///
+ [ComUnregisterFunctionAttribute]
+ public static void Unregister(Type t)
+ {
+ string guid = t.GUID.ToString("B");
+ BandObjectAttribute[] boa = (BandObjectAttribute[])t.GetCustomAttributes(
+ typeof(BandObjectAttribute),
+ false );
+
+ BandObjectStyle style = 0;
+ if( boa.Length == 1 ) style = boa[0].Style;
+
+ if( 0 != (style & BandObjectStyle.ExplorerToolbar) )
+ Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Internet Explorer\Toolbar").DeleteValue(guid,false);
+
+ Registry.ClassesRoot.CreateSubKey(@"CLSID").DeleteSubKeyTree(guid);
+ }
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Title of band object. Displayed at the left or on top of the band object.
+ ///
+ [Browsable(true)]
+ [DefaultValue("")]
+ public String Title
+ {
+ get
+ {
+ return _title;
+ }
+ set
+ {
+ _title = value;
+ }
+ }
+
+ ///
+ /// Minimum size of the band object. Default value of -1 sets no minimum constraint.
+ ///
+ [Browsable(true)]
+ [DefaultValue(typeof(Size), "-1,-1")]
+ public Size MinSize
+ {
+ get
+ {
+ return _minSize;
+ }
+ set
+ {
+ _minSize = value;
+ }
+ }
+
+ ///
+ /// Maximum size of the band object. Default value of -1 sets no maximum constraint.
+ ///
+ [Browsable(true)]
+ [DefaultValue(typeof(Size), "-1,-1")]
+ public Size MaxSize
+ {
+ get
+ {
+ return _maxSize;
+ }
+ set
+ {
+ _maxSize = value;
+ }
+ }
+
+ ///
+ /// Says that band object's size must be multiple of this size. Defauilt value of -1 does not set this constraint.
+ ///
+ [Browsable(true)]
+ [DefaultValue(typeof(Size), "-1,-1")]
+ public Size IntegralSize
+ {
+ get
+ {
+ return _integralSize;
+ }
+ set
+ {
+ _integralSize = value;
+ }
+ }
+
+ #endregion
+
+ #region Member Variables
+
+ ///
+ /// This event is fired after reference to hosting explorer is retreived and stored in Explorer property.
+ ///
+ public event EventHandler ExplorerAttached;
+
+ protected WebBrowserClass Explorer;
+ protected IInputObjectSite BandObjectSite;
+
+ private bool _compositionEnabled = true;
+ private String _title;
+ private Size _minSize = new Size(-1, -1);
+ private Size _integralSize = new Size(-1, -1);
+ private Size _maxSize = new Size(-1, -1);
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Deskband/BandObjectBase/BandObject.csproj b/Deskband/BandObjectBase/BandObject.csproj
new file mode 100644
index 0000000..488dc6f
--- /dev/null
+++ b/Deskband/BandObjectBase/BandObject.csproj
@@ -0,0 +1,157 @@
+
+
+ Local
+ 9.0.30729
+ 2.0
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}
+ Debug
+ AnyCPU
+
+
+
+
+ Foo.BandObject
+ BandObjects.snk
+ JScript
+ Grid
+ IE50
+ false
+ Library
+ Foo.Deskband.BandObject
+
+
+
+
+ 0.0
+
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+ ..\..\Target\Debug\
+ false
+ 285212672
+ false
+
+
+ DEBUG;TRACE
+
+
+ true
+ 4096
+ false
+ false
+ false
+ false
+ 4
+ full
+ prompt
+
+
+ ..\..\Target\Release\
+ false
+ 285212672
+ false
+
+
+ TRACE
+
+
+ false
+ 4096
+ true
+ false
+ false
+ false
+ 4
+ none
+ prompt
+
+
+
+ System
+
+
+ System.Drawing
+
+
+ System.Windows.Forms
+
+
+
+
+ Code
+
+
+ UserControl
+
+
+ Code
+
+
+ BandObject.cs
+ Designer
+
+
+
+
+ False
+ .NET Framework 2.0 %28x86%29
+ true
+
+
+ False
+ .NET Framework 3.0 %28x86%29
+ false
+
+
+ False
+ .NET Framework 3.5
+ false
+
+
+
+
+ {EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}
+ 1
+ 1
+ 0
+ tlbimp
+ False
+
+
+
+
+
+
+
+
+
+ "$(FrameworkSDKDir)bin\gacutil.exe" /if "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)"
+"$(FrameworkSDKDir)bin\gacutil.exe" /if "$(SolutionDir)target\$(ConfigurationName)\Interop.SHDocVw.dll"
+
+
+
\ No newline at end of file
diff --git a/Deskband/BandObjectBase/BandObject.resx b/Deskband/BandObjectBase/BandObject.resx
new file mode 100644
index 0000000..ff31a6d
--- /dev/null
+++ b/Deskband/BandObjectBase/BandObject.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Deskband/BandObjectBase/BandObjectBase.sln b/Deskband/BandObjectBase/BandObjectBase.sln
new file mode 100644
index 0000000..09953a4
--- /dev/null
+++ b/Deskband/BandObjectBase/BandObjectBase.sln
@@ -0,0 +1,55 @@
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BandObjectLib", "BandObjectLib.csproj", "{BDB3B670-A17B-483E-954C-52FC2B6FF9D3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RegisterLib", "RegisterLib\RegisterLib.vcproj", "{E35915FE-ED91-4AE5-B566-F269CD854498}"
+ ProjectSection(ProjectDependencies) = postProject
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3} = {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(TeamFoundationVersionControl) = preSolution
+ SccNumberOfProjects = 3
+ SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
+ SccTeamFoundationServer = http://myhome.romischer.com:8080/
+ SccLocalPath0 = .
+ SccProjectUniqueName1 = BandObjectLib.csproj
+ SccLocalPath1 = .
+ SccProjectUniqueName2 = RegisterLib\\RegisterLib.vcproj
+ SccProjectName2 = RegisterLib
+ SccLocalPath2 = RegisterLib
+ EndGlobalSection
+ 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
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Win32.ActiveCfg = Release|Any CPU
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Debug|Any CPU.ActiveCfg = Debug|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Debug|Win32.Build.0 = Debug|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Release|Any CPU.ActiveCfg = Release|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Release|Win32.ActiveCfg = Release|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Deskband/BandObjectBase/BandObjects.snk b/Deskband/BandObjectBase/BandObjects.snk
new file mode 100644
index 0000000..87ebce5
Binary files /dev/null and b/Deskband/BandObjectBase/BandObjects.snk differ
diff --git a/Deskband/BandObjectBase/ComInterop.cs b/Deskband/BandObjectBase/ComInterop.cs
new file mode 100644
index 0000000..f09d526
--- /dev/null
+++ b/Deskband/BandObjectBase/ComInterop.cs
@@ -0,0 +1,246 @@
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+
+namespace Foo.Deskband.BandObject
+{
+
+ abstract class ExplorerGUIDs
+ {
+ public static readonly Guid IID_IWebBrowserApp = new Guid("{0002DF05-0000-0000-C000-000000000046}");
+ public static readonly Guid IID_IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}");
+ }
+
+ [Flags]
+ public enum DBIM : uint
+ {
+ MINSIZE = 0x0001,
+ MAXSIZE = 0x0002,
+ INTEGRAL = 0x0004,
+ ACTUAL = 0x0008,
+ TITLE = 0x0010,
+ MODEFLAGS = 0x0020,
+ BKCOLOR = 0x0040,
+ }
+
+ [Flags]
+ public enum DBIMF : uint
+ {
+ NORMAL = 0x0001,
+ FIXED = 0x0002,
+ FIXEDBMP = 0x0004,
+ VARIABLEHEIGHT = 0x0008,
+ UNDELETEABLE = 0x0010,
+ DEBOSSED = 0x0020,
+ BKCOLOR = 0x0040,
+ USECHEVRON = 0x0080,
+ BREAK = 0x0100,
+ ADDTOFRONT = 0x0200,
+ TOPALIGN = 0x0400,
+ NOGRIPPER = 0x0800,
+ ALWAYSGRIPPER = 0x1000,
+ NOMARGINS = 0x2000,
+ }
+
+ [Flags]
+ public enum DBIF : uint
+ {
+ VIEWMODE_NORMAL = 0x0000,
+ VIEWMODE_VERTICAL = 0x0001,
+ VIEWMODE_FLOATING = 0x0002,
+ VIEWMODE_TRANSPARENT = 0x0004
+ }
+
+ [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]
+ public struct DESKBANDINFO
+ {
+ public DBIM dwMask;
+ public Point ptMinSize;
+ public Point ptMaxSize;
+ public Point ptIntegral;
+ public Point ptActual;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)]
+ public String wszTitle;
+ public DBIMF dwModeFlags;
+ public Int32 crBkgnd;
+ };
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct CMINVOKECOMMANDINFO
+ {
+ uint cbSize;
+ uint fMask;
+ IntPtr hwnd;
+ string lpVerb;
+ string lpParameters;
+ string lpDirectory;
+ int nShow;
+ uint dwHotKey;
+ IntPtr hIcon;
+ };
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")]
+ public interface IObjectWithSite
+ {
+ void SetSite([In ,MarshalAs(UnmanagedType.IUnknown)] Object pUnkSite);
+ void GetSite(ref Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out Object ppvSite);
+ }
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("00000114-0000-0000-C000-000000000046")]
+ public interface IOleWindow
+ {
+ void GetWindow(out System.IntPtr phwnd);
+ void ContextSensitiveHelp([In] bool fEnterMode);
+ }
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("012dd920-7b26-11d0-8ca9-00a0c92dbfe8")]
+ public interface IDockingWindow
+ {
+ void GetWindow(out System.IntPtr phwnd);
+ void ContextSensitiveHelp([In] bool fEnterMode);
+
+ void ShowDW([In] bool fShow);
+ void CloseDW([In] UInt32 dwReserved);
+ void ResizeBorderDW(
+ IntPtr prcBorder,
+ [In, MarshalAs(UnmanagedType.IUnknown)] Object punkToolbarSite,
+ bool fReserved);
+ }
+
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("EB0FE172-1A3A-11D0-89B3-00A0C90A90AC")]
+ public interface IDeskBand
+ {
+ void GetWindow(out System.IntPtr phwnd);
+ void ContextSensitiveHelp([In] bool fEnterMode);
+
+ void ShowDW([In] bool fShow);
+ void CloseDW([In] UInt32 dwReserved);
+
+ void ResizeBorderDW(
+ IntPtr prcBorder,
+ [In, MarshalAs(UnmanagedType.IUnknown)] Object punkToolbarSite,
+ bool fReserved);
+
+ void GetBandInfo(
+ UInt32 dwBandID,
+ UInt32 dwViewMode,
+ ref DESKBANDINFO pdbi);
+ }
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsDual)]
+ [Guid("79D16DE4-ABEE-4021-8D9D-9169B261D657")]
+ public interface IDeskBand2
+ {
+ void GetBandInfo(UInt32 dwBandID, UInt32 dwViewMode, ref DESKBANDINFO pdbi);
+
+ void CanRenderComposited(ref bool pfCanRenderComposited);
+
+ void GetCompositionState(ref bool pfCompositionEnabled);
+
+ void SetCompositionState([MarshalAs(UnmanagedType.Bool)] bool fCompositionEnabled);
+ }
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("0000010c-0000-0000-C000-000000000046")]
+ public interface IPersist
+ {
+ void GetClassID(out Guid pClassID);
+ }
+
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("00000109-0000-0000-C000-000000000046")]
+ public interface IPersistStream
+ {
+ void GetClassID(out Guid pClassID);
+
+ void IsDirty ();
+
+ void Load ([In, MarshalAs(UnmanagedType.Interface)] Object pStm);
+
+ void Save ([In, MarshalAs(UnmanagedType.Interface)] Object pStm,
+ [In] bool fClearDirty);
+
+ void GetSizeMax ([Out] out UInt64 pcbSize);
+ }
+
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
+ public interface _IServiceProvider
+ {
+ void QueryService(
+ ref Guid guid,
+ ref Guid riid,
+ [MarshalAs(UnmanagedType.Interface)] out Object Obj);
+ }
+
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("68284faa-6a48-11d0-8c78-00c04fd918b4")]
+ public interface IInputObject
+ {
+ void UIActivateIO(Int32 fActivate, ref MSG msg);
+
+ [PreserveSig]
+ //[return:MarshalAs(UnmanagedType.Error)]
+ Int32 HasFocusIO();
+
+ [PreserveSig]
+ Int32 TranslateAcceleratorIO(ref MSG msg);
+ }
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("000214e4-0000-0000-c000-000000000046")]
+ public interface IContextMenu
+ {
+ [PreserveSig()]
+ int QueryContextMenu(uint hmenu, uint indexMenu, int idCmdFirst, int idCmdLast, uint uFlags);
+ [PreserveSig()]
+ void InvokeCommand (IntPtr pici);
+ [PreserveSig()]
+ void GetCommandString(int idCmd, uint uFlags, int reserved, string name, int cchMax);
+ }
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("f1db8392-7331-11d0-8c99-00a0c92dbfe8")]
+ public interface IInputObjectSite
+ {
+ [PreserveSig]
+ Int32 OnFocusChangeIS( [MarshalAs(UnmanagedType.IUnknown)] Object punkObj, Int32 fSetFocus);
+ }
+
+ public struct POINT
+ {
+ public Int32 x;
+ public Int32 y;
+ }
+
+ public struct MSG
+ {
+ public IntPtr hwnd;
+ public UInt32 message;
+ public UInt32 wParam;
+ public Int32 lParam;
+ public UInt32 time;
+ public POINT pt;
+ }
+
+}
\ No newline at end of file
diff --git a/Deskband/BandObjectBase/RegisterLib/RegisterLib.vcproj b/Deskband/BandObjectBase/RegisterLib/RegisterLib.vcproj
new file mode 100644
index 0000000..f1975df
--- /dev/null
+++ b/Deskband/BandObjectBase/RegisterLib/RegisterLib.vcproj
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Deskband/DeskBand/AssemblyInfo.cs b/Deskband/DeskBand/AssemblyInfo.cs
new file mode 100644
index 0000000..4c31478
--- /dev/null
+++ b/Deskband/DeskBand/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// 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("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// 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 Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.0.0")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+//[assembly: AssemblyDelaySign(false)]
+//[assembly: AssemblyKeyFile(@"..\..\..\BandObjects.snk")]
+//[assembly: AssemblyKeyName("")]
diff --git a/Deskband/DeskBand/DeskBand.cs b/Deskband/DeskBand/DeskBand.cs
new file mode 100644
index 0000000..5feca0f
--- /dev/null
+++ b/Deskband/DeskBand/DeskBand.cs
@@ -0,0 +1,503 @@
+using System;
+using System.ComponentModel;
+using System.Windows.Forms;
+using System.Runtime.InteropServices;
+using System.Reflection;
+
+using Foo.Platform;
+using Foo.Deskband.BandObject;
+using Foo.ClientServices.GUIWPForms;
+using Microsoft.Win32;
+
+namespace Foo.Deskband.Deskband
+{
+ [Guid("AE07101B-46D4-4a98-AF68-0333EA26E113")]
+ [BandObject("Ooganizer", BandObjectStyle.Horizontal | BandObjectStyle.TaskbarToolBar, HelpText = "Tame the Chaos : Ooganizer")]
+ public class DeskBand : BandObjectBase
+ {
+ private Button btnLaunch;
+ private IContainer components;
+ private System.Threading.TimerCallback _clickTimerCallback;
+ private System.Threading.Timer _clickTimer;
+ private int _previousClick = 0;
+ private ContextMenuStrip contextMenuStrip;
+ private ToolStripMenuItem settingsToolStripMenuItem;
+ private ToolStripMenuItem aboutToolStripMenuItem;
+ private ToolStripMenuItem helpToolStripMenuItem;
+ private ToolStripMenuItem hideToolStripMenuItem;
+ private ToolStripMenuItem unloadToolStripMenuItem;
+ private ToolStripMenuItem showToolStripMenuItem;
+ private ToolStripSeparator toolStripWorkspaceOptionSeparator;
+ private MouseButtons _previousClickMouseButton = MouseButtons.None;
+
+ // GUI Access Object
+ GUIWPForms GetGUI{ get { return new GUIWPForms(); } }
+
+
+ public DeskBand()
+ {
+ AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnAssemblyResolve);
+ InitializeComponent();
+ InitializeClickTimer();
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (components != null)
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ private void InitializeClickTimer()
+ {
+ _clickTimerCallback = new System.Threading.TimerCallback(SingleClickCallback);
+ }
+
+ #region Component Designer generated code
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.btnLaunch = new System.Windows.Forms.Button();
+ this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.unloadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.hideToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.showToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripWorkspaceOptionSeparator = new System.Windows.Forms.ToolStripSeparator();
+ this.contextMenuStrip.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // btnLaunch
+ //
+ this.btnLaunch.BackColor = System.Drawing.SystemColors.ControlText;
+ this.btnLaunch.ContextMenuStrip = this.contextMenuStrip;
+ this.btnLaunch.FlatStyle = System.Windows.Forms.FlatStyle.System;
+ this.btnLaunch.Font = new System.Drawing.Font("Forte", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.btnLaunch.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.btnLaunch.Location = new System.Drawing.Point(0, 0);
+ this.btnLaunch.Margin = new System.Windows.Forms.Padding(0);
+ this.btnLaunch.Name = "btnLaunch";
+ this.btnLaunch.Size = new System.Drawing.Size(24, 24);
+ this.btnLaunch.TabIndex = 0;
+ this.btnLaunch.TabStop = false;
+ this.btnLaunch.Text = "O";
+ this.btnLaunch.UseVisualStyleBackColor = false;
+ this.btnLaunch.HandleCreated += new System.EventHandler(this.btnLaunch_HandleCreated);
+ this.btnLaunch.HandleDestroyed += new System.EventHandler(this.btnLaunch_HandleDestroyed);
+ this.btnLaunch.Click += new System.EventHandler(this.btnLaunch_Click);
+ this.btnLaunch.MouseClick += new System.Windows.Forms.MouseEventHandler(this.btnLaunch_MouseClick);
+ this.btnLaunch.MouseDown += new System.Windows.Forms.MouseEventHandler(this.btnLaunch_MouseDown);
+ this.btnLaunch.MouseUp += new System.Windows.Forms.MouseEventHandler(this.btnLaunch_MouseUp);
+ //
+ // contextMenuStrip
+ //
+ this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.hideToolStripMenuItem,
+ this.unloadToolStripMenuItem,
+ this.showToolStripMenuItem,
+ this.toolStripWorkspaceOptionSeparator,
+ this.settingsToolStripMenuItem,
+ this.helpToolStripMenuItem,
+ this.aboutToolStripMenuItem});
+ this.contextMenuStrip.Name = "contextMenuStrip";
+ this.contextMenuStrip.Size = new System.Drawing.Size(153, 164);
+ this.contextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuStrip_Opening);
+ //
+ // settingsToolStripMenuItem
+ //
+ this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
+ this.settingsToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
+ this.settingsToolStripMenuItem.Text = "Settings";
+ this.settingsToolStripMenuItem.Click += new System.EventHandler(this.settingsToolStripMenuItem_Click);
+ //
+ // aboutToolStripMenuItem
+ //
+ this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem";
+ this.aboutToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
+ this.aboutToolStripMenuItem.Text = "About";
+ this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click);
+ //
+ // helpToolStripMenuItem
+ //
+ this.helpToolStripMenuItem.Name = "helpToolStripMenuItem";
+ this.helpToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
+ this.helpToolStripMenuItem.Text = "Help";
+ //
+ // unloadToolStripMenuItem
+ //
+ this.unloadToolStripMenuItem.Name = "unloadToolStripMenuItem";
+ this.unloadToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
+ this.unloadToolStripMenuItem.Text = "Unload";
+ this.unloadToolStripMenuItem.Click += new System.EventHandler(this.unloadToolStripMenuItem_Click);
+ //
+ // hideToolStripMenuItem
+ //
+ this.hideToolStripMenuItem.Name = "hideToolStripMenuItem";
+ this.hideToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
+ this.hideToolStripMenuItem.Text = "Hide";
+ this.hideToolStripMenuItem.Click += new System.EventHandler(this.hideToolStripMenuItem_Click);
+ //
+ // showToolStripMenuItem
+ //
+ this.showToolStripMenuItem.Name = "showToolStripMenuItem";
+ this.showToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
+ this.showToolStripMenuItem.Text = "Show";
+ this.showToolStripMenuItem.Click += new System.EventHandler(this.showToolStripMenuItem_Click);
+ //
+ // toolStripWorkspaceOptionSeparator
+ //
+ this.toolStripWorkspaceOptionSeparator.Name = "toolStripWorkspaceOptionSeparator";
+ this.toolStripWorkspaceOptionSeparator.Size = new System.Drawing.Size(149, 6);
+ //
+ // DeskBand
+ //
+ this.BackColor = System.Drawing.SystemColors.ControlText;
+ this.Controls.Add(this.btnLaunch);
+ this.ForeColor = System.Drawing.SystemColors.ControlText;
+ this.MaxSize = new System.Drawing.Size(24, 24);
+ this.MinSize = new System.Drawing.Size(24, 24);
+ this.Name = "DeskBand";
+ this.Title = "";
+ this.contextMenuStrip.ResumeLayout(false);
+ this.ResumeLayout(false);
+
+ }
+ #endregion
+
+ #region Other Handlers
+
+ private void btnLaunch_HandleCreated(object sender, EventArgs e)
+ {
+ //m_gui = new GUIWPForms();
+ //MessageBox.Show("btnLaunch_Created is called!");
+ }
+
+ private void btnLaunch_HandleDestroyed(object sender, EventArgs e)
+ {
+ //m_gui = null;
+ //MessageBox.Show("btnLaunch_Destroyed is called!");
+ }
+
+ #endregion
+
+ #region Button Click Handlers
+
+ private void btnLaunch_MouseClick(object sender, MouseEventArgs e)
+ {
+
+ }
+
+ private void SingleClickCallback(Object arg)
+ {
+ switch (((MouseEventArgs)arg).Button)
+ {
+ case MouseButtons.Left:
+ {
+ //MessageBox.Show("Left Click");
+
+ try
+ {
+ GetGUI.LaunchArtifactWall(this.Handle);
+ }
+ catch (Exception e)
+ {
+ MessageBox.Show(e.Message);
+ }
+
+ //LaunchArtifactWall();
+
+ break;
+ }
+ case MouseButtons.Right:
+ {
+ //LaunchContextMenu((MouseEventArgs)arg);
+
+ break;
+ }
+ case MouseButtons.Middle:
+ {
+ // TODO - Handle middle button ... if desired
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ private void DoubleClickCallback(MouseEventArgs args)
+ {
+ switch (args.Button)
+ {
+ case MouseButtons.Left:
+ {
+ try
+ {
+ GetGUI.LaunchWorkspaceSelector(this.Handle);
+ }
+ catch (Exception e)
+ {
+ MessageBox.Show(e.Message);
+ }
+
+ //LaunchWorkspaceSelector();
+
+ break;
+ }
+ case MouseButtons.Right:
+ {
+ // TODO - Handle right button double click ... if desired
+
+ break;
+ }
+ case MouseButtons.Middle:
+ {
+ // TODO - Handle middle button double click ... if desired
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ private void LaunchContextMenu(MouseEventArgs args)
+ {
+ contextMenuStrip.Show(PointToScreen(args.Location));
+ }
+
+ private void btnLaunch_Click(object sender, EventArgs e)
+ {
+
+ }
+
+ private void btnLaunch_MouseDown(object sender, MouseEventArgs e)
+ {
+ // Do not remove this handler ... it seems to quiet down the taskbar context menu
+ // so we can do our own context menu
+ }
+
+ private void btnLaunch_MouseUp(object sender, MouseEventArgs e)
+ {
+ int now = System.Environment.TickCount;
+
+ if ((now - _previousClick) <= SystemInformation.DoubleClickTime &&
+ e.Button == _previousClickMouseButton)
+ {
+ // Cancel click timer ... we've got a double click instead
+ _clickTimer.Change(System.Threading.Timeout.Infinite,
+ System.Threading.Timeout.Infinite);
+
+ DoubleClickCallback(e);
+
+ _previousClick = 0;
+ }
+ else
+ {
+ _previousClick = now;
+ _previousClickMouseButton = e.Button;
+
+ // Fire the OnClick event after the DoubleClickTime so that double-click handling gets a chance
+ _clickTimer = new System.Threading.Timer(_clickTimerCallback,
+ (Object)e,
+ (int)(SystemInformation.DoubleClickTime * 1.3),
+ System.Threading.Timeout.Infinite);
+ }
+ }
+
+ #endregion
+
+ ///
+ /// Assembly Resolve Handler for entire Component
+ ///
+ static System.Reflection.Assembly OnAssemblyResolve(object sender, ResolveEventArgs args)
+ {
+
+ string installPath = "";
+ RegistryKey RootKey = Registry.LocalMachine.OpenSubKey("Software\\Ooganizer", false);
+ if (RootKey != null)
+ {
+ object keyvalue = RootKey.GetValue("InstallPath");;
+ if ((keyvalue != null) && (keyvalue.ToString() != ""))
+ installPath = keyvalue.ToString();
+ }
+
+ string[] asmName = args.Name.Split(',');
+ switch (asmName[0])
+ {
+ case "GUIWPForms":
+ return Assembly.LoadFile(installPath + @"GUIWPForms.dll", Assembly.GetExecutingAssembly().Evidence);
+
+ case "Platform":
+ return Assembly.LoadFile(installPath + @"Platform.dll", Assembly.GetExecutingAssembly().Evidence);
+
+ default:
+ return null;
+ }
+
+ //Assembly assembly = null;
+ //string[] asmName = args.Name.Split(',');
+ //string basePath = "";
+
+ //RegistryKey RootKey = Registry.LocalMachine.OpenSubKey("Software\\Ooganizer", false);
+ //if (RootKey != null)
+ //{
+ // object keyvalue = null;
+ // keyvalue = RootKey.GetValue("InstallPath");
+ // if ((keyvalue != null) && (keyvalue.ToString() != ""))
+ // basePath = keyvalue.ToString();
+ //}
+
+ //MessageBox.Show(System.Environment.CurrentDirectory);
+ ////MessageBox.Show(asmName[0]);
+ //switch (asmName[0])
+ //{
+ // case "GUIWPForms":
+ // assembly = Assembly.LoadFile(basePath + @"GUIWPForms.dll", Assembly.GetExecutingAssembly().Evidence);
+ // break;
+ // case "Platform":
+ // assembly = Assembly.LoadFile(basePath + @"Platform.dll", Assembly.GetExecutingAssembly().Evidence);
+ // break;
+ // default:
+ // break;
+ //}
+
+ //return assembly;
+ }
+
+ #region ContextMenu Handlers
+
+ private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
+ {
+ //string currentWorkspace = null;
+ //OoganizerState.WorkspaceState workspaceState = OoganizerState.WorkspaceState.Unloaded;
+
+ //using (OoganizerState oogyState = new OoganizerState())
+ //{
+ // currentWorkspace = oogyState.GetCurrentWorkspace();
+
+ // if (currentWorkspace != null)
+ // {
+ // workspaceState = oogyState.GetWorkspaceState(currentWorkspace);
+ // }
+ //}
+
+ //if (currentWorkspace == null)
+ //{
+ // // Hide these options when there is no workspace loaded
+ // this.hideToolStripMenuItem.Visible = false;
+ // this.unloadToolStripMenuItem.Visible = false;
+ // this.showToolStripMenuItem.Visible = false;
+ // this.toolStripWorkspaceOptionSeparator.Visible = false;
+ //}
+ //else
+ //{
+ // switch (workspaceState)
+ // {
+ // case OoganizerState.WorkspaceState.Hidden:
+ // this.hideToolStripMenuItem.Visible = false;
+ // this.unloadToolStripMenuItem.Visible = true;
+ // this.showToolStripMenuItem.Visible = true;
+ // this.toolStripWorkspaceOptionSeparator.Visible = true;
+
+ // break;
+
+ // case OoganizerState.WorkspaceState.Shown:
+ // this.hideToolStripMenuItem.Visible = true;
+ // this.unloadToolStripMenuItem.Visible = true;
+ // this.showToolStripMenuItem.Visible = false;
+ // this.toolStripWorkspaceOptionSeparator.Visible = true;
+
+ // break;
+
+ // default:
+ // // Otherwise hide workspace options
+ // this.hideToolStripMenuItem.Visible = false;
+ // this.unloadToolStripMenuItem.Visible = false;
+ // this.showToolStripMenuItem.Visible = false;
+ // this.toolStripWorkspaceOptionSeparator.Visible = false;
+
+ // break;
+ // }
+ //}
+ }
+
+ private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ // Display About Form ... Form should provide :
+ // * company and product version information
+ // * support website / phone number
+ MessageBox.Show("Ooganizer 1.0");
+ }
+
+ private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ // Display Settings Form ... Form should provide :
+ // * Settings
+ MessageBox.Show("Ooganizer Settings Form");
+ }
+
+ private void hideToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ //string currWorkspaceName = null;
+
+ //using (OoganizerState oogyState = new OoganizerState())
+ //{
+ // currWorkspaceName = oogyState.GetCurrentWorkspace();
+
+ // if (currWorkspaceName != null)
+ // {
+ // oogyState.HideWorkspace(currWorkspaceName);
+ // }
+ //}
+ }
+
+ private void showToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ //string currWorkspaceName = null;
+
+ //using (OoganizerState oogyState = new OoganizerState())
+ //{
+ // currWorkspaceName = oogyState.GetCurrentWorkspace();
+
+ // if (currWorkspaceName != null)
+ // {
+ // oogyState.ShowWorkspace(currWorkspaceName);
+ // }
+ //}
+ }
+
+ private void unloadToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ //string currWorkspaceName = null;
+
+ //using (OoganizerState oogyState = new OoganizerState())
+ //{
+ // currWorkspaceName = oogyState.GetCurrentWorkspace();
+
+ // if (currWorkspaceName != null)
+ // {
+ // string currentWorkspaceName = oogyState.GetCurrentWorkspace();
+
+ // if (currentWorkspaceName != null)
+ // {
+ // oogyState.UnloadWorkspace(currentWorkspaceName);
+ // }
+ // }
+ //}
+ }
+
+ #endregion
+
+
+ }
+}
diff --git a/Deskband/DeskBand/DeskBand.csproj b/Deskband/DeskBand/DeskBand.csproj
new file mode 100644
index 0000000..79a58a5
--- /dev/null
+++ b/Deskband/DeskBand/DeskBand.csproj
@@ -0,0 +1,174 @@
+
+
+ Local
+ 9.0.30729
+ 2.0
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}
+ Debug
+ AnyCPU
+
+
+
+
+ Foo.DeskBand
+ MyKeyFile.SNK
+ JScript
+ Grid
+ IE50
+ false
+ Library
+ Foo.Deskband.Deskband
+
+
+
+
+ 0.0
+
+
+ publish\
+ true
+ Disk
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ 0
+ 1.0.0.%2a
+ false
+ false
+ true
+ true
+
+
+
+
+
+
+
+
+ v3.5
+
+
+ ..\..\Target\Debug\
+ false
+ 285212672
+ false
+
+
+ DEBUG;TRACE
+
+
+ true
+ 4096
+ false
+ false
+ false
+ false
+ 4
+ full
+ prompt
+
+
+ ..\..\Target\Release\
+ false
+ 285212672
+ false
+
+
+ TRACE
+
+
+ false
+ 4096
+ true
+ false
+ false
+ false
+ 4
+ none
+ prompt
+
+
+
+ System
+
+
+ System.Data
+
+
+ System.Drawing
+
+
+
+ System.Windows.Forms
+
+
+ System.XML
+
+
+
+
+ Code
+
+
+ UserControl
+
+
+ True
+ True
+ Resources.resx
+
+
+ DeskBand.cs
+ Designer
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+
+
+ False
+ .NET Framework 2.0 %28x86%29
+ true
+
+
+ False
+ .NET Framework 3.0 %28x86%29
+ false
+
+
+ False
+ .NET Framework 3.5
+ false
+
+
+
+
+
+
+
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}
+ GUIWPForms
+
+
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}
+ Platform
+
+
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}
+ BandObject
+
+
+
+
+ "$(FrameworkSDKDir)bin\gacutil.exe" /uf "$(TargetName)"
+ "$(FrameworkSDKDir)bin\gacutil.exe" /if "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)"
+"$(FrameworkDir)\regasm.exe" "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" tlb:$(TargetName).tlb /codebase
+
+
\ No newline at end of file
diff --git a/Deskband/DeskBand/DeskBand.resx b/Deskband/DeskBand/DeskBand.resx
new file mode 100644
index 0000000..bd3ae11
--- /dev/null
+++ b/Deskband/DeskBand/DeskBand.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
\ No newline at end of file
diff --git a/Deskband/DeskBand/DeskBand.sln b/Deskband/DeskBand/DeskBand.sln
new file mode 100644
index 0000000..bc198aa
--- /dev/null
+++ b/Deskband/DeskBand/DeskBand.sln
@@ -0,0 +1,91 @@
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeskBand", "DeskBand.csproj", "{ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}"
+ ProjectSection(ProjectDependencies) = postProject
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3} = {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Register", "Register\Register.vcproj", "{E35915FE-ED91-4AE5-B566-F269CD854498}"
+ ProjectSection(ProjectDependencies) = postProject
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7} = {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BandObject", "..\BandObjectBase\BandObject.csproj", "{BDB3B670-A17B-483E-954C-52FC2B6FF9D3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RegisterLib", "..\BandObjectBase\RegisterLib\RegisterLib.vcproj", "{A6903D99-B950-4D1A-B715-0B808ED64376}"
+ ProjectSection(ProjectDependencies) = postProject
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3} = {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(TeamFoundationVersionControl) = preSolution
+ SccNumberOfProjects = 5
+ SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
+ SccTeamFoundationServer = http://myhome.romischer.com:8080/
+ SccLocalPath0 = .
+ SccProjectUniqueName1 = Register\\Register.vcproj
+ SccProjectName1 = Register
+ SccLocalPath1 = Register
+ SccProjectUniqueName2 = DeskBand.csproj
+ SccLocalPath2 = .
+ SccProjectUniqueName3 = ..\\BandObjectBase\\BandObject.csproj
+ SccProjectName3 = ../BandObjectBase
+ SccLocalPath3 = ..\\BandObjectBase
+ SccProjectUniqueName4 = ..\\BandObjectBase\\RegisterLib\\RegisterLib.vcproj
+ SccProjectName4 = ../BandObjectBase/RegisterLib
+ SccLocalPath4 = ..\\BandObjectBase\\RegisterLib
+ EndGlobalSection
+ 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
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Release|Win32.ActiveCfg = Release|Any CPU
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Debug|Any CPU.ActiveCfg = Debug|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Debug|Win32.Build.0 = Debug|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Release|Any CPU.ActiveCfg = Release|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Release|Win32.ActiveCfg = Release|Win32
+ {E35915FE-ED91-4AE5-B566-F269CD854498}.Release|Win32.Build.0 = Release|Win32
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Win32.ActiveCfg = Release|Any CPU
+ {A6903D99-B950-4D1A-B715-0B808ED64376}.Debug|Any CPU.ActiveCfg = Debug|Win32
+ {A6903D99-B950-4D1A-B715-0B808ED64376}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {A6903D99-B950-4D1A-B715-0B808ED64376}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {A6903D99-B950-4D1A-B715-0B808ED64376}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A6903D99-B950-4D1A-B715-0B808ED64376}.Debug|Win32.Build.0 = Debug|Win32
+ {A6903D99-B950-4D1A-B715-0B808ED64376}.Release|Any CPU.ActiveCfg = Release|Win32
+ {A6903D99-B950-4D1A-B715-0B808ED64376}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {A6903D99-B950-4D1A-B715-0B808ED64376}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {A6903D99-B950-4D1A-B715-0B808ED64376}.Release|Win32.ActiveCfg = Release|Win32
+ {A6903D99-B950-4D1A-B715-0B808ED64376}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Deskband/DeskBand/MyKeyFile.SNK b/Deskband/DeskBand/MyKeyFile.SNK
new file mode 100644
index 0000000..8bc8162
Binary files /dev/null and b/Deskband/DeskBand/MyKeyFile.SNK differ
diff --git a/Deskband/DeskBand/Properties/Resources.Designer.cs b/Deskband/DeskBand/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..855091e
--- /dev/null
+++ b/Deskband/DeskBand/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.Deskband.Deskband.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Foo.Deskband.Deskband.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Deskband/DeskBand/Properties/Resources.resx b/Deskband/DeskBand/Properties/Resources.resx
new file mode 100644
index 0000000..5ea0895
--- /dev/null
+++ b/Deskband/DeskBand/Properties/Resources.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Deskband/DeskBand/Register/Register.vcproj b/Deskband/DeskBand/Register/Register.vcproj
new file mode 100644
index 0000000..7a738d0
--- /dev/null
+++ b/Deskband/DeskBand/Register/Register.vcproj
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/GUILib/GUICommon.cs b/GUILib/GUICommon.cs
new file mode 100644
index 0000000..0e975d4
--- /dev/null
+++ b/GUILib/GUICommon.cs
@@ -0,0 +1,285 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Drawing;
+using System.Windows.Forms;
+using System.Diagnostics;
+
+// Ooganizer Namespaces
+using Foo.Platform;
+using Foo.Platform.Interacters;
+using Foo.Platform.Win32;
+
+namespace Foo.GUILib
+{
+ ///
+ /// This is the generic GUICommon Class, that serves us a generic implementation to
+ /// everyone as to isolate ourselves from OS Changes
+ ///
+ public class GUICommon
+ {
+ // Keep track of all the origianl window positions that go
+ // thru here, ~we delete them when position back to org position
+ // get's called.
+ private static Dictionary s_orgWindowPosMap;
+ private static bool s_bOutOfProc_UseBH = false;
+
+ // public properties
+ public static bool OutOfProc { get { return s_bOutOfProc_UseBH; } }
+
+ // keep track of Window Positions
+ static GUICommon()
+ {
+ s_orgWindowPosMap = new Dictionary();
+ }
+
+ ///
+ /// Performs a screen snapshot of the passed in window handle.
+ ///
+ /// Window to Snap
+ /// a window image
+ public static Image PerformSnapshot(IntPtr hWnd)
+ {
+ if (hWnd != IntPtr.Zero)
+ {
+ ScreenCapture screencap = new ScreenCapture();
+
+ if (Env.Theme == Env.Themes.AeroTheme)
+ return screencap.SaveWindowUsingFullScreenShotCrop(hWnd);
+ else
+ return screencap.SaveWindowUsingDCNBitBlt(hWnd, false);
+ }
+ return null;
+ }
+
+ ///
+ /// Positions a window in the center at Golden Ratio and takes a snapshot.
+ /// ~corner stone of our add workspace strategy
+ ///
+ /// handle to the window to manipulate
+ /// Set to true to use ButtonHook to Perform the action
+ public static Image PositionWindowToGoldenPosAndTakeSnapshot(IntPtr hWnd, bool bOutOfProc)
+ {
+ // use ButtonHook, Yes / No?
+ s_bOutOfProc_UseBH = bOutOfProc;
+
+ // First thing to do is to save the org position
+ RECT rect;
+ Win32Functions.GetWindowRect(hWnd, out rect);
+ s_orgWindowPosMap[hWnd] = rect;
+
+ // First we fade the window totally away
+ FadeWindow(hWnd, true);
+
+ // now we want to fade it out of the monitor center
+ // However using the golden ratio as the size
+ FadeWindowOutOfMonitorCenterInGoldenRatio(hWnd, rect);
+
+ // Make sure we are in position and drawing at this point,
+ // perform the snapshot and return
+ System.Threading.Thread.Sleep(10);
+
+ //PositionWindowBackToWhereItWas(hWnd);
+
+ Image image = PerformSnapshot(hWnd);
+ //image.Save(@"D:\Users\HPInvent\Desktop\Snapshot1.png", System.Drawing.Imaging.ImageFormat.Png);
+ //return null;
+
+ return image;
+ }
+
+ ///
+ /// Positions a window back to where it was prior to calling PositionWindowToGoldenPosAndTakeSnapshot().
+ /// ~Hence, you should call this after calling that function
+ ///
+ /// handle to the window to manipulate
+ /// Set to true to use ButtonHook to Perform the action
+ public static void PositionWindowBackToWhereItWas(IntPtr hWnd, bool bOutOfProc)
+ {
+ // use ButtonHook, Yes / No?
+ s_bOutOfProc_UseBH = bOutOfProc;
+
+ // try to retrieve the org value from the map
+ if (!s_orgWindowPosMap.ContainsKey(hWnd))
+ return;
+
+ RECT orgRect = s_orgWindowPosMap[hWnd];
+
+ // Set the Window totally invisible
+ SetAlphaTransparency(hWnd, 0);
+
+ // As part of the effect, wait a little
+ System.Threading.Thread.Sleep(60);
+
+ // Now just flat out position it back to where it was
+ Win32Functions.SetWindowPos(hWnd, IntPtr.Zero, orgRect.left, orgRect.top, orgRect.AsRectangle.Width, orgRect.AsRectangle.Height, (uint)SetWindowPosFlags.SWP_SHOWWINDOW);
+
+ // Now Fade the Window out
+ FadeWindow(hWnd, false);
+
+ //SetAlphaTransparency(hWnd, 0); // invisible
+ //SetAlphaTransparency(hWnd, 255); // visible
+
+ // since we positioned the window back to where it was,
+ // we no longer need to keep track of it's org position
+ s_orgWindowPosMap.Remove(hWnd);
+ }
+
+ ///
+ /// Use this generic function to set the transparency
+ ///
+ private static void SetAlphaTransparency(IntPtr hWnd, byte alpha)
+ {
+ if (s_bOutOfProc_UseBH)
+ BHInteracter.SetWindowTransparency(hWnd, alpha);
+ else
+ Win32_WrapperFunc.SetAlphaChannel(hWnd, alpha);
+ }
+
+ ///
+ /// The Golden Ratio (~1.618) is used for the Snapshot to give it the best look
+ ///
+ /// pass in th screen for which to calculate the ratio for
+ /// the width and height to achieve the best golden ratio for that screen
+ private static void CalculateGoldenRatio(Screen screen, out RECT rect)
+ {
+ const int _MAXHEIGHT = 1100; // max pleasing height
+ const double _fGoldenRatio = 1.618;
+ const double _fsafetybuffer = 10; // 10% just in case
+ // safety buffer for height/width
+
+ int maxHeight = screen.WorkingArea.Height;
+ int maxWidth = screen.WorkingArea.Width;
+
+ // is this a potrait screen?
+ bool bIsPortrait = maxHeight > maxWidth;
+
+ // calculated height and width
+ int height = 0;
+ int width = 0;
+
+ // Normal Screen
+ if (!bIsPortrait)
+ {
+ // calculated height and width;
+ height = maxHeight - (int)(((double)maxHeight / 100) * _fsafetybuffer);
+ width = (int)((double)height / _fGoldenRatio);
+ }
+ else // Portrait
+ {
+ width = maxWidth - (int)(((double)maxWidth / 100) * _fsafetybuffer);
+ height = (int)((double)width * _fGoldenRatio);
+ }
+
+ // Enforce that the height is not bigger than _MAXHEIGHT, anything bigger than
+ // that just look unpleasant.
+ if (height >= _MAXHEIGHT)
+ {
+ height = _MAXHEIGHT;
+ width = (int)((double)height / _fGoldenRatio);
+ }
+
+ // pass out the calculated height and width
+ rect.left = 0;
+ rect.top = 0;
+ rect.bottom = height;
+ rect.right = width;
+ }
+
+ ///
+ /// Use this to quickle fade a window
+ ///
+ /// Set to true to fade in, false to Fade out
+ private static void FadeWindow(IntPtr hWnd, bool bFadeIn)
+ {
+
+ // Stole Increment Fading from Buttonhook
+ const int LOWER_INCREMENT = 7;
+ const int MIDDLE_INCREMENT = 15;
+ const int UPPER_INCREMENT = 25;
+
+ // Increment Points *inverted*
+ const int LOWER_POINT = 60;
+ const int MIDDLE_POINT = 160;
+ const int UPPER_POINT = 230;
+
+ // Fade in or Fade out?
+ byte alpha = (!bFadeIn)? (byte)0 : (byte)255;
+ bool bDone = false;
+
+ if (!bFadeIn) // FadeOut
+ {
+ while (!bDone)
+ {
+ if (alpha >= UPPER_POINT)
+ {
+ alpha = 255; // just show the thing already
+ bDone = true;
+ }
+ else if (alpha <= LOWER_POINT)
+ alpha += LOWER_INCREMENT;
+ else if (alpha <= MIDDLE_POINT)
+ alpha += MIDDLE_INCREMENT;
+ else
+ alpha += UPPER_INCREMENT;
+
+ SetAlphaTransparency(hWnd, alpha);
+ System.Threading.Thread.Sleep(20);
+ }
+ }
+ else // FadeIn
+ {
+ while (!bDone)
+ {
+ if (alpha <= (255 - UPPER_POINT)) //25
+ {
+ alpha = 0; // just hide the thing already
+ bDone = true;
+ }
+ else if (alpha >= (255 - LOWER_POINT)) //195
+ alpha -= LOWER_INCREMENT;
+ else if (alpha >= (255 - MIDDLE_POINT)) // 95
+ alpha -= MIDDLE_INCREMENT;
+ else
+ alpha -= UPPER_INCREMENT;
+
+ SetAlphaTransparency(hWnd, alpha);
+ System.Threading.Thread.Sleep(20);
+ }
+ }
+ }
+
+ ///
+ /// Helper function to determine the monitor and it's center and
+ /// fade out the window there in GoldenRatio Siz
+ ///
+ private static void FadeWindowOutOfMonitorCenterInGoldenRatio(IntPtr hWnd, RECT orgRect)
+ {
+ // get the screen the original rect was mostly located
+ Screen screen = Screen.FromRectangle(orgRect.AsRectangle);
+
+ // now figure out the best rect to use for this screen
+ RECT goldenRect;
+ CalculateGoldenRatio(screen, out goldenRect);
+
+ // calculate where we must place the golden window
+ // (centering it on the screen)
+ Point pt = new Point();
+ pt.Y = (screen.Bounds.Height - goldenRect.AsRectangle.Height) / 2;
+ pt.X = (screen.Bounds.Width - goldenRect.AsRectangle.Width) / 2;
+
+ // Calculate the window center according to the screen
+ pt.Y = screen.Bounds.Top + pt.Y;
+ pt.X = screen.Bounds.Left + pt.X;
+
+ // Make the window totally transparent and show it in the golden ratio position
+ SetAlphaTransparency(hWnd, 0);
+ Win32Functions.SetWindowPos(hWnd, IntPtr.Zero, pt.X, pt.Y, goldenRect.AsRectangle.Width, goldenRect.AsRectangle.Height, (uint) SetWindowPosFlags.SWP_SHOWWINDOW);
+
+ // Now Fade the Window out
+ FadeWindow(hWnd, false);
+ }
+
+ }
+}
+
diff --git a/GUILib/GUILib.csproj b/GUILib/GUILib.csproj
new file mode 100644
index 0000000..48fbdd5
--- /dev/null
+++ b/GUILib/GUILib.csproj
@@ -0,0 +1,103 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {C1282050-455B-44F4-8520-1C005E38EFB2}
+ Library
+ Properties
+ Foo.GUILib
+ GUILib
+ v3.5
+ 512
+
+
+
+
+
+
+
+
+
+
+ true
+ MyKeyFile.SNK
+
+
+ true
+ full
+ false
+ ..\Target\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\Target\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ False
+ ..\Components\log4net.dll
+
+
+ 3.0
+
+
+ 3.0
+
+
+
+ 3.5
+
+
+
+ 3.5
+
+
+
+
+
+ 3.0
+
+
+ 3.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}
+ Platform
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GUILib/MyKeyFile.SNK b/GUILib/MyKeyFile.SNK
new file mode 100644
index 0000000..8bc8162
Binary files /dev/null and b/GUILib/MyKeyFile.SNK differ
diff --git a/GUILib/Properties/AssemblyInfo.cs b/GUILib/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0053aea
--- /dev/null
+++ b/GUILib/Properties/AssemblyInfo.cs
@@ -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("GUILib")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("GUILib")]
+[assembly: AssemblyCopyright("Copyright © 2009")]
+[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("451a4209-15d4-49ef-a70f-2cc6c6d524b5")]
+
+// 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")]
diff --git a/GUILib/ScreenCapture.cs b/GUILib/ScreenCapture.cs
new file mode 100644
index 0000000..92d4734
--- /dev/null
+++ b/GUILib/ScreenCapture.cs
@@ -0,0 +1,207 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Drawing;
+using System.Windows.Forms;
+using System.Reflection;
+
+using Foo.Platform;
+using Foo.Platform.Win32;
+
+namespace Foo.GUILib
+{
+
+ public class ScreenCapture
+ {
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// Saves a Window using a DC of the Full Screen, then crops the window out of the
+ /// full screen capture. We have to do this because SaveWindowUsingDCNBitBlt() doesn't
+ /// work for all programs that overwrite the glass area on Aero (like MS Office)
+ ///
+ ///
+ /// IMP! - This function will work on some multiple monitor configurations but currently NOT all!
+ /// If for example, the primary display is on the left and sec on the right, and the window is on the
+ /// right monitor, then all x and y values will be positive, (We currently only handle multiple monitors,
+ /// where one x or y value is negative!),
+ /// ~more calculations must be done for multiple x, multiple y positive configurations
+ ///
+ /// handle to a Window
+ public Image SaveWindowUsingFullScreenShotCrop(IntPtr hWnd)
+ {
+ try
+ {
+ // First get the Window Rect
+ RECT rectWnd;
+ Win32Functions.GetWindowRect(hWnd, out rectWnd);
+
+ // Now figure out which monitor the window is in
+ IntPtr hMonitor = Win32Functions.MonitorFromRect(ref rectWnd, (int)Win32_Constants.MONITOR_DEFAULTTONEAREST);
+
+ // Get the szDevice Name for the Monitor
+ MONITORINFOEX monitorinfoex = new MONITORINFOEX();
+ monitorinfoex.cbSize = Marshal.SizeOf(monitorinfoex);
+ if (!Win32Functions.GetMonitorInfo(hMonitor, ref monitorinfoex))
+ return null;
+
+ // Use szDevice to create a DC
+ IntPtr hDC = Win32Functions.CreateDC(monitorinfoex.szDeviceName, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
+
+ //Here we make a compatible device context in memory for screen device context.
+ IntPtr hMemDC = Win32Functions.CreateCompatibleDC(hDC);
+
+ // Let's get all the monitor dimensions we need
+ Rectangle rectDim = monitorinfoex.rcMonitor.AsRectangle;
+ int DisplayHeight = rectDim.Height;
+ int DisplayWidth = rectDim.Width;
+
+ //The .net way to retrieve dimensions
+ Screen screen = Screen.FromHandle(hWnd);
+
+ //We create a compatible bitmap of screen size using screen device context.
+ IntPtr hBitmap = Win32Functions.CreateCompatibleBitmap(hDC, DisplayWidth, DisplayHeight);
+
+ if (hBitmap != IntPtr.Zero)
+ {
+ //Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
+ IntPtr hOld = (IntPtr)Win32Functions.SelectObject(hMemDC, hBitmap);
+
+ //We copy the Bitmap to the memory device context.
+ Win32Functions.BitBlt(hMemDC, 0, 0, DisplayWidth, DisplayHeight, hDC, 0, 0, Win32_Constants.SRCCOPY);
+
+ //We select the old bitmap back to the memory device context.
+ Win32Functions.SelectObject(hMemDC, hOld);
+
+ //We delete the memory device context.
+ Win32Functions.DeleteDC(hMemDC);
+
+ //Delete the screen device context.
+ Win32Functions.DeleteDC(hDC);
+
+ //Image is created by Image bitmap handle and stored in local variable.
+ Image image = (Image)System.Drawing.Image.FromHbitmap(hBitmap);
+
+ // * For Debugging *
+ //string strFileNameNPathWExtPNG = (Env.GetSnapshotDirectory() + @"\" + hWnd.ToString() + ".png");
+ //image.Save(strFileNameNPathWExtPNG, System.Drawing.Imaging.ImageFormat.Png);
+
+ //Release the memory for compatible bitmap.
+ Win32Functions.DeleteObject(hBitmap);
+
+ ////
+ // Imp! - Now we want to crop the Window out of the Screen Image
+ // NOTE! - Here we convert the screen positions into the corresponding
+ // image position on that screen
+ ////
+ int height = rectWnd.AsRectangle.Height;
+ int width = rectWnd.AsRectangle.Width;
+
+ rectWnd.left = Math.Abs(rectWnd.left - screen.Bounds.Left);
+ rectWnd.right = rectWnd.left + width;
+
+ rectWnd.top = Math.Abs(rectWnd.top - screen.Bounds.Top);
+ rectWnd.bottom = rectWnd.top + height;
+
+ // Convert the Rectangle for .Net Use
+ Rectangle rectangleWnd = rectWnd.AsRectangle;
+
+ Bitmap bmpImage = new Bitmap(image);
+ Bitmap bmpCrop = bmpImage.Clone(rectangleWnd, bmpImage.PixelFormat);
+
+ //Bitmap bmpCrop = (Bitmap)image;
+ //bmpCrop = bmpCrop.Clone(rectangleWnd, bmpCrop.PixelFormat);
+
+ return (Image)bmpCrop;
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - Error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+
+ return null;
+ }
+
+ ///
+ /// Saves the Window using a DC, this works well for bUseClientDC = true, but doesn't
+ /// work when using the Window's DC because of Aero drawing via directx, the window frame
+ /// won't be in the image
+ ///
+ /// handle to a Window
+ /// true to use ClientDC, false to use WindowDC
+ public Image SaveWindowUsingDCNBitBlt(IntPtr hWnd, bool bUseClientDC)
+ {
+ try
+ {
+ SIZE size;
+ IntPtr hDC;
+ IntPtr hBitmap;
+ Image image;
+ RECT Rect = new RECT();
+
+ if (bUseClientDC)
+ Win32Functions.GetClientRect(hWnd, out Rect);
+ else
+ Win32Functions.GetWindowRect(hWnd, out Rect);
+
+ size.cx = (Rect.right - Rect.left);
+ size.cy = (Rect.bottom - Rect.top);
+
+ // TRY USING GetDCEx() - May actually do better
+ //hDC = Win32Functions.GetDCEx(hWnd);
+ if (bUseClientDC)
+ hDC = Win32Functions.GetDC(hWnd);
+ else
+ hDC = Win32Functions.GetWindowDC(hWnd);
+
+ //Here we make a compatible device context in memory for screen device context.
+ IntPtr hMemDC = Win32Functions.CreateCompatibleDC(hDC);
+
+ //We create a compatible bitmap of screen size using screen device context.
+ hBitmap = Win32Functions.CreateCompatibleBitmap(hDC, size.cx, size.cy);
+
+ if (hBitmap != IntPtr.Zero)
+ {
+ //Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
+ IntPtr hOld = (IntPtr)Win32Functions.SelectObject(hMemDC, hBitmap);
+
+ //We copy the Bitmap to the memory device context.
+ Win32Functions.BitBlt(hMemDC, 0, 0, size.cx, size.cy, hDC, 0, 0, Win32_Constants.SRCCOPY);
+
+ //We select the old bitmap back to the memory device context.
+ Win32Functions.SelectObject(hMemDC, hOld);
+
+ //We delete the memory device context.
+ Win32Functions.DeleteDC(hMemDC);
+
+ //We release the screen device context.
+ Win32Functions.ReleaseDC(hWnd, hDC);
+
+ //Image is created by Image bitmap handle and stored in local variable.
+ image = (Image)System.Drawing.Image.FromHbitmap(hBitmap);
+
+ // * For Debugging *
+ //string strFileNameNPathWExtPNG = (Env.GetSnapshotDirectory() + @"\" + hWnd.ToString() + ".png");
+ //image.Save(strFileNameNPathWExtPNG, System.Drawing.Imaging.ImageFormat.Png);
+
+ //Release the memory for compatible bitmap.
+ Win32Functions.DeleteObject(hBitmap);
+ return image;
+ }
+ else
+ {
+ Log.Error(string.Format("{0}() - hBitmap is Null, something is wrong", MethodBase.GetCurrentMethod().Name));
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - Error thrown", MethodBase.GetCurrentMethod().Name), e);
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/GUILib/WPFHelper.cs b/GUILib/WPFHelper.cs
new file mode 100644
index 0000000..c5d660c
--- /dev/null
+++ b/GUILib/WPFHelper.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Controls;
+using System.Windows.Media.Imaging;
+using System.Windows.Media;
+using System.Windows;
+
+namespace Foo.GUILib
+{
+ static public class WPFHelper
+ {
+ ///
+ /// Useful to create a simple wrapping tooltip for a wpf control
+ ///
+ ///
+ /// Set to 0 to leave default, else set to 0> to define max height
+ /// Set to 0 to leave default, else set to 0> to define max width
+ /// a ToolTip Object to assign to a control
+ public static ToolTip CreateNewStringToolTip(string strToolTipContent, int height, int width)
+ {
+ // Create the TextBlock
+ TextBlock tx = new TextBlock();
+ if(height > 0)
+ tx.Height = height;
+ if(width > 0)
+ tx.Width = width;
+ tx.TextWrapping = TextWrapping.Wrap;
+ tx.Text = strToolTipContent;
+
+ // Create the ToolTip with the TextBlock inside
+ ToolTip tt = new ToolTip();
+ tt.Content = strToolTipContent;
+ return tt;
+ }
+
+ ///
+ /// Useful if you want to know if the Mouse cursor is over the specified Wpf Window
+ /// (Uses windowsforms to do the calculations)
+ ///
+ /// true if the mouse cursor is over the specified form window, false otherwise
+ public static bool IsMouseCursorOverWPFormWindow(Window wpfWindow)
+ {
+ if (wpfWindow != null)
+ {
+ // Get the Point location of the mouse cursor
+ System.Drawing.Point point = System.Windows.Forms.Cursor.Position;
+
+ // Get the rect for the Navigation Form
+ Point wpfFormLeftTopPoint = new Point(wpfWindow.Left, wpfWindow.Top);
+ Size wpfFormSize = new Size(wpfWindow.Width, wpfWindow.Height);
+ Rect rect = new Rect(wpfFormLeftTopPoint, wpfFormSize);
+
+ // Return if the Mouse is over the Navigation Form
+ return (rect.Contains((double)point.X, (double)point.Y));
+ }
+ return false;
+ }
+
+ ///
+ /// For Dynamically Creating Text ComboBox Items
+ ///
+ /// Text Content to Display
+ /// object to tag to the menu item
+ ///
+ public static ComboBoxItem CreateAComboBoxItem(string strContent, object tag)
+ {
+ if (!String.IsNullOrEmpty(strContent) && (tag != null))
+ {
+ ComboBoxItem item = new ComboBoxItem();
+ item.Content = strContent;
+ item.Tag = tag;
+ return item;
+ }
+ return null;
+ }
+
+ ///
+ /// For dynamically creating Image sources, this function helps you to create an image out of
+ /// a Resource Uri. You can then assign this image to a 'Source' property on an image wpf object
+ ///
+ /// a valid relative Resource Uri String to an image
+ /// the output image's desired height
+ /// the output image's desired width
+ ///
+ public static Image CreateWPFImageFromRelativeResourceUri(string strRelativeResourceUri, int ImageHeight, int ImageWidth)
+ {
+ if (!String.IsNullOrEmpty(strRelativeResourceUri))
+ {
+ Image myImage = new Image();
+ BitmapImage image = new BitmapImage();
+ image.BeginInit();
+ image.UriSource = new Uri(strRelativeResourceUri, UriKind.Relative);
+ image.EndInit();
+ myImage.Stretch = Stretch.Fill;
+ myImage.Height = ImageHeight;
+ myImage.Width = ImageWidth;
+ myImage.Source = image;
+ return myImage;
+ }
+ return null;
+ }
+
+ }
+}
diff --git a/GUILib/WPFHiddenWindow.cs b/GUILib/WPFHiddenWindow.cs
new file mode 100644
index 0000000..c0fd561
--- /dev/null
+++ b/GUILib/WPFHiddenWindow.cs
@@ -0,0 +1,148 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows.Controls;
+using System.Windows.Media.Imaging;
+using System.Windows.Media;
+using System.Windows;
+using System.Windows.Interop;
+
+namespace Foo.GUILib
+{
+ ///
+ /// Class used to keep WPF Windows Hidden permanently.
+ /// Should be called by Performance WPF Window 'Hidden' loads
+ /// when constructed, and when loaded.
+ ///
+ /// Note: All WPFWindow's that use this class don't set certain properties on the
+ /// window until they are loaded and it's NOT a performance Cache window.
+ ///
+ public static class WPFHiddenWindow
+ {
+ private static Dictionary s_hWndToWindowMap = new Dictionary();
+
+ ///
+ /// * Core * 'Hiding' Function. Makes sure that the Window is and
+ /// stays hidden.
+ ///
+ /// a WPF window object
+ private static void HideWPFWindow(Window wpfWindow)
+ {
+ // Force Opacity
+ wpfWindow.WindowStyle = WindowStyle.None;
+ wpfWindow.Opacity = 0.0;
+ wpfWindow.ShowInTaskbar = false;
+ wpfWindow.ShowActivated = false;
+
+ // Force a tiny Window in top-left corner
+ wpfWindow.Width = 5;
+ wpfWindow.Height = 5;
+ wpfWindow.Top = 0;
+ wpfWindow.Left = 0;
+ wpfWindow.WindowStartupLocation = WindowStartupLocation.Manual;
+ }
+
+ ///
+ /// Call this to execute a Show() call on a wpfWindow Performance cache window. Returns true
+ /// if bPerformanceCache is true. This means that this Function did something to the window.
+ ///
+ /// a WPF window object
+ /// Pass in true, if this is a performance Cache window
+ /// true if bPerformanceCache is true, false otherwise
+ public static bool ExecuteShowOnAHiddenWindow(Window wpfWindow, bool bPerformanceCache)
+ {
+ if (bPerformanceCache)
+ {
+ HideWPFWindow(wpfWindow);
+ wpfWindow.Show();
+ wpfWindow.Hide();
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Call this in your WPFWindow's constructor. Returns true if bPerformanceCache is true.
+ /// This means that this Function did something to the window.
+ ///
+ /// a WPF window object
+ /// Pass in true, if this is a performance Cache window
+ /// true if bPerformanceCache is true, false otherwise
+ public static bool HiddenWindowConstructor(Window wpfWindow, bool bPerformanceCache)
+ {
+ if (bPerformanceCache)
+ {
+ HideWPFWindow(wpfWindow);
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Call this from your WPFWindow's OnLoad Event. Returns true if bPerformanceCache is true.
+ /// This means that this Function did something to the window.
+ ///
+ /// a WPF window object
+ /// Pass in true, if this is a performance Cache window
+ /// true if bPerformanceCache is true, false otherwise
+ public static bool HiddenWindowOnLoad(Window wpfWindow, bool bPerformanceCache)
+ {
+ if (bPerformanceCache)
+ {
+ HideWPFWindow(wpfWindow);
+
+ // Add Message Hook for performanceCache WPForm * To make sure it is always invisible *
+ WindowInteropHelper interop = new WindowInteropHelper(wpfWindow);
+ HwndSource source = HwndSource.FromHwnd(interop.Handle);
+ source.AddHook(new HwndSourceHook(MessageHook));
+ s_hWndToWindowMap[interop.Handle] = wpfWindow;
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Call this from your WPFWindow's Closing Event. Returns true if bPerformanceCache is true.
+ /// This means that this Function did something to the window.
+ ///
+ /// a WPF window object
+ /// Pass in true, if this is a performance Cache window
+ /// true if bPerformanceCache is true, false otherwise
+ public static bool HiddenWindowClosing(Window wpfWindow, bool bPerformanceCache)
+ {
+ if (s_hWndToWindowMap.ContainsValue(wpfWindow))
+ {
+ foreach (IntPtr hWnd in s_hWndToWindowMap.Keys)
+ {
+ if (s_hWndToWindowMap[hWnd] == wpfWindow)
+ {
+ s_hWndToWindowMap.Remove(hWnd);
+ break;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// This Message Hook is for the Hidden wpfForm that we use for better performance,
+ /// We want to make sure that it is never displayed *It can occur that explorer.exe can show it, without this hook*
+ /// ~i.e. when explorer.exe crashes, and get's restarted
+ ///
+ private static IntPtr MessageHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
+ {
+ // Get the Proper WPF Object and make sure it is Hidden
+ if (s_hWndToWindowMap.ContainsKey(hwnd))
+ {
+ Window wpfWindow = s_hWndToWindowMap[hwnd];
+ if (wpfWindow != null)
+ HideWPFWindow(wpfWindow);
+ }
+
+ handled = false;
+ return System.IntPtr.Zero;
+ }
+ }
+}
diff --git a/GUILib/app.config b/GUILib/app.config
new file mode 100644
index 0000000..b7db281
--- /dev/null
+++ b/GUILib/app.config
@@ -0,0 +1,3 @@
+
+
+
diff --git a/Hooks/ButtonHook/ButtonHook.cpp b/Hooks/ButtonHook/ButtonHook.cpp
new file mode 100644
index 0000000..1396732
--- /dev/null
+++ b/Hooks/ButtonHook/ButtonHook.cpp
@@ -0,0 +1,1153 @@
+// This is the main DLL file.
+
+#include "stdafx.h"
+#define DLLAPI_BUTTON_HOOK
+#include "ButtonHook.h"
+#include
+
+using namespace Ooganizer;
+
+#ifdef _DEBUG
+ #import "..\\..\\Target\\Debug\\Settings.tlb" raw_interfaces_only
+#else
+ #import "..\\..\\Target\\Release\\Settings.tlb" raw_interfaces_only
+#endif
+using namespace Settings;
+
+#ifdef _DEBUG
+ #import "..\\..\\Target\\Debug\\Platform.tlb" raw_interfaces_only
+#else
+ #import "..\\..\\Target\\Release\\Platform.tlb" raw_interfaces_only
+#endif
+using namespace Platform;
+
+#ifdef _DEBUG
+ #import "..\\..\\Target\\Debug\\ButtonWPForm.tlb"
+#else
+ #import "..\\..\\Target\\Release\\ButtonWPForm.tlb"
+#endif
+using namespace ButtonWPForm;
+
+////
+// ***** What type of Windows should have the Button *****
+////
+const DWORD WS_STYLES_TO_TEST_FOR = WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU;
+
+////
+// ***** Top-Level Dialogs *****
+////
+const DWORD WS_STYLES_TO_TEST_FOR_DIALOGS = WS_SYSMENU | WS_POPUP;
+
+//////////////////////////////////////////////////////////////////////
+//********************************************************************
+// Macros and typedefs
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+
+#define MSG_HOOK ( L"MSG_HOOK" )
+#define MSG_UNHOOK ( L"MSG_UNHOOK" )
+
+////
+// Each DLL instance (All Instances) need to keeps track of the following
+// Data members (these end up being the same values so no need to put them into the DS)
+////
+HINSTANCE s_hModule = NULL;
+UINT m_WMHook = NULL;
+UINT m_WMUnHook = NULL;
+
+// enum to send MSG_HOOK and MSG_UNHOOK
+typedef enum _MSG{_MSG_HOOK,_MSG_UNHOOK} MSG_;
+
+////
+// Each DLL instance (All instances not just the once whose window,
+// we'll hook into) will hold a pointer to it's own
+// CWHPaccess Object. (allowing it access to the Shared Data Segment)
+////
+CWHPaccess* s_ButtonHookAccess = NULL;
+
+////
+// Each DLL instanc needs to keep track of it's recently closed windows
+////
+#define NCLOSES_TO_TRACK 25
+// timeout values, we need to ignore activate messages for nTime when
+// we unhook to avoid rehooking again in processes that have multiple windows
+const int IGNORE_ACTIVATE_MESSAGE_TIMEOUT_MS = 150;
+struct RecentWindowsWTimeouts
+{
+ HWND hWnd;
+ DWORD dwTimeInserted;
+};
+RecentWindowsWTimeouts s_hRecentClosedWindows[NCLOSES_TO_TRACK] = {NULL,NULL};
+UINT s_HRecentListI = 0;
+
+//////////////////////////////////////////////////////////////////////
+// Func: InsertRecentClosedWindow()
+// Desc: Insert a recently closed window
+//////////////////////////////////////////////////////////////////////
+void InsertRecentClosedWindow(HWND hWnd)
+{
+ RecentWindowsWTimeouts recent;
+ recent.hWnd = hWnd;
+ recent.dwTimeInserted = GetTickCount();
+
+ s_hRecentClosedWindows[s_HRecentListI] = recent;
+ s_HRecentListI = s_HRecentListI + 1;
+
+ if(s_HRecentListI == NCLOSES_TO_TRACK)
+ s_HRecentListI = 0;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: FindRecentClosedWindow()
+// Desc: Find a recently closed window
+//////////////////////////////////////////////////////////////////////
+BOOL FindRecentClosedWindow(HWND hWnd)
+{
+ DWORD dwTickCount = GetTickCount();
+ for (UINT i = 0; i < s_HRecentListI; ++i)
+ {
+ if(s_hRecentClosedWindows[i].hWnd == hWnd)
+ {
+ DWORD diffTime = dwTickCount - s_hRecentClosedWindows[i].dwTimeInserted;
+ if(diffTime < IGNORE_ACTIVATE_MESSAGE_TIMEOUT_MS)
+ return true;
+ else
+ return false;
+ }
+ }
+ return false;
+}
+bool IsAWindowToHookInto(HWND hwnd);
+//////////////////////////////////////////////////////////////////////
+// Func: EnumProc()
+// Desc: Hook/Unhook all top level windows. Called for every top-level
+// Window on the screen.
+//
+// Prms: lParam, if true send Hook Message, false send UnHook Msg
+//
+// Retr: TRUE, always
+//////////////////////////////////////////////////////////////////////
+BOOL CALLBACK EnumProc( HWND hWnd, LPARAM lParam )
+{
+ switch (lParam)
+ {
+ case _MSG_HOOK:
+ if((m_WMHook >= 0xC000) && (m_WMHook <= 0xFFFF) &&
+ (IsAWindowToHookInto(hWnd)))
+ {
+ log(LOGGING_DEBUG, L"Sending m_WMHook to hWnd %u Msg %u", hWnd, m_WMHook);
+ SendMessage( hWnd, m_WMHook, 0, 0 );
+ }
+ break;
+
+ case _MSG_UNHOOK:
+ if((m_WMUnHook >= 0xC000) && (m_WMUnHook <= 0xFFFF) &&
+ /* Check if Window is hooked into */
+ ( s_ButtonHookAccess->FindHookedWnd(hWnd) == TRUE ))
+ {
+ log(LOGGING_DEBUG, L"Sending m_WMUnHook to hWnd %u Msg %u", hWnd, m_WMHook);
+ SendMessage( hWnd, m_WMUnHook, 0, 0 );
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: GetProcessNameFromPID()
+// Retr: Returns the process name in the buffer and true if everything went well,
+// false otherwise.
+//////////////////////////////////////////////////////////////////////
+bool GetProcessNameFromHWND(HWND hwnd, wchar_t strProcessNameBuf[MAX_PATH + 1])
+{
+ DWORD pid = NULL;
+ GetWindowThreadProcessId(hwnd,&pid);
+ HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid );
+
+ // Get the process name
+ if (NULL != hProcess )
+ GetModuleBaseName( hProcess, NULL, strProcessNameBuf, (MAX_PATH + 1));
+
+ CloseHandle(hProcess);
+ return true;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: IsWhiteListed()
+// Desc: Function allows us to Blacklist certain windows to not be
+// included when hooking the WinProcButton Hook.
+// a Window can be whitelisted either on Title or Type, passed in
+// thru the configuration
+//
+// Prms: hwnd, handle to a window we want to check
+//
+// Retr: true, if window is WhiteListed, false otherwise
+//////////////////////////////////////////////////////////////////////
+bool IsWhiteListed(HWND hwnd)
+{
+ wchar_t strBuf[MAX_PATH + 1] = {0};
+
+ if(GetProcessNameFromHWND(hwnd,strBuf))
+ {
+ _wcsupr_s(strBuf,MAX_PATH);
+ if(s_ButtonHookAccess->IsAllowedProcessName(strBuf))
+ return true;
+ }
+
+ if (GetWindowText(hwnd,strBuf,MAX_PATH))
+ {
+ _wcsupr_s(strBuf,MAX_PATH);
+ if(s_ButtonHookAccess->IsAllowedWindowsTitle(strBuf))
+ return true;
+ }
+
+ if(GetClassName(hwnd,strBuf,MAX_PATH))
+ {
+ _wcsupr_s(strBuf,MAX_PATH);
+ if(s_ButtonHookAccess->IsAllowedWindowsClass(strBuf))
+ return true;
+ }
+
+ return false;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: IsFileOpenOrFileSaveAsDialog()
+// Desc: We also hook into FileOpen and FileSaveAs Dialogs(), in order
+// to do so we compare the window class
+//
+// Retr: true, if dialog is of a fileopen/filesaveas class, false otherwise
+//////////////////////////////////////////////////////////////////////
+bool IsFileOpenOrFileSaveAsDialog(HWND hwnd)
+{
+ wchar_t strBuf[MAX_PATH + 1] = {0};
+ if(GetClassName(hwnd,strBuf,MAX_PATH))
+ {
+ _wcsupr_s(strBuf);
+ if(lstrcmp(strBuf, L"#32770") == 0)
+ return true;
+ }
+ return false;
+}
+//////////////////////////////////////////////////////////////////////
+// Strc: FileNameAndLocationStruct()
+// Desc: We use this to pass out location and file name by EnumFileNameAndLocationProc
+//////////////////////////////////////////////////////////////////////
+struct FileNameAndLocationStruct
+{
+ wchar_t location[MAX_PATH + 1];
+ wchar_t filename[MAX_PATH + 1];
+ wchar_t filetypes[MAX_PATH + 1];
+};
+//////////////////////////////////////////////////////////////////////
+// Func: EnumFileNameAndLocationProc()
+// Desc: Iterate all child windows and extract FileName and FileLocation
+//
+// Prms: lParam, a FileNameAndLocationStruct*
+//
+// Retr: TRUE, always
+//////////////////////////////////////////////////////////////////////
+BOOL CALLBACK EnumFileNameAndLocationProc( HWND hWnd, LPARAM lParam )
+{
+ wchar_t strWindowText[MAX_PATH + 1] = {0};
+ wchar_t strClassName[MAX_PATH + 1] = {0};
+ GetWindowText(hWnd, strWindowText, MAX_PATH);
+ GetClassName(hWnd, strClassName, MAX_PATH);
+
+ bool bContinue = false;
+ // We only care about the following 3 window classes
+ // all others continue iteration
+ if((lstrcmp(L"Edit", strClassName) == 0) ||
+ (lstrcmp(L"ComboBox", strClassName) == 0) ||
+ (lstrcmp(L"ToolbarWindow32", strClassName) == 0))
+ {
+ bContinue = true;
+ }
+
+ // skip this window
+ if(!bContinue)
+ return TRUE;
+
+ // passed in file struct pointer
+ FileNameAndLocationStruct* pstruct = (FileNameAndLocationStruct*) lParam;
+
+ // Stop if there is no window text
+ if(lstrlen(strWindowText) <= 0)
+ return TRUE;
+
+ // ignore any window texts that have an &
+ if(wcsstr(strWindowText, L"&"))
+ return TRUE;
+
+ // * Good for Debugging *
+ //log(LOGGING_DEBUG, L"Found Window Text - %s ", strWindowText);
+
+ // File Types Window Text (pass out in case it's needed later)
+ if(wcsstr(strWindowText, L"*."))
+ {
+ log(LOGGING_DEBUG, L"Found FileType Text %s", strWindowText);
+ lstrcpy(pstruct->filetypes,strWindowText);
+ return TRUE;
+ }
+
+ // Is this a location text
+ if(wcsstr(strWindowText, L": ")) // This could be very much English Windows Specific (or not?, should check)
+ {
+ // get the location of ": "
+ int i = 0;
+ wchar_t* pBegin = strWindowText;
+ for (; i < MAX_PATH; ++i)
+ {
+ if((*pBegin == L':') && (*(pBegin + 1) == L' '))
+ {
+ pBegin = pBegin + 2; // start after the ": "
+ break;
+ }
+ ++pBegin;
+ }
+
+ if(pBegin != NULL)
+ {
+ log(LOGGING_DEBUG, L"Found Location Text %s", pBegin);
+ lstrcpy(pstruct->location,pBegin);
+ }
+ return TRUE;
+ }
+
+ // illegal file name characters
+ wchar_t* illegalfilechars = L"\\/:*?\"<>|";
+ int illegalsize = lstrlen(illegalfilechars);
+
+ if(wcsstr(strWindowText,L"."))
+ {
+ // check to see if string contains any illegal
+ // file name characters
+ for(int i = 0; i < illegalsize; ++i)
+ {
+ wchar_t c[2] = {0};
+ c[0] = illegalfilechars[i];
+
+ // found illegal character, ignore string as file name
+ if(wcsstr(strWindowText,c))
+ return TRUE;
+ }
+
+ // Found a 100% file name string (it contains a '.')
+ log(LOGGING_DEBUG, L"Found FileName Text %s", strWindowText);
+ lstrcpy(pstruct->filename,strWindowText);
+ return TRUE;
+ }
+ else if(lstrlen(strWindowText) >= 1)
+ {
+ // check to see if string contains any illegal
+ // file name characters
+ for(int i = 0; i < illegalsize; ++i)
+ {
+ wchar_t c[2] = {0};
+ c[0] = illegalfilechars[i];
+
+ // found illegal character, ignore string as file name
+ if(wcsstr(strWindowText,c))
+ return TRUE;
+ }
+
+ // Found a possible Most likely file name string (must not contain a '.')
+ log(LOGGING_DEBUG, L"Found FileName Text %s", strWindowText);
+ lstrcpy(pstruct->filename,strWindowText);
+ return TRUE;
+ }
+
+ return TRUE;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: GetFileNameAndLocationStringValuesFromDialogWindow()
+// Desc: Iterates through all the child windows and get the values we need
+// and pass them back out
+//
+// Prms: hwnd, handle the fileOpen dialog
+// pCallerObj, WPFCaller object where we will write the retrieved information to
+//////////////////////////////////////////////////////////////////////
+bool GetFileNameAndLocationStringValuesFromDialogWindow(HWND hwnd, WPFCaller* pCallerObj)
+{
+ // Iterate all child Windows and parse all the texts, the enum function
+ // will do all the work
+ if(hwnd && ::IsWindow(hwnd))
+ {
+ // Clear any old values in the caller object
+ memset(pCallerObj->m_strFileNameLocationBuf, 0, sizeof(pCallerObj->m_strFileNameLocationBuf));
+ memset(pCallerObj->m_strFileTypesBuf, 0, sizeof(pCallerObj->m_strFileTypesBuf));
+
+ // Create temporary object to hold values
+ FileNameAndLocationStruct filenameAndLocation;
+ memset(filenameAndLocation.filename, 0, sizeof(filenameAndLocation.filename));
+ memset(filenameAndLocation.location, 0, sizeof(filenameAndLocation.location));
+ memset(filenameAndLocation.filetypes, 0, sizeof(filenameAndLocation.filetypes));
+
+ // Try to Resolve
+ log(LOGGING_DEBUG, L"About to call EnumFileNameAndLocationProc (EnumChildWindows)");
+ EnumChildWindows(hwnd, EnumFileNameAndLocationProc, (LPARAM) &filenameAndLocation );
+
+ // get resolving lengths
+ int nLen1 = lstrlen(filenameAndLocation.filename);
+ int nLen2 = lstrlen(filenameAndLocation.location);
+ int nLen3 = lstrlen(filenameAndLocation.filetypes);
+
+ // Handle errors * Good for Debugging *
+ /*
+ if(nLen1 == 0)
+ log(LOGGING_DEBUG, L"Error resolving - FileName - FileOpen or FileSaveAs Dialog");
+ if(nLen2 == 0)
+ log(LOGGING_DEBUG, L"Error resolving - FileLocation - FileOpen or FileSaveAs Dialog");
+ if(nLen3 == 0)
+ log(LOGGING_DEBUG, L"Error resolving - FileTypes - FileOpen or FileSaveAs Dialog");
+ */
+
+ // Something went wrong! no point moving on
+ if(nLen1 == 0 || nLen2 == 0 || nLen3 == 0)
+ return false;
+
+ ////
+ // Now Copy out the values to the buffers of the caller object that was passed in
+ ////
+ lstrcpyn(pCallerObj->m_strFileNameLocationBuf, filenameAndLocation.location, MAX_PATH);
+ lstrcat(pCallerObj->m_strFileNameLocationBuf, L"\\");
+ lstrcat(pCallerObj->m_strFileNameLocationBuf, filenameAndLocation.filename);
+ lstrcpyn(pCallerObj->m_strFileTypesBuf, filenameAndLocation.filetypes, MAX_PATH);
+
+ // Log info to see what's going on
+ log(LOGGING_DEBUG, L"GetFileNameAndLocation setting m_strFileNameLocattionBuf to %s", pCallerObj->m_strFileNameLocationBuf);
+ log(LOGGING_DEBUG, L"GetFileNameAndLocation setting m_strFileTypesBuf to %s", pCallerObj->m_strFileTypesBuf);
+ return true;
+
+ }
+ return false;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: IsAWindowToHookInto()
+// Desc: Broad check to see if we want to hook into a window.
+// Called by CallWndHookProc.
+// Window on the screen.
+//
+// Prms: hwnd, handle to a window we want to check//
+//
+// Note: This function calls IsBlackListed() for more window exclusions.
+//
+// Retr: true, if window is should be hooked into, false otherwise
+//////////////////////////////////////////////////////////////////////
+bool IsAWindowToHookInto(HWND hwnd)
+{
+ DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
+ DWORD dwExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
+
+ if ( /* top-raised windows */
+ ( ( dwExStyle & WS_EX_WINDOWEDGE ) == WS_EX_WINDOWEDGE )
+
+ /* Styles to test for (named above) */
+ && ( ( dwStyle & WS_STYLES_TO_TEST_FOR ) == WS_STYLES_TO_TEST_FOR )
+
+ /* Has no parent = top-level window */
+ && ( GetParent(hwnd) == NULL )
+
+ /* Check if Window is not already hooked into*/
+ && ( s_ButtonHookAccess->FindHookedWnd(hwnd) == FALSE )
+
+ /* Check if Window has not been recently closed in this process*/
+ && ( FindRecentClosedWindow(hwnd) == FALSE )
+
+ // **** CUSTOM INCLUSION LIST ****
+ && ( IsWhiteListed(hwnd) )
+
+ // Make sure the window is visible to begin with * bug fix for ms word*
+ && ( ::IsWindowVisible(hwnd))
+ )
+ {
+ return true;
+ }
+ else if ( // We also want to hook into the FileOpen & FileSaveAs Dialog
+
+ /* top-raised windows */
+ ( ( dwExStyle & WS_EX_WINDOWEDGE ) == WS_EX_WINDOWEDGE )
+
+ /* Styles to test for (named above) */
+ && ( ( dwStyle & WS_STYLES_TO_TEST_FOR_DIALOGS ) == WS_STYLES_TO_TEST_FOR_DIALOGS )
+
+ /* Has a parent = it is a top-level window with parent */
+ && ( GetParent(hwnd) != NULL )
+
+ /* Check if Window's parent is hooked into */
+ && ( s_ButtonHookAccess->FindHookedWnd(GetParent(hwnd)) == TRUE )
+
+ /* Check if Window is not already hooked into*/
+ && ( s_ButtonHookAccess->FindHookedWnd(hwnd) == FALSE )
+
+ /* Check if Window has not been recently closed in this process*/
+ && ( FindRecentClosedWindow(hwnd) == FALSE )
+
+ // **** CUSTOM INCLUSION LIST ****
+ && ( IsWhiteListed(GetParent(hwnd)) )
+
+ // Make sure the window's parent is visible to begin with * bug fix for ms word *
+ && ( ::IsWindowVisible(GetParent(hwnd)))
+
+ // * We currently hook only into Top-Level FileOpen/SaveAs Dialogs
+ && ( IsFileOpenOrFileSaveAsDialog(hwnd) )
+ )
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+//////////////////////////////////////////////////////////////////////
+// Func: HookWndProc()
+// Desc: Function that implements the WndProc for every process that
+// has the window we are looking for. This is code is shared within
+// the process on every window in the system.
+//
+// Note: This function is just the WndProc() Implementation
+// All we have to do is process it if we care for it or pass it down
+// to the next hook (that may be in the system).
+//
+// Prms: hWnd, handle to window
+// Msg, passed in message
+// wParam, specifies additional message information
+// lParam, specifies additional message information
+//
+// Retr: LRESULT,
+//////////////////////////////////////////////////////////////////////
+LRESULT CALLBACK MyWndProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam )
+{
+ // default return
+ LRESULT result = 0;
+
+ // Get the HookWndItem Information
+ BLANK_HookWndItem(item);
+ item = s_ButtonHookAccess->GetHookedWndItem(hWnd);
+
+ bool bCloseMsg = ((Msg == WM_NCDESTROY) || (Msg == WM_DESTROY) || (Msg == WM_CLOSE));
+ if(bCloseMsg)
+ log(LOGGING_DEBUG, L"Received WM_NCDESTROY or DESTROY MESSAGE or WM_CLOSE for window %u", item.hWnd);
+
+ // Is this is a Window that is hooked? --- Ignore FileOpen / SaveDialog (Deal with them below)
+ if((item.hWnd != NULL) && (hWnd == item.hWnd) && !IsFileOpenOrFileSaveAsDialog(item.hWnd))
+ {
+ ////
+ // Create wpfcaller object for this Window, if it doesn't exist
+ // ~Every wpfcaller is mapped to a single HookWndItem
+ ////
+ if(item.wpfcaller == NULL)
+ {
+ log(LOGGING_DEBUG, L"Creating a wpfCaller Instance for window %u", item.hWnd);
+ item.wpfcaller = new WPFCaller(item, s_hModule);
+ }
+
+ ////
+ // Case StopHook wants us to Unhook the WmProc Hook or
+ // the Window gets Closed
+ ////
+ if ( (Msg == m_WMUnHook) || bCloseMsg )
+ {
+ log(LOGGING_MEDIUM, L"Received WMUnook or bCloseMsg message for window %u", item.hWnd);
+
+ // No Longer need to monitor this Window
+ s_ButtonHookAccess->DeleteHookedWnd(item.hWnd);
+ InsertRecentClosedWindow(item.hWnd);
+
+ // Unhook Our WndProc Procedure (put the old one back)
+ log(LOGGING_MEDIUM, L"Unhooking a Window %u from the HookWndProc", item.hWnd);
+ SetWindowLong(hWnd,GWL_WNDPROC,(LONG) item.DefWndProc);
+
+ // Delete this Window's CaptionButton Object
+ if(item.wpfcaller != NULL)
+ {
+ log(LOGGING_DEBUG, L"Deleting a wpfCaller Instance for Window %u", item.hWnd);
+ delete item.wpfcaller;
+ }
+
+ // Call the old WindProc to handle Close message
+ if(bCloseMsg)
+ result = CallWindowProc( item.DefWndProc, hWnd, Msg, wParam, lParam );
+ }
+ // All other Messages
+ else
+ {
+ // FOR TESTING - Skip Handling of Messages (Below)
+ // result = CallWindowProc( item->DefWndProc, hWnd, Msg, wParam, lParam );
+ try
+ {
+ // the wpfCaller Handles all other Messages
+ if(item.wpfcaller != NULL)
+ result = item.wpfcaller->OnDefault( hWnd, Msg, wParam, lParam);
+ else
+ result = CallWindowProc( item.DefWndProc, hWnd, Msg, wParam, lParam);
+ }
+ catch(...)
+ {
+ log(LOGGING_LOW, L"*Error* Occured calling WpfCaller->OnDefault()");
+ }
+ }
+ }
+ else if((item.hWnd != NULL) && (hWnd == item.hWnd) && IsFileOpenOrFileSaveAsDialog(item.hWnd)) // Deal with FileOpen / FileSave Dialog Here
+ {
+ ////
+ // Case StopHook wants us to Unhook the WmProc Hook or
+ // the Window gets Closed
+ ////
+ if ( (Msg == m_WMUnHook) || bCloseMsg )
+ {
+ log(LOGGING_DEBUG, L"FileOpenOrFileSaveDialog() Received WMUnook or bCloseMsg message for Window %u", item.hWnd);
+
+ // No Longer need to monitor this Window
+ s_ButtonHookAccess->DeleteHookedWnd(item.hWnd);
+ InsertRecentClosedWindow(item.hWnd);
+
+ // Unhook Our WndProc Procedure (put the old one back)
+ log(LOGGING_DEBUG, L"FileOpenOrFileSaveDialog() Unhooking from the HookWndProc for Window %u", item.hWnd);
+ SetWindowLong(hWnd,GWL_WNDPROC,(LONG) item.DefWndProc);
+
+ // Call the old WindProc to handle Close message
+ if(bCloseMsg)
+ {
+ // Handle CLose Message
+ result = CallWindowProc( item.DefWndProc, hWnd, Msg, wParam, lParam );
+ }
+ }
+ else if((Msg == WM_COMMAND) && (LOWORD(wParam) == 1)) // Received Ok or Open Button
+ {
+ log(LOGGING_DEBUG, L"Reveived Command Message from Dialog Button %u - Ok or Open Button",LOWORD(wParam));
+ // First Let's get the WPFCaller Instance of the main window and let it know that this occured
+ BLANK_HookWndItem(itemTmp);
+ itemTmp = s_ButtonHookAccess->GetHookedWndItem(GetParent(hWnd));
+
+ if(itemTmp.hWnd != NULL && itemTmp.wpfcaller != NULL)
+ {
+ // we want to obtain the File Location & File Name & File Types from the Dialogs
+ // ~this is the whole point why we hooked into it
+ log(LOGGING_DEBUG, L"Calling GetFileNameAndLocationStringValuesFromDialogWindow()");
+ if((GetFileNameAndLocationStringValuesFromDialogWindow(hWnd, itemTmp.wpfcaller)) &&
+ (lstrlen(itemTmp.wpfcaller->m_strFileNameLocationBuf) > 0))
+ {
+ log(LOGGING_DEBUG, L"About to post WM_CLIENT_EVENT_OPENFILEORSAVEASDIALOGOCCURED to WPFCallerThread");
+ log(LOGGING_DEBUG, L"Found FileNameLocation - %s", itemTmp.wpfcaller->m_strFileNameLocationBuf);
+ log(LOGGING_DEBUG, L"Found FileTypes - %s", itemTmp.wpfcaller->m_strFileTypesBuf);
+
+ // Post to the WPFCallerThread that this Event Occured
+ // WM_CLIENT_EVENT_OPENFILEORSAVEASDIALOGOCCURED (WM_USER + 808)
+ PostThreadMessage(itemTmp.wpfcaller->m_threadID, (WM_USER + 808),0,0);
+ }
+ else
+ {
+ // This should resolve now since we are looking only for command id 1
+ log(LOGGING_LOW, L"FileOpenOrFileSaveDialog() Error - GetFileNameAndLocationStringValuesFromDialogWindow Failed!");
+ }
+ }
+ else
+ {
+ log(LOGGING_LOW, L"FileOpenOrFileSaveDialog() Error - Couldn't fetch Parents WPFCaller object - skipping file resolution");
+ }
+ }
+
+ // Forward all Messages
+ result = CallWindowProc(item.DefWndProc, hWnd, Msg, wParam, lParam);
+ }
+
+ return result;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: CallWndHookProc()
+// Desc: Function that will replace the normal WndProc with the HookWndProc
+// procedure. It will do that for every process on the system that
+// has a window. It will assign the function HookWndProc()
+//
+// Prms: nCode [in] = if == HC_ACTION CallWndHookProc must process the message
+// wParam [in] = specifies if message is send by current process
+// non-zero if it is current process, null otherwise
+// LPARAM [in] = pointer to a CWPRETSTRUCT that contains details about the message
+//
+// Note: see MSDN for CallWndRetProc Function passed in with SetWindowHookEx
+// ~We don't check wParam (pass directly thru) because we want to process all messages
+// for all processes and don't care where it originates
+//
+// IMP!: In this function we check the Window and decide whether to display the button or not
+// ~!IMP) WH_CALLWNDPROC hook is called in the context of the thread that calls SendMessage
+//
+// Retr: LRESULT,
+//////////////////////////////////////////////////////////////////////
+LRESULT WINAPI CallWndHookProc(int nCode, WPARAM wParam, LPARAM lParam)
+{
+
+ if (nCode == HC_ACTION)
+ {
+ LPCWPSTRUCT pCwp = (LPCWPSTRUCT) lParam;
+
+ // Do we care about this Window?, We don't want to hook into all Windows
+ if(IsAWindowToHookInto(pCwp->hwnd))
+ {
+ // Do we care about this Message?
+ if((pCwp->message == m_WMHook) /* We'll receive the Hook Message StartButtonHook is called */
+ || (pCwp->message == WM_NCACTIVATE) /* Activates & deactivates a window, caption is redrawn. */
+ || (pCwp->message == WM_CREATE) /* A new window is being created */
+ || (pCwp->message == WM_ACTIVATE) /* a window is being activated */
+ || (pCwp->message == WM_PAINT) /* I added this after figguring out that drag n' droped files don't trigger above messages */
+ || (pCwp->message == WM_NCPAINT) /* Same as for WM_PAINT */
+ )
+ {
+
+ // Log that we are hooking into a FileOpen Or FileSaveAsDialog
+ if(IsFileOpenOrFileSaveAsDialog(pCwp->hwnd))
+ log(LOGGING_DEBUG, L"FileOpenOrFileSaveDialog() We are hooking into a FileOpen or FileSaveDialog");
+
+ // Create a hook Item, We are ready to hook into this Window
+ HookWndItem item;
+
+ // hWnd = the handle to the current window
+ // DefWndProc = handle of the this window procedure (the address that is replaced by our Hook Function)
+ // HookWndProc = the address of this DLL instance's HookWndProc Function
+ item.hWnd = pCwp->hwnd;
+ item.DefWndProc = reinterpret_cast(GetWindowLong(pCwp->hwnd,GWL_WNDPROC));
+ item.HookWndProc = MyWndProc;
+ item.wpfcaller = NULL; // The Caption Button will be initialized by MyHookWnd
+
+ // Add the hook Item to the Global List
+ s_ButtonHookAccess->InsertHookedWndItem(item);
+
+ ////
+ // ********************** INSTALL THE NEW WNDHOOK_PROCEDURE **********************
+ // *******************************************************************************
+ // GWL_WNDPROC - Sets a new address for the window procedure (WinProc())
+ // Windows NT/2000/XP: You cannot change this attribute if the window does not
+ // belong to the same process as the calling thread. */The hook is responsible for
+ // putting the .dll into the memoryspace of every process. This Dll iterates thru
+ // all the Windows and right here hooks into the WndProc
+ ////
+ log(LOGGING_LOW, L"Installing HookWndProc for Window %u", pCwp->hwnd);
+
+ // We have to call SetWindowLongPtr to install the WNDPROC. Not doins so causes
+ // our UnHook message to never be received by the Hooked Wnd
+ int result = SetWindowLongPtr( pCwp->hwnd, GWL_WNDPROC, (LONG) MyWndProc );
+ }
+ }
+ }
+
+ // We now pass in our Hook Handle down the current hook chain (in case other hooks are listening)
+ return (CallNextHookEx( s_ButtonHookAccess->get_hHook(), nCode, wParam, lParam ));
+}
+//////////////////////////////////////////////////////////////////////
+// Func: Helper_ReadSafeArrayIntoWCharArr()
+// Desc: Small Helper function to quickly read a SafeArray Into a WChar Array
+//
+// Prms: +pDes, char destination buffer to copy into
+// -size, passes out the size of the safearray
+// +pSrc, the Safearray source to copy from
+//
+// Note: Not much safety checking going on. Make sure the buffer has enough space!
+// ~also only 1 dimensional arrays/safearrays work
+//
+// IMP!: MAX_PATH is the ultimate Max of size and elements of the pDest Buffer
+//////////////////////////////////////////////////////////////////////
+void Helper_ReadSafeArrayIntoWCharArr(wchar_t pDes[MAX_PATH][MAX_PATH],UINT& size,SAFEARRAY* pSrc)
+{
+ try
+ {
+ // this func only handles 1-dim arrays/safearrays
+ const int ONE_DIMENSIONAL = 1;
+
+ long lUBound = 0;
+ long lLBound = 0;
+ SafeArrayGetLBound(pSrc, ONE_DIMENSIONAL, &lLBound);
+ SafeArrayGetUBound(pSrc, ONE_DIMENSIONAL, &lUBound);
+
+ BSTR* pBSTR;
+ SafeArrayAccessData(pSrc, (void**) &pBSTR);
+ for (long n = lLBound; ((n <= lUBound) && (n < MAX_PATH)); ++n)
+ {
+ _bstr_t bstr(pBSTR[n], true);
+ lstrcpyn(&pDes[n][0],(wchar_t*) bstr , MAX_PATH);
+ }
+ SafeArrayUnaccessData(pSrc);
+
+ // pass out the size
+ size = lUBound - lLBound + 1;
+
+ // pSrc was empty so set size to 0
+ if((size == 1) && (pDes[0][0] == 0))
+ size = 0;
+ }
+ catch(...)
+ {
+ return;
+ }
+}
+//////////////////////////////////////////////////////////////////////
+// Func: ReadOoganizerSettings()
+// Desc: Calls OoganizerSettings COM Object to read in all the settings
+// into our SharedDS.
+//
+// These are the important settings we need like Logging details,
+// What windows to hook into, what window classes, and even
+// window layout as well as debugging options
+//
+// Retr: true, if settings were read, false otherwise
+//////////////////////////////////////////////////////////////////////
+bool ReadOoganizerSettings()
+{
+ try
+ {
+ IOoganizerSettingsPtr pSettings(__uuidof(OoganizerSettingsAcc));
+
+ // Read Configuration File
+ _configurationPtr config = NULL;
+ if(FAILED(pSettings->ReadConfigXMLFile(&config)))
+ return false;
+
+ // Get ButtonHook Settings
+ _ButtonHookSettingsPtr buttonhookSettings = NULL;
+ if(FAILED(config->get_ButtonHook(&buttonhookSettings)))
+ return false;
+
+ // Let's do that First! ~Imp! Get/Set LogPath & Debug Settings
+ _bstr_t LogPath;
+ _LoggingSettingsPtr logSettings;
+ buttonhookSettings->get_LogSettings(&logSettings);
+ logSettings->get_LogPath(LogPath.GetAddress());
+ s_ButtonHookAccess->SetLogPath((wchar_t*) LogPath);
+ log(LOGGING_DEBUG, L"Setting Log Path: %s", (wchar_t*) LogPath);
+
+ // Logging Detail
+ unsigned long nLoggingDetail = 0;
+ logSettings->get_LoggingDetail(&nLoggingDetail);
+ s_ButtonHookAccess->SetLoggingDetail(static_cast(nLoggingDetail));
+#ifdef _DEBUG
+ log(LOGGING_DEBUG, L"Setting Log Detail: 4 (DEBUG)", nLoggingDetail);
+#else
+ log(LOGGING_DEBUG, L"Setting Log Detail: %u", nLoggingDetail);
+#endif
+
+ ////
+ // Now set this instance's Logging option
+ ////
+ SetLoggingDetail(s_ButtonHookAccess->GetLoggingDetail(),s_ButtonHookAccess->GetLogPath());
+
+ SAFEARRAY* safeArray;
+
+ // Get AllowedProcessNames
+ _AllowedProcessNamesWPtr processNames;
+ buttonhookSettings->get_AllowedProcessNames(&processNames);
+ processNames->get_ProcessName(&safeArray);
+ Helper_ReadSafeArrayIntoWCharArr(s_ButtonHookAccess->ALLOWED_PROCESS_NAMES,s_ButtonHookAccess->NUMBER_OF_ALLOWED_PROCESS_NAMES,safeArray);
+
+ // log values
+ if(s_ButtonHookAccess->NUMBER_OF_ALLOWED_PROCESS_NAMES)
+ {
+ for (UINT i = 0; i < s_ButtonHookAccess->NUMBER_OF_ALLOWED_PROCESS_NAMES; ++i)
+ log(LOGGING_DEBUG, L"AllowedProcessName: %s", s_ButtonHookAccess->ALLOWED_PROCESS_NAMES[i]);
+ }
+
+ // Get AllowedWindowTitles
+ _AllowedWindowTitlesWPtr windowTitles;
+ buttonhookSettings->get_AllowedWindowTitles(&windowTitles);
+ windowTitles->get_WindowTitle(&safeArray);
+ Helper_ReadSafeArrayIntoWCharArr(s_ButtonHookAccess->ALLOWED_WINDOW_TITLES,s_ButtonHookAccess->NUMBER_OF_ALLOWED_WINDOW_TITLES,safeArray);
+
+ // log values
+ if(s_ButtonHookAccess->NUMBER_OF_ALLOWED_WINDOW_TITLES)
+ {
+ for (UINT i = 0; i < s_ButtonHookAccess->NUMBER_OF_ALLOWED_WINDOW_TITLES; ++i)
+ log(LOGGING_DEBUG, L"AllowedWindowTitle: %s", s_ButtonHookAccess->ALLOWED_WINDOW_TITLES[i]);
+ }
+
+ // Get AllowedWindowClasses
+ _AllowedWindowClassesWPtr windowClasses;
+ buttonhookSettings->get_AllowedWindowClasses(&windowClasses);
+ windowClasses->get_WindowClass(&safeArray);
+ Helper_ReadSafeArrayIntoWCharArr(s_ButtonHookAccess->ALLOWED_WINDOW_CLASSES,s_ButtonHookAccess->NUMBER_OF_ALLOWED_WINDOW_CLASSES,safeArray);
+
+ // log values
+ if(s_ButtonHookAccess->NUMBER_OF_ALLOWED_WINDOW_CLASSES)
+ {
+ for (UINT i = 0; i < s_ButtonHookAccess->NUMBER_OF_ALLOWED_WINDOW_CLASSES; ++i)
+ log(LOGGING_DEBUG, L"AllowedWindowClass: %s", s_ButtonHookAccess->ALLOWED_WINDOW_CLASSES[i]);
+ }
+ return true;
+ }
+ catch(...)
+ {
+ return false;
+ }
+}
+//////////////////////////////////////////////////////////////////////
+// Func: SystemMetricsTesterHELPER()
+// Desc: Use this for Debugging only when you need to know certain system metrics values
+//////////////////////////////////////////////////////////////////////
+void SystemMetricsTesterHELPER()
+{
+ int k = 0;
+ k = GetSystemMetrics(SM_CXEDGE); //2 on vista
+ k = GetSystemMetrics(SM_CYEDGE); //2 on vista
+
+ k = GetSystemMetrics(SM_CXFRAME); //8 on vista
+ k = GetSystemMetrics(SM_CYFRAME); //8 on vista
+
+ k = GetSystemMetrics(SM_CXFIXEDFRAME); //3 on vista
+ k = GetSystemMetrics(SM_CYFIXEDFRAME); //3 on vista
+
+ k = GetSystemMetrics(SM_CXMIN); //124 on vista
+ k = GetSystemMetrics(SM_CYMIN); //36 on vista
+
+ k = GetSystemMetrics(SM_CXBORDER); // 1 on vista
+ k = GetSystemMetrics(SM_CYBORDER); // 1 on vista
+
+ k = GetSystemMetrics(SM_CXSIZE); //32 on vista
+ k = GetSystemMetrics(SM_CYSIZE); //19 on vista
+
+ k = GetSystemMetrics(SM_CYCAPTION); //20 on vista
+ //k = GetSystemMetrics(SM_CXCAPTION);
+
+ k = GetSystemMetrics(SM_CYSMCAPTION); //18 on vista
+ //k = GetSystemMetrics(SM_CXSMCAPTION);
+
+ k = GetSystemMetrics(SM_CYSMSIZE); //17 on vista
+ k = GetSystemMetrics(SM_CXSMSIZE); //17 on vista
+}
+//////////////////////////////////////////////////////////////////////
+// Func: StartWinProcButtonHook()
+// Desc: Exported DLL function to allow a process to start/attach
+// the system WinProcButtonhook. This function will attach the WinProc function
+// to the process's window via the CallWndHookProc() function
+//
+// Note: We'll check if the system is supported here. We'll only allow
+// to start the hook, if that is the case
+//
+// Retr: TRUE, if succesfully attached, FALSE otherwise (i.e. OS NOT SUPPORTED)
+//////////////////////////////////////////////////////////////////////
+BOOL WINAPI StartButtonHook()
+{
+ // Debugging ONLY when we need certain values (comment/uncomment)
+ //SystemMetricsTesterHELPER();
+
+ // Let's try to see if we can force a rehook
+ bool bThereWasAnExistingHook = false;
+ if(s_ButtonHookAccess->get_hHook() != NULL)
+ {
+ s_ButtonHookAccess->set_hHook(NULL);
+ bThereWasAnExistingHook = true;
+ }
+
+ // Global doesn't exist, we can start
+ if(s_ButtonHookAccess->get_hHook() == NULL)
+ {
+ // Delete All Shared Data Hook Data - Just in case previous DLL Instance corrupted HookData
+ s_ButtonHookAccess->ClearHookSData();
+
+ // Don't start ButtonHook unless the OS supports it
+ VARIANT_BOOL bIsSupported;
+ _EnvironmentCCWPtr env(__uuidof(EnvironmentCCW));
+ env->IsWindowsOSSupported(&bIsSupported);
+
+ if(bIsSupported == -1) // TRUE
+ {
+ bool bSettings = ReadOoganizerSettings();
+ clearLog(); // Start Fresh (with a new Log)
+
+ // We won't be able to log until we have read in the settings
+ if(bThereWasAnExistingHook)
+ log(LOGGING_LOW, L"A previous ButtonHook Existed - overwriting it");
+
+ if(!bSettings)
+ log(LOGGING_LOW, L"ReadOoganizerSettings Failed!");
+ else
+ log(LOGGING_MEDIUM, L"ReadOoganizerSettings Succeeded");
+
+ // There really is no sense to start ButtonHook with no Settings Info
+ if(bSettings)
+ {
+ log(LOGGING_LOW, L"StartButtonHook Called()");
+
+ // Create/Store Global Hook (every instance needs access to this HOOK)
+ // ~WH_CALLWNDPROC hook is called in the context of the thread that calls SendMessage
+ log(LOGGING_DEBUG, L"Setting the Windows Hook");
+ HHOOK hook = SetWindowsHookEx( WH_CALLWNDPROC, CallWndHookProc, s_hModule, 0 );
+
+ if(hook == NULL)
+ {
+ log(LOGGING_LOW, L"Windows Hook Failed error %i", GetLastError());
+ return FALSE;
+ }
+ else
+ {
+ // Assign the hook value to the Global DS
+ log(LOGGING_DEBUG, L"Windows Hook Succeeded Hook Set %i", hook);
+ s_ButtonHookAccess->set_hHook(hook);
+ }
+
+ // Send Hook Msg - This forces all windows already open in the system and that
+ // we want to hook into to load the captionbutton
+
+ if(m_WMHook >= 0xC000 && m_WMHook <= 0xFFFF)
+ {
+ log(LOGGING_DEBUG, L"StartButtonHook - About to call EnumWindows");
+ EnumWindows( EnumProc, _MSG_HOOK );
+ log(LOGGING_LOW, L"StartButtonHook EnumWindows Returns - Everything is O.K.");
+ }
+ else
+ {
+ log(LOGGING_LOW, L"Registered Message m_WMHook is invalid - something is terribly wrong");
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: StopWinProcButtonHook()
+// Desc: Exported DLL function to allow a process to stop/deattach
+// the WinProcButton system hook
+//
+// Retr: TRUE, if succesfully deattached, FALSE otherwise
+//////////////////////////////////////////////////////////////////////
+BOOL WINAPI StopButtonHook()
+{
+ // Global does exist, we can exit
+ if(s_ButtonHookAccess->get_hHook() != NULL)
+ {
+ // Send UnHook Msg
+ if(m_WMUnHook >= 0xC000 && m_WMUnHook <= 0xFFFF)
+ {
+ log(LOGGING_LOW, L"StopButtonHook Called()");
+ EnumWindows( EnumProc, _MSG_UNHOOK );
+ log(LOGGING_LOW, L"StopButtonHook() EnumWindows Returns - Everything is O.K.");
+ }
+ else
+ {
+ log(LOGGING_LOW, L"Registered Message m_WMUnHook is invalid - something is terribly wrong");
+ return FALSE;
+ }
+
+ try
+ {
+ // now we can exit
+ if ( UnhookWindowsHookEx( s_ButtonHookAccess->get_hHook() ) != 0 )
+ {
+ log(LOGGING_MEDIUM, L"Successfully Unhooked Hook %i", s_ButtonHookAccess->get_hHook());
+ }
+ else
+ {
+ log(LOGGING_LOW, L"Error Occrured in StopButtonHook %i", GetLastError());
+ return FALSE;
+ }
+
+ // Reset Global Hook - Delete All Shared Data
+ log(LOGGING_HIGH, L"Reset Global Hook & Clearing ALL Hook Related Data");
+ s_ButtonHookAccess->set_hHook(NULL);
+ s_ButtonHookAccess->ClearHookSData();
+
+ // New Code: ~errors out~ Unregister all Window Classes here (used to be done in ~WPFCaller())
+ /*if(!UnregisterClass(L"W32ButtonHookWndClass", s_hModule))
+ log(LOGGING_DEBUG, L"Error occured for UnregisterClass W32ButtonHookWndClass");*/
+ }
+ catch(...)
+ {
+ log(LOGGING_LOW, L"Error occured in StopButtonHook");
+ return FALSE;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: IsButtonHookSet()
+// Desc: Exported DLL function to allow a caller to know if the buttonhook
+// is set or not
+//
+// Retr: TRUE, if Hook is attached, FALSE otherwise
+//////////////////////////////////////////////////////////////////////
+BOOL WINAPI IsButtonHookSet()
+{
+ return (s_ButtonHookAccess->get_hHook() != NULL);
+}
+//////////////////////////////////////////////////////////////////////
+// Func: GetAllHookedWindowHandles()
+// Desc: Exported DLL function to allow a caller to retrieve all Hooked
+// Window Handles.
+// ~passed in pBuf must be at least of size MAX_PATH
+//
+// Retr: int, returns the size of the passed out pBuf list
+//////////////////////////////////////////////////////////////////////
+int WINAPI GetAllHookedWindowHandles(int* pBuf)
+{
+ if(s_ButtonHookAccess->get_hHook() != NULL)
+ {
+ int buf[MAX_PATH] = {0};
+ int nsize = 0;
+ s_ButtonHookAccess->GetHookedWindowListNSize(buf,&nsize);
+
+ ////
+ // there could be nulls in the buf, so filter them out,
+ // to return a complete list the caller. Copy only Non-Null
+ // values to the output buffer * and ONLY EXISTING WINDOWS *
+ ////
+ int nNullsOrInvalid = 0;
+ for(int i = 0; i < nsize; ++i)
+ {
+ if(buf[i] != NULL && ::IsWindow((HWND) buf[i]))
+ *(pBuf + i) = buf[i];
+ else
+ ++nNullsOrInvalid;
+ }
+
+ // return the adjusted size, if needed
+ log(LOGGING_DEBUG, L"GetAllHookedWindowHandles() got called returning WindowHandles Buf size of %u", (nsize - nNullsOrInvalid));
+ return (nsize - nNullsOrInvalid);
+ }
+ return 0;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: DllMain()
+// Desc: Dll Main Entry Point - The DLL is being attached to every
+// process in the system! ~therefore it must be fast. Also
+// we can't start the main register hook function from here
+// system call from here. (because this dll get loaded many times,
+// we only however want the system hook code to be called only once.
+//
+// Note: Attaching the dll will cause MSG_HOOK to be registred
+//
+// Retr: TRUE, always
+//////////////////////////////////////////////////////////////////////
+BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
+{
+
+ switch ( ul_reason_for_call )
+ {
+ case DLL_PROCESS_ATTACH:
+
+ // This is to access DS segment's Hook Information,
+ // Across all instances of this DLL.
+ s_ButtonHookAccess = new CWHPaccess();
+
+ // Store local Module Handle
+ s_hModule = (HINSTANCE) hModule;
+
+ // message is used to send to all windows when the HOOK attaches
+ m_WMHook = RegisterWindowMessage( MSG_HOOK );
+
+ // message is used to send to all windows when the HOOK unattaches
+ m_WMUnHook = RegisterWindowMessage( MSG_UNHOOK );
+
+ // get the shared setting logging information and store it into this instance
+ SetLoggingDetail(s_ButtonHookAccess->GetLoggingDetail(), s_ButtonHookAccess->GetLogPath());
+
+ break;
+ case DLL_PROCESS_DETACH:
+ case DLL_THREAD_DETACH:
+ case DLL_THREAD_ATTACH:
+ default:
+ break;
+ }
+
+ return TRUE;
+}
\ No newline at end of file
diff --git a/Hooks/ButtonHook/ButtonHook.h b/Hooks/ButtonHook/ButtonHook.h
new file mode 100644
index 0000000..0264782
--- /dev/null
+++ b/Hooks/ButtonHook/ButtonHook.h
@@ -0,0 +1,17 @@
+// ButtonHook.h
+#pragma once
+#include "CWHPaccess.h"
+
+#ifdef DLLAPI_BUTTON_HOOK
+#define ENTRY_FUNCTION extern "C" _declspec(dllexport)
+#else
+#define ENTRY_FUNCTION extern "C" _declspec(dllimport)
+#endif
+
+////
+// Entry-Point (Exposed)Functions
+////
+ENTRY_FUNCTION BOOL WINAPI StartButtonHook(void);
+ENTRY_FUNCTION BOOL WINAPI StopButtonHook(void);
+ENTRY_FUNCTION BOOL WINAPI IsButtonHookSet(void);
+ENTRY_FUNCTION int WINAPI GetAllHookedWindowHandles(int* pBuf);
diff --git a/Hooks/ButtonHook/ButtonHook.vcproj b/Hooks/ButtonHook/ButtonHook.vcproj
new file mode 100644
index 0000000..7c4a7bc
--- /dev/null
+++ b/Hooks/ButtonHook/ButtonHook.vcproj
@@ -0,0 +1,236 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Hooks/ButtonHook/ButtonStrategy.cpp b/Hooks/ButtonHook/ButtonStrategy.cpp
new file mode 100644
index 0000000..91024c9
--- /dev/null
+++ b/Hooks/ButtonHook/ButtonStrategy.cpp
@@ -0,0 +1,390 @@
+#include "StdAfx.h"
+#include "ButtonStrategy.h"
+//#include "HiddenWindow.h" // for Some Strategies we need to create
+ // a hidden window and draw the buttons on it
+
+////
+// We are delay-loading the UXTheme.dll. In case we are running on
+// a system where the dll doesn't exist, we'll only load it we know
+// that this is a system where it should exist
+////
+#include "uxtheme.h"
+////
+// We are delay-loading the DWMapi.dll. In case we are running on
+// a system where the dll doesn't exist, we'll only load it we know
+// that this is a system where it should exist
+////
+#include "dwmapi.h"
+
+using namespace Ooganizer;
+
+//********************************************************************
+// Clss ButtonStrategy
+//
+// Programmer Daniel Romischer
+// Ooganizer Development Team
+//
+// Description Base/Abstract Class for all Button Strategies
+//
+// Note CalcCaptionRect() and CalcCaptionButtonRect()
+// is implemented in the base class for now (as it appears
+// to be the same calculation for all Button Strategies).
+//
+// Created 06-01-2008
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+//********************************************************************
+// Construction / Destruction
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+ButtonStrategy::ButtonStrategy(void)
+{
+}
+ButtonStrategy::~ButtonStrategy(void)
+{
+}
+//////////////////////////////////////////////////////////////////////
+// Func: CalcCaptionRect()
+// Desc: Calculates the dimensions of the Caption Bar
+//
+// Prms: +hWnd, handle to a Windows
+// +-Rect, returns the x,y RECT area dimension coordinates of the caption bar
+// +-SIZE, returns the width and height of the Caption bar
+//////////////////////////////////////////////////////////////////////
+void ButtonStrategy::CalcCaptionRect(HWND hWnd, RECT &RectCaption, SIZE &heightNwidth)const
+{
+ RECT Rect;
+ SIZE sFrame;
+ DWORD dStyle = GetWindowLong( hWnd, GWL_STYLE );
+
+ // Get frame size of window
+ // (x and y height width dim of the resizable or non-resizable windows frame)
+ sFrame.cy = GetSystemMetrics( ( dStyle & WS_THICKFRAME ) ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME );
+ sFrame.cx = GetSystemMetrics( ( dStyle & WS_THICKFRAME ) ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME );
+
+ // Gets the location of the Window
+ GetWindowRect( hWnd, &Rect );
+
+ // Height and Width of the Window
+ LONG height = Rect.bottom - Rect.top; // Window height not intersting to us (not used)
+ LONG width = Rect.right - Rect.left;
+
+ // Pass the CaptionBar Dimension out
+ RectCaption.top = sFrame.cy; // 4, 8
+ RectCaption.left = sFrame.cx; // 4, 8
+ RectCaption.right = width - sFrame.cy; // 771
+
+ // SM_CYCAPTION = The height of a caption area, in pixels
+ // SM_CYBORDER = The height of a window border
+ int heightCaption = GetSystemMetrics( SM_CYCAPTION ); // 20
+ int heightWindowBorder = GetSystemMetrics( SM_CYBORDER ); // 1
+
+ RectCaption.bottom = heightCaption;
+
+ //heightCaption gives us the correct caption height, but in order to get the exact RECT location,
+ //calculated from top left, we need to add sFrame.cy to it. ~we substract the bottom border because,
+ //otherwise the height will be too long
+
+ //sFrame.cy + heightCaption - heightWindowBorder;
+
+ // sample return
+ // top = 4, left = 4, bottom = 23, right = 771
+
+ // Pass out the height & Width of the CaptionBar
+ heightNwidth.cx = heightCaption;
+ heightNwidth.cy = width;
+}
+//********************************************************************
+// Clss ClassicButtonStrategy
+//
+// Description Implementation for our Windows Classic Theme Strategy
+//
+// Note Uses DrawFrameControl() to draw the Button. This will
+// Only work in Windows2000/XP without theme (classic View)
+//
+// Created 06-01-2008
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+//********************************************************************
+// Construction / Destruction
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+ClassicButtonStrategy::ClassicButtonStrategy()
+{
+}
+ClassicButtonStrategy::~ClassicButtonStrategy()
+{
+}
+//////////////////////////////////////////////////////////////////////
+// Func: draw()
+// Desc: generic draw function - called for all default messages
+//////////////////////////////////////////////////////////////////////
+void ClassicButtonStrategy::draw(HWND hWnd, const HDC &hDc, const RECT &rPos) const
+{
+ // Use the regular Frame Control *Windows Classic*
+ // DrawFrameControl( hDc, const_cast(&rPos), DFC_BUTTON, DFCS_BUTTONPUSH );
+
+ HICON hIcon = (HICON) LoadImage(NULL, L"C:\\bridge.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
+ DrawIcon(hDc, rPos.left, rPos.top, hIcon);
+}
+//////////////////////////////////////////////////////////////////////
+// Func: drawButtonUp()
+// Desc: draw the button in an up state
+//////////////////////////////////////////////////////////////////////
+void ClassicButtonStrategy::drawButtonUp(HWND hWnd, const HDC &hDc, const RECT &rPos) const
+{
+ // Use the regular Frame Control *Windows Classic*
+ // DrawFrameControl( hDc, const_cast(&rPos), DFC_BUTTON, DFCS_BUTTONPUSH );
+
+ HICON hIcon = (HICON) LoadImage(NULL, L"C:\\bridge.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
+ DrawIcon(hDc, rPos.left, rPos.top, hIcon);
+}
+//////////////////////////////////////////////////////////////////////
+// Func: drawButtonDown()
+// Desc: draw the button in a down state
+//////////////////////////////////////////////////////////////////////
+void ClassicButtonStrategy::drawButtonDown(HWND hWnd, const HDC &hDc, const RECT &rPos) const
+{
+ // Use the regular Frame Control *Windows Classic*
+ // DrawFrameControl( hDc, const_cast(&rPos), DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_PUSHED );
+
+ HICON hIcon = (HICON) LoadImage(NULL, L"C:\\bridge.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
+ DrawIcon(hDc, rPos.left, rPos.top, hIcon);
+}
+//********************************************************************
+// Clss AeroButtonStrategy
+//
+// Description Implementation for our Windows Aero Theme Strategy
+//
+// Note
+//
+//
+// Created 06-01-2008
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+//********************************************************************
+// Construction / Destruction
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+AeroButtonStrategy::AeroButtonStrategy()
+{
+}
+AeroButtonStrategy::~AeroButtonStrategy()
+{
+}
+//////////////////////////////////////////////////////////////////////
+// Func: CalcCaptionButtonRect()
+// Desc: Calculates the dimensions of the Caption Button. Takes into
+// account the number of caption buttons on the window and returns
+// the pos (RECT) where to draw the Caption Button.
+//
+// Prms: +hWnd, handle to a Windows
+// +-RectButtonPos, returns the x,y dimension of where to place the Button
+//////////////////////////////////////////////////////////////////////
+void AeroButtonStrategy::CalcCaptionButtonRect(HWND hWnd, RECT& RectButtonPos) const
+{
+ // Button Constants
+ const LONG BUTTON_MARGIN = 2; // The Margin Space between the Buttons
+
+ //The width of a button in a window caption or title bar, in pixels
+ const LONG CAPTION_WIDTH = GetSystemMetrics(SM_CXSIZE); // should be 28
+
+ log(LOGGING_HIGH, "Caption Width = %i", CAPTION_WIDTH);
+
+ RECT rect;
+ SIZE size;
+ // Get The dimensions of the CaptionBar
+ CalcCaptionRect(hWnd,rect,size);
+
+ // sample return from CalcCaptionRect()
+ // top = 4, left = 4, bottom = 23, right = 771
+
+ // On Aero the distance of the Button is 10 not 6. Calculating by multiplying top * 2 (=8)
+ // ~this makes sense because our Rect start at the top most location (not where vista wants to draw the button
+ const LONG TOP_PLACEMENT = (2 * rect.top) + BUTTON_MARGIN;
+ const LONG BOTTOM_PLACEMENT = rect.bottom - BUTTON_MARGIN;
+
+ // Left and Right Placement has to be calculated using the spacing on the right, the caption button widths,
+ // of (close, max, min) and the margins in between the buttons. (RECT includes all caption buttons),
+ // we also subtract rect.top from the left because a window border on right is not considered (+ another margin)
+ const LONG RIGHT_PLACEMENT = rect.right - (CAPTION_WIDTH * 3) - (BUTTON_MARGIN * 3) - (rect.top + BUTTON_MARGIN);
+ const LONG LEFT_PLACEMENT = RIGHT_PLACEMENT - CAPTION_WIDTH; // - BUTTON_MARGIN?
+
+ ////
+ // Pass out the dimension of the CaptionButton
+ ////
+ RectButtonPos.top = TOP_PLACEMENT;
+ RectButtonPos.bottom = BOTTOM_PLACEMENT;
+ RectButtonPos.right = RIGHT_PLACEMENT;
+ RectButtonPos.left = LEFT_PLACEMENT;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: draw()
+// Desc: generic draw function - called for all default messages
+//////////////////////////////////////////////////////////////////////
+void AeroButtonStrategy::draw(HWND hWnd, const HDC &hDc, const RECT &rPos) const
+{
+ // HTHEME hTheme = OpenThemeData(hWnd, L"OkButton;Button;Window");
+ // HTHEME hTheme = OpenThemeData(hWnd, L"Button");
+
+ // DrawThemeParentBackground(hWnd,hDc,&rPos);
+ // DrawThemeBackground(hTheme,hDc,0,0,&rPos,0);
+
+ HICON hIcon = (HICON) LoadImage(NULL, L"C:\\VistaNoAero.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
+ DrawIcon(hDc, rPos.left, rPos.top, hIcon);
+}
+//////////////////////////////////////////////////////////////////////
+// Func: drawButtonUp()
+// Desc: draw the button in an up state
+//////////////////////////////////////////////////////////////////////
+void AeroButtonStrategy::drawButtonUp(HWND hWnd, const HDC &hDc, const RECT &rPos) const
+{
+ HICON hIcon = (HICON) LoadImage(NULL, L"C:\\bridge.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
+ DrawIcon(hDc, rPos.left, rPos.top, hIcon);
+}
+//////////////////////////////////////////////////////////////////////
+// Func: drawButtonDown()
+// Desc: draw the button in a down state
+//////////////////////////////////////////////////////////////////////
+void AeroButtonStrategy::drawButtonDown(HWND hWnd, const HDC &hDc, const RECT &rPos) const
+{
+ HICON hIcon = (HICON) LoadImage(NULL, L"C:\\bridge.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
+ DrawIcon(hDc, rPos.left, rPos.top, hIcon);
+}
+//********************************************************************
+// Clss VistaNoAeroStrategy
+//
+// Description Implementation for Vista when Aero (Glass) is not running
+//
+// Note
+//
+//
+// Created 06-01-2008
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+//********************************************************************
+// Construction / Destruction
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+VistaNoAeroStrategy::VistaNoAeroStrategy()
+{
+}
+VistaNoAeroStrategy::~VistaNoAeroStrategy()
+{
+}
+//////////////////////////////////////////////////////////////////////
+// Func: CalcCaptionButtonRect()
+// Desc: Calculates the dimensions of the Caption Button. Takes into
+// account the number of caption buttons on the window and returns
+// the pos (RECT) where to draw the Caption Button.
+//
+// Prms: +hWnd, handle to a Windows
+// +-RectButtonPos, returns the x,y dimension of where to place the Button
+//////////////////////////////////////////////////////////////////////
+void VistaNoAeroStrategy::CalcCaptionButtonRect(HWND hWnd, RECT& RectButtonPos) const
+{
+ // Button Constants
+ const LONG BUTTON_MARGIN = 2; // The Margin Space between the Buttons
+
+ //The width of a button in a window caption or title bar, in pixels
+ const LONG CAPTION_WIDTH = GetSystemMetrics(SM_CXSIZE); // 32 (appears to include left and righ Margin)
+
+ RECT rect;
+ SIZE size;
+ // Get The dimensions of the CaptionBar
+ CalcCaptionRect(hWnd,rect,size);
+ log(LOGGING_HIGH, "rect is top %i, bottom %i, left %i, right %i", rect.top, rect.bottom, rect.left, rect.right);
+
+ // sample return from CalcCaptionRect()
+
+ // Vista Aero
+ // top = 4, left = 4, bottom = 23, right = 771
+
+ // Vista NoAero
+ // rect is top 8, bottom 27, left 8, right 831
+
+ // On Aero the distance of the Button is 10 not 6. Calculating by multiplying top * 2 (=8)
+ // ~this makes sense because our Rect start at the top most location (not where vista wants to draw the button
+ const LONG TOP_PLACEMENT = 10; //(2 * rect.top) + BUTTON_MARGIN;
+ const LONG BOTTOM_PLACEMENT = rect.bottom - BUTTON_MARGIN;
+
+ // Left and Right Placement has to be calculated using the spacing on the right, the caption button widths,
+ // of (close, max, min) and the margins in between the buttons. (RECT includes all caption buttons),
+ // we also subtract rect.top from the left because a window border on right is not considered (+ another margin)
+ // 96
+ const LONG RIGHT_PLACEMENT = rect.right - 96;
+ const LONG LEFT_PLACEMENT = RIGHT_PLACEMENT - 28; // - BUTTON_MARGIN?
+
+ ////
+ // Pass out the dimension of the CaptionButton
+ ////
+ RectButtonPos.top = TOP_PLACEMENT;
+ RectButtonPos.bottom = BOTTOM_PLACEMENT;
+ RectButtonPos.right = RIGHT_PLACEMENT;
+ RectButtonPos.left = LEFT_PLACEMENT;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: draw()
+// Desc: generic draw function - called for all default messages
+//////////////////////////////////////////////////////////////////////
+void VistaNoAeroStrategy::draw(HWND hWnd, const HDC &hDc, const RECT &rPos) const
+{
+ HICON hIcon = (HICON) LoadImage(NULL, L"C:\\VistaNoAero.ico", IMAGE_ICON, 28, 15, LR_LOADFROMFILE);
+ DrawIcon(hDc, rPos.left, rPos.top, hIcon);
+}
+//////////////////////////////////////////////////////////////////////
+// Func: drawButtonUp()
+// Desc: draw the button in an up state
+//////////////////////////////////////////////////////////////////////
+void VistaNoAeroStrategy::drawButtonUp(HWND hWnd, const HDC &hDc, const RECT &rPos) const
+{
+}
+//////////////////////////////////////////////////////////////////////
+// Func: drawButtonDown()
+// Desc: draw the button in a down state
+//////////////////////////////////////////////////////////////////////
+void VistaNoAeroStrategy::drawButtonDown(HWND hWnd, const HDC &hDc, const RECT &rPos) const
+{
+}
+//********************************************************************
+// Clss XPButtonStrategy
+//
+// Description Implementation for Windows XP Themed Strategy
+//
+// Note
+//
+//
+// Created 06-01-2008
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+//********************************************************************
+// Construction / Destruction
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+XPButtonStrategy::XPButtonStrategy()
+{
+}
+XPButtonStrategy::~XPButtonStrategy()
+{
+}
+//////////////////////////////////////////////////////////////////////
+// Func: draw()
+// Desc: generic draw function - called for all default messages
+//////////////////////////////////////////////////////////////////////
+void XPButtonStrategy::draw(HWND hWnd, const HDC &hDc, const RECT &rPos) const
+{
+}
+//////////////////////////////////////////////////////////////////////
+// Func: drawButtonUp()
+// Desc: draw the button in an up state
+//////////////////////////////////////////////////////////////////////
+void XPButtonStrategy::drawButtonUp(HWND hWnd, const HDC &hDc, const RECT &rPos) const
+{
+}
+//////////////////////////////////////////////////////////////////////
+// Func: drawButtonDown()
+// Desc: draw the button in a down state
+//////////////////////////////////////////////////////////////////////
+void XPButtonStrategy::drawButtonDown(HWND hWnd, const HDC &hDc, const RECT &rPos) const
+{
+}
\ No newline at end of file
diff --git a/Hooks/ButtonHook/ButtonStrategy.h b/Hooks/ButtonHook/ButtonStrategy.h
new file mode 100644
index 0000000..64605ac
--- /dev/null
+++ b/Hooks/ButtonHook/ButtonStrategy.h
@@ -0,0 +1,102 @@
+#pragma once
+
+namespace Ooganizer
+{
+ //////////////////////////////////////////////////////////////////////
+ // Itce: ButtonStrategy
+ // Desc: This interface allows us to abstract out specific implementations
+ // for different caption buttons with different Themes.
+ //
+ // Note: following functions will be called from the windows messages to
+ // be implemented directly here independently and draw only the button.
+ //
+ // Note2: Each Button Strategy is directly tied to a C
+ //////////////////////////////////////////////////////////////////////
+ class ButtonStrategy
+ {
+ public:
+ // generic draw function - called for all default messages
+ virtual void draw(HWND hWnd, const HDC &hdc, const RECT &rpos) const = 0;
+ // draw the button in an up state
+ virtual void drawButtonUp(HWND hWnd, const HDC &hDc, const RECT &rPos) const = 0;
+ // draw the button in a down state
+ virtual void drawButtonDown(HWND hWnd, const HDC &hDc, const RECT &rPos) const = 0;
+
+ // returns the RECT position of the the CaptionButton
+ virtual void CalcCaptionButtonRect(HWND hWnd, RECT& RectButtonPos) const = 0;
+
+ ////
+ // returns the dimension / size of the caption / title bar (impl. in base)
+ ////
+ void CalcCaptionRect(HWND hWnd, RECT& RectCaption, SIZE &heightNwidth) const;
+
+ ButtonStrategy(void);
+ virtual ~ButtonStrategy(void);
+ };
+ //////////////////////////////////////////////////////////////////////
+ // Clss: ClassicButtonStrategy
+ // Desc: Implementation for our Windows Classic Theme Strategy
+ //////////////////////////////////////////////////////////////////////
+ class ClassicButtonStrategy : public ButtonStrategy
+ {
+ public:
+ void draw(HWND hWnd, const HDC &hdc, const RECT &rpos) const;
+ void drawButtonUp(HWND hWnd, const HDC &hDc, const RECT &rPos) const;
+ void drawButtonDown(HWND hWnd, const HDC &hDc, const RECT &rPos) const;
+
+ void CalcCaptionButtonRect(HWND hWnd, RECT& RectButtonPos) const {};
+
+ ClassicButtonStrategy();
+ virtual ~ClassicButtonStrategy();
+ };
+ //////////////////////////////////////////////////////////////////////
+ // Clss: AeroButtonStrategy
+ // Desc: Implementation for our Windows Aero (Glass) Strategy
+ //////////////////////////////////////////////////////////////////////
+ class AeroButtonStrategy : public ButtonStrategy
+ {
+ public:
+ virtual void draw(HWND hWnd, const HDC &hdc, const RECT &rpos) const;
+ void drawButtonUp(HWND hWnd, const HDC &hDc, const RECT &rPos) const;
+ void drawButtonDown(HWND hWnd, const HDC &hDc, const RECT &rPos) const;
+
+ void CalcCaptionButtonRect(HWND hWnd, RECT& RectButtonPos) const;
+
+ AeroButtonStrategy();
+ virtual ~AeroButtonStrategy();
+ };
+ //////////////////////////////////////////////////////////////////////
+ // Clss: VistaNoAeroStrategy
+ // Desc: Implementation for Vista when Aero (Glass) is not running
+ //////////////////////////////////////////////////////////////////////
+ class VistaNoAeroStrategy : public ButtonStrategy
+ {
+ public:
+ virtual void draw(HWND hWnd, const HDC &hdc, const RECT &rpos) const;
+ void drawButtonUp(HWND hWnd, const HDC &hDc, const RECT &rPos) const;
+ void drawButtonDown(HWND hWnd, const HDC &hDc, const RECT &rPos) const;
+
+ void CalcCaptionButtonRect(HWND hWnd, RECT& RectButtonPos) const;
+
+ // Uses Hidden Window Strategy
+ VistaNoAeroStrategy();
+ virtual ~VistaNoAeroStrategy();
+ };
+ //////////////////////////////////////////////////////////////////////
+ // Clss: XPButtonStrategy
+ // Desc: Implementation for Windows XP Themed Strategy
+ //////////////////////////////////////////////////////////////////////
+ class XPButtonStrategy : public ButtonStrategy
+ {
+ public:
+
+ virtual void draw(HWND hWnd, const HDC &hdc, const RECT &rpos) const;
+ void drawButtonUp(HWND hWnd, const HDC &hDc, const RECT &rPos) const;
+ void drawButtonDown(HWND hWnd, const HDC &hDc, const RECT &rPos) const;
+
+ void CalcCaptionButtonRect(HWND hWnd, RECT& RectButtonPos) const{};
+
+ XPButtonStrategy();
+ virtual ~XPButtonStrategy();
+ };
+}
\ No newline at end of file
diff --git a/Hooks/ButtonHook/CWHPaccess.cpp b/Hooks/ButtonHook/CWHPaccess.cpp
new file mode 100644
index 0000000..221381e
--- /dev/null
+++ b/Hooks/ButtonHook/CWHPaccess.cpp
@@ -0,0 +1,414 @@
+#include "stdafx.h"
+#include "CWHPaccess.h"
+
+using namespace Ooganizer;
+//////////////////////////////////////////////////////////////////////
+//********************************************************************
+// Global variables - Shared Data Segment (Shared across all instances
+// of this dll!)
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+#pragma data_seg( ".CWHP" )
+HHOOK CWHPaccess::hHook = NULL;
+HookWndItem CWHPaccess::HList[MAX_PATH] = {NULL,NULL,NULL,NULL};
+UINT CWHPaccess::HListI = 0;
+wchar_t CWHPaccess::ALLOWED_PROCESS_NAMES[MAX_PATH][MAX_PATH] = {0};
+UINT CWHPaccess::NUMBER_OF_ALLOWED_PROCESS_NAMES = 0;
+wchar_t CWHPaccess::ALLOWED_WINDOW_TITLES[MAX_PATH][MAX_PATH] = {0};
+UINT CWHPaccess::NUMBER_OF_ALLOWED_WINDOW_TITLES = 0;
+wchar_t CWHPaccess::ALLOWED_WINDOW_CLASSES[MAX_PATH][MAX_PATH] = {0};
+UINT CWHPaccess::NUMBER_OF_ALLOWED_WINDOW_CLASSES = 0;
+UINT CWHPaccess::nLoggingDetail = LOGGING_NONE;
+wchar_t CWHPaccess::LoggingPath[MAX_PATH] = {0};
+#pragma data_seg()
+#pragma comment( linker, "/SECTION:.CWHP,rws" )
+//////////////////////////////////////////////////////////////////////
+// Constructor / Destructor
+//////////////////////////////////////////////////////////////////////
+CWHPaccess::CWHPaccess()
+{
+ InitializeCriticalSection(&cs);
+}
+CWHPaccess::~CWHPaccess()
+{
+ DeleteCriticalSection(&cs);
+}
+// Set/Get hHook
+void CWHPaccess::set_hHook(HHOOK hook)
+{
+ EnterCS();
+ hHook = hook;
+ LeaveCS();
+}
+HHOOK CWHPaccess::get_hHook()
+{
+ return hHook;
+}
+// Public CRITICAL_SECTION Accessors
+void CWHPaccess::EnterCS()
+{
+ EnterCriticalSection(&cs);
+}
+void CWHPaccess::LeaveCS()
+{
+ LeaveCriticalSection(&cs);
+}
+//////////////////////////////////////////////////////////////////////
+// Func: ClearHookItem()
+// Desc: Clears a single Hook Item
+//////////////////////////////////////////////////////////////////////
+void CWHPaccess::ClearHookItem(UINT nItem)
+{
+ if((nItem < 0) || (nItem >= MAX_PATH))
+ return;
+
+ HList[nItem].hWnd = NULL;
+ HList[nItem].DefWndProc = NULL;
+ HList[nItem].HookWndProc = NULL;
+ HList[nItem].wpfcaller = NULL;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: ClearHookSData()
+// Desc: Clears all the data stored in the Shared DS segment's Hook List
+//////////////////////////////////////////////////////////////////////
+void CWHPaccess::ClearHookSData()
+{
+ EnterCS();
+ hHook = NULL;
+ HListI = 0;
+
+ for (int i=0; i < MAX_PATH; ++i)
+ ClearHookItem(i);
+
+ LeaveCS();
+}
+//////////////////////////////////////////////////////////////////////
+// Func: InsertHookedWndItem()
+// Desc: Inserts a HookWndItem into the Shared DS's HookedList
+//////////////////////////////////////////////////////////////////////
+BOOL CWHPaccess::InsertHookedWndItem(HookWndItem &Item)
+{
+ BOOL bRetVal = FALSE;
+ EnterCS();
+ for (UINT i = 0;i < MAX_PATH; ++i)
+ {
+ if(HList[i].hWnd == NULL)
+ {
+ HList[i] = Item;
+
+ log(LOGGING_DEBUG, L"Inserting HookedItem into DS index = %i", i);
+ // Keep track of the list top index *performance*
+ if(i > HListI)
+ {
+ HListI = i;
+ log(LOGGING_DEBUG, L"Inserting HookedItem setting HListI = %i", HListI);
+ }
+ bRetVal = TRUE;
+ break;
+ }
+ }
+ LeaveCS();
+
+ return bRetVal;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: FindHookedWnd()
+// Desc: Finds Inserts a HookWndItem into the Shared DS's HookedList
+//////////////////////////////////////////////////////////////////////
+BOOL CWHPaccess::FindHookedWnd(HWND hWnd)
+{
+ BOOL bRetVal = FALSE;
+
+ EnterCS();
+ for (UINT i = 0;i <= HListI;++i)
+ {
+ if(HList[i].hWnd == hWnd)
+ {
+ bRetVal = TRUE;
+ break;
+ }
+ }
+ LeaveCS();
+
+ return bRetVal;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: GetHookedWndItem()
+// Desc: Returns a matchin HookWndItem (.hWnd will be NULL if not found)
+//////////////////////////////////////////////////////////////////////
+HookWndItem CWHPaccess::GetHookedWndItem(HWND hWnd)
+{
+ BLANK_HookWndItem(retVal);
+
+ EnterCS();
+ for (UINT i = 0;i <= HListI;++i)
+ {
+ if(HList[i].hWnd == hWnd)
+ {
+ retVal = HList[i];
+ }
+ }
+ LeaveCS();
+
+ return(retVal);
+}
+//////////////////////////////////////////////////////////////////////
+// Func: GetHookedWindowListNSize()
+// Desc: Use this to get a copy of the hooked window buffer and size in the Shared DS
+//////////////////////////////////////////////////////////////////////
+void CWHPaccess::GetHookedWindowListNSize(int* nbuf, int* nsize)
+{
+ EnterCS();
+
+ // write out the size
+ *nsize = HListI;
+
+ for (UINT i = 0;i <= HListI;++i)
+ {
+ // write out the actual buffer
+ *(nbuf + i) = (int) HList[i].hWnd;
+ }
+
+ LeaveCS();
+}
+//////////////////////////////////////////////////////////////////////
+// Func: SetHookedWndItem()
+// Desc: Use this to overwrite Hook information for a window in the Shared DS
+//////////////////////////////////////////////////////////////////////
+BOOL CWHPaccess::SetHookedWndItem(HWND hWnd, HookWndItem& Item)
+{
+ BOOL bRetVal = FALSE;
+ EnterCS();
+ for (UINT i = 0;i <= HListI;++i)
+ {
+ if((HList[i].hWnd == hWnd) &&
+ (hWnd == Item.hWnd))
+ {
+ HList[i] = Item;
+ bRetVal = TRUE;
+ }
+ }
+ LeaveCS();
+ return bRetVal;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: DeleteHookedWnd()
+// Desc: Finds Inserts a HookWndItem into the Shared DS's HookedList
+//////////////////////////////////////////////////////////////////////
+BOOL CWHPaccess::DeleteHookedWnd(HWND hWnd)
+{
+
+ BOOL retVal = FALSE;
+ EnterCS();
+ // Is it the Last Item in the list?
+ if(HList[HListI].hWnd == hWnd)
+ {
+ ClearHookItem(HListI);
+ if(HListI > 0)
+ {
+ HListI = HListI - 1;
+ log(LOGGING_DEBUG, L"DeleteHookedWnd HListI set to %i", HListI);
+ }
+
+ retVal = TRUE;
+ }
+ else
+ {
+ for (UINT i = 0; i <= HListI; ++i)
+ {
+ if(HList[i].hWnd == hWnd)
+ {
+ ClearHookItem(i);
+ deltaListTopI(i);
+ retVal = TRUE;
+ break;
+ }
+ }
+ }
+ LeaveCS();
+
+ return retVal;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: deltaListTopI()
+// Desc: *for performance * adjusts the Top index responding to a delete
+//////////////////////////////////////////////////////////////////////
+void CWHPaccess::deltaListTopI(int deletedIndex)
+{
+ UINT i;
+
+ EnterCS();
+ for(i = deletedIndex + 1; i <= HListI; ++i)
+ {
+ if(HList[i].hWnd == NULL)
+ {
+ continue;
+ }
+ break;
+ }
+ if(i > HListI)
+ {
+ if(deletedIndex > 0)
+ {
+ HListI = deletedIndex - 1;
+ log(LOGGING_DEBUG, L"deltaListTopI HListI set to %i", HListI);
+ }
+ else
+ {
+ log(LOGGING_DEBUG, L"deltaListTopI HListI set to %i", HListI);
+ HListI = 0;
+ }
+ }
+ LeaveCS();
+}
+//////////////////////////////////////////////////////////////////////
+// Func: AddAllowedProcessName()
+// Desc: Add Allowed Process Name
+//////////////////////////////////////////////////////////////////////
+void CWHPaccess::AddAllowedProcessName(wchar_t* strProcessNameInUpperCase)
+{
+ if(strProcessNameInUpperCase)
+ {
+ EnterCS();
+ int i = NUMBER_OF_ALLOWED_PROCESS_NAMES;
+ lstrcpyn(ALLOWED_PROCESS_NAMES[i], strProcessNameInUpperCase, MAX_PATH - 1);
+ NUMBER_OF_ALLOWED_PROCESS_NAMES = i + 1;
+ LeaveCS();
+
+ log(LOGGING_DEBUG, L"Allowing Process %s", strProcessNameInUpperCase);
+ }
+
+}
+//////////////////////////////////////////////////////////////////////
+// Func: IsAllowedProcessName()
+// Desc: Find Allowed Process Name
+//////////////////////////////////////////////////////////////////////
+BOOL CWHPaccess::IsAllowedProcessName(wchar_t* strProcessNameInUpperCase)
+{
+ BOOL bRetVal = FALSE;
+ if(strProcessNameInUpperCase)
+ {
+ EnterCS();
+ for (UINT i = 0; i < NUMBER_OF_ALLOWED_PROCESS_NAMES; ++i)
+ {
+ if(wcsstr(strProcessNameInUpperCase, ALLOWED_PROCESS_NAMES[i]))
+ {
+ bRetVal = TRUE;
+ break;
+ }
+ }
+ LeaveCS();
+ }
+ return bRetVal;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: AddAllowedApplication()
+// Desc: Add Allowed Windows Titles
+//////////////////////////////////////////////////////////////////////
+void CWHPaccess::AddAllowedWindowsTitle(wchar_t* strWindowsTitleInUpperCase)
+{
+ if(strWindowsTitleInUpperCase)
+ {
+ EnterCS();
+ int i = NUMBER_OF_ALLOWED_WINDOW_TITLES;
+ lstrcpyn(ALLOWED_WINDOW_TITLES[i], strWindowsTitleInUpperCase, MAX_PATH - 1);
+ NUMBER_OF_ALLOWED_WINDOW_TITLES = i + 1;
+ LeaveCS();
+
+ log(LOGGING_DEBUG, L"Allowing Window %s", strWindowsTitleInUpperCase);
+ }
+}
+//////////////////////////////////////////////////////////////////////
+// Func: IsAllowedWindowsTitle()
+// Desc: Find Allowed Window Title
+//////////////////////////////////////////////////////////////////////
+BOOL CWHPaccess::IsAllowedWindowsTitle(wchar_t* strWindowsTitleInUpperCase)
+{
+ BOOL bRetVal = FALSE;
+ if(strWindowsTitleInUpperCase)
+ {
+ EnterCS();
+ for (UINT i = 0; i < NUMBER_OF_ALLOWED_WINDOW_TITLES; ++i)
+ {
+ if(wcsstr(strWindowsTitleInUpperCase, ALLOWED_WINDOW_TITLES[i]))
+ {
+ bRetVal = TRUE;
+ break;
+ }
+ }
+ LeaveCS();
+ }
+ return bRetVal;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: AddAllowedWindowsClass()
+// Desc: Add Allowed Windows Class
+//////////////////////////////////////////////////////////////////////
+void CWHPaccess::AddAllowedWindowsClass(wchar_t* strWindowsClassInUpperCase)
+{
+ if(strWindowsClassInUpperCase)
+ {
+ EnterCS();
+ int i = NUMBER_OF_ALLOWED_WINDOW_CLASSES;
+ lstrcpyn(ALLOWED_WINDOW_CLASSES[i], strWindowsClassInUpperCase, MAX_PATH - 1);
+ NUMBER_OF_ALLOWED_WINDOW_CLASSES = i + 1;
+ LeaveCS();
+
+ log(LOGGING_DEBUG, L"Allowing Window Class %s", strWindowsClassInUpperCase);
+ }
+}
+//////////////////////////////////////////////////////////////////////
+// Func: IsAllowedWindowsClass()
+// Desc: Find Allowed Window Class
+//////////////////////////////////////////////////////////////////////
+BOOL CWHPaccess::IsAllowedWindowsClass(wchar_t* strWindowsClassInUpperCase)
+{
+ BOOL bRetVal = FALSE;
+ if(strWindowsClassInUpperCase)
+ {
+ EnterCS();
+ for (UINT i = 0; i < NUMBER_OF_ALLOWED_WINDOW_CLASSES; ++i)
+ {
+ if(wcsstr(strWindowsClassInUpperCase, ALLOWED_WINDOW_CLASSES[i]))
+ {
+ bRetVal = TRUE;
+ break;
+ }
+ }
+ LeaveCS();
+ }
+ return bRetVal;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: SetLoggingDetail()
+// Desc: Allows us to set a global used by all button hooks to log
+//////////////////////////////////////////////////////////////////////
+void CWHPaccess::SetLoggingDetail(LoggingDetail nLoggingDetailSetting)
+{
+ EnterCS();
+ nLoggingDetail = nLoggingDetailSetting;
+ LeaveCS();
+}
+//////////////////////////////////////////////////////////////////////
+// Desc: Returns the Detail of our Logging (high, medium, low, or none)
+//////////////////////////////////////////////////////////////////////
+LoggingDetail CWHPaccess::GetLoggingDetail()
+{
+ return (static_cast(nLoggingDetail));
+}
+//////////////////////////////////////////////////////////////////////
+// Desc: Get Directory location where we should log to
+//////////////////////////////////////////////////////////////////////
+wchar_t* CWHPaccess::GetLogPath()
+{
+ return reinterpret_cast(&LoggingPath);
+}
+//////////////////////////////////////////////////////////////////////
+// Desc: Set Directory location where we should log to
+//////////////////////////////////////////////////////////////////////
+void CWHPaccess::SetLogPath(wchar_t* buf)
+{
+ EnterCS();
+ lstrcpyn(LoggingPath,buf,MAX_PATH - 1);
+ EnterCS();
+}
\ No newline at end of file
diff --git a/Hooks/ButtonHook/CWHPaccess.h b/Hooks/ButtonHook/CWHPaccess.h
new file mode 100644
index 0000000..1d70f59
--- /dev/null
+++ b/Hooks/ButtonHook/CWHPaccess.h
@@ -0,0 +1,97 @@
+// CWHPaccess.h
+#pragma once
+#include "WPFCaller.h"
+
+namespace Ooganizer
+{
+ //////////////////////////////////////////////////////////////////////
+ //********************************************************************
+ // DS access Class - Created to easily enforce critical sections and
+ // share the statically created DS
+ //********************************************************************
+ //////////////////////////////////////////////////////////////////////
+ class CWHPaccess
+ {
+ public:
+ ////
+ // All these statics are put into the DS and shared accross all DLL instances
+ // ~Use accessor functions below to modify these
+ ////
+ static HINSTANCE hModule;
+ static HHOOK hHook;
+ static HookWndItem HList[MAX_PATH];
+ static UINT HListI;
+
+ static wchar_t ALLOWED_PROCESS_NAMES[MAX_PATH][MAX_PATH];
+ static UINT NUMBER_OF_ALLOWED_PROCESS_NAMES;
+
+ static wchar_t ALLOWED_WINDOW_TITLES[MAX_PATH][MAX_PATH];
+ static UINT NUMBER_OF_ALLOWED_WINDOW_TITLES;
+
+ static wchar_t ALLOWED_WINDOW_CLASSES[MAX_PATH][MAX_PATH];
+ static UINT NUMBER_OF_ALLOWED_WINDOW_CLASSES;
+
+ static UINT nLoggingDetail;
+ static wchar_t LoggingPath[MAX_PATH];
+
+ // Hook Handle
+ void set_hHook(HHOOK);
+ HHOOK get_hHook();
+
+ // Clears all Shared DS segment's Hook List data
+ // (imp, when releasing the hook)
+ void ClearHookSData();
+
+ // Allows a Caller to get a copy of all hooked Window Handles
+ // and size of the hooked window list
+ void GetHookedWindowListNSize(int* nbuf, int* nsize);
+
+ ////
+ // Find,Insert,Deletion of HookWnd
+ ////
+ BOOL InsertHookedWndItem(HookWndItem& Item);
+ BOOL FindHookedWnd(HWND hWnd);
+ HookWndItem GetHookedWndItem(HWND hWnd);
+ BOOL SetHookedWndItem(HWND hWnd, HookWndItem& Item);
+ BOOL DeleteHookedWnd(HWND hWnd);
+
+ ////
+ // Allowed ProcessNames & WindowTitles & Classes WhiteList
+ ////
+ void AddAllowedProcessName(wchar_t* strProcessNameInUpperCase);
+ BOOL IsAllowedProcessName(wchar_t* strProcessNameInUpperCase);
+ void AddAllowedWindowsTitle(wchar_t* strWindowsTitleInUpperCase);
+ BOOL IsAllowedWindowsTitle(wchar_t* strWindowsTitleInUpperCase);
+ void AddAllowedWindowsClass(wchar_t* strWindowsClassInUpperCase);
+ BOOL IsAllowedWindowsClass(wchar_t* strWindowsClassInUpperCase);
+
+ ////
+ // Get/Set and use Logging Detail Levels
+ ////
+ void SetLoggingDetail(LoggingDetail nLoggingDetailSetting);
+ LoggingDetail GetLoggingDetail();
+ wchar_t* GetLogPath();
+ void SetLogPath(wchar_t* buf);
+
+ // CRITICAL_SECTION
+ void EnterCS();
+ void LeaveCS();
+
+ CWHPaccess();
+ ~CWHPaccess();
+
+ private:
+ ////
+ // Private functions to keep track of iteration
+ ////
+ void deltaListTopI(int);
+
+ ////
+ // Private Helper Functions
+ ////
+ void ClearHookItem(UINT nItem);
+
+ //Many threads could update the DS.
+ CRITICAL_SECTION cs;
+ };
+}
\ No newline at end of file
diff --git a/Hooks/ButtonHook/HookList.h b/Hooks/ButtonHook/HookList.h
new file mode 100644
index 0000000..1ecc834
--- /dev/null
+++ b/Hooks/ButtonHook/HookList.h
@@ -0,0 +1,151 @@
+//#pragma once
+//
+//#include "malloc.h"
+//
+//namespace Ooganizer
+//{
+//
+// enum ButtonState{BUTTON_UP,BUTTON_DOWN};
+//
+// //////////////////////////////////////////////////////////////////////
+// // Clss: HookItem
+// // Desc: Hook Item is used in the HookList. Each HookItem keeps track
+// // of all the addresses needed for each hook, as well as the
+// // hookstate.
+// //
+// // Note: Add State Items for a Window as neccessary
+// //////////////////////////////////////////////////////////////////////
+// class HookItem
+// {
+// public:
+// HWND m_hWnd;
+// WNDPROC m_HookWndProc;
+// WNDPROC m_DefWndProc;
+// ButtonState m_btnState;
+//
+// // Constructor
+// HookItem(HWND hWnd, WNDPROC hookWndProc, WNDPROC defWndProc):
+// m_hWnd(hWnd),
+// m_HookWndProc(hookWndProc),
+// m_DefWndProc(defWndProc),
+// m_btnState(BUTTON_UP)
+// {
+// }
+// };
+// //////////////////////////////////////////////////////////////////////
+// // Clss: HookList
+// // Desc: Generic List / Custom written list for the sake of speed.
+// // Hook list is made up of individual HookItems.
+// //
+// // Note: You can use GetNext() to iterate thru all the items in the list.
+// // ~adding or removing an item causes GetNext() to start over.
+// //////////////////////////////////////////////////////////////////////
+// class HookList
+// {
+// public:
+// //////////////////////////////////////////////////////////////////////
+// // Func: AddItem()
+// // Desc: Adds a HookItem to the List
+// //////////////////////////////////////////////////////////////////////
+// void AddItem(HookItem* pItem)
+// {
+// m_NbrItems++;
+//
+// if ( m_pHookItem == NULL )
+// m_pHookItem = (HookItem*) malloc( m_NbrItems * sizeof( HookItem ) );
+// else
+// m_pHookItem = (HookItem*) realloc( m_pHookItem, m_NbrItems * sizeof( HookItem ) );
+//
+// log(pItem->m_hWnd,"hase been added");
+//
+// memcpy( m_pHookItem+(m_NbrItems-1), pItem, sizeof( HookItem ) );
+// }
+// //////////////////////////////////////////////////////////////////////
+// // Func: GetItem()
+// // Desc: Get a HookItem from the List
+// //////////////////////////////////////////////////////////////////////
+// HookItem* GetItem(HWND hWnd)
+// {
+// UINT i;
+// HookItem * pItem = m_pHookItem;
+// for( i=0; im_hWnd!=hWnd; i++, pItem++ );
+// return ( i < m_NbrItems ) ? pItem : NULL;
+// }
+// //////////////////////////////////////////////////////////////////////
+// // Func: DelItem()
+// // Desc: Deletes a HookItem from the List
+// //////////////////////////////////////////////////////////////////////
+// void DelItem(HWND hWnd)
+// {
+// UINT i;
+// HookItem * pItem = m_pHookItem;
+// for( i =0; im_hWnd!=hWnd; i++, pItem++ );
+// if ( i < m_NbrItems )
+// {
+// m_NbrItems--;
+// memcpy( pItem, pItem+1, ( m_NbrItems - i ) * sizeof( HookItem ) );
+// m_pHookItem = (HookItem*) realloc( m_pHookItem, m_NbrItems * sizeof( HookItem ) );
+//
+// log(pItem->m_hWnd,"hase been deleted");
+// }
+// }
+// //////////////////////////////////////////////////////////////////////
+// // Func: DelAllItems()
+// // Desc: Deletes all HookItems from the List
+// //////////////////////////////////////////////////////////////////////
+// void DelAllItems()
+// {
+// if ( m_pHookItem != NULL )
+// free( m_pHookItem );
+// m_pHookItem = NULL;
+// m_NbrItems = 0;
+// }
+// //////////////////////////////////////////////////////////////////////
+// // Func: UnhookAllItems()
+// // Desc: Responsible for iterating through entire list and 'unhooking'
+// // the WndProc function of every HookItem
+// //
+// // Note: has to be put in here since the list has to be iterated here
+// //////////////////////////////////////////////////////////////////////
+// void UnhookAllItems()
+// {
+// HookItem * pItem;
+//
+// while ( m_NbrItems > 0 )
+// {
+// pItem = m_pHookItem+(m_NbrItems-1);
+//
+// // Unhook window
+// HWND hWnd = pItem->m_hWnd;
+//
+// log(hWnd,"Unhooking...");
+// SetWindowLong( hWnd, GWL_WNDPROC, (LONG) pItem->m_DefWndProc );
+// SendMessage( hWnd, WM_NCPAINT, 1, 0 );
+// log(hWnd,"Sending WM_NCPAINT message...");
+//
+// // Delete item
+// DelItem( hWnd );
+// }
+// }
+// //////////////////////////////////////////////////////////////////////
+// // Func: CleanUp()
+// // Desc: Unhooks all HookItems in the list and deletes the list
+// //////////////////////////////////////////////////////////////////////
+// void CleanUp()
+// {
+// UnhookAllItems();
+// DelAllItems();
+// }
+// //////////////////////////////////////////////////////////////////////
+// //********************************************************************
+// // Construction / Destruction
+// //********************************************************************
+// //////////////////////////////////////////////////////////////////////
+// HookList():m_NbrItems(0),m_pHookItem(NULL){}
+// ~HookList(){CleanUp();}
+//
+// protected:
+// UINT m_NbrItems;
+// HookItem* m_pHookItem;
+// };
+//}
\ No newline at end of file
diff --git a/Hooks/ButtonHook/HookWndItem.h b/Hooks/ButtonHook/HookWndItem.h
new file mode 100644
index 0000000..71cf895
--- /dev/null
+++ b/Hooks/ButtonHook/HookWndItem.h
@@ -0,0 +1,20 @@
+// HookWndItem.h
+#pragma once
+extern class CaptionButton;
+
+//////////////////////////////////////////////////////////////////////
+// Strc: HookWndItem
+// Desc: Hook Item is used in the HookedWndList. Each HookWndItem keeps track
+// of all the addresses needed for each hook for each Windows,
+// as well as each Window's ButtonState.
+//
+// Note: Add State Items for a Window as neccessary
+//////////////////////////////////////////////////////////////////////
+struct HookWndItem
+{
+ HWND hWnd;
+ WNDPROC HookWndProc;
+ WNDPROC DefWndProc;
+ ButtonState state;
+ CaptionButton* button;
+};
\ No newline at end of file
diff --git a/Hooks/ButtonHook/Stdafx.cpp b/Hooks/ButtonHook/Stdafx.cpp
new file mode 100644
index 0000000..ca1c0cb
--- /dev/null
+++ b/Hooks/ButtonHook/Stdafx.cpp
@@ -0,0 +1,153 @@
+// stdafx.cpp : source file that includes just the standard includes
+// Ooganizer-Hook.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+#include "stdafx.h"
+#include "stdio.h"
+#include "stdlib.h"
+
+//////////////////////////////////////////////////////////////////////
+// Func: SetLoggingDetail()
+//////////////////////////////////////////////////////////////////////
+void SetLoggingDetail(LoggingDetail detail, wchar_t* logPath)
+{
+#ifdef _DEBUG
+ g_LoggingDetail = LOGGING_DEBUG;
+#else
+ g_LoggingDetail = detail;
+#endif
+
+ // If the log path is set externally set it here internally
+ // else set the log path to %USERPROFILE%\AppData\Local\Temp
+ if(logPath && logPath[0] != 0)
+ {
+ lstrcpyn(g_LogPath, logPath, (MAX_PATH - lstrlen(g_LOG_FILE_NAME)));
+ }
+ else
+ {
+ size_t len = 0;
+ errno_t err = 0;
+ wchar_t* pValue = NULL;
+
+ if(err = _wdupenv_s( &pValue, &len, L"TMP"))
+ if(err = _wdupenv_s( &pValue, &len, L"TEMP"))
+ return;
+
+ if(pValue != NULL)
+ lstrcpyn(g_LogPath, pValue, (MAX_PATH - lstrlen(g_LOG_FILE_NAME)));
+ }
+
+ // Make sure Path ends with '\'
+ if(g_LogPath[lstrlen(g_LogPath) - 1] != L'\\')
+ lstrcat(g_LogPath, L"\\");
+
+ // Add the Log File name to the path variable (now we have everything)
+ // ~we are ready to do some serious logging
+ lstrcat(g_LogPath,g_LOG_FILE_NAME);
+}
+//////////////////////////////////////////////////////////////////////
+// Func: GetLoggingDetail()
+//////////////////////////////////////////////////////////////////////
+_LoggingDetail GetLoggingDetail()
+{
+ return g_LoggingDetail;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: log()
+// Desc: Logs to Ooganizer.log in defined LogPath or temporary folder
+// Prms: Variable # of params
+//
+// Usge: Log("%s %d %d %d", "test", 1, 2, 3)
+//////////////////////////////////////////////////////////////////////
+//void log( LoggingDetail detail, char * pFmt, ... )
+//{
+// if(g_LoggingDetail >= detail)
+// {
+// FILE* pFile = NULL;
+// errno_t err = 0;
+//
+// if ( !( err = fopen_s( &pFile, g_LogPath, "at" ) ) )
+// {
+// fprintf( pFile, "ThreadId %i -", GetCurrentThreadId());
+// va_list arg;
+// va_start( arg, pFmt );
+// vfprintf( pFile, pFmt, arg );
+// va_end( arg );
+//
+// if ( pFmt[strlen( pFmt ) - 1] != '\n' )
+// fprintf( pFile, "\n" );
+// fclose( pFile );
+// }
+// }
+//}
+//////////////////////////////////////////////////////////////////////
+// Func: log()
+// Desc: Logs to Ooganizer.log in defined LogPath or temporary folder using Wide Char
+// Prms: Variable # of params
+//
+// Usge: Log("%s %d %d %d", "test", 1, 2, 3)
+//////////////////////////////////////////////////////////////////////
+void log( LoggingDetail detail, wchar_t * pFmt, ... )
+{
+ if(g_LoggingDetail >= detail)
+ {
+ FILE* pFile = NULL;
+ errno_t err = 0;
+
+ if ( !( err = _wfopen_s( &pFile, g_LogPath, L"at" ) ) )
+ {
+
+ if(detail == LOGGING_LOW)
+ fwprintf( pFile, L"ThreadId %i - [Imp] - ", GetCurrentThreadId()); // low == very important messages
+ else if(detail == LOGGING_MEDIUM)
+ fwprintf( pFile, L"ThreadId %i - {P/D} - ", GetCurrentThreadId()); // medium == program details
+ else if(detail == LOGGING_HIGH)
+ fwprintf( pFile, L"ThreadId %i - {X/D} - ", GetCurrentThreadId()); // high == more program details (extra}
+ else if(detail == LOGGING_DEBUG)
+ fwprintf( pFile, L"ThreadId %i - Debug - ", GetCurrentThreadId()); // debug == only show up in debug builds (Debug Only)
+ else
+ fwprintf( pFile, L"ThreadId %i - - ", GetCurrentThreadId()); // should never happen
+
+ va_list arg;
+ va_start( arg, pFmt );
+ vfwprintf( pFile, pFmt, arg );
+ va_end( arg );
+
+ if ( pFmt[lstrlen( pFmt ) - 1] != '\n' )
+ fwprintf( pFile, L"\n" );
+ fclose( pFile );
+ }
+ }
+}
+//////////////////////////////////////////////////////////////////////
+// Func: log()
+// Desc: Logs the window title text to the Log File
+// Prms: HWND, handle to a window
+// str, custom string to log
+//
+// Note: GetWindowText doesn't always return TRUE, if this function
+// gets called during the WndProc it will return False
+//////////////////////////////////////////////////////////////////////
+void log(LoggingDetail detail, HWND hWnd, wchar_t* str)
+{
+ if(g_LoggingDetail >= detail)
+ {
+ wchar_t Title[MAX_PATH + 1] = {0};
+ if (GetWindowText(hWnd,Title,MAX_PATH))
+ log(detail, L"Window - %s - %s", Title, str);
+ }
+}
+//////////////////////////////////////////////////////////////////////
+// Func: clearLog()
+// Desc: clears the log file (used at startup) - Only Clears if Logging is enabled
+//////////////////////////////////////////////////////////////////////
+void clearLog()
+{
+ if(g_LoggingDetail != LOGGING_NONE)
+ {
+ FILE* pFile = NULL;
+ errno_t err = 0;
+
+ if( !( err = _wfopen_s( &pFile, g_LogPath, L"w" ) ) )
+ fclose( pFile );
+ }
+}
\ No newline at end of file
diff --git a/Hooks/ButtonHook/Stdafx.h b/Hooks/ButtonHook/Stdafx.h
new file mode 100644
index 0000000..312dd01
--- /dev/null
+++ b/Hooks/ButtonHook/Stdafx.h
@@ -0,0 +1,47 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently,
+// but are changed infrequently
+#pragma once
+
+// Compiler Error Messages that we want to disable:
+#pragma warning ( disable : 4793 ) // Compiling functions as native code
+#pragma warning ( disable : 4996 ) // 'strncpy': This function or variable may be unsafe
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+
+#include
+
+//////////////////////////////////////////////////////////////////////
+//********************************************************************
+// Global Enums
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+
+// Logging Detail Settings
+typedef enum _LoggingDetail{LOGGING_NONE,LOGGING_LOW,LOGGING_MEDIUM,LOGGING_HIGH,LOGGING_DEBUG} LoggingDetail;
+
+// Enable Logging and if so, which detail (default = none)
+static LoggingDetail g_LoggingDetail = LOGGING_NONE;
+static wchar_t g_LogPath[MAX_PATH + 1] = {0};
+static const wchar_t g_LOG_FILE_NAME[] = L"ButtonHook.log"; // Log File for now is just hardcoded
+
+//////////////////////////////////////////////////////////////////////
+//********************************************************************
+// Global Functions
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+
+// Logs to Ooganizer.log in temporary folder if no log path is set
+// %USERPROFILE%\AppData\Local\Temp\Ooganizer.log
+//void log(LoggingDetail detail, char * pFmt, ... );
+void log( LoggingDetail detail, HWND hWnd, wchar_t* str); // Logs Window Text
+void log( LoggingDetail detail, wchar_t * pFmt, ... );
+
+// At Startup we clear the log
+void clearLog();
+
+// Set the global (for this dll instance) Logging Detail Setting
+void SetLoggingDetail(LoggingDetail detail, wchar_t* logPath);
+
+// Get Logging Detail for custom debug behavior
+_LoggingDetail GetLoggingDetail();
\ No newline at end of file
diff --git a/Hooks/ButtonHook/WPFCaller.cpp b/Hooks/ButtonHook/WPFCaller.cpp
new file mode 100644
index 0000000..334f1f1
--- /dev/null
+++ b/Hooks/ButtonHook/WPFCaller.cpp
@@ -0,0 +1,1417 @@
+#include "StdAfx.h"
+#include "WPFCaller.h"
+#include "CWHPaccess.h"
+#include "shellapi.h"
+#include "dde.h"
+#include "ddeml.h"
+
+using namespace Ooganizer;
+
+// Specifies a nonzero timer identifier
+#define NID_RESTORE_EVENT_TIMER (WM_USER + 1)
+#define NID_CLOSE_BUT_NOT_DESTROY_EVENT_TIMER (WM_USER + 2)
+
+// * Messages send from WPFCaller class to WPFProc Thread
+#define WM_KILLTHREAD (WM_USER + 501)
+
+// * Messages Send from W32Button to WPFProc Thread
+#define WM_GETBUTTONTHEMESETTING (WM_USER + 601)
+#define WM_W32BUTTONCLICKED (WM_USER + 602)
+
+// * External Messages * Send to us by outside
+// Programs (most likely WPFForm or Platform)
+#define WM_W32PINGISALIVE (WM_USER + 700)
+#define WM_W32SETBUTTONSTATE (WM_USER + 701)
+#define WM_W32GETBUTTONSTATE (WM_USER + 702)
+#define WM_W32SETPARENTWINDOWTRANSPERANCY (WM_USER + 703)
+#define WM_W32SETPARENTWINDOWACTIVE (WM_USER + 704)
+#define WM_W32POSTMESSAGETOPARENTWINDOW (WM_USER + 705)
+
+// * Messages Only handled by WPFThreadProc * Events Send to
+// C# Client Event Dispatcher for handling
+#define WM_CLIENT_EVENT_WINDOWACTIVATE (WM_USER + 800)
+#define WM_CLIENT_EVENT_DRAGNDROPOCCURED (WM_USER + 801)
+#define WM_CLIENT_EVENT_MDICHILDWINDOWSWITCHOCCURED (WM_USER + 802)
+#define WM_CLIENT_EVENT_PARENTGETSETTEXTOCCURED (WM_USER + 803)
+#define WM_CLIENT_EVENT_PARENTNOTIFYLBUTTONCLICKOCCURED (WM_USER + 804)
+#define WM_CLIENT_EVENT_PARENTNOTIFYWMCREATEOCCURED (WM_USER + 805)
+#define WM_CLIENT_EVENT_PARENTCLOSEWITHOUTDESTROYOCCURED (WM_USER + 806)
+#define WM_CLIENT_EVENT_PARENTSETFOCUSOCCURED (WM_USER + 807)
+#define WM_CLIENT_EVENT_OPENFILEORSAVEASDIALOGOCCURED (WM_USER + 808)
+
+#ifdef _DEBUG
+ #import "..\\..\\Target\\Debug\\Settings.tlb" raw_interfaces_only
+#else
+ #import "..\\..\\Target\\Release\\Settings.tlb" raw_interfaces_only
+#endif
+using namespace Settings;
+
+// access the SharedDS *initialized by WPFCaller() constructor*
+CWHPaccess* s_WPFCallerAccess = NULL;
+
+//////////////////////////////////////////////////////////////////////
+// Func: ReadButtonThemeSetting
+// Desc: static function to quickly read in Button Theme Settings.
+// ~Uses COM, must be called ONLY from within a COM initialized Thread!
+//////////////////////////////////////////////////////////////////////
+bool ReadButtonThemeSetting(WPFCaller* pCaller)
+{
+ HRESULT hr = S_FALSE;
+
+ _ButtonThemeNIconSettingsCCWPtr pButtonThemeNIconSetting;
+ hr = pButtonThemeNIconSetting.CreateInstance(__uuidof(ButtonThemeNIconSettingsCCW));
+
+ if(SUCCEEDED(hr))
+ {
+ log(LOGGING_HIGH, L"Succeed creating ButtonThemeNIconSettings Instance");
+ }
+ else
+ {
+ log(LOGGING_LOW, L"FAILED to create the ButtonThemeNIconSettings COM Instance");
+ return false;
+ }
+
+ ////
+ // Get the Button Theme N Icon Settings
+ ////
+ IButtonThemeSettingPtr pThemeSetting;
+ IButtonIconLocationPtr pIconLocation;
+ pButtonThemeNIconSetting->GetIButtonThemeInterface(&pThemeSetting);
+ pButtonThemeNIconSetting->GetIButtonIconLocation(&pIconLocation);
+
+ if(pThemeSetting == NULL)
+ log(LOGGING_LOW, L"pThemeSetting == NULL - Error");
+ if(pIconLocation == NULL)
+ log(LOGGING_LOW, L"pIconLocation == NULL - Error");
+
+ if((pThemeSetting == NULL) || (pIconLocation == NULL))
+ return false;
+
+ ////
+ // Get Button Dimension/Location
+ ////
+ if(SUCCEEDED(hr))
+ hr = pThemeSetting->Top(&pCaller->m_ButtonThemeSetting.Top);
+ if(SUCCEEDED(hr))
+ hr = pThemeSetting->Right(&pCaller->m_ButtonThemeSetting.Right);
+ if(SUCCEEDED(hr))
+ hr = pThemeSetting->Height(&pCaller->m_ButtonThemeSetting.Height);
+ if(SUCCEEDED(hr))
+ hr = pThemeSetting->Width(&pCaller->m_ButtonThemeSetting.Width);
+
+ ////
+ // Get Button Icon Location
+ ////
+ if(SUCCEEDED(hr))
+ pIconLocation->GetBUTTON_UP(pCaller->m_ButtonThemeSetting.bstrBUTTON_UP.GetAddress());
+ if(SUCCEEDED(hr))
+ pIconLocation->GetBUTTON_DOWN(pCaller->m_ButtonThemeSetting.bstrBUTTON_DOWN.GetAddress());
+ if(SUCCEEDED(hr))
+ pIconLocation->GetTOGGLE_UP(pCaller->m_ButtonThemeSetting.bstrTOGGLE_UP.GetAddress());
+
+ if(SUCCEEDED(hr))
+ {
+ log(LOGGING_HIGH, L"ReadButtonTheme Settings Successfully - Height=%i, Width=%i, Top=%i, Right=%i",
+ pCaller->m_ButtonThemeSetting.Height,pCaller->m_ButtonThemeSetting.Width,pCaller->m_ButtonThemeSetting.Top, pCaller->m_ButtonThemeSetting.Right);
+
+ if(pCaller->m_ButtonThemeSetting.bIsInitialized)
+ pCaller->m_ButtonThemeSetting.bIsChanged = true;
+
+ if(!pCaller->m_ButtonThemeSetting.bIsInitialized)
+ pCaller->m_ButtonThemeSetting.bIsInitialized = true;
+ }
+ else
+ {
+ pCaller->m_ButtonThemeSetting.bIsChanged = false;
+ pCaller->m_ButtonThemeSetting.bIsInitialized = false;
+ log(LOGGING_LOW, L"ReadButtonTheme Settings FAILED!");
+ }
+
+ if(SUCCEEDED(hr))
+ return true;
+ else
+ return false;
+}
+
+////
+// When we want to communicate back to the ButtonHook from externaly windows,
+// we use these custom messages in order to do so. We keep track of them seperatly
+// because we allow Custom Messages to return a Value to the caller.
+////
+UINT s_nMessagesCustomMessages = 6;
+UINT s_nMessagesCustomMessagesWeHave[] =
+{
+ WM_W32PINGISALIVE,
+ WM_W32SETBUTTONSTATE,
+ WM_W32GETBUTTONSTATE,
+ WM_W32SETPARENTWINDOWTRANSPERANCY,
+ WM_W32SETPARENTWINDOWACTIVE,
+ WM_W32POSTMESSAGETOPARENTWINDOW
+};
+bool g_IsMessageACustomMessage(UINT msgID)
+{
+ for(UINT i = 0; i < s_nMessagesCustomMessages; ++i)
+ {
+ if(s_nMessagesCustomMessagesWeHave[i] == msgID)
+ return true;
+ }
+ return false;
+}
+////
+// For wndproc to know what we care about and pass it down to to W32WndProc
+// ~these messages will be tagged with WM_USER for us to handle in our W32WndProc
+////
+UINT s_nMessagesWPFormCaresAbout = 2;
+UINT s_MessagesWPFormCaresAbout[] =
+{
+ WM_ACTIVATE,
+ WM_SIZE,
+};
+bool g_IsMessageWPFormCaresAbout(UINT msgID)
+{
+ for(UINT i = 0; i < s_nMessagesWPFormCaresAbout; ++i)
+ {
+ if(s_MessagesWPFormCaresAbout[i] == msgID)
+ return true;
+ }
+ return false;
+}
+////
+// For wndproc to know what we care about and pass it down to to MainWndProc
+// ~these messages will be send straight down for us to handle in our MainWndProc
+////
+UINT s_nMessagesW32WindowCaresAbout = 8;
+UINT s_MessagesW32WindowCaresAbout[] =
+{
+ WM_PAINT,
+ WM_DISPLAYCHANGE,
+ WM_THEMECHANGED,
+ WM_SIZE,
+ WM_MOVE,
+ WM_LBUTTONDOWN,
+ WM_MOUSEMOVE,
+ WM_SHOWWINDOW
+};
+bool g_IsMessageW32WindowCaresAbout(UINT msgID)
+{
+ for(UINT i = 0; i < s_nMessagesW32WindowCaresAbout; ++i)
+ {
+ if(s_MessagesW32WindowCaresAbout[i] == msgID)
+ return true;
+ }
+ return false;
+}
+//////////////////////////////////////////////////////////////////////
+// Desc: We need to make sure that we have the init button settings,
+// before we can continue in many of our Messaging functions
+//////////////////////////////////////////////////////////////////////
+void MakeSureButtonThemeSettingWereInitialized(WPFCaller* pCaller)
+{
+ // We must make sure the Button has all the settings before
+ // we can draw,move it, etc so sleep the thread until we know we have them
+ while(!pCaller->m_ButtonThemeSetting.bIsInitialized)
+ Sleep(20);
+}
+//////////////////////////////////////////////////////////////////////
+// Desc: For our WPFThread callback into WPForm we must make sure
+// that we have the handle for our W32Button so to pass it down to them
+//////////////////////////////////////////////////////////////////////
+void MakeSureW32ButtonWindowGotCreated(WPFCaller* pCaller)
+{
+ // We must make sure the Button window got created so we can pass the
+ // handle down
+ while(pCaller->m_hwndW32Window == NULL)
+ Sleep(20);
+}
+//////////////////////////////////////////////////////////////////////
+// Desc: For our Win32 Thread we must make sure we have a valid pointer to
+// a WPFCaller Object.
+//////////////////////////////////////////////////////////////////////
+WPFCaller* GetWPFCallerObject(HWND ParenthWnd)
+{
+ if(s_WPFCallerAccess)
+ {
+ BLANK_HookWndItem(Item);
+ Item = s_WPFCallerAccess->GetHookedWndItem(ParenthWnd);
+ WPFCaller* pCaller = Item.wpfcaller;
+ return pCaller;
+ }
+ return NULL;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: DrawIconButton (Owner Drawing out Buttons)
+// Desc: Responsible for drawing the owner buttons onto the caption bar
+//////////////////////////////////////////////////////////////////////
+bool DrawIconButton(HINSTANCE hInstance,HDC hdc, WPFCaller* pCaller)
+{
+ // static Icon handles:
+ static HANDLE hCurrIcon = NULL;
+ static HANDLE hButtonUp = NULL;
+ static HANDLE hButtonDown = NULL;
+ static HANDLE hToggleUp = NULL;
+
+ // LoadIcon only loads once, but LoadImage does not,
+ // so in case you call the latter, use this flag
+ static bool bIconsLoaded = false;
+
+ // Make sure that we don't continue unless we have all the settings
+ MakeSureButtonThemeSettingWereInitialized(pCaller);
+
+ if (!bIconsLoaded || pCaller->m_ButtonThemeSetting.bIsChanged)
+ {
+ ////
+ // ButtonUp
+ ////
+ if(!hButtonUp)
+ {
+ HANDLE hTemp = hButtonUp;
+ hButtonUp = NULL; //*avoid poss. threading issue
+ DestroyIcon((HICON)hTemp);
+ }
+ hButtonUp = LoadImage(hInstance, (WCHAR*)pCaller->m_ButtonThemeSetting.bstrBUTTON_UP,IMAGE_ICON,pCaller->m_ButtonThemeSetting.Width,pCaller->m_ButtonThemeSetting.Height,LR_LOADFROMFILE);
+ if(!hButtonUp)
+ log(LOGGING_LOW, L"hButtonUp LoadImage Failed! with error %i - path %s",GetLastError(),(wchar_t*)pCaller->m_ButtonThemeSetting.bstrBUTTON_UP);
+
+ ////
+ // ButtonDown
+ ////
+ if(!hButtonDown)
+ {
+ HANDLE hTemp = hButtonDown;
+ hButtonDown = NULL; //*avoid poss. threading issue
+ DestroyIcon((HICON)hTemp);
+ }
+ hButtonDown = LoadImage(hInstance, (WCHAR*)pCaller->m_ButtonThemeSetting.bstrBUTTON_DOWN,IMAGE_ICON,pCaller->m_ButtonThemeSetting.Width,pCaller->m_ButtonThemeSetting.Height,LR_LOADFROMFILE);
+ if(!hButtonDown)
+ log(LOGGING_LOW, L"hButtonDown LoadImage Failed! with error %i - path %s",GetLastError(),(wchar_t*)pCaller->m_ButtonThemeSetting.bstrBUTTON_DOWN);
+
+ ////
+ // ToogleUp
+ ////
+ if(!hToggleUp)
+ {
+ HANDLE hTemp = hToggleUp;
+ hToggleUp = NULL; //*avoid poss. threading issue
+ DestroyIcon((HICON)hTemp);
+ }
+ hToggleUp = LoadImage(hInstance, (WCHAR*)pCaller->m_ButtonThemeSetting.bstrTOGGLE_UP,IMAGE_ICON,pCaller->m_ButtonThemeSetting.Width,pCaller->m_ButtonThemeSetting.Height,LR_LOADFROMFILE);
+ if(!hToggleUp)
+ log(LOGGING_LOW, L"hToggleUp LoadImage Failed! with error %i - path %s",GetLastError(),(wchar_t*)pCaller->m_ButtonThemeSetting.bstrTOGGLE_UP);
+
+ // Everything went well.
+ bIconsLoaded = true;
+ pCaller->m_ButtonThemeSetting.bIsChanged = false;
+ }
+
+ ////
+ // Now Draw the proper Icon State
+ ////
+ bool bUseToogleState = (pCaller->m_ButtonToggledState != BUTTON_NONE);
+
+ if(!bUseToogleState && pCaller->m_ButtonState == BUTTON_DOWN)
+ hCurrIcon = hButtonDown;
+ else if(pCaller->m_ButtonState == BUTTON_UP)
+ hCurrIcon = hButtonUp;
+ else if(bUseToogleState || pCaller->m_ButtonState == BUTTON_TOGGLED)
+ hCurrIcon = hToggleUp;
+
+ if(hCurrIcon != NULL)
+ {
+ if (!DrawIconEx(hdc,0,0,(HICON) hCurrIcon,
+ pCaller->m_ButtonThemeSetting.Width,
+ pCaller->m_ButtonThemeSetting.Height,
+ 0, NULL, DI_NORMAL))
+ {
+ log(LOGGING_LOW, L"DrawIconEx Failed!");
+ return false;
+ }
+ }
+
+ return true;
+}
+//////////////////////////////////////////////////////////////////////
+// Desc: Set static HeightNWidth (keeping track of the Window size)
+//////////////////////////////////////////////////////////////////////
+void Helper_GetRectAndSetHeightNWidth(HWND hWnd, WPFCaller* pCaller)
+{
+ RECT rect;
+ GetWindowRect(hWnd,&rect);
+
+ pCaller->m_wndHeight = (rect.bottom - rect.top);
+ pCaller->m_wndWidth = (rect.right - rect.left);
+ pCaller->m_wndRECT = rect;
+}
+//////////////////////////////////////////////////////////////////////
+// Desc: Set static HeightNWidth (keeping track of the Window size)
+//////////////////////////////////////////////////////////////////////
+void Helper_GetRectAndSetHeightNWidthUsingPlacement(HWND hWnd, WPFCaller* pCaller)
+{
+ WINDOWPLACEMENT place;
+ place.length = sizeof(WINDOWPLACEMENT);
+ GetWindowPlacement(hWnd,&place);
+
+ pCaller->m_wndHeight = (place.rcNormalPosition.bottom - place.rcNormalPosition.top);
+ pCaller->m_wndWidth = (place.rcNormalPosition.right - place.rcNormalPosition.left);
+ pCaller->m_wndRECT = place.rcNormalPosition;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: W32WndProc (W32Window)
+// Desc: Responsible for handling the Wnd32Window's incoming messages
+//////////////////////////////////////////////////////////////////////
+LRESULT CALLBACK W32WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result = 0;
+ PAINTSTRUCT ps;
+ HDC hdc;
+ int nTop = 0;
+ int nRight = 0;
+ bool bIsMaximized = false;
+ HINSTANCE hInst = NULL;
+
+ // Use the ParentHWND to get access to the correct WPFCaller instance,
+ // we need to do this in case multiple windows exist in the same process
+ WPFCaller* pCaller = GetWPFCallerObject(::GetParent(hWnd));
+
+ // Nothing to do here, WPFCaller is not ready (just handle the message)
+ if(pCaller == NULL)
+ goto HANDLE_MESSAGE;
+
+ ////
+ // Messages should be handled here (if we are interested)
+ ////
+ try
+ {
+ // For some calls we need th HINSTANCE
+ hInst = pCaller->m_hInst;
+
+ switch(Msg)
+ {
+ ////
+ // Win32Button Messages we handle
+ ////
+ case WM_SIZE:
+ if(wParam == SIZE_MINIMIZED)
+ {
+ pCaller->m_bButtonIsMinimized = true;
+ }
+ else if((wParam == SIZE_RESTORED && pCaller->m_bButtonIsMinimized) ||
+ (wParam == SIZE_MAXIMIZED && pCaller->m_bButtonIsMinimized))
+ {
+ // the Button receives this message way before the parent does.
+ pCaller->m_bButtonIsBeingRestored = true;
+ }
+ // Intentional Fallthru
+ case WM_DISPLAYCHANGE:
+ case WM_MOVE:
+ {
+ // ~Calculate Offset for Maximized Windows - IMP
+ // in vista, we need 7 height offset
+ // we need 5 width offset
+ // ~i tried using the best values that make sense
+ const int YHEIGHT_OFFSET = GetSystemMetrics(SM_CYFRAME) - 1; // subtract 1 to better position the button (and not cut it off as much)
+ const int XWIDTH_OFFSET = (2 * GetSystemMetrics(SM_CXEDGE)) + GetSystemMetrics(SM_CXBORDER);
+ bool bIsMaximized = (IsZoomed(pCaller->m_hWnd) == TRUE);
+
+ int YOFFSET = 0;
+ int XOFFSET = 0;
+ if(bIsMaximized)
+ {
+ YOFFSET = YHEIGHT_OFFSET;
+ XOFFSET = XWIDTH_OFFSET;
+ }
+
+ // Set the Window Position (Use Offset if need be)
+ MakeSureButtonThemeSettingWereInitialized(pCaller);
+ Helper_GetRectAndSetHeightNWidth(pCaller->m_hWnd, pCaller);
+ nTop = pCaller->m_wndRECT.top + pCaller->m_ButtonThemeSetting.Top;
+ nRight = pCaller->m_wndRECT.left + pCaller->m_wndWidth - pCaller->m_ButtonThemeSetting.Right;
+ SetWindowPos(hWnd, HWND_TOP, nRight - XOFFSET, nTop + YOFFSET, pCaller->m_ButtonThemeSetting.Width, pCaller->m_ButtonThemeSetting.Height, NULL);
+
+ bool bIsMinimizeMoveMessage = false;
+ if(Msg == WM_MOVE)
+ {
+ int x = LOWORD(lParam);
+ int y = HIWORD(lParam);
+ bIsMinimizeMoveMessage = (x > 33500) && (y > 33500);
+ }
+ // If the window is just too damn small to hold all the buttons just hide it!
+ // ~better user experience
+ const int MIN_WITDH_TO_DISPLAY_BUTTON_IN = 300;
+ if((pCaller->m_wndWidth > 25) && /* make sure width is bigger >0 may as well put in some magic number buffer */
+ !bIsMinimizeMoveMessage &&
+ (pCaller->m_wndWidth < MIN_WITDH_TO_DISPLAY_BUTTON_IN) && !pCaller->m_bButtonIsArtificiallyHidden_MOVE && !pCaller->m_bButtonIsMinimized)
+ {
+ log(LOGGING_DEBUG, L"WM_MOVE Setting ButtonWindow Artificially Hidden to true");
+ pCaller->m_bButtonIsArtificiallyHidden_MOVE = true;
+ RedrawWindow(pCaller->m_hwndW32Window,NULL,NULL,(RDW_INVALIDATE | RDW_UPDATENOW));
+ }
+ else if((pCaller->m_wndWidth >= MIN_WITDH_TO_DISPLAY_BUTTON_IN) && pCaller->m_bButtonIsArtificiallyHidden_MOVE && !pCaller->m_bButtonIsMinimized)
+ {
+ log(LOGGING_DEBUG, L"WM_MOVE Setting ButtonWindow Artificially Hidden to false");
+ pCaller->m_bButtonIsArtificiallyHidden_MOVE = false;
+ pCaller->StartRestoreEventFadeTimer();
+ }
+ return 0;
+ }
+ break;
+
+ case WM_SHOWWINDOW:
+ if((BOOL) wParam == FALSE) // window is being hidden
+ {
+ pCaller->SetAlpha(0);
+ }
+ else if((BOOL) wParam == TRUE) // window is being shown
+ {
+ pCaller->StartRestoreEventFadeTimer();
+ }
+ return 0;
+
+ case WM_MOUSEMOVE:
+ TRACKMOUSEEVENT mouseEvent;
+ mouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
+ mouseEvent.dwFlags = TME_HOVER | TME_LEAVE;
+ mouseEvent.hwndTrack = hWnd;
+ mouseEvent.dwHoverTime = 25;
+ TrackMouseEvent(&mouseEvent);
+ break;
+
+ case WM_LBUTTONDOWN:
+ log(LOGGING_HIGH, L"ButtonWindow received ButtonClick Sending Click Event to WPForm");
+ PostThreadMessage(pCaller->m_threadID,WM_W32BUTTONCLICKED,NULL,NULL);
+ return 0;
+
+ case WM_MOUSEHOVER:
+ pCaller->m_ButtonState = BUTTON_UP;
+ RedrawWindow(pCaller->m_hwndW32Window,NULL,NULL,(RDW_INVALIDATE | RDW_UPDATENOW));
+ return 0;
+
+ case WM_MOUSELEAVE:
+ pCaller->m_ButtonState = BUTTON_DOWN;
+ RedrawWindow(pCaller->m_hwndW32Window,NULL,NULL,(RDW_INVALIDATE | RDW_UPDATENOW));
+ return 0;
+
+ case WM_TIMER:
+ // FadeInTimer (Restore from Minimize)
+ if(wParam == NID_RESTORE_EVENT_TIMER)
+ {
+ // Increment Opaqueness
+ const int SLEEP_INCREMENT = 1; // 1 == lowest
+ const int LOWER_INCREMENT = 7;
+ const int MIDDLE_INCREMENT = 15;
+ const int UPPER_INCREMENT = 25;
+
+ // Increment Points
+ const int SLEEP_DONE_POINT = 7; // (7 + 1) * 20 = 160ms of sleep
+ const int LOWER_POINT = 60;
+ const int MIDDLE_POINT = 160;
+ const int UPPER_POINT = 230;
+
+ BYTE alpha = pCaller->GetAlpha();
+ if(alpha >= UPPER_POINT)
+ alpha = 255; // just show the thing already
+ else if(alpha <= SLEEP_DONE_POINT) // sleep a little in the beginning...
+ alpha += SLEEP_INCREMENT;
+ else if(alpha <= LOWER_POINT)
+ alpha += LOWER_INCREMENT;
+ else if(alpha <= MIDDLE_POINT)
+ alpha += MIDDLE_INCREMENT;
+ else
+ alpha += UPPER_INCREMENT;
+
+ // Set the calculated Alpha Opaqueness
+ pCaller->SetAlpha(alpha);
+
+ // Close Restore Timer if we are done
+ if(pCaller->GetAlpha() == 255)
+ {
+ // Kill the Restore Timer
+ KillTimer(hWnd,NID_RESTORE_EVENT_TIMER);
+ log(LOGGING_DEBUG, L"Stopping Restore Event Timer");
+ }
+ }
+ else if(wParam == NID_CLOSE_BUT_NOT_DESTROY_EVENT_TIMER) // Closing Timer for MDI Apps (notify WPFCaller)
+ {
+ // We'll run this timer 21x, that should give us ~5 seconds (more than enough, i hope in 99% of cases)
+ if(pCaller->m_StartCloseButNotDestroyTimerCount == 20)
+ {
+ log(LOGGING_DEBUG, L"Stopping Close But not Destroy Timer");
+ pCaller->m_StartCloseButNotDestroyTimerCount = 0;
+ KillTimer(hWnd,NID_CLOSE_BUT_NOT_DESTROY_EVENT_TIMER);
+ }
+ else
+ {
+ log(LOGGING_DEBUG, L"EventDispatcherHandler - WM_CLOSE but no WM_DESTROY Occured letting WPFCaller know");
+ pCaller->m_StartCloseButNotDestroyTimerCount = pCaller->m_StartCloseButNotDestroyTimerCount + 1;
+ PostThreadMessage(pCaller->m_threadID, WM_CLIENT_EVENT_PARENTCLOSEWITHOUTDESTROYOCCURED,0,0);
+ }
+ }
+ break;
+
+ case WM_PAINT:
+ // If we are minimized and we are getting messages from our parent
+ // ~now we can launch the restore Timer
+ if(pCaller->m_bButtonIsBeingRestored &&
+ (wParam == (WPARAM) pCaller->m_hWnd) && (lParam == (LPARAM) pCaller->m_hWnd))
+ {
+ // restore timer will from now on handle the restore
+ pCaller->m_bButtonIsBeingRestored = false;
+ pCaller->m_bButtonIsMinimized = false;
+
+ // Hides the Button Completly
+ log(LOGGING_DEBUG, L"WM_PAINT is starting StartRestoreEventFadeTimer()");
+ pCaller->StartRestoreEventFadeTimer();
+ }
+
+ // Only Draw the button when we want to
+ if(!pCaller->m_bButtonIsMinimized &&
+ !pCaller->m_bButtonIsArtificiallyHidden_MOVE)
+ {
+ hdc = BeginPaint(hWnd, &ps);
+ DrawIconButton(hInst,ps.hdc,pCaller);
+ EndPaint(hWnd, &ps);
+ }
+ return 0;
+
+ case WM_THEMECHANGED:
+ log(LOGGING_MEDIUM, L"Received WM_THEMECHANGED. W32Button is trying to retrieve new Theme Settings via WPFProc");
+ PostThreadMessage(pCaller->m_threadID,WM_GETBUTTONTHEMESETTING,NULL,NULL);
+ break;
+
+ case WM_W32PINGISALIVE:
+ return 1;
+
+ case WM_W32SETBUTTONSTATE:
+ log(LOGGING_DEBUG, L"Received WM_W32SetButtonState Message. Setting Button to %d", (int)lParam);
+ pCaller->m_ButtonState = (BUTTON_STATE) lParam;
+
+ // Button will be toggled / untoggled when the caller set it
+ if(pCaller->m_ButtonState == BUTTON_TOGGLED)
+ pCaller->m_ButtonToggledState = BUTTON_TOGGLED;
+ else
+ pCaller->m_ButtonToggledState = BUTTON_NONE;
+
+ RedrawWindow(pCaller->m_hwndW32Window,NULL,NULL,(RDW_INVALIDATE | RDW_UPDATENOW));
+ return 1;
+
+ case WM_W32GETBUTTONSTATE:
+ log(LOGGING_DEBUG, L"Received WM_W32GetButtonState Message. Sending Button State %d", (int)pCaller->m_ButtonState);
+ return (LRESULT) pCaller->m_ButtonState;
+
+ case WM_W32SETPARENTWINDOWTRANSPERANCY:
+ {
+ if((int)lParam == 0)
+ log(LOGGING_DEBUG, L"Received WM_W32SETPARENTWINDOWTRANSPERANCY Message with Alpha Setting of %u - Invisible", (int)lParam);
+ else if((int)lParam == 255)
+ log(LOGGING_DEBUG, L"Received WM_W32SETPARENTWINDOWTRANSPERANCY Message with Alpha Setting of %u - Visible", (int)lParam);
+
+ long dwStyle = (GetWindowLong(pCaller->m_hWnd,GWL_EXSTYLE) | WS_EX_LAYERED);
+ long retVal = SetWindowLong(pCaller->m_hWnd,GWL_EXSTYLE,dwStyle);
+
+ if(retVal == 0)
+ {
+ log(LOGGING_LOW, L"WM_W32SETPARENTWINDOWTRANSPERANCY SetWindowLong Failed! It returned 0");
+ return 0;
+ }
+
+ // Set the Alpha Channel on the Parent Window
+ if(!SetLayeredWindowAttributes(pCaller->m_hWnd,RGB(0,0,0),(BYTE)lParam,LWA_ALPHA))
+ {
+ log(LOGGING_LOW, L"WM_W32SETPARENTWINDOWTRANSPERANCY SetLayeredWindowAttributes Failed! It returned false");
+ return 0;
+ }
+
+ // Also Set it on the Button (let it become transparent/untransparent with the hooked window)
+ pCaller->SetAlpha((BYTE)lParam);
+ }
+ return 1;
+
+ case WM_W32SETPARENTWINDOWACTIVE:
+ {
+ HWND hWnd = ::SetActiveWindow(pCaller->m_hWnd);
+ if(hWnd == NULL)
+ return 0;
+ else
+ return 1;
+ }
+ return 0;
+
+ case WM_W32POSTMESSAGETOPARENTWINDOW:
+ {
+ if((int)lParam != 0)
+ {
+ wchar_t buf[MAX_PATH] = {0};
+ if(GlobalGetAtomName((ATOM) lParam, buf,MAX_PATH) == 0)
+ {
+ log(LOGGING_DEBUG, L"*Error* - WM_W32SENDMESSAGETOPARENTWINDOW received no String from Atom");
+ }
+ else
+ {
+ HWND hWndM = NULL;
+ UINT MsgM = 0;
+ WPARAM wParamM = 0;
+ LPARAM lParamM = 0;
+ int IntsM[4] = {0};
+
+ bool bParseFailed = false;
+ log(LOGGING_DEBUG, L"WM_W32SENDMESSAGETOPARENTWINDOW received String from Atom %s", buf);
+
+ wchar_t* pToken = wcstok(buf, L";");
+ for (int i = 0; (pToken != NULL) && (i < 4); ++i)
+ {
+ log(LOGGING_DEBUG, L"WM_W32SENDMESSAGETOPARENTWINDOW Token %d - %s", (i + 1), pToken);
+ IntsM[i] = _wtoi(pToken);
+ if(((i == 0) || (i == 1))&& (IntsM[i] == 0))
+ {
+ log(LOGGING_DEBUG, L"*Error* - WM_W32SENDMESSAGETOPARENTWINDOW token %d is invalid", (i + 1));
+ bParseFailed = true;
+ }
+
+ pToken = wcstok(NULL, L";");
+ }
+
+ if(!bParseFailed)
+ {
+ hWndM = (HWND) IntsM[0];
+ MsgM = (UINT) IntsM[1];
+ wParamM = (WPARAM) IntsM[2];
+ lParamM = (LPARAM) IntsM[3];
+
+ if(IsWindow(hWndM))
+ {
+ log(LOGGING_DEBUG, L"WM_W32SENDMESSAGETOPARENTWINDOW Posting Message to hWnd %d, Msg %d, wParam %d, lParam %i", hWndM, MsgM, wParamM, lParamM);
+ PostMessage(hWndM,MsgM,wParamM,lParamM);
+ return 1;
+ }
+ else
+ log(LOGGING_DEBUG, L"*Error* - WM_W32SENDMESSAGETOPARENTWINDOW window handle %d is invalid", hWndM);
+ }
+ return 0;
+ }
+ }
+ else
+ {
+ log(LOGGING_DEBUG, L"*Error* - WM_W32SENDMESSAGETOPARENTWINDOW received no Atom");
+ }
+ }
+ return 0;
+
+ }
+ }
+ catch(...)
+ {
+ log(LOGGING_LOW, L"*Error* - A fatal error occured in W32WndProc for W32Button");
+ }
+
+ HANDLE_MESSAGE:
+ LRESULT lr = DefWindowProc(hWnd,Msg,wParam,lParam);
+ return (lr);
+}
+//////////////////////////////////////////////////////////////////////
+// Func: WPFThreadProc (WPFButtonForm)
+// Desc: Responsible for handling messages that are supposed to go to the WPFButtonForm
+//////////////////////////////////////////////////////////////////////
+DWORD WINAPI WPFThreadProc(__in LPVOID lpParameter)
+{
+ CoInitialize(NULL);
+ MSG msg;
+
+ // Force the system to create a message queue for the thread
+ PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+
+ IButtonFormPtr wpfForm;
+ IClientEventsPtr EventDispatcherForwarder;
+
+ WPFCaller* pCaller = (WPFCaller*) lpParameter;
+
+ // handle to parent window (Hooked Window)
+ HWND hWnd = pCaller->m_hWnd;
+
+ // First thing we want to do is read the icon setting for the win32 button
+ // *we are doing it here because we are reading the settings using COM,
+ // and this thread is COM enabled
+ if(!ReadButtonThemeSetting(pCaller))
+ return -1;
+
+ // We need to sit here idly and wait to make sure that we got the Button Window Handle
+ MakeSureW32ButtonWindowGotCreated(pCaller);
+ HWND hWndButton = pCaller->m_hwndW32Window; // handle to the Button Window
+ log(LOGGING_DEBUG, L"WPFThreadProc: Wait over. ButtonW32 Window got created (%u).", hWndButton);
+
+ // Try to create a WPF Form Objects
+ HRESULT hr = wpfForm.CreateInstance(__uuidof(ButtonWPFormCCW));
+
+ if(SUCCEEDED(hr))
+ {
+ try
+ {
+ // Let's get the IClientEvents Interface to forward Window Client Events
+ log(LOGGING_HIGH, L"Trying to query for IClientEvents Interface");
+ HRESULT hr = wpfForm.QueryInterface(__uuidof(IClientEvents), &EventDispatcherForwarder);
+
+ if(SUCCEEDED(hr))
+ log(LOGGING_HIGH, L"Querying for IClientEvents succeeded");
+ else
+ log(LOGGING_LOW, L"Querying for IClientEvents failed");
+
+ // Let the WPF form know that we activated (and pass out the window handle
+ // that activated it) ~this is importanted for housekeeping. also pass out the
+ // Button Handle so that it can set it's state. ~Imp
+ log(LOGGING_DEBUG, L"Calling WPFThreadProc_ButtonWPForm_Activated Method with Parent (%u) and Button (%u)", hWnd, hWndButton);
+ wpfForm->WPFThreadProc_ButtonWPForm_Activated((long)hWnd, (long) hWndButton);
+ log(LOGGING_HIGH, L"Calling WPFThreadProc_ButtonWPForm_Activated Method Returned - Everything is O.K.");
+
+ // Also let the Client Event know the same thing
+ log(LOGGING_DEBUG, L"WM_CLIENT_EVENT hWndInitialActivate() forwarding it to WPFButton for PID %u and hWnd %u with CommandLine %s", ::GetCurrentProcessId(), hWnd, ::GetCommandLine());
+ _bstr_t CommandLinePrms(GetCommandLine());
+ EventDispatcherForwarder->hWndInitialActivate(GetCurrentProcessId(), (long)hWnd,CommandLinePrms);
+ log(LOGGING_HIGH, L"WM_CLIENT_EVENT hWndInitialActivate() returned - Everything is O.K.");
+
+ // Let OnDefault know that this Thread is ready to receive messages
+ pCaller->m_bThreadIsReady = true;
+ BOOL bRet = FALSE;
+
+ while( (bRet = GetMessage( &msg, (HWND)-1, 0, 0 )) != 0)
+ {
+ if (bRet == -1)
+ {
+ // handle the error and possibly exit
+ log(LOGGING_LOW, L"A Fatal Error Occured in ThreadProc. Exiting!", hr);
+ goto STOPPING_THREAD;
+ break;
+ }
+ else
+ {
+ ////
+ // MAIN MESSAGE LOOP
+ ////
+ switch(msg.message)
+ {
+ case WM_KILLTHREAD:
+ log(LOGGING_MEDIUM, L"WM_KILLTHREAD was Posted to Thread. Exiting Window(%u) in pid(%u).", pCaller->m_hWnd, GetCurrentProcessId());
+ pCaller->m_hwndWPForm = NULL;
+ goto STOPPING_THREAD;
+ break;
+
+ case WM_GETBUTTONTHEMESETTING:
+ if(ReadButtonThemeSetting(pCaller))
+ log(LOGGING_HIGH, L"Received GetButtonThemeSetting Message - Read ButtonThemeSettings Succeeded");
+ else
+ log(LOGGING_LOW, L"Received GetButtonThemeSetting Message - Read ButtonThemeSettings Failed!");
+ break;
+
+ case WM_W32BUTTONCLICKED:
+ log(LOGGING_DEBUG, L"WM_W32BUTTONCLICKED passing down to WPFForm->W32BUTTONCLICKED()");
+ pCaller->m_hwndWPForm = (HWND) wpfForm->W32BUTTONCLICKED();
+ break;
+
+ case (WM_USER + WM_ACTIVATE):
+ if((LOWORD(msg.wParam) == WA_ACTIVE) ||
+ (LOWORD(msg.wParam) == WA_CLICKACTIVE))
+ {
+ if(HIWORD(msg.wParam) == 0)
+ wpfForm->WindowEvent_WindowActivated();
+ }
+ else if(LOWORD(msg.wParam) == WA_INACTIVE)
+ {
+ if(HIWORD(msg.wParam) == 0)
+ wpfForm->WindowEvent_WindowDeactivated();
+ }
+ break;
+
+ case (WM_USER + WM_SIZE):
+ if(msg.wParam == SIZE_MAXIMIZED)
+ wpfForm->WindowEvent_MaximizeOccured((long)HIWORD(msg.lParam),(long)LOWORD(msg.lParam));
+
+ else if(msg.wParam == SIZE_MINIMIZED)
+ wpfForm->WindowEvent_MinimizeOccured();
+
+ break;
+
+ ////
+ // Client Window Events * WPFThreadProc sends them to a Event Dispatcher
+ // via COM to let C# know about these *
+ ////
+ case (WM_CLIENT_EVENT_MDICHILDWINDOWSWITCHOCCURED):
+ case (WM_CLIENT_EVENT_PARENTGETSETTEXTOCCURED):
+ case (WM_CLIENT_EVENT_PARENTSETFOCUSOCCURED):
+ {
+ log(LOGGING_DEBUG, L"WM_CLIENT_EVENT ReResolve() forwarding it to WPFButton");
+ EventDispatcherForwarder->ReResolve(GetCurrentProcessId(),(long)hWnd); // Ideally only switches of active document occur this way
+ }
+ break;
+
+ case (WM_CLIENT_EVENT_PARENTNOTIFYLBUTTONCLICKOCCURED):
+ case (WM_CLIENT_EVENT_PARENTNOTIFYWMCREATEOCCURED):
+ case (WM_CLIENT_EVENT_PARENTCLOSEWITHOUTDESTROYOCCURED):
+ {
+ log(LOGGING_DEBUG, L"WM_CLIENT_EVENT PossArtifactAddedDeleted() forwarding it to WPFButton");
+ //EventDispatcherForwarder->ReResolve(GetCurrentProcessId(),(long)hWnd);
+ }
+ break;
+
+ case (WM_CLIENT_EVENT_DRAGNDROPOCCURED):
+ {
+ log(LOGGING_DEBUG, L"WM_CLIENT_EVENT DragNDropOccured() forwarding it to WPFButton");
+ EventDispatcherForwarder->DragNDropOccured(GetCurrentProcessId(),(long)hWnd,pCaller->m_nDragDroppedFilesCount,pCaller->m_bstrDragDroppedFilesSemiColonSep);
+ }
+ break;
+
+ case (WM_CLIENT_EVENT_OPENFILEORSAVEASDIALOGOCCURED):
+ {
+ log(LOGGING_DEBUG, L"WM_CLIENT_EVENT OpenOrSaveFileDialogOccured() forwarding it to WPFButton");
+ _bstr_t possLocAndFileName(pCaller->m_strFileNameLocationBuf);
+ _bstr_t FileTypes(pCaller->m_strFileTypesBuf);
+ EventDispatcherForwarder->OpenOrSaveFileDialogOccured(GetCurrentProcessId(), (long)hWnd, possLocAndFileName, FileTypes);
+ }
+ break;
+ }
+ }
+ }
+
+ // Let the WPF Form know that this thread is exiting to allow it to do
+ // any cleanup it may want to do
+ STOPPING_THREAD:
+
+ log(LOGGING_LOW, L"EventDispatcherHandler - hWindow %u Deactivation Occured for PID %u", hWnd,::GetCurrentProcessId());
+ wpfForm->WPFThreadProc_ButtonWPForm_Deactivated();
+
+ // Also let the Client Event know the same thing
+ log(LOGGING_DEBUG, L"WM_CLIENT_EVENT hWndLastDeactivate() forwarding it to WPFButton for PID %u and hWnd %u", ::GetCurrentProcessId(), hWnd);
+ EventDispatcherForwarder->hWndLastDeactivate(GetCurrentProcessId(), (long)hWnd);
+
+ }
+ catch(...)
+ {
+ log(LOGGING_LOW, L"*Error* - A fatal Error Occured in WPFThreadProc WpfButton. Exiting...");
+ }
+ }
+ else
+ {
+ log(LOGGING_LOW, L"Error occured creating WPForm Instance COM %i. Exiting...",hr);
+ }
+
+ pCaller->m_bThreadIsReady = false;
+ CoUninitialize();
+ return 0;
+}
+//********************************************************************
+// Class WPFCaller
+//
+// Programmer Daniel Romischer
+// Ooganizer Development Team
+//
+// Description ~This class holds the default wndproc to process all the
+// messages and send them to the WPF COM Object via the COM Thread.
+//
+// Note ~ All the host's Windows Messages enter in on OnDefault()
+//
+// Created 05-26-2008
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+//********************************************************************
+// Construction / Destruction
+//********************************************************************
+//////////////////////////////////////////////////////////////////////
+WPFCaller::WPFCaller(HookWndItem Item, HINSTANCE hInstance):
+m_hWnd(Item.hWnd),
+m_hwndWPForm(NULL),
+m_hwndW32Window(NULL),
+m_DefWndProc(Item.DefWndProc),
+m_HookWndProc(Item.HookWndProc),
+m_thread(NULL),
+m_threadID(0),
+m_bThreadIsReady(false),
+m_hInst(hInstance),
+m_wndHeight(0),
+m_wndWidth(0),
+m_ButtonState(BUTTON_NONE),
+m_ButtonToggledState(BUTTON_NONE),
+m_ButtonStateLastSaved(BUTTON_NONE),
+m_ButtonToggledStateLastSaved(BUTTON_NONE),
+m_bButtonIsArtificiallyHidden_MOVE(false),
+m_bButtonIsMinimized(false),
+m_bButtonIsBeingRestored(false),
+m_StartCloseButNotDestroyTimerCount(0),
+m_nDragDroppedFilesCount(0)
+{
+
+ // Allow us access to the static DS *only load once*
+ if(s_WPFCallerAccess == NULL)
+ s_WPFCallerAccess = new CWHPaccess();
+
+ // just to make sure (to avoid any thread issues) assign out the this instance
+ // BEFORE creating the threads *below*.
+ Item.wpfcaller = this;
+ if(s_WPFCallerAccess->SetHookedWndItem(Item.hWnd, Item) == FALSE)
+ log(LOGGING_LOW, L"WPFCaller SetHookedWndItem FAILED!! (THIS IS NOT GOOD!)");
+
+ // Create the COM WPF Object for WPF Power and Flexibility
+ m_thread = CreateThread(NULL,0,&WPFThreadProc,(LPVOID)this,0,&m_threadID);
+
+ if(m_threadID > 0)
+ log(LOGGING_HIGH, L"WPFCaller Spawned WPFThreadID %i",m_threadID);
+ else
+ log(LOGGING_LOW, L"Error - WPFCaller Failed to Spawn WPFThread",m_threadID);
+
+ // Clear FileName/Types Buffer
+ memset(m_strFileNameLocationBuf,0,(MAX_PATH + 1));
+ memset(m_strFileTypesBuf,0,(MAX_PATH + 1));
+
+ // We are creating a new Thread to deal with 2 windows (WPForm Window,
+ // Start Window32 Button (for speed)
+ Start();
+}
+WPFCaller::~WPFCaller()
+{
+ log(LOGGING_DEBUG, L"~WPFCaller() got called");
+
+ // Destroy the Button Window
+ if(m_hwndW32Window && ::IsWindow(m_hwndW32Window))
+ ::DestroyWindow(m_hwndW32Window);
+
+ // Destroy the COM Thread
+ if(m_bThreadIsReady)
+ {
+ // First let's make sure the thread is even still running and valid,
+ // an error could have closed down the thread. Let's check if the handle
+ // gives us a valid id.
+ DWORD dwThreadId = GetThreadId(m_thread);
+ bool bThreadIsValid = ((dwThreadId != 0) && (dwThreadId == m_threadID));
+
+ // if this thread is not valid no need to continue below
+ if(!bThreadIsValid)
+ log(LOGGING_LOW, L"WPFThread ID %i was invalid when compared to Id %i, ~thread must already have been closed. An error must have occured", m_threadID, dwThreadId);
+
+ if(bThreadIsValid)
+ {
+ // Pass QUIT Message to the COM Thread
+ log(LOGGING_DEBUG, L"Posting WM_KILLTHREAD Message to COM Thread %i", m_threadID);
+ PostThreadMessage(m_threadID, WM_KILLTHREAD, NULL, NULL);
+
+ // We need to wait to make sure COM deallocated before exiting,
+ // otherwise the WPForm remains active, because deallocation never occurs
+ while(m_bThreadIsReady)
+ Sleep(20);
+
+ log(LOGGING_DEBUG, L"Closing Thread Handle to Thread %i", m_threadID);
+ CloseHandle(m_thread);
+
+ // Also Unregister all Window Classes here
+ //UnregisterClass(L"W32ButtonHookWndClass", m_hInst);
+ }
+ else
+ {
+ log(LOGGING_LOW, L"Did NOT close WPFThread m_bThreadIsReady was not true - this should mean WPFThread closed due to an error with COM");
+ }
+ }
+ else
+ {
+ log(LOGGING_LOW, L"Did NOT close WPFThread m_bThreadIsReady was not true - this should mean WPFThread closed due to an error with COM");
+ }
+}
+/////////////////////////////////////////////////////////////////////
+// Desc: Get the Alpha Channel / Opaqueness of the Button
+/////////////////////////////////////////////////////////////////////
+BYTE WPFCaller::GetAlpha()
+{
+ COLORREF pcrKey;
+ BYTE pbAlpha;
+ DWORD dwFlags;
+ GetLayeredWindowAttributes(m_hwndW32Window, &pcrKey, &pbAlpha, &dwFlags);
+ return pbAlpha;
+}
+/////////////////////////////////////////////////////////////////////
+// Desc: Set the Alpha Channel / Opaqueness for the Button
+/////////////////////////////////////////////////////////////////////
+void WPFCaller::SetAlpha(BYTE bAlpha)
+{
+ SetLayeredWindowAttributes(m_hwndW32Window, RGB(255,255,255),bAlpha, LWA_COLORKEY|LWA_ALPHA);
+}
+/////////////////////////////////////////////////////////////////////
+// Desc: Use this to start the Fade event on the Button
+/////////////////////////////////////////////////////////////////////
+void WPFCaller::StartRestoreEventFadeTimer()
+{
+ log(LOGGING_DEBUG, L"Launching Restore Event Timer...");
+ SetAlpha(0); // Hide Button Completly
+ SetTimer(m_hwndW32Window, NID_RESTORE_EVENT_TIMER,20,NULL);
+}
+/////////////////////////////////////////////////////////////////////
+// Desc: Use this when a WM_CLOSE message is received. Some Apps won't
+// close when this event occurs (but rather close an artifact),
+// ~this allows us to detect this occurance
+/////////////////////////////////////////////////////////////////////
+void WPFCaller::StartCloseButNotDestroyTimer()
+{
+ // quarter of a second is more than enough time to know whether an app closed or not
+ // ~but just in case we'll run the timer multiple times over and over
+ m_StartCloseButNotDestroyTimerCount = 0;
+ log(LOGGING_DEBUG, L"Launching CloseButNotDestroyTimer...");
+ SetTimer(m_hwndW32Window, NID_CLOSE_BUT_NOT_DESTROY_EVENT_TIMER,250,NULL);
+}
+/////////////////////////////////////////////////////////////////////
+// Func: EventDispatcherHandler()
+// Desc: Responsible for sending certain client events to the WPFThreadProc
+// This allows us to be more interactive.
+//
+// Note: Not all Client events are handled here *only the easiest ones*
+//////////////////////////////////////////////////////////////////////
+void WPFCaller::EventDispatcherHandler(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
+{
+
+ switch(Msg)
+ {
+ // DragNDropOccured
+ case WM_DROPFILES:
+ {
+ HDROP hdrop = (HDROP) wParam;
+ wchar_t buf[MAX_PATH + 1] = {0};
+
+ m_bstrDragDroppedFilesSemiColonSep = L"";
+ m_nDragDroppedFilesCount = DragQueryFile(hdrop,0xFFFFFFFF,NULL,0);
+ //log(LOGGING_DEBUG, L"EventDispatcherHandler - hWindow %u received %d Dropped Files", hWnd, m_nDragDroppedFilesCount);
+
+ for(int i = 0; i < m_nDragDroppedFilesCount; ++i)
+ {
+ if(i > 0)
+ m_bstrDragDroppedFilesSemiColonSep += L";";
+
+ DragQueryFile(hdrop,i,buf,MAX_PATH);
+ //log(LOGGING_DEBUG, L"EventDispatcherHandler - File %u - received dropped file %s", i, (char*) buf);
+ lstrcat((wchar_t *)m_bstrDragDroppedFilesSemiColonSep, buf);
+ }
+
+ // Let WPFCaller know
+ PostThreadMessage(m_threadID, WM_CLIENT_EVENT_DRAGNDROPOCCURED ,0,0);
+ }
+ break;
+
+ // MDIChildWindowSwitchOccured
+ case WM_KEYDOWN:
+ {
+ // Did Ctrl + F6 or Ctrl + Tab get pushed, if so a possible MDI
+ // switch occured so relay that information
+ if((wParam == VK_TAB || wParam == VK_F6) &&
+ (GetKeyState(VK_CONTROL) < 0))
+ {
+ // Let WPFCaller know
+ //log(LOGGING_DEBUG, L"EventDispatcherHandler - Ctrl + F6 or Ctrl + Tab got pushed - poss. MDIChildWindowSwitch occured");
+ PostThreadMessage(m_threadID, WM_CLIENT_EVENT_MDICHILDWINDOWSWITCHOCCURED ,0,0);
+ }
+ }
+ break;
+
+ // ParentGetSetTextOccured
+ case WM_GETTEXT:
+ case WM_SETTEXT:
+ {
+ // Let WPFCaller know
+ //log(LOGGING_DEBUG, L"EventDispatcherHandler - ParentGetSetText Occured - poss. MDIChildWindowSwitch occured");
+ PostThreadMessage(m_threadID, WM_CLIENT_EVENT_PARENTGETSETTEXTOCCURED,0,0);
+ }
+ break;
+
+ // ParentNotifyLButtonClick Occured
+ // ParentNotifyWMCreate Occured
+ case WM_PARENTNOTIFY:
+ {
+ WORD wMsg = LOWORD(wParam);
+ switch(wMsg)
+ {
+ case WM_CREATE:
+ {
+ // Let WPFCaller know
+ //log(LOGGING_DEBUG, L"EventDispatcherHandler - ParentNotify WM_CREATE Occured - poss. MDIChildWindow Creation occured");
+ PostThreadMessage(m_threadID, WM_CLIENT_EVENT_PARENTNOTIFYWMCREATEOCCURED,0,0);
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ {
+ // Let WPFCaller know
+ //log(LOGGING_DEBUG, L"EventDispatcherHandler - ParentNotify LBUTTONDOWN Occured - poss. MDIChildWindowSwitch occured");
+ PostThreadMessage(m_threadID, WM_CLIENT_EVENT_PARENTNOTIFYLBUTTONCLICKOCCURED,0,0);
+ }
+ break;
+ }
+ }
+ break;
+
+ // Parent received a WM_CLOSE but didn't destroy itself
+ case WM_CLOSE:
+ {
+ //log(LOGGING_DEBUG, L"EventDispatcherHandler - Received WM_CLOSE running StartCloseButNotDestroyTimer()");
+ StartCloseButNotDestroyTimer(); // Win32Button will let the WPFCaller know
+ }
+ break;
+
+ // Parent received focus message
+ case WM_SETFOCUS:
+ {
+ // Let WPFCaller know
+ //log(LOGGING_DEBUG, L"EventDispatcherHandler - Parent SetFocus Occured - poss. MDIChildWindowSwitch occured");
+ PostThreadMessage(m_threadID, WM_CLIENT_EVENT_PARENTSETFOCUSOCCURED,0,0);
+ }
+ break;
+ }
+}
+/////////////////////////////////////////////////////////////////////
+// Func: HandleDDEMessages()
+// Desc: Because DDE is a message-based protocol, it employs no functions or libraries.
+// All DDE transactions are conducted by passing certain defined DDE messages between the
+// client and server windows.
+// ~We may need to use this for certain applications to listen in
+//
+// Note: We call this OnDefault(), because DDE message can get passed into us before WPFThread is up and running
+//////////////////////////////////////////////////////////////////////
+void WPFCaller::HandleDDEMessages(HWND hWnd, UINT Msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(Msg)
+ {
+ case WM_DDE_ACK:
+ //log(LOGGING_DEBUG, L"Received DDE Message WM_DDE_ACK");
+ break;
+
+ case WM_DDE_ADVISE:
+ //log(LOGGING_DEBUG, L"Received DDE Message WM_DDE_ADVISE");
+ break;
+
+ case WM_DDE_DATA:
+ //log(LOGGING_DEBUG, L"Received DDE Message WM_DDE_DATA");
+ break;
+
+ case WM_DDE_EXECUTE:
+ //log(LOGGING_DEBUG, L"Received DDE Message WM_DDE_EXECUTE");
+ break;
+
+ case WM_DDE_INITIATE:
+ //log(LOGGING_DEBUG, L"Received DDE Message WM_DDE_INITIATE");
+ {
+ wchar_t strBuf[MAX_PATH] = {0};
+ ATOM lowword = LOWORD(lParam);
+ ATOM highword = HIWORD(lParam);
+ if(lowword != NULL)
+ {
+ int nSize = ::GlobalGetAtomName((ATOM)lowword,strBuf,MAX_PATH);
+ strBuf[nSize] = 0;
+ //log(LOGGING_DEBUG, L"Found lowword Atom, %d, with lowword String, %s", lowword, strBuf);
+ }
+ if(highword != NULL)
+ {
+ int nSize = ::GlobalGetAtomName((ATOM)highword,strBuf,MAX_PATH);
+ strBuf[nSize] = 0;
+ //log(LOGGING_DEBUG, L"Found highword Atom, %d, with highword String, %s", highword, strBuf);
+ }
+ }
+ break;
+
+ case WM_DDE_POKE:
+ //log(LOGGING_DEBUG, L"Received DDE Message WM_DDE_POKE");
+ break;
+
+ case WM_DDE_REQUEST:
+ //log(LOGGING_DEBUG, L"Received DDE Message WM_DDE_REQUEST");
+ break;
+
+ case WM_DDE_TERMINATE:
+ //log(LOGGING_DEBUG, L"Received DDE Message WM_DDE_TERMINATE");
+ break;
+
+ case WM_DDE_UNADVISE:
+ //log(LOGGING_DEBUG, L"Received DDE Message WM_DDE_UNADVISE");
+ break;
+ }
+}
+/////////////////////////////////////////////////////////////////////
+// Func: OnDefault()
+// Desc: Default handler for any WM_message received (ALL except WM_NCDESTROY
+// and m_msgWMUnHook) the Destroy Messages delete this class and are handled
+// therefore outside of it
+//////////////////////////////////////////////////////////////////////
+LRESULT WPFCaller::OnDefault(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
+{
+ LRESULT result = 0;
+ try
+ {
+
+ // Handle DDE Messages
+ HandleDDEMessages(hWnd,Msg,wParam,lParam);
+
+ // If this is a custom message forward it our Button,
+ // it will be the main handler for our custom messages because it can communicate
+ // to the COMThread as well as manipulate the Button (we can skip and return the value)
+ if((m_hwndW32Window != NULL) && (g_IsMessageACustomMessage(Msg)))
+ {
+ return SendMessage(m_hwndW32Window,Msg,wParam,lParam);
+ }
+
+ // regular messages that our W32Button Cares about it, send it (no WM_USER offset needed here)
+ if((m_hwndW32Window != NULL) && (g_IsMessageW32WindowCaresAbout(Msg)))
+ {
+ // work-around for Minimize/Restore. Let the parent communicate
+ // to the child that it is being redrawn
+ if(Msg == WM_PAINT && m_bButtonIsMinimized)
+ {
+ wParam = (WPARAM) m_hWnd;
+ lParam = (LPARAM) m_hWnd;
+ PostMessage(m_hwndW32Window, Msg, wParam, lParam);
+ }
+ else
+ {
+ SendMessage(m_hwndW32Window, Msg, wParam, lParam);
+ }
+ }
+
+ // We pass the Messages we care about forward to our COM/W32/WPF Thread
+ if(m_bThreadIsReady && (m_threadID != 0))
+ {
+ // IF our COM object cares about this, send it
+ if(g_IsMessageWPFormCaresAbout(Msg))
+ {
+ // We error if we use PostThreadMessage with message < WM_USER so we offset it
+ PostThreadMessage(m_threadID,(WM_USER + Msg),wParam,lParam);
+ }
+
+ // our Event Dispatcher maybe interested in this
+ // message let it know about it
+ EventDispatcherHandler(hWnd,Msg,wParam,lParam);
+ }
+
+ // Call the Default Window Proc - IMPORTANT - Always do this
+ result = CallWindowProc(m_DefWndProc, hWnd, Msg, wParam, lParam);
+ }
+ catch(...)
+ {
+ log(LOGGING_LOW, L"*Error* - A Fatal Error occured in WpfCaller's OnDefault() - (This can't be good)");
+ }
+ return result;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: threadproc
+// Desc: Thread Entry Point responsible for Dispatching the W32Window Messages
+//
+// Note: We are on purpose Ignoring Error Msg 1410. If the window class is already registered it
+// will throw an error, we can safely continuen and instantiate the window class
+//////////////////////////////////////////////////////////////////////
+int WINAPI WPFCaller::threadproc(HINSTANCE hinstance, HINSTANCE hPrevInstance, void* vArg, int nCmdShow)
+{
+ if (!InitApplication(hinstance))
+ {
+ // "Class already exists" this happens if the
+ // same window get's called again to be hooked into.
+ // this error can safely be ignored.
+ if(!(GetLastError() == 1410))
+ {
+ log(LOGGING_LOW, L"initApplication failed error %i",GetLastError());
+ return FALSE;
+ }
+ }
+
+ if (!InitInstance(hinstance, nCmdShow))
+ {
+ log(LOGGING_LOW, L"initInstance failed error %i",GetLastError());
+ return FALSE;
+ }
+
+ MSG msg;
+ BOOL bGotMessage;
+ m_bThreadIsReady = true; // Thread is up N' Ready and Receiving Messages
+ while ((bGotMessage = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0 )
+ {
+ if(bGotMessage == -1)
+ {
+ // handle the error and possible exit
+ log(LOGGING_LOW, L"An Error Occured in ThreadProc Messaging. Exiting!");
+ ExitThread(0);
+ }
+ else
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ return msg.wParam;
+}
+//////////////////////////////////////////////////////////////////////
+// Func: InitApplication()
+// Desc: Responsible for setting up the WNDCLASSEX struct and register
+// the transparent window with Windows via RegisterClassEx()
+//
+// Retr: TRUE, if successful, FALSE otherwise
+//////////////////////////////////////////////////////////////////////
+BOOL WPFCaller::InitApplication(HINSTANCE hInstance)
+{
+ // Fill in the window class structure with parameters
+ // that describe the main window.
+ WNDCLASSEX wcx;
+
+ wcx.cbSize = sizeof(wcx); // size of structure
+ wcx.style = CS_HREDRAW | CS_VREDRAW; // redraw if size changes
+ wcx.lpfnWndProc = (WNDPROC) W32WndProc; // points to W32 window procedure
+ wcx.cbClsExtra = 0; // no extra class memory
+ wcx.cbWndExtra = 0; // no extra window memory
+ wcx.hInstance = hInstance; // handle to instance
+ wcx.hIcon = NULL;
+ wcx.hCursor = LoadCursor(NULL, IDC_ARROW); // predefined arrow
+ wcx.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); // white background brush
+ wcx.lpszMenuName = L"MainMenu"; // name of menu resource
+ wcx.lpszClassName = L"W32ButtonHookWndClass"; // name of window class
+ wcx.hIconSm = NULL;
+
+ // Register the window class. *may throw error 1410*
+ return RegisterClassEx(&wcx);
+}
+//////////////////////////////////////////////////////////////////////
+// Func: InitInstance()
+// Desc: Responsible for Creating and Showing a new Window Class Instance
+//
+// Retr: TRUE, if successful, FALSE otherwise
+//////////////////////////////////////////////////////////////////////
+BOOL WPFCaller::InitInstance(HINSTANCE hInstance, int nCmdShow)
+{
+ // Get the Dimensions of the hooked in Window
+ RECT rect;
+ GetWindowRect(m_hWnd,&rect);
+
+ // set owner/parent window
+ HWND hParent = m_hWnd;
+ DWORD dwStyle;
+
+ //dwStyle = ( WS_POPUP | WS_BORDER ); // For Debugging
+ dwStyle = ( WS_POPUP );
+
+ // If parent Window get's hidden for some reason, should we hide this window?
+ // by default owned windows don't hide, when their parent is hidden,
+ // they do hide when parent is minimized.
+ log(LOGGING_DEBUG, L"Calling CreateWindowEx with Parent %i", hParent);
+
+ //( WS_POPUP | WS_BORDER ), // top-level window
+ m_hwndW32Window = CreateWindowEx(
+ ( WS_EX_LAYERED ), // A Layered window is by default transparent
+ L"W32ButtonHookWndClass", // name of window class
+ L"W32ButtonHookWndTitle",// title-bar string
+ dwStyle, // top-level window
+ rect.left, // default horizontal position
+ rect.top, // default vertical position
+ (rect.right - rect.left), // default width
+ (rect.bottom - rect.top), // default height
+ (HWND) hParent, // set owner window
+ // ~An owned window is always above its owner in the Z order and
+ // is hidden when its owner is minimized
+ (HMENU) NULL, // use class menu
+ hInstance, // handle to application instance
+ (LPVOID) NULL); // no window-creation data
+
+ log(LOGGING_DEBUG, L"CreateWindowEx returns (m_hwndW32Window is set to %i) ", m_hwndW32Window);
+
+ // we can use this to fade the window if we want too... (something to think about...)
+ //if(SetLayeredWindowAttributes(m_hwndW32Window, RGB(255,255,255),255, LWA_COLORKEY|LWA_ALPHA)){}
+ SetLayeredWindowAttributes(m_hwndW32Window, RGB(255,255,255),255, LWA_COLORKEY|LWA_ALPHA);
+
+ // Show the window and send a WM_PAINT message to the window procedure.
+ ShowWindow(m_hwndW32Window, nCmdShow);
+ UpdateWindow(m_hwndW32Window);
+
+ return (m_hwndW32Window != NULL);
+}
\ No newline at end of file
diff --git a/Hooks/ButtonHook/WPFCaller.h b/Hooks/ButtonHook/WPFCaller.h
new file mode 100644
index 0000000..e1cb7fb
--- /dev/null
+++ b/Hooks/ButtonHook/WPFCaller.h
@@ -0,0 +1,171 @@
+#pragma once
+
+#include "thread.h"
+
+#ifdef _DEBUG
+ #import "..\\..\\Target\\Debug\\ButtonWPForm.tlb"
+#else
+ #import "..\\..\\Target\\Release\\ButtonWPForm.tlb"
+#endif
+using namespace ButtonWPForm;
+
+namespace Ooganizer
+{
+
+ enum BUTTON_STATE
+ {
+ // These are the states that coincide with the states defined
+ // in ButtonWPFormCCW
+ BUTTON_NONE = 1,
+ BUTTON_DOWN = 2, // BUTTON_ADD
+ BUTTON_TOGGLED = 3, // BUTTON_DELETE
+
+ // Button Up is the Hover image (Used on Mouse Over),
+ // it is NOT DEFINED in BHInteracter
+ BUTTON_UP = 1000
+ };
+
+ ////
+ // ButtonThemeSetting, this static holds our current Button Theme Setting
+ // ~This structure can be reloaded when a ThemeChange occured (WM_THEMECHANGED)
+ ////
+ struct ButtonThemeSetting
+ {
+ // Init Flags
+ bool bIsInitialized;
+ bool bIsChanged;
+
+ // Int Button Dimension/Location
+ long Top;
+ long Right;
+ long Height;
+ long Width;
+
+ // String Button Locations
+ _bstr_t bstrBUTTON_UP;
+ _bstr_t bstrBUTTON_DOWN;
+ _bstr_t bstrTOGGLE_UP;
+
+ ButtonThemeSetting()
+ {
+ Top = 0;
+ Right = 0;
+ Height = 0;
+ Width = 0;
+ bIsInitialized = false;
+ bIsChanged = false;
+ }
+ };
+
+ class CWHPaccess;
+ class WPFCaller;
+
+ #define BLANK_HookWndItem(n) HookWndItem n = {NULL,NULL,NULL,NULL}
+ //////////////////////////////////////////////////////////////////////
+ // Strc: HookWndItem
+ // Desc: Hook Item is used in the HookedWndList. Each HookWndItem keeps track
+ // of all the addresses needed for each hook for each Windows,
+ // as well as each Window's WPFCaller.
+ //////////////////////////////////////////////////////////////////////
+ struct HookWndItem
+ {
+ HWND hWnd;
+ WNDPROC HookWndProc;
+ WNDPROC DefWndProc;
+ WPFCaller* wpfcaller;
+ };
+ //////////////////////////////////////////////////////////////////////
+ // Clss: WPFCaller
+ // Desc: This class is responsible for overriding wndproc draw routines
+ // and communicate to the WPF COM object
+ //////////////////////////////////////////////////////////////////////
+ class WPFCaller : Thread
+ {
+ public:
+ // All Windows Messages *Except NCDestroy & UnHook* enter here
+ virtual LRESULT OnDefault (HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
+ WPFCaller(HookWndItem Item, HINSTANCE hInstance);
+ ~WPFCaller();
+
+ // Each WPFCaller is mapped to a HookWndItem (Hooked Window)
+ HWND m_hWnd;
+ WNDPROC m_HookWndProc;
+ WNDPROC m_DefWndProc;
+ HINSTANCE m_hInst;
+
+ // Window W32 State Settings
+ // ~we are keeping track of the Hooked W32 sizes
+ int m_wndHeight;
+ int m_wndWidth;
+ RECT m_wndRECT;
+
+ // We need to keep track of the Button State in order
+ // to know what to draw
+ BUTTON_STATE m_ButtonState;
+ BUTTON_STATE m_ButtonToggledState; // We can overwrite buttonDown state
+ // with another state. this allows us to
+ // specify which state to use to overwrite.
+
+ BUTTON_STATE m_ButtonStateLastSaved;
+ BUTTON_STATE m_ButtonToggledStateLastSaved;
+ bool m_bButtonIsArtificiallyHidden_MOVE;
+ bool m_bButtonIsMinimized;
+ bool m_bButtonIsBeingRestored;
+
+ // Transparency / Fade Effect
+ BYTE GetAlpha();
+ void SetAlpha(BYTE bAlpha);
+ void StartRestoreEventFadeTimer();
+
+ // Client Events
+ void StartCloseButNotDestroyTimer();
+ int m_StartCloseButNotDestroyTimerCount;
+
+ // Drag N' Dropped Files
+ int m_nDragDroppedFilesCount;
+ _bstr_t m_bstrDragDroppedFilesSemiColonSep;
+
+ // OpenFile or FileSaveAs Dialog Prms Passing
+ wchar_t m_strFileNameLocationBuf[MAX_PATH + 1];
+ wchar_t m_strFileTypesBuf[MAX_PATH + 1];
+
+ // WPFProc Will load the Button Settings via COM which
+ // we'll use to draw the Icon
+ ButtonThemeSetting m_ButtonThemeSetting;
+
+ // Window Handles
+ HWND m_hwndWPForm; // passed back to us by ButtonWPForm
+ HWND m_hwndW32Window; // our w32 Button
+
+ // ThreadStuff (WPFComThread)
+ bool m_bThreadIsReady;
+ HANDLE m_thread;
+ DWORD m_threadID;
+
+ private:
+
+ // OnDefault() uses this function to possible send messages
+ // to the EventDispatcher in C# for further processing
+ void EventDispatcherHandler(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
+
+ // We don't need to right now, but we may need it more in the future.
+ // Office passes in startup file prms via DDE (other apps may too)
+ void HandleDDEMessages(HWND hWnd, UINT Msg,WPARAM wParam,LPARAM lParam);
+
+ // Win32 Button Window * Created for better speed *
+ // Responsible for setting up the WNDCLASSEX struct and register the Window
+ BOOL InitApplication(HINSTANCE hInstance);
+
+ // Responsible for Creating and Showing a new Window Class Instance
+ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
+
+ // Thread Entry
+ int WINAPI threadproc(HINSTANCE hinstance, HINSTANCE hPrevInstance, void* vArg, int nCmdShow);
+
+ // Thread Entry
+ virtual DWORD Run(LPVOID vArg)
+ {
+ return(threadproc(m_hInst,NULL,vArg,TRUE));
+ }
+ };
+}
\ No newline at end of file
diff --git a/Hooks/ButtonHook/resource.h b/Hooks/ButtonHook/resource.h
new file mode 100644
index 0000000..3135bc0
--- /dev/null
+++ b/Hooks/ButtonHook/resource.h
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by ButtonHook.rc
+//
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 105
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Hooks/ButtonHook/thread.h b/Hooks/ButtonHook/thread.h
new file mode 100644
index 0000000..2b1d418
--- /dev/null
+++ b/Hooks/ButtonHook/thread.h
@@ -0,0 +1,100 @@
+#pragma once
+
+namespace Ooganizer
+{
+ // Generic Thread Class!
+ class Thread
+ {
+ public:
+
+ // Starts the thread
+ // This function starts the thread pointed by m_pThreadFunc with default attributes
+ DWORD Start( void* arg = NULL )
+ {
+ m_ThreadCtx.m_pUserData = arg;
+ m_ThreadCtx.m_hThread = CreateThread(NULL, 0, m_pThreadFunc, this, 0, &m_ThreadCtx.m_dwTID);
+ m_ThreadCtx.m_dwExitCode = (DWORD)-1;
+ return GetLastError();
+ }
+
+ // Stops the thread.
+ // This function stops the current thread
+ DWORD Stop ( bool bForceKill = false )
+ {
+ log(LOGGING_HIGH, L"Hidden Wnd Thread Stopped()");
+ if ( m_ThreadCtx.m_hThread )
+ {
+ GetExitCodeThread(m_ThreadCtx.m_hThread, &m_ThreadCtx.m_dwExitCode);
+
+ if ( m_ThreadCtx.m_dwExitCode == STILL_ACTIVE && bForceKill )
+ TerminateThread(m_ThreadCtx.m_hThread, DWORD(-1));
+
+ m_ThreadCtx.m_hThread = NULL;
+ }
+ return m_ThreadCtx.m_dwExitCode;
+ }
+
+ // Returns Thread Exit Code
+ DWORD GetExitCode() const
+ {
+ if ( m_ThreadCtx.m_hThread )
+ GetExitCodeThread(m_ThreadCtx.m_hThread, (LPDWORD)&m_ThreadCtx.m_dwExitCode);
+ return m_ThreadCtx.m_dwExitCode;
+ }
+
+ // Attaches a Thread Function
+ // Used primarily for porting but can serve in developing generic thread objects
+ void Attach( LPTHREAD_START_ROUTINE lpThreadFunc ){
+ m_pThreadFunc = lpThreadFunc;
+ }
+
+ // Detaches the Attached Thread Function
+ // Detaches the Attached Thread Function, If any.
+ void Detach( void ){
+ m_pThreadFunc = Thread::EntryPoint;
+ }
+
+ Thread(){ m_pThreadFunc = Thread::EntryPoint; /*Can call Detach Also*/ }
+ //plug-in constructor
+ Thread(PTHREAD_START_ROUTINE lpExternalRoutine){Attach(lpExternalRoutine);}
+ ~Thread(){ if(m_ThreadCtx.m_hThread) Stop(true);}
+
+ protected:
+
+ // Std Template: Override if you are sure of what you are doing
+ static DWORD WINAPI EntryPoint( LPVOID pArg)
+ {
+ Thread *pParent = reinterpret_cast(pArg);
+ pParent->ThreadCtor();
+ pParent->Run( pParent->m_ThreadCtx.m_pUserData );
+ pParent->ThreadDtor();
+ return STILL_ACTIVE;
+ }
+
+ // Override this method with the body/code of your thread
+ virtual DWORD Run( LPVOID /*arg */){return m_ThreadCtx.m_dwExitCode;}
+ // override this function to provide your extra initialization
+ virtual void ThreadCtor(){}
+ // Override this function to provide your extra destruction
+ virtual void ThreadDtor(){}
+
+ ////
+ // Thread Context Inner Class (UserData Pointer, Handle, Thread ID)
+ ////
+ class CThreadContext
+ {
+ public:
+ CThreadContext(){memset(this, 0, sizeof(this));}
+
+ // Attributes
+ public:
+ HANDLE m_hThread; // The Thread Handle
+ DWORD m_dwTID; // The Thread ID
+ LPVOID m_pUserData; // The user data pointer
+ LPVOID m_pParent; // The this pointer of the parent CThread object
+ DWORD m_dwExitCode; // The Exit Code of the thread
+
+ } m_ThreadCtx; // The Thread Context Member
+ LPTHREAD_START_ROUTINE m_pThreadFunc; // The Worker Thread Function Pointer
+ };
+}
\ No newline at end of file
diff --git a/Hooks/CaptionButton/CaptionButton.Designer.cs b/Hooks/CaptionButton/CaptionButton.Designer.cs
new file mode 100644
index 0000000..55ba685
--- /dev/null
+++ b/Hooks/CaptionButton/CaptionButton.Designer.cs
@@ -0,0 +1,57 @@
+namespace Foo.Hooks.CaptionButton
+{
+ partial class CaptionButton
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.SuspendLayout();
+ //
+ // CaptionButton
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.SystemColors.ControlText;
+ this.ClientSize = new System.Drawing.Size(10, 10);
+ this.ControlBox = false;
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "CaptionButton";
+ this.Opacity = 0.0;
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
+ this.Load += new System.EventHandler(this.CaptionButton_Load);
+ this.HandleCreated += new System.EventHandler(CaptionButton_HandleCreated);
+ this.Shown += new System.EventHandler(CaptionButton_Shown);
+ this.ResumeLayout(false);
+ }
+
+ #endregion
+ }
+}
+
diff --git a/Hooks/CaptionButton/CaptionButton.cs b/Hooks/CaptionButton/CaptionButton.cs
new file mode 100644
index 0000000..b10a3e4
--- /dev/null
+++ b/Hooks/CaptionButton/CaptionButton.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using System.Runtime.InteropServices;
+using System.Reflection;
+
+using Foo.Platform;
+using Foo.Platform.Interacters;
+
+namespace Foo.Hooks.CaptionButton
+{
+ public partial class CaptionButton : Form
+ {
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ [DllImport("user32.dll")]
+ public static extern Int32 GetWindowLong(IntPtr hwnd, int nIndex);
+
+ [DllImport("user32.dll")]
+ public static extern Int32 SetWindowLong(IntPtr hwnd, int nIndex, Int32 dwNewLong);
+
+ [DllImport("user32.dll")]
+ public static extern bool SetLayeredWindowAttributes(IntPtr hwnd, Int32 crKey, int bAlpha, uint dwFlags);
+
+ public const int GWL_EXSTYLE = -20;
+ public const int LWA_COLORKEY = 0x00000001;
+ public const int WS_EX_LAYERED = 0x00080000;
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct COLORREF
+ {
+ public byte R;
+ public byte G;
+ public byte B;
+ }
+
+ public CaptionButton()
+ {
+ InitializeComponent();
+ }
+
+ ~CaptionButton()
+ {
+ }
+
+ protected override void WndProc(ref Message m)
+ {
+ // Debug Only *Allows us to step right into buttonhook starting *
+ if (Program.DEBUG_ONLY_SETTING_STARTBUTTONHOOK &&
+ !Program.DEBUG_ONLY_SETTING_STARTBUTTONHOOK_IS_STARTED)
+ {
+ Log.Info(string.Format("{0}() - * Debug Only Option * Starting ButtonHook", MethodBase.GetCurrentMethod().Name));
+ BHInteracter.StartButtonHookDLLEntryW();
+ Program.DEBUG_ONLY_SETTING_STARTBUTTONHOOK_IS_STARTED = true;
+ }
+
+ if (m.Msg == BHInteracter.WM_CAPTIONBUTTON_START)
+ {
+ Log.Info(string.Format("{0}() - Received CAPTIONBUTTON_START Message", MethodBase.GetCurrentMethod().Name));
+ BHInteracter.StartButtonHookDLLEntryW();
+ }
+ else if (m.Msg == BHInteracter.WM_CAPTIONBUTTON_STOP)
+ {
+ Log.Info(string.Format("{0}() - Received CAPTIONBUTTON_STOP Message", MethodBase.GetCurrentMethod().Name));
+ BHInteracter.StopButtonHookDLLEntryW();
+ }
+
+ // force opacity at all times
+ if (Opacity == 1.0)
+ Opacity = 0.0;
+
+ // force minimized at all times
+ if (WindowState != FormWindowState.Minimized)
+ WindowState = FormWindowState.Minimized;
+
+ // force Not to be seen in taskbar
+ if (ShowInTaskbar == true)
+ ShowInTaskbar = false;
+
+ base.WndProc(ref m);
+ }
+
+ void CaptionButton_Shown(object sender, System.EventArgs e)
+ {
+ Hide();
+ }
+
+ private void CaptionButton_HandleCreated(object sender, EventArgs e)
+ {
+ IntPtr hWnd = this.Handle;
+ SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
+ SetLayeredWindowAttributes(hWnd, 0x00000000, 0, LWA_COLORKEY);
+ }
+
+ void CaptionButton_Load(object sender, System.EventArgs e)
+ {
+ Log.Info(string.Format("{0}() - CaptionButton Load Called! - passing out hWnd Handle {1}", MethodBase.GetCurrentMethod().Name,Handle.ToInt32()));
+ TemporaryVal.SetValI(Handle.ToInt32());
+ }
+ }
+}
diff --git a/Hooks/CaptionButton/CaptionButton.csproj b/Hooks/CaptionButton/CaptionButton.csproj
new file mode 100644
index 0000000..b37f858
--- /dev/null
+++ b/Hooks/CaptionButton/CaptionButton.csproj
@@ -0,0 +1,115 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {3854981D-5F6B-4AC5-A3F9-5C3761838821}
+ WinExe
+ Properties
+ Foo.Hooks.CaptionButton
+ CaptionButton
+ v3.5
+ 512
+
+
+
+
+
+
+
+
+ true
+ MyKeyFile.SNK
+
+
+ true
+ full
+ false
+ ..\..\Target\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\..\Target\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ False
+ ..\..\Components\log4net.dll
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ CaptionButton.cs
+
+
+
+
+ CaptionButton.cs
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+ True
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}
+ Platform
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Hooks/CaptionButton/CaptionButton.resx b/Hooks/CaptionButton/CaptionButton.resx
new file mode 100644
index 0000000..ff31a6d
--- /dev/null
+++ b/Hooks/CaptionButton/CaptionButton.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Hooks/CaptionButton/MyKeyFile.SNK b/Hooks/CaptionButton/MyKeyFile.SNK
new file mode 100644
index 0000000..8bc8162
Binary files /dev/null and b/Hooks/CaptionButton/MyKeyFile.SNK differ
diff --git a/Hooks/CaptionButton/Program.cs b/Hooks/CaptionButton/Program.cs
new file mode 100644
index 0000000..337ec3f
--- /dev/null
+++ b/Hooks/CaptionButton/Program.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Forms;
+
+// Ooganizer Namespaces
+using Foo.Platform;
+using Foo.Platform.Interacters;
+
+namespace Foo.Hooks.CaptionButton
+{
+ static class Program
+ {
+ static string DEBUG_ONLY_SETTING_STARTBUTTONHOOK_CMD_STRING = "/StartButtonHook";
+ static internal bool DEBUG_ONLY_SETTING_STARTBUTTONHOOK = false;
+ static internal bool DEBUG_ONLY_SETTING_STARTBUTTONHOOK_IS_STARTED = false;
+
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+
+ ////
+ // We want to make sure that we are getting the correct command line params
+ // otherwise we won't allow this .exe to start
+ ////
+ bool bStartButtonHook = false;
+ string[] args = Environment.GetCommandLineArgs();
+ foreach (string arg in args)
+ {
+ if(!bStartButtonHook)
+ bStartButtonHook = (arg == BHInteracter.CAPTIONBUTTON_CMDLINE);
+
+ if(!DEBUG_ONLY_SETTING_STARTBUTTONHOOK)
+ DEBUG_ONLY_SETTING_STARTBUTTONHOOK = (arg == DEBUG_ONLY_SETTING_STARTBUTTONHOOK_CMD_STRING);
+ }
+
+ // Should only start if this exe is called through Platform's BHInteracter
+ if (bStartButtonHook)
+ {
+ Application.Run(new CaptionButton());
+ }
+ }
+ }
+}
diff --git a/Hooks/CaptionButton/Properties/AssemblyInfo.cs b/Hooks/CaptionButton/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e215914
--- /dev/null
+++ b/Hooks/CaptionButton/Properties/AssemblyInfo.cs
@@ -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("OogyCaptionButton")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("OogyCaptionButton")]
+[assembly: AssemblyCopyright("Copyright © 2009")]
+[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("3696fc3e-e32a-4a2a-bff3-bd99ce83090f")]
+
+// 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")]
diff --git a/Hooks/CaptionButton/Properties/Resources.Designer.cs b/Hooks/CaptionButton/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..7295cd6
--- /dev/null
+++ b/Hooks/CaptionButton/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.Hooks.CaptionButton.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Foo.Hooks.CaptionButton.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Hooks/CaptionButton/Properties/Resources.resx b/Hooks/CaptionButton/Properties/Resources.resx
new file mode 100644
index 0000000..ffecec8
--- /dev/null
+++ b/Hooks/CaptionButton/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Hooks/CaptionButton/Properties/Settings.Designer.cs b/Hooks/CaptionButton/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..bb86ec2
--- /dev/null
+++ b/Hooks/CaptionButton/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.Hooks.CaptionButton.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Hooks/CaptionButton/Properties/Settings.settings b/Hooks/CaptionButton/Properties/Settings.settings
new file mode 100644
index 0000000..abf36c5
--- /dev/null
+++ b/Hooks/CaptionButton/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/Oggynize_1.0.sln b/Oggynize_1.0.sln
new file mode 100644
index 0000000..15d47c7
--- /dev/null
+++ b/Oggynize_1.0.sln
@@ -0,0 +1,249 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Platform", "Platform\Platform.csproj", "{F6929AFC-BF61-43A0-BABD-F807B65FFFA1}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Components", "Components", "{3E00D968-DF7D-4836-9A46-980BA5304FEB}"
+ ProjectSection(SolutionItems) = preProject
+ Components\log4net.dll = Components\log4net.dll
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Settings", "Settings\Settings.csproj", "{48D75C4F-2749-48BB-9386-721E0E94C144}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hooks", "Hooks", "{D54033AB-5562-487C-A096-AC8D9B185F40}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ButtonHook", "Hooks\ButtonHook\ButtonHook.vcproj", "{5E8EB95C-9C4F-4DE3-A5E4-827268AF4E9B}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client Services", "Client Services", "{AE52FFA4-5B75-44C4-B80D-7E406C69868E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ButtonWPForm", "Client Services\ButtonWPForm\ButtonWPForm.csproj", "{E179DF39-539A-407F-94DE-C21F690E02C4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataAccessLayer", "DataAccessLayer\DataAccessLayer.csproj", "{C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GUILib", "GUILib\GUILib.csproj", "{C1282050-455B-44F4-8520-1C005E38EFB2}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Deskband", "Deskband", "{A51A5BDB-B9B7-4B5C-B5D2-57F5B6ABC634}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CaptionButton", "Hooks\CaptionButton\CaptionButton.csproj", "{3854981D-5F6B-4AC5-A3F9-5C3761838821}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeskBand", "Deskband\DeskBand\DeskBand.csproj", "{ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BandObject", "Deskband\BandObjectBase\BandObject.csproj", "{BDB3B670-A17B-483E-954C-52FC2B6FF9D3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkspaceMgr", "WorkspaceMgr\WorkspaceMgr.csproj", "{09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GUIWPForms", "Client Services\GUIWPForms\GUIWPForms.csproj", "{A02E052C-3C52-43DB-BB30-A47446B8165F}"
+ ProjectSection(ProjectDependencies) = postProject
+ {E179DF39-539A-407F-94DE-C21F690E02C4} = {E179DF39-539A-407F-94DE-C21F690E02C4}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GUIDebugStepExe", "Client Services\GUIDebugStepExe\GUIDebugStepExe.csproj", "{4C81A790-31CA-4A71-99AD-339D3837A5C6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "zEasyTest", "zEasyTest\zEasyTest.csproj", "{6CDF553C-5060-4871-9CE8-63F66346716A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Satellite", "Satellite\Satellite.csproj", "{6DC93F91-D6D4-4C35-8A83-C180E8E22E16}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AddIns", "AddIns", "{C737AEEA-27C5-494F-8121-3E5C82315DD5}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Target", "Target", "{E7CF7E1E-CEAB-4015-BD70-7B2C727BD63E}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Release", "Release", "{1295F70C-6CDC-4B99-AB85-5305CA8D7103}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Debug", "Debug", "{47DF5C34-9275-4F92-8E87-B81B899EBA1F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AddIns", "AddIns", "{208D8FE2-6A2C-438D-9CE9-CB4AAB6B33FD}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AddIns", "AddIns", "{113E65CD-E297-4114-9C1B-0446A12D2EE1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AddIn.Common", "AddIns\AddIn.Common\AddIn.Common.csproj", "{D32C4454-9334-47AA-9A3F-456B8B12220A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Addin.Office", "AddIns\Addin.Office\Addin.Office.csproj", "{0CA1DD2E-2752-4587-ADB4-77194411648B}"
+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
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}.Release|Win32.ActiveCfg = Release|Any CPU
+ {48D75C4F-2749-48BB-9386-721E0E94C144}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {48D75C4F-2749-48BB-9386-721E0E94C144}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {48D75C4F-2749-48BB-9386-721E0E94C144}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {48D75C4F-2749-48BB-9386-721E0E94C144}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {48D75C4F-2749-48BB-9386-721E0E94C144}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {48D75C4F-2749-48BB-9386-721E0E94C144}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {48D75C4F-2749-48BB-9386-721E0E94C144}.Release|Any CPU.Build.0 = Release|Any CPU
+ {48D75C4F-2749-48BB-9386-721E0E94C144}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {48D75C4F-2749-48BB-9386-721E0E94C144}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {48D75C4F-2749-48BB-9386-721E0E94C144}.Release|Win32.ActiveCfg = Release|Any CPU
+ {5E8EB95C-9C4F-4DE3-A5E4-827268AF4E9B}.Debug|Any CPU.ActiveCfg = Debug|Win32
+ {5E8EB95C-9C4F-4DE3-A5E4-827268AF4E9B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {5E8EB95C-9C4F-4DE3-A5E4-827268AF4E9B}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {5E8EB95C-9C4F-4DE3-A5E4-827268AF4E9B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {5E8EB95C-9C4F-4DE3-A5E4-827268AF4E9B}.Debug|Win32.Build.0 = Debug|Win32
+ {5E8EB95C-9C4F-4DE3-A5E4-827268AF4E9B}.Release|Any CPU.ActiveCfg = Release|Win32
+ {5E8EB95C-9C4F-4DE3-A5E4-827268AF4E9B}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {5E8EB95C-9C4F-4DE3-A5E4-827268AF4E9B}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {5E8EB95C-9C4F-4DE3-A5E4-827268AF4E9B}.Release|Win32.ActiveCfg = Release|Win32
+ {5E8EB95C-9C4F-4DE3-A5E4-827268AF4E9B}.Release|Win32.Build.0 = Release|Win32
+ {E179DF39-539A-407F-94DE-C21F690E02C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E179DF39-539A-407F-94DE-C21F690E02C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E179DF39-539A-407F-94DE-C21F690E02C4}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {E179DF39-539A-407F-94DE-C21F690E02C4}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {E179DF39-539A-407F-94DE-C21F690E02C4}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {E179DF39-539A-407F-94DE-C21F690E02C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E179DF39-539A-407F-94DE-C21F690E02C4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E179DF39-539A-407F-94DE-C21F690E02C4}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {E179DF39-539A-407F-94DE-C21F690E02C4}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {E179DF39-539A-407F-94DE-C21F690E02C4}.Release|Win32.ActiveCfg = Release|Any CPU
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}.Release|Win32.ActiveCfg = Release|Any CPU
+ {C1282050-455B-44F4-8520-1C005E38EFB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C1282050-455B-44F4-8520-1C005E38EFB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C1282050-455B-44F4-8520-1C005E38EFB2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {C1282050-455B-44F4-8520-1C005E38EFB2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {C1282050-455B-44F4-8520-1C005E38EFB2}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {C1282050-455B-44F4-8520-1C005E38EFB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C1282050-455B-44F4-8520-1C005E38EFB2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C1282050-455B-44F4-8520-1C005E38EFB2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {C1282050-455B-44F4-8520-1C005E38EFB2}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {C1282050-455B-44F4-8520-1C005E38EFB2}.Release|Win32.ActiveCfg = Release|Any CPU
+ {3854981D-5F6B-4AC5-A3F9-5C3761838821}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3854981D-5F6B-4AC5-A3F9-5C3761838821}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3854981D-5F6B-4AC5-A3F9-5C3761838821}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {3854981D-5F6B-4AC5-A3F9-5C3761838821}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {3854981D-5F6B-4AC5-A3F9-5C3761838821}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {3854981D-5F6B-4AC5-A3F9-5C3761838821}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3854981D-5F6B-4AC5-A3F9-5C3761838821}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3854981D-5F6B-4AC5-A3F9-5C3761838821}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {3854981D-5F6B-4AC5-A3F9-5C3761838821}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {3854981D-5F6B-4AC5-A3F9-5C3761838821}.Release|Win32.ActiveCfg = Release|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7}.Release|Win32.ActiveCfg = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3}.Release|Win32.ActiveCfg = Release|Any CPU
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}.Release|Any CPU.Build.0 = Release|Any CPU
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}.Release|Win32.ActiveCfg = Release|Any CPU
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {A02E052C-3C52-43DB-BB30-A47446B8165F}.Release|Win32.ActiveCfg = Release|Any CPU
+ {4C81A790-31CA-4A71-99AD-339D3837A5C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4C81A790-31CA-4A71-99AD-339D3837A5C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4C81A790-31CA-4A71-99AD-339D3837A5C6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {4C81A790-31CA-4A71-99AD-339D3837A5C6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {4C81A790-31CA-4A71-99AD-339D3837A5C6}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {4C81A790-31CA-4A71-99AD-339D3837A5C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4C81A790-31CA-4A71-99AD-339D3837A5C6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4C81A790-31CA-4A71-99AD-339D3837A5C6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {4C81A790-31CA-4A71-99AD-339D3837A5C6}.Release|Win32.ActiveCfg = Release|Any CPU
+ {6CDF553C-5060-4871-9CE8-63F66346716A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6CDF553C-5060-4871-9CE8-63F66346716A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6CDF553C-5060-4871-9CE8-63F66346716A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {6CDF553C-5060-4871-9CE8-63F66346716A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {6CDF553C-5060-4871-9CE8-63F66346716A}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {6CDF553C-5060-4871-9CE8-63F66346716A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6CDF553C-5060-4871-9CE8-63F66346716A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6CDF553C-5060-4871-9CE8-63F66346716A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {6CDF553C-5060-4871-9CE8-63F66346716A}.Release|Win32.ActiveCfg = Release|Any CPU
+ {6DC93F91-D6D4-4C35-8A83-C180E8E22E16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6DC93F91-D6D4-4C35-8A83-C180E8E22E16}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6DC93F91-D6D4-4C35-8A83-C180E8E22E16}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {6DC93F91-D6D4-4C35-8A83-C180E8E22E16}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {6DC93F91-D6D4-4C35-8A83-C180E8E22E16}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {6DC93F91-D6D4-4C35-8A83-C180E8E22E16}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6DC93F91-D6D4-4C35-8A83-C180E8E22E16}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6DC93F91-D6D4-4C35-8A83-C180E8E22E16}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {6DC93F91-D6D4-4C35-8A83-C180E8E22E16}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {6DC93F91-D6D4-4C35-8A83-C180E8E22E16}.Release|Win32.ActiveCfg = Release|Any CPU
+ {D32C4454-9334-47AA-9A3F-456B8B12220A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D32C4454-9334-47AA-9A3F-456B8B12220A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D32C4454-9334-47AA-9A3F-456B8B12220A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {D32C4454-9334-47AA-9A3F-456B8B12220A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {D32C4454-9334-47AA-9A3F-456B8B12220A}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {D32C4454-9334-47AA-9A3F-456B8B12220A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D32C4454-9334-47AA-9A3F-456B8B12220A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D32C4454-9334-47AA-9A3F-456B8B12220A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {D32C4454-9334-47AA-9A3F-456B8B12220A}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {D32C4454-9334-47AA-9A3F-456B8B12220A}.Release|Win32.ActiveCfg = Release|Any CPU
+ {0CA1DD2E-2752-4587-ADB4-77194411648B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0CA1DD2E-2752-4587-ADB4-77194411648B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0CA1DD2E-2752-4587-ADB4-77194411648B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {0CA1DD2E-2752-4587-ADB4-77194411648B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {0CA1DD2E-2752-4587-ADB4-77194411648B}.Debug|Win32.ActiveCfg = Debug|Any CPU
+ {0CA1DD2E-2752-4587-ADB4-77194411648B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0CA1DD2E-2752-4587-ADB4-77194411648B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0CA1DD2E-2752-4587-ADB4-77194411648B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {0CA1DD2E-2752-4587-ADB4-77194411648B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {0CA1DD2E-2752-4587-ADB4-77194411648B}.Release|Win32.ActiveCfg = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {5E8EB95C-9C4F-4DE3-A5E4-827268AF4E9B} = {D54033AB-5562-487C-A096-AC8D9B185F40}
+ {3854981D-5F6B-4AC5-A3F9-5C3761838821} = {D54033AB-5562-487C-A096-AC8D9B185F40}
+ {E179DF39-539A-407F-94DE-C21F690E02C4} = {AE52FFA4-5B75-44C4-B80D-7E406C69868E}
+ {A02E052C-3C52-43DB-BB30-A47446B8165F} = {AE52FFA4-5B75-44C4-B80D-7E406C69868E}
+ {4C81A790-31CA-4A71-99AD-339D3837A5C6} = {AE52FFA4-5B75-44C4-B80D-7E406C69868E}
+ {ACCDA683-C6AC-43DD-819F-4C3DE36E6BD7} = {A51A5BDB-B9B7-4B5C-B5D2-57F5B6ABC634}
+ {BDB3B670-A17B-483E-954C-52FC2B6FF9D3} = {A51A5BDB-B9B7-4B5C-B5D2-57F5B6ABC634}
+ {D32C4454-9334-47AA-9A3F-456B8B12220A} = {C737AEEA-27C5-494F-8121-3E5C82315DD5}
+ {0CA1DD2E-2752-4587-ADB4-77194411648B} = {C737AEEA-27C5-494F-8121-3E5C82315DD5}
+ {1295F70C-6CDC-4B99-AB85-5305CA8D7103} = {E7CF7E1E-CEAB-4015-BD70-7B2C727BD63E}
+ {47DF5C34-9275-4F92-8E87-B81B899EBA1F} = {E7CF7E1E-CEAB-4015-BD70-7B2C727BD63E}
+ {113E65CD-E297-4114-9C1B-0446A12D2EE1} = {1295F70C-6CDC-4B99-AB85-5305CA8D7103}
+ {208D8FE2-6A2C-438D-9CE9-CB4AAB6B33FD} = {47DF5C34-9275-4F92-8E87-B81B899EBA1F}
+ EndGlobalSection
+EndGlobal
diff --git a/Platform/Env.cs b/Platform/Env.cs
new file mode 100644
index 0000000..ada570b
--- /dev/null
+++ b/Platform/Env.cs
@@ -0,0 +1,247 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Foo.Platform
+{
+ ///
+ /// Oogy Environment Class for getting OS, Application, and Theme Settings
+ ///
+ public class Env
+ {
+ private static int m_dwMajorVersion = 0;
+ private static int m_dwMinorVersion = 0;
+ private static Themes m_Theme = Themes.Classic;
+ private static AssemblyRunTimePath m_RunTimePath = null;
+
+ ///
+ /// Public Properties
+ ///
+ public static int MajorVersion {get{return m_dwMajorVersion;}}
+ public static int MinorVersion {get{return m_dwMinorVersion;}}
+ public static Themes Theme {get{return m_Theme;}}
+
+ ///
+ /// This is our versioning system, does not correspond to Windows
+ ///
+ public enum OSVersions : int
+ {
+ OS_WINDOWS_VISTA = 1,
+ OS_WINDOWS_2000 = 2, /*incl. Server OSes*/
+ OS_WINDOWS_2003 = 3, /*incl. Server OSes and Windows XP*/
+ OS_WINDOWS_SE7EN = 7, /*for future use ?*/
+ OS_NOT_SUPPORTED = 99
+ }
+
+ ///
+ /// This are our Theme Configurations for ButtonHook/GUI components.
+ ///
+ public enum Themes : int
+ {
+ Classic = 0,
+ XPtheme = 1,
+ AeroTheme = 2,
+ VistaNoAero = 3
+ }
+
+ ///
+ /// Static Constructor, immediatly sets our environment variables
+ ///
+ static Env()
+ {
+ ObtainEnvInformation();
+ m_RunTimePath = new AssemblyRunTimePath();
+ }
+
+ ///
+ /// Call this function first - before querying for themes, etc
+ ///
+ private static void ObtainEnvInformation()
+ {
+ GetSystemInformation(out m_dwMajorVersion, out m_dwMinorVersion);
+ CheckWindowsXPTheme();
+ CheckWindowsVistaTheme();
+ }
+
+ ///
+ /// Use to get the Oogy Application path. Creates folder if none exists
+ ///
+ /// Path to Ooganizer Application Folder
+ public static string GetAppdirectory()
+ {
+ string appDataFolder = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData);
+ string oogyAppData = appDataFolder + @"\Ooganizer";
+
+ if (!Directory.Exists(oogyAppData))
+ {
+ // create oogy app data folder
+ Directory.CreateDirectory(oogyAppData);
+ }
+
+ return oogyAppData;
+ }
+
+ ///
+ /// Use to get the Oogy artifact snapshot image path. Creates folder if none exists
+ ///
+ /// Path to Ooganizer artifact snapshot data folder
+ public static string GetSnapshotDirectory()
+ {
+ string path = Platform.Env.GetAppdirectory() + @"\Snapshots";
+
+ if (!Directory.Exists(path))
+ {
+ // create snapshot data folder
+ Directory.CreateDirectory(path);
+ }
+
+ return path;
+ }
+
+ ///
+ /// Use to get the Oogy log path. Creates folder if none exists
+ ///
+ /// Path to Ooganizer log folder
+ public static string GetLogDirectory()
+ {
+ string path = Platform.Env.GetAppdirectory() + @"\Logs";
+
+ if (!Directory.Exists(path))
+ {
+ // create snapshot data folder
+ Directory.CreateDirectory(path);
+ }
+
+ return path;
+ }
+
+ ///
+ /// Use this to query the current running assembly path
+ ///
+ /// Path of assembly location
+ public static string GetRunTimePath()
+ {
+ return m_RunTimePath.strPath;
+ }
+
+ ///
+ /// Quickly Check if the current OS Environment is supported by Oogy
+ ///
+ /// true if it is supported, false otherwise
+ public static bool IsWindowsOSSupported()
+ {
+ OSVersions version = OSVersionCheck();
+
+ if ((version == OSVersions.OS_WINDOWS_2003) ||
+ (version == OSVersions.OS_WINDOWS_VISTA) ||
+ (version == OSVersions.OS_WINDOWS_SE7EN))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Retrieves Windows OS specific information
+ ///
+ /// dwMajorVersion[out]
+ /// dwMinorVersion[out]
+ /// is32bitNT[out] = supports 32-bit Windows NT
+ /// true, if succesfully retrieved, false otherwise
+ private static void GetSystemInformation(out int dwMajorVersion, out int dwMinorVersion)
+ {
+ dwMajorVersion = System.Environment.OSVersion.Version.Major;
+ dwMinorVersion = System.Environment.OSVersion.Version.Minor;
+ }
+
+ ///
+ /// Use this function to obtain the current OS version information
+ ///
+ /// Returns the Current OSVersion Enum of this Environment
+ private static OSVersions OSVersionCheck()
+ {
+ switch(m_dwMajorVersion) // we ignore minor version for now
+ {
+ case 4: // Windows 2000?
+ return (OSVersions.OS_WINDOWS_2000);
+ case 5: // Windows XP && Windows 2003
+ return (OSVersions.OS_WINDOWS_2003);
+ case 6:
+ return (OSVersions.OS_WINDOWS_VISTA);
+ case 7:
+ return (OSVersions.OS_WINDOWS_SE7EN);
+ default:
+ return (OSVersions.OS_NOT_SUPPORTED);
+ }
+ }
+
+ ///
+ /// Vista Specific Theme Checking is done here
+ ///
+ ///
+ private static void CheckWindowsVistaTheme()
+ {
+ if(OSVersionCheck() == OSVersions.OS_WINDOWS_VISTA)
+ {
+ bool bIsAero = false;
+ if(Win32.Win32Functions.DwmIsCompositionEnabled(ref bIsAero) < 0)
+ return; //Call Failed
+
+ if (bIsAero)
+ m_Theme = Themes.AeroTheme;
+ else
+ m_Theme = Themes.VistaNoAero;
+ }
+ }
+
+ ///
+ /// XP Specific Theme Checking is done here
+ ///
+ ///
+ private static void CheckWindowsXPTheme()
+ {
+ if (OSVersionCheck() == OSVersions.OS_WINDOWS_2003)
+ {
+ if (Win32.Win32Functions.IsAppThemed())
+ m_Theme = Themes.XPtheme;
+ else
+ m_Theme = Themes.Classic;
+ }
+ }
+ }
+
+ ///
+ /// Since we only can query the Assembly path by instantiation,
+ /// we have a class that handles it
+ ///
+ internal class AssemblyRunTimePath
+ {
+ public string strPath;
+ public AssemblyRunTimePath(){strPath = Path.GetDirectoryName(GetType().Assembly.Location);}
+ }
+
+ ///
+ /// EnvironmentCCW is a wrapper around Env - specifically made to be non-static
+ /// as to be able to be called from COM (ButtonHook/C++ code can now use Environment as well
+ ///
+ [Guid("85E2E5F6-877F-4edd-B7D1-D52C431F0AFC")]
+ [ClassInterface(ClassInterfaceType.AutoDual)]
+ [ComVisible(true)]
+ public class EnvironmentCCW
+ {
+ public bool IsWindowsOSSupported()
+ {
+ return Env.IsWindowsOSSupported();
+ }
+ public int GetCurWindowsTheme()
+ {
+ return (int)Env.Theme;
+ }
+ }
+
+}
diff --git a/Platform/ErrorReporting/UserError.cs b/Platform/ErrorReporting/UserError.cs
new file mode 100644
index 0000000..64a903b
--- /dev/null
+++ b/Platform/ErrorReporting/UserError.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Forms;
+
+namespace Foo.Platform.ErrorReporting
+{
+ public class UserError
+ {
+ ///
+ /// Display an Error to the User
+ ///
+ /// Error Title
+ /// Any Details about the Error that maybe pertinent to the User
+ public static void Show(string title, string detail)
+ {
+ string strTitle = "Error - " + title;
+ string strDetail = detail + "\n\n\nContact Ooganizer Support at http://ooganizer.com/support for more help and information.";
+
+ MessageBox.Show(strDetail,strTitle);
+ }
+
+ }
+}
diff --git a/Platform/InstallationSpec.cs b/Platform/InstallationSpec.cs
new file mode 100644
index 0000000..5d7ac04
--- /dev/null
+++ b/Platform/InstallationSpec.cs
@@ -0,0 +1,201 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.Win32;
+using System.Reflection;
+
+namespace Foo.Platform
+{
+ ///
+ /// Installation Specific Settings. "HKLM\Software\Ooganizer",
+ /// The Installer must put the correct values in there so that we know where our files
+ /// are. ~Since now some of our assemblies are in the GAC, we require this.
+ ///
+ public class InstallationSpec
+ {
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// private statics
+ ///
+ private static string m_strInstallPath = "";
+ //private static string m_strPlatformPath = "";
+ //private static string m_strServerPath = "";
+ //private static string m_strLogPath = "";
+ private static RegistryKey s_OogyRootKey;
+
+ ///
+ /// Public Properties
+ ///
+ public static string InstallPath { get { return m_strInstallPath; } }
+ //public static string PlatformPath { get { return m_strPlatformPath; } }
+ //public static string ServerPath { get { return m_strServerPath; } }
+ //public static string LogPath { get { return m_strLogPath; } }
+
+ ///
+ /// Static Constructor, immediatly gets our installation specific variables
+ ///
+ static InstallationSpec()
+ {
+ s_OogyRootKey = Registry.LocalMachine.OpenSubKey("Software\\Ooganizer",false);
+ if (s_OogyRootKey != null)
+ {
+ object keyvalue = null;
+
+ keyvalue = s_OogyRootKey.GetValue("InstallPath");
+ if (isValidStr(keyvalue))
+ m_strInstallPath = keyvalue.ToString();
+
+ //keyvalue = s_OogyRootKey.GetValue("PlatformPath");
+ //if (isValidStr(keyvalue))
+ // m_strPlatformPath = keyvalue.ToString();
+
+ //keyvalue = s_OogyRootKey.GetValue("ServerPath");
+ //if (isValidStr(keyvalue))
+ // m_strServerPath = keyvalue.ToString();
+
+ //keyvalue = s_OogyRootKey.GetValue("LogPath");
+ //if (isValidStr(keyvalue))
+ // m_strLogPath = keyvalue.ToString();
+ }
+ else
+ {
+ Log.Error(string.Format("{0}() - Couldn't Open Software\\Ooganizer Registry Key for Reading", MethodBase.GetCurrentMethod().Name));
+ }
+ }
+
+ /// Returns true if passed in object is valid and not ""
+ private static bool isValidStr(object oToValidate)
+ {
+ if ((oToValidate != null) && (oToValidate.ToString() != ""))
+ return true;
+ else
+ return false;
+ }
+ }
+
+ ///
+ /// Use this class for Debug Specific Settings
+ ///
+ public class DebugSpec
+ {
+ public static bool SkipCaptionButtonStarter { get; private set; }
+
+ private static RegistryKey s_DebugSpecRootKey;
+
+ static DebugSpec()
+ {
+ SkipCaptionButtonStarter = false;
+
+ #if DEBUG
+ s_DebugSpecRootKey = Registry.LocalMachine.CreateSubKey("Software\\Ooganizer\\DebugSpec", RegistryKeyPermissionCheck.ReadWriteSubTree);
+ SkipCaptionButtonStarter = GetValB("SkipCaptionButtonStarter");
+ #endif
+ }
+
+ private static bool GetValB(string strValKey)
+ {
+ try
+ {
+ string val = GetVal(strValKey);
+ if (!String.IsNullOrEmpty(val))
+ {
+ bool bVal = Boolean.Parse(val);
+ return bVal;
+ }
+ }
+ catch (Exception) { /* ignore */ }
+ return false;
+ }
+
+ private static string GetVal(string strValKey)
+ {
+ try
+ {
+ object keyvalue = null;
+ keyvalue = s_DebugSpecRootKey.GetValue(strValKey);
+ if (isValidStr(keyvalue))
+ return keyvalue.ToString();
+ }
+ catch (Exception) { }
+ return String.Empty;
+ }
+
+ /// Returns true if passed in object is valid and not ""
+ private static bool isValidStr(object oToValidate)
+ {
+ if ((oToValidate != null) && (oToValidate.ToString() != ""))
+ return true;
+ else
+ return false;
+ }
+ }
+
+ ///
+ /// Temporary Values / "HKLM\Software\Ooganizer\TemporaryVal",
+ /// This class is being used to temporarily store values in the registry and retrieve them.
+ /// Useful for quick and dirty inter process communication. works out well for certain things.
+ ///
+ public class TemporaryVal
+ {
+ private static RegistryKey s_OogyRootKey;
+
+ static TemporaryVal()
+ {
+ s_OogyRootKey = Registry.LocalMachine.OpenSubKey("Software\\Ooganizer", true);
+ }
+
+ public static void SetVal(string strValue)
+ {
+ try { s_OogyRootKey.SetValue("TemporaryVal", strValue); }
+ catch (Exception) { }
+ }
+
+ public static void SetValI(int iValue)
+ {
+ try{ SetVal(iValue.ToString()); }
+ catch (Exception){}
+ }
+
+ public static string GetVal()
+ {
+ try
+ {
+ object keyvalue = null;
+ keyvalue = s_OogyRootKey.GetValue("TemporaryVal");
+ if (isValidStr(keyvalue))
+ return keyvalue.ToString();
+ }
+ catch (Exception) { }
+ return String.Empty;
+ }
+
+ public static int GetValI()
+ {
+ int I = 0;
+ try
+ {
+ string strVal = GetVal();
+ I = int.Parse(strVal);
+ }
+ catch (Exception) { }
+ return I;
+ }
+
+ public static void DeleteVal()
+ {
+ try { s_OogyRootKey.DeleteValue("TemporaryVal"); }
+ catch (Exception) { }
+ }
+
+ /// Returns true if passed in object is valid and not ""
+ private static bool isValidStr(object oToValidate)
+ {
+ if ((oToValidate != null) && (oToValidate.ToString() != ""))
+ return true;
+ else
+ return false;
+ }
+ }
+}
diff --git a/Platform/Interacters/BHInteracter.cs b/Platform/Interacters/BHInteracter.cs
new file mode 100644
index 0000000..e765075
--- /dev/null
+++ b/Platform/Interacters/BHInteracter.cs
@@ -0,0 +1,489 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+using System.Threading;
+
+namespace Foo.Platform.Interacters
+{
+ ///
+ /// BHInteracter - ButtonHook Interacter.
+ /// Use this class abstraction to send/communicate with ButtonHook.
+ ///
+ public class BHInteracter
+ {
+ ////
+ // Our ButtonHook.Dll Entry Points (Delegates)
+ ////
+ internal delegate bool MyStartButtonHook();
+ internal static MyStartButtonHook _MyStartButtonHook = null;
+
+ internal delegate bool MyStopButtonHook();
+ internal static MyStopButtonHook _MyStopButtonHook = null;
+
+ internal delegate bool MyIsButtonHookSet();
+ internal static MyIsButtonHookSet _MyIsButtonHookSet = null;
+
+ internal delegate int MyGetAllHookedWindowHandles(IntPtr pBuf);
+ internal static MyGetAllHookedWindowHandles _MyGetAllHookedWindowHandles = null;
+
+ ///
+ /// Use this to send down to Buttonhook so that it knows what to show
+ ///
+ public enum BUTTON_HOOK_STATE
+ {
+ BUTTON_NONE = 1,
+ BUTTON_ADD = 2,
+ BUTTON_DELETE = 3
+ }
+
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ////
+ // Custom ButtonHook Message Handlers
+ ////
+ private const int WM_W32PINGISALIVE = (Platform.Win32.Win32_Constants.WM_USER + 700);
+ private const int WM_W32SETBUTTONSTATE = (Platform.Win32.Win32_Constants.WM_USER + 701);
+ private const int WM_W32GETBUTTONSTATE = (Platform.Win32.Win32_Constants.WM_USER + 702);
+ private const int WM_W32SETPARENTWINDOWTRANSPERANCY = (Platform.Win32.Win32_Constants.WM_USER + 703);
+ private const int WM_W32SETPARENTWINDOWACTIVE = (Platform.Win32.Win32_Constants.WM_USER + 704);
+ private const int WM_W32POSTMESSAGETOPARENTWINDOW = (Platform.Win32.Win32_Constants.WM_USER + 705);
+
+ ////
+ // Custom OogyCaptionButton Message Handlers
+ ////
+ public const int WM_CAPTIONBUTTON_START = (Platform.Win32.Win32_Constants.WM_USER + 1200);
+ public const int WM_CAPTIONBUTTON_STOP = (Platform.Win32.Win32_Constants.WM_USER + 1201);
+
+ ////
+ // OogyCaptionButton Spec
+ ////
+ private const int CAPTION_START_STOP_MAX_TRY_COUNT = 5;
+ public const string CAPTIONBUTTON_CMDLINE = @"/App:StartThis4Real639";
+ private const string CAPTIONBUTTON_PROCESSNAME = "CaptionButton";
+ private static string CAPTIONBUTTON_EXE = CAPTIONBUTTON_PROCESSNAME + ".exe";
+ private static string CAPTIONBUTTON_EXE_FULLPATH = InstallationSpec.InstallPath + CAPTIONBUTTON_EXE;
+ private static IntPtr s_CaptionButtonHandle = IntPtr.Zero;
+
+ ///
+ /// Validity internal State checking for OogyCaptionButton.exe
+ ///
+ private enum CAPTIONBUTTON_VALIDITY_STATE
+ {
+ VALIDITY_NONE = 1,
+ VALIDITY_CREATEDSUCCESS = 2,
+ VALIDITY_CREATEDFAILED = 3,
+ VALIDITY_STOPPEDSUCCESS = 4,
+ VALIDITY_STOPPEDFAILED = 5,
+ VALIDITY_INTEGRITYCHECK_FAILED = 6
+ }
+
+ // State Success / Error Checking
+ private static CAPTIONBUTTON_VALIDITY_STATE s_CaptionButtonState = CAPTIONBUTTON_VALIDITY_STATE.VALIDITY_NONE;
+
+ ///
+ /// Static Constructor Loads the ButtonHook.dll dynamically from the correct path
+ ///
+ static BHInteracter()
+ {
+ try
+ {
+ IntPtr procaddr = IntPtr.Zero;
+ string strButtonHookDll = InstallationSpec.InstallPath + "ButtonHook.dll";
+
+ Log.Info(string.Format("{0}() - BHInteracter() Trying to load ButtonHook.dll {1}", MethodBase.GetCurrentMethod().Name, strButtonHookDll));
+ IntPtr ButtonHook = Win32.Win32Functions.LoadLibrary(strButtonHookDll);
+ if(ButtonHook != IntPtr.Zero)
+ Log.Info(string.Format("{0}() - BHInteracter() loading ButtonHook.dll succeeded", MethodBase.GetCurrentMethod().Name));
+ else
+ Log.Error(string.Format("{0}() - BHInteracter() loading ButtonHook.dll failed!", MethodBase.GetCurrentMethod().Name));
+
+ // StartButtonHook
+ procaddr = Win32.Win32Functions.GetProcAddress(ButtonHook, "_StartButtonHook@0");
+ if(procaddr != null)
+ _MyStartButtonHook = (MyStartButtonHook)Marshal.GetDelegateForFunctionPointer(procaddr, typeof(MyStartButtonHook));
+ else
+ Log.Info(string.Format("{0}() - BHInteracter() GetProcAddress for StartButtonHook Failed", MethodBase.GetCurrentMethod().Name));
+
+ // StopButtonHook
+ procaddr = Win32.Win32Functions.GetProcAddress(ButtonHook, "_StopButtonHook@0");
+ if (procaddr != null)
+ _MyStopButtonHook = (MyStopButtonHook)Marshal.GetDelegateForFunctionPointer(procaddr, typeof(MyStopButtonHook));
+ else
+ Log.Info(string.Format("{0}() - BHInteracter() GetProcAddress for StopButtonHook Failed", MethodBase.GetCurrentMethod().Name));
+
+ // IsButtonHookSet
+ procaddr = Win32.Win32Functions.GetProcAddress(ButtonHook, "_IsButtonHookSet@0");
+ if (procaddr != null)
+ _MyIsButtonHookSet = (MyIsButtonHookSet)Marshal.GetDelegateForFunctionPointer(procaddr, typeof(MyIsButtonHookSet));
+ else
+ Log.Info(string.Format("{0}() - BHInteracter() GetProcAddress for IsButtonHookSet Failed", MethodBase.GetCurrentMethod().Name));
+
+ // GetAllHookedWindowHandles
+ procaddr = Win32.Win32Functions.GetProcAddress(ButtonHook, "_GetAllHookedWindowHandles@4");
+ if (procaddr != null)
+ _MyGetAllHookedWindowHandles = (MyGetAllHookedWindowHandles)Marshal.GetDelegateForFunctionPointer(procaddr, typeof(MyGetAllHookedWindowHandles));
+ else
+ Log.Info(string.Format("{0}() - BHInteracter() GetProcAddress for GetAllHookedWindowHandles Failed", MethodBase.GetCurrentMethod().Name));
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - BHInteracter() Construction Failed", MethodBase.GetCurrentMethod().Name), e);
+ }
+ }
+
+ ///
+ /// Use this function wrapper to call the StartButtonHook DLLEntry Point
+ ///
+ public static void StartButtonHookDLLEntryW()
+ {
+ Log.Info(string.Format("{0}() - CaptionButton - About to call StartButtonHook()", MethodBase.GetCurrentMethod().Name));
+ if (_MyStartButtonHook())
+ Log.Info(string.Format("{0}() - StartButtonHook() Succeeded", MethodBase.GetCurrentMethod().Name));
+ else
+ Log.Error(string.Format("{0}() - StartButtonHook() Failed", MethodBase.GetCurrentMethod().Name));
+ }
+
+ ///
+ /// Use this function wrapper to call the StopButtonHook DLLEntry Point
+ ///
+ public static void StopButtonHookDLLEntryW()
+ {
+ Log.Info(string.Format("{0}() - CaptionButton - About to call StopButtonHook()", MethodBase.GetCurrentMethod().Name));
+ if (_MyStopButtonHook())
+ Log.Info(string.Format("{0}() - StopButtonHook() Succeeded", MethodBase.GetCurrentMethod().Name));
+ else
+ Log.Error(string.Format("{0}() - StopButtonHook() Failed", MethodBase.GetCurrentMethod().Name));
+ }
+
+ ///
+ /// Use this function wrapper to call the IsButtonHookSet DLLEntry Point
+ ///
+ public static bool IsButtonHookSetDLLEntryW()
+ {
+ return _MyIsButtonHookSet();
+ }
+
+ ///
+ /// Use this function wrapper to call the GetAllHookedWindowHandles DLLEntry Point
+ ///
+ public static void GetAllHookedWindowHandlesDLLEntryW(ref List handleList)
+ {
+ // Temporary ar buffer
+ int[] ar = new int[Win32.Win32_Constants.MAX_PATH];
+
+ // allocate and reset an new unmanaged buffer
+ IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(ar));
+ Marshal.Copy(ar, 0, p, ar.Length);
+
+ // get the size
+ int nsize = _MyGetAllHookedWindowHandles(p);
+
+ // copy data back as needed *delete unmanaged buffer*
+ Marshal.Copy(p,ar,0,nsize);
+ Marshal.FreeHGlobal(p);
+
+ // Make sure the passed in list is empty * and pass out the handle list*
+ handleList.Clear();
+ for (int i = 0; i < nsize; ++i)
+ handleList.Add((IntPtr)ar[i]);
+ }
+
+ ///
+ /// CaptionButton exe is the external process that hosts ButtonHook.dll
+ ///
+ /// true if the CaptionButtion exe is running, false otherwise
+ public static bool IsCaptionButtonRunning()
+ {
+ Process[] processes = Process.GetProcessesByName(CAPTIONBUTTON_PROCESSNAME);
+ return (processes.Length == 1);
+ }
+
+ ///
+ /// Start CaptionButton exe which can host the ButtonHook.dll
+ ///
+ public static void StartCaptionButton()
+ {
+ try
+ {
+ if (!IsCaptionButtonRunning())
+ {
+ TemporaryVal.DeleteVal();
+ ProcessStartInfo startInfo = new ProcessStartInfo(CAPTIONBUTTON_EXE_FULLPATH, CAPTIONBUTTON_CMDLINE);
+ startInfo.WindowStyle = ProcessWindowStyle.Hidden;
+ startInfo.WorkingDirectory = InstallationSpec.InstallPath;
+ Process p = Process.Start(startInfo);
+ Log.Info(string.Format("{0}() - Created a new Oogy CaptionButton Instance EXE with PID{1}", MethodBase.GetCurrentMethod().Name, p.Id.ToString()));
+
+ // Wait a little before sending any messages
+ Thread.Sleep(3000);
+
+ ////
+ // State Checking *IMP* .exe could have not shut down correctly, and buttonhook never got stopped
+ // so let's check to see what is going on
+ ////
+ bool bIsInvalidState = ((s_CaptionButtonState != CAPTIONBUTTON_VALIDITY_STATE.VALIDITY_NONE) &&
+ (s_CaptionButtonState != CAPTIONBUTTON_VALIDITY_STATE.VALIDITY_STOPPEDSUCCESS));
+
+ // Let's get the window handle from the child process
+ s_CaptionButtonHandle = (IntPtr)TemporaryVal.GetValI();
+ if (s_CaptionButtonHandle == IntPtr.Zero)
+ Log.Error(string.Format("{0}() - Child Handle is Zero! This means all functions below will return out and everything fails. Check into this.", MethodBase.GetCurrentMethod().Name));
+
+ TemporaryVal.DeleteVal();
+
+ // We somehow got into an invalid state, so let's send Stop Messages and see what happens,
+ // if those failed there is really not much more we can do except fail here
+ if (bIsInvalidState && !Helper_CaptionButtonMessageSender(s_CaptionButtonHandle, WM_CAPTIONBUTTON_STOP))
+ Log.Info(string.Format("{0}() - Trying to StopButtonHook gracefully failed - ignoring and trying to StartButtonHook Anyways", MethodBase.GetCurrentMethod().Name, p.Id.ToString()));
+
+ // Regular starting...
+ if (Helper_CaptionButtonMessageSender(s_CaptionButtonHandle, WM_CAPTIONBUTTON_START))
+ {
+ s_CaptionButtonState = CAPTIONBUTTON_VALIDITY_STATE.VALIDITY_CREATEDSUCCESS;
+ Log.Info(string.Format("{0}() - StartCaptionButton Succeeded - Started the ButtonHook Worked Successfully", MethodBase.GetCurrentMethod().Name, p.Id.ToString()));
+ }
+ else
+ {
+ s_CaptionButtonState = CAPTIONBUTTON_VALIDITY_STATE.VALIDITY_CREATEDFAILED;
+ Log.Error(string.Format("{0}() - StartCaptionButton Failed - Started the ButtonHook Did not work - VALIDITY_CREATEDFAILED - forcefully Killing the Process", MethodBase.GetCurrentMethod().Name, p.Id.ToString()));
+ p.Kill();
+ }
+ }
+ else
+ {
+ // Process is already running for some reason - this should never happen, but if it does,
+ // we'll handle it by doing an integrity check
+ Log.Info(string.Format("{0}() - StartCaptionButton - CaptionButton.exe already exists - performing Complete Integrity Check...", MethodBase.GetCurrentMethod().Name));
+ bool bIntegrityIsGood = CompleteButtonHookIntegrityCheck();
+
+ if (bIntegrityIsGood)
+ s_CaptionButtonState = CAPTIONBUTTON_VALIDITY_STATE.VALIDITY_CREATEDSUCCESS;
+ else
+ s_CaptionButtonState = CAPTIONBUTTON_VALIDITY_STATE.VALIDITY_INTEGRITYCHECK_FAILED;
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - StartCaptionButton - Error occured", MethodBase.GetCurrentMethod().Name), e);
+ }
+ }
+
+ ///
+ /// Stop CaptionButton exe which can host the ButtonHook.dll
+ ///
+ public static void StopCaptionButton()
+ {
+ Log.Info(string.Format("{0}() - StopCaptionButton Called", MethodBase.GetCurrentMethod().Name));
+ if (IsCaptionButtonRunning())
+ {
+ Process[] processes = Process.GetProcessesByName(CAPTIONBUTTON_PROCESSNAME);
+ foreach (Process p in processes)
+ {
+ Log.Info(string.Format("{0}() - Found OogyCaptionButton Pid {1}", MethodBase.GetCurrentMethod().Name, p.Id));
+
+ if (Helper_CaptionButtonMessageSender(s_CaptionButtonHandle, WM_CAPTIONBUTTON_STOP))
+ {
+ s_CaptionButtonState = CAPTIONBUTTON_VALIDITY_STATE.VALIDITY_STOPPEDSUCCESS;
+ Log.Info(string.Format("{0}() - StopCaptionButton Succeeded - Closing the ButtonHook Worked Successfully", MethodBase.GetCurrentMethod().Name, p.Id.ToString()));
+ }
+ else
+ {
+ s_CaptionButtonState = CAPTIONBUTTON_VALIDITY_STATE.VALIDITY_STOPPEDFAILED;
+ Log.Error(string.Format("{0}() - StopCaptionButton Failed - Closing the ButtonHook Did not work - forcefully Killing the Process", MethodBase.GetCurrentMethod().Name, p.Id.ToString()));
+ }
+
+ Log.Info(string.Format("{0}() - Closing a Oogy CaptionButton Instance EXE of PID{1}", MethodBase.GetCurrentMethod().Name, p.Id.ToString()));
+ p.Kill();
+ }
+ }
+ }
+
+ ///
+ /// Use this to send the Start/Stop Messages to Oogy CaptionButton.exe. Small Helper
+ /// function allows us to do cleaner error handling for starting and stopping (above)
+ ///
+ /// WM_CAPTIONBUTTON_START or WM_CAPTIONBUTTON_STOP
+ /// returns true if successful, false otherwise
+ private static bool Helper_CaptionButtonMessageSender(IntPtr hWnd, int Message)
+ {
+ if((hWnd != IntPtr.Zero) &&
+ (Message == WM_CAPTIONBUTTON_START || Message == WM_CAPTIONBUTTON_STOP))
+ {
+ for (int i = 0; i < CAPTION_START_STOP_MAX_TRY_COUNT; ++i)
+ {
+ // Send the Stop ButonHook Message to the Hidden window of the Process
+ Win32.Win32Functions.SendMessage(hWnd, Message, IntPtr.Zero, IntPtr.Zero);
+
+ // Wait a little second before querying for the state
+ Thread.Sleep(500);
+
+ // If this is a start message we can stop once the button hook is started
+ if (Message == WM_CAPTIONBUTTON_START &&
+ IsButtonHookSetDLLEntryW())
+ return true;
+
+ // If this is a stop message we can stop once the button hook no longer set
+ if (Message == WM_CAPTIONBUTTON_STOP &&
+ !IsButtonHookSetDLLEntryW())
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Check to see if buttonhook is alive for the passed in window
+ ///
+ /// handle to a buttonHooked Parent Window
+ public static bool IsButtonHookAliveOnWindow(IntPtr hWnd)
+ {
+ if (hWnd != IntPtr.Zero)
+ {
+ int retVal = Win32.Win32Functions.SendMessage((IntPtr)hWnd, WM_W32PINGISALIVE, IntPtr.Zero, IntPtr.Zero);
+ if (retVal == 0)
+ {
+ Log.Error(string.Format("{0}() - IsButtonHookAlive Failed for Window {1}", MethodBase.GetCurrentMethod().Name, hWnd.ToString()));
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Call this function to run a complete ButtonHook Integrity Check
+ ///
+ /// true if buttonhook passed all checks, false otherwise
+ public static bool CompleteButtonHookIntegrityCheck()
+ {
+ bool bSuccess = true;
+ Log.Info(string.Format("{0}() - CompleteButtonHookIntegrityCheck got called", MethodBase.GetCurrentMethod().Name));
+
+ // Make first sure that the Hook Is Set
+ if (!IsButtonHookSetDLLEntryW())
+ bSuccess = false;
+
+ // Now iterate through each hooked window pinging it
+ // for feedback
+ List handleList = new List();
+ foreach (IntPtr hWnd in handleList)
+ {
+ if (!IsButtonHookAliveOnWindow(hWnd) && Win32.Win32Functions.IsWindow(hWnd))
+ {
+ bSuccess = false; // buttonhook not responsive on an existing window
+ break;
+ }
+ }
+
+ if(bSuccess)
+ Log.Info(string.Format("{0}() - CompleteButtonHookIntegrityCheck passed successfully", MethodBase.GetCurrentMethod().Name));
+ else
+ Log.Error(string.Format("{0}() - CompleteButtonHookIntegrityCheck failed", MethodBase.GetCurrentMethod().Name));
+
+ return bSuccess;
+ }
+
+ ///
+ /// Use this to set the Transparency on a Window that is running the ButtonHook. ~Will Only work
+ /// for those windows.
+ ///
+ /// handle to a buttonHooked Parent Window
+ /// 0-255 byte value indicating the Transparency
+ public static void SetWindowTransparency(IntPtr hWnd, byte alpha)
+ {
+ if (hWnd != IntPtr.Zero)
+ {
+ int retVal = Win32.Win32Functions.SendMessage((IntPtr)hWnd, WM_W32SETPARENTWINDOWTRANSPERANCY, IntPtr.Zero, (IntPtr)alpha);
+ if (retVal == 0)
+ Log.Error(string.Format("{0}() - SetWindowTransparency Failed for Window {1} with alpha {2}", MethodBase.GetCurrentMethod().Name, hWnd.ToString(), alpha.ToString()));
+ }
+ }
+
+ ///
+ /// Use this to set the ActiveWindow on a Window that is running the ButtonHook. ~Will Only work
+ /// for those windows.
+ ///
+ /// handle to a buttonHooked Parent Window
+ public static void SetAsActiveWindow(IntPtr hWnd)
+ {
+ if (hWnd != IntPtr.Zero)
+ {
+ int retVal = Win32.Win32Functions.SendMessage((IntPtr)hWnd, WM_W32SETPARENTWINDOWACTIVE, IntPtr.Zero, IntPtr.Zero);
+ if (retVal == 0)
+ Log.Error(string.Format("{0}() - SetAsActiveWindow Failed for Window {1}", MethodBase.GetCurrentMethod().Name, hWnd.ToString()));
+ }
+ }
+
+ ///
+ /// Use this to send a message to a window to send a message to itself
+ ///
+ ///
+ public static void PostMessageAsIfFromWindow(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam )
+ {
+ if (hWnd != IntPtr.Zero)
+ {
+ StringBuilder strAtom = new StringBuilder(hWnd.ToString() + ";" + Msg.ToString() + ";" + wParam.ToString() + ";" + lParam.ToString());
+ int nAtom = Win32.Win32Functions.GlobalAddAtom(strAtom);
+
+ if (nAtom == 0)
+ Log.Error(string.Format("{0}() - SendMessageAsIfFromWindow GlobalAddAtom Failed for Window {1}", MethodBase.GetCurrentMethod().Name, hWnd.ToString()));
+
+ int retVal = Win32.Win32Functions.SendMessage((IntPtr)hWnd, WM_W32POSTMESSAGETOPARENTWINDOW, IntPtr.Zero, (IntPtr)nAtom);
+ if (retVal == 0)
+ Log.Error(string.Format("{0}() - SendMessageAsIfFromWindow ButtonHook Failed to process the String for Window {1}", MethodBase.GetCurrentMethod().Name, hWnd.ToString()));
+
+ Win32.Win32Functions.GlobalDeleteAtom(nAtom);
+ }
+ }
+
+ ///
+ /// Use this to set a new ButtonState to a buttonhooked window
+ ///
+ /// handle to a buttonHooked Parent Window
+ /// a new button state
+ public static BUTTON_HOOK_STATE SetW32ButtonToNewState(IntPtr hWnd, BUTTON_HOOK_STATE buttonState)
+ {
+ if (hWnd != IntPtr.Zero)
+ {
+ int retVal = Platform.Win32.Win32Functions.SendMessage((IntPtr)hWnd, WM_W32SETBUTTONSTATE, IntPtr.Zero, (IntPtr)buttonState);
+ if (retVal == 0)
+ Log.Error(string.Format("{0}() - SetW32ButtonToNewState Failed for Window {1} ", MethodBase.GetCurrentMethod().Name, hWnd.ToString()));
+ }
+ return buttonState;
+ }
+
+ ///
+ /// Use this to get a ButtonState from a buttonhooked window
+ ///
+ /// handle to a buttonHooked Parent Window
+ /// a new button state
+ public static BUTTON_HOOK_STATE GetW32ButtonState(IntPtr hWnd)
+ {
+ BUTTON_HOOK_STATE buttonState = BUTTON_HOOK_STATE.BUTTON_NONE;
+ if (hWnd != IntPtr.Zero)
+ {
+ int retVal = Platform.Win32.Win32Functions.SendMessage((IntPtr)hWnd, WM_W32GETBUTTONSTATE, IntPtr.Zero, IntPtr.Zero);
+ if (retVal == 0)
+ Log.Error(string.Format("{0}() - SetW32ButtonToNewState Failed for Window {1} ", MethodBase.GetCurrentMethod().Name, hWnd.ToString()));
+
+ try
+ {
+ buttonState = (BUTTON_HOOK_STATE)retVal;
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - Error Thrown ", MethodBase.GetCurrentMethod().Name), e);
+ }
+ }
+ return buttonState;
+ }
+
+ }
+}
diff --git a/Platform/Logger.cs b/Platform/Logger.cs
new file mode 100644
index 0000000..4d1b906
--- /dev/null
+++ b/Platform/Logger.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using log4net;
+using log4net.Config;
+using log4net.Core;
+using log4net.Appender;
+using log4net.Layout;
+using log4net.Repository.Hierarchy;
+
+namespace Foo.Platform
+{
+ public class Logger
+ {
+ static Logger()
+ {
+ BasicConfigurator.Configure(CreateAndConfigureRollingFileAppender());
+ }
+
+ ///
+ /// Returns the Log4Net Interface
+ ///
+ /// Object Type to pass in to create Logger for
+ /// Log4Net Interface
+ public static ILog GetLog4NetInterface(Type type)
+ {
+ return LogManager.GetLogger(type);
+ }
+
+ ///
+ /// Creates and Configures teh RollingFileAppender *Configuration goes on here *
+ ///
+ /// RollingFileAppender Class to be used in Configuring Log4Net
+ static private RollingFileAppender CreateAndConfigureRollingFileAppender()
+ {
+ RollingFileAppender fileAppender = new RollingFileAppender();
+ fileAppender.Layout = new PatternLayout(PatternLayout.DetailConversionPattern);
+
+ // Locking Minimal allows us to run Log4Net from multiple processes
+ fileAppender.LockingModel = new FileAppender.MinimalLock();
+
+ fileAppender.File = (Env.GetLogDirectory() + @"\LogServer.log");
+ fileAppender.AppendToFile = true;
+
+ #if DEBUG
+ fileAppender.Threshold = Level.All;
+ #else
+ fileAppender.Threshold = Level.Error;
+ #endif
+
+ fileAppender.MaximumFileSize = "5MB";
+ fileAppender.MaxSizeRollBackups = 3;
+ fileAppender.ActivateOptions();
+ return fileAppender;
+ }
+
+ }
+}
diff --git a/Platform/MyKeyFile.SNK b/Platform/MyKeyFile.SNK
new file mode 100644
index 0000000..8bc8162
Binary files /dev/null and b/Platform/MyKeyFile.SNK differ
diff --git a/Platform/OSWrapper.cs b/Platform/OSWrapper.cs
new file mode 100644
index 0000000..e6bba38
--- /dev/null
+++ b/Platform/OSWrapper.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Ooganizer.Platform
+{
+ class OSWrapper
+ {
+
+
+ void Lalelu()
+ {
+ using (OoganizerState oogyState = new OoganizerState())
+ {
+ string curWorkspaceName = oogyState.GetCurrentWorkspace();
+
+ if (curWorkspaceName != null)
+ {
+ using (OoganizerAPIProxy proxy = oogyState.GetAPIProxy())
+ {
+ Workspace curWorkspace = proxy.API.GetWorkspace(curWorkspaceName);
+
+ foreach (OoganizerDAL.Artifact artifact in curWorkspace.Artifacts)
+ {
+ if (curArtifact.Location.ToUpper() == artifact.Location.ToUpper())
+ {
+ bFound = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
+ }
+}
diff --git a/Platform/ObjectPooling.txt b/Platform/ObjectPooling.txt
new file mode 100644
index 0000000..d259d25
--- /dev/null
+++ b/Platform/ObjectPooling.txt
@@ -0,0 +1,3 @@
+
+Enterprise Services (.NET 1.1) Performance Guidelines - Object Pooling
+http://www.guidanceshare.com/wiki/Enterprise_Services_(.NET_1.1)_Performance_Guidelines_-_Object_Pooling
\ No newline at end of file
diff --git a/Platform/Platform.csproj b/Platform/Platform.csproj
new file mode 100644
index 0000000..4842e92
--- /dev/null
+++ b/Platform/Platform.csproj
@@ -0,0 +1,99 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}
+ Library
+ Properties
+ Foo.Platform
+ Platform
+ v3.5
+ 512
+
+
+
+
+
+
+
+
+
+
+ true
+ MyKeyFile.SNK
+
+
+ true
+ full
+ false
+ ..\Target\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\Target\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ False
+ ..\Components\log4net.dll
+
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {6DC93F91-D6D4-4C35-8A83-C180E8E22E16}
+ Satellite
+
+
+
+
+
+ $(FrameworkDir)\regasm.exe "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /unregister
+$(FrameworkDir)\regasm.exe "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /tlb:$(TargetName).tlb /codebase
+mkdir "$(SolutionDir)target\$(ConfigurationName)\Resources"
+xcopy "$(ProjectDir)Resources" "$(SolutionDir)target\$(ConfigurationName)\Resources" /E /C /Y
+copy "$(SolutionDir)Components\log4net.dll" "$(SolutionDir)target\$(ConfigurationName)\log4net.dll" /Y
+
+
+
+
\ No newline at end of file
diff --git a/Platform/Properties/AssemblyInfo.cs b/Platform/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..86debdf
--- /dev/null
+++ b/Platform/Properties/AssemblyInfo.cs
@@ -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("Platform")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Platform")]
+[assembly: AssemblyCopyright("Copyright © 2008")]
+[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("7401c7a2-13c4-4821-9b09-deb707d27b3a")]
+
+// 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")]
diff --git a/Platform/Resources/Themes/AeroTheme/ButtonDown.ico b/Platform/Resources/Themes/AeroTheme/ButtonDown.ico
new file mode 100644
index 0000000..bfc3922
Binary files /dev/null and b/Platform/Resources/Themes/AeroTheme/ButtonDown.ico differ
diff --git a/Platform/Resources/Themes/AeroTheme/ButtonUp.ico b/Platform/Resources/Themes/AeroTheme/ButtonUp.ico
new file mode 100644
index 0000000..eae7472
Binary files /dev/null and b/Platform/Resources/Themes/AeroTheme/ButtonUp.ico differ
diff --git a/Platform/Resources/Themes/AeroTheme/ToggleUp.ico b/Platform/Resources/Themes/AeroTheme/ToggleUp.ico
new file mode 100644
index 0000000..95056b1
Binary files /dev/null and b/Platform/Resources/Themes/AeroTheme/ToggleUp.ico differ
diff --git a/Platform/Resources/Themes/ClassicTheme/ButtonDown.ico b/Platform/Resources/Themes/ClassicTheme/ButtonDown.ico
new file mode 100644
index 0000000..e944d27
Binary files /dev/null and b/Platform/Resources/Themes/ClassicTheme/ButtonDown.ico differ
diff --git a/Platform/Resources/Themes/ClassicTheme/ButtonUp.ico b/Platform/Resources/Themes/ClassicTheme/ButtonUp.ico
new file mode 100644
index 0000000..516f4e8
Binary files /dev/null and b/Platform/Resources/Themes/ClassicTheme/ButtonUp.ico differ
diff --git a/Platform/Resources/Themes/ClassicTheme/ToggleUp.ico b/Platform/Resources/Themes/ClassicTheme/ToggleUp.ico
new file mode 100644
index 0000000..6b801ae
Binary files /dev/null and b/Platform/Resources/Themes/ClassicTheme/ToggleUp.ico differ
diff --git a/Platform/Resources/Themes/VistaNoAeroTheme/ButtonDown.ico b/Platform/Resources/Themes/VistaNoAeroTheme/ButtonDown.ico
new file mode 100644
index 0000000..e944d27
Binary files /dev/null and b/Platform/Resources/Themes/VistaNoAeroTheme/ButtonDown.ico differ
diff --git a/Platform/Resources/Themes/VistaNoAeroTheme/ButtonUp.ico b/Platform/Resources/Themes/VistaNoAeroTheme/ButtonUp.ico
new file mode 100644
index 0000000..516f4e8
Binary files /dev/null and b/Platform/Resources/Themes/VistaNoAeroTheme/ButtonUp.ico differ
diff --git a/Platform/Resources/Themes/VistaNoAeroTheme/ToggleUp.ico b/Platform/Resources/Themes/VistaNoAeroTheme/ToggleUp.ico
new file mode 100644
index 0000000..6b801ae
Binary files /dev/null and b/Platform/Resources/Themes/VistaNoAeroTheme/ToggleUp.ico differ
diff --git a/Platform/Resources/Themes/XPTheme/ButtonDown.ico b/Platform/Resources/Themes/XPTheme/ButtonDown.ico
new file mode 100644
index 0000000..e944d27
Binary files /dev/null and b/Platform/Resources/Themes/XPTheme/ButtonDown.ico differ
diff --git a/Platform/Resources/Themes/XPTheme/ButtonUp.ico b/Platform/Resources/Themes/XPTheme/ButtonUp.ico
new file mode 100644
index 0000000..516f4e8
Binary files /dev/null and b/Platform/Resources/Themes/XPTheme/ButtonUp.ico differ
diff --git a/Platform/Resources/Themes/XPTheme/ToggleUp.ico b/Platform/Resources/Themes/XPTheme/ToggleUp.ico
new file mode 100644
index 0000000..6b801ae
Binary files /dev/null and b/Platform/Resources/Themes/XPTheme/ToggleUp.ico differ
diff --git a/Platform/Satellite/GUI.cs b/Platform/Satellite/GUI.cs
new file mode 100644
index 0000000..d5ee080
--- /dev/null
+++ b/Platform/Satellite/GUI.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Resources;
+using System.Reflection;
+
+namespace Foo.Platform.Satellite
+{
+ ///
+ /// Quick N' Easy access to the Satellite GUI Assembly Resource
+ ///
+ public static class GUIResx
+ {
+ private static ResourceManager _ResourceManager = null;
+ private static Assembly _Assembly = null;
+
+ ///
+ /// Construction
+ ///
+ static GUIResx()
+ {
+ try
+ {
+ if (_ResourceManager == null && _Assembly == null)
+ {
+ _Assembly = Assembly.LoadFile(InstallationSpec.InstallPath + "\\" + "Satellite.dll");
+ _ResourceManager = new ResourceManager("Foo.Satellite.GUI", _Assembly);
+
+ // * For Debugging *
+ //string[] resourceNames = _Assembly.GetManifestResourceNames();
+ //foreach (string resourceName in resourceNames)
+ //{
+ // string Doris = resourceName;
+ //}
+ }
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ }
+ }
+
+ ///
+ /// Returns a Resource value as a string
+ ///
+ /// name of resource to get
+ /// the value of the resource
+ public static string GetString(string strName)
+ {
+ string retVal = string.Empty;
+ try
+ {
+ retVal = _ResourceManager.GetString(strName);
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ }
+ return retVal;
+ }
+ }
+}
diff --git a/Platform/Utilities/DebugLogger.cs b/Platform/Utilities/DebugLogger.cs
new file mode 100644
index 0000000..f58e99b
--- /dev/null
+++ b/Platform/Utilities/DebugLogger.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using Microsoft.Win32;
+using System.Reflection;
+using System.Diagnostics;
+
+namespace Ooganizer.Platform.Utilities
+{
+ public class DebugLogger
+ {
+ private static string s_strFileNPath = "";
+ private static FileM s_fileM = null;
+ private static LogInstantiator s_LogI = null;
+ private static int s_LoadTime = 0;
+ private static bool s_firstTime = true;
+
+ ///
+ /// Use the Log(string line) method to quickly write to a temp log file in the current assembly directory
+ ///
+ static DebugLogger()
+ {
+ if (s_LogI == null)
+ {
+ int timebefore = System.Environment.TickCount;
+ s_LogI = new LogInstantiator();
+ s_LoadTime = System.Environment.TickCount - timebefore;
+ }
+
+ if (s_fileM == null)
+ s_fileM = new FileM(s_LogI.strFileName, "log", s_LogI.strDirectoryPath, true);
+
+ if(s_strFileNPath == "")
+ s_strFileNPath = s_fileM.PathNFile;
+ }
+
+ public static void Log(string line)
+ {
+ if (s_firstTime)
+ {
+ //s_fileM.WriteLineUTF8("EasyLogger's Logger.cs was loaded in " + s_LoadTime.ToString() + " miliseconds");
+ s_firstTime = false;
+ }
+ s_fileM.WriteLineUTF8(line);
+ }
+
+ ///
+ /// Small Helper class in order to get the location of the currently running assembly
+ ///
+ private class LogInstantiator
+ {
+ public string strFileName;
+ public string strDirectoryPath;
+ private static RegistryKey s_OogyRootKey;
+
+ public LogInstantiator()
+ {
+ // For Random File names ~shouldn't be used anymore
+ //string strRandomFileName = Path.GetRandomFileName();
+ //strRandomFileName = strRandomFileName.Substring(0, (strRandomFileName.Length - 4)); // stripe extension (.xyz)
+ //strFileName = strRandomFileName;
+
+ // Find the Calling Assembly that is NOT this one
+ StackTrace stackTrace = new StackTrace();
+ StackFrame stackFrame;
+ MethodBase stackFrameMethod;
+ string typeName;
+
+ int framecount = 3;
+ stackFrame = stackTrace.GetFrame(framecount);
+ stackFrameMethod = stackFrame.GetMethod();
+ typeName = stackFrameMethod.ReflectedType.FullName;
+
+ // *IMP* Use the calling Assembly Type Name as the file name
+ strFileName = typeName;
+
+ // *Work-Around*, we can't have a circular reference with InstallationSpec, so we just
+ // have to Query for the LogPath Directly instead of using Platform.InstallationSpec
+ s_OogyRootKey = Registry.LocalMachine.OpenSubKey("Software\\Ooganizer",false);
+
+ if (s_OogyRootKey != null)
+ {
+ object keyvalue = s_OogyRootKey.GetValue("LogPath");
+ if ((keyvalue != null) && (keyvalue.ToString() != ""))
+ strDirectoryPath = keyvalue.ToString();
+ }
+ }
+ }
+ }
+}
diff --git a/Platform/Utilities/FileM.cs b/Platform/Utilities/FileM.cs
new file mode 100644
index 0000000..7d08be7
--- /dev/null
+++ b/Platform/Utilities/FileM.cs
@@ -0,0 +1,154 @@
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace Ooganizer.Platform.Utilities
+{
+ public class FileM
+ {
+ private string m_sFileName;
+ private string m_sFileType;
+ private string m_sFileDirPath;
+
+ //Flags
+ private bool m_bIsFileCreated = false;
+ private bool m_bOverideExisting = true;
+ private bool m_bDeleteOnDestruct = false;
+
+ // Creates Temporary File by Default
+ public FileM(string FileType)
+ {
+ m_sFileName = Path.GetRandomFileName();
+ m_sFileType = FileType;
+ m_sFileDirPath = Path.GetTempPath();
+ m_bDeleteOnDestruct = true;
+ }
+
+ public FileM(string FileType, bool bDontDeleteOnDestruct)
+ {
+ m_sFileName = Path.GetRandomFileName();
+ m_sFileType = FileType;
+ m_sFileDirPath = Path.GetTempPath();
+ m_bDeleteOnDestruct = !bDontDeleteOnDestruct;
+ }
+
+ public FileM(string FileName, string FileType, string DirectoryPath, bool OverideExisting)
+ {
+ m_sFileName = FileName;
+ m_sFileType = FileType;
+ if (!Directory.Exists(DirectoryPath))
+ {
+ Directory.CreateDirectory(DirectoryPath);
+ }
+ m_sFileDirPath = DirectoryPath + "\\";
+ m_bOverideExisting = OverideExisting;
+ }
+
+ ~FileM()
+ {
+ if (m_bDeleteOnDestruct)
+ {
+ File.Delete(this.PathNFile);
+ }
+ }
+
+ public void WriteLineA(string line)
+ {
+ FileStream fs = CreateFile();
+ StreamWriter sw = new StreamWriter(fs, Encoding.ASCII);
+ sw.WriteLine(line);
+ sw.Flush();
+ sw.Close();
+ fs.Close();
+ }
+
+ public void WriteLineA(string[] lines)
+ {
+ FileStream fs = CreateFile();
+ StreamWriter sw = new StreamWriter(fs, Encoding.ASCII);
+
+ foreach (string line in lines)
+ {
+ sw.WriteLine(line);
+ }
+
+ sw.Flush();
+ sw.Close();
+ fs.Close();
+ }
+
+ public void WriteLineUTF8(string line)
+ {
+ FileStream fs = CreateFile();
+ StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
+ sw.WriteLine(line);
+ sw.Flush();
+ sw.Close();
+ fs.Close();
+ }
+
+ public void WriteLineUTF8(string[] lines)
+ {
+ FileStream fs = CreateFile();
+ StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
+
+ foreach (string line in lines)
+ {
+ sw.WriteLine(line);
+ }
+
+ sw.Flush();
+ sw.Close();
+ fs.Close();
+ }
+
+ public void DeleteIfExists()
+ {
+ if (File.Exists(this.PathNFile))
+ {
+ File.Delete(this.PathNFile);
+ }
+ }
+
+ private FileStream CreateFile()
+ {
+ if (!m_bIsFileCreated && m_bOverideExisting)
+ {
+ m_bIsFileCreated = true;
+ return (new FileStream(this.PathNFile, FileMode.Create));
+ }
+ else
+ {
+ return (new FileStream(this.PathNFile, FileMode.Append));
+ }
+ }
+
+ // public properties
+ public string FileName
+ {
+ get
+ {
+ return (this.FileName);
+ }
+ }
+
+ public string DirectoryPath
+ {
+ get
+ {
+ return (this.m_sFileDirPath);
+ }
+ }
+
+ public string PathNFile
+ {
+ get
+ {
+ return (m_sFileDirPath + m_sFileName + "." + m_sFileType);
+ }
+ }
+
+ }
+}
diff --git a/Platform/Utilities/RegM.cs b/Platform/Utilities/RegM.cs
new file mode 100644
index 0000000..122bb65
--- /dev/null
+++ b/Platform/Utilities/RegM.cs
@@ -0,0 +1,191 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.Win32;
+
+namespace Foo.Platform.Utilities
+{
+ public enum HKEYRoot
+ {
+ ClassesRoot,
+ CurrentUser,
+ LocalMachine,
+ }
+
+ public enum KeySub
+ {
+ Software,
+ Custom
+ }
+
+ public class RegM
+ {
+
+ private RegistryKey _RegKey;
+
+ ///
+ /// Use this to Open/Automatically Create a Registry Key
+ ///
+ /// specify registry root
+ /// specify a sub or custom
+ /// key you want to open / create
+ /// true if you plan on writing to it
+ public RegM(HKEYRoot root, KeySub sub, string Key, bool bWrite)
+ {
+ string KeyToOpen = String.Empty;
+ if (sub == KeySub.Custom)
+ KeyToOpen = Key;
+ else
+ KeyToOpen = sub.ToString() + "\\" + Key;
+
+ RegistryKeyPermissionCheck permission = RegistryKeyPermissionCheck.ReadSubTree;
+ if (bWrite)
+ permission = RegistryKeyPermissionCheck.ReadWriteSubTree;
+
+ // Open/Create if it doesn't exist, the Proper Key
+ switch (root)
+ {
+ case HKEYRoot.ClassesRoot:
+ _RegKey = Registry.ClassesRoot.CreateSubKey(KeyToOpen, permission);
+ break;
+
+ case HKEYRoot.CurrentUser:
+ _RegKey = Registry.CurrentUser.CreateSubKey(KeyToOpen, permission);
+ break;
+
+ case HKEYRoot.LocalMachine:
+ _RegKey = Registry.LocalMachine.CreateSubKey(KeyToOpen, permission);
+ break;
+ }
+ }
+
+ #region GetValue Registry Functions
+
+ public bool GetVal_String(string strValKey, out string StringValue)
+ {
+ StringValue = String.Empty;
+ try
+ {
+ object keyvalue = null;
+ keyvalue = _RegKey.GetValue(strValKey);
+ if (isValidStr(keyvalue))
+ StringValue = keyvalue.ToString();
+ return true;
+ }
+ catch (Exception) { /* ignore */ }
+ return false;
+ }
+
+ public bool GetVal_Bool(string strValKey, out bool BoolValue)
+ {
+ BoolValue = false;
+ try
+ {
+ string StringValue;
+ if (GetVal_String(strValKey, out StringValue) &&
+ !String.IsNullOrEmpty(StringValue))
+ BoolValue = Boolean.Parse(StringValue);
+ return true;
+ }
+ catch (Exception) { /* ignore */ }
+ return false;
+ }
+
+ public bool GetVal_Int(string strValKey, out int IntValue)
+ {
+ IntValue = 0;
+ try
+ {
+ string StringValue;
+ if (GetVal_String(strValKey, out StringValue) &&
+ !String.IsNullOrEmpty(StringValue))
+ IntValue = int.Parse(StringValue);
+ return true;
+ }
+ catch (Exception) { /* ignore */ }
+ return false;
+ }
+
+ public bool GetVal_Binary(string strValKey, out byte[] ByteValue)
+ {
+ ByteValue = null;
+ try
+ {
+ string StringValue;
+ if (GetVal_String(strValKey, out StringValue) &&
+ !String.IsNullOrEmpty(StringValue))
+ {
+ ByteValue = new Byte[StringValue.Length];
+ for (int i = 0; i < ByteValue.Length; ++i)
+ {
+ string strByte = Convert.ToString(StringValue[i]);
+ ByteValue[i] = byte.Parse(strByte);
+ }
+ }
+ return true;
+ }
+ catch (Exception) { /* ignore */ }
+ return false;
+ }
+
+ #endregion
+
+ #region SetValue Registry Functions
+
+ public bool SetVal_String(string strValKey, string StringValue)
+ {
+ try
+ {
+ _RegKey.SetValue(strValKey, StringValue, RegistryValueKind.String);
+ return true;
+ }
+ catch (Exception) { /* ignore */ }
+ return false;
+ }
+
+ public bool SetVal_Bool(string strValKey, bool BoolValue)
+ {
+ try
+ {
+ _RegKey.SetValue(strValKey, BoolValue.ToString(), RegistryValueKind.String);
+ return true;
+ }
+ catch (Exception) { /* ignore */ }
+ return false;
+ }
+
+ public bool SetVal_Int(string strValKey, int DwordValue)
+ {
+ try
+ {
+ _RegKey.SetValue(strValKey, DwordValue, RegistryValueKind.DWord);
+ return true;
+ }
+ catch (Exception) { /* ignore */ }
+ return false;
+ }
+
+ public bool SetVal_Binary(string strValKey, byte[] ByteValue)
+ {
+ try
+ {
+ _RegKey.SetValue(strValKey, ByteValue, RegistryValueKind.Binary);
+ return true;
+ }
+ catch (Exception) { /* ignore */ }
+ return false;
+ }
+
+ #endregion
+
+ /// Returns true if passed in object is valid and not ""
+ private bool isValidStr(object oToValidate)
+ {
+ if ((oToValidate != null) && (oToValidate.ToString() != ""))
+ return true;
+ else
+ return false;
+ }
+ }
+
+}
diff --git a/Platform/Win32.cs b/Platform/Win32.cs
new file mode 100644
index 0000000..0fe3a71
--- /dev/null
+++ b/Platform/Win32.cs
@@ -0,0 +1,1362 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using System.Diagnostics;
+using System.Threading;
+using System.Windows.Forms;
+using System.Drawing;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+
+// TODO Move most of this to the Platform project
+namespace Foo.Platform.Win32
+{
+ public class MyWin32Wnd : IWin32Window
+ {
+ private IntPtr m_Handle = IntPtr.Zero;
+ public IntPtr Handle
+ {
+ get{return m_Handle;}
+ set{m_Handle = value;}
+ }
+ }
+
+ ////
+ // Win32 Enums
+ ////
+ #region Win32 Enums
+
+ public enum WindowAction : int
+ {
+ SW_HIDE = 0,
+ SW_SHOWNORMAL = 1,
+ SW_NORMAL = 1,
+ SW_SHOWMINIMIZED = 2,
+ SW_SHOWMAXIMIZED = 3,
+ SW_MAXIMIZE = 3,
+ SW_SHOWNOACTIVATE = 4,
+ SW_SHOW = 5,
+ SW_MINIMIZE = 6,
+ SW_SHOWMINNOACTIVE = 7,
+ SW_SHOWNA = 8,
+ SW_RESTORE = 9,
+ SW_SHOWDEFAULT = 10,
+ SW_FORCEMINIMIZE = 11,
+ SW_MAX = 11
+ }
+
+ public enum WindowLong : int
+ {
+ GWL_EXSTYLE = -20,
+ GWL_STYLE = -16,
+ GWL_WNDPROC = -4,
+ GWL_HINSTANCE = -6,
+ GWL_ID = -12,
+ GWL_USERDATA = -21,
+ DWL_DLGPROC = 4,
+ DWL_MSGRESULT = 0,
+ DWL_USER = 8
+ }
+
+ public enum WindowStyles : uint
+ {
+ WS_MAXIMIZE = 0x01000000,
+ WS_VISIBLE = 0x10000000,
+ WS_POPUP = 0x80000000,
+ WS_BORDER = 0x00800000,
+ WS_CAPTION = 0x00C00000,
+ WS_CHILD = 0x40000000,
+ WS_CHILDWINDOW = 0x40000000,
+ WS_CLIPCHILDREN = 0x02000000,
+ WS_CLIPSIBLINGS = 0x04000000,
+ WS_DISABLED = 0x08000000,
+ WS_DLGFRAME = 0x00400000,
+ WS_GROUP = 0x00020000
+ }
+
+ public enum WindowMessage : int
+ {
+ WM_NULL = 0x0000,
+ WM_CREATE = 0x0001,
+ WM_DESTROY = 0x0002,
+ WM_MOVE = 0x0003,
+ WM_SIZE = 0x0005,
+ WM_ACTIVATE = 0x0006,
+ WM_SETFOCUS = 0x0007,
+ WM_KILLFOCUS = 0x0008,
+ WM_ENABLE = 0x000A,
+ WM_SETREDRAW = 0x000B,
+ WM_SETTEXT = 0x000C,
+ WM_GETTEXT = 0x000D,
+ WM_GETTEXTLENGTH = 0x000E,
+ WM_PAINT = 0x000F,
+ WM_CLOSE = 0x0010,
+ WM_QUERYENDSESSION = 0x0011,
+ WM_QUIT = 0x0012,
+ WM_QUERYOPEN = 0x0013,
+ WM_ERASEBKGND = 0x0014,
+ WM_SYSCOLORCHANGE = 0x0015,
+ WM_ENDSESSION = 0x0016,
+ WM_SHOWWINDOW = 0x0018,
+ WM_CTLCOLOR = 0x0019,
+ WM_WININICHANGE = 0x001A,
+ WM_SETTINGCHANGE = 0x001A,
+ WM_DEVMODECHANGE = 0x001B,
+ WM_ACTIVATEAPP = 0x001C,
+ WM_FONTCHANGE = 0x001D,
+ WM_TIMECHANGE = 0x001E,
+ WM_CANCELMODE = 0x001F,
+ WM_SETCURSOR = 0x0020,
+ WM_MOUSEACTIVATE = 0x0021,
+ WM_CHILDACTIVATE = 0x0022,
+ WM_QUEUESYNC = 0x0023,
+ WM_GETMINMAXINFO = 0x0024,
+ WM_PAINTICON = 0x0026,
+ WM_ICONERASEBKGND = 0x0027,
+ WM_NEXTDLGCTL = 0x0028,
+ WM_SPOOLERSTATUS = 0x002A,
+ WM_DRAWITEM = 0x002B,
+ WM_MEASUREITEM = 0x002C,
+ WM_DELETEITEM = 0x002D,
+ WM_VKEYTOITEM = 0x002E,
+ WM_CHARTOITEM = 0x002F,
+ WM_SETFONT = 0x0030,
+ WM_GETFONT = 0x0031,
+ WM_SETHOTKEY = 0x0032,
+ WM_GETHOTKEY = 0x0033,
+ WM_QUERYDRAGICON = 0x0037,
+ WM_COMPAREITEM = 0x0039,
+ WM_GETOBJECT = 0x003D,
+ WM_COMPACTING = 0x0041,
+ WM_COMMNOTIFY = 0x0044,
+ WM_WINDOWPOSCHANGING = 0x0046,
+ WM_WINDOWPOSCHANGED = 0x0047,
+ WM_POWER = 0x0048,
+ WM_COPYDATA = 0x004A,
+ WM_CANCELJOURNAL = 0x004B,
+ WM_NOTIFY = 0x004E,
+ WM_INPUTLANGCHANGEREQUEST = 0x0050,
+ WM_INPUTLANGCHANGE = 0x0051,
+ WM_TCARD = 0x0052,
+ WM_HELP = 0x0053,
+ WM_USERCHANGED = 0x0054,
+ WM_NOTIFYFORMAT = 0x0055,
+ WM_CONTEXTMENU = 0x007B,
+ WM_STYLECHANGING = 0x007C,
+ WM_STYLECHANGED = 0x007D,
+ WM_DISPLAYCHANGE = 0x007E,
+ WM_GETICON = 0x007F,
+ WM_SETICON = 0x0080,
+ WM_NCCREATE = 0x0081,
+ WM_NCDESTROY = 0x0082,
+ WM_NCCALCSIZE = 0x0083,
+ WM_NCHITTEST = 0x0084,
+ WM_NCPAINT = 0x0085,
+ WM_NCACTIVATE = 0x0086,
+ WM_GETDLGCODE = 0x0087,
+ WM_SYNCPAINT = 0x0088,
+ WM_NCMOUSEMOVE = 0x00A0,
+ WM_NCLBUTTONDOWN = 0x00A1,
+ WM_NCLBUTTONUP = 0x00A2,
+ WM_NCLBUTTONDBLCLK = 0x00A3,
+ WM_NCRBUTTONDOWN = 0x00A4,
+ WM_NCRBUTTONUP = 0x00A5,
+ WM_NCRBUTTONDBLCLK = 0x00A6,
+ WM_NCMBUTTONDOWN = 0x00A7,
+ WM_NCMBUTTONUP = 0x00A8,
+ WM_NCMBUTTONDBLCLK = 0x00A9,
+ WM_KEYDOWN = 0x0100,
+ WM_KEYUP = 0x0101,
+ WM_CHAR = 0x0102,
+ WM_DEADCHAR = 0x0103,
+ WM_SYSKEYDOWN = 0x0104,
+ WM_SYSKEYUP = 0x0105,
+ WM_SYSCHAR = 0x0106,
+ WM_SYSDEADCHAR = 0x0107,
+ WM_KEYLAST = 0x0108,
+ WM_IME_STARTCOMPOSITION = 0x010D,
+ WM_IME_ENDCOMPOSITION = 0x010E,
+ WM_IME_COMPOSITION = 0x010F,
+ WM_IME_KEYLAST = 0x010F,
+ WM_INITDIALOG = 0x0110,
+ WM_COMMAND = 0x0111,
+ WM_SYSCOMMAND = 0x0112,
+ WM_TIMER = 0x0113,
+ WM_HSCROLL = 0x0114,
+ WM_VSCROLL = 0x0115,
+ WM_INITMENU = 0x0116,
+ WM_INITMENUPOPUP = 0x0117,
+ WM_MENUSELECT = 0x011F,
+ WM_MENUCHAR = 0x0120,
+ WM_ENTERIDLE = 0x0121,
+ WM_MENURBUTTONUP = 0x0122,
+ WM_MENUDRAG = 0x0123,
+ WM_MENUGETOBJECT = 0x0124,
+ WM_UNINITMENUPOPUP = 0x0125,
+ WM_MENUCOMMAND = 0x0126,
+ WM_CTLCOLORMSGBOX = 0x0132,
+ WM_CTLCOLOREDIT = 0x0133,
+ WM_CTLCOLORLISTBOX = 0x0134,
+ WM_CTLCOLORBTN = 0x0135,
+ WM_CTLCOLORDLG = 0x0136,
+ WM_CTLCOLORSCROLLBAR = 0x0137,
+ WM_CTLCOLORSTATIC = 0x0138,
+ WM_MOUSEMOVE = 0x0200,
+ WM_LBUTTONDOWN = 0x0201,
+ WM_LBUTTONUP = 0x0202,
+ WM_LBUTTONDBLCLK = 0x0203,
+ WM_RBUTTONDOWN = 0x0204,
+ WM_RBUTTONUP = 0x0205,
+ WM_RBUTTONDBLCLK = 0x0206,
+ WM_MBUTTONDOWN = 0x0207,
+ WM_MBUTTONUP = 0x0208,
+ WM_MBUTTONDBLCLK = 0x0209,
+ WM_MOUSEWHEEL = 0x020A,
+ WM_PARENTNOTIFY = 0x0210,
+ WM_ENTERMENULOOP = 0x0211,
+ WM_EXITMENULOOP = 0x0212,
+ WM_NEXTMENU = 0x0213,
+ WM_SIZING = 0x0214,
+ WM_CAPTURECHANGED = 0x0215,
+ WM_MOVING = 0x0216,
+ WM_DEVICECHANGE = 0x0219,
+ WM_MDICREATE = 0x0220,
+ WM_MDIDESTROY = 0x0221,
+ WM_MDIACTIVATE = 0x0222,
+ WM_MDIRESTORE = 0x0223,
+ WM_MDINEXT = 0x0224,
+ WM_MDIMAXIMIZE = 0x0225,
+ WM_MDITILE = 0x0226,
+ WM_MDICASCADE = 0x0227,
+ WM_MDIICONARRANGE = 0x0228,
+ WM_MDIGETACTIVE = 0x0229,
+ WM_MDISETMENU = 0x0230,
+ WM_ENTERSIZEMOVE = 0x0231,
+ WM_EXITSIZEMOVE = 0x0232,
+ WM_DROPFILES = 0x0233,
+ WM_MDIREFRESHMENU = 0x0234,
+ WM_IME_SETCONTEXT = 0x0281,
+ WM_IME_NOTIFY = 0x0282,
+ WM_IME_CONTROL = 0x0283,
+ WM_IME_COMPOSITIONFULL = 0x0284,
+ WM_IME_SELECT = 0x0285,
+ WM_IME_CHAR = 0x0286,
+ WM_IME_REQUEST = 0x0288,
+ WM_IME_KEYDOWN = 0x0290,
+ WM_IME_KEYUP = 0x0291,
+ WM_MOUSEHOVER = 0x02A1,
+ WM_MOUSELEAVE = 0x02A3,
+ WM_CUT = 0x0300,
+ WM_COPY = 0x0301,
+ WM_PASTE = 0x0302,
+ WM_CLEAR = 0x0303,
+ WM_UNDO = 0x0304,
+ WM_RENDERFORMAT = 0x0305,
+ WM_RENDERALLFORMATS = 0x0306,
+ WM_DESTROYCLIPBOARD = 0x0307,
+ WM_DRAWCLIPBOARD = 0x0308,
+ WM_PAINTCLIPBOARD = 0x0309,
+ WM_VSCROLLCLIPBOARD = 0x030A,
+ WM_SIZECLIPBOARD = 0x030B,
+ WM_ASKCBFORMATNAME = 0x030C,
+ WM_CHANGECBCHAIN = 0x030D,
+ WM_HSCROLLCLIPBOARD = 0x030E,
+ WM_QUERYNEWPALETTE = 0x030F,
+ WM_PALETTEISCHANGING = 0x0310,
+ WM_PALETTECHANGED = 0x0311,
+ WM_HOTKEY = 0x0312,
+ WM_PRINT = 0x0317,
+ WM_PRINTCLIENT = 0x0318,
+ WM_HANDHELDFIRST = 0x0358,
+ WM_HANDHELDLAST = 0x035F,
+ WM_AFXFIRST = 0x0360,
+ WM_AFXLAST = 0x037F,
+ WM_PENWINFIRST = 0x0380,
+ WM_PENWINLAST = 0x038F,
+ WM_APP = 0x8000,
+ WM_USER = 0x0400,
+ WM_REFLECT = WM_USER + 0x1c00,
+ WM_CHANGEUISTATE = 0x0127,
+ WM_UPDATEUISTATE = 0x0128,
+ WM_QUERYUISTATE = 0x0129
+ }
+
+ public enum WindowUIState : int
+ {
+ UIS_SET = 1,
+ UIS_CLEAR = 2,
+ UIS_INITIALIZE = 3
+ }
+
+ public enum CSIDL : int
+ {
+ CSIDL_DESKTOP = 0x0000, //
+ CSIDL_INTERNET = 0x0001, // Internet Explorer (icon on desktop)
+ CSIDL_PROGRAMS = 0x0002, // Start Menu\Programs
+ CSIDL_CONTROLS = 0x0003, // My Computer\Control Panel
+ CSIDL_PRINTERS = 0x0004, // My Computer\Printers
+ CSIDL_PERSONAL = 0x0005, // My Documents
+ CSIDL_FAVORITES = 0x0006, // \Favorites
+ CSIDL_STARTUP = 0x0007, // Start Menu\Programs\Startup
+ CSIDL_RECENT = 0x0008, // \Recent
+ CSIDL_SENDTO = 0x0009, // \SendTo
+ CSIDL_BITBUCKET = 0x000a, // \Recycle Bin
+ CSIDL_STARTMENU = 0x000b, // \Start Menu
+ CSIDL_MYDOCUMENTS = 0x000c, // logical "My Documents" desktop icon
+ CSIDL_MYMUSIC = 0x000d, // "My Music" folder
+ CSIDL_MYVIDEO = 0x000e, // "My Videos" folder
+ CSIDL_DESKTOPDIRECTORY = 0x0010, // \Desktop
+ CSIDL_DRIVES = 0x0011, // My Computer
+ CSIDL_NETWORK = 0x0012, // Network Neighborhood (My Network Places)
+ CSIDL_NETHOOD = 0x0013, // \nethood
+ CSIDL_FONTS = 0x0014, // windows\fonts
+ CSIDL_TEMPLATES = 0x0015,
+ CSIDL_COMMON_STARTMENU = 0x0016, // All Users\Start Menu
+ CSIDL_COMMON_PROGRAMS = 0X0017, // All Users\Start Menu\Programs
+ CSIDL_COMMON_STARTUP = 0x0018, // All Users\Startup
+ CSIDL_COMMON_DESKTOPDIRECTORY = 0x0019, // All Users\Desktop
+ CSIDL_APPDATA = 0x001a, // \Application Data
+ CSIDL_PRINTHOOD = 0x001b, // \PrintHood
+ CSIDL_LOCAL_APPDATA = 0x001c, // \Local Settings\Applicaiton Data (non roaming)
+ CSIDL_ALTSTARTUP = 0x001d, // non localized startup
+ CSIDL_COMMON_ALTSTARTUP = 0x001e, // non localized common startup
+ CSIDL_COMMON_FAVORITES = 0x001f,
+ CSIDL_INTERNET_CACHE = 0x0020,
+ CSIDL_COOKIES = 0x0021,
+ CSIDL_HISTORY = 0x0022,
+ CSIDL_COMMON_APPDATA = 0x0023, // All Users\Application Data
+ CSIDL_WINDOWS = 0x0024, // GetWindowsDirectory()
+ CSIDL_SYSTEM = 0x0025, // GetSystemDirectory()
+ CSIDL_PROGRAM_FILES = 0x0026, // C:\Program Files
+ CSIDL_MYPICTURES = 0x0027, // C:\Program Files\My Pictures
+ CSIDL_PROFILE = 0x0028, // USERPROFILE
+ CSIDL_SYSTEMX86 = 0x0029, // x86 system directory on RISC
+ CSIDL_PROGRAM_FILESX86 = 0x002a, // x86 C:\Program Files on RISC
+ CSIDL_PROGRAM_FILES_COMMON = 0x002b, // C:\Program Files\Common
+ CSIDL_PROGRAM_FILES_COMMONX86 = 0x002c, // x86 Program Files\Common on RISC
+ CSIDL_COMMON_TEMPLATES = 0x002d, // All Users\Templates
+ CSIDL_COMMON_DOCUMENTS = 0x002e, // All Users\Documents
+ CSIDL_COMMON_ADMINTOOLS = 0x002f, // All Users\Start Menu\Programs\Administrative Tools
+ CSIDL_ADMINTOOLS = 0x0030, // \Start Menu\Programs\Administrative Tools
+ CSIDL_CONNECTIONS = 0x0031, // Network and Dial-up Connections
+ CSIDL_COMMON_MUSIC = 0x0035, // All Users\My Music
+ CSIDL_COMMON_PICTURES = 0x0036, // All Users\My Pictures
+ CSIDL_COMMON_VIDEO = 0x0037, // All Users\My Video
+ CSIDL_CDBURN_AREA = 0x003b // USERPROFILE\Local
+ }
+
+ public enum SHGFP_TYPE : int
+ {
+ SHGFP_TYPE_CURRENT = 0,
+ SHGFP_TYPE_DEFAULT = 1
+ }
+
+ public enum DesiredAccess : int
+ {
+ DELETE = 0x00010000, // Required to delete the object.
+ READ_CONTROL = 0x00020000, // Required to read information in the security descriptor for the object, not including the information in the SACL. To read or write the SACL, you must request the ACCESS_SYSTEM_SECURITY access right. For more information, see SACL Access Right.
+ SYNCHRONIZE = 0x00100000, // The right to use the object for synchronization. This enables a thread to wait until the object is in the signaled state.
+ WRITE_DAC = 0x00040000, // Required to modify the DACL in the security descriptor for the object.
+ WRITE_OWNER = 0x00080000 // Required to change the owner in the security descriptor for the object.
+ }
+
+ public enum WaitTime : uint
+ {
+ IGNORE = 0, // Ignore signal
+ INFINITE = 0xFFFFFFFF // Infinite timeout
+ }
+
+ public enum SystemMetric : int
+ {
+ SM_CXSCREEN = 0,
+ SM_CYSCREEN = 1,
+ SM_CXVSCROLL = 2,
+ SM_CYHSCROLL = 3,
+ SM_CYCAPTION = 4,
+ SM_CXBORDER = 5,
+ SM_CYBORDER = 6,
+ SM_CXDLGFRAME = 7,
+ SM_CYDLGFRAME = 8,
+ SM_CYVTHUMB = 9,
+ SM_CXHTHUMB = 10,
+ SM_CXICON = 11,
+ SM_CYICON = 12,
+ SM_CXCURSOR = 13,
+ SM_CYCURSOR = 14,
+ SM_CYMENU = 15,
+ SM_CXFULLSCREEN = 16,
+ SM_CYFULLSCREEN = 17,
+ SM_CYKANJIWINDOW = 18,
+ SM_MOUSEPRESENT = 19,
+ SM_CYVSCROLL = 20,
+ SM_CXHSCROLL = 21,
+ SM_DEBUG = 22,
+ SM_SWAPBUTTON = 23,
+ SM_RESERVED1 = 24,
+ SM_RESERVED2 = 25,
+ SM_RESERVED3 = 26,
+ SM_RESERVED4 = 27,
+ SM_CXMIN = 28,
+ SM_CYMIN = 29,
+ SM_CXSIZE = 30,
+ SM_CYSIZE = 31,
+ SM_CXFRAME = 32,
+ SM_CYFRAME = 33,
+ SM_CXMINTRACK = 34,
+ SM_CYMINTRACK = 35,
+ SM_CXDOUBLECLK = 36,
+ SM_CYDOUBLECLK = 37,
+ SM_CXICONSPACING = 38,
+ SM_CYICONSPACING = 39,
+ SM_MENUDROPALIGNMENT = 40,
+ SM_PENWINDOWS = 41,
+ SM_DBCSENABLED = 42,
+ SM_CMOUSEBUTTONS = 43
+ }
+
+ public enum SetWindowPosFlags : uint
+ {
+ SWP_NOSIZE = 0x0001,
+ SWP_NOMOVE = 0x0002,
+ SWP_NOZORDER = 0x0004,
+ SWP_NOREDRAW = 0x0008,
+ SWP_NOACTIVATE = 0x0010,
+ SWP_FRAMECHANGED = 0x0020,
+ SWP_SHOWWINDOW = 0x0040,
+ SWP_HIDEWINDOW = 0x0080,
+ SWP_NOCOPYBITS = 0x0100,
+ SWP_NOOWNERZORDER = 0x0200,
+ SWP_NOSENDCHANGING = 0x0400,
+ SWP_DRAWFRAME = SWP_FRAMECHANGED,
+ SWP_NOREPOSITION = SWP_NOOWNERZORDER
+ }
+
+ public enum WindowLayerAttributes
+ {
+ LWA_COLORKEY = 0x00000001,
+ LWA_ALPHA = 0x00000002
+ }
+
+ public enum WindowPos : int
+ {
+ HWND_TOP = 0,
+ HWND_BOTTOM = 1,
+ HWND_TOPMOST = -1,
+ HWND_NOTOPMOST = -2
+ }
+
+ public enum VK : ushort
+ {
+ SHIFT = 0x10,
+ CONTROL = 0x11,
+ MENU = 0x12,
+ ESCAPE = 0x1B,
+ BACK = 0x08,
+ TAB = 0x09,
+ RETURN = 0x0D,
+ PRIOR = 0x21,
+ NEXT = 0x22,
+ END = 0x23,
+ HOME = 0x24,
+ LEFT = 0x25,
+ UP = 0x26,
+ RIGHT = 0x27,
+ DOWN = 0x28,
+ SELECT = 0x29,
+ PRINT = 0x2A,
+ EXECUTE = 0x2B,
+ SNAPSHOT = 0x2C,
+ INSERT = 0x2D,
+ DELETE = 0x2E,
+ HELP = 0x2F,
+ NUMPAD0 = 0x60,
+ NUMPAD1 = 0x61,
+ NUMPAD2 = 0x62,
+ NUMPAD3 = 0x63,
+ NUMPAD4 = 0x64,
+ NUMPAD5 = 0x65,
+ NUMPAD6 = 0x66,
+ NUMPAD7 = 0x67,
+ NUMPAD8 = 0x68,
+ NUMPAD9 = 0x69,
+ MULTIPLY = 0x6A,
+ ADD = 0x6B,
+ SEPARATOR = 0x6C,
+ SUBTRACT = 0x6D,
+ DECIMAL = 0x6E,
+ DIVIDE = 0x6F,
+ F1 = 0x70,
+ F2 = 0x71,
+ F3 = 0x72,
+ F4 = 0x73,
+ F5 = 0x74,
+ F6 = 0x75,
+ F7 = 0x76,
+ F8 = 0x77,
+ F9 = 0x78,
+ F10 = 0x79,
+ F11 = 0x7A,
+ F12 = 0x7B,
+ OEM_1 = 0xBA, // ',:' for US
+ OEM_PLUS = 0xBB, // '+' any country
+ OEM_COMMA = 0xBC, // ',' any country
+ OEM_MINUS = 0xBD, // '-' any country
+ OEM_PERIOD = 0xBE, // '.' any country
+ OEM_2 = 0xBF, // '/?' for US
+ OEM_3 = 0xC0, // '`~' for US
+ MEDIA_NEXT_TRACK = 0xB0,
+ MEDIA_PREV_TRACK = 0xB1,
+ MEDIA_STOP = 0xB2,
+ MEDIA_PLAY_PAUSE = 0xB3,
+ LWIN = 0x5B,
+ RWIN = 0x5C
+ }
+
+ public enum AssocF : ushort
+ {
+ Init_NoRemapCLSID = 0x1,
+ Init_ByExeName = 0x2,
+ Open_ByExeName = 0x2,
+ Init_DefaultToStar = 0x4,
+ Init_DefaultToFolder = 0x8,
+ NoUserSettings = 0x10,
+ NoTruncate = 0x20,
+ Verify = 0x40,
+ RemapRunDll = 0x80,
+ NoFixUps = 0x100,
+ IgnoreBaseClass = 0x200
+ }
+
+ public enum AssocStr : ushort
+ {
+ Command = 1,
+ Executable,
+ FriendlyDocName,
+ FriendlyAppName,
+ NoOpen,
+ ShellNewValue,
+ DDECommand,
+ DDEIfExec,
+ DDEApplication,
+ DDETopic
+ }
+
+ #endregion
+
+ ////
+ // Win32 Structures
+ ////
+ #region Win32 Structures
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RECT
+ {
+ public int left;
+ public int top;
+ public int right;
+ public int bottom;
+
+ public Rectangle AsRectangle
+ {
+ get
+ {
+ return new Rectangle(this.left, this.top, this.right - this.left, this.bottom - this.top);
+ }
+ }
+
+ public static RECT FromXYWH(int x, int y, int width, int height)
+ {
+ RECT rect = new RECT();
+ rect.left = x;
+ rect.top = y;
+ rect.right = x + width;
+ rect.bottom = y + height;
+ return rect;
+ }
+
+ public static RECT FromRectangle(Rectangle rectangle)
+ {
+ RECT rect = new RECT();
+ rect.left = rectangle.Left;
+ rect.top = rectangle.Top;
+ rect.right = rectangle.Right;
+ rect.bottom = rectangle.Bottom;
+ return rect;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SIZE
+ {
+ public int cx;
+ public int cy;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ShellExecuteInfo
+ {
+ public int cbSize;
+ public uint fMask;
+ public IntPtr hwnd;
+ public string lpVerb;
+ public string lpFile;
+ public string lpParameters;
+ public string lpDirectory;
+ public uint nShow;
+ public IntPtr hInstApp;
+ public IntPtr lpIDList;
+ public string lpClass;
+ public IntPtr hkeyClass;
+ public uint dwHotKey;
+ public IntPtr hIcon_Monitor; // union DUMMYUNIONNAME
+ public IntPtr hProcess;
+ }
+
+ [StructLayout(LayoutKind.Explicit, Size = 28)]
+ public struct INPUT
+ {
+ [FieldOffset(0)]
+ public uint type;
+ [FieldOffset(4)]
+ public KEYBDINPUT ki;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct KEYBDINPUT
+ {
+ public ushort wVk;
+ public ushort wScan;
+ public uint dwFlags;
+ public long time;
+ public uint dwExtraInfo;
+ };
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MONITORINFOEX
+ {
+ public int cbSize;
+ public RECT rcMonitor;
+ public RECT rcWork;
+ public int dwFlags;
+ [MarshalAs(UnmanagedType.ByValTStr,SizeConst=32)]
+ public string szDeviceName;
+ }
+
+ #endregion
+
+ ////
+ // .Net Win32 Wrapper Functions
+ ////
+ public class Win32_WrapperFunc
+ {
+ ///
+ /// Get a windows client rectangle in a .NET structure
+ ///
+ /// The window handle to look up
+ /// The rectangle
+ public static Rectangle GetClientRect(IntPtr hwnd)
+ {
+ RECT rect = new RECT();
+ Win32Functions.GetClientRect(hwnd, out rect);
+ return rect.AsRectangle;
+ }
+
+ ///
+ /// Get a windows rectangle in a .NET structure
+ ///
+ /// The window handle to look up
+ /// The rectangle
+ public static Rectangle GetWindowRect(IntPtr hwnd)
+ {
+ RECT rect = new RECT();
+ Win32Functions.GetWindowRect(hwnd, out rect);
+ return rect.AsRectangle;
+ }
+
+ ///
+ /// Get's the System's registered file for the corresponding File
+ ///
+ /// full file name and path
+ /// Returns Registered exe for file in Uppercase
+ public static string GetRegisteredExeForFile(string fileNameAndPath)
+ {
+ if (!String.IsNullOrEmpty(fileNameAndPath))
+ {
+ bool bIsValidExe = false;
+ string strExeOrDllPath = string.Empty;
+ bool bSuccess = Win32_WrapperFunc.FindExeOrDll(fileNameAndPath, out strExeOrDllPath, out bIsValidExe);
+
+ if (bSuccess && bIsValidExe)
+ return Path.GetFileName(strExeOrDllPath).ToUpper();
+ }
+ return string.Empty;
+ }
+
+ ///
+ /// Useful for finding who is responsible by Shell32 to handle this file
+ ///
+ /// full qualifying path to File
+ /// will contain that path that is found in the registry
+ /// true if the return value is a valid exe, false if it is a Dll
+ /// true if a match was found, false otherwise
+ public static bool FindExeOrDll(string fileNameAndPath, out string strExeOrDllPath, out bool IsValidExe)
+ {
+ if (!String.IsNullOrEmpty(fileNameAndPath))
+ {
+ // Try FindExecutable first
+ StringBuilder retStr = new StringBuilder();
+ int ret = (int)Win32Functions.FindExecutable(fileNameAndPath, null, retStr);
+ strExeOrDllPath = retStr.ToString();
+
+ // If FindExe Failed, try AssocQueryString instead
+ if (String.IsNullOrEmpty(strExeOrDllPath))
+ {
+ string Ext = Path.GetExtension(fileNameAndPath);
+ StringBuilder retStr2 = new StringBuilder();
+ uint pcchOut = Win32_Constants.MAX_PATH;
+ Win32Functions.AssocQueryString(0, AssocStr.Executable, Ext, "open", retStr2, ref pcchOut);
+
+ if (retStr2.Length > 0)
+ strExeOrDllPath = retStr2.ToString();
+ }
+
+ IsValidExe = false;
+ if (!String.IsNullOrEmpty(strExeOrDllPath))
+ {
+ string Ext = Path.GetExtension(strExeOrDllPath);
+ IsValidExe = (Ext.ToUpper() == ".EXE");
+ return true;
+ }
+ }
+ strExeOrDllPath = string.Empty;
+ IsValidExe = false;
+ return false;
+ }
+
+ ///
+ /// Uses Shell32 to get the Windows location on this computer
+ ///
+ /// path to windows dir on this machine
+ public static string GetWindowsPath()
+ {
+ StringBuilder windowsPath = new StringBuilder();
+ Win32Functions.SHGetFolderPath(IntPtr.Zero, (int)CSIDL.CSIDL_WINDOWS, IntPtr.Zero, (int)SHGFP_TYPE.SHGFP_TYPE_CURRENT, windowsPath);
+ return windowsPath.ToString();
+ }
+
+ ///
+ /// Use this function to set transparency of a layered top level window.
+ /// This will only work on Windows that are part of your own Process Space. calling this on external windows,
+ /// outside of your process SetLayeredWindowAttributes() will fail.
+ ///
+ /// the window to make or unmake transparent
+ /// 0 for transparent 255 for totally visible
+ public static void SetAlphaChannel(IntPtr hWnd, byte alpha)
+ {
+ long dwStyle = (long) Win32Functions.GetWindowLong(hWnd, (int) ((int) WindowLong.GWL_EXSTYLE | (int) Win32_Constants.WS_EX_LAYERED));
+ long retVal = Win32Functions.SetWindowLong(hWnd, (int) WindowLong.GWL_EXSTYLE, (int) dwStyle);
+
+ if (retVal == 0)
+ Trace.Write("SetAlphaChannel's SetWindowLong Failed");
+
+ bool bSuccess = Win32Functions.SetLayeredWindowAttributes(hWnd, (int)Win32Functions.RGB(0, 0, 0), alpha, (uint)(WindowLayerAttributes.LWA_ALPHA));
+ if (!bSuccess)
+ Trace.Write("SetAlphaChannel's SetLayeredWindowAttributes Failed");
+ }
+
+ ///
+ /// Could be useful later - maybe
+ ///
+ ///
+ //public static Rectangle GetAbsoluteClientRect(IntPtr hWnd)
+ //{
+ // //Rectangle windowRect = Win32Functions.GetWindowRect(hWnd);
+ // //Rectangle clientRect = Win32Functions.GetClientRect(hWnd);
+
+ // //// This gives us the width of the left, right and bottom chrome - we can then determine the top height
+ // //int chromeWidth = (int)((windowRect.Width - clientRect.Width) / 2);
+ // //return new Rectangle(new Point(windowRect.X + chromeWidth, windowRect.Y + (windowRect.Height - clientRect.Height - chromeWidth)), clientRect.Size);
+ //}
+
+ }
+
+ ////
+ // Win32 Constants
+ ////
+ public class Win32_Constants
+ {
+ public const ushort KEYEVENTF_KEYUP = 0x0002;
+ public const int SRCCOPY = 0x00CC0020;
+ public const int CAPTUREBLT = 0x40000000;
+ public const int MONITOR_DEFAULTTONEAREST = 0x00000002;
+ public const int WM_USER = 0x0400;
+ public const int WS_EX_LAYERED = 0x00080000;
+ public const int MAX_PATH = 260;
+ }
+
+ ////
+ // Win32 Functions
+ ////
+ public class Win32Functions
+ {
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public static int LOWORD(int n)
+ {
+ return (n & 0xffff);
+ }
+ public static int HIWORD(int n)
+ {
+ return ((n >> 16) & 0xffff);
+ }
+ public static int RGB(int r, int g, int b)
+ {
+ int rs = r & 0xffff;
+ int gs = (g << 8) & 0xffff;
+ int bs = (b << 16) & 0xffff;
+ return (rs | gs | bs);
+ }
+
+ ////
+ // Shell32
+ ////
+ #region Shell32
+
+ [DllImport("shell32.dll")]
+ public static extern IntPtr ShellExecute(IntPtr hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd);
+
+ [DllImport("shell32.dll", SetLastError = true)]
+ extern public static bool ShellExecuteEx(ref ShellExecuteInfo lpExecInfo);
+
+ [DllImport("shell32.dll")]
+ extern public static IntPtr FindExecutable(string lfFile, string lpDirectory, [Out] StringBuilder lpResult);
+
+ [DllImport("shell32.dll")]
+ extern public static long SHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken, int dwFlags, [Out] StringBuilder pszPath);
+
+ #endregion
+
+ ////
+ // User32
+ ////
+ #region User32
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr SetFocus(IntPtr hwnd);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetFocus();
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr SetActiveWindow(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ extern public static IntPtr SetParent(IntPtr child, IntPtr newParent);
+
+ [DllImport("user32.dll")]
+ extern public static long SetWindowLong(IntPtr hWnd, int nIndex, Int32 dwNewLong);
+
+ [DllImport("user32.dll")]
+ extern public static long GetWindowLong(IntPtr hWnd, int nIndex);
+
+ [DllImport("User32.dll")]
+ extern public static int SetForegroundWindow(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ extern public static bool SetLayeredWindowAttributes(IntPtr hwnd, Int32 crKey, byte bAlpha, uint dwFlags);
+
+ [DllImport("User32.dll")]
+ extern public static IntPtr GetForegroundWindow();
+
+ [DllImport("User32.dll")]
+ extern public static bool IsWindow(IntPtr hwnd);
+
+ [DllImport("user32.dll")]
+ extern public static int ShowWindow(IntPtr hwnd, int nCmdShow);
+
+ [DllImport("user32.dll")]
+ extern public static int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
+
+ [DllImport("user32.dll")]
+ extern public static bool GetWindowRect(IntPtr hWnd, out RECT rect);
+
+ [DllImport("user32.dll")]
+ extern public static bool GetClientRect(IntPtr hWnd, out RECT rect);
+
+ [DllImport("User32.dll")]
+ extern public static bool EnumWindows(Delegate lpEnumFunc, IntPtr lParam);
+
+ [DllImport("User32.dll")]
+ extern public static int GetWindowThreadProcessId(IntPtr hWnd, ref int lpdwProcessId);
+
+ [DllImport("User32.dll")]
+ extern public static bool PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport("user32.dll")]
+ public static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);
+
+ [DllImport("User32.dll")]
+ extern public static int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport("user32.dll")]
+ extern public static int GetSystemMetrics(int index);
+
+ [DllImport("user32.dll")]
+ extern public static bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetDesktopWindow();
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetDC(IntPtr ptr);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetWindowDC(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetDCEx(IntPtr hWnd, IntPtr hrgnClip, int flags);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);
+
+ [DllImport("user32.dll")]
+ public static extern bool EmptyClipboard();
+
+ [DllImport("user32.dll")]
+ public static extern int GetClipboardSequenceNumber();
+
+ [DllImport("user32.dll")]
+ public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFOEX monitorinfo);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr MonitorFromRect(ref RECT rect, int dwFlags);
+
+ #endregion
+
+ ////
+ // Kernel32
+ ////
+ #region Kernel32
+
+ [DllImport("kernel32.dll")]
+ internal static extern IntPtr LoadLibrary(String dllname);
+
+ [DllImport("kernel32.dll")]
+ internal static extern IntPtr GetProcAddress(IntPtr hModule, String procname);
+
+ [DllImport("kernel32.dll")]
+ extern public static int GetProcessId(IntPtr hProcess);
+
+ [DllImport("kernel32.dll")]
+ extern public static IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
+
+ [DllImport("kernel32.dll")]
+ extern public static int WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
+
+ [DllImport("kernel32.dll")]
+ extern public static int GetLastError();
+
+ [DllImport("kernel32.dll")]
+ // lpEventAttributes should be a ref to a SECURITY_ATTRIBUTES struct, but we only pass in NULL so we can just make it an IntPtr
+ extern public static IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, [In] StringBuilder lpName);
+
+ [DllImport("kernel32.dll")]
+ extern public static IntPtr SetEvent(IntPtr hEvent);
+
+ [DllImport("kernel32.dll")]
+ extern public static bool CloseHandle(IntPtr hHandle);
+
+ [DllImport("kernel32.dll")]
+ extern public static int GlobalAddAtom([In] StringBuilder lpString);
+
+ [DllImport("kernel32.dll")]
+ extern public static int GlobalDeleteAtom(int nAtom);
+
+ #endregion
+
+ ////
+ // Shlwapi
+ ////
+ [DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ public static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder pszOut, [In][Out] ref uint pcchOut);
+
+ ////
+ // Ole32
+ ////
+ [DllImport("ole32.dll")]
+ public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);
+
+ ////
+ // Uxtheme
+ ////
+ [DllImport("uxTheme.dll")]
+ extern public static bool IsAppThemed();
+
+ ////
+ // Dwmapi
+ ////
+ [DllImport("dwmapi.dll")]
+ extern public static long DwmIsCompositionEnabled(ref bool pfEnabled);
+
+ ////
+ // GDI32
+ ////
+ #region GDI32
+
+ [DllImport("gdi32.dll")]
+ public static extern IntPtr DeleteDC(IntPtr hDc);
+
+ [DllImport("gdi32.dll")]
+ public static extern IntPtr DeleteObject(IntPtr hDc);
+
+ [DllImport("gdi32.dll")]
+ public static extern bool BitBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, int RasterOp);
+
+ [DllImport("gdi32.dll")]
+ public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
+
+ [DllImport("gdi32.dll")]
+ public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
+
+ [DllImport("gdi32.dll")]
+ public static extern IntPtr SelectObject(IntPtr hdc, IntPtr bmp);
+
+ [DllImport("gdi32.dll")]
+ public static extern IntPtr CreateDC(string lpszDriver, IntPtr passNULL, IntPtr passNULL2, IntPtr passNULL3);
+
+ #endregion
+
+ ////
+ // Helper .Net Functions
+ ////
+ // .net implementation of EnumWindowsProc Callback
+ public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
+
+ public interface IWindowHandleAccess
+ {
+ IntPtr hWnd
+ {
+ get;
+ set;
+ }
+ }
+
+ public static IntPtr GetWindowHandle(EnumWindowsProc proc, Context context) where Context : IWindowHandleAccess
+ {
+ // Initialize unmanged memory to hold the struct.
+ IntPtr pContext = Marshal.AllocHGlobal(Marshal.SizeOf(context));
+
+ try
+ {
+ // Copy the struct to unmanaged memory.
+ Marshal.StructureToPtr(context, pContext, false);
+
+ bool bFound = false;
+ int numTries = 5;
+
+ while (!bFound && numTries != 0)
+ {
+ Win32Functions.EnumWindows(proc, pContext);
+
+ // Marshall context back to managed
+ context = (Context)Marshal.PtrToStructure(pContext, typeof(Context));
+
+ if (context.hWnd != IntPtr.Zero)
+ {
+ bFound = true;
+ }
+ else
+ {
+ // Sleep a little and try again
+ Thread.Sleep(500);
+ --numTries;
+ }
+ }
+ }
+ finally
+ {
+ Log.ErrorFormat("{0}() - Unknown exception occured!", MethodBase.GetCurrentMethod().Name);
+
+ // Free the unmanaged memory.
+ Marshal.FreeHGlobal(pContext);
+ }
+
+ return context.hWnd;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct EnumWindowsContext_pid_filename : IWindowHandleAccess
+ {
+ public int targetPid;
+ public string filePath;
+ private IntPtr _hWnd;
+
+ public IntPtr hWnd
+ {
+ get
+ {
+ return _hWnd;
+ }
+
+ set
+ {
+ _hWnd = value;
+ }
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct EnumWindowsContext_filePath : IWindowHandleAccess
+ {
+ public string filePath;
+ private IntPtr _hWnd;
+
+ public IntPtr hWnd
+ {
+ get
+ {
+ return _hWnd;
+ }
+
+ set
+ {
+ _hWnd = value;
+ }
+ }
+ }
+
+ public static bool EnumWindowProcImpl_filePath(IntPtr hWnd, IntPtr pContext)
+ {
+ bool bContinueEnumerating = true;
+
+ // Marshall context back to managed
+ EnumWindowsContext_filePath context = new EnumWindowsContext_filePath();
+ context = (EnumWindowsContext_filePath)Marshal.PtrToStructure(pContext, typeof(EnumWindowsContext_filePath));
+
+ // Check if filePath is the text in the window title bar
+ if (IsTitleBar(hWnd, context.filePath))
+ {
+ Log.InfoFormat("{0}() - found!", MethodBase.GetCurrentMethod().Name);
+ context.hWnd = hWnd;
+
+ // Marshall changed data back to unmanaged
+ Marshal.StructureToPtr(context, pContext, false);
+ bContinueEnumerating = false;
+ }
+
+ return bContinueEnumerating;
+ }
+
+ public static bool EnumWindowProcImpl_pid_filename(IntPtr hWnd, IntPtr pContext)
+ {
+ bool bContinueEnumerating = true;
+
+ int currentPid = 0;
+ GetWindowThreadProcessId(hWnd, ref currentPid);
+
+ // Marshall context back to managed
+ EnumWindowsContext_pid_filename context = new EnumWindowsContext_pid_filename();
+ context = (EnumWindowsContext_pid_filename)Marshal.PtrToStructure(pContext, typeof(EnumWindowsContext_pid_filename));
+
+ if (currentPid == context.targetPid)
+ {
+ Log.InfoFormat("{0}() - currentpid = {1} vs. targetPid = {2} hwnd = {3}", MethodBase.GetCurrentMethod().Name, currentPid, context.targetPid, hWnd.ToString("X"));
+
+ // Check if fileName is in window title bar
+ if (IsFilenameInTitleBar(hWnd, context.filePath))
+ {
+ Log.InfoFormat("{0}() - found!", MethodBase.GetCurrentMethod().Name);
+ context.hWnd = hWnd;
+
+ // Marshall changed data back to unmanaged
+ Marshal.StructureToPtr(context, pContext, false);
+ bContinueEnumerating = false;
+ }
+ }
+
+ return bContinueEnumerating;
+ }
+
+ public static bool IsFilenameInTitleBar(IntPtr hWnd, string filePath)
+ {
+ bool bFound = false;
+ int maxTextSize = 256;
+
+ StringBuilder titleBarText = new StringBuilder(maxTextSize);
+
+ if (GetWindowText(hWnd, titleBarText, maxTextSize) > 0)
+ {
+ string fileName = Path.GetFileName(filePath);
+
+ if (fileName.Length > 0)
+ {
+ if (titleBarText.ToString().ToLower().IndexOf(fileName.ToLower()) != -1)
+ {
+ bFound = true;
+ }
+ }
+ }
+
+ return bFound;
+ }
+
+ public static bool IsTitleBar(IntPtr hWnd, string filePath)
+ {
+ bool bFound = false;
+ int maxTextSize = 256;
+
+ StringBuilder titleBarText = new StringBuilder(maxTextSize);
+
+ if (GetWindowText(hWnd, titleBarText, maxTextSize) > 0)
+ {
+ if (filePath.Length > 0)
+ {
+ if (titleBarText.ToString().ToLower().CompareTo(filePath.ToLower()) == 0)
+ {
+ bFound = true;
+ }
+ }
+ }
+
+ return bFound;
+ }
+
+ public static string GetProcessName(IntPtr hWnd)
+ {
+ int currentPid = 0;
+ Win32Functions.GetWindowThreadProcessId(hWnd, ref currentPid);
+
+ Process process;
+ try
+ {
+ process = Process.GetProcessById(currentPid);
+ }
+ catch (ArgumentException e)
+ {
+ // This is thrown when Process.GetProcessById cannot find the process
+ throw e;
+ }
+
+ return process.ProcessName;
+ }
+
+ ///
+ /// Returns the .Net Process Object that owns the passed in hWnd
+ ///
+ /// handle to a Window
+ /// a .Net Process or throws an error
+ public static Process GetProcessFromHandle(IntPtr hWnd)
+ {
+ try
+ {
+ int currentPid = 0;
+ Win32Functions.GetWindowThreadProcessId(hWnd, ref currentPid);
+
+ Process process;
+ process = Process.GetProcessById(currentPid);
+ return process;
+ }
+ catch (ArgumentException e)
+ {
+ // This is thrown when Process.GetProcessById cannot find the process
+ throw e;
+ }
+ }
+
+ ///
+ /// Attaches to instance of COM object matching progid
+ /// and returns an object. Client must cast and know
+ /// expected type.
+ ///
+ public static Object GetCOMObject(string progId)
+ {
+ Object app = null;
+ try
+ {
+ app = Marshal.GetActiveObject(progId);
+ }
+ catch (SystemException e)
+ {
+ string d = e.ToString();
+ }
+
+ return app;
+ }
+
+ public struct RunningObject
+ {
+ public string name;
+ public object o;
+ }
+
+ ///
+ /// Use this to Get All Running Objects in the ROT
+ ///
+ public static List GetRunningObjects()
+ {
+ // Get the table.
+ var res = new List();
+ IBindCtx bc;
+
+ CreateBindCtx(0, out bc);
+ IRunningObjectTable runningObjectTable;
+
+ bc.GetRunningObjectTable(out runningObjectTable);
+ IEnumMoniker monikerEnumerator;
+ runningObjectTable.EnumRunning(out monikerEnumerator);
+ monikerEnumerator.Reset();
+
+ // Enumerate and fill our nice dictionary.
+ IMoniker[] monikers = new IMoniker[1];
+ IntPtr numFetched = IntPtr.Zero;
+
+ while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
+ {
+ RunningObject running;
+ monikers[0].GetDisplayName(bc, null, out running.name);
+ runningObjectTable.GetObject(monikers[0], out running.o);
+ res.Add(running);
+ }
+ return res;
+ }
+
+ ///
+ /// Use this to Get A specific type of Object from the ROT
+ ///
+ public static List GetRunningObjectsOfType()
+ {
+ // Get the table.
+ var res = new List();
+ IBindCtx bc;
+
+ CreateBindCtx(0, out bc);
+ IRunningObjectTable runningObjectTable;
+
+ bc.GetRunningObjectTable(out runningObjectTable);
+ IEnumMoniker monikerEnumerator;
+ runningObjectTable.EnumRunning(out monikerEnumerator);
+ monikerEnumerator.Reset();
+
+ // Enumerate and fill our nice dictionary.
+ IMoniker[] monikers = new IMoniker[1];
+ IntPtr numFetched = IntPtr.Zero;
+
+ while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
+ {
+ object o;
+ runningObjectTable.GetObject(monikers[0], out o);
+
+ if (o is T)
+ {
+ res.Add((T) o);
+ }
+ o = null;
+ }
+ return res;
+ }
+
+ }
+}
diff --git a/Platform/app.config b/Platform/app.config
new file mode 100644
index 0000000..b7db281
--- /dev/null
+++ b/Platform/app.config
@@ -0,0 +1,3 @@
+
+
+
diff --git a/Satellite/GUI.Designer.cs b/Satellite/GUI.Designer.cs
new file mode 100644
index 0000000..290695e
--- /dev/null
+++ b/Satellite/GUI.Designer.cs
@@ -0,0 +1,72 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.Satellite {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class GUI {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal GUI() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Foo.Satellite.GUI", typeof(GUI).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Hello, My Name is Doris - JAJAJA.
+ ///
+ internal static string TEST_STRING {
+ get {
+ return ResourceManager.GetString("TEST_STRING", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Satellite/GUI.de.resx b/Satellite/GUI.de.resx
new file mode 100644
index 0000000..85c9090
--- /dev/null
+++ b/Satellite/GUI.de.resx
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 1.3
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Satellite/GUI.en.resx b/Satellite/GUI.en.resx
new file mode 100644
index 0000000..5117373
--- /dev/null
+++ b/Satellite/GUI.en.resx
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Artifact Wall
+ Group Header in 'Settings' for Artifact Wall
+
+
+ Workspace Selector
+ Group Header in 'Settings' for Workspace Selector
+
+
+ About Us
+ Tab Header for 'About Us' Tab
+
+
+ Help
+ Tab Header for 'Help' Tab
+
+
+ Settings
+ Tab Header for 'Settings' Tab
+
+
\ No newline at end of file
diff --git a/Satellite/GUI.resx b/Satellite/GUI.resx
new file mode 100644
index 0000000..0e0012c
--- /dev/null
+++ b/Satellite/GUI.resx
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ Hello, My Name is Doris - JAJAJA
+ What is going on?
+
+
\ No newline at end of file
diff --git a/Satellite/MyKeyFile.SNK b/Satellite/MyKeyFile.SNK
new file mode 100644
index 0000000..8bc8162
Binary files /dev/null and b/Satellite/MyKeyFile.SNK differ
diff --git a/Satellite/Properties/AssemblyInfo.cs b/Satellite/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..a6fb99a
--- /dev/null
+++ b/Satellite/Properties/AssemblyInfo.cs
@@ -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("Satellite")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Satellite")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
+[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("b241af6c-dd72-4c16-b1e1-b009c61e7641")]
+
+// 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")]
diff --git a/Satellite/Satellite.csproj b/Satellite/Satellite.csproj
new file mode 100644
index 0000000..0e396c8
--- /dev/null
+++ b/Satellite/Satellite.csproj
@@ -0,0 +1,69 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {6DC93F91-D6D4-4C35-8A83-C180E8E22E16}
+ Library
+ Properties
+ Foo.Satellite
+ Satellite
+ v3.5
+ 512
+ true
+ MyKeyFile.SNK
+
+
+ true
+ full
+ false
+ ..\Target\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\Target\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ 3.5
+
+
+
+
+
+ True
+ True
+ GUI.resx
+
+
+
+
+
+
+
+ ResXFileCodeGenerator
+ GUI.Designer.cs
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Settings/AppConfig.xml b/Settings/AppConfig.xml
new file mode 100644
index 0000000..80a6979
--- /dev/null
+++ b/Settings/AppConfig.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ IEXPLORE.EXE
+ WINWORD.EXE
+ EXCEL.EXE
+ POWERPNT.EXE
+ MSPUB.EXE
+ VISIO.EXE
+ MSACCESS.EXE
+ ACROBAT.EXE
+ NOTEPAD.EXE
+ PAINT.EXE
+ WORDPAD.EXE
+ HH.EXE
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
\ No newline at end of file
diff --git a/Settings/ButtonThemeSetting.cs b/Settings/ButtonThemeSetting.cs
new file mode 100644
index 0000000..3619852
--- /dev/null
+++ b/Settings/ButtonThemeSetting.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace Foo.Settings
+{
+
+ ///
+ /// Use this to specificy the names of each themed button
+ ///
+ [ComVisible(false)]
+ public static class ButtonNames
+ {
+ public const string BUTTON_UP = "ButtonUp.ico";
+ public const string BUTTON_DOWN = "ButtonDown.ico";
+ public const string TOGGLE_UP = "ToggleUp.ico";
+ }
+ ///
+ /// Button Location Interface for COM
+ ///
+ [Guid("CFE7FDB8-E3F0-45aa-9935-C9A8502FF7DF")]
+ [InterfaceType(ComInterfaceType.InterfaceIsDual)]
+ [ComVisible(true)]
+ public interface IButtonIconLocation
+ {
+ string GetBUTTON_UP();
+ string GetBUTTON_DOWN();
+ string GetTOGGLE_UP();
+ }
+ ///
+ /// Button Theme Settings COM
+ ///
+ [Guid("F82358CD-8521-4d03-AFF9-352491E9A10E")]
+ [InterfaceType(ComInterfaceType.InterfaceIsDual)]
+ [ComVisible(true)]
+ public interface IButtonThemeSetting
+ {
+ int Top();
+ int Right();
+ int Height();
+ int Width();
+ }
+ ///
+ /// Parent Class for all the Button Shared Code - *MAIN class for everthing basically*
+ ///
+ [ComVisible(false)]
+ public class ButtonSharedCode : IButtonThemeSetting, IButtonIconLocation
+ {
+ private string m_RelativePath = "";
+ private string m_AssemblyPath = "";
+ private int m_nTop = 0;
+ private int m_nRight = 0;
+ private int m_nHeight = 0;
+ private int m_nWidth = 0;
+
+ ///
+ /// Constructor for SharedButtonCode
+ ///
+ /// relative location (folder) inside running application directory
+ /// Theme specific Top location for Button
+ /// Theme specific Right location for Button
+ /// Theme specific Height of Button
+ /// Theme specific Width of Button
+ public ButtonSharedCode(string strRelativeLoc, int nTop, int nRight, int nHeight, int nWidth)
+ {
+ // Theme settings are stored in the Platform Path
+ //m_AssemblyPath = Platform.InstallationSpec.PlatformPath;
+ m_AssemblyPath = Platform.InstallationSpec.InstallPath;
+
+ // Debug path
+ //m_AssemblyPath = @"C:\_ROOT_\Ooganizer\Ooganizer_1.0\Target\debug\Platform";
+
+ m_RelativePath = strRelativeLoc;
+
+ m_nTop = nTop;
+ m_nRight = nRight;
+ m_nHeight = nHeight;
+ m_nWidth = nWidth;
+ }
+
+ ////
+ // IButtonThemeSetting
+ ////
+ public int Top() { return m_nTop; }
+ public int Right() { return m_nRight; }
+ public int Height() { return m_nHeight; }
+ public int Width() { return m_nWidth; }
+
+ ////
+ // IButtonLocation
+ ////
+ public string GetBUTTON_UP() { return (m_AssemblyPath + "\\" + m_RelativePath + "\\" + ButtonNames.BUTTON_UP); }
+ public string GetBUTTON_DOWN() { return (m_AssemblyPath + "\\" + m_RelativePath + "\\" + ButtonNames.BUTTON_DOWN); }
+ public string GetTOGGLE_UP() { return (m_AssemblyPath + "\\" + m_RelativePath + "\\" + ButtonNames.TOGGLE_UP); }
+ }
+ ///
+ /// Classic Button Theme Setting
+ ///
+ [ComVisible(false)]
+ public class ButtonClassicTheme : ButtonSharedCode
+ {
+ public ButtonClassicTheme() : base("Resources\\Themes\\ClassicTheme", 0, 0, 0, 0) { }
+ }
+ ///
+ /// XP Button Theme Setting
+ ///
+ [ComVisible(false)]
+ public class ButtonXPTheme : ButtonSharedCode
+ {
+ public ButtonXPTheme() : base("Resources\\Themes\\XPTheme", 1, 126, 16, 26) { }
+ }
+ ///
+ /// Aero Button Theme Setting
+ ///
+ [ComVisible(false)]
+ public class ButtonAeroTheme : ButtonSharedCode
+ {
+ //public ButtonAeroTheme() : base("Resources\\AeroTheme", 0, 129, 18, 26) { }
+ public ButtonAeroTheme() : base("Resources\\Themes\\AeroTheme", 1, 126, 16, 26) { }
+ }
+ ///
+ /// Vista No Aero Theme Setting
+ ///
+ [ComVisible(false)]
+ public class ButtonVistaNoAeroTheme : ButtonSharedCode
+ {
+ public ButtonVistaNoAeroTheme() : base("Resources\\Themes\\VistaNoAeroTheme", 0, 0, 15, 28) { }
+ }
+ ///
+ /// This class abstracts away all the settings we need for
+ /// ButtonHook to deal with themes and Buttons. (we may consider in the future
+ /// to use this class to retrieve custom settings)
+ /// ~this class is accessible via COM for the W32Button to work
+ ///
+ [Guid("9EEC54A0-77F3-4dcf-8C74-B6720437C59E")]
+ [ClassInterface(ClassInterfaceType.AutoDual)]
+ [ProgId("Ooganizer.ButtonThemeNIconSettingsCCW")]
+ [ComVisible(true)]
+ public class ButtonThemeNIconSettingsCCW
+ {
+ private object m_oButtonThemeObject = null;
+
+ public ButtonThemeNIconSettingsCCW()
+ {
+ switch (Foo.Platform.Env.Theme)
+ {
+ case Foo.Platform.Env.Themes.Classic:
+ m_oButtonThemeObject = new ButtonClassicTheme();
+ break;
+ case Foo.Platform.Env.Themes.AeroTheme:
+ m_oButtonThemeObject = new ButtonAeroTheme();
+ break;
+ case Foo.Platform.Env.Themes.VistaNoAero:
+ m_oButtonThemeObject = new ButtonVistaNoAeroTheme();
+ break;
+ case Foo.Platform.Env.Themes.XPtheme:
+ m_oButtonThemeObject = new ButtonXPTheme();
+ break;
+ }
+ }
+ public IButtonThemeSetting GetIButtonThemeInterface() { return (IButtonThemeSetting)m_oButtonThemeObject; }
+ public IButtonIconLocation GetIButtonIconLocation() { return (IButtonIconLocation)m_oButtonThemeObject; }
+ }
+}
diff --git a/Settings/MyKeyFile.SNK b/Settings/MyKeyFile.SNK
new file mode 100644
index 0000000..8bc8162
Binary files /dev/null and b/Settings/MyKeyFile.SNK differ
diff --git a/Settings/Properties/AssemblyInfo.cs b/Settings/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..ac455b6
--- /dev/null
+++ b/Settings/Properties/AssemblyInfo.cs
@@ -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("Settings")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Ooganizer")]
+[assembly: AssemblyProduct("Settings")]
+[assembly: AssemblyCopyright("Copyright © Ooganizer 2009")]
+[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("a28ce1f1-2b84-42ee-abd8-8230ae6a186c")]
+
+// 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")]
diff --git a/Settings/Properties/Resources.Designer.cs b/Settings/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..e3af3f2
--- /dev/null
+++ b/Settings/Properties/Resources.Designer.cs
@@ -0,0 +1,78 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.Platform.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Foo.Platform.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to <?xml version="1.0" encoding="utf-8"?>
+ ///<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.ooganizer.com">
+ /// <ButtonHook>
+ /// <AllowedProcessNames>
+ /// <ProcessName strategy="BrowserResolve" prms="" wcinc="*" wtxtinc="*" versions="6.*;7.*;8.*" bhloc="normal">IEXPLORE.EXE</ProcessName>
+ /// <ProcessName strategy="FHWinResolve" prms="TopOnly" wcinc="*" wtxtinc="*" versions="11.*;12.*" bhloc="normal">WINWORD.EXE</ProcessName>
+ /// <P [rest of string was truncated]";.
+ ///
+ internal static string AppConfigXML {
+ get {
+ return ResourceManager.GetString("AppConfigXML", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Settings/Properties/Resources.resx b/Settings/Properties/Resources.resx
new file mode 100644
index 0000000..7dbac60
--- /dev/null
+++ b/Settings/Properties/Resources.resx
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+ ..\AppConfig.xml;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252
+
+
\ No newline at end of file
diff --git a/Settings/Properties/Settings.Designer.cs b/Settings/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..fe8b1ba
--- /dev/null
+++ b/Settings/Properties/Settings.Designer.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4200
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Foo.Platform.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Settings/Properties/Settings.settings b/Settings/Properties/Settings.settings
new file mode 100644
index 0000000..15034e7
--- /dev/null
+++ b/Settings/Properties/Settings.settings
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/Settings/RegPathsConfig.bat b/Settings/RegPathsConfig.bat
new file mode 100644
index 0000000..02fe716
--- /dev/null
+++ b/Settings/RegPathsConfig.bat
@@ -0,0 +1,23 @@
+@rem //-- Author: Daniel Romischer (daniel@romischer.com)
+@echo off
+
+goto :start
+
+:Usage
+echo Use this File to Register Ooganizer Paths in the registry
+echo.
+echo Syntax: RegPathsConfig "[main ooganizer path]"
+echo.
+echo Example: RegPathsConfig "C:\Program Files\Ooganizer"
+echo.
+goto :Exit
+
+:start
+if (%1)==() Goto :Usage
+
+REG ADD HKLM\Software\Ooganizer /v InstallPath /d %1\ /f
+REG ADD HKLM\Software\Ooganizer /v LogPath /d %1\Platform\Logs\ /f
+REG ADD HKLM\Software\Ooganizer /v PlatformPath /d %1\Platform\ /f
+REG ADD HKLM\Software\Ooganizer /v ServerPath /d %1\Server\ /f
+
+:Exit
\ No newline at end of file
diff --git a/Settings/Settings.csproj b/Settings/Settings.csproj
new file mode 100644
index 0000000..a716858
--- /dev/null
+++ b/Settings/Settings.csproj
@@ -0,0 +1,107 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {48D75C4F-2749-48BB-9386-721E0E94C144}
+ Library
+ Properties
+ Foo.Platform
+ Settings
+ v2.0
+ 512
+
+
+
+
+
+
+
+
+ true
+ MyKeyFile.SNK
+
+
+
+
+ true
+ full
+ false
+ ..\Target\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ false
+
+
+ pdbonly
+ true
+ ..\Target\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ False
+ ..\Components\log4net.dll
+
+
+
+
+
+
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ True
+ Settings.settings
+
+
+
+
+
+
+
+
+
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+
+
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}
+ Platform
+
+
+
+
+
+ $(FrameworkDir)\regasm.exe "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /unregister
+$(FrameworkDir)\regasm.exe "$(SolutionDir)target\$(ConfigurationName)\$(TargetFileName)" /tlb:$(TargetName).tlb /codebase
+ "$(ProjectDir)RegPathsConfig.bat" "$(SolutionDir)target\$(ConfigurationName)"
+
+
\ No newline at end of file
diff --git a/Settings/SettingsAcc.cs b/Settings/SettingsAcc.cs
new file mode 100644
index 0000000..8cbbc99
--- /dev/null
+++ b/Settings/SettingsAcc.cs
@@ -0,0 +1,459 @@
+using System;
+using System.Collections;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Xml;
+using System.Xml.Serialization;
+using System.IO;
+using System.Reflection;
+using Foo.Platform;
+using System.Diagnostics;
+
+namespace Foo.Settings
+{
+ [Guid("6FBB970D-0825-471e-9839-448FB2B6A842")]
+ [InterfaceType(ComInterfaceType.InterfaceIsDual)]
+ [ComVisible(true)]
+ public interface IOoganizerSettings
+ {
+ // reading in configuration data
+ configuration ReadConfigXMLFile();
+
+ // write custom configuration data to default location
+ void WriteConfigXMLFileDefaultLoc(configuration config);
+ }
+
+ ///
+ /// Serializable Xml Object used to store all Configuration data - place any new class objects in here
+ ///
+ [Guid("EA2D77C2-AA17-4142-8FA7-7D6FA35316F4")]
+ [ClassInterface(ClassInterfaceType.AutoDual)]
+ [ComVisible(true)]
+ [XmlRoot("configuration", Namespace = "http://www.ooganizer.com", IsNullable = false)]
+ public class configuration
+ {
+ // Member Tags <>
+ public ButtonHookSettings ButtonHook = null;
+
+ ///
+ /// configuration - Constructor
+ ///
+ public configuration()
+ {
+ ButtonHook = new ButtonHookSettings();
+ }
+ }
+
+ ///
+ /// Serializable Xml Object used to store ButtonHookSettings
+ ///
+ [Guid("2C055265-715A-4d10-B744-ADCE796BED1C")]
+ [ClassInterface(ClassInterfaceType.AutoDual)]
+ [ComVisible(true)]
+ [XmlRoot("ButtonHookSettings", Namespace = "http://www.ooganizer.com", IsNullable = false)]
+ public class ButtonHookSettings
+ {
+ // Member Tags <>
+ public AllowedProcessNamesW AllowedProcessNames = null;
+ public AllowedWindowTitlesW AllowedWindowTitles = null;
+ public AllowedWindowClassesW AllowedWindowClasses = null;
+ public LoggingSettings LogSettings = null;
+
+ ///
+ /// AllowedProcessNames - (Wrapper) around ArrayList to work with COM and XML
+ ///
+ [Guid("06403D5A-E309-42d3-B639-1F9DB99880A4")]
+ [ClassInterface(ClassInterfaceType.AutoDual)]
+ [ComVisible(true)]
+ public class AllowedProcessNamesW
+ {
+ private ArrayList m_ArrayList;
+ public AllowedProcessNamesW()
+ {
+ m_ArrayList = new ArrayList();
+ }
+
+ [XmlElement("ProcessName")]
+ public ProcessName[] ProcessNames
+ {
+ get
+ {
+ ProcessName[] processNames = new ProcessName[m_ArrayList.Count];
+ m_ArrayList.CopyTo(processNames);
+ return processNames;
+ }
+ set
+ {
+ if (value == null) return;
+ ProcessName[] processNames = (ProcessName[])value;
+ m_ArrayList.Clear();
+ foreach (ProcessName processName in processNames)
+ m_ArrayList.Add(processName);
+ }
+ }
+
+ public int AddProcessName(ProcessName processName)
+ {
+ return m_ArrayList.Add(processName);
+ }
+ }
+
+ [Guid("EC4E542F-2877-4bb4-8FEF-30F1A1C1B53B")]
+ [ClassInterface(ClassInterfaceType.AutoDual)]
+ [ComVisible(true)]
+ public class ProcessName
+ {
+ public ProcessName()
+ {
+ this.CustomBHTop = 0;
+ this.CustomBHRight = 0;
+ }
+
+ public ProcessName(string ProcessExe, string Resolver, string ResolverPrms, string Launcher, string Closer, string ShowHider, string Versions, int CustomBHTop, int CustomBHRight)
+ {
+ this._ProcessExe = ProcessExe;
+ this.Resolver = Resolver;
+ this.ResolverPrms = ResolverPrms;
+ this.Launcher = Launcher;
+ this.Closer = Closer;
+ this.ShowHider = ShowHider;
+ this.Versions = Versions;
+ this.CustomBHTop = CustomBHTop;
+ this.CustomBHRight = CustomBHRight;
+ }
+
+ private string _ProcessExe;
+ [XmlText]
+ public string ProcessExe
+ {
+ get
+ {
+ if (!String.IsNullOrEmpty(_ProcessExe))
+ return _ProcessExe.ToUpper();
+ else
+ return String.Empty;
+ }
+ set
+ {
+ _ProcessExe = value;
+ }
+ }
+
+ [XmlAttribute("Resolver")]
+ public string Resolver;
+
+ [XmlAttribute("ResolverPrms")]
+ public string ResolverPrms;
+
+ [XmlAttribute("Launcher")]
+ public string Launcher;
+
+ [XmlAttribute("Closer")]
+ public string Closer;
+
+ [XmlAttribute("ShowHider")]
+ public string ShowHider;
+
+ [XmlAttribute("Versions")]
+ public string Versions;
+
+ [XmlAttribute("CustomBHTop")]
+ public int CustomBHTop;
+
+ [XmlAttribute("CustomBHRight")]
+ public int CustomBHRight;
+ }
+
+ ///
+ /// AllowedWindowTitles - (Wrapper) around ArrayList to work with COM and XML
+ ///
+ [Guid("5B9CC560-9E53-4ae2-8701-E60F99A9A80D")]
+ [ClassInterface(ClassInterfaceType.AutoDual)]
+ [ComVisible(true)]
+ public class AllowedWindowTitlesW
+ {
+ private ArrayList m_ArrayList;
+ public AllowedWindowTitlesW()
+ {
+ m_ArrayList = new ArrayList();
+ m_ArrayList.Add("");
+ }
+ [XmlElement("WindowTitle")]
+ public string[] WindowTitle
+ {
+ get
+ {
+ string[] windowTitles = new string[m_ArrayList.Count];
+ m_ArrayList.CopyTo(windowTitles);
+ return windowTitles;
+ }
+ set
+ {
+ if (value == null) return;
+ string[] windowTitles = (string[])value;
+ m_ArrayList.Clear();
+ foreach (string windowTitle in windowTitles)
+ m_ArrayList.Add(windowTitle);
+ }
+ }
+ }
+
+ ///
+ /// AllowedWindowClasses - (Wrapper) around ArrayList to work with COM and XML
+ ///
+ [Guid("FE3ECBC4-9082-43b5-8274-7DC3A4FB4855")]
+ [ClassInterface(ClassInterfaceType.AutoDual)]
+ [ComVisible(true)]
+ public class AllowedWindowClassesW
+ {
+ private ArrayList m_ArrayList;
+ public AllowedWindowClassesW()
+ {
+ m_ArrayList = new ArrayList();
+ m_ArrayList.Add("");
+ }
+
+ [XmlElement("WindowClass")]
+ public string[] WindowClass
+ {
+ get
+ {
+ string[] windowClasses = new string[m_ArrayList.Count];
+ m_ArrayList.CopyTo(windowClasses);
+ return windowClasses;
+ }
+ set
+ {
+ if (value == null) return;
+ string[] windowClasses = (string[])value;
+ m_ArrayList.Clear();
+ foreach (string windowClass in windowClasses)
+ m_ArrayList.Add(windowClass);
+ }
+ }
+ }
+
+ ///
+ /// LoggingSettings = Set Log Settings (Location & Detail) for ButtonHook
+ ///
+ [Guid("A5A6EBA5-DC51-4bba-B7DC-0202153F57DF")]
+ [ClassInterface(ClassInterfaceType.AutoDual)]
+ [ComVisible(true)]
+ public class LoggingSettings
+ {
+ public uint LoggingDetail;
+
+ private string _LogPath;
+ public string LogPath
+ {
+ get
+ {
+ if (!String.IsNullOrEmpty(_LogPath))
+ return Platform.Env.GetLogDirectory();
+ else
+ return _LogPath;
+ }
+ set
+ {
+ try
+ {
+ if (Directory.Exists(value))
+ _LogPath = value;
+ }
+ catch(Exception){}
+ }
+ }
+
+ public LoggingSettings()
+ {
+ _LogPath = String.Empty;
+ LoggingDetail = (int)_LoggingDetail.LOGGING_NONE;
+ }
+
+ // same enum Definition in ButtonHook
+ public enum _LoggingDetail { LOGGING_NONE = 0, LOGGING_LOW = 1, LOGGING_MEDIUM = 2, LOGGING_HIGH = 3};
+ }
+
+ ///
+ /// ButtonHookSettings - Constructor
+ ///
+ public ButtonHookSettings()
+ {
+ AllowedProcessNames = new AllowedProcessNamesW();
+ AllowedWindowTitles = new AllowedWindowTitlesW();
+ AllowedWindowClasses = new AllowedWindowClassesW();
+ LogSettings = new LoggingSettings();
+ }
+ }
+
+ [Guid("80adff74-7124-42e6-ac2c-e19f51a47432")]
+ [ClassInterface(ClassInterfaceType.None)]
+ [ProgId("Ooganizer.SettingsAcc")]
+ [ComVisible(true)]
+ public class OoganizerSettingsAcc : IOoganizerSettings
+ {
+ private XmlSerializer m_ConfigSerializer = null;
+ public const string DEFAULT_CONFIG_XML_FILE_NAME = "AppConfig.xml";
+ private string m_AssemblyLocation = "";// location of running assembly
+ private configuration m_Configuration; // holds the latest configuration read in or written out,
+ // for easy access to the configuration
+
+ ///
+ /// Construcs the SettingsAccessor Object, Responsible for
+ /// interfacing with the App.Config file
+ ///
+ public OoganizerSettingsAcc()
+ {
+ m_ConfigSerializer = new XmlSerializer(typeof(configuration));
+
+ if (m_ConfigSerializer == null)
+ throw new OutOfMemoryException();
+
+ // The location of this assembly is in the Platform Directory
+ m_AssemblyLocation = Platform.InstallationSpec.InstallPath;
+ }
+
+ #region IOoganizerSettings
+
+ ///
+ /// Reads in the Config File from the Resource.
+ ///
+ /// the configuration object
+ public configuration ReadConfigXMLFile()
+ {
+ string strFileNameWithPath = m_AssemblyLocation + '\\' + DEFAULT_CONFIG_XML_FILE_NAME;
+
+ // If a physical xml file exists in the current directory (allow it to overwrite our settings)
+ if (File.Exists(strFileNameWithPath + '\\' + DEFAULT_CONFIG_XML_FILE_NAME))
+ {
+ return ReadConfigXMLFile(strFileNameWithPath, false);
+ }
+ else
+ {
+ // Else force reading of the Resource
+ return ReadConfigXMLFile(strFileNameWithPath, true);
+ }
+ }
+
+ ///
+ /// Writes the specified configruation to the default location and configuration file
+ ///
+ /// configuration object to write out
+ public void WriteConfigXMLFileDefaultLoc(configuration config)
+ {
+ string strFileNameWithPath = m_AssemblyLocation + '\\' + DEFAULT_CONFIG_XML_FILE_NAME;
+ WriteConfigXMLFile(strFileNameWithPath, config);
+ }
+
+ #endregion
+
+ #region XML Writer Functions - useful for * Development and Debugging *
+
+ ///
+ /// Writes the specified configuration to the specified configuration file
+ ///
+ /// absolute path to file
+ /// configuration object to write out
+ public void WriteConfigXMLFile(string strFileNameWithPath, configuration config)
+ {
+ try
+ {
+ if (!Directory.Exists(Path.GetDirectoryName(strFileNameWithPath)))
+ {
+ Log.Error(string.Format("{0}() - Directory for {1} does not exist", MethodBase.GetCurrentMethod().Name, strFileNameWithPath));
+ return;
+ }
+
+ TextWriter writer = new StreamWriter(strFileNameWithPath);
+ m_ConfigSerializer.Serialize(writer, config);
+ m_Configuration = config;
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ return;
+ }
+ }
+
+ ///
+ /// Use this to write a blank xml config file that you can then use
+ /// to store your configuration
+ ///
+ /// absolute path to file
+ public void WriteBlankConfigXMLFile(string strFileNameWithPath)
+ {
+ try
+ {
+ if (!Directory.Exists(Path.GetDirectoryName(strFileNameWithPath)))
+ {
+ Log.Error(string.Format("{0}() - Directory for {1} does not exist", MethodBase.GetCurrentMethod().Name, strFileNameWithPath));
+ return;
+ }
+
+ TextWriter writer = new StreamWriter(strFileNameWithPath);
+ configuration settings = new configuration();
+ m_ConfigSerializer.Serialize(writer, settings);
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ return;
+ }
+ }
+
+ #endregion
+
+ #region Main ReadConfig Function - Does most of the work
+
+ ///
+ /// Reads in the config file from the passed in location or from the Resource
+ ///
+ /// absolute path to file (not used when bReadFromResource is true)
+ /// true to read Resource XML, false to read from passed in strFileNameWithPath
+ ///
+ private configuration ReadConfigXMLFile(string strFileNameWithPath, bool bReadFromResource)
+ {
+ const string SETTING_XML_RESOURCE_NAME = "Foo.Platform.AppConfig.xml";
+ try
+ {
+
+ if (bReadFromResource)
+ {
+ Assembly assembly = Assembly.GetExecutingAssembly();
+
+ // * Debugging Only * Make sure resource Name exists
+ #if DEBUG
+ string[] resourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames();
+ bool bFound = false;
+ foreach (string resourceName in resourceNames)
+ {
+ if (resourceName == SETTING_XML_RESOURCE_NAME)
+ bFound = true;
+ }
+ Debug.Assert(bFound);
+ #endif
+
+ TextReader reader = new StreamReader(assembly.GetManifestResourceStream(SETTING_XML_RESOURCE_NAME));
+ m_Configuration = (configuration)m_ConfigSerializer.Deserialize(reader);
+ return m_Configuration;
+ }
+ else
+ {
+ TextReader reader = new StreamReader(strFileNameWithPath);
+ m_Configuration = (configuration)m_ConfigSerializer.Deserialize(reader);
+ return m_Configuration;
+ }
+ }
+ catch (Exception e)
+ {
+ Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
+ throw (new Exception(e.Message));
+ }
+ }
+
+ #endregion
+
+ // Declare the Log4net Variable
+ private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);
+ }
+}
diff --git a/Settings/app.config b/Settings/app.config
new file mode 100644
index 0000000..b7db281
--- /dev/null
+++ b/Settings/app.config
@@ -0,0 +1,3 @@
+
+
+
diff --git a/WorkspaceMgr/Closers/Closer_Generic.cs b/WorkspaceMgr/Closers/Closer_Generic.cs
new file mode 100644
index 0000000..25c5a04
--- /dev/null
+++ b/WorkspaceMgr/Closers/Closer_Generic.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Foo.Platform.Win32;
+
+namespace Foo.WorkspaceMgr.Closers
+{
+ internal class Closer_Generic : IClose
+ {
+ #region IClose Members
+
+ ///
+ /// Sends a WM_QUERYENDSESSION to the Window that the Artifact Belongs To
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType IQueryClose(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ // To Do: Must get hWnd From RAT
+ IntPtr hWnd = IntPtr.Zero;
+ if (Win32Functions.SendMessage(hWnd, (int)WindowMessage.WM_QUERYENDSESSION, IntPtr.Zero, IntPtr.Zero) != 0)
+ {
+ return FuncDepBoolType.Success;
+ }
+ else
+ {
+ return FuncDepBoolType.Failed;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ ///
+ /// Sends a WM_Close to the Window that the Artifact Belongs To
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType IClose(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ // To Do: Must get hWnd From RAT
+ IntPtr hWnd = IntPtr.Zero;
+ if (Win32Functions.SendMessage(hWnd, (int)WindowMessage.WM_CLOSE, IntPtr.Zero, IntPtr.Zero) == 0)
+ {
+ return FuncDepBoolType.Success;
+ }
+ else
+ {
+ return FuncDepBoolType.Failed;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+ }
+}
diff --git a/WorkspaceMgr/Closers/Closer_IE.cs b/WorkspaceMgr/Closers/Closer_IE.cs
new file mode 100644
index 0000000..28738d0
--- /dev/null
+++ b/WorkspaceMgr/Closers/Closer_IE.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Foo.Platform.Win32;
+
+namespace Foo.WorkspaceMgr.Closers
+{
+ internal class Closer_IE : IClose
+ {
+ #region IClose Members
+
+ ///
+ ///
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType IQueryClose(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ // To Do: Must get hWnd From RAT
+ //IntPtr hWnd = IntPtr.Zero;
+ //if (Win32Functions.SendMessage(hWnd, (int)WindowMessage.WM_QUERYENDSESSION, IntPtr.Zero, IntPtr.Zero) != 0)
+ //{
+ // return FuncDepBoolType.Success;
+ //}
+ //else
+ //{
+ // return FuncDepBoolType.Failed;
+ //}
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ ///
+ /// Sends a WM_Close to the Window that the Artifact Belongs To
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType IClose(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ // To Do: Must get hWnd From RAT
+ //IntPtr hWnd = IntPtr.Zero;
+ //if (Win32Functions.SendMessage(hWnd, (int)WindowMessage.WM_CLOSE, IntPtr.Zero, IntPtr.Zero) == 0)
+ //{
+ // return FuncDepBoolType.Success;
+ //}
+ //else
+ //{
+ // return FuncDepBoolType.Failed;
+ //}
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+ }
+}
diff --git a/WorkspaceMgr/Closers/Closer_Office.cs b/WorkspaceMgr/Closers/Closer_Office.cs
new file mode 100644
index 0000000..a623af3
--- /dev/null
+++ b/WorkspaceMgr/Closers/Closer_Office.cs
@@ -0,0 +1,625 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+using System.Reflection;
+
+using Foo.Platform;
+using Foo.Platform.Win32;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+////
+// Ignore 'Ambiguity' warning message, seems like no way around those
+////
+#pragma warning disable 0467
+
+namespace Foo.WorkspaceMgr.Closers
+{
+ class Closer_Office : IClose
+ {
+
+ #region IClose Members
+
+ ///
+ /// Dispatches the QueryClose Request to the Proper Office Closer
+ ///
+ ///
+ ///
+ public FuncDepBoolType IQueryClose(string strArtifactLocation)
+ {
+ switch (Win32_WrapperFunc.GetRegisteredExeForFile(strArtifactLocation))
+ {
+ case "WINWORD.EXE":
+ return QueryClose_MSWord(strArtifactLocation);
+
+ case "EXCEL.EXE":
+ return QueryClose_MSExcel(strArtifactLocation);
+
+ case "POWERPNT.EXE":
+ return QueryClose_MSPowerPoint(strArtifactLocation);
+
+ case "MSPUB.EXE":
+ return QueryClose_MSPublisher(strArtifactLocation);
+
+ case "VISIO.EXE":
+ return QueryClose_MSVisio(strArtifactLocation);
+
+ case "MSACCESS.EXE":
+ return QueryClose_MSAccess(strArtifactLocation);
+ }
+ return FuncDepBoolType.FunctionallityNotSupported;
+ }
+
+ ///
+ /// Dispatches the Close Request to the Proper Office Closer
+ ///
+ ///
+ ///
+ public FuncDepBoolType IClose(string strArtifactLocation)
+ {
+ switch (Win32_WrapperFunc.GetRegisteredExeForFile(strArtifactLocation))
+ {
+ case "WINWORD.EXE":
+ return Close_MSWord(strArtifactLocation);
+
+ case "EXCEL.EXE":
+ return Close_MSExcel(strArtifactLocation);
+
+ case "POWERPNT.EXE":
+ return Close_MSPowerPoint(strArtifactLocation);
+
+ case "MSPUB.EXE":
+ return Close_MSPublisher(strArtifactLocation);
+
+ case "VISIO.EXE":
+ return Close_MSVisio(strArtifactLocation);
+
+ case "MSACCESS.EXE":
+ return Close_MSAccess(strArtifactLocation);
+ }
+ return FuncDepBoolType.FunctionallityNotSupported;
+ }
+
+ #endregion
+
+ #region Microsoft Word IClose Members
+
+ public const string Word_ProgId = "Word.Application";
+
+ ///
+ /// To Do : Test This - Let's us know if the user has unsaved data
+ ///
+ ///
+ ///
+ public FuncDepBoolType QueryClose_MSWord(string strArtifactLocation)
+ {
+ try
+ {
+ // Microsoft.Office.Interop.Word.Application app = null;
+ // app = Win32Functions.GetCOMObject(Word_ProgId) as Microsoft.Office.Interop.Word.Application;
+ var RunningWordDocuments = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if (doc.Saved)
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.Failed;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+
+ //**** Another Way Stored here for Later ****
+ // may be this is helpful..
+ //using ComTypes = System.Runtime.InteropServices.ComTypes;
+ //ComTypes.IPersistFile persistFile = (ComTypes.IPersistFile)document;
+ //Checks an object for changes since it was last saved to its current file.
+ //if (persistFile.IsDirty)
+ //{
+ //do your stuff
+ //}
+ return FuncDepBoolType.Failed;
+ }
+
+ ///
+ /// *** Technically ** Here we want to close the Word Document (Not Prompt the user at all)
+ /// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the
+ /// DOM, however more testing to be done here
+ ///
+ ///
+ ///
+ public FuncDepBoolType Close_MSWord(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningWordDocuments = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Found the document to close * Close it Without Prompting *
+ object saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdSaveChanges;
+ object originalFormat = Microsoft.Office.Interop.Word.WdOriginalFormat.wdOriginalDocumentFormat;
+ object routeDocument = false;
+ var app = doc.Application;
+
+ // Let's get the Window that belongs to this document
+ Microsoft.Office.Interop.Word.Window docWindow = null;
+ foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
+ {
+ if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ docWindow = window;
+ }
+ }
+
+ //Object missing = Missing.Value;
+ doc.Close(ref saveOption, ref originalFormat, ref routeDocument);
+ Marshal.FinalReleaseComObject(doc); // force clean-up
+
+ // Close the Window
+ if (docWindow != null)
+ docWindow.Close(ref saveOption, ref routeDocument);
+
+ // Close Word if this is the Last Document Instance
+ if (app.Documents.Count == 0)
+ {
+ app.Quit(ref saveOption, ref originalFormat, ref routeDocument);
+ Marshal.FinalReleaseComObject(app); // force clean-up, closes Process for sure
+ }
+
+ return FuncDepBoolType.Success;
+ }
+ }
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+
+ #region Microsoft Excel IClose Members
+
+ public const string Excel_ProgId = "Excel.Application";
+
+ ///
+ /// To Do : Test This - Let's us know if the user has unsaved data
+ ///
+ ///
+ ///
+ public FuncDepBoolType QueryClose_MSExcel(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ var RunningExcelWorkbooks = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
+ {
+ if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if(book.Saved)
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.Failed;
+ }
+ }
+ return FuncDepBoolType.ArtifactLocationUnavailable;
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ ///
+ /// *** Technically ** Here we want to close the Excel Workbook (Not Prompt the user at all)
+ /// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the
+ /// DOM, however more testing to be done here
+ ///
+ ///
+ ///
+ public FuncDepBoolType Close_MSExcel(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningExcelWorkbooks = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
+ {
+ if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // In case there is a running rogue excel process left open,
+ // we can always force it to close by closing the process
+ // int hWnd = app.Hwnd;
+ // Process process = Win32Functions.GetProcessFromHandle((IntPtr) hWnd);
+ var app = book.Application;
+
+ // Close the Workbook
+ book.Close(true, strArtifactLocation, false);
+ Marshal.FinalReleaseComObject(book); // force clean-up
+
+ // Close Excel if this is the last Workbook
+ if (app.Workbooks.Count == 0)
+ {
+ app.Quit();
+ Marshal.FinalReleaseComObject(app); // force clean-up, should clean up excel process
+ //process.Close();
+ }
+ return FuncDepBoolType.Success;
+ }
+ }
+ return FuncDepBoolType.ArtifactLocationUnavailable;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+
+ #region Microsoft PowerPoint IClose Members
+
+ public const string PowerPoint_ProgId = "PowerPoint.Application";
+
+ ///
+ /// To Do : Test This - Let's us know if the user has unsaved data
+ ///
+ ///
+ ///
+ public FuncDepBoolType QueryClose_MSPowerPoint(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ //Microsoft.Office.Interop.PowerPoint.Application app = null;
+ //app = Win32Functions.GetCOMObject(PowerPoint_ProgId) as Microsoft.Office.Interop.PowerPoint.Application;
+ //foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in app.Presentations)
+
+ var RunningPowerPoints = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints)
+ {
+ if (presentation.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ switch (presentation.Saved)
+ {
+ case Microsoft.Office.Core.MsoTriState.msoTrue:
+ return FuncDepBoolType.Success;
+
+ case Microsoft.Office.Core.MsoTriState.msoFalse:
+ return FuncDepBoolType.Failed;
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ ///
+ /// *** Technically ** Here we want to close the Word Document (Not Prompt the user at all)
+ /// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the
+ /// DOM, however more testing to be done here
+ ///
+ ///
+ ///
+ public FuncDepBoolType Close_MSPowerPoint(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ //Microsoft.Office.Interop.PowerPoint.Application app = null;
+ //app = Win32Functions.GetCOMObject(PowerPoint_ProgId) as Microsoft.Office.Interop.PowerPoint.Application;
+ //foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in app.Presentations)
+
+ var RunningPowerPoints = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints)
+ {
+ if (presentation.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ var app = presentation.Application;
+
+ // Save this Presentation
+ presentation.Save();
+
+ // Close this Presentation
+ presentation.Close();
+
+ Marshal.FinalReleaseComObject(presentation); // force clean-up
+
+ // Close PowerPoint if there are no more Presentations
+ if (app.Presentations.Count == 0)
+ {
+ app.Quit();
+ Marshal.FinalReleaseComObject(app); // force clean-up, kill application for sure
+ }
+
+ return FuncDepBoolType.Success;
+ }
+ }
+ return FuncDepBoolType.Failed;
+
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+
+ #region Microsoft Publisher IClose Members
+
+ public const string Publisher_ProgId = "Publisher.Application";
+
+ ///
+ /// To Do : Test This - Let's us know if the user has unsaved data
+ ///
+ ///
+ ///
+ public FuncDepBoolType QueryClose_MSPublisher(string strArtifactLocation)
+ {
+ var RunningPublisherApps = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps)
+ {
+ foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents)
+ {
+ if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ try
+ {
+ if (pubDoc.Saved)
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ }
+
+ break;
+ }
+ }
+ }
+ return FuncDepBoolType.Success;
+ }
+
+ ///
+ /// *** Technically ** Here we want to close the Word Document (Not Prompt the user at all)
+ /// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the
+ /// DOM, however more testing to be done here
+ ///
+ ///
+ ///
+ public FuncDepBoolType Close_MSPublisher(string strArtifactLocation)
+ {
+
+ IntPtr hWnd = IntPtr.Zero;
+ try
+ {
+ var RunningPublisherApps = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps)
+ {
+ foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents)
+ {
+ if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Save the Document
+ pubDoc.Save();
+
+ // Get the Handle
+ hWnd = (IntPtr)pubDoc.ActiveWindow.Hwnd;
+ goto FOUND_DOCUMENT_HWND;
+ }
+ }
+ }
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ }
+
+ FOUND_DOCUMENT_HWND:
+ // Get the Process
+ Process process = Win32Functions.GetProcessFromHandle(hWnd);
+
+ // Send Close Message
+ if (Win32Functions.SendMessage((IntPtr)hWnd, (int)WindowMessage.WM_CLOSE, IntPtr.Zero, IntPtr.Zero) == 0)
+ {
+ process.Kill();
+ return FuncDepBoolType.Success;
+ }
+ else
+ {
+ return FuncDepBoolType.Failed;
+ }
+ }
+
+ #endregion
+
+ #region Microsoft Visio IClose Members
+
+ public const string Visio_ProgId = "Visio.Application";
+
+ ///
+ /// To Do : Test This - Let's us know if the user has unsaved data
+ ///
+ ///
+ ///
+ public FuncDepBoolType QueryClose_MSVisio(string strArtifactLocation)
+ {
+
+ var RunningVisioDocs = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ try
+ {
+ if (doc.Saved)
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ }
+
+ break;
+ }
+ }
+
+ return FuncDepBoolType.Success;
+ }
+
+ ///
+ /// *** Technically ** Here we want to close the Word Document (Not Prompt the user at all)
+ /// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the
+ /// DOM, however more testing to be done here
+ ///
+ ///
+ ///
+ public FuncDepBoolType Close_MSVisio(string strArtifactLocation)
+ {
+
+ var RunningVisioDocs = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ try
+ {
+ doc.Save();
+
+ var app = doc.Application;
+
+ doc.Close();
+ Marshal.FinalReleaseComObject(doc); // Force Clean-up
+
+ if (app.Documents.Count == 0)
+ {
+ app.Quit();
+ Marshal.FinalReleaseComObject(app); // force clean-up
+ }
+
+
+ return FuncDepBoolType.Success;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ }
+ }
+ }
+
+ return FuncDepBoolType.Success;
+ }
+
+ #endregion
+
+ #region Microsoft Access IClose Members
+
+ public const string Access_ProgId = "Access.Application";
+
+ ///
+ /// To Do : Test This - Let's us know if the user has unsaved data
+ ///
+ ///
+ ///
+ public FuncDepBoolType QueryClose_MSAccess(string strArtifactLocation)
+ {
+
+ var RunningAccessApps = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Access.Application app in RunningAccessApps)
+ {
+ if (app.CurrentProject.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ return FuncDepBoolType.Success;
+ }
+ }
+ return FuncDepBoolType.Failed;
+ }
+
+ ///
+ /// *** Technically ** Here we want to close the Word Document (Not Prompt the user at all)
+ /// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the
+ /// DOM, however more testing to be done here
+ ///
+ ///
+ ///
+ public FuncDepBoolType Close_MSAccess(string strArtifactLocation)
+ {
+
+ var RunningAccessApps = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Access.Application app in RunningAccessApps)
+ {
+ if (app.CurrentProject.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Get Handle and Process
+ IntPtr hWnd = (IntPtr) app.hWndAccessApp();
+ Process process = Win32Functions.GetProcessFromHandle((IntPtr)hWnd);
+
+ // Close the database
+ //app.CloseCurrentDatabase();
+ app.Quit(Microsoft.Office.Interop.Access.AcQuitOption.acQuitSaveAll);
+ Marshal.FinalReleaseComObject(app); // force clean-up
+
+ // Kill the process
+ process.Kill();
+
+ return FuncDepBoolType.Success;
+ }
+ }
+ return FuncDepBoolType.Failed;
+ }
+
+ #endregion
+ }
+}
diff --git a/WorkspaceMgr/Closers/IClose.cs b/WorkspaceMgr/Closers/IClose.cs
new file mode 100644
index 0000000..d8c5eee
--- /dev/null
+++ b/WorkspaceMgr/Closers/IClose.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Foo.WorkspaceMgr.Closers
+{
+ internal interface IClose
+ {
+ FuncDepBoolType IQueryClose(string strArtifactLocation);
+ FuncDepBoolType IClose(string strArtifactLocation);
+ }
+}
diff --git a/WorkspaceMgr/Configurations.cs b/WorkspaceMgr/Configurations.cs
new file mode 100644
index 0000000..17e9823
--- /dev/null
+++ b/WorkspaceMgr/Configurations.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Foo.Platform.Utilities;
+
+namespace Foo.WorkspaceMgr
+{
+ public static class Configurations
+ {
+ #region Excel 2007 Configuration
+
+ private static string EXCEL_OPTIONS_REGISTRY_LOCATION = "Microsoft\\Office\\12.0\\Excel\\Options";
+
+ static public void Configure_Excel2007()
+ {
+ RegM reg = new RegM(HKEYRoot.CurrentUser, KeySub.Software, EXCEL_OPTIONS_REGISTRY_LOCATION, true);
+ reg.SetVal_Int("ShowWindowsInTaskbar", 1);
+ }
+
+ #endregion
+
+ static Configurations()
+ {
+ }
+
+
+
+ }
+
+}
diff --git a/WorkspaceMgr/HelperFunc.cs b/WorkspaceMgr/HelperFunc.cs
new file mode 100644
index 0000000..956b656
--- /dev/null
+++ b/WorkspaceMgr/HelperFunc.cs
@@ -0,0 +1,147 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Foo.DataAccessLayer.DataTypes;
+
+namespace Foo.WorkspaceMgr
+{
+ internal static class HelperFunc
+ {
+ internal const int DEFAULT_SHOWNHIDE_SLEEP_TIME = 250;
+ internal const int DEFAULT_CLOSE_SLEEP_TIME = 500;
+ internal const int DEFAULT_LAUNCH_SLEEP_TIME = 1000;
+
+ ///
+ /// Depending on the Quality of the Index Optimizations,
+ /// Return what the best type of action is afterward
+ ///
+ internal enum IndexOptimizationQuality
+ {
+ Good,
+ Average,
+ Poor
+ }
+
+ // Helper Class for OptimalLaunchIndexesForFileArtifacts
+ internal class OptimalIndexes
+ {
+ public int Index;
+ public string FileName;
+ internal OptimalIndexes(int Index, string FileName)
+ {
+ this.Index = Index;
+ this.FileName = FileName;
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static int GetSleepTimeForQuality(IndexOptimizationQuality quality)
+ {
+ int nSleepTime = 1350;
+ switch (quality)
+ {
+ case HelperFunc.IndexOptimizationQuality.Good:
+ nSleepTime = 1350;
+ break;
+
+ case HelperFunc.IndexOptimizationQuality.Average:
+ nSleepTime = 1675;
+ break;
+
+ case HelperFunc.IndexOptimizationQuality.Poor:
+ nSleepTime = 2000;
+ break;
+ }
+ return nSleepTime;
+ }
+
+ ///
+ /// For Launching of File Artifacts we must make sure that artifacts are in an order that allows us
+ /// to properly resolve them dynamically. When files with the same name get launched too close together,
+ /// window resolution will become increasingly difficult.
+ ///
+ /// a group of artifacts (Only file Artifacts will be processed)
+ /// an array of indexes that specifies the launch order of all the files in this group
+ internal static IndexOptimizationQuality OptimalLaunchIndexesForFileArtifacts(ArtifactItem[] artifactItems, out int[] optimalIndexes)
+ {
+
+ // Step One - If it is a file type, then we get the file name and it's index to put into a list
+ List optIndex = new List();
+ for (int i = 0; i < artifactItems.Length; ++i)
+ {
+ if(artifactItems[i].IsFile)
+ optIndex.Add(new OptimalIndexes(i, artifactItems[i].FileName));
+ }
+
+ // Step Two - Sort the List by FileName
+ optIndex.Sort(delegate(OptimalIndexes o1, OptimalIndexes o2) { return o1.FileName.CompareTo(o2.FileName); });
+
+ // Step Three - Go thru sorted list and get out all the Singles
+ List singlesList = new List();
+ for (int i = 0; i < optIndex.Count; ++i)
+ {
+ bool bIsSingle = true;
+ bool bCompareUp = ((i > 0) && (i < optIndex.Count));
+ bool bCompareDown = (i < (optIndex.Count - 1));
+
+ if (bIsSingle && bCompareUp)
+ bIsSingle = (String.Compare(optIndex[i].FileName, optIndex[i - 1].FileName, true) != 0);
+
+ if (bIsSingle && bCompareDown)
+ bIsSingle = (String.Compare(optIndex[i].FileName, optIndex[i + 1].FileName, true) != 0);
+
+ // If Single - Add To Singles List
+ if (bIsSingle)
+ singlesList.Add(i);
+ }
+
+ // If all items in the List were singles then we are really good to go
+ // and can exit out of here
+ if (singlesList.Count == optIndex.Count)
+ {
+ // Pass out the Indexes of the Array To The Caller
+ optimalIndexes = new int[optIndex.Count];
+ for (int i = 0; i < optIndex.Count; ++i)
+ optimalIndexes[i] = optIndex[i].Index;
+
+ // Since there are no doubles - this is a low risk / high quality optimization
+ return IndexOptimizationQuality.Good;
+ }
+
+ // Step Four - There are doubles and/or no singles
+ // ~remove all singles from optIndex
+ foreach (int index in singlesList)
+ {
+
+ }
+
+
+
+
+
+ // 2) we make a list of all filenames in sorted order (with an index to which artifact it belongs)
+
+
+ // 3) we then generate the most optimal list of indexes that we pass out for the caller to use
+
+ foreach (ArtifactItem artifact in artifactItems)
+ {
+
+
+ }
+
+ optimalIndexes = new int[1];
+
+ return IndexOptimizationQuality.Average;
+ }
+
+
+
+ }
+}
diff --git a/WorkspaceMgr/IWorkspaceMgr.cs b/WorkspaceMgr/IWorkspaceMgr.cs
new file mode 100644
index 0000000..22cdf35
--- /dev/null
+++ b/WorkspaceMgr/IWorkspaceMgr.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Foo.DataAccessLayer;
+using Foo.DataAccessLayer.DataTypes;
+
+namespace Foo.WorkspaceMgr
+{
+ public interface IWorkspaceMgr
+ {
+ // Artifact Related
+ bool LaunchArtifact(ArtifactItem artifactItem);
+ bool CloseArtifact(ArtifactItem artifactItem);
+ bool HideShowArtifact(ArtifactItem artifactItem, bool bShow);
+
+ // Workspace Related
+ bool LaunchWorkspace(string WorkspaceName);
+ bool CloseWorkspace(string WorkspaceName);
+ bool HideShowWorkspace(string WorkspaceName, bool bShow);
+ }
+}
diff --git a/WorkspaceMgr/Launchers/ILaunch.cs b/WorkspaceMgr/Launchers/ILaunch.cs
new file mode 100644
index 0000000..70b1b91
--- /dev/null
+++ b/WorkspaceMgr/Launchers/ILaunch.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Foo.WorkspaceMgr.Launchers
+{
+ internal interface ILaunch
+ {
+ FuncDepBoolType IQueryLaunch(string strArtifactLocation);
+ FuncDepBoolType ILaunch(string strArtifactLocation);
+ }
+}
diff --git a/WorkspaceMgr/Launchers/Launcher_Excel.cs b/WorkspaceMgr/Launchers/Launcher_Excel.cs
new file mode 100644
index 0000000..3d52e87
--- /dev/null
+++ b/WorkspaceMgr/Launchers/Launcher_Excel.cs
@@ -0,0 +1,155 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+using Foo.Platform.Win32;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+using System.Reflection;
+
+namespace Foo.WorkspaceMgr.Launchers
+{
+ internal class Launcher_Excel : ILaunch
+ {
+ #region ILaunch Members
+
+ ///
+ /// Checks to see if the file exists in the system i.e. can be reached over
+ /// the network. if FileExists fails, we shouldn't be able to launch it.
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType IQueryLaunch(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation) && (strArtifactLocation.Length > 3))
+ {
+ if (File.Exists(strArtifactLocation))
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.ArtifactLocationUnavailable;
+ }
+ else
+ {
+ return FuncDepBoolType.ParametersInvalid;
+ }
+ }
+
+ public const string Excel_ProgId = "Excel.Application";
+
+ ///
+ /// Generic Launcher should be able to handle any file type. Launched the .Net Way.
+ /// ~this is the same as if the User clicks on the file.
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType ILaunch(string strArtifactLocation)
+ {
+ Microsoft.Office.Interop.Excel.Application app = null;
+ app = new Microsoft.Office.Interop.Excel.Application();
+
+ // Mark the Application as visible
+ app.Visible = true;
+
+ app.Workbooks.Open(strArtifactLocation, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
+ Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
+ Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value );
+
+ // Keep Track of all our Excel Instances
+ ///WorkspaceState.Launched_ExcelInstances.Add(app);
+
+ return FuncDepBoolType.Success;
+
+ //if (!String.IsNullOrEmpty(strArtifactLocation) && (strArtifactLocation.Length > 3))
+ //{
+ // Process.Start(strArtifactLocation);
+ //}
+ //return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+
+
+
+
+
+
+ /////
+ ///// To Do : Test This - Let's us know if the user has unsaved data
+ /////
+ /////
+ /////
+ //public FuncDepBoolType QueryClose_MSExcel(string strArtifactLocation)
+ //{
+ // try
+ // {
+
+
+ // foreach (Microsoft.Office.Interop.Excel.Workbook book in app.Workbooks)
+ // {
+ // if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ // {
+ // if (book.Saved)
+ // return FuncDepBoolType.Success;
+ // else
+ // return FuncDepBoolType.Failed;
+ // }
+ // }
+ // }
+ // catch (Exception e)
+ // {
+ // string message = e.Message;
+ // message = message + "";
+ // // TODO: Log Something here
+ // return FuncDepBoolType.ErrorThrown;
+ // }
+
+ // return FuncDepBoolType.Failed;
+ //}
+
+ /////
+ ///// *** Technically ** Here we want to close the Excel Workbook (Not Prompt the user at all)
+ ///// **** we could close it with a WM_CLOSE or WM_SCLOSE or with the DOM. ~for now it's the
+ ///// DOM, however more testing to be done here
+ /////
+ /////
+ /////
+ //public FuncDepBoolType Close_MSExcel(string strArtifactLocation)
+ //{
+ // try
+ // {
+ // Microsoft.Office.Interop.Excel.Application app = null;
+ // app = Win32Functions.GetCOMObject(Excel_ProgId) as Microsoft.Office.Interop.Excel.Application;
+
+ // // For Debugging
+ // //int nCount = app.Workbooks.Count;
+
+ // foreach (Microsoft.Office.Interop.Excel.Workbook book in app.Workbooks)
+ // {
+ // if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ // {
+ // book.Close(true, strArtifactLocation, false);
+
+ // // Close Excel if this is the last Workbook
+ // if (app.Workbooks.Count == 0)
+ // app.Quit();
+
+ // return FuncDepBoolType.Success;
+ // }
+ // }
+ // }
+ // catch (Exception e)
+ // {
+ // string message = e.Message;
+ // message = message + "";
+ // // TODO: Log Something here
+ // return FuncDepBoolType.ErrorThrown;
+ // }
+
+ // return FuncDepBoolType.Failed;
+ //}
+
+
+ }
+}
diff --git a/WorkspaceMgr/Launchers/Launcher_Generic.cs b/WorkspaceMgr/Launchers/Launcher_Generic.cs
new file mode 100644
index 0000000..ed8d92f
--- /dev/null
+++ b/WorkspaceMgr/Launchers/Launcher_Generic.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+using Foo.Platform.Win32;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+
+namespace Foo.WorkspaceMgr.Launchers
+{
+ internal class Launcher_Generic : ILaunch
+ {
+ #region ILaunch Members
+
+ ///
+ /// Checks to see if the file exists in the system i.e. can be reached over
+ /// the network. if FileExists fails, we shouldn't be able to launch it.
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType IQueryLaunch(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation) && (strArtifactLocation.Length > 3))
+ {
+ if (File.Exists(strArtifactLocation))
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.ArtifactLocationUnavailable;
+ }
+ else
+ {
+ return FuncDepBoolType.ParametersInvalid;
+ }
+ }
+
+ ///
+ /// Generic Launcher should be able to handle any file type. Launched the .Net Way.
+ /// ~this is the same as if the User clicks on the file.
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType ILaunch(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation) && (strArtifactLocation.Length > 3))
+ {
+ Process.Start(strArtifactLocation);
+ return FuncDepBoolType.Success;
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+ }
+}
diff --git a/WorkspaceMgr/Launchers/Launcher_Shell.cs b/WorkspaceMgr/Launchers/Launcher_Shell.cs
new file mode 100644
index 0000000..9807d24
--- /dev/null
+++ b/WorkspaceMgr/Launchers/Launcher_Shell.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+using Foo.Platform.Win32;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+
+namespace Foo.WorkspaceMgr.Launchers
+{
+ internal class Launcher_Shell : ILaunch
+ {
+ #region ILaunch Members
+
+ ///
+ /// Checks to see if the file exists in the system i.e. can be reached over
+ /// the network. if FileExists fails, we shouldn't be able to launch it.
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType IQueryLaunch(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation) && (strArtifactLocation.Length > 3))
+ {
+ if (File.Exists(strArtifactLocation))
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.ArtifactLocationUnavailable;
+ }
+ else
+ {
+ return FuncDepBoolType.ParametersInvalid;
+ }
+ }
+
+ ///
+ /// Generic Launcher should be able to handle any file type using Shell Execute
+ /// ~This is NOT the same as Process.start(). When using ShellExecute, Excel workbooks
+ /// launch in a different window (and for some reason Don't SHOW UP in the Excel DOM)
+ /// ~this is why this is broken out (more testing is needed)
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType ILaunch(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation) && (strArtifactLocation.Length > 3))
+ {
+ // Shellexecute works almost just like process.start except for the limitation
+ // mentioned:
+ // We could do process start but doing so means all excel docs open in the same
+ // excel window (just like powerpoint does) ~this may or may not be desirable
+ // ~excel docs won't show in the DOM, after being launched this way ~ - very odd
+ bool bIsValidExe = false;
+ string strExeOrDllPath = string.Empty;
+ bool bFound = Win32_WrapperFunc.FindExeOrDll(strArtifactLocation, out strExeOrDllPath, out bIsValidExe);
+
+ const int SEE_MASK_NOCLOSEPROCESS = 0x40;
+ ShellExecuteInfo sei = new ShellExecuteInfo();
+ sei.cbSize = Marshal.SizeOf(sei);
+ sei.lpVerb = "open";
+ sei.lpParameters = '\"' + strArtifactLocation + '\"';
+ sei.nShow = (int)WindowAction.SW_SHOWNORMAL;
+ sei.fMask = SEE_MASK_NOCLOSEPROCESS;
+
+ // Use Shell32 or Explorer to launch the artifact
+ if (bFound && bIsValidExe)
+ sei.lpFile = strExeOrDllPath;
+ else
+ sei.lpFile = '\"' + Win32_WrapperFunc.GetWindowsPath() + "\\explorer.exe" + '\"';
+
+ if (Win32Functions.ShellExecuteEx(ref sei))
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.Failed;
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+ }
+}
diff --git a/WorkspaceMgr/Launchers/Launcher_Visio.cs b/WorkspaceMgr/Launchers/Launcher_Visio.cs
new file mode 100644
index 0000000..5aa7c57
--- /dev/null
+++ b/WorkspaceMgr/Launchers/Launcher_Visio.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+using Foo.Platform.Win32;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
+using System.Reflection;
+
+namespace Foo.WorkspaceMgr.Launchers
+{
+ internal class Launcher_Visio : ILaunch
+ {
+ #region ILaunch Members
+
+ ///
+ /// Checks to see if the file exists in the system i.e. can be reached over
+ /// the network. if FileExists fails, we shouldn't be able to launch it.
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType IQueryLaunch(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation) && (strArtifactLocation.Length > 3))
+ {
+ if (File.Exists(strArtifactLocation))
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.ArtifactLocationUnavailable;
+ }
+ else
+ {
+ return FuncDepBoolType.ParametersInvalid;
+ }
+ }
+
+ public const string Excel_ProgId = "Visio.Application";
+
+ ///
+ /// Generic Launcher should be able to handle any file type. Launched the .Net Way.
+ /// ~this is the same as if the User clicks on the file.
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType ILaunch(string strArtifactLocation)
+ {
+ Microsoft.Office.Interop.Visio.Application app = null;
+ app = new Microsoft.Office.Interop.Visio.Application();
+
+ // Mark the Application as visible
+ app.Visible = true;
+
+ app.Documents.Open(strArtifactLocation);
+
+ // Keep Track of all our Excel Instances
+ ///WorkspaceState.Launched_ExcelInstances.Add(app);
+
+ return FuncDepBoolType.Success;
+
+ //if (!String.IsNullOrEmpty(strArtifactLocation) && (strArtifactLocation.Length > 3))
+ //{
+ // Process.Start(strArtifactLocation);
+ //}
+ //return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+
+ }
+}
diff --git a/WorkspaceMgr/Launchers/Launcher_Web.cs b/WorkspaceMgr/Launchers/Launcher_Web.cs
new file mode 100644
index 0000000..6099b19
--- /dev/null
+++ b/WorkspaceMgr/Launchers/Launcher_Web.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Diagnostics;
+
+namespace Foo.WorkspaceMgr.Launchers
+{
+ class Launcher_Web : ILaunch
+ {
+ #region ILaunch Members
+
+ ///
+ /// Checks to see if the url is valid
+ /// ~~( We could even check if the webpage is available here!!!) ~to do later?
+ ///
+ /// url to launch
+ ///
+ public FuncDepBoolType IQueryLaunch(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation) && (strArtifactLocation.Length > 3))
+ {
+ if (Uri.IsWellFormedUriString(strArtifactLocation, UriKind.Absolute))
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.Failed;
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ ///
+ /// Generic Launcher should be able to handle any url type
+ ///
+ /// url to launch
+ public FuncDepBoolType ILaunch(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation) && (strArtifactLocation.Length > 3))
+ {
+ Process.Start(strArtifactLocation);
+ return FuncDepBoolType.Success;
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+ }
+}
diff --git a/WorkspaceMgr/MyKeyFile.SNK b/WorkspaceMgr/MyKeyFile.SNK
new file mode 100644
index 0000000..8bc8162
Binary files /dev/null and b/WorkspaceMgr/MyKeyFile.SNK differ
diff --git a/WorkspaceMgr/Properties/AssemblyInfo.cs b/WorkspaceMgr/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..654523c
--- /dev/null
+++ b/WorkspaceMgr/Properties/AssemblyInfo.cs
@@ -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("WorkspaceMgr")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("WorkspaceMgr")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
+[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("5f6d39ae-f75e-447b-b3c0-e1abb34b4fc8")]
+
+// 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")]
diff --git a/WorkspaceMgr/ShowNHide/IShowNHide.cs b/WorkspaceMgr/ShowNHide/IShowNHide.cs
new file mode 100644
index 0000000..fbee3e5
--- /dev/null
+++ b/WorkspaceMgr/ShowNHide/IShowNHide.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Foo.WorkspaceMgr.Hiders
+{
+ internal interface IShowNHide
+ {
+ FuncDepBoolType IQueryShow(string strArtifactLocation);
+ FuncDepBoolType IShow(string strArtifactLocation);
+
+ FuncDepBoolType IQueryHide(string strArtifactLocation);
+ FuncDepBoolType IHide(string strArtifactLocation);
+ }
+}
diff --git a/WorkspaceMgr/ShowNHide/ShowNHide_Generic.cs b/WorkspaceMgr/ShowNHide/ShowNHide_Generic.cs
new file mode 100644
index 0000000..174ebf6
--- /dev/null
+++ b/WorkspaceMgr/ShowNHide/ShowNHide_Generic.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Foo.Platform.Win32;
+
+namespace Foo.WorkspaceMgr.Hiders
+{
+ internal class ShowNHide_Generic : IShowNHide
+ {
+
+ #region IShowNHide Members
+
+ ///
+ /// Default behavior is to just return success ** Should Check if Window is hidden?/shown???
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType IQueryShow(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ return FuncDepBoolType.Success;
+
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ ///
+ /// Calls ShowWindow to Show the Window
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType IShow(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ IntPtr hWnd = IntPtr.Zero; // ToDo : Implement RAT
+ Win32Functions.ShowWindow(hWnd, (int)WindowAction.SW_SHOW);
+ return FuncDepBoolType.Success;
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ ///
+ /// Default behavior is to just return success ** Should Check if Window is hidden?/shown???
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType IQueryHide(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ return FuncDepBoolType.Success;
+
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ ///
+ /// Calls ShowWindow to Hide the Window
+ ///
+ /// location of the path + file to launch
+ ///
+ public FuncDepBoolType IHide(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ IntPtr hWnd = IntPtr.Zero; // ToDo : Implement RAT
+ Win32Functions.ShowWindow(hWnd, (int)WindowAction.SW_HIDE);
+ return FuncDepBoolType.Success;
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+ }
+}
diff --git a/WorkspaceMgr/ShowNHide/ShowNHide_Office.cs b/WorkspaceMgr/ShowNHide/ShowNHide_Office.cs
new file mode 100644
index 0000000..d1234d7
--- /dev/null
+++ b/WorkspaceMgr/ShowNHide/ShowNHide_Office.cs
@@ -0,0 +1,847 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Foo.Platform.Win32;
+using System.Runtime.InteropServices;
+
+namespace Foo.WorkspaceMgr.Hiders
+{
+ internal class ShowNHide_Office : IShowNHide
+ {
+ #region IShowNHide Members
+
+ public FuncDepBoolType IQueryShow(string strArtifactLocation)
+ {
+ switch (Win32_WrapperFunc.GetRegisteredExeForFile(strArtifactLocation))
+ {
+ case "WINWORD.EXE":
+ return QueryShow_MSWord(strArtifactLocation);
+
+ case "EXCEL.EXE":
+ return QueryShow_MSExcel(strArtifactLocation);
+
+ case "POWERPNT.EXE":
+ return QueryShow_MSPowerPoint(strArtifactLocation);
+
+ case "MSPUB.EXE":
+ return QueryShow_MSPublisher(strArtifactLocation);
+
+ case "VISIO.EXE":
+ return QueryShow_MSVisio(strArtifactLocation);
+
+ //case "ACCESS.EXE":
+ // return QueryClose_MSAccess(strArtifactLocation);
+ }
+ return FuncDepBoolType.FunctionallityNotSupported;
+ }
+
+ public FuncDepBoolType IShow(string strArtifactLocation)
+ {
+ switch (Win32_WrapperFunc.GetRegisteredExeForFile(strArtifactLocation))
+ {
+ case "WINWORD.EXE":
+ return Show_MSWord(strArtifactLocation);
+
+ case "EXCEL.EXE":
+ return Show_MSExcel(strArtifactLocation);
+
+ case "POWERPNT.EXE":
+ return Show_MSPowerPoint(strArtifactLocation);
+
+ case "MSPUB.EXE":
+ return Show_MSPublisher(strArtifactLocation);
+
+ case "VISIO.EXE":
+ return Show_MSVisio(strArtifactLocation);
+
+ //case "ACCESS.EXE":
+ // return QueryClose_MSAccess(strArtifactLocation);
+ }
+ return FuncDepBoolType.FunctionallityNotSupported;
+ }
+
+ public FuncDepBoolType IQueryHide(string strArtifactLocation)
+ {
+ switch (Win32_WrapperFunc.GetRegisteredExeForFile(strArtifactLocation))
+ {
+ case "WINWORD.EXE":
+ return QueryHide_MSWord(strArtifactLocation);
+
+ case "EXCEL.EXE":
+ return QueryHide_MSExcel(strArtifactLocation);
+
+ case "POWERPNT.EXE":
+ return QueryHide_MSPowerPoint(strArtifactLocation);
+
+ case "MSPUB.EXE":
+ return QueryHide_MSPublisher(strArtifactLocation);
+
+ case "VISIO.EXE":
+ return QueryHide_MSVisio(strArtifactLocation);
+
+ //case "ACCESS.EXE":
+ // return QueryClose_MSAccess(strArtifactLocation);
+ }
+ return FuncDepBoolType.FunctionallityNotSupported;
+ }
+
+ public FuncDepBoolType IHide(string strArtifactLocation)
+ {
+ switch (Win32_WrapperFunc.GetRegisteredExeForFile(strArtifactLocation))
+ {
+ case "WINWORD.EXE":
+ return Hide_MSWord(strArtifactLocation);
+
+ case "EXCEL.EXE":
+ return Hide_MSExcel(strArtifactLocation);
+
+ case "POWERPNT.EXE":
+ return Hide_MSPowerPoint(strArtifactLocation);
+
+ case "MSPUB.EXE":
+ return Hide_MSPublisher(strArtifactLocation);
+
+ case "VISIO.EXE":
+ return Hide_MSVisio(strArtifactLocation);
+
+ //case "ACCESS.EXE":
+ // return QueryClose_MSAccess(strArtifactLocation);
+ }
+ return FuncDepBoolType.FunctionallityNotSupported;
+ }
+
+ #endregion
+
+ #region Microsoft Word IShowNHide Members
+
+ FuncDepBoolType QueryShow_MSWord(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningWordDocuments = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
+ {
+ foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
+ {
+ if(window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if(!window.Visible)
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.Failed;
+ }
+ }
+ }
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType Show_MSWord(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningWordDocuments = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
+ {
+ foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
+ {
+ if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if (!window.Visible)
+ {
+ window.Visible = true;
+ return FuncDepBoolType.Success;
+ }
+ else
+ {
+ return FuncDepBoolType.Failed;
+ }
+ }
+ }
+ }
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType QueryHide_MSWord(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningWordDocuments = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
+ {
+ foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
+ {
+ if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if (window.Visible)
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.Failed;
+ }
+ }
+ }
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType Hide_MSWord(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningWordDocuments = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
+ {
+ foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
+ {
+ if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ if (window.Visible)
+ {
+ window.Visible = false;
+ return FuncDepBoolType.Success;
+ }
+ else
+ {
+ return FuncDepBoolType.Failed;
+ }
+ }
+ }
+ }
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+
+ #region Microsoft Excel IShowNHide Members
+
+ FuncDepBoolType QueryShow_MSExcel(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningExcelWorkbooks = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
+ {
+ if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ var app = book.Application;
+
+ bool bIsTheOnlyDocumentInApp = (app.Workbooks.Count == 1);
+ if (!app.Visible && bIsTheOnlyDocumentInApp)
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.Failed;
+ }
+ }
+ return FuncDepBoolType.ArtifactLocationUnavailable;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType Show_MSExcel(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningExcelWorkbooks = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
+ {
+ if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ var app = book.Application;
+
+ bool bIsTheOnlyDocumentInApp = (app.Workbooks.Count == 1);
+ if (!app.Visible && bIsTheOnlyDocumentInApp)
+ {
+ app.Visible = true;
+ return FuncDepBoolType.Success;
+ }
+ else
+ return FuncDepBoolType.Failed;
+ }
+ }
+ return FuncDepBoolType.ArtifactLocationUnavailable;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType QueryHide_MSExcel(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningExcelWorkbooks = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
+ {
+ if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ var app = book.Application;
+
+ bool bIsTheOnlyDocumentInApp = (app.Workbooks.Count == 1);
+ if (app.Visible && bIsTheOnlyDocumentInApp)
+ {
+ return FuncDepBoolType.Success;
+ }
+ else
+ return FuncDepBoolType.Failed;
+ }
+ }
+ return FuncDepBoolType.ArtifactLocationUnavailable;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType Hide_MSExcel(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningExcelWorkbooks = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
+ {
+ if (book.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ var app = book.Application;
+
+ bool bIsTheOnlyDocumentInApp = (app.Workbooks.Count == 1);
+
+ // We could potentially not hide the window but instead just minimize the selected workbook
+ // ~have to learn
+ //if (!bIsTheOnlyDocumentInApp)
+ //{
+ // foreach (Microsoft.Office.Interop.Excel.Window window in book.Windows)
+ // {
+ // window.WindowState = Microsoft.Office.Interop.Excel.XlWindowState.xlMinimized;
+ // }
+ //}
+
+ if (app.Visible && bIsTheOnlyDocumentInApp)
+ {
+ app.Visible = false;
+ return FuncDepBoolType.Success;
+ }
+ else
+ return FuncDepBoolType.Failed;
+ }
+ }
+ return FuncDepBoolType.ArtifactLocationUnavailable;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+
+ #region Microsoft PowerPoint IShowNHide Members
+
+ FuncDepBoolType QueryShow_MSPowerPoint(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningPowerPoints = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints)
+ {
+ if (presentation.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ switch (presentation.Application.Visible)
+ {
+ case Microsoft.Office.Core.MsoTriState.msoTrue:
+ return FuncDepBoolType.Failed;
+
+ case Microsoft.Office.Core.MsoTriState.msoFalse:
+ return FuncDepBoolType.Success;
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType Show_MSPowerPoint(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningPowerPoints = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints)
+ {
+ if (presentation.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ switch (presentation.Application.Visible)
+ {
+ case Microsoft.Office.Core.MsoTriState.msoTrue:
+ return FuncDepBoolType.Failed;
+
+ case Microsoft.Office.Core.MsoTriState.msoFalse:
+ {
+ //presentation.Application.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
+
+ Win32Functions.ShowWindow((IntPtr)presentation.Application.HWND, (int)WindowAction.SW_SHOW);
+
+ return FuncDepBoolType.Success;
+ }
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType QueryHide_MSPowerPoint(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningPowerPoints = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints)
+ {
+ if (presentation.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ switch (presentation.Application.Visible)
+ {
+ case Microsoft.Office.Core.MsoTriState.msoTrue:
+ return FuncDepBoolType.Success;
+
+ case Microsoft.Office.Core.MsoTriState.msoFalse:
+ return FuncDepBoolType.Failed;
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType Hide_MSPowerPoint(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ try
+ {
+ var RunningPowerPoints = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.PowerPoint.Presentation presentation in RunningPowerPoints)
+ {
+ if (presentation.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ switch (presentation.Application.Visible)
+ {
+ case Microsoft.Office.Core.MsoTriState.msoTrue:
+ {
+ //presentation.Application.Visible = Microsoft.Office.Core.MsoTriState.msoFalse;
+ //foreach (Microsoft.Office.Interop.PowerPoint.DocumentWindow docWindow in presentation.Windows)
+ //{
+ // //docWindow.
+ //}
+
+ Win32Functions.ShowWindow((IntPtr) presentation.Application.HWND, (int)WindowAction.SW_HIDE);
+ return FuncDepBoolType.Success;
+ }
+
+ case Microsoft.Office.Core.MsoTriState.msoFalse:
+ {
+ return FuncDepBoolType.Failed;
+ }
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ return FuncDepBoolType.ErrorThrown;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+
+ #region Microsoft Publisher IShowNHide Members
+
+ FuncDepBoolType QueryShow_MSPublisher(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ IntPtr hWnd = IntPtr.Zero;
+ try
+ {
+ var RunningPublisherApps = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps)
+ {
+ foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents)
+ {
+ if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Get the Handle
+ hWnd = (IntPtr)pubDoc.ActiveWindow.Hwnd;
+ goto FOUND_DOCUMENT_HWND;
+ }
+ }
+ }
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ }
+
+ FOUND_DOCUMENT_HWND:
+ return FuncDepBoolType.Success; // Check Window State... - TO DO Later
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType Show_MSPublisher(string strArtifactLocation)
+ {
+ IntPtr hWnd = IntPtr.Zero;
+ try
+ {
+ var RunningPublisherApps = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps)
+ {
+ foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents)
+ {
+ if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Save the Document
+ pubDoc.Save();
+
+ // Get the Handle
+ hWnd = (IntPtr)pubDoc.ActiveWindow.Hwnd;
+ goto FOUND_DOCUMENT_HWND;
+ }
+ }
+ }
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ }
+
+ FOUND_DOCUMENT_HWND:
+
+ // Send Show Message
+ Win32Functions.ShowWindow(hWnd, (int)WindowAction.SW_SHOW);
+ return FuncDepBoolType.Success;
+ }
+
+ FuncDepBoolType QueryHide_MSPublisher(string strArtifactLocation)
+ {
+ if (!String.IsNullOrEmpty(strArtifactLocation))
+ {
+ IntPtr hWnd = IntPtr.Zero;
+ try
+ {
+ var RunningPublisherApps = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps)
+ {
+ foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents)
+ {
+ if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Get the Handle
+ hWnd = (IntPtr)pubDoc.ActiveWindow.Hwnd;
+ goto FOUND_DOCUMENT_HWND;
+ }
+ }
+ }
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ }
+
+ FOUND_DOCUMENT_HWND:
+ return FuncDepBoolType.Success; // Check Window State... - TO DO Later
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType Hide_MSPublisher(string strArtifactLocation)
+ {
+ IntPtr hWnd = IntPtr.Zero;
+ try
+ {
+ var RunningPublisherApps = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Publisher.Application app in RunningPublisherApps)
+ {
+ foreach (Microsoft.Office.Interop.Publisher.Document pubDoc in app.Documents)
+ {
+ if (pubDoc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ // Save the Document
+ pubDoc.Save();
+
+ // Get the Handle
+ hWnd = (IntPtr)pubDoc.ActiveWindow.Hwnd;
+ goto FOUND_DOCUMENT_HWND;
+ }
+ }
+ }
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ }
+
+ FOUND_DOCUMENT_HWND:
+
+ // Send Show Message
+ Win32Functions.ShowWindow(hWnd, (int)WindowAction.SW_HIDE);
+ return FuncDepBoolType.Success;
+ }
+
+ #endregion
+
+ #region Microsoft Visio IShowNHide Members
+
+ FuncDepBoolType QueryShow_MSVisio(string strArtifactLocation)
+ {
+ var RunningVisioDocs = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ try
+ {
+ bool bIsTheOnlyDocumentInApp = true; // TO DO: (doc.Application.Documents.Count == 1); not working
+ if (!doc.Application.Visible && bIsTheOnlyDocumentInApp)
+ return FuncDepBoolType.Success;
+ else
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ }
+
+ break;
+ }
+ }
+
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType Show_MSVisio(string strArtifactLocation)
+ {
+ var RunningVisioDocs = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ try
+ {
+ bool bIsTheOnlyDocumentInApp = true; // TO DO - (doc.Application.Documents.Count == 1); not working
+ if (!doc.Application.Visible && bIsTheOnlyDocumentInApp)
+ {
+ doc.Application.Visible = true;
+ return FuncDepBoolType.Success;
+ }
+ else
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ }
+
+ break;
+ }
+ }
+
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType QueryHide_MSVisio(string strArtifactLocation)
+ {
+ var RunningVisioDocs = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ try
+ {
+ bool bIsTheOnlyDocumentInApp = true; // (doc.Application.Documents.Count == 1); // TO DO - not working
+ if (doc.Application.Visible && bIsTheOnlyDocumentInApp)
+ {
+ return FuncDepBoolType.Success;
+ }
+ else
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ }
+
+ break;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ FuncDepBoolType Hide_MSVisio(string strArtifactLocation)
+ {
+ var RunningVisioDocs = Win32Functions.GetRunningObjectsOfType();
+ foreach (Microsoft.Office.Interop.Visio.Document doc in RunningVisioDocs)
+ {
+ if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
+ {
+ try
+ {
+ bool bIsTheOnlyDocumentInApp = true; // (doc.Application.Documents.Count == 1); // TO DO - not working
+ if (doc.Application.Visible && bIsTheOnlyDocumentInApp)
+ {
+ doc.Application.Visible = false;
+ return FuncDepBoolType.Success;
+ }
+ else
+ return FuncDepBoolType.Failed;
+ }
+ catch (Exception e)
+ {
+ string message = e.Message;
+ message = message + "";
+ // TODO: Log Something here
+ }
+
+ break;
+ }
+ }
+ return FuncDepBoolType.ParametersInvalid;
+ }
+
+ #endregion
+
+
+ }
+}
diff --git a/WorkspaceMgr/WorkspaceMgr.cs b/WorkspaceMgr/WorkspaceMgr.cs
new file mode 100644
index 0000000..6917725
--- /dev/null
+++ b/WorkspaceMgr/WorkspaceMgr.cs
@@ -0,0 +1,248 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Foo.DataAccessLayer;
+using Foo.DataAccessLayer.DataTypes;
+
+using Foo.WorkspaceMgr.Closers;
+using Foo.WorkspaceMgr.Hiders;
+using Foo.WorkspaceMgr.Launchers;
+using System.Reflection;
+
+namespace Foo.WorkspaceMgr
+{
+ public class WorkspaceMgr : IWorkspaceMgr
+ {
+ #region IWorkspaceMgr Members
+
+ ///
+ /// Responsible for Launching a single artifact // ToDo: - CHECK RAT if Artifact is already running
+ /// // ToDo: - Test IEXPLORER LAUNCHER
+ /// artifact to launch // ToDo: - Figgure out what to do in Error State
+ /// true if successful, false otherwise
+ public bool LaunchArtifact(ArtifactItem artifactItem)
+ {
+
+ AssemblyName assemblyName = new AssemblyName("Microsoft.Office.Interop.Access, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
+ Assembly assembly = Assembly.Load(assemblyName);
+
+
+ //if (artifactItem.IsValid && artifactItem.IsValidFileIntegrity)
+ if (artifactItem.IsLocationValid)
+ {
+ // Step One - Create the Launcher Obj
+ ILaunch launcher = WorkspaceTypeHelpers.CreateLauncherObj(artifactItem);
+ if (launcher == null)
+ return false;
+
+ // Step Two - Query if Launching for this Artifact is supported
+ FuncDepBoolType retVal = launcher.IQueryLaunch(artifactItem.Location);
+
+ // Step Three - launch it if supported
+ if (retVal == FuncDepBoolType.Success)
+ {
+ retVal = launcher.ILaunch(artifactItem.Location);
+ }
+ else
+ {
+ // * Log error or something and return otherwise * To Do
+ return false;
+ }
+
+ // Step Four - if success signal to the db the artifact was launched
+ if (retVal == FuncDepBoolType.Success)
+ {
+ Data.Artifacts.ArtifactWasLaunched(artifactItem);
+ }
+
+ return (retVal == FuncDepBoolType.Success);
+ }
+ return false;
+ }
+
+ ///
+ /// Responsible for Closing a single artifact // ToDo: - CHECK RAT if Artifact is running, if so Get Proccess that it is running in!!! ----
+ /// // ToDo: - Test Office, Generic, Notepad, IExplore Closers
+ /// artifact to close // ToDo: - Figgure out what to do in Error State
+ /// true if successful, false otherwise
+ public bool CloseArtifact(ArtifactItem artifactItem)
+ {
+ if (artifactItem.IsValid && artifactItem.IsValidFileIntegrity)
+ {
+ // Step One - Create the Closer Obj
+ IClose closer = WorkspaceTypeHelpers.CreateCloserObj(artifactItem);
+ if (closer == null)
+ return false;
+
+ // Step Two - Query if Closing for this Artifact is possible
+ FuncDepBoolType retVal = closer.IQueryClose(artifactItem.Location);
+
+ // Step Three - close it if supported
+ if (retVal == FuncDepBoolType.Success)
+ {
+ retVal = closer.IClose(artifactItem.Location);
+ }
+ else
+ {
+ // * Log error or something and return otherwise * To Do
+ return false;
+ }
+
+ return (retVal == FuncDepBoolType.Success);
+ }
+ return false;
+ }
+
+ ///
+ /// Responsible for Hiding or showing a single artifact // ToDo: - CHECK RAT if Artifact is running, if so Get Proccess that it is running in!!! ----
+ /// // ToDo: - Test Office, Generic, Notepad, IExplore Hiders
+ /// artifact to hide // ToDo: - Figgure out what to do in Error State
+ /// true to show, false to hide artifact
+ /// true if successful, false otherwise
+ public bool HideShowArtifact(ArtifactItem artifactItem, bool bShow)
+ {
+ if (artifactItem.IsValid && artifactItem.IsValidFileIntegrity)
+ {
+ // Step One - Create the ShowNHider Obj
+ IShowNHide ShowHider = WorkspaceTypeHelpers.CreateShowNHiderObj(artifactItem);
+ if (ShowHider == null)
+ return false;
+
+ // Step Two - Query if Hiding or Showing is available for this Artifact
+ FuncDepBoolType retVal = FuncDepBoolType.Failed;
+ if (bShow)
+ retVal = ShowHider.IQueryShow(artifactItem.Location);
+ else
+ retVal = ShowHider.IQueryHide(artifactItem.Location);
+
+ // Step Three - Show or Hide it if supported
+ if (retVal == FuncDepBoolType.Success)
+ {
+ if(bShow)
+ retVal = ShowHider.IShow(artifactItem.Location);
+ else
+ retVal = ShowHider.IHide(artifactItem.Location);
+ }
+ else
+ {
+ // * Log error or something and return otherwise * To Do
+ return false;
+ }
+
+ return (retVal == FuncDepBoolType.Success);
+ }
+ return false;
+ }
+
+ /// // ToDo: -
+ /// Launches a Workspace. When for some reason an artifact location
+ /// is not available to launch we keep track of it and display it to the
+ /// user - however, we don't stop. we try to launch as many artifacts as
+ /// we can.
+ /// ---------------------------------------------------------------------
+ /// There are a few steps we have to do in order to successfully launch:
+ /// 1) Make sure all files that have the same file name are not launched together
+ /// 2) we must wait a little after each file to make sure that they can be resolved
+ ///
+ ///
+ /// Name of Workspace to launch artifacts for
+ /// true if 1 or more artifacts were launched, false otherwise
+ public bool LaunchWorkspace(string WorkspaceName)
+ {
+ // Step One - First Get all the Artifacts by Name
+ ArtifactItem[] artifacts = Data.Artifacts.GetAllArtifactsForWorkspace(WorkspaceName, SortOrderForArtifacts.Descending);
+ if (!DataTypeValidation.IsEmptyArtifactItemGroup(artifacts))
+ {
+
+ // Let's get the optimal Indexes for all the file artifacts
+ int[] optimalIndexes;
+ HelperFunc.IndexOptimizationQuality quality;
+ quality = HelperFunc.OptimalLaunchIndexesForFileArtifacts(artifacts, out optimalIndexes);
+
+ ////
+ // Launch the file Artifacts according to their optimal indexes
+ ////
+ foreach (int optIndex in optimalIndexes)
+ {
+ // Launch file artifact
+ LaunchArtifact(artifacts[optIndex]);
+
+ // depending on the quality of indexes sleep accordingly
+ int nSleepTime = HelperFunc.GetSleepTimeForQuality(quality);
+
+ // Sleep Now before launching again
+ System.Threading.Thread.Sleep(nSleepTime);
+ }
+
+ ////
+ // Launch the url Artifacts according to their optimal indexes
+ ////
+ foreach (ArtifactItem artifact in artifacts)
+ {
+ if (artifact.IsUrl)
+ {
+ LaunchArtifact(artifact);
+ System.Threading.Thread.Sleep(HelperFunc.DEFAULT_LAUNCH_SLEEP_TIME);
+ }
+ }
+
+ // Signal the Workspace as Launched
+ Data.Workspace.WorkspaceWasLaunched(WorkspaceName);
+
+ // Set it to this Workspace 'State'
+ Data.State.SetCurrentWorkspaceName(WorkspaceName);
+ }
+ return false;
+ }
+
+ ///
+ ///
+ ///
+ /// Name of Workspace to close artifacts for
+ ///
+ public bool CloseWorkspace(string WorkspaceName)
+ {
+ ArtifactItem[] artifacts = Data.Artifacts.GetAllArtifactsForWorkspace(WorkspaceName, SortOrderForArtifacts.Ascending);
+ if (!DataTypeValidation.IsEmptyArtifactItemGroup(artifacts))
+ {
+ foreach (ArtifactItem artifact in artifacts)
+ {
+ CloseArtifact(artifact);
+
+ // Sleep a little
+ System.Threading.Thread.Sleep(HelperFunc.DEFAULT_CLOSE_SLEEP_TIME);
+ }
+
+ // Clear Workspace 'State'
+ Data.State.ClearCurrentWorkspaceName();
+ }
+ return false;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ /// true to show, false to hide artifact
+ ///
+ public bool HideShowWorkspace(string WorkspaceName, bool bShow)
+ {
+ ArtifactItem[] artifacts = Data.Artifacts.GetAllArtifactsForWorkspace(WorkspaceName, SortOrderForArtifacts.Ascending);
+
+ if (!DataTypeValidation.IsEmptyArtifactItemGroup(artifacts))
+ {
+ foreach (ArtifactItem artifact in artifacts)
+ {
+ HideShowArtifact(artifact, bShow);
+
+ // Sleep a little
+ System.Threading.Thread.Sleep(HelperFunc.DEFAULT_SHOWNHIDE_SLEEP_TIME);
+ }
+ }
+ return false;
+ }
+
+ #endregion
+ }
+}
diff --git a/WorkspaceMgr/WorkspaceMgr.csproj b/WorkspaceMgr/WorkspaceMgr.csproj
new file mode 100644
index 0000000..1d6c631
--- /dev/null
+++ b/WorkspaceMgr/WorkspaceMgr.csproj
@@ -0,0 +1,134 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}
+ Library
+ Properties
+ Foo.WorkspaceMgr
+ WorkspaceMgr
+ v3.5
+ 512
+ true
+ MyKeyFile.SNK
+
+
+ true
+ full
+ false
+ ..\Target\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\Target\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ False
+ False
+
+
+ False
+ False
+
+
+ False
+ False
+
+
+ False
+ False
+
+
+ False
+ False
+
+
+ False
+ False
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}
+ DataAccessLayer
+
+
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}
+ Platform
+
+
+ {48D75C4F-2749-48BB-9386-721E0E94C144}
+ Settings
+
+
+
+
+
+
+
+ {2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}
+ 2
+ 3
+ 0
+ primary
+ False
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WorkspaceMgr/WorkspaceState.cs b/WorkspaceMgr/WorkspaceState.cs
new file mode 100644
index 0000000..c080442
--- /dev/null
+++ b/WorkspaceMgr/WorkspaceState.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Foo.WorkspaceMgr
+{
+ static class WorkspaceState
+ {
+ static public List Launched_ExcelInstances = new List();
+ static public List Launched_PowerPointInstances = new List();
+
+ static WorkspaceState()
+ {
+ }
+
+ }
+}
diff --git a/WorkspaceMgr/WorkspaceTypes.cs b/WorkspaceMgr/WorkspaceTypes.cs
new file mode 100644
index 0000000..2c08076
--- /dev/null
+++ b/WorkspaceMgr/WorkspaceTypes.cs
@@ -0,0 +1,291 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Foo.Settings;
+using Foo.Platform.Win32;
+using Foo.DataAccessLayer.DataTypes;
+using Foo.WorkspaceMgr.Hiders;
+using Foo.WorkspaceMgr.Closers;
+using Foo.WorkspaceMgr.Launchers;
+
+namespace Foo.WorkspaceMgr
+{
+ ///
+ /// Allows us to extend functionallity by creating our own
+ /// Custom Types to be used in certain scenarios
+ ///
+ internal enum CustomStateChangingTypes
+ {
+ LaunchGenericUrl
+ }
+
+ ///
+ /// Useful for StateChanger Returns where we
+ /// need more information on failures
+ ///
+ public enum FuncDepBoolType
+ {
+ Success,
+ Failed,
+ ParametersInvalid,
+ ArtifactLocationUnavailable,
+ FunctionallityNotSupported,
+ ErrorThrown
+ }
+
+ ///
+ /// Use this to request the proper state
+ /// Changing Object
+ ///
+ public enum StateChangerReqType
+ {
+ Launcher,
+ ShowNHider,
+ Closer
+ }
+
+ ///
+ /// Class for useful Workspace Type Helpers
+ ///
+ internal static class WorkspaceTypeHelpers
+ {
+ private static configuration _configuration = null;
+
+ static WorkspaceTypeHelpers()
+ {
+ OoganizerSettingsAcc accessor = new OoganizerSettingsAcc();
+ _configuration = accessor.ReadConfigXMLFile();
+ }
+
+ #region Internal Object Creator Functions (Call these in this assembly)
+
+ ///
+ /// Creates a Launcher Object from an artifact Item
+ ///
+ /// valid artifact to create a launcher for
+ /// object or null
+ internal static ILaunch CreateLauncherObj(ArtifactItem artifactItem)
+ {
+ if (artifactItem.IsUrl)
+ {
+ return CreateLauncherObj(CustomStateChangingTypes.LaunchGenericUrl.ToString());
+ }
+ else if (artifactItem.IsFile)
+ {
+ string strRegisteredProcessExe = Win32_WrapperFunc.GetRegisteredExeForFile(artifactItem.Location);
+ if (!String.IsNullOrEmpty(strRegisteredProcessExe))
+ return CreateLauncherObj(strRegisteredProcessExe);
+ //return CreateLauncherObj(LauncherGenericType.LaunchGenericFile);
+ }
+ return null;
+ }
+
+ ///
+ /// Creates a Hider Object from an artifact Item
+ ///
+ /// name for process to create object for
+ /// object or null
+ internal static IShowNHide CreateShowNHiderObj(ArtifactItem artifactItem) // TO DO: We can check the RAT which Process the artifact was launched in!!
+ {
+ if (artifactItem.IsUrl)
+ {
+ // To Do: Query the RAT for the process this artifact is in, then call
+ // the object creator function for the correct process
+ return null;
+ }
+ else if (artifactItem.IsFile)
+ {
+ string strRegisteredProcessExe = Win32_WrapperFunc.GetRegisteredExeForFile(artifactItem.Location);
+ if (!String.IsNullOrEmpty(strRegisteredProcessExe))
+ return CreateShowNHiderObj(strRegisteredProcessExe);
+ }
+ return null;
+ }
+
+ ///
+ /// Creates a Closer Object from an artifact Item
+ ///
+ /// valid artifact to a closer for
+ /// object or null
+ internal static IClose CreateCloserObj(ArtifactItem artifactItem) // TO DO: We can check the RAT which Process the artifact was launched in!!
+ {
+ if (artifactItem.IsUrl)
+ {
+ // To Do: Query the RAT for the process this artifact is in, then call
+ // the object creator function for the correct process
+ return null;
+ }
+ else if (artifactItem.IsFile)
+ {
+ string strRegisteredProcessExe = Win32_WrapperFunc.GetRegisteredExeForFile(artifactItem.Location);
+ if (!String.IsNullOrEmpty(strRegisteredProcessExe))
+ return CreateCloserObj(strRegisteredProcessExe);
+ }
+ return null;
+ }
+
+ #endregion
+
+ #region Private Object Creator Helper Functions
+
+ ///
+ /// Creates a Closer Object
+ ///
+ /// name for process to create object for
+ /// object or null
+ private static IClose CreateCloserObj(string ProcessNameOrCustomType)
+ {
+ object o = CreateStateChangerObject(StateChangerReqType.Closer, ProcessNameOrCustomType);
+ if (IsObjectOfType(StateChangerReqType.Closer, o))
+ return (o as IClose);
+ else
+ return null;
+ }
+
+ ///
+ /// Creates a Hider Object
+ ///
+ /// name for process to create object for
+ /// object or null
+ private static IShowNHide CreateShowNHiderObj(string ProcessNameOrCustomType)
+ {
+ object o = CreateStateChangerObject(StateChangerReqType.ShowNHider, ProcessNameOrCustomType);
+ if (IsObjectOfType(StateChangerReqType.ShowNHider, o))
+ return (o as IShowNHide);
+ else
+ return null;
+ }
+
+ ///
+ /// Creates a Launcher Object
+ ///
+ /// type of Launcher you want to create
+ /// object or null
+ private static ILaunch CreateLauncherObj(string ProcessNameOrCustomType)
+ {
+ object o = CreateStateChangerObject(StateChangerReqType.Launcher, ProcessNameOrCustomType);
+ if (IsObjectOfType(StateChangerReqType.Launcher, o))
+ return (o as ILaunch);
+ else
+ return null;
+ }
+
+ ///
+ /// Useful for quick Interface Type checking of StateChangers
+ ///
+ /// A StateChangerRequestTyp
+ /// a stateChanger Object
+ /// true if object is of that Type
+ private static bool IsObjectOfType(StateChangerReqType reqType, object o)
+ {
+ if (o != null)
+ {
+ switch (reqType)
+ {
+ case StateChangerReqType.Launcher:
+ return (o is ILaunch);
+
+ case StateChangerReqType.ShowNHider:
+ return (o is IShowNHide);
+
+ case StateChangerReqType.Closer:
+ return (o is IClose);
+ }
+ }
+ return false;
+ }
+
+ #endregion
+
+ #region Main Object Factory Function (All calls ultimately end up here)
+
+ ///
+ /// Function is responsible for create the StateChanging Objects that we
+ /// need for the system. It will either be hardcoded in or be reading from
+ /// the settings file to know what object to create
+ ///
+ /// A StateChangerRequestType
+ /// the name of the process to create it for
+ /// an object of the correct type, the caller must then cast it
+ private static object CreateStateChangerObject(StateChangerReqType reqType, string ProcessNameOrCustomType)
+ {
+ if (!String.IsNullOrEmpty(ProcessNameOrCustomType))
+ {
+ ////
+ // First Step - Create any Custom Types
+ ////
+ switch (ProcessNameOrCustomType)
+ {
+ case "LaunchGenericUrl":
+ {
+ if (reqType == StateChangerReqType.Launcher)
+ return new Launchers.Launcher_Web();
+ }
+ break;
+ }
+
+ ////
+ // Second Step - Read thru the Configuration and create the corresponding
+ // object as the Configuration says we should use
+ ////
+ foreach (ButtonHookSettings.ProcessName processObj in _configuration.ButtonHook.AllowedProcessNames.ProcessNames)
+ {
+
+ if (processObj.ProcessExe == ProcessNameOrCustomType.ToUpper())
+ {
+ switch (reqType)
+ {
+ case StateChangerReqType.Launcher:
+ switch (processObj.Launcher.ToUpper())
+ {
+ case "WEB":
+ return new Launcher_Web();
+
+ case "SHELL":
+ return new Launcher_Shell();
+
+ case "EXCEL":
+ return new Launcher_Excel();
+
+ case "VISIO":
+ return new Launcher_Visio();
+
+ default:
+ return new Launcher_Generic();
+ }
+
+ case StateChangerReqType.Closer:
+ switch (processObj.Closer.ToUpper())
+ {
+ case "IE":
+ return new Closer_IE();
+
+ case "OFFICE":
+ return new Closer_Office();
+
+ default:
+ return new Closer_Generic();
+ }
+
+ case StateChangerReqType.ShowNHider:
+ switch (processObj.ShowHider.ToUpper())
+ {
+ case "OFFICE":
+ return new ShowNHide_Office();
+
+ default:
+ return new ShowNHide_Generic();
+ }
+
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ #endregion
+ }
+}
diff --git a/zEasyTest/Program.cs b/zEasyTest/Program.cs
new file mode 100644
index 0000000..22ddfc9
--- /dev/null
+++ b/zEasyTest/Program.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Foo.Platform;
+using Foo.Platform.Win32;
+using Foo.Settings;
+using Foo.DataAccessLayer;
+using Foo.DataAccessLayer.DataTypes;
+
+
+namespace zEasyTest
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ foreach (Win32Functions.RunningObject running in Win32Functions.GetRunningObjects())
+ {
+ if (running.name == "Doris")
+ {
+ int j = 5;
+ j = j + 5;
+ }
+ }
+
+
+
+
+ // DataAccessLayer
+ //DB.DeleteDefaultDB();
+ //DataAccessLayer.TestData.TestData.FillDBWithTestData();
+
+ // Settings
+ //Settings_Test.MockAroundWithSettings();
+
+ // WorkspaceMgr
+ //WorkspaceMgr_Test.TestSingleArtifactLaunch();
+ //WorkspaceMgr_Test.TestWorkspaceLaunch();
+ //WorkspaceMgr_Test.TestConfiguration();
+
+ int i = 5;
+ i = i - 5;
+ }
+ }
+}
diff --git a/zEasyTest/Properties/AssemblyInfo.cs b/zEasyTest/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..2d03398
--- /dev/null
+++ b/zEasyTest/Properties/AssemblyInfo.cs
@@ -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("zEasyTest")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("zEasyTest")]
+[assembly: AssemblyCopyright("Copyright © 2010")]
+[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("9543b631-51de-4051-b115-ac39fd28e0cc")]
+
+// 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")]
diff --git a/zEasyTest/Settings_Test.cs b/zEasyTest/Settings_Test.cs
new file mode 100644
index 0000000..a2f01c4
--- /dev/null
+++ b/zEasyTest/Settings_Test.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Foo.Settings;
+
+namespace zEasyTest
+{
+ static class Settings_Test
+ {
+
+ public static void MockAroundWithSettings()
+ {
+ OoganizerSettingsAcc acc = new OoganizerSettingsAcc();
+
+ configuration conf = new configuration();
+ conf.ButtonHook.AllowedProcessNames.AddProcessName(new ButtonHookSettings.ProcessName("Doris", "Doris1", "Doris3", "Doris4", "123", "dd", "vv", 0, 0));
+ conf.ButtonHook.AllowedProcessNames.AddProcessName(new ButtonHookSettings.ProcessName("Voris", "Voris1", "Voris3", "Voris4", "123", "dd", "vv", 0, 0));
+ conf.ButtonHook.AllowedProcessNames.AddProcessName(new ButtonHookSettings.ProcessName("Koris", "Koris1", "Koris3", "Koris4", "123", "dd", "vv", 0, 0));
+
+ //configuration config = acc.ReadConfigXMLFile();
+
+ //configuration config = acc.ReadConfigXMLFile(@"D:\Users\HPinvent\_ROOT_\TestANizer\DataAccessLayer\Doris.xml", false);
+
+ acc.WriteConfigXMLFile(@"D:\Users\HPinvent\_ROOT_\TestANizer\DataAccessLayer\Doris.xml", conf);
+
+ //acc.WriteBlankConfigXMLFile(@"D:\Users\HPinvent\_ROOT_\TestANizer\DataAccessLayer\Doris.xml");
+ }
+
+
+ }
+}
diff --git a/zEasyTest/WorkspaceMgr_Test.cs b/zEasyTest/WorkspaceMgr_Test.cs
new file mode 100644
index 0000000..85a7049
--- /dev/null
+++ b/zEasyTest/WorkspaceMgr_Test.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using Foo.DataAccessLayer;
+using Foo.DataAccessLayer.DataTypes;
+using Foo.Platform;
+using Foo.GUILib;
+using Foo.WorkspaceMgr;
+
+namespace zEasyTest
+{
+ static class WorkspaceMgr_Test
+ {
+
+ static public void TestConfiguration()
+ {
+ Configurations.Configure_Excel2007();
+ }
+
+ static public void TestSingleArtifactLaunch()
+ {
+ //WorkspaceMgr mgr = new WorkspaceMgr();
+ //mgr.LaunchArtifact(DataTypeHelpers.CreateLocationOnlyArtifact(@"D:\Users\HPinvent\Documents\KeepFocusedTask.txt"));
+ //mgr.LaunchArtifact(DataTypeHelpers.CreateLocationOnlyArtifact(@"http://www.google.com/"));
+ }
+
+ static public void TestWorkspaceLaunch()
+ {
+ WorkspaceMgr mgr = new WorkspaceMgr();
+
+ string strTestWorkspace = "Presentations";
+
+ mgr.LaunchWorkspace(strTestWorkspace);
+
+ System.Threading.Thread.Sleep(30000);
+
+ mgr.CloseWorkspace(strTestWorkspace);
+
+
+ //mgr.LaunchArtifact(DataTypeHelpers.CreateLocationOnlyArtifact(@"D:\Users\HPinvent\Documents\KeepFocusedTask.txt"));
+ }
+
+ }
+}
diff --git a/zEasyTest/zEasyTest.csproj b/zEasyTest/zEasyTest.csproj
new file mode 100644
index 0000000..469b304
--- /dev/null
+++ b/zEasyTest/zEasyTest.csproj
@@ -0,0 +1,83 @@
+
+
+
+ Debug
+ AnyCPU
+ 9.0.30729
+ 2.0
+ {6CDF553C-5060-4871-9CE8-63F66346716A}
+ Exe
+ Properties
+ zEasyTest
+ zEasyTest
+ v3.5
+ 512
+
+
+ true
+ full
+ false
+ ..\target\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\target\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+ 3.5
+
+
+ 3.5
+
+
+ 3.5
+
+
+
+
+
+
+
+
+
+
+
+
+ {C7E4B4C1-64D4-45FF-AAFD-C4B9AE216618}
+ DataAccessLayer
+
+
+ {C1282050-455B-44F4-8520-1C005E38EFB2}
+ GUILib
+
+
+ {F6929AFC-BF61-43A0-BABD-F807B65FFFA1}
+ Platform
+
+
+ {48D75C4F-2749-48BB-9386-721E0E94C144}
+ Settings
+
+
+ {09ED5DCC-9350-42E5-8E3A-4A3EA25BCD35}
+ WorkspaceMgr
+
+
+
+
+
\ No newline at end of file