Skip to content

Commit

Permalink
Prototyped version lookup for installed application items.
Browse files Browse the repository at this point in the history
Refactored error handling for XML errors to pave the way for validation of the applist.
  • Loading branch information
zacr committed Dec 6, 2006
1 parent 3adcc98 commit 4aa0b85
Show file tree
Hide file tree
Showing 12 changed files with 649 additions and 406 deletions.
6 changes: 4 additions & 2 deletions Changelog.txt
@@ -1,7 +1,9 @@
- Prototype version lookup for installed applist items.
- Add ability to parse empty XML elements. Slightly refactor XML error message collection. Add stubs for applist validation.
- Small error dialog on startup if your environment vars are bad in some way; keeps installpad from bombing out silently
- Added ability to edit an applications details by double clicking on it. (Craig Reynolds)
- refactored unit tests, embedded /data as a resource so the unit test dl can be run from anywhere (Zac Ruiz)
- helper methods for zip class (contains(), hasRootFolder()) (Zac Ruiz)
- Refactored unit tests, embedded /data as a resource so the unit test dl can be run from anywhere (Zac Ruiz)
- Helper methods for zip class (contains(), hasRootFolder()) (Zac Ruiz)
- Create a root folder for the zip if it doesn't have one, instead of extracting tons of files to c:\program files (Zac Ruiz)
- Bugfix: If there is an error writing our applist back to disk, backup the original file and then restore it so it is not lost (Craig Reynolds)
- Turned on double buffering for the ApplicationListItem control. Makes resizing a little faster.
Expand Down
7 changes: 6 additions & 1 deletion InstallPad.csproj
Expand Up @@ -37,11 +37,15 @@
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="src\ApplicationItemOptions.cs" />
<Compile Include="src\InstallationOptions.cs" />
<Compile Include="src\Persistable.cs" />
<Compile Include="Settings.cs" />
<Compile Include="src\about\AboutDialog.cs">
<SubType>Form</SubType>
Expand Down Expand Up @@ -85,7 +89,7 @@
<DependentUpon>AppListErrorDialog.cs</DependentUpon>
</Compile>
<Compile Include="src\ControlList.cs">
<SubType>Component</SubType>
<SubType>UserControl</SubType>
</Compile>
<Compile Include="src\ControlList.Designer.cs">
<DependentUpon>ControlList.cs</DependentUpon>
Expand Down Expand Up @@ -171,6 +175,7 @@
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="src\ProxyOptions.cs" />
<Compile Include="src\RemoteVersionChecker.cs" />
<Compile Include="src\Zip.cs" />
</ItemGroup>
Expand Down
4 changes: 3 additions & 1 deletion src/ApplicationDialog.cs
Expand Up @@ -247,7 +247,9 @@ public void ModifyApplicationItemFromDialog(ApplicationItem item)
item.Options.DownloadLatestVersion = this.DownloadLatestVersion;
item.Options.SilentInstall = this.SilentInstall;
item.Options.InstallerArguments = this.InstallerArguments;
item.Options.Checked = this.Checked;
item.Options.Checked = this.Checked;

item.DetectVersion();

// Setting InstallationRoot is disabled for now until the rules are decided.
// Could allow setting Options, but probably wouldn't want to allow setting
Expand Down
255 changes: 85 additions & 170 deletions src/ApplicationItem.cs
Expand Up @@ -14,13 +14,15 @@
using System.Text;
using System.Xml;

using Microsoft.Win32;

namespace InstallPad
{
/// <summary>
/// An application item describes an application - its name, filename, and download options.
/// It can also attempt to check and find the latest version of the application online.
/// </summary>
public class ApplicationItem
public class ApplicationItem : Persistable
{
string name;

Expand Down Expand Up @@ -118,6 +120,58 @@ public string Version
set { version = value; }
}

string detectedVersion = string.Empty;
public string DetectedVersion
{
get { return detectedVersion; }
}

public bool DetectVersion()
{
RegistryKey UninstallKey = Registry.LocalMachine;
UninstallKey = UninstallKey.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", true);

try
{
// Iterate subkeys... each subkey is an installed package
foreach (string subkeyname in UninstallKey.GetSubKeyNames())
{
RegistryKey pkg = Registry.LocalMachine;
pkg = UninstallKey.OpenSubKey(subkeyname, true);

try
{
string displayname = pkg.GetValue("DisplayName").ToString();

if (displayname.Contains(name) || name.Contains(displayname))
{
try
{
detectedVersion = "v"+pkg.GetValue("DisplayVersion").ToString();
return true;
}
catch
{
detectedVersion = "found but not found";
}
}
}
catch
{
}
finally
{
pkg.Close();
}
}
}
finally
{
UninstallKey.Close();
}
return false;
}

ApplicationItemOptions options = new ApplicationItemOptions();

public ApplicationItemOptions Options
Expand Down Expand Up @@ -292,7 +346,7 @@ private static bool IsDigit(char c)
}

#region Xml methods
public static ApplicationItem FromXml(XmlReader reader, List<string> errors)
public static ApplicationItem FromXml(XmlReader reader)
{
ApplicationItem item = new ApplicationItem();

Expand All @@ -303,213 +357,74 @@ public static ApplicationItem FromXml(XmlReader reader, List<string> errors)
case XmlNodeType.Element:
if (reader.Name == "Name")
{
item.Name = reader.ReadString();
reader.ReadEndElement();
if (reader.IsEmptyElement == false)
{
item.Name = reader.ReadString();
reader.ReadEndElement();
}
}
else if (reader.Name == "FileUrl")
{
item.DownloadUrl = reader.ReadString();
reader.ReadEndElement();
if (reader.IsEmptyElement == false)
{
item.DownloadUrl = reader.ReadString();
reader.ReadEndElement();
}
}
else if (reader.Name == "Comment")
{
item.Comment = reader.ReadString();
reader.ReadEndElement();
if (reader.IsEmptyElement == false)
{
item.Comment = reader.ReadString();
reader.ReadEndElement();
}
}
else if (reader.Name == "Options")
{
item.Options = ApplicationItemOptions.FromXml(reader, errors);
item.Options = ApplicationItemOptions.FromXml(reader);
item.XmlErrors.AddRange(item.options.XmlErrors);
}

else
{
errors.Add(
item.XmlErrors.Add(
String.Format("Unrecognized element in an application: \"{0}\"", reader.Name));
}
break;
case XmlNodeType.EndElement:
if (reader.Name=="Application")
if (reader.Name == "Application")
{
item.DetectVersion();
return item;
}
break;
}
}
item.DetectVersion();
return item;
}

public void WriteXml(XmlWriter writer)
{
writer.WriteStartElement("Application");
writer.WriteElementString("Name", this.Name);
writer.WriteElementString("FileUrl", this.DownloadUrl);
writer.WriteElementString("FileUrl", this.DownloadUrl);

if (this.Comment != null && this.Comment.Length > 0)
{
writer.WriteElementString("Comment", this.Comment);
}

this.Options.WriteXml(writer);

writer.WriteEndElement();
}
#endregion
}

public class ApplicationItemOptions
{
#region XML methods
public static ApplicationItemOptions FromXml(XmlReader reader, List<string> errors)
#region Persistable
public override bool Validate()
{
ApplicationItemOptions options = new ApplicationItemOptions();

// If this is an empty option element then don't read further
if (reader.IsEmptyElement)
return options;

while (reader.Read())
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "DownloadLatestVersion")
{
options.DownloadLatestVersion = true;
}
else if (reader.Name == "SilentInstall")
{
options.SilentInstall = true;
}
else if (reader.Name == "PostInstallScript")
{
options.PostInstallScript = reader.ReadString().Trim();
reader.ReadEndElement();
}
else if (reader.Name == "InstallationRoot")
{
options.InstallationRoot = reader.ReadString();
reader.ReadEndElement();
}
else if (reader.Name == "AlternateFileUrl")
{
options.AlternateFileUrls.Add(reader.ReadString());
reader.ReadEndElement();
}
else if (reader.Name == "InstallerArguments")
{
options.InstallerArguments = reader.ReadString();
reader.ReadEndElement();
}
else if (reader.Name == "Checked")
{
bool value=true;
try
{
value = bool.Parse(reader.ReadString());
}
catch (Exception)
{
}
options.Checked = value;
}


else
errors.Add(String.Format("Unrecognized application option: \"{0}\"", reader.Name));

break;
case XmlNodeType.EndElement:
// Only stop reading when we've hit the end of the Options element
if (reader.Name == "Options")
return options;
break;
}
}
return options;
}
public void WriteXml(XmlWriter writer)
{
// Only write if there is an option set. This could be more elegant.
if ((InstallerArguments != null && InstallerArguments.Length > 0) ||
(PostInstallScript != null && PostInstallScript.Length > 0) ||
this.SilentInstall || this.DownloadLatestVersion || !this.Checked)
{

writer.WriteStartElement("Options");
if (this.DownloadLatestVersion)
writer.WriteElementString("DownloadLatestVersion", "");
if (this.SilentInstall)
writer.WriteElementString("SilentInstall", "");

if (InstallerArguments != null && InstallerArguments.Length > 0)
writer.WriteElementString("InstallerArguments", this.InstallerArguments);
if (PostInstallScript != null && PostInstallScript.Length > 0)
writer.WriteElementString("PostInstallScript", this.PostInstallScript);
if (InstallationRoot.Length > 0)
writer.WriteElementString("InstallationRoot", this.InstallationRoot);
foreach (string s in AlternateFileUrls)
{
if (s.Length > 0)
writer.WriteElementString("AlternateFileUrl", s);
}
if (Checked==false)
writer.WriteElementString("Checked", "false");

writer.WriteEndElement();
}
return true;
}
#endregion

/// <summary>
/// You can specify in the applist whether this application should be checked by default
/// </summary>
private bool checkEnabled = true;

public bool Checked
{
get { return checkEnabled; }
set { checkEnabled = value; }
}

private bool downloadLatestVersion=false;

public bool DownloadLatestVersion
{
get { return downloadLatestVersion; }
set { downloadLatestVersion = value; }
}

private bool silentInstall = false;
public bool SilentInstall
{
get { return silentInstall; }
set { silentInstall = value; }
}
private string installerArguments=null;

public string InstallerArguments
{
get { return installerArguments; }
set { installerArguments = value; }
}
private string postInstallScript=null;

public string PostInstallScript
{
get { return postInstallScript; }
set { postInstallScript = value; }
}

private string installationRoot = string.Empty;

public string InstallationRoot
{
get { return installationRoot; }
set { installationRoot = value; }
}

private List<string> alternateFileUrls = new List<string>();

public List<string> AlternateFileUrls
{
get { return alternateFileUrls; }
set { alternateFileUrls = value; }
}
}
}

0 comments on commit 4aa0b85

Please sign in to comment.