//
<copyright file="Layouts.cs" company="Western Electric
Coordinating Council">
//
Copyright (c) 2010 All Right Reserved
//
</copyright>
//
<author>Jeff Martin</author>
//
<email>jmartin@bridgeenergygroup.com</email>
//
<date>31-Jul-2010</date>
// <summary>Anonymous,
singleton class containing functions for saving,
//
parsing and loading procbook layout configuration files.</summary>
namespace
AddInPB_LayoutMgr
{
using
System;
using
System.IO;
using
System.Text;
using
System.Collections;
using
System.Collections.Generic;
using
System.Linq;
using
PBObjLib;
using
PBSymLib;
using
System.ComponentModel;
using
System.Windows.Forms;
using
System.Runtime.InteropServices;
class
Layouts
{
// processbook application
private PBObjLib.Application
app = null;
// store keys that refer to .pdi displays
string sDisplay = string.Empty;
// store the Procbook main window keys
string sProcbook = string.Empty;
// string for storing exception messages
public string
sException = string.Empty;
// generic bool
private static bool bBool;
#if
DEBUG
// generic DialogResult
private static DialogResult Result;
#endif
// Dictionary object for storing KEY=VALUE; pairs
private static Dictionary<string,
string> dictLayout = new Dictionary<string, string>();
// list of all child windows titles
private static List<string>
ChildTitles = new List<string>();
// list of all child windows handles
private static List<System.IntPtr>
ChildHandles = new List<System.IntPtr>();
// struct for GetWindowRect() / GetClientRect()
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public Int32
Left;
// x position of upper-left corner
public Int32
Top;
// y position of upper-left corner
public Int32
Right;
// x position of lower-right corner
public Int32
Bottom; // y position of lower-right corner
public Int32
Width
{
get { return
Right - Left; }
}
public Int32
Height
{
get { return
Bottom - Top; }
}
}
// get the total height of all toolbars
public static Int32 ToolBarHeight = 0;
// map child screen coordinates to procbook client area
coordinates.
Int32 ChildTop = 0;
Int32 ChildLeft = 0;
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////// Win API prototypes and structs
//////////////////////////////
// Win API functions for Window Handles
public delegate bool EnumChildProc(System.IntPtr hwnd, int
lParam);
// Win API for looping through child windows
[DllImport("user32.dll",
SetLastError = true)]
internal static extern int
EnumChildWindows(System.IntPtr hWndParent, EnumChildProc callback,
int lParam);
// Win API function for getting the window label
[DllImport("user32.dll",
SetLastError = true)]
internal static extern int
GetWindowText(System.IntPtr hWnd, StringBuilder title, int
count);
// Win API function for sending system messages to a window
[DllImport("user32.dll",
SetLastError = true)]
internal static extern int
SendMessage(System.IntPtr hWnd, int Msg, int wParam, StringBuilder sb);
// Win API constant for getting a windows text
private static int WM_GETTEXT = 0x000D;
// Win API constant for getting a windows text
private static uint SWP_SHOWWINDOW = 0x0040;
// Win API constands for sending a Restore command to a
window
//private static int WM_SYSCOMMAND = 0x0112;
//private static int SC_RESTORE = 0xF120;
// Win API function for setting window position
[DllImport("user32.dll",
SetLastError = true)]
internal static extern bool
SetWindowPos(System.IntPtr hWnd, System.IntPtr hWndInsertAfter,
int x, int
y, int cx, int
cy, uint uFlags);
[DllImport("user32.dll",
CharSet = CharSet.Auto)]
internal static extern bool
MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int
nHeight, bool bRepaint);
// Win API function for getting a windows position
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr
hWnd, out RECT
lpRect);
// Win API function for getting the size of a windows
client area
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetClientRect(IntPtr
hWnd, out RECT
lpRect);
/////////////////////////////////////////////////////////////////////////////////////////
// create a new Layouts object and store procbook app
reference
public Layouts(PBObjLib.Application
app)
{
this.app = app;
// find the start of the client area
//commandBar =
this.app.CommandBars.Item("Layout Manager");
//ToolBarHeight = commandBar.Top +
commandBar.Height;
// find the start of the client area
// last commandbar top + height
Int32 iHeight = 0;
foreach (PBObjLib.PBCommandBar cmdbar in
this.app.CommandBars)
{
if (cmdbar.Visible == true)
{
if (cmdbar.Top >= ToolBarHeight)
{
ToolBarHeight = cmdbar.Top;
iHeight = cmdbar.Height;
}
}
}
ToolBarHeight = ToolBarHeight + iHeight;
}
~Layouts()
{
}
////////////////////////////////////////////////////////////////////
// load layouts from file
// J. Martin, jmartin@bridgeenerygroup.com
///////////////////////////////////////////////////////////////////
public Boolean
LoadFromFile(string sFile)
{
// Main Window Handle from the thread
System.IntPtr hMainWnd =
System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
// define a return object for Displays.Open
function
PBObjLib.Display pbDisplay;
// define a return object for ProcBooks.Open
function
PBObjLib.ProcBook pbBook = (PBObjLib.ProcBook)null;
// parse the layout file
try
{
// Create an instance of StreamReader to read
from a file.
// The using statement also closes the
StreamReader.
using (StreamReader
sr = new StreamReader(sFile))
{
string line;
string sParsed = string.Empty;
string sValue = string.Empty;
string sKey = string.Empty;
// Read lines from the the until EOF
while ((line = sr.ReadLine()) != null)
{
// ignore comment lines
if (line[0] != '#')
{
// store key=value; pairs in dictLayout
for (int
x = 0; x < line.Length; x++)
{
switch (line[x])
{
case '=':
sKey = sParsed.Trim();
sParsed = string.Empty;
break;
case ';':
sValue = sParsed.Trim();
sParsed = string.Empty;
// store the key=value; pair
dictLayout.Add(sKey, sValue);
//MessageBox.Show(sKey + "\n" +
sValue);
break;
default:
sParsed = sParsed + line[x];
break;
}
} // for (int x = 0; x < line.Length; x++)
////////// PROCBOOK
///////////////////////////////////////
sProcbook = string.Empty;
if (dictLayout.TryGetValue("PARENT", out
sProcbook))
{
// reposition the processbook application
window
#if DEBUG
Result = MessageBox.Show("procbook: \n" +
"\nLeft: " +
Convert.ToInt32(dictLayout["LEFT"]) +
"\nTop: " + Convert.ToInt32(dictLayout["TOP"]) +
"\nWidth: " + Convert.ToInt32(dictLayout["WIDTH"]) +
"\nHeight: " + Convert.ToInt32(dictLayout["HEIGHT"]),
"Positioning Procbook.." );
#endif
SetWindowPos(hMainWnd, System.IntPtr.Zero,
Convert.ToInt32(dictLayout["LEFT"]),
Convert.ToInt32(dictLayout["TOP"]),
Convert.ToInt32(dictLayout["WIDTH"]),
Convert.ToInt32(dictLayout["HEIGHT"]),
SWP_SHOWWINDOW);
}
///////// .pdi DISPLAYS
/////////////////////////////////////
sDisplay = string.Empty;
if (dictLayout.TryGetValue("DISPLAY", out
sDisplay))
{
#if DEBUG
Result = MessageBox.Show("DISPLAY: \n" +
dictLayout["DISPLAY"] +
"\nLeft: " +
Convert.ToInt32(dictLayout["LEFT"]) +
"\nTop: " + Convert.ToInt32(dictLayout["TOP"]) +
"\nWidth:
" + Convert.ToInt32(dictLayout["WIDTH"]) +
"\nHeight: " + Convert.ToInt32(dictLayout["HEIGHT"])
+
"\nZoom: " + Convert.ToInt32(dictLayout["ZOOM"]),
"Loading DISPLAY..");
#endif
// open the procbook DISPLAY and position/size
it..
pbDisplay = app.Displays.Open(dictLayout["DISPLAY"],
1);
if (pbDisplay != null)
{
pbDisplay.Left = Convert.ToInt32(dictLayout["LEFT"]);
pbDisplay.Top = Convert.ToInt32(dictLayout["TOP"]);
pbDisplay.Width = Convert.ToInt32(dictLayout["WIDTH"]);
pbDisplay.Height = Convert.ToInt32(dictLayout["HEIGHT"]);
pbDisplay.Zoom = Convert.ToInt32(dictLayout["ZOOM"]);
}
}
///////// .piw WORKBOOKS /////////////////////////////////////
sDisplay = string.Empty;
if (dictLayout.TryGetValue("WORKBOOK", out
sDisplay))
{
#if DEBUG
Result = MessageBox.Show("WORKBOOK: \n" +
dictLayout["WORKBOOK"] +
"\nLeft: " +
Convert.ToInt32(dictLayout["LEFT"]) +
"\nTop: " + Convert.ToInt32(dictLayout["TOP"]) +
"\nWidth: " +
Convert.ToInt32(dictLayout["WIDTH"]) +
"\nHeight: " +
Convert.ToInt32(dictLayout["HEIGHT"]),
"Loading
WORKBOOK..");
#endif
// open the WORKBOOK first before any
Entries..
pbBook = (PBObjLib.ProcBook)app.ProcBooks.Open(dictLayout["WORKBOOK"], 1);
// size the WORKBOOK
bBool = MoveWindow(GetWindowHandle(pbBook.Path.Substring(pbBook.Path.LastIndexOf("\\") + 1)),
Convert.ToInt32(dictLayout["LEFT"]),
Convert.ToInt32(dictLayout["TOP"]),
Convert.ToInt32(dictLayout["WIDTH"]),
Convert.ToInt32(dictLayout["HEIGHT"]),
true);
}
///////// workbook ENTRY
/////////////////////////////////////
sDisplay = string.Empty;
if (dictLayout.TryGetValue("ENTRY",
out sDisplay))
{
#if DEBUG
Result = MessageBox.Show("ENTRY: \n" +
dictLayout["ENTRY"] +
"\nLeft: " +
Convert.ToInt32(dictLayout["LEFT"]) +
"\nTop: " + Convert.ToInt32(dictLayout["TOP"]) +
"\nWidth: " + Convert.ToInt32(dictLayout["WIDTH"]) +
"\nHeight: " +
Convert.ToInt32(dictLayout["HEIGHT"]),
"Loading ENTRY..");
#endif
// open the ENTRY
bBool = pbBook.Entries.Item(dictLayout["ENTRY"]).Execute(true);
// size the ENTRY
bBool = MoveWindow(GetWindowHandle(dictLayout["ENTRY"]),
Convert.ToInt32(dictLayout["LEFT"]),
Convert.ToInt32(dictLayout["TOP"]),
Convert.ToInt32(dictLayout["WIDTH"]),
Convert.ToInt32(dictLayout["HEIGHT"]),
true);
}
// clear the dictionary (no dup keys)
dictLayout.Clear();
} // if (line[0] != '#')
} // while ((line = sr.ReadLine()) != null)
}
// using (StreamReader sr = new
StreamReader(sFile))
}
catch (Exception
ex)
{
// store the exeption message
sException = ex.Message;
return false;
}
return true;
}
///////////////////////////////////////////////////////////////////
// returns the window handle for the supplied window title
// J. Martin, jmartin@bridgeenerygroup.com
///////////////////////////////////////////////////////////////////
private static
System.IntPtr GetWindowHandle(string sTitle)
{
// load a list of child window titles to
search
bBool = LoadChildWindows();
foreach (string
cTitle in ChildTitles)
{ // this also captures any copies or 'read only' annotated
displays
if (cTitle.StartsWith(sTitle, StringComparison.OrdinalIgnoreCase))
{
return
ChildHandles[ChildTitles.IndexOf(cTitle)];
}
}
return System.IntPtr.Zero;
}
///////////////////////////////////////////////////////////////////
// load a list of all child window titles and handles
// J. Martin, jmartin@bridgeenerygroup.com
///////////////////////////////////////////////////////////////////
private static bool LoadChildWindows()
{
// init lists
ChildTitles.Clear();
ChildHandles.Clear();
// Main Window Handle for this thread
(procbook.exe)
System.IntPtr hMainWnd =
System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
// bind callback EnumChildWindow_Handle to
user32.dll.EnumChildWindows()
EnumChildProc EnumChildWindow = new EnumChildProc(EnumChildWindow_Handle);
EnumChildWindows(hMainWnd, EnumChildWindow, 0);
return true;
}
///////////////////////////////////////////////////////////////////
// this function is a callback function, called on each
child window by the
// WinAPI function EnumChildWindows. It loads the
ChildWindows list with elements
// J. Martin, jmartin@bridgeenerygroup.com
///////////////////////////////////////////////////////////////////
private static bool EnumChildWindow_Handle(System.IntPtr hWnd, int
lparam)
{
try
{
StringBuilder s = new StringBuilder(51);
// retrieve the window label for the child
window
GetWindowText(hWnd, s, 50);
// query windows if procbook doesn't respond
to this handle
if (s.ToString() == string.Empty)
{
SendMessage(hWnd, WM_GETTEXT, 50, s);
}
//only add non-empty strings to the lists
if (s.ToString() != string.Empty && s.ToString() != "")
{
// add the child title and handle to lists
ChildTitles.Add(s.ToString());
// add the child window handle.
List<>.Add() method must produce
// identical sequential indexes for this work
(looks like it does)..
// To find the childs handle from it's title
use:
// System.IntPtr Handle =
ChildHandles[ChildTitles.IndexOf("Title")];
ChildHandles.Add(hWnd);
}
return true;
}
catch
{
throw;
}
}
////////////////////////////////////////////////////////////////////
// save layouts in a file
//
// This function builds a list of procbook child windows.
// It searches this list for any open workbooks, workbook
entries
// or pdi displays. It calculates their client area
coordinates
// and adds them to a file.
// J. Martin, jmartin@bridgeenerygroup.com
///////////////////////////////////////////////////////////////////
public Boolean
SaveToFile(string sFile)
{
//foreach (PBObjLib.ProcBook pbBook1 in
app.ProcBooks)
//{
// foreach (PBObjLib.Entry
pbEntry1 in pbBook1.Entries)
// {
//
disp1 = (PBObjLib.Display)pbEntry1;
//
Result = MessageBox.Show("Top: " + disp1.Top + "\n"
+
//
"Left: " +
disp1.Left + "\n" +
//
"Width: " + disp1.Width + "\n" +
//
"Height: " + disp1.Height + "\n\n" +
//
"ViewTop: " + disp1.ViewTop + "\n" +
//
"ViewLeft: " + disp1.ViewLeft + "\n" +
//
"ViewHeight: " + disp1.ViewHeight + "\n" +
//
"ViewWidth: " + disp1.ViewWidth + "\n\n" +
//
"Zoom: " + disp1.Zoom + "\n");
// }
//}
// Main Window Handle from the thread
System.IntPtr hMainWnd =
System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
// struct for main Procbook parent window
RECT rectProcBook;
// struct for main Procbook client area
RECT rectClientArea;
// struct for GetWindowRect()
RECT rectChild;
// Create the Layout ini file if needed.
FileStream fs = new FileStream(sFile,
FileMode.Create,
FileAccess.Write,
FileShare.Write);
fs.Close();
StreamWriter sw = new StreamWriter(sFile,
true,
Encoding.ASCII);
sw.WriteLine("##################################################################");
sw.WriteLine("# ProcessBook Layout
Configuration File");
sw.WriteLine("#");
sw.WriteLine("# Created on: "
+ Environment.MachineName + " (" + Environment.UserName
+ ")");
sw.WriteLine("# Created by: "
+ app.FullName );
sw.WriteLine("# Created at: "
+ DateTime.Now);
sw.WriteLine("#");
sw.WriteLine("# Do not edit
directly.");
sw.WriteLine("#################################################################");
// save the Main Processbook window
position/size and its client area
bBool = GetWindowRect(hMainWnd, out
rectProcBook);
bBool = GetClientRect(hMainWnd, out
rectClientArea);
sw.WriteLine("PARENT=PROCBOOK"
+
"; LEFT=" + Convert.ToString(rectProcBook.Left) +
"; TOP=" + Convert.ToString(rectProcBook.Top) +
"; WIDTH=" + Convert.ToString(rectProcBook.Width) +
"; HEIGHT=" + Convert.ToString(rectProcBook.Height) + ";");
// load a list of child window titles and
handles
bBool = LoadChildWindows();
// find and store all the open workbook
size/positions.
foreach (string
sTitle in ChildTitles)
{
// get all the possible entries in all open
workbooks.
foreach (PBObjLib.ProcBook
pbBook in app.ProcBooks)
{
// are any of them a procbook child handle ?
if
(sTitle.StartsWith(pbBook.Path.Substring(pbBook.Path.LastIndexOf("\\") + 1),
StringComparison.OrdinalIgnoreCase))
{
// get the child windows screen coordinates
bBool = GetWindowRect(ChildHandles[ChildTitles.IndexOf(sTitle)], out rectChild);
// GetClientRect() reports all of the client
area including that used
// by toolbar. GetWindowRect() gives screen
coordinates (not client area).
// The following arithemtic is intended to
offset screen coordinates so
// that they equal the procbook's child client
area coordinates.
ChildTop = rectChild.Top - ((rectProcBook.Height -
rectClientArea.Height) +
(rectProcBook.Top
+ ToolBarHeight) - 1);
if (ChildTop < 0)
{
ChildTop = ChildTop * -1;
}
// 6 is the width of the procbook main windows
border (a guess)..
ChildLeft = (rectChild.Left - rectProcBook.Left) - 6;
if (ChildLeft < 0)
{
ChildLeft = ChildLeft * -1;
}
#if DEBUG
Result = MessageBox.Show("WORKBOOK=" + pbBook.Path +
"; LEFT=" + Convert.ToString(ChildLeft) +
";
TOP=" + Convert.ToString(ChildTop) +
"; WIDTH=" + Convert.ToString(rectChild.Width) +
"; HEIGHT=" + Convert.ToString(rectChild.Height) +
";"
,"Found WORKBOOK:");
#endif
sw.WriteLine("WORKBOOK=" +
pbBook.Path +
"; LEFT=" + Convert.ToString(ChildLeft) +
"; TOP=" + Convert.ToString(ChildTop) +
"; WIDTH=" + Convert.ToString(rectChild.Width) +
"; HEIGHT=" + Convert.ToString(rectChild.Height) + ";");
// find and store all the open entries in this
workbook
// the order is important since LoadFromFile()
will first
// create the needed workkbook object and then
execute Entries from it.
foreach (string
sTitle1 in ChildTitles)
{
foreach (PBObjLib.Entry pbEntry in
pbBook.Entries)
{
if (sTitle1.StartsWith(pbEntry.Label, StringComparison.OrdinalIgnoreCase))
{
// store the child window position/size (see
comments for Workbooks..)
bBool = GetWindowRect(ChildHandles[ChildTitles.IndexOf(sTitle1)], out rectChild);
ChildTop = rectChild.Top - ((rectProcBook.Height - rectClientArea.Height)
+
(rectProcBook.Top + ToolBarHeight) - 1);
if (ChildTop < 0)
{
ChildTop = ChildTop * -1;
}
ChildLeft = (rectChild.Left - rectProcBook.Left) - 6;
if (ChildLeft < 0)
{
ChildLeft
= ChildLeft * -1;
}
#if DEBUG
Result = MessageBox.Show("ENTRY=" + pbEntry.Label +
"; LEFT=" + Convert.ToString(ChildLeft) +
"; TOP=" + Convert.ToString(ChildTop) +
";
WIDTH=" + Convert.ToString(rectChild.Width) +
"; HEIGHT=" + Convert.ToString(rectChild.Height) +
";"
,"Found
ENTRY:");
#endif
sw.WriteLine("ENTRY=" +
pbEntry.Label +
"; LEFT=" + Convert.ToString(ChildLeft) +
"; TOP=" + Convert.ToString(ChildTop) +
"; WIDTH=" + Convert.ToString(rectChild.Width) +
"; HEIGHT=" + Convert.ToString(rectChild.Height)
+ ";");
}
}
} //
foreach (string sTitle1 in ChildTitles)
} // if (sTitle.StartsWith(pbBook.Path.Substring(pbBook.Path
}
// foreach (PBObjLib.ProcBook pbBook in
app.ProcBooks)
}
// foreach (string sTitle in ChildTitles)
// loop thru every pdi display and store their
positions/sizes
foreach (PBObjLib.Display disp in
app.Displays)
{
// don`t save minimized or maximized displays.
if (disp.WindowState == PBObjLib.pbWindowState.pbWindowStateNormal)
{
#if
DEBUG
Result = MessageBox.Show("DISPLAY=" + disp.Path +
"; LEFT=" + Convert.ToString(disp.Left) +
"; TOP=" + Convert.ToString(disp.Top) +
"; WIDTH=" + Convert.ToString(disp.Width) +
"; HEIGHT=" + Convert.ToString(disp.Height) +
"; ZOOM=" + Convert.ToString(disp.Zoom) + ";"
,"Found DISPLAY:");
#endif
sw.WriteLine("DISPLAY=" +
disp.Path +
"; LEFT=" + Convert.ToString(disp.Left) +
"; TOP=" + Convert.ToString(disp.Top) +
"; WIDTH=" + Convert.ToString(disp.Width) +
"; HEIGHT=" + Convert.ToString(disp.Height)
+
"; ZOOM=" + Convert.ToString(disp.Zoom) + ";");
}
}
sw.Close();
// close the streamwriter
return true;
}
}
}