Initial commit

This commit is contained in:
Holger Boerchers
2018-03-21 20:07:40 +01:00
commit d383f0ef1c
77 changed files with 7050 additions and 0 deletions

6
AppStubEx/App.config Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup>
</configuration>

19
AppStubEx/AppEntry.cs Normal file
View File

@ -0,0 +1,19 @@
using System;
using System.IO;
namespace Katteker.AppStub
{
public class AppEntry : IComparable<AppEntry>
{
public AppEntry(DirectoryInfo info)
{
DirInfo = info;
Version = SemanticVersion.Parse(info.Name.Replace("app-", ""));
}
public SemanticVersion Version { get; }
public DirectoryInfo DirInfo { get; }
public int CompareTo(AppEntry other) => Version.CompareTo(other.Version);
}
}

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{AF7579CC-C0B2-4E5A-B052-00D2991DC715}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Katteker.AppStubEx</RootNamespace>
<AssemblyName>AppStubEx</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.ServiceProcess" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="AppEntry.cs" />
<Compile Include="IniFile.cs" />
<Compile Include="InstallerUx.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="InstallerUx.designer.cs">
<DependentUpon>InstallerUx.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SemanticVersion.cs" />
<Compile Include="Taskbar.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="InstallerUx.resx">
<DependentUpon>InstallerUx.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

50
AppStubEx/IniFile.cs Normal file
View File

@ -0,0 +1,50 @@
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
namespace Katteker.AppStub
{
public class IniFile // revision 11
{
private readonly FileInfo _path;
private readonly string _exe = Assembly.GetExecutingAssembly().GetName().Name;
[DllImport("kernel32", CharSet = CharSet.Unicode)]
private static extern long WritePrivateProfileString(string section, string key, string value, string filePath);
[DllImport("kernel32", CharSet = CharSet.Unicode)]
private static extern int GetPrivateProfileString(string section, string key, string Default, StringBuilder retVal, int size, string filePath);
public IniFile(string iniPath = null)
{
_path = new FileInfo(iniPath ?? _exe + ".ini");
}
public string Read(string key, string section = null)
{
var retVal = new StringBuilder(255);
GetPrivateProfileString(section ?? _exe, key, "", retVal, 255, _path.FullName);
return retVal.ToString();
}
public void Write(string key, string value, string section = null)
{
WritePrivateProfileString(section ?? _exe, key, value, _path.FullName);
}
public void DeleteKey(string key, string section = null)
{
Write(key, null, section ?? _exe);
}
public void DeleteSection(string section = null)
{
Write(null, null, section ?? _exe);
}
public bool Exists => _path.Exists;
public bool KeyExists(string key, string section = null) => Read(key, section).Length > 0;
}
}

73
AppStubEx/InstallerUx.cs Normal file
View File

@ -0,0 +1,73 @@
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Katteker.AppStub
{
public sealed partial class InstallerUx : Form
{
private int _autoCloseCountdown = 10;
public InstallerUx(string appName)
{
Font = SystemFonts.MessageBoxFont;
InitializeComponent();
SetLocationAndShow();
this.appName.Text = appName;
}
private void SetLocationAndShow()
{
var taskBar = new Taskbar();
switch (taskBar.Position)
{
case TaskbarPosition.Unknown:
break;
case TaskbarPosition.Left:
Location = new Point(taskBar.Bounds.Left + taskBar.Bounds.Width, taskBar.Bounds.Bottom - Size.Height);
break;
case TaskbarPosition.Top:
Location = new Point(taskBar.Bounds.Right - Size.Width, taskBar.Bounds.Bottom);
break;
case TaskbarPosition.Right:
Location = new Point(taskBar.Bounds.Left - Size.Width, taskBar.Bounds.Bottom - Size.Height);
break;
case TaskbarPosition.Bottom:
Location = new Point(taskBar.Bounds.Right - Size.Width, taskBar.Bounds.Top - Size.Height);
break;
default:
break;
}
Show();
}
private void closeBtn_Click(object sender, EventArgs e)
{
Close();
}
private void installBtn_Click(object sender, EventArgs e)
{
_autoCloseCountdown = 0;
MessageBox.Show("Hallo Welt");
}
private void autoCloseTimer_Tick(object sender, EventArgs e)
{
switch (_autoCloseCountdown)
{
case 1:
Close();
break;
case 0:
countDownLbl.Text = string.Empty;
autoCloseTimer.Enabled = false;
break;
default:
countDownLbl.Tag = --_autoCloseCountdown;
countDownLbl.Text = _autoCloseCountdown.ToString();
break;
}
}
}
}

149
AppStubEx/InstallerUx.designer.cs generated Normal file
View File

@ -0,0 +1,149 @@
namespace Katteker.AppStub
{
sealed partial class InstallerUx
{
/// <summary>
/// Erforderliche Designervariable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Verwendete Ressourcen bereinigen.
/// </summary>
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Vom Windows Form-Designer generierter Code
/// <summary>
/// Erforderliche Methode für die Designerunterstützung.
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.closeBtn = new System.Windows.Forms.Button();
this.installBtn = new System.Windows.Forms.Button();
this.messageLbl = new System.Windows.Forms.Label();
this.appName = new System.Windows.Forms.Label();
this.countDownLbl = new System.Windows.Forms.Label();
this.autoCloseTimer = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// closeBtn
//
this.closeBtn.AutoSize = true;
this.closeBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.closeBtn.FlatAppearance.BorderSize = 0;
this.closeBtn.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(122)))), ((int)(((byte)(204)))));
this.closeBtn.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(63)))), ((int)(((byte)(63)))), ((int)(((byte)(65)))));
this.closeBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.closeBtn.Font = new System.Drawing.Font("Marlett", 10F);
this.closeBtn.Location = new System.Drawing.Point(249, 0);
this.closeBtn.Margin = new System.Windows.Forms.Padding(0);
this.closeBtn.Name = "closeBtn";
this.closeBtn.Size = new System.Drawing.Size(31, 26);
this.closeBtn.TabIndex = 1;
this.closeBtn.TabStop = false;
this.closeBtn.Text = "r";
this.closeBtn.UseVisualStyleBackColor = true;
this.closeBtn.Click += new System.EventHandler(this.closeBtn_Click);
//
// installBtn
//
this.installBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.installBtn.FlatAppearance.BorderSize = 0;
this.installBtn.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(122)))), ((int)(((byte)(204)))));
this.installBtn.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(63)))), ((int)(((byte)(63)))), ((int)(((byte)(65)))));
this.installBtn.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.installBtn.Location = new System.Drawing.Point(192, 59);
this.installBtn.Margin = new System.Windows.Forms.Padding(0);
this.installBtn.Name = "installBtn";
this.installBtn.Size = new System.Drawing.Size(77, 30);
this.installBtn.TabIndex = 2;
this.installBtn.TabStop = false;
this.installBtn.Text = "Install";
this.installBtn.UseVisualStyleBackColor = true;
this.installBtn.Click += new System.EventHandler(this.installBtn_Click);
//
// messageLbl
//
this.messageLbl.AutoSize = true;
this.messageLbl.Location = new System.Drawing.Point(11, 68);
this.messageLbl.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
this.messageLbl.Name = "messageLbl";
this.messageLbl.Size = new System.Drawing.Size(93, 13);
this.messageLbl.TabIndex = 3;
this.messageLbl.Text = "Upgrade available";
//
// appName
//
this.appName.AutoSize = true;
this.appName.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.appName.Location = new System.Drawing.Point(13, 13);
this.appName.Name = "appName";
this.appName.Size = new System.Drawing.Size(80, 20);
this.appName.TabIndex = 4;
this.appName.Text = "AppName";
//
// countDownLbl
//
this.countDownLbl.AutoSize = true;
this.countDownLbl.BackColor = System.Drawing.Color.Transparent;
this.countDownLbl.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.countDownLbl.ForeColor = System.Drawing.SystemColors.ControlDark;
this.countDownLbl.Location = new System.Drawing.Point(229, 5);
this.countDownLbl.Name = "countDownLbl";
this.countDownLbl.Size = new System.Drawing.Size(24, 17);
this.countDownLbl.TabIndex = 5;
this.countDownLbl.Tag = 10;
this.countDownLbl.Text = "10";
this.countDownLbl.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// autoCloseTimer
//
this.autoCloseTimer.Enabled = true;
this.autoCloseTimer.Interval = 1000;
this.autoCloseTimer.Tick += new System.EventHandler(this.autoCloseTimer_Tick);
//
// InstallerUx
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(48)))));
this.ClientSize = new System.Drawing.Size(278, 98);
this.ControlBox = false;
this.Controls.Add(this.countDownLbl);
this.Controls.Add(this.appName);
this.Controls.Add(this.messageLbl);
this.Controls.Add(this.installBtn);
this.Controls.Add(this.closeBtn);
this.ForeColor = System.Drawing.SystemColors.Control;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Location = new System.Drawing.Point(30, 0);
this.Name = "InstallerUx";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
this.TopMost = true;
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button closeBtn;
private System.Windows.Forms.Button installBtn;
private System.Windows.Forms.Label messageLbl;
private System.Windows.Forms.Label appName;
private System.Windows.Forms.Label countDownLbl;
private System.Windows.Forms.Timer autoCloseTimer;
}
}

126
AppStubEx/InstallerUx.resx Normal file
View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="autoCloseTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>167, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>87</value>
</metadata>
</root>

102
AppStubEx/Program.cs Normal file
View File

@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Katteker.AppStub
{
internal class Program
{
private Program()
{
CurrentDir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
ConfigFile = new IniFile(Path.Combine(CurrentDir.FullName, "app.ini"));
}
private DirectoryInfo CurrentDir { get; }
private IniFile ConfigFile { get; }
private Process MainProcess { get; set; }
[STAThread]
private static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var p = new Program();
p.Run(args);
}
private void Run(string[] args)
{
StartExecutable(args);
StartUpdateInfo();
}
private static void StartUpdateInfo()
{
Application.Run(new InstallerUx("TestProgramm"));
}
private void StartExecutable(string[] args)
{
var dirEntries = CurrentDir.EnumerateDirectories().Where(x => x.Name.StartsWith("app-"))
.Select(x => new AppEntry(x)).ToList();
var latestVersion = dirEntries.OrderByDescending(x => x).FirstOrDefault();
if (latestVersion != null && ConfigFile.Exists)
{
try
{
var executable = ConfigFile.Read("Executable", "Main");
var a = args.Aggregate(string.Empty, (current, s) => current + s + " ").TrimEnd(' ');
MainProcess = new Process
{
StartInfo =
new ProcessStartInfo($"{latestVersion.DirInfo.FullName}\\{executable}")
{
Arguments = a,
WorkingDirectory = latestVersion.DirInfo.FullName,
UseShellExecute = false
}
};
MainProcess.Start();
Task.Run(() =>
DeleteOldVersionDirectories(dirEntries.Where(x =>
x.DirInfo.Name != latestVersion.DirInfo.Name)));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
{
MessageBox.Show("Error, File not found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private static void DeleteOldVersionDirectories(IEnumerable<AppEntry> dirEntries)
{
#if !DEBUG
foreach (var directoryInfo in dirEntries)
{
try
{
directoryInfo.DirInfo.Delete(true);
}
catch (Exception)
{
// silently ignore
}
}
#endif
}
}
}

View File

@ -0,0 +1,42 @@
using System.Reflection;
using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
//[assembly: AssemblyTitle("AppStub")]
//[assembly: AssemblyDescription("")]
//[assembly: AssemblyConfiguration("")]
//[assembly: AssemblyCompany("")]
//[assembly: AssemblyProduct("AppStub")]
//[assembly: AssemblyCopyright("Copyright © 2016")]
//[assembly: AssemblyTrademark("")]
//[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird
[assembly: Guid("af7579cc-c0b2-4e5a-b052-00d2991dc715")]
[assembly: AssemblyTitle("Katteker.AppStubEx")]
[assembly: AssemblyDescription("Katteker.AppStubEx")]
[assembly: AssemblyCompany("Holger Börchers")]
[assembly: AssemblyProduct("Katteker.AppStubEx")]
[assembly: AssemblyCopyright("Holger Börchers")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden.
// übernehmen, indem Sie "*" eingeben:
// [assembly: AssemblyVersion("1.0.*")]
//[assembly: AssemblyVersion("1.0.0.0")]
//[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,268 @@
using System;
using System.Text.RegularExpressions;
namespace Katteker.AppStub
{
/// <summary>
/// A hybrid implementation of SemVer that supports semantic versioning as described at http://semver.org while not
/// strictly enforcing it to
/// allow older 4-digit versioning schemes to continue working.
/// </summary>
[Serializable]
//[TypeConverter(typeof(SemanticVersionTypeConverter))]
public sealed class SemanticVersion : IComparable, IComparable<SemanticVersion>, IEquatable<SemanticVersion>
{
private const RegexOptions Flags =
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture;
private static readonly Regex SemanticVersionRegex =
new Regex(@"^(?<Version>\d+(\s*\.\s*\d+){0,3})(?<Release>-[a-z][0-9a-z-]*)?$", Flags);
private static readonly Regex StrictSemanticVersionRegex =
new Regex(@"^(?<Version>\d+(\.\d+){2})(?<Release>-[a-z][0-9a-z-]*)?$", Flags);
private readonly string _originalString;
public SemanticVersion(string version)
: this(Parse(version))
{
// The constructor normalizes the version string so that it we do not need to normalize it every time we need to operate on it.
// The original string represents the original form in which the version is represented to be used when printing.
_originalString = version;
}
public SemanticVersion(int major, int minor, int build, int revision)
: this(new Version(major, minor, build, revision))
{
}
public SemanticVersion(int major, int minor, int build, string specialVersion)
: this(new Version(major, minor, build), specialVersion)
{
}
public SemanticVersion(Version version)
: this(version, string.Empty)
{
}
public SemanticVersion(Version version, string specialVersion)
: this(version, specialVersion, null)
{
}
private SemanticVersion(Version version, string specialVersion, string originalString)
{
if (version == null)
throw new ArgumentNullException(nameof(version));
Version = NormalizeVersionValue(version);
SpecialVersion = specialVersion ?? string.Empty;
_originalString = string.IsNullOrEmpty(originalString)
? version + (!string.IsNullOrEmpty(specialVersion) ? '-' + specialVersion : null)
: originalString;
}
internal SemanticVersion(SemanticVersion semVer)
{
_originalString = semVer.ToString();
Version = semVer.Version;
SpecialVersion = semVer.SpecialVersion;
}
/// <summary>
/// Gets the normalized version portion.
/// </summary>
public Version Version { get; }
/// <summary>
/// Gets the optional special version.
/// </summary>
public string SpecialVersion { get; }
public int CompareTo(object obj)
{
if (ReferenceEquals(obj, null))
return 1;
var other = obj as SemanticVersion;
if (other == null)
throw new ArgumentException("Type Must Be A Semantic Version", nameof(obj));
return CompareTo(other);
}
public int CompareTo(SemanticVersion other)
{
if (ReferenceEquals(other, null))
return 1;
var result = Version.CompareTo(other.Version);
if (result != 0)
return result;
var empty = string.IsNullOrEmpty(SpecialVersion);
var otherEmpty = string.IsNullOrEmpty(other.SpecialVersion);
if (empty && otherEmpty)
return 0;
if (empty)
return 1;
if (otherEmpty)
return -1;
return StringComparer.OrdinalIgnoreCase.Compare(SpecialVersion, other.SpecialVersion);
}
public bool Equals(SemanticVersion other)
{
return !ReferenceEquals(null, other) &&
Version.Equals(other.Version) &&
SpecialVersion.Equals(other.SpecialVersion, StringComparison.OrdinalIgnoreCase);
}
public string[] GetOriginalVersionComponents()
{
if (!string.IsNullOrEmpty(_originalString))
{
// search the start of the SpecialVersion part, if any
var dashIndex = _originalString.IndexOf('-');
var original = dashIndex != -1 ? _originalString.Substring(0, dashIndex) : _originalString;
return SplitAndPadVersionString(original);
}
return SplitAndPadVersionString(Version.ToString());
}
private static string[] SplitAndPadVersionString(string version)
{
var a = version.Split('.');
if (a.Length == 4)
{
return a;
}
// if 'a' has less than 4 elements, we pad the '0' at the end
// to make it 4.
var b = new string[4] {"0", "0", "0", "0"};
Array.Copy(a, 0, b, 0, a.Length);
return b;
}
/// <summary>
/// Parses a version string using loose semantic versioning rules that allows 2-4 version components followed by an
/// optional special version.
/// </summary>
public static SemanticVersion Parse(string version)
{
if (string.IsNullOrEmpty(version))
throw new ArgumentException(nameof(version));
if (!TryParse(version, out var semVer))
throw new ArgumentException("Invalid Version String", nameof(version));
return semVer;
}
/// <summary>
/// Parses a version string using loose semantic versioning rules that allows 2-4 version components followed by an
/// optional special version.
/// </summary>
public static bool TryParse(string version, out SemanticVersion value)
{
return TryParseInternal(version, SemanticVersionRegex, out value);
}
/// <summary>
/// Parses a version string using strict semantic versioning rules that allows exactly 3 components and an optional
/// special version.
/// </summary>
public static bool TryParseStrict(string version, out SemanticVersion value)
{
return TryParseInternal(version, StrictSemanticVersionRegex, out value);
}
private static bool TryParseInternal(string version, Regex regex, out SemanticVersion semVer)
{
semVer = null;
if (string.IsNullOrEmpty(version))
return false;
var match = regex.Match(version.Trim());
if (!match.Success || !Version.TryParse(match.Groups["Version"].Value, out var versionValue))
return false;
semVer = new SemanticVersion(NormalizeVersionValue(versionValue),
match.Groups["Release"].Value.TrimStart('-'), version.Replace(" ", ""));
return true;
}
/// <summary>
/// Attempts to parse the version token as a SemanticVersion.
/// </summary>
/// <returns>An instance of SemanticVersion if it parses correctly, null otherwise.</returns>
public static SemanticVersion ParseOptionalVersion(string version)
{
TryParse(version, out var semVer);
return semVer;
}
private static Version NormalizeVersionValue(Version version)
{
return new Version(version.Major,
version.Minor,
Math.Max(version.Build, 0),
Math.Max(version.Revision, 0));
}
public static bool operator ==(SemanticVersion version1, SemanticVersion version2)
{
if (ReferenceEquals(version1, null))
return ReferenceEquals(version2, null);
return version1.Equals(version2);
}
public static bool operator !=(SemanticVersion version1, SemanticVersion version2)
{
return !(version1 == version2);
}
public static bool operator <(SemanticVersion version1, SemanticVersion version2)
{
if (version1 == null)
throw new ArgumentNullException(nameof(version1));
return version1.CompareTo(version2) < 0;
}
public static bool operator <=(SemanticVersion version1, SemanticVersion version2)
{
return version1 == version2 || version1 < version2;
}
public static bool operator >(SemanticVersion version1, SemanticVersion version2)
{
if (version1 == null)
throw new ArgumentNullException(nameof(version1));
return version2 < version1;
}
public static bool operator >=(SemanticVersion version1, SemanticVersion version2)
{
return version1 == version2 || version1 > version2;
}
public override string ToString()
{
return _originalString;
}
public override bool Equals(object obj)
{
var semVer = obj as SemanticVersion;
return !ReferenceEquals(null, semVer) && Equals(semVer);
}
public override int GetHashCode()
{
var hashCode = Version.GetHashCode();
if (SpecialVersion != null)
hashCode = hashCode * 4567 + SpecialVersion.GetHashCode();
return hashCode;
}
}
}

117
AppStubEx/Taskbar.cs Normal file
View File

@ -0,0 +1,117 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace Katteker.AppStub
{
public enum TaskbarPosition
{
Unknown = -1,
Left,
Top,
Right,
Bottom
}
public sealed class Taskbar
{
private const string ClassName = "Shell_TrayWnd";
public Taskbar()
{
var taskbarHandle = User32.FindWindow(ClassName, null);
var data = new APPBARDATA
{
cbSize = (uint) Marshal.SizeOf(typeof(APPBARDATA)),
hWnd = taskbarHandle
};
var result = Shell32.SHAppBarMessage(ABM.GetTaskbarPos, ref data);
if (result == IntPtr.Zero)
throw new InvalidOperationException();
Position = (TaskbarPosition) data.uEdge;
Bounds = Rectangle.FromLTRB(data.rc.left, data.rc.top, data.rc.right, data.rc.bottom);
data.cbSize = (uint) Marshal.SizeOf(typeof(APPBARDATA));
result = Shell32.SHAppBarMessage(ABM.GetState, ref data);
var state = result.ToInt32();
AlwaysOnTop = (state & ABS.AlwaysOnTop) == ABS.AlwaysOnTop;
AutoHide = (state & ABS.Autohide) == ABS.Autohide;
}
public Rectangle Bounds { get; }
public TaskbarPosition Position { get; private set; }
public Point Location => Bounds.Location;
public Size Size => Bounds.Size;
//Always returns false under Windows 7
public bool AlwaysOnTop { get; private set; }
public bool AutoHide { get; private set; }
}
public enum ABM : uint
{
New = 0x00000000,
Remove = 0x00000001,
QueryPos = 0x00000002,
SetPos = 0x00000003,
GetState = 0x00000004,
GetTaskbarPos = 0x00000005,
Activate = 0x00000006,
GetAutoHideBar = 0x00000007,
SetAutoHideBar = 0x00000008,
WindowPosChanged = 0x00000009,
SetState = 0x0000000A
}
public enum ABE : uint
{
Left = 0,
Top = 1,
Right = 2,
Bottom = 3
}
public static class ABS
{
public const int Autohide = 0x0000001;
public const int AlwaysOnTop = 0x0000002;
}
public static class Shell32
{
[DllImport("shell32.dll", SetLastError = true)]
public static extern IntPtr SHAppBarMessage(ABM dwMessage, [In] ref APPBARDATA pData);
}
public static class User32
{
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}
[StructLayout(LayoutKind.Sequential)]
public struct APPBARDATA
{
public uint cbSize;
public IntPtr hWnd;
public uint uCallbackMessage;
public ABE uEdge;
public RECT rc;
public int lParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
}