using System;
using System.IO;
using System.Drawing;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
using System.Text;
// V2.05
// by: Christian Treffler
//
// The function loads several informations about the current desktop and applies them
// for the current monitor setup:
// - Current desktop icons in a desktop icon profile
// - desktop gadget settings in "%userprofile%\AppData\Local\DisplayFusion\SidebarSettings"
// - position of windows in restored state in "%userprofile%\AppData\Local\DisplayFusion\WindowSettings"
// The profile name is built using the resolution and Y-position info of each monitor
// except the primary monitor where the Y-Position is 0.
// The information was generated by the function 'Desktop Auto-Save'
//
// Recommended to start with trigger "Monitor Profile changed"
//
// History:
// V2.01:
// Bugfix:
// - If Desktop Gadgets are running, but no respective settings have been saved for the ProfileName,
// they are not stopped. Nevertheless an attempt to restart them was made, leading to the opening
// of the System32 folder.
//
// V2.02:
// Improvement:
// Some windows seem not to be on the right place when this function is triggered by a change in monitor profiles.
// Only when calling it a second time it works.
// Introduced a wait time. RearrangeWait variable contains this time.
// 1s works most of the time, but not always
// 2s seems also not OK. Moved to desktop windows only, wait 2s after desktop gadgets
// 2s not enough, tried 5s
//
// V2.03:
// Removed wait time because it doesn't work
// Remove check, if Desktop Gadgets are running. Instead check, if a settings file for the profile exists
// Check program windos before Desktop Gadgets
//
// V2.04:
// Desktop gadget settings (sidebar): do not check, if setting exist. Info about start/stop is now stored with Program Settings
// The path to the sidebar appliaciton will also be stored
// Assure that LoadProgramSettings returns an object != null
//
// V2.05: Changes only in Desktop Auto-Save
public static class DisplayFusionFunction
{
public static void Run(IntPtr windowHandle)
{
string app = "";
// Are there desktop gadgets running?
bool SideBarExists = BFS.Application.IsAppRunningByFile("*sidebar.exe");
// Get Resolution of all Monitors and generate profile name
Rectangle[] Monitors = BFS.Monitor.GetMonitorBounds();
string ProfileName = buildProfileName(Monitors);
BFS.DisplayFusion.LoadDesktopIconsProfile(ProfileName);
DesktopPrograms AllPrgrms = ReadProgramSettings(SideBarExists /*V2.04*/); // Check current windows
DesktopPrograms SavedPrgrms = LoadProgramSettings(ProfileName); // Get stored window settings
if (SavedPrgrms.Prgrms.Count > 0) // were settings stored?
{
foreach (string key in SavedPrgrms.Prgrms.Keys) // for each stored window setting
{
if (AllPrgrms.Prgrms.ContainsKey(key)) // is the respective window running?
{
// restore size and location
Rectangle rct = SavedPrgrms.Prgrms[key].Rct;
IntPtr window = AllPrgrms.Prgrms[key].Ptr;
BFS.Window.SetSizeAndLocation(window, rct.X, rct.Y, rct.Size.Width, rct.Size.Height);
}
}
}
// Stop desktop gadgets
bool ok = true;
uint appID = BFS.Application.GetAppIDByFile("*sidebar.exe");
app = BFS.Application.GetMainFileByAppID(appID);
if (SideBarExists){ // V2.03
ok = BFS.Application.Kill(appID);
}
SideBarExists = SavedPrgrms.SideBarExists; //V2.04
if(SideBarExists)
{
//Replace current sidebar settings from the DisplayFusion User folder using the ProfileName
//Location of the DisplyFusion user folder&File
string source = Environment.ExpandEnvironmentVariables("%userprofile%\\AppData\\Local\\DisplayFusion\\SidebarSettings\\" + ProfileName + ".ini");
//Location of the sidebar settings
string destination = Environment.ExpandEnvironmentVariables("%userprofile%\\AppData\\Local\\Microsoft\\Windows Sidebar\\Settings.ini");
if (File.Exists(source) && Directory.Exists(Path.GetDirectoryName(destination))) // Check that operation is possible
{
if (ok) // if sidebar is inactive
{
File.Copy(source, destination, true);
// SideBarExists = true; //V2.03, moved with V2.04
} // else SideBarExists = false; removed with V2.04
// desktop gadgets will be restart after changing window settings
} // else SideBarExists = false; Removed with V2.04
// restart desktop gadgets
BFS.Application.Start(SavedPrgrms.SideBarPath,""); // V2.04
}
}
public static string buildProfileName(Rectangle[] screens)
{
// needs System.Text to have StringBuilder class
StringBuilder pname = new StringBuilder();
for (int i = 0; i < screens.Length; i++) // For each monitor
{
// Add monitors resolution in the format "[<Width>x<Height>, <Y>]"
pname.Append("[");
pname.Append(screens[i].Width);
pname.Append("x");
pname.Append(screens[i].Height);
if(screens[i].X!=0 || screens[i].Y!=0) // Primary screen has coordinates [0,0]
{
// Add the y-coordinate, if not primary screen
pname.Append(",");
pname.Append(screens[i].Y);
}
pname.Append("]");
}
return pname.ToString();
}
public static DesktopPrograms ReadProgramSettings(bool SideBarExists /*V2.04*/) // Get window settings
{
DesktopPrograms AllPrograms = new DesktopPrograms();
AllPrograms.SideBarExists = SideBarExists; // V2.04
if (SideBarExists) // V2.04
{
uint appID = BFS.Application.GetAppIDByFile("*sidebar.exe");
AllPrograms.SideBarPath = BFS.Application.GetMainFileByAppID(appID);
}
foreach(IntPtr window in BFS.Window.GetVisibleWindowHandles())
{
if (BFS.Window.IsRestored(window) && BFS.Window.GetText(window)!="") // only for windows which are not maximized or minimized
{
DProgram prgrm = new DProgram(); // DProgram is the class to store a setting
prgrm.ProgramClass = BFS.Window.GetClass(window);
prgrm.Text = BFS.Window.GetText(window);
prgrm.Rct = BFS.Window.GetBounds(window);
prgrm.Ptr = window;
AllPrograms.AddProgram(prgrm); // add to list
}
}
return AllPrograms;
}
public static void SaveProgramSettings(DesktopPrograms Data, string profile) // store all window settings in an xml file with the provided filename
{
XmlSerializer XmlSer = new XmlSerializer(typeof(DesktopPrograms)); // Provides the methods for XML-Serialization
// will be stored in the users local DisplayFusion AppData folder:
string path = Environment.ExpandEnvironmentVariables("%userprofile%\\AppData\\Local\\DisplayFusion\\WindowSettings\\" + profile + ".xml");
bool ready2copy = false; // Copy only if destination folder exists
try
{
//Location of the DisplyFusion user folder
string destination = Environment.ExpandEnvironmentVariables("%userprofile%\\AppData\\Local\\DisplayFusion");
if (Directory.Exists(destination)) // DisplyFusion user folder found?
{
// Creat a subfolder if it doesn't exist, yet
destination = destination + "\\WindowSettings";
ready2copy = Directory.Exists(destination);
if (!ready2copy)
{
ready2copy = Directory.CreateDirectory(destination).Exists;
}
}
}
catch (Exception) { }
if (ready2copy) // if destination folder exists
{
FileStream DStream = new FileStream(path, FileMode.Create); // Create the Filestream, overwrite mode
try
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); // Use this object
ns.Add("", ""); // to prevent that attributes are added in the files
XmlWriterSettings xws = new XmlWriterSettings(); // Use this object to
xws.Indent = true; // - add line feeds and indents
xws.CloseOutput = true; // - close stream after writing
xws.Encoding = Encoding.Default; // - set encoding
xws.IndentChars = " "; // - set indent depth
xws.NewLineHandling = NewLineHandling.None; // - handle line feeds properly
using (XmlWriter writer = XmlWriter.Create(DStream, xws)) // Now serialize
{
XmlSer.Serialize(writer, Data, ns);
writer.Close();
}
}
catch (Exception) { }
finally
{
if (!(DStream == null)) DStream.Close(); // Close the stream
}
}
}
public static DesktopPrograms LoadProgramSettings(string profile) // read window settings from an xml file with the provided filename
{
DesktopPrograms r = new DesktopPrograms();
string p = Environment.ExpandEnvironmentVariables("%userprofile%\\AppData\\Local\\DisplayFusion\\WindowSettings\\" + profile + ".xml"); // Full Filename with path
XmlSerializer XmlSer = new XmlSerializer(typeof(DesktopPrograms)); // Provides the methods for XML-Serialization
FileStream DStream = null;
try
{
if (File.Exists(p))
{
DStream = new FileStream(p, FileMode.Open); // Create the Filestream
r = (DesktopPrograms)XmlSer.Deserialize(DStream); // and load the Data
}
}
catch (Exception) { }
finally
{
if (!(DStream == null)) DStream.Close(); // Done
if (r == null) r = new DesktopPrograms(); // V2.04
}
return r;
}
[Serializable]
public class DProgram // stores window settings
{
public string Text = "";
public string ProgramClass = "";
public Rectangle Rct = new Rectangle();
[XmlIgnoreAttribute] // the handle will not be stored to file
public IntPtr Ptr = new IntPtr();
public Point Loc
{
get
{
return Rct.Location;
}
}
public DProgram() { } // empty constructor is needed to make the class serializable
}
[Serializable]
public class DesktopPrograms // list of window settings
{
public DesktopPrograms() { } // empty constructor is needed to make the class serializable
public XMLDictionary<string, DProgram> Prgrms = new XMLDictionary<string, DProgram>(); // list of windows
public bool SideBarExists = false; // V2.04
public string SideBarPath = ""; // V2.04
public void AddProgram(DProgram prgrm) // build a key and add the window settings to the list
{
// the key will be built out of the windows class and name and a counter
int i = 0;
string keyo = prgrm.ProgramClass + prgrm.Text;
string key = keyo + i.ToString("00");
while (Prgrms.ContainsKey(key))
{
if (++i > 99) break;
key = keyo + i.ToString("00");
}
if (i < 100)
{
Prgrms.Add(key, prgrm);
}
}
}
// ***** XMLDictionary *****
// A Module to provide a dictionary which is serializable.
// Purpose: e.g. ini-files
// Paul Welter 3/5/2006
//
// http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx
public class XMLDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable
{
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
bool wasEmpty = reader.IsEmptyElement;
reader.Read();
if (wasEmpty)
return;
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
reader.ReadStartElement("item");
reader.ReadStartElement("key");
TKey key = (TKey)keySerializer.Deserialize(reader);
reader.ReadEndElement();
reader.ReadStartElement("value");
TValue value = (TValue)valueSerializer.Deserialize(reader);
reader.ReadEndElement();
this.Add(key, value);
reader.ReadEndElement();
reader.MoveToContent();
}
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
XmlSerializer keySerializer = new XmlSerializer(typeof(TKey));
XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
// Addition by Christian Treffler, 6/9/2010:
XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); // Use this object
ns.Add("", ""); // to prevent that attributes are added in the files
// End of addition
foreach (TKey key in this.Keys)
{
writer.WriteStartElement("item");
writer.WriteStartElement("key");
keySerializer.Serialize(writer, key, ns); // Added ns in this call
writer.WriteEndElement();
writer.WriteStartElement("value");
TValue value = this[key];
valueSerializer.Serialize(writer, value, ns); // Added ns in this call
writer.WriteEndElement();
writer.WriteEndElement();
}
}
}
}