diff --git a/.gitignore b/.gitignore index 3e759b7..1f7a27e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore +# SVN +.svn* + # User-specific files *.suo *.user diff --git a/Config.cs b/Config.cs new file mode 100644 index 0000000..5ff1e48 --- /dev/null +++ b/Config.cs @@ -0,0 +1,59 @@ +using Microsoft.WindowsAPICodePack.Dialogs; +using System; +using System.IO; + +namespace SystemTrayMenu +{ + public class Config + { + public static string Language = "en"; + + public static string Path + { + get + { + return Properties.Settings.Default.PathDirectory; + } + } + + public static bool LoadOrSetByUser() + { + bool pathOK = Directory.Exists( + Properties.Settings.Default.PathDirectory); + if (!pathOK) + { + pathOK = SetFolderByUser(); + } + return pathOK; + } + + public static bool SetFolderByUser() + { + bool pathOK = false; + bool userAborted = false; + CommonOpenFileDialog dialog = new CommonOpenFileDialog(); + dialog.InitialDirectory = Path; + dialog.IsFolderPicker = true; + do + { + if (dialog.ShowDialog() == CommonFileDialogResult.Ok) + { + if (Directory.Exists(dialog.FileName)) + { + pathOK = true; + Properties.Settings.Default.PathDirectory = + dialog.FileName; + Properties.Settings.Default.Save(); + } + } + else + { + userAborted = true; + } + } + while (!pathOK && !userAborted); + + return pathOK; + } + } +} diff --git a/Controls/AboutBox.Designer.cs b/Controls/AboutBox.Designer.cs new file mode 100644 index 0000000..bd3ca39 --- /dev/null +++ b/Controls/AboutBox.Designer.cs @@ -0,0 +1,526 @@ +namespace SystemTrayMenu.Controls +{ + partial class AboutBox + { + /// + /// 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() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutBox)); + this.buttonDetails = new System.Windows.Forms.Button(); + this.ImagePictureBox = new System.Windows.Forms.PictureBox(); + this.AppDateLabel = new System.Windows.Forms.Label(); + this.buttonSystemInfo = new System.Windows.Forms.Button(); + this.AppCopyrightLabel = new System.Windows.Forms.Label(); + this.AppVersionLabel = new System.Windows.Forms.Label(); + this.AppDescriptionLabel = new System.Windows.Forms.Label(); + this.GroupBox1 = new System.Windows.Forms.GroupBox(); + this.AppTitleLabel = new System.Windows.Forms.Label(); + this.buttonOk = new System.Windows.Forms.Button(); + this.MoreRichTextBox = new System.Windows.Forms.RichTextBox(); + this.TabPanelDetails = new System.Windows.Forms.TabControl(); + this.TabPageApplication = new System.Windows.Forms.TabPage(); + this.AppInfoListView = new System.Windows.Forms.ListView(); + this.colKey = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.colValue = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.TabPageAssemblies = new System.Windows.Forms.TabPage(); + this.AssemblyInfoListView = new System.Windows.Forms.ListView(); + this.colAssemblyName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.colAssemblyVersion = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.colAssemblyBuilt = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.colAssemblyCodeBase = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.TabPageAssemblyDetails = new System.Windows.Forms.TabPage(); + this.AssemblyDetailsListView = new System.Windows.Forms.ListView(); + this.ColumnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.ColumnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.AssemblyNamesComboBox = new System.Windows.Forms.ComboBox(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + ((System.ComponentModel.ISupportInitialize)(this.ImagePictureBox)).BeginInit(); + this.TabPanelDetails.SuspendLayout(); + this.TabPageApplication.SuspendLayout(); + this.TabPageAssemblies.SuspendLayout(); + this.TabPageAssemblyDetails.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.tableLayoutPanel4.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); + this.SuspendLayout(); + // + // buttonDetails + // + this.buttonDetails.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonDetails.AutoSize = true; + this.buttonDetails.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.buttonDetails.Location = new System.Drawing.Point(148, 5); + this.buttonDetails.Margin = new System.Windows.Forms.Padding(5); + this.buttonDetails.MinimumSize = new System.Drawing.Size(133, 40); + this.buttonDetails.Name = "buttonDetails"; + this.buttonDetails.Size = new System.Drawing.Size(133, 40); + this.buttonDetails.TabIndex = 25; + this.buttonDetails.Text = "Details"; + this.buttonDetails.Click += new System.EventHandler(this.DetailsButton_Click); + // + // ImagePictureBox + // + this.ImagePictureBox.BackgroundImage = global::SystemTrayMenu.Properties.Resources.STM; + this.ImagePictureBox.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.ImagePictureBox.Location = new System.Drawing.Point(5, 5); + this.ImagePictureBox.Margin = new System.Windows.Forms.Padding(5); + this.ImagePictureBox.Name = "ImagePictureBox"; + this.ImagePictureBox.Size = new System.Drawing.Size(68, 63); + this.ImagePictureBox.TabIndex = 24; + this.ImagePictureBox.TabStop = false; + // + // AppDateLabel + // + this.AppDateLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.AppDateLabel.AutoSize = true; + this.AppDateLabel.Location = new System.Drawing.Point(5, 140); + this.AppDateLabel.Margin = new System.Windows.Forms.Padding(5); + this.AppDateLabel.Name = "AppDateLabel"; + this.AppDateLabel.Size = new System.Drawing.Size(668, 25); + this.AppDateLabel.TabIndex = 23; + this.AppDateLabel.Text = "Built on %builddate%"; + // + // buttonSystemInfo + // + this.buttonSystemInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonSystemInfo.AutoSize = true; + this.buttonSystemInfo.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.buttonSystemInfo.Location = new System.Drawing.Point(5, 5); + this.buttonSystemInfo.Margin = new System.Windows.Forms.Padding(5); + this.buttonSystemInfo.MinimumSize = new System.Drawing.Size(133, 40); + this.buttonSystemInfo.Name = "buttonSystemInfo"; + this.buttonSystemInfo.Size = new System.Drawing.Size(133, 40); + this.buttonSystemInfo.TabIndex = 22; + this.buttonSystemInfo.Text = "System Info"; + this.buttonSystemInfo.Visible = false; + this.buttonSystemInfo.Click += new System.EventHandler(this.SysInfoButton_Click); + // + // AppCopyrightLabel + // + this.AppCopyrightLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.AppCopyrightLabel.AutoSize = true; + this.AppCopyrightLabel.Location = new System.Drawing.Point(5, 175); + this.AppCopyrightLabel.Margin = new System.Windows.Forms.Padding(5); + this.AppCopyrightLabel.Name = "AppCopyrightLabel"; + this.AppCopyrightLabel.Size = new System.Drawing.Size(668, 25); + this.AppCopyrightLabel.TabIndex = 21; + this.AppCopyrightLabel.Text = "Copyright © %year%, %company%"; + // + // AppVersionLabel + // + this.AppVersionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.AppVersionLabel.AutoSize = true; + this.AppVersionLabel.Location = new System.Drawing.Point(5, 105); + this.AppVersionLabel.Margin = new System.Windows.Forms.Padding(5); + this.AppVersionLabel.Name = "AppVersionLabel"; + this.AppVersionLabel.Size = new System.Drawing.Size(668, 25); + this.AppVersionLabel.TabIndex = 20; + this.AppVersionLabel.Text = "Version %version%"; + // + // AppDescriptionLabel + // + this.AppDescriptionLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.AppDescriptionLabel.AutoSize = true; + this.AppDescriptionLabel.Location = new System.Drawing.Point(5, 40); + this.AppDescriptionLabel.Margin = new System.Windows.Forms.Padding(5); + this.AppDescriptionLabel.Name = "AppDescriptionLabel"; + this.AppDescriptionLabel.Size = new System.Drawing.Size(142, 25); + this.AppDescriptionLabel.TabIndex = 19; + this.AppDescriptionLabel.Text = "%description%"; + // + // GroupBox1 + // + this.GroupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.GroupBox1.Location = new System.Drawing.Point(5, 91); + this.GroupBox1.Margin = new System.Windows.Forms.Padding(5); + this.GroupBox1.Name = "GroupBox1"; + this.GroupBox1.Padding = new System.Windows.Forms.Padding(5); + this.GroupBox1.Size = new System.Drawing.Size(668, 4); + this.GroupBox1.TabIndex = 18; + this.GroupBox1.TabStop = false; + this.GroupBox1.Text = "GroupBox1"; + // + // AppTitleLabel + // + this.AppTitleLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.AppTitleLabel.AutoSize = true; + this.AppTitleLabel.Location = new System.Drawing.Point(5, 5); + this.AppTitleLabel.Margin = new System.Windows.Forms.Padding(5); + this.AppTitleLabel.Name = "AppTitleLabel"; + this.AppTitleLabel.Size = new System.Drawing.Size(142, 25); + this.AppTitleLabel.TabIndex = 17; + this.AppTitleLabel.Text = "%title%"; + // + // buttonOk + // + this.buttonOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOk.AutoSize = true; + this.buttonOk.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.buttonOk.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonOk.Location = new System.Drawing.Point(291, 5); + this.buttonOk.Margin = new System.Windows.Forms.Padding(5); + this.buttonOk.MinimumSize = new System.Drawing.Size(133, 40); + this.buttonOk.Name = "buttonOk"; + this.buttonOk.Size = new System.Drawing.Size(133, 40); + this.buttonOk.TabIndex = 16; + this.buttonOk.Text = "OK"; + // + // MoreRichTextBox + // + this.MoreRichTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.MoreRichTextBox.BackColor = System.Drawing.SystemColors.ControlLight; + this.MoreRichTextBox.Location = new System.Drawing.Point(5, 210); + this.MoreRichTextBox.Margin = new System.Windows.Forms.Padding(5); + this.MoreRichTextBox.Name = "MoreRichTextBox"; + this.MoreRichTextBox.ReadOnly = true; + this.MoreRichTextBox.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical; + this.MoreRichTextBox.Size = new System.Drawing.Size(668, 210); + this.MoreRichTextBox.TabIndex = 26; + this.MoreRichTextBox.Text = "%product% is %copyright%, %trademark%"; + this.MoreRichTextBox.LinkClicked += new System.Windows.Forms.LinkClickedEventHandler(this.MoreRichTextBox_LinkClicked); + // + // TabPanelDetails + // + this.TabPanelDetails.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TabPanelDetails.Controls.Add(this.TabPageApplication); + this.TabPanelDetails.Controls.Add(this.TabPageAssemblies); + this.TabPanelDetails.Controls.Add(this.TabPageAssemblyDetails); + this.TabPanelDetails.Location = new System.Drawing.Point(5, 430); + this.TabPanelDetails.Margin = new System.Windows.Forms.Padding(5); + this.TabPanelDetails.Name = "TabPanelDetails"; + this.TabPanelDetails.SelectedIndex = 0; + this.TabPanelDetails.Size = new System.Drawing.Size(668, 219); + this.TabPanelDetails.TabIndex = 27; + this.TabPanelDetails.Visible = false; + this.TabPanelDetails.SelectedIndexChanged += new System.EventHandler(this.TabPanelDetails_SelectedIndexChanged); + // + // TabPageApplication + // + this.TabPageApplication.Controls.Add(this.AppInfoListView); + this.TabPageApplication.Location = new System.Drawing.Point(4, 33); + this.TabPageApplication.Margin = new System.Windows.Forms.Padding(5); + this.TabPageApplication.Name = "TabPageApplication"; + this.TabPageApplication.Size = new System.Drawing.Size(660, 182); + this.TabPageApplication.TabIndex = 0; + this.TabPageApplication.Text = "Application"; + // + // AppInfoListView + // + this.AppInfoListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.colKey, + this.colValue}); + this.AppInfoListView.Dock = System.Windows.Forms.DockStyle.Fill; + this.AppInfoListView.FullRowSelect = true; + this.AppInfoListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.AppInfoListView.Location = new System.Drawing.Point(0, 0); + this.AppInfoListView.Margin = new System.Windows.Forms.Padding(5); + this.AppInfoListView.Name = "AppInfoListView"; + this.AppInfoListView.Size = new System.Drawing.Size(660, 182); + this.AppInfoListView.TabIndex = 16; + this.AppInfoListView.UseCompatibleStateImageBehavior = false; + this.AppInfoListView.View = System.Windows.Forms.View.Details; + // + // colKey + // + this.colKey.Text = "Application Key"; + this.colKey.Width = 120; + // + // colValue + // + this.colValue.Text = "Value"; + this.colValue.Width = 700; + // + // TabPageAssemblies + // + this.TabPageAssemblies.Controls.Add(this.AssemblyInfoListView); + this.TabPageAssemblies.Location = new System.Drawing.Point(4, 33); + this.TabPageAssemblies.Margin = new System.Windows.Forms.Padding(5); + this.TabPageAssemblies.Name = "TabPageAssemblies"; + this.TabPageAssemblies.Size = new System.Drawing.Size(660, 182); + this.TabPageAssemblies.TabIndex = 1; + this.TabPageAssemblies.Text = "Assemblies"; + // + // AssemblyInfoListView + // + this.AssemblyInfoListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.colAssemblyName, + this.colAssemblyVersion, + this.colAssemblyBuilt, + this.colAssemblyCodeBase}); + this.AssemblyInfoListView.Dock = System.Windows.Forms.DockStyle.Fill; + this.AssemblyInfoListView.FullRowSelect = true; + this.AssemblyInfoListView.Location = new System.Drawing.Point(0, 0); + this.AssemblyInfoListView.Margin = new System.Windows.Forms.Padding(5); + this.AssemblyInfoListView.MultiSelect = false; + this.AssemblyInfoListView.Name = "AssemblyInfoListView"; + this.AssemblyInfoListView.Size = new System.Drawing.Size(660, 182); + this.AssemblyInfoListView.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.AssemblyInfoListView.TabIndex = 13; + this.AssemblyInfoListView.UseCompatibleStateImageBehavior = false; + this.AssemblyInfoListView.View = System.Windows.Forms.View.Details; + this.AssemblyInfoListView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.AssemblyInfoListView_ColumnClick); + this.AssemblyInfoListView.DoubleClick += new System.EventHandler(this.AssemblyInfoListView_DoubleClick); + // + // colAssemblyName + // + this.colAssemblyName.Text = "Assembly"; + this.colAssemblyName.Width = 123; + // + // colAssemblyVersion + // + this.colAssemblyVersion.Text = "Version"; + this.colAssemblyVersion.Width = 100; + // + // colAssemblyBuilt + // + this.colAssemblyBuilt.Text = "Built"; + this.colAssemblyBuilt.Width = 130; + // + // colAssemblyCodeBase + // + this.colAssemblyCodeBase.Text = "CodeBase"; + this.colAssemblyCodeBase.Width = 750; + // + // TabPageAssemblyDetails + // + this.TabPageAssemblyDetails.Controls.Add(this.AssemblyDetailsListView); + this.TabPageAssemblyDetails.Controls.Add(this.AssemblyNamesComboBox); + this.TabPageAssemblyDetails.Location = new System.Drawing.Point(4, 33); + this.TabPageAssemblyDetails.Margin = new System.Windows.Forms.Padding(5); + this.TabPageAssemblyDetails.Name = "TabPageAssemblyDetails"; + this.TabPageAssemblyDetails.Size = new System.Drawing.Size(660, 182); + this.TabPageAssemblyDetails.TabIndex = 2; + this.TabPageAssemblyDetails.Text = "Assembly Details"; + // + // AssemblyDetailsListView + // + this.AssemblyDetailsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.ColumnHeader1, + this.ColumnHeader2}); + this.AssemblyDetailsListView.Dock = System.Windows.Forms.DockStyle.Fill; + this.AssemblyDetailsListView.FullRowSelect = true; + this.AssemblyDetailsListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.AssemblyDetailsListView.Location = new System.Drawing.Point(0, 32); + this.AssemblyDetailsListView.Margin = new System.Windows.Forms.Padding(5); + this.AssemblyDetailsListView.Name = "AssemblyDetailsListView"; + this.AssemblyDetailsListView.Size = new System.Drawing.Size(660, 150); + this.AssemblyDetailsListView.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.AssemblyDetailsListView.TabIndex = 19; + this.AssemblyDetailsListView.UseCompatibleStateImageBehavior = false; + this.AssemblyDetailsListView.View = System.Windows.Forms.View.Details; + // + // ColumnHeader1 + // + this.ColumnHeader1.Text = "Assembly Key"; + this.ColumnHeader1.Width = 120; + // + // ColumnHeader2 + // + this.ColumnHeader2.Text = "Value"; + this.ColumnHeader2.Width = 700; + // + // AssemblyNamesComboBox + // + this.AssemblyNamesComboBox.Dock = System.Windows.Forms.DockStyle.Top; + this.AssemblyNamesComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.AssemblyNamesComboBox.Location = new System.Drawing.Point(0, 0); + this.AssemblyNamesComboBox.Margin = new System.Windows.Forms.Padding(5); + this.AssemblyNamesComboBox.Name = "AssemblyNamesComboBox"; + this.AssemblyNamesComboBox.Size = new System.Drawing.Size(660, 32); + this.AssemblyNamesComboBox.Sorted = true; + this.AssemblyNamesComboBox.TabIndex = 18; + this.AssemblyNamesComboBox.SelectedIndexChanged += new System.EventHandler(this.AssemblyNamesComboBox_SelectedIndexChanged); + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.AutoSize = true; + this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel4, 0, 8); + this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.AppCopyrightLabel, 0, 4); + this.tableLayoutPanel1.Controls.Add(this.AppDateLabel, 0, 3); + this.tableLayoutPanel1.Controls.Add(this.GroupBox1, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.TabPanelDetails, 0, 7); + this.tableLayoutPanel1.Controls.Add(this.MoreRichTextBox, 0, 6); + this.tableLayoutPanel1.Controls.Add(this.AppVersionLabel, 0, 2); + this.tableLayoutPanel1.Location = new System.Drawing.Point(16, 12); + this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(4); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 9; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel1.Size = new System.Drawing.Size(678, 712); + this.tableLayoutPanel1.TabIndex = 28; + // + // tableLayoutPanel4 + // + this.tableLayoutPanel4.AutoSize = true; + this.tableLayoutPanel4.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel4.ColumnCount = 3; + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.Controls.Add(this.buttonSystemInfo, 0, 0); + this.tableLayoutPanel4.Controls.Add(this.buttonDetails, 1, 0); + this.tableLayoutPanel4.Controls.Add(this.buttonOk, 2, 0); + this.tableLayoutPanel4.Location = new System.Drawing.Point(4, 658); + this.tableLayoutPanel4.Margin = new System.Windows.Forms.Padding(4); + this.tableLayoutPanel4.Name = "tableLayoutPanel4"; + this.tableLayoutPanel4.RowCount = 1; + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel4.Size = new System.Drawing.Size(429, 50); + this.tableLayoutPanel4.TabIndex = 29; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.AutoSize = true; + this.tableLayoutPanel2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel2.ColumnCount = 2; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 548F)); + this.tableLayoutPanel2.Controls.Add(this.ImagePictureBox, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel3, 1, 0); + this.tableLayoutPanel2.Location = new System.Drawing.Point(4, 4); + this.tableLayoutPanel2.Margin = new System.Windows.Forms.Padding(4); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 1; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel2.Size = new System.Drawing.Size(626, 78); + this.tableLayoutPanel2.TabIndex = 29; + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.AutoSize = true; + this.tableLayoutPanel3.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel3.ColumnCount = 1; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.Controls.Add(this.AppTitleLabel, 0, 0); + this.tableLayoutPanel3.Controls.Add(this.AppDescriptionLabel, 0, 1); + this.tableLayoutPanel3.Location = new System.Drawing.Point(82, 4); + this.tableLayoutPanel3.Margin = new System.Windows.Forms.Padding(4); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.RowCount = 2; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel3.Size = new System.Drawing.Size(152, 70); + this.tableLayoutPanel3.TabIndex = 25; + // + // AboutBox + // + this.AutoScaleDimensions = new System.Drawing.SizeF(168F, 168F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.CancelButton = this.buttonOk; + this.ClientSize = new System.Drawing.Size(704, 861); + this.Controls.Add(this.tableLayoutPanel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Margin = new System.Windows.Forms.Padding(5); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AboutBox"; + this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "About %title%"; + this.Load += new System.EventHandler(this.AboutBox_Load); + this.Paint += new System.Windows.Forms.PaintEventHandler(this.AboutBox_Paint); + ((System.ComponentModel.ISupportInitialize)(this.ImagePictureBox)).EndInit(); + this.TabPanelDetails.ResumeLayout(false); + this.TabPageApplication.ResumeLayout(false); + this.TabPageAssemblies.ResumeLayout(false); + this.TabPageAssemblyDetails.ResumeLayout(false); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.tableLayoutPanel4.ResumeLayout(false); + this.tableLayoutPanel4.PerformLayout(); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.tableLayoutPanel3.ResumeLayout(false); + this.tableLayoutPanel3.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button buttonDetails; + private System.Windows.Forms.PictureBox ImagePictureBox; + private System.Windows.Forms.Label AppDateLabel; + private System.Windows.Forms.Button buttonSystemInfo; + private System.Windows.Forms.Label AppCopyrightLabel; + private System.Windows.Forms.Label AppVersionLabel; + private System.Windows.Forms.Label AppDescriptionLabel; + private System.Windows.Forms.GroupBox GroupBox1; + private System.Windows.Forms.Label AppTitleLabel; + private System.Windows.Forms.Button buttonOk; + internal System.Windows.Forms.RichTextBox MoreRichTextBox; + internal System.Windows.Forms.TabControl TabPanelDetails; + internal System.Windows.Forms.TabPage TabPageApplication; + internal System.Windows.Forms.ListView AppInfoListView; + internal System.Windows.Forms.ColumnHeader colKey; + internal System.Windows.Forms.ColumnHeader colValue; + internal System.Windows.Forms.TabPage TabPageAssemblies; + internal System.Windows.Forms.ListView AssemblyInfoListView; + internal System.Windows.Forms.ColumnHeader colAssemblyName; + internal System.Windows.Forms.ColumnHeader colAssemblyVersion; + internal System.Windows.Forms.ColumnHeader colAssemblyBuilt; + internal System.Windows.Forms.ColumnHeader colAssemblyCodeBase; + internal System.Windows.Forms.TabPage TabPageAssemblyDetails; + internal System.Windows.Forms.ListView AssemblyDetailsListView; + internal System.Windows.Forms.ColumnHeader ColumnHeader1; + internal System.Windows.Forms.ColumnHeader ColumnHeader2; + internal System.Windows.Forms.ComboBox AssemblyNamesComboBox; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; + } +} \ No newline at end of file diff --git a/Controls/AboutBox.cs b/Controls/AboutBox.cs new file mode 100644 index 0000000..9be8f61 --- /dev/null +++ b/Controls/AboutBox.cs @@ -0,0 +1,846 @@ +using Microsoft.Win32; +using System; +using System.Collections.Specialized; +using System.Drawing; +using System.IO; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Windows.Forms; + +namespace SystemTrayMenu.Controls +{ + /// + /// Generic, self-contained About Box dialog + /// + /// + /// Jeff Atwood + /// http://www.codinghorror.com + /// converted to C# by Scott Ferguson + /// http://www.forestmoon.com + /// + public partial class AboutBox : Form + { + public AboutBox() + { + InitializeComponent(); + buttonOk.Text = Program.Translate("buttonOk"); + buttonDetails.Text = Program.Translate("buttonDetails"); + buttonSystemInfo.Text = Program.Translate("buttonSystemInfo"); + } + + private bool _IsPainted = false; + private string _EntryAssemblyName; + private string _CallingAssemblyName; + private string _ExecutingAssemblyName; + private Assembly _EntryAssembly; + private NameValueCollection _EntryAssemblyAttribCollection; + private int _MinWindowHeight; + + // + // returns the entry assembly for the current application domain + // + // + // This is usually read-only, but in some weird cases (Smart Client apps) + // you won't have an entry assembly, so you may want to set this manually. + // + public Assembly AppEntryAssembly + { + get + { + return _EntryAssembly; + } + set + { + _EntryAssembly = value; + } + } + + // + // single line of text to show in the application title section of the about box dialog + // + // + // defaults to "%title%" + // %title% = Assembly: AssemblyTitle + // + public string AppTitle + { + get + { + return AppTitleLabel.Text; + } + set + { + AppTitleLabel.Text = value; + } + } + + // + // single line of text to show in the description section of the about box dialog + // + // + // defaults to "%description%" + // %description% = Assembly: AssemblyDescription + // + public string AppDescription + { + get + { + return AppDescriptionLabel.Text; + } + set + { + if (value == "") + { + AppDescriptionLabel.Visible = false; + } + else + { + AppDescriptionLabel.Visible = true; + AppDescriptionLabel.Text = value; + } + } + } + + // + // single line of text to show in the version section of the about dialog + // + // + // defaults to "Version %version%" + // %version% = Assembly: AssemblyVersion + // + public string AppVersion + { + get + { + return AppVersionLabel.Text; + } + set + { + if (value == "") + { + AppVersionLabel.Visible = false; + } + else + { + AppVersionLabel.Visible = true; + AppVersionLabel.Text = value; + } + } + } + + // + // single line of text to show in the copyright section of the about dialog + // + // + // defaults to "Copyright © %year%, %company%" + // %company% = Assembly: AssemblyCompany + // %year% = current 4-digit year + // + public string AppCopyright + { + get + { + return AppCopyrightLabel.Text; + } + set + { + if (value == "") + { + AppCopyrightLabel.Visible = false; + } + else + { + AppCopyrightLabel.Visible = true; + AppCopyrightLabel.Text = value; + } + } + } + + // + // intended for the default 32x32 application icon to appear in the upper left of the about dialog + // + // + // if you open this form using .ShowDialog(Owner), the icon can be derived from the owning form + // + public Image AppImage + { + get + { + return ImagePictureBox.Image; + } + set + { + ImagePictureBox.Image = value; + } + } + + // + // multiple lines of miscellaneous text to show in rich text box + // + // + // defaults to "%product% is %copyright%, %trademark%" + // %product% = Assembly: AssemblyProduct + // %copyright% = Assembly: AssemblyCopyright + // %trademark% = Assembly: AssemblyTrademark + // + public string AppMoreInfo + { + get + { + return MoreRichTextBox.Text; + } + set + { + if (value == null || value == "") + { + MoreRichTextBox.Visible = false; + } + else + { + MoreRichTextBox.Visible = true; + MoreRichTextBox.Text = value; + } + } + } + + // + // determines if the "Details" (advanced assembly details) button is shown + // + public bool AppDetailsButton + { + get + { + return buttonDetails.Visible; + } + set + { + buttonDetails.Visible = value; + } + } + + // + // exception-safe retrieval of LastWriteTime for this assembly. + // + // File.GetLastWriteTime, or DateTime.MaxValue if exception was encountered. + private DateTime AssemblyLastWriteTime(Assembly a) + { + if (a.Location == null || a.Location == "") + return DateTime.MaxValue; + try + { + return File.GetLastWriteTime(a.Location); + } + catch (Exception) + { + return DateTime.MaxValue; + } + } + + // + // returns DateTime this Assembly was last built. Will attempt to calculate from build number, if possible. + // If not, the actual LastWriteTime on the assembly file will be returned. + // + // Assembly to get build date for + // Don't attempt to use the build number to calculate the date + // DateTime this assembly was last built + private DateTime AssemblyBuildDate(Assembly a, bool ForceFileDate) + { + Version AssemblyVersion = a.GetName().Version; + DateTime dt; + + if (ForceFileDate) + { + dt = AssemblyLastWriteTime(a); + } + else + { + dt = DateTime.Parse("01/01/2000").AddDays(AssemblyVersion.Build).AddSeconds(AssemblyVersion.Revision * 2); + if (TimeZone.IsDaylightSavingTime(dt, TimeZone.CurrentTimeZone.GetDaylightChanges(dt.Year))) + { + dt = dt.AddHours(1); + } + if (dt > DateTime.Now || AssemblyVersion.Build < 730 || AssemblyVersion.Revision == 0) + { + dt = AssemblyLastWriteTime(a); + } + } + + return dt; + } + + // + // returns string name / string value pair of all attribs + // for specified assembly + // + // + // note that Assembly* values are pulled from AssemblyInfo file in project folder + // + // Trademark = AssemblyTrademark string + // Debuggable = true + // GUID = 7FDF68D5-8C6F-44C9-B391-117B5AFB5467 + // CLSCompliant = true + // Product = AssemblyProduct string + // Copyright = AssemblyCopyright string + // Company = AssemblyCompany string + // Description = AssemblyDescription string + // Title = AssemblyTitle string + // + private NameValueCollection AssemblyAttribs(Assembly a) + { + string TypeName; + string Name; + string Value; + NameValueCollection nvc = new NameValueCollection(); + Regex r = new Regex(@"(\.Assembly|\.)(?[^.]*)Attribute$", RegexOptions.IgnoreCase); + + foreach (object attrib in a.GetCustomAttributes(false)) + { + TypeName = attrib.GetType().ToString(); + Name = r.Match(TypeName).Groups["Name"].ToString(); + Value = ""; + switch (TypeName) + { + case "System.CLSCompliantAttribute": + Value = ((CLSCompliantAttribute)attrib).IsCompliant.ToString(); break; + case "System.Diagnostics.DebuggableAttribute": + Value = ((System.Diagnostics.DebuggableAttribute)attrib).IsJITTrackingEnabled.ToString(); break; + case "System.Reflection.AssemblyCompanyAttribute": + Value = ((AssemblyCompanyAttribute)attrib).Company.ToString(); break; + case "System.Reflection.AssemblyConfigurationAttribute": + Value = ((AssemblyConfigurationAttribute)attrib).Configuration.ToString(); break; + case "System.Reflection.AssemblyCopyrightAttribute": + Value = ((AssemblyCopyrightAttribute)attrib).Copyright.ToString(); break; + case "System.Reflection.AssemblyDefaultAliasAttribute": + Value = ((AssemblyDefaultAliasAttribute)attrib).DefaultAlias.ToString(); break; + case "System.Reflection.AssemblyDelaySignAttribute": + Value = ((AssemblyDelaySignAttribute)attrib).DelaySign.ToString(); break; + case "System.Reflection.AssemblyDescriptionAttribute": + Value = ((AssemblyDescriptionAttribute)attrib).Description.ToString(); break; + case "System.Reflection.AssemblyInformationalVersionAttribute": + Value = ((AssemblyInformationalVersionAttribute)attrib).InformationalVersion.ToString(); break; + case "System.Reflection.AssemblyKeyFileAttribute": + Value = ((AssemblyKeyFileAttribute)attrib).KeyFile.ToString(); break; + case "System.Reflection.AssemblyProductAttribute": + Value = ((AssemblyProductAttribute)attrib).Product.ToString(); break; + case "System.Reflection.AssemblyTrademarkAttribute": + Value = ((AssemblyTrademarkAttribute)attrib).Trademark.ToString(); break; + case "System.Reflection.AssemblyTitleAttribute": + Value = ((AssemblyTitleAttribute)attrib).Title.ToString(); break; + case "System.Resources.NeutralResourcesLanguageAttribute": + Value = ((System.Resources.NeutralResourcesLanguageAttribute)attrib).CultureName.ToString(); break; + case "System.Resources.SatelliteContractVersionAttribute": + Value = ((System.Resources.SatelliteContractVersionAttribute)attrib).Version.ToString(); break; + case "System.Runtime.InteropServices.ComCompatibleVersionAttribute": + { + System.Runtime.InteropServices.ComCompatibleVersionAttribute x; + x = ((System.Runtime.InteropServices.ComCompatibleVersionAttribute)attrib); + Value = x.MajorVersion + "." + x.MinorVersion + "." + x.RevisionNumber + "." + x.BuildNumber; break; + } + case "System.Runtime.InteropServices.ComVisibleAttribute": + Value = ((System.Runtime.InteropServices.ComVisibleAttribute)attrib).Value.ToString(); break; + case "System.Runtime.InteropServices.GuidAttribute": + Value = ((System.Runtime.InteropServices.GuidAttribute)attrib).Value.ToString(); break; + case "System.Runtime.InteropServices.TypeLibVersionAttribute": + { + System.Runtime.InteropServices.TypeLibVersionAttribute x; + x = ((System.Runtime.InteropServices.TypeLibVersionAttribute)attrib); + Value = x.MajorVersion + "." + x.MinorVersion; break; + } + case "System.Security.AllowPartiallyTrustedCallersAttribute": + Value = "(Present)"; break; + default: + // debug.writeline("** unknown assembly attribute '" + TypeName + "'") + Value = TypeName; break; + } + + if (nvc[Name] == null) + { + nvc.Add(Name, Value); + } + } + + // add some extra values that are not in the AssemblyInfo, but nice to have + // codebase + try + { + nvc.Add("CodeBase", a.CodeBase.Replace("file:///", "")); + } + catch (NotSupportedException) + { + nvc.Add("CodeBase", "(not supported)"); + } + // build date + DateTime dt = AssemblyBuildDate(a, false); + if (dt == DateTime.MaxValue) + { + nvc.Add("BuildDate", "(unknown)"); + } + else + { + nvc.Add("BuildDate", dt.ToString("yyyy-MM-dd hh:mm tt")); + } + // location + try + { + nvc.Add("Location", a.Location); + } + catch (NotSupportedException) + { + nvc.Add("Location", "(not supported)"); + } + // version + try + { + if (a.GetName().Version.Major == 0 && a.GetName().Version.Minor == 0) + { + nvc.Add("Version", "(unknown)"); + } + else + { + nvc.Add("Version", a.GetName().Version.ToString()); + } + } + catch (Exception) + { + nvc.Add("Version", "(unknown)"); + } + + nvc.Add("FullName", a.FullName); + + return nvc; + } + + // + // reads an HKLM Windows Registry key value + // + private string RegistryHklmValue(string KeyName, string SubKeyRef) + { + RegistryKey rk; + try + { + rk = Registry.LocalMachine.OpenSubKey(KeyName); + return (string)rk.GetValue(SubKeyRef, ""); + } + catch (Exception) + { + return ""; + } + } + + // + // launch the MSInfo "system information" application (works on XP, 2003, and Vista) + // + private void ShowSysInfo() + { + string strSysInfoPath = ""; + + strSysInfoPath = RegistryHklmValue(@"SOFTWARE\Microsoft\Shared Tools Location", "MSINFO"); + if (strSysInfoPath == "") + { + strSysInfoPath = RegistryHklmValue(@"SOFTWARE\Microsoft\Shared Tools\MSINFO", "PATH"); + } + + if (strSysInfoPath == "") + { + MessageBox.Show("System Information is unavailable at this time." + + Environment.NewLine + + Environment.NewLine + + "(couldn't find path for Microsoft System Information Tool in the registry.)", + Text, MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + try + { + System.Diagnostics.Process.Start(strSysInfoPath); + } + catch (Exception) + { + MessageBox.Show("System Information is unavailable at this time." + + Environment.NewLine + + Environment.NewLine + + "(couldn't launch '" + strSysInfoPath + "')", + Text, MessageBoxButtons.OK, MessageBoxIcon.Stop); + } + + } + + // + // populate a listview with the specified key and value strings + // + private void Populate(ListView lvw, string Key, string Value) + { + if (Value == "") + return; + ListViewItem lvi = new ListViewItem(); + lvi.Text = Key; + lvi.SubItems.Add(Value); + lvw.Items.Add(lvi); + } + + // + // populates the Application Information listview + // + private void PopulateAppInfo() + { + AppDomain d = System.AppDomain.CurrentDomain; + Populate(AppInfoListView, "Application Name", d.SetupInformation.ApplicationName); + Populate(AppInfoListView, "Application Base", d.SetupInformation.ApplicationBase); + Populate(AppInfoListView, "Cache Path", d.SetupInformation.CachePath); + Populate(AppInfoListView, "Configuration File", d.SetupInformation.ConfigurationFile); + Populate(AppInfoListView, "Dynamic Base", d.SetupInformation.DynamicBase); + Populate(AppInfoListView, "Friendly Name", d.FriendlyName); + Populate(AppInfoListView, "License File", d.SetupInformation.LicenseFile); + Populate(AppInfoListView, "private Bin Path", d.SetupInformation.PrivateBinPath); + Populate(AppInfoListView, "Shadow Copy Directories", d.SetupInformation.ShadowCopyDirectories); + Populate(AppInfoListView, " ", " "); + Populate(AppInfoListView, "Entry Assembly", _EntryAssemblyName); + Populate(AppInfoListView, "Executing Assembly", _ExecutingAssemblyName); + Populate(AppInfoListView, "Calling Assembly", _CallingAssemblyName); + } + + // + // populate Assembly Information listview with ALL assemblies + // + private void PopulateAssemblies() + { + foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) + { + PopulateAssemblySummary(a); + } + AssemblyNamesComboBox.SelectedIndex = AssemblyNamesComboBox.FindStringExact(_EntryAssemblyName); + } + + // + // populate Assembly Information listview with summary view for a specific assembly + // + private void PopulateAssemblySummary(Assembly a) + { + NameValueCollection nvc = AssemblyAttribs(a); + + string strAssemblyName = a.GetName().Name; + + ListViewItem lvi = new ListViewItem(); + lvi.Text = strAssemblyName; + lvi.Tag = strAssemblyName; + if (strAssemblyName == _CallingAssemblyName) + { + lvi.Text += " (calling)"; + } + if (strAssemblyName == _ExecutingAssemblyName) + { + lvi.Text += " (executing)"; + } + if (strAssemblyName == _EntryAssemblyName) + { + lvi.Text += " (entry)"; + } + lvi.SubItems.Add(nvc["version"]); + lvi.SubItems.Add(nvc["builddate"]); + lvi.SubItems.Add(nvc["codebase"]); + //lvi.SubItems.Add(AssemblyVersion(a)) + //lvi.SubItems.Add(AssemblyBuildDatestring(a, true)) + //lvi.SubItems.Add(AssemblyCodeBase(a)) + AssemblyInfoListView.Items.Add(lvi); + AssemblyNamesComboBox.Items.Add(strAssemblyName); + } + + // + // retrieves a cached value from the entry assembly attribute lookup collection + // + private string EntryAssemblyAttrib(string strName) + { + if (_EntryAssemblyAttribCollection[strName] == null) + { + return ""; + } + else + { + return _EntryAssemblyAttribCollection[strName].ToString(); + } + } + + // + // Populate all the form labels with tokenized text + // + private void PopulateLabels() + { + // get entry assembly attribs + _EntryAssemblyAttribCollection = AssemblyAttribs(_EntryAssembly); + + // set icon from parent, if present + if (Owner == null) + { + //ImagePictureBox.Visible = false; + //AppTitleLabel.Left = AppCopyrightLabel.Left; + //AppDescriptionLabel.Left = AppCopyrightLabel.Left; + } + else + { + Icon = Owner.Icon; + ImagePictureBox.Image = Icon.ToBitmap(); + } + // replace all labels and window title + Text = ReplaceTokens(Text); + AppTitleLabel.Text = ReplaceTokens(AppTitleLabel.Text); + if (AppDescriptionLabel.Visible) + { + AppDescriptionLabel.Text = ReplaceTokens(AppDescriptionLabel.Text); + } + if (AppCopyrightLabel.Visible) + { + AppCopyrightLabel.Text = ReplaceTokens(AppCopyrightLabel.Text); + } + if (AppVersionLabel.Visible) + { + AppVersionLabel.Text = ReplaceTokens(AppVersionLabel.Text); + } + if (AppDateLabel.Visible) + { + AppDateLabel.Text = ReplaceTokens(AppDateLabel.Text); + } + if (MoreRichTextBox.Visible) + { + MoreRichTextBox.Text = ReplaceTokens(MoreRichTextBox.Text); + } + } + + // + // perform assemblyinfo to string replacements on labels + // + private string ReplaceTokens(string s) + { + s = s.Replace("%title%", EntryAssemblyAttrib("title")); + s = s.Replace("%copyright%", EntryAssemblyAttrib("copyright")); + s = s.Replace("%description%", EntryAssemblyAttrib("description")); + s = s.Replace("%company%", EntryAssemblyAttrib("company")); + s = s.Replace("%product%", EntryAssemblyAttrib("product")); + s = s.Replace("%trademark%", EntryAssemblyAttrib("trademark")); + s = s.Replace("%year%", DateTime.Now.Year.ToString()); + s = s.Replace("%version%", EntryAssemblyAttrib("version")); + s = s.Replace("%builddate%", EntryAssemblyAttrib("builddate")); + return s; + } + + // + // populate details for a single assembly + // + private void PopulateAssemblyDetails(Assembly a, ListView lvw) + { + lvw.Items.Clear(); + + // this assembly property is only available in framework versions 1.1+ + Populate(lvw, "Image Runtime Version", a.ImageRuntimeVersion); + Populate(lvw, "Loaded from GAC", a.GlobalAssemblyCache.ToString()); + + NameValueCollection nvc = AssemblyAttribs(a); + foreach (string strKey in nvc) + { + Populate(lvw, strKey, nvc[strKey]); + } + } + + // + // matches assembly by Assembly.GetName.Name; returns nothing if no match + // + private Assembly MatchAssemblyByName(string AssemblyName) + { + foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) + { + if (a.GetName().Name == AssemblyName) + { + return a; + } + } + return null; + } + + // + // things to do when form is loaded + // + private void AboutBox_Load(object sender, EventArgs e) + { + // if the user didn't provide an assembly, try to guess which one is the entry assembly + if (_EntryAssembly == null) + { + _EntryAssembly = Assembly.GetEntryAssembly(); + } + if (_EntryAssembly == null) + { + _EntryAssembly = Assembly.GetExecutingAssembly(); + } + + _ExecutingAssemblyName = Assembly.GetExecutingAssembly().GetName().Name; + _CallingAssemblyName = Assembly.GetCallingAssembly().GetName().Name; + try + { + // for web hosted apps, GetEntryAssembly = nothing + _EntryAssemblyName = Assembly.GetEntryAssembly().GetName().Name; + } + catch (Exception) + { + } + + _MinWindowHeight = AppCopyrightLabel.Top + AppCopyrightLabel.Height + buttonOk.Height + 30; + + TabPanelDetails.Visible = false; + if (!MoreRichTextBox.Visible) + { + Height = Height - MoreRichTextBox.Height; + } + } + + // + // things to do when form is FIRST painted + // + private void AboutBox_Paint(object sender, PaintEventArgs e) + { + if (!_IsPainted) + { + _IsPainted = true; + Application.DoEvents(); + Cursor.Current = Cursors.WaitCursor; + PopulateLabels(); + Cursor.Current = Cursors.Default; + } + } + + // + // expand about dialog to show additional advanced details + // + private void DetailsButton_Click(object sender, EventArgs e) + { + Cursor.Current = Cursors.WaitCursor; + buttonDetails.Visible = false; + SuspendLayout(); + MaximizeBox = true; + FormBorderStyle = FormBorderStyle.Sizable; + TabPanelDetails.Dock = DockStyle.Fill; + tableLayoutPanel1.Dock = DockStyle.Fill; + this.AutoSize = false; + SizeGripStyle = SizeGripStyle.Show; + Size = new Size(580, Size.Height); + MoreRichTextBox.Visible = false; + TabPanelDetails.Visible = true; + buttonSystemInfo.Visible = true; + PopulateAssemblies(); + PopulateAppInfo(); + CenterToParent(); + ResumeLayout(); + Cursor.Current = Cursors.Default; + } + + // + // for detailed system info, launch the external Microsoft system info app + // + private void SysInfoButton_Click(object sender, EventArgs e) + { + ShowSysInfo(); + } + + // + // if an assembly is double-clicked, go to the detail page for that assembly + // + private void AssemblyInfoListView_DoubleClick(object sender, EventArgs e) + { + string strAssemblyName; + if (AssemblyInfoListView.SelectedItems.Count > 0) + { + strAssemblyName = Convert.ToString(AssemblyInfoListView.SelectedItems[0].Tag); + AssemblyNamesComboBox.SelectedIndex = AssemblyNamesComboBox.FindStringExact(strAssemblyName); + TabPanelDetails.SelectedTab = TabPageAssemblyDetails; + } + } + + // + // if a new assembly is selected from the combo box, show details for that assembly + // + private void AssemblyNamesComboBox_SelectedIndexChanged(object sender, EventArgs e) + { + string strAssemblyName = Convert.ToString(AssemblyNamesComboBox.SelectedItem); + PopulateAssemblyDetails(MatchAssemblyByName(strAssemblyName), AssemblyDetailsListView); + } + + // + // sort the assembly list by column + // + private void AssemblyInfoListView_ColumnClick(object sender, ColumnClickEventArgs e) + { + int intTargetCol = e.Column + 1; + + if (AssemblyInfoListView.Tag != null) + { + if (Math.Abs(Convert.ToInt32(AssemblyInfoListView.Tag)) == intTargetCol) + { + intTargetCol = -Convert.ToInt32(AssemblyInfoListView.Tag); + } + } + AssemblyInfoListView.Tag = intTargetCol; + AssemblyInfoListView.ListViewItemSorter = new ListViewItemComparer(intTargetCol, true); + } + + // + // launch any http:// or mailto: links clicked in the body of the rich text box + // + private void MoreRichTextBox_LinkClicked(object sender, LinkClickedEventArgs e) + { + try + { + System.Diagnostics.Process.Start(e.LinkText); + } + catch (Exception) + { + } + } + + // + // things to do when the selected tab is changed + // + class ListViewItemComparer : System.Collections.IComparer + { + private int _intCol; + private bool _IsAscending = true; + + public ListViewItemComparer() + { + _intCol = 0; + _IsAscending = true; + } + + public ListViewItemComparer(int column, bool ascending) + { + if (column < 0) + { + _IsAscending = false; + } + else + { + _IsAscending = ascending; + } + _intCol = Math.Abs(column) - 1; + } + + public int Compare(object x, object y) + { + int intResult = + string.Compare(((ListViewItem)x).SubItems[_intCol].Text, ((ListViewItem)y).SubItems[_intCol].Text); + + if (_IsAscending) + { + return intResult; + } + else + { + return -intResult; + } + } + } + + private void TabPanelDetails_SelectedIndexChanged(object sender, EventArgs e) + { + if (TabPanelDetails.SelectedTab == TabPageAssemblyDetails) + AssemblyNamesComboBox.Focus(); + } + + } +} \ No newline at end of file diff --git a/Controls/AboutBox.resx b/Controls/AboutBox.resx new file mode 100644 index 0000000..a04fa62 --- /dev/null +++ b/Controls/AboutBox.resx @@ -0,0 +1,377 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAMAEBAAAAEAIABoBAAANgAAACAgAAABACAAqBAAAJ4EAAAwMAAAAQAgAKglAABGFQAAKAAAABAA + AAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAJAAAAcwEB + AXsBAQF7AQEBewEBAXsBAQF7AQEBewEBAXsBAQF7AQEBewEBAXsAAABzAAAACQAAAAEAAAABAAAACQAA + AHMBAQF7AQEBewEBAXsBAQF7AQEBewEBAXsBAQF7AQEBewEBAXsBAQF7AAAAcwAAAAkAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAACQAAAHUAAAB7AAAAewAAAHsAAAB7AAAAewAAAHsAAAB7AAAAewAAAHsAAAB7AAAAdQAA + AAkAAAABAAAAAQAAAAkAAABzAAAAewAAAHsAAAB7AAAAewAAAHsAAAB7AAAAewAAAHsAAAB7AAAAewAA + AHMAAAAJAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAkAAABzAQEBewEBAXsBAQF7AQEBewEBAXsBAQF7AQEBewEB + AXsBAQF7AQEBewAAAHMAAAAJAAAAAQAAAAEAAAAJAAAAcwEBAXsBAQF7AQEBewEBAXsBAQF7AQEBewEB + AXsBAQF7AQEBewEBAXsAAABzAAAACQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAAAABAAAAAAQAgAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAHwAAANkBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AAAA2QAAAB8AAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAfAAAA2QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUAAADZAAAAHwAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAFAAAAIQAAACUAAAAlAAAAJQAAACUAAAAlAAAAJQAA + ACUAAAAlAAAAJQAAACUAAAAlAAAAJQAAACUAAAAlAAAAJQAAACUAAAAlAAAAJQAAACUAAAAlAAAAJQAA + ACUAAAAhAAAABQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQEBARsAAAC5AAAA0QAAANEAAADRAAAA0QAA + ANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAA + ANEAAADRAAAA0QAAALkBAQEbAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAQEBGwEBAbkAAADRAAAA0QAA + ANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAA + ANEAAADRAAAA0QAAANEAAADRAQEBuQEBARsAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAFAQEBIQEB + ASUBAQElAQEBJQEBASUBAQElAQEBJQEBASUBAQElAQEBJQEBASUBAQElAQEBJQEBASUBAQElAQEBJQEB + ASUBAQElAQEBJQEBASUBAQElAQEBJQEBASUBAQEhAAAABQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAfAAAA2QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUAAADZAAAAHwAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAB8AAADZAQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QAAANkAAAAfAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAwAAAAYAAAAAEA + IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAABUAAABdAQEBcQAA + AHEBAQFxAQEBcQAAAHEBAQFxAQEBcQAAAHEBAQFxAAAAcQAAAHEAAABxAQEBcQAAAHEBAQFxAAAAcQEB + AXEAAABxAAAAcQEBAXEAAABxAQEBcQAAAHEBAQFxAQEBcQAAAHEAAABxAQEBcQAAAHEAAABxAQEBcQAA + AHEAAABxAQEBcQEBAV0AAAAVAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQEB + AS8AAADTAAAA/wAAAP8AAAD/AAAA/wAAAP8BAQH/AAAA/wAAAP8AAAD/AQEB/wAAAP8AAAD/AQEB/wAA + AP8AAAD/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEB/wAAAP8BAQH/AAAA/wEBAf8AAAD/AAAA/wEB + Af8BAQH/AAAA/wEBAf8BAQH/AAAA/wAAANMAAAAvAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQEBAS8AAADTAAAA/wEBAf8AAAD/AAAA/wEBAf8BAQH/AAAA/wAAAP8AAAD/AQEB/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AQEB/wAAAP8AAAD/AQEB/wAAAP8AAAD/AQEB/wAAAP8AAAD/AAAA/wEB + Af8AAAD/AAAA/wEBAf8BAQH/AAAA/wEBAf8BAQH/AAAA/wAAANMAAAAvAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAABUAAABdAQEBcQEBAXEBAQFxAQEBcQEBAXEBAQFxAQEBcQEB + AXEBAQFxAAAAcQAAAHEAAABxAQEBcQAAAHEBAQFxAAAAcQEBAXEAAABxAAAAcQEBAXEAAABxAQEBcQAA + AHEBAQFxAQEBcQAAAHEAAABxAQEBcQAAAHEAAABxAQEBcQAAAHEAAABxAQEBcQEBAV0AAAAVAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAABcAAABhAQEBdwAAAHcBAQF3AAAAdwEBAXcBAQF3AAAAdwEBAXcAAAB3AAAAdwEB + AXcAAAB3AQEBdwAAAHcAAAB3AAAAdwEBAXcBAQF3AAAAdwAAAHcAAAB3AQEBdwAAAHcBAQF3AQEBdwAA + AHcBAQF3AQEBdwAAAHcBAQF3AQEBdwAAAHcBAQF3AQEBdwAAAGEAAAAXAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAC8AAADPAQEB+QEBAfkAAAD5AAAA+QEBAfkBAQH5AAAA+QAA + APkAAAD5AAAA+QAAAPkAAAD5AAAA+QEBAfkAAAD5AAAA+QAAAPkAAAD5AAAA+QAAAPkBAQH5AAAA+QAA + APkAAAD5AAAA+QAAAPkAAAD5AAAA+QAAAPkAAAD5AAAA+QAAAPkAAAD5AAAA+QEBAc8AAAAvAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAC8AAADPAAAA+QAAAPkAAAD5AQEB+QAA + APkAAAD5AQEB+QEBAfkAAAD5AQEB+QAAAPkAAAD5AAAA+QEBAfkAAAD5AAAA+QEBAfkBAQH5AAAA+QEB + AfkBAQH5AAAA+QEBAfkAAAD5AAAA+QEBAfkAAAD5AAAA+QEBAfkBAQH5AQEB+QAAAPkBAQH5AQEB+QAA + AM8AAAAvAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQEBARcAAABhAQEBdQEB + AXUBAQF1AAAAdQEBAXUBAQF1AAAAdQEBAXUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAA + AHUAAAB1AQEBdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAA + AHUAAAB1AAAAdQEBAWEBAQEXAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAABUBAQFdAQEBcQAAAHEBAQFxAQEBcQAA + AHEAAABxAQEBcQEBAXEBAQFxAAAAcQAAAHEAAABxAQEBcQAAAHEBAQFxAAAAcQEBAXEBAQFxAAAAcQEB + AXEAAABxAQEBcQAAAHEBAQFxAAAAcQAAAHEBAQFxAQEBcQEBAXEBAQFxAQEBcQEBAXEAAABxAAAAcQEB + AV0AAAAVAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAC8BAQHTAAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAANMAAAAvAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AC8AAADTAQEB/wAAAP8AAAD/AAAA/wEBAf8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEB/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wEBAdMAAAAvAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAABUBAQFdAQEBcQAAAHEBAQFxAQEBcQAAAHEAAABxAQEBcQEBAXEBAQFxAAAAcQAA + AHEAAABxAQEBcQAAAHEBAQFxAAAAcQEBAXEBAQFxAAAAcQEBAXEAAABxAQEBcQAAAHEBAQFxAAAAcQAA + AHEBAQFxAQEBcQEBAXEBAQFxAQEBcQEBAXEAAABxAAAAcQEBAV0AAAAVAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + \ No newline at end of file diff --git a/Controls/AppContextMenu.cs b/Controls/AppContextMenu.cs new file mode 100644 index 0000000..369c74b --- /dev/null +++ b/Controls/AppContextMenu.cs @@ -0,0 +1,258 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; + +namespace SystemTrayMenu.Controls +{ + class AppContextMenu + { + public event EventHandler ClickedChangeFolder; + public event EventHandler ClickedOpenLog; + public event EventHandler ClickedRestart; + public event EventHandler ClickedExit; + + public ContextMenuStrip Create() + { + ContextMenuStrip menu = new ContextMenuStrip(); + menu.BackColor = SystemColors.Control; + ToolStripMenuItem changeFolder = new ToolStripMenuItem(); + changeFolder.Text = Program.Translate("Folder"); + changeFolder.Click += ChangeFolder_Click; + void ChangeFolder_Click(object sender, EventArgs e) + { + ClickedChangeFolder.Invoke(); + } + menu.Items.Add(changeFolder); + + ToolStripMenuItem changeLanguage = new ToolStripMenuItem() + { + Name = "changeLanguage", + Text = Program.Translate("Language") + }; + foreach (CultureInfo cultureInfo in + GetCultureList(CultureTypes.AllCultures)) + { + if (Program.Languages.Contains(cultureInfo.Name)) + { + ToolStripItem language = changeLanguage.DropDownItems. + Add(Program.Translate(cultureInfo.EnglishName)); + language.Click += Language_Click; + void Language_Click(object sender, EventArgs e) + { + string twoLetter = cultureInfo.Name.Substring(0, 2); + Properties.Settings.Default.CurrentCultureInfoName = + twoLetter; + Properties.Settings.Default.Save(); + ClickedRestart.Invoke(); + } + if (cultureInfo.Name == Properties.Settings.Default. + CurrentCultureInfoName) + { + language.Image = Properties.Resources.Selected; + language.ImageScaling = ToolStripItemImageScaling.None; + language.Image = ResizeImage(language.Image); + } + } + } + menu.Items.Add(changeLanguage); + + ToolStripMenuItem autostart = new ToolStripMenuItem(); + autostart.Text = Program.Translate("Autostart"); + //autostart.Image.HorizontalResolution.wi.c.sc.Select .ImageScaling = ToolStripItemImageScaling.None; + if (Properties.Settings.Default.IsAutostartActivated) + { + autostart.Image = Properties.Resources.Selected; + } + else + { + autostart.Image = Properties.Resources.NotSelected; + } + autostart.ImageScaling = ToolStripItemImageScaling.None; + autostart.Image = ResizeImage(autostart.Image); + autostart.Click += Autostart_Click; + void Autostart_Click(object sender, EventArgs e) + { + if (Properties.Settings.Default.IsAutostartActivated) + { + Microsoft.Win32.RegistryKey key = + Microsoft.Win32.Registry.CurrentUser.OpenSubKey( + @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", + true); + key.DeleteValue("SystemTrayMenu", false); + Properties.Settings.Default.IsAutostartActivated = false; + } + else + { + Microsoft.Win32.RegistryKey key = + Microsoft.Win32.Registry.CurrentUser.OpenSubKey( + @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", + true); + key.SetValue( + Assembly.GetExecutingAssembly().GetName().Name, + Assembly.GetEntryAssembly().Location); + Properties.Settings.Default.IsAutostartActivated = true; + } + Properties.Settings.Default.Save(); + ClickedRestart.Invoke(); + } + menu.Items.Add(autostart); + + ToolStripMenuItem hotKey = new ToolStripMenuItem(); + string hotKeyText = + $"{Program.Translate("CTRL")} + " + + $"{Program.Translate("ALT")} + "; + + hotKey.ImageScaling = ToolStripItemImageScaling.SizeToFit; + if (string.IsNullOrEmpty(Properties.Settings.Default.HotKey)) + { + hotKey.Image = Properties.Resources.NotSelected; + hotKey.Text = hotKeyText + "? "; + } + else + { + hotKey.Image = Properties.Resources.Selected; + hotKey.Text = hotKeyText + + $"{Properties.Settings.Default.HotKey}"; + } + hotKey.ImageScaling = ToolStripItemImageScaling.None; + hotKey.Image = ResizeImage(hotKey.Image); + hotKey.Click += HotKey_Click; + void HotKey_Click(object sender, EventArgs e) + { + AskHotKeyForm askHotKey = new AskHotKeyForm(); + if (askHotKey.ShowDialog() == DialogResult.OK) + { + Properties.Settings.Default.HotKey = askHotKey.NewHotKey; + Properties.Settings.Default.Save(); + ClickedRestart?.Invoke(); + } + } + menu.Items.Add(hotKey); + + ToolStripSeparator seperator = new ToolStripSeparator(); + seperator.BackColor = SystemColors.Control; + menu.Items.Add(seperator); + + ToolStripMenuItem openLog = new ToolStripMenuItem(); + openLog.Text = Program.Translate("Log File"); + openLog.Click += OpenLog_Click; + void OpenLog_Click(object sender, EventArgs e) + { + ClickedOpenLog.Invoke(); + } + menu.Items.Add(openLog); + + menu.Items.Add(new ToolStripSeparator()); + + ToolStripMenuItem about = new ToolStripMenuItem(); + about.Text = Program.Translate("About"); + about.Click += About_Click; + void About_Click(object sender, EventArgs e) + { + FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo( + Assembly.GetEntryAssembly().Location); + AboutBox ab = new AboutBox(); + ab.AppTitle = versionInfo.ProductName; + ab.AppDescription = versionInfo.FileDescription; + ab.AppVersion = $"Version {versionInfo.FileVersion}"; + ab.AppCopyright = versionInfo.LegalCopyright; + ab.AppMoreInfo = "SystemTrayMenu - An improved Windows Toolbar"; + ab.AppMoreInfo += Environment.NewLine; + ab.AppMoreInfo += "Code from © 2019, TAMAHO, All Rights Reserved."; + ab.AppMoreInfo += Environment.NewLine; + ab.AppMoreInfo += "Developer:"; + ab.AppMoreInfo += Environment.NewLine; + ab.AppMoreInfo += "Markus Hofknecht (mailto:Markus@Hofknecht.eu)"; + ab.AppMoreInfo += Environment.NewLine; + ab.AppMoreInfo += "Tanja Kauth (Tanja@Hofknecht.eu)"; + ab.AppMoreInfo += Environment.NewLine; + ab.AppMoreInfo += Environment.NewLine; + ab.AppMoreInfo += "http://www.hofknecht.eu/systemtraymenu/" + Environment.NewLine; + ab.AppDetailsButton = true; + ab.ShowDialog(); + } + menu.Items.Add(about); + + menu.Items.Add(new ToolStripSeparator()); + + ToolStripMenuItem restart = new ToolStripMenuItem(); + restart.Text = Program.Translate("Restart"); + restart.Click += Restart_Click; + void Restart_Click(object sender, EventArgs e) + { + ClickedRestart.Invoke(); + } + menu.Items.Add(restart); + + ToolStripMenuItem exit = new ToolStripMenuItem(); + exit.Text = Program.Translate("Exit"); + exit.Click += Exit_Click; + void Exit_Click(object sender, EventArgs e) + { + ClickedExit.Invoke(); + } + menu.Items.Add(exit); + + return menu; + } + + /// + /// https://www.codeproject.com/Tips/744914/ + /// Sorted-list-of-available-cultures-in-NET + /// + public IEnumerable GetCultureList( + CultureTypes cultureType = CultureTypes.SpecificCultures) + { + var cultureList = CultureInfo.GetCultures(cultureType).ToList(); + cultureList.Sort((p1, p2) => string.Compare( + p1.NativeName, p2.NativeName, true)); + return cultureList; + } + + /// + /// Resize the image to the specified width and height. + /// + /// The image to resize. + /// The width to resize to. + /// The height to resize to. + /// The resized image. + public static Bitmap ResizeImage(Image image) + { + int length = (int)Math.Round( + 16 * Program.ScalingFactor, 0, + MidpointRounding.AwayFromZero); + return ResizeImage(image, length, length); + } + public static Bitmap ResizeImage(Image image, int width, int height) + { + var destRect = new Rectangle(0, 0, width, height); + var destImage = new Bitmap(width, height); + + destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution); + + using (var graphics = Graphics.FromImage(destImage)) + { + graphics.CompositingMode = CompositingMode.SourceCopy; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + using (var wrapMode = new ImageAttributes()) + { + wrapMode.SetWrapMode(WrapMode.TileFlipXY); + graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode); + } + } + + return destImage; + } + } +} \ No newline at end of file diff --git a/Controls/AppNotifyIcon.cs b/Controls/AppNotifyIcon.cs new file mode 100644 index 0000000..b450968 --- /dev/null +++ b/Controls/AppNotifyIcon.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using SystemTrayMenu.Controls; +using R = SystemTrayMenu.Properties.Resources; +using Timer = System.Windows.Forms.Timer; + +namespace SystemTrayMenu +{ + class MenuNotifyIcon : IDisposable + { + public event EventHandler HandleClick; + public event EventHandler ChangeFolder; + public event EventHandler OpenLog; + public event EventHandler Restart; + public event EventHandler Exit; + + NotifyIcon notifyIcon = new NotifyIcon(); + private DateTime timeLoadingStart; + int threadsLoading = 0; + Timer load = new Timer(); + int loadCount = 0, indexLoad = 0; + List bitmapsLoading = new List() { R.L010, R.L020, R.L030, + R.L040, R.L050, R.L060, R.L070, R.L080, R.L090, R.L100, R.L110, R.L120, + R.L130, R.L140, R.L150, R.L160, R.L170, R.L180}; + + public MenuNotifyIcon() + { + indexLoad = bitmapsLoading.Count; + notifyIcon.Icon = bitmapsLoading.First(); + load.Tick += Load_Tick; + load.Interval = MenuDefines.IntervalLoad; + + notifyIcon.Text = "SystemTrayMenu"; + notifyIcon.Visible = true; + notifyIcon.Icon = R.SystemTrayMenu; + AppContextMenu contextMenus = new AppContextMenu(); + contextMenus.ClickedChangeFolder += ClickedChangeFolder; + void ClickedChangeFolder() + { + ChangeFolder.Invoke(); + } + + contextMenus.ClickedOpenLog += ClickedOpenLog; + void ClickedOpenLog() + { + OpenLog.Invoke(); + } + + contextMenus.ClickedRestart += ClickedRestart; + void ClickedRestart() + { + Restart.Invoke(); + } + + contextMenus.ClickedExit += ClickedExit; + void ClickedExit() + { + Exit.Invoke(); + } + + notifyIcon.ContextMenuStrip = contextMenus.Create(); + notifyIcon.MouseClick += NotifyIcon_MouseClick; + void NotifyIcon_MouseClick(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + HandleClick(); + } + } + + notifyIcon.MouseDoubleClick += NotifyIcon_MouseDoubleClick; + void NotifyIcon_MouseDoubleClick(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + HandleClick(); + } + } + } + + public void Dispose() + { + notifyIcon.Icon = null; + notifyIcon.Dispose(); + } + + public void LoadingStart() + { + timeLoadingStart = DateTime.Now; + threadsLoading++; + load.Start(); + } + + public void LoadingStop() + { + threadsLoading--; + } + public void LoadWait() + { + notifyIcon.Icon = bitmapsLoading[loadCount++ % indexLoad]; + } + public void LoadStop() + { + notifyIcon.Icon = R.SystemTrayMenu; + } + + private void Load_Tick(object sender, EventArgs e) + { + if (threadsLoading > 0) + { + if (DateTime.Now - timeLoadingStart > new TimeSpan(0, 0, 0, 0, 500)) + { + notifyIcon.Icon = bitmapsLoading[loadCount++ % indexLoad]; + } + } + else + { + notifyIcon.Icon = R.SystemTrayMenu; + load.Stop(); + } + } + } +} \ No newline at end of file diff --git a/Controls/AskHotKeyForm.Designer.cs b/Controls/AskHotKeyForm.Designer.cs new file mode 100644 index 0000000..c76199f --- /dev/null +++ b/Controls/AskHotKeyForm.Designer.cs @@ -0,0 +1,139 @@ +namespace SystemTrayMenu.Controls +{ + partial class AskHotKeyForm + { + /// + /// 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() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AskHotKeyForm)); + this.tableLayoutPanelMain = new System.Windows.Forms.TableLayoutPanel(); + this.labelText = new System.Windows.Forms.Label(); + this.tableLayoutPanelBottom = new System.Windows.Forms.TableLayoutPanel(); + this.buttonOk = new System.Windows.Forms.Button(); + this.labelCaption = new System.Windows.Forms.Label(); + this.tableLayoutPanelMain.SuspendLayout(); + this.tableLayoutPanelBottom.SuspendLayout(); + this.SuspendLayout(); + // + // tableLayoutPanelMain + // + this.tableLayoutPanelMain.AutoSize = true; + this.tableLayoutPanelMain.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanelMain.ColumnCount = 1; + this.tableLayoutPanelMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanelMain.Controls.Add(this.labelText, 0, 1); + this.tableLayoutPanelMain.Controls.Add(this.tableLayoutPanelBottom, 0, 2); + this.tableLayoutPanelMain.Controls.Add(this.labelCaption, 0, 0); + this.tableLayoutPanelMain.Location = new System.Drawing.Point(12, 12); + this.tableLayoutPanelMain.Name = "tableLayoutPanelMain"; + this.tableLayoutPanelMain.RowCount = 3; + this.tableLayoutPanelMain.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanelMain.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanelMain.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanelMain.Size = new System.Drawing.Size(121, 77); + this.tableLayoutPanelMain.TabIndex = 0; + // + // labelText + // + this.labelText.AutoSize = true; + this.labelText.Location = new System.Drawing.Point(3, 21); + this.labelText.Margin = new System.Windows.Forms.Padding(3, 8, 3, 8); + this.labelText.Name = "labelText"; + this.labelText.Size = new System.Drawing.Size(67, 13); + this.labelText.TabIndex = 1; + this.labelText.Text = "Ctrl + Alt + ?)"; + // + // tableLayoutPanelBottom + // + this.tableLayoutPanelBottom.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.tableLayoutPanelBottom.AutoSize = true; + this.tableLayoutPanelBottom.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanelBottom.ColumnCount = 3; + this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanelBottom.Controls.Add(this.buttonOk, 1, 0); + this.tableLayoutPanelBottom.Location = new System.Drawing.Point(3, 45); + this.tableLayoutPanelBottom.Name = "tableLayoutPanelBottom"; + this.tableLayoutPanelBottom.RowCount = 1; + this.tableLayoutPanelBottom.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanelBottom.Size = new System.Drawing.Size(115, 29); + this.tableLayoutPanelBottom.TabIndex = 1; + // + // buttonOk + // + this.buttonOk.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonOk.Location = new System.Drawing.Point(20, 3); + this.buttonOk.Name = "buttonOk"; + this.buttonOk.Size = new System.Drawing.Size(75, 23); + this.buttonOk.TabIndex = 2; + this.buttonOk.Text = "OK"; + this.buttonOk.UseVisualStyleBackColor = true; + this.buttonOk.Click += new System.EventHandler(this.ButtonOk_Click); + // + // labelCaption + // + this.labelCaption.AutoSize = true; + this.labelCaption.Location = new System.Drawing.Point(3, 0); + this.labelCaption.MaximumSize = new System.Drawing.Size(217, 0); + this.labelCaption.Name = "labelCaption"; + this.labelCaption.Size = new System.Drawing.Size(115, 13); + this.labelCaption.TabIndex = 0; + this.labelCaption.Text = "Shortcut key (e.g. F12)"; + // + // AskHotKeyForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.ClientSize = new System.Drawing.Size(302, 221); + this.Controls.Add(this.tableLayoutPanelMain); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AskHotKeyForm"; + this.Padding = new System.Windows.Forms.Padding(0, 0, 10, 0); + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "AskHotKeyForm"; + this.tableLayoutPanelMain.ResumeLayout(false); + this.tableLayoutPanelMain.PerformLayout(); + this.tableLayoutPanelBottom.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanelMain; + private System.Windows.Forms.Button buttonOk; + private System.Windows.Forms.Label labelCaption; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanelBottom; + private System.Windows.Forms.Label labelText; + } +} \ No newline at end of file diff --git a/Controls/AskHotKeyForm.cs b/Controls/AskHotKeyForm.cs new file mode 100644 index 0000000..cc9d246 --- /dev/null +++ b/Controls/AskHotKeyForm.cs @@ -0,0 +1,121 @@ +using System; +using System.Windows.Forms; + +namespace SystemTrayMenu.Controls +{ + public partial class AskHotKeyForm : Form + { + public string NewHotKey; + + public AskHotKeyForm() + { + InitializeComponent(); + this.Text = Program.Translate("Shortcut key"); + this.labelCaption.Text = $"{Program.Translate("Shortcut key")} " + + $"{Program.Translate("(e.g. F12)")}"; + this.labelText.Text = + Program.Translate("CTRL") + " + " + + Program.Translate("ALT") + " + ?"; + + this.buttonOk.Text = Program.Translate("buttonOk"); + } + + private void ButtonOk_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.None; + this.Close(); + } + + protected override bool ProcessCmdKey(ref Message msg, Keys keys) + { + switch (keys) + { + case Keys.Space: + case Keys.D0: + case Keys.D1: + case Keys.D2: + case Keys.D3: + case Keys.D4: + case Keys.D5: + case Keys.D6: + case Keys.D7: + case Keys.D8: + case Keys.D9: + case Keys.A: + case Keys.B: + case Keys.C: + case Keys.D: + case Keys.E: + case Keys.F: + case Keys.G: + case Keys.H: + case Keys.I: + case Keys.J: + case Keys.K: + case Keys.L: + case Keys.M: + case Keys.N: + case Keys.O: + case Keys.P: + case Keys.Q: + case Keys.R: + case Keys.S: + case Keys.T: + case Keys.U: + case Keys.V: + case Keys.W: + case Keys.X: + case Keys.Y: + case Keys.Z: + case Keys.NumPad0: + case Keys.NumPad1: + case Keys.NumPad2: + case Keys.NumPad3: + case Keys.NumPad4: + case Keys.NumPad5: + case Keys.NumPad6: + case Keys.NumPad7: + case Keys.NumPad8: + case Keys.NumPad9: + case Keys.F1: + case Keys.F2: + case Keys.F3: + case Keys.F4: + case Keys.F5: + case Keys.F6: + case Keys.F7: + case Keys.F8: + case Keys.F9: + case Keys.F10: + case Keys.F11: + case Keys.F12: + case Keys.F13: + case Keys.F14: + case Keys.F15: + case Keys.F16: + case Keys.F17: + case Keys.F18: + case Keys.F19: + case Keys.F20: + case Keys.F21: + case Keys.F22: + case Keys.F23: + case Keys.F24: + NewHotKey = keys.ToString(); + this.DialogResult = DialogResult.OK; + this.Close(); + break; + case Keys.Back: + case Keys.Delete: + NewHotKey = string.Empty; + this.DialogResult = DialogResult.OK; + this.Close(); + break; + default: + break; + } + + return base.ProcessCmdKey(ref msg, keys); + } + } +} diff --git a/Controls/AskHotKeyForm.resx b/Controls/AskHotKeyForm.resx new file mode 100644 index 0000000..a04fa62 --- /dev/null +++ b/Controls/AskHotKeyForm.resx @@ -0,0 +1,377 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAMAEBAAAAEAIABoBAAANgAAACAgAAABACAAqBAAAJ4EAAAwMAAAAQAgAKglAABGFQAAKAAAABAA + AAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAJAAAAcwEB + AXsBAQF7AQEBewEBAXsBAQF7AQEBewEBAXsBAQF7AQEBewEBAXsAAABzAAAACQAAAAEAAAABAAAACQAA + AHMBAQF7AQEBewEBAXsBAQF7AQEBewEBAXsBAQF7AQEBewEBAXsBAQF7AAAAcwAAAAkAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAACQAAAHUAAAB7AAAAewAAAHsAAAB7AAAAewAAAHsAAAB7AAAAewAAAHsAAAB7AAAAdQAA + AAkAAAABAAAAAQAAAAkAAABzAAAAewAAAHsAAAB7AAAAewAAAHsAAAB7AAAAewAAAHsAAAB7AAAAewAA + AHMAAAAJAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAkAAABzAQEBewEBAXsBAQF7AQEBewEBAXsBAQF7AQEBewEB + AXsBAQF7AQEBewAAAHMAAAAJAAAAAQAAAAEAAAAJAAAAcwEBAXsBAQF7AQEBewEBAXsBAQF7AQEBewEB + AXsBAQF7AQEBewEBAXsAAABzAAAACQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAAAABAAAAAAQAgAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAHwAAANkBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AAAA2QAAAB8AAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAfAAAA2QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUAAADZAAAAHwAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAFAAAAIQAAACUAAAAlAAAAJQAAACUAAAAlAAAAJQAA + ACUAAAAlAAAAJQAAACUAAAAlAAAAJQAAACUAAAAlAAAAJQAAACUAAAAlAAAAJQAAACUAAAAlAAAAJQAA + ACUAAAAhAAAABQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQEBARsAAAC5AAAA0QAAANEAAADRAAAA0QAA + ANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAA + ANEAAADRAAAA0QAAALkBAQEbAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAQEBGwEBAbkAAADRAAAA0QAA + ANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAA + ANEAAADRAAAA0QAAANEAAADRAQEBuQEBARsAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAFAQEBIQEB + ASUBAQElAQEBJQEBASUBAQElAQEBJQEBASUBAQElAQEBJQEBASUBAQElAQEBJQEBASUBAQElAQEBJQEB + ASUBAQElAQEBJQEBASUBAQElAQEBJQEBASUBAQEhAAAABQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAfAAAA2QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUAAADZAAAAHwAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAB8AAADZAQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QAAANkAAAAfAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAwAAAAYAAAAAEA + IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAABUAAABdAQEBcQAA + AHEBAQFxAQEBcQAAAHEBAQFxAQEBcQAAAHEBAQFxAAAAcQAAAHEAAABxAQEBcQAAAHEBAQFxAAAAcQEB + AXEAAABxAAAAcQEBAXEAAABxAQEBcQAAAHEBAQFxAQEBcQAAAHEAAABxAQEBcQAAAHEAAABxAQEBcQAA + AHEAAABxAQEBcQEBAV0AAAAVAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQEB + AS8AAADTAAAA/wAAAP8AAAD/AAAA/wAAAP8BAQH/AAAA/wAAAP8AAAD/AQEB/wAAAP8AAAD/AQEB/wAA + AP8AAAD/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEB/wAAAP8BAQH/AAAA/wEBAf8AAAD/AAAA/wEB + Af8BAQH/AAAA/wEBAf8BAQH/AAAA/wAAANMAAAAvAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQEBAS8AAADTAAAA/wEBAf8AAAD/AAAA/wEBAf8BAQH/AAAA/wAAAP8AAAD/AQEB/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AQEB/wAAAP8AAAD/AQEB/wAAAP8AAAD/AQEB/wAAAP8AAAD/AAAA/wEB + Af8AAAD/AAAA/wEBAf8BAQH/AAAA/wEBAf8BAQH/AAAA/wAAANMAAAAvAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAABUAAABdAQEBcQEBAXEBAQFxAQEBcQEBAXEBAQFxAQEBcQEB + AXEBAQFxAAAAcQAAAHEAAABxAQEBcQAAAHEBAQFxAAAAcQEBAXEAAABxAAAAcQEBAXEAAABxAQEBcQAA + AHEBAQFxAQEBcQAAAHEAAABxAQEBcQAAAHEAAABxAQEBcQAAAHEAAABxAQEBcQEBAV0AAAAVAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAABcAAABhAQEBdwAAAHcBAQF3AAAAdwEBAXcBAQF3AAAAdwEBAXcAAAB3AAAAdwEB + AXcAAAB3AQEBdwAAAHcAAAB3AAAAdwEBAXcBAQF3AAAAdwAAAHcAAAB3AQEBdwAAAHcBAQF3AQEBdwAA + AHcBAQF3AQEBdwAAAHcBAQF3AQEBdwAAAHcBAQF3AQEBdwAAAGEAAAAXAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAC8AAADPAQEB+QEBAfkAAAD5AAAA+QEBAfkBAQH5AAAA+QAA + APkAAAD5AAAA+QAAAPkAAAD5AAAA+QEBAfkAAAD5AAAA+QAAAPkAAAD5AAAA+QAAAPkBAQH5AAAA+QAA + APkAAAD5AAAA+QAAAPkAAAD5AAAA+QAAAPkAAAD5AAAA+QAAAPkAAAD5AAAA+QEBAc8AAAAvAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAC8AAADPAAAA+QAAAPkAAAD5AQEB+QAA + APkAAAD5AQEB+QEBAfkAAAD5AQEB+QAAAPkAAAD5AAAA+QEBAfkAAAD5AAAA+QEBAfkBAQH5AAAA+QEB + AfkBAQH5AAAA+QEBAfkAAAD5AAAA+QEBAfkAAAD5AAAA+QEBAfkBAQH5AQEB+QAAAPkBAQH5AQEB+QAA + AM8AAAAvAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQEBARcAAABhAQEBdQEB + AXUBAQF1AAAAdQEBAXUBAQF1AAAAdQEBAXUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAA + AHUAAAB1AQEBdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAA + AHUAAAB1AAAAdQEBAWEBAQEXAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAABUBAQFdAQEBcQAAAHEBAQFxAQEBcQAA + AHEAAABxAQEBcQEBAXEBAQFxAAAAcQAAAHEAAABxAQEBcQAAAHEBAQFxAAAAcQEBAXEBAQFxAAAAcQEB + AXEAAABxAQEBcQAAAHEBAQFxAAAAcQAAAHEBAQFxAQEBcQEBAXEBAQFxAQEBcQEBAXEAAABxAAAAcQEB + AV0AAAAVAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAC8BAQHTAAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAANMAAAAvAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AC8AAADTAQEB/wAAAP8AAAD/AAAA/wEBAf8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEB/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wEBAdMAAAAvAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAABUBAQFdAQEBcQAAAHEBAQFxAQEBcQAAAHEAAABxAQEBcQEBAXEBAQFxAAAAcQAA + AHEAAABxAQEBcQAAAHEBAQFxAAAAcQEBAXEBAQFxAAAAcQEBAXEAAABxAQEBcQAAAHEBAQFxAAAAcQAA + AHEBAQFxAQEBcQEBAXEBAQFxAQEBcQEBAXEAAABxAAAAcQEBAV0AAAAVAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + \ No newline at end of file diff --git a/Controls/DragDropHintForm.Designer.cs b/Controls/DragDropHintForm.Designer.cs new file mode 100644 index 0000000..66b48f3 --- /dev/null +++ b/Controls/DragDropHintForm.Designer.cs @@ -0,0 +1,140 @@ +namespace SystemTrayMenu.Controls +{ + partial class DragDropHintForm + { + /// + /// 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() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DragDropHintForm)); + this.tableLayoutPanelMain = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanelBottom = new System.Windows.Forms.TableLayoutPanel(); + this.buttonOk = new System.Windows.Forms.Button(); + this.labelHint = new System.Windows.Forms.Label(); + this.pictureBoxHint = new System.Windows.Forms.PictureBox(); + this.tableLayoutPanelMain.SuspendLayout(); + this.tableLayoutPanelBottom.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxHint)).BeginInit(); + this.SuspendLayout(); + // + // tableLayoutPanelMain + // + this.tableLayoutPanelMain.AutoSize = true; + this.tableLayoutPanelMain.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanelMain.ColumnCount = 1; + this.tableLayoutPanelMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanelMain.Controls.Add(this.tableLayoutPanelBottom, 0, 2); + this.tableLayoutPanelMain.Controls.Add(this.labelHint, 0, 0); + this.tableLayoutPanelMain.Controls.Add(this.pictureBoxHint, 0, 1); + this.tableLayoutPanelMain.Location = new System.Drawing.Point(12, 12); + this.tableLayoutPanelMain.Name = "tableLayoutPanelMain"; + this.tableLayoutPanelMain.RowCount = 3; + this.tableLayoutPanelMain.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanelMain.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanelMain.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanelMain.Size = new System.Drawing.Size(223, 149); + this.tableLayoutPanelMain.TabIndex = 0; + // + // tableLayoutPanelBottom + // + this.tableLayoutPanelBottom.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.tableLayoutPanelBottom.AutoSize = true; + this.tableLayoutPanelBottom.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanelBottom.ColumnCount = 3; + this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanelBottom.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanelBottom.Controls.Add(this.buttonOk, 1, 0); + this.tableLayoutPanelBottom.Location = new System.Drawing.Point(3, 117); + this.tableLayoutPanelBottom.Name = "tableLayoutPanelBottom"; + this.tableLayoutPanelBottom.RowCount = 1; + this.tableLayoutPanelBottom.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanelBottom.Size = new System.Drawing.Size(217, 29); + this.tableLayoutPanelBottom.TabIndex = 1; + // + // buttonOk + // + this.buttonOk.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonOk.Location = new System.Drawing.Point(71, 3); + this.buttonOk.Name = "buttonOk"; + this.buttonOk.Size = new System.Drawing.Size(75, 23); + this.buttonOk.TabIndex = 2; + this.buttonOk.Text = "OK"; + this.buttonOk.UseVisualStyleBackColor = true; + this.buttonOk.Click += new System.EventHandler(this.ButtonOk_Click); + // + // labelHint + // + this.labelHint.AutoSize = true; + this.labelHint.Location = new System.Drawing.Point(3, 0); + this.labelHint.MaximumSize = new System.Drawing.Size(217, 0); + this.labelHint.Name = "labelHint"; + this.labelHint.Size = new System.Drawing.Size(41, 13); + this.labelHint.TabIndex = 0; + this.labelHint.Text = "Hint: ..."; + // + // pictureBoxHint + // + this.pictureBoxHint.Image = global::SystemTrayMenu.Properties.Resources.hintDragDrop; + this.pictureBoxHint.Location = new System.Drawing.Point(3, 16); + this.pictureBoxHint.Name = "pictureBoxHint"; + this.pictureBoxHint.Size = new System.Drawing.Size(217, 95); + this.pictureBoxHint.TabIndex = 1; + this.pictureBoxHint.TabStop = false; + // + // DragDropHintForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.ClientSize = new System.Drawing.Size(302, 221); + this.Controls.Add(this.tableLayoutPanelMain); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "DragDropHintForm"; + this.Padding = new System.Windows.Forms.Padding(0, 0, 10, 0); + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "DragDropHintForm"; + this.tableLayoutPanelMain.ResumeLayout(false); + this.tableLayoutPanelMain.PerformLayout(); + this.tableLayoutPanelBottom.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pictureBoxHint)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanelMain; + private System.Windows.Forms.Button buttonOk; + private System.Windows.Forms.Label labelHint; + private System.Windows.Forms.PictureBox pictureBoxHint; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanelBottom; + } +} \ No newline at end of file diff --git a/Controls/DragDropHintForm.cs b/Controls/DragDropHintForm.cs new file mode 100644 index 0000000..75ffd14 --- /dev/null +++ b/Controls/DragDropHintForm.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace SystemTrayMenu.Controls +{ + public partial class DragDropHintForm : Form + { + public DragDropHintForm(string hintTitle, string hintText, + string buttonOk) + { + InitializeComponent(); + this.Text = hintTitle; + this.labelHint.Text = hintText; + this.buttonOk.Text = buttonOk; + } + + private void ButtonOk_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/Controls/DragDropHintForm.resx b/Controls/DragDropHintForm.resx new file mode 100644 index 0000000..a04fa62 --- /dev/null +++ b/Controls/DragDropHintForm.resx @@ -0,0 +1,377 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAMAEBAAAAEAIABoBAAANgAAACAgAAABACAAqBAAAJ4EAAAwMAAAAQAgAKglAABGFQAAKAAAABAA + AAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAJAAAAcwEB + AXsBAQF7AQEBewEBAXsBAQF7AQEBewEBAXsBAQF7AQEBewEBAXsAAABzAAAACQAAAAEAAAABAAAACQAA + AHMBAQF7AQEBewEBAXsBAQF7AQEBewEBAXsBAQF7AQEBewEBAXsBAQF7AAAAcwAAAAkAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAACQAAAHUAAAB7AAAAewAAAHsAAAB7AAAAewAAAHsAAAB7AAAAewAAAHsAAAB7AAAAdQAA + AAkAAAABAAAAAQAAAAkAAABzAAAAewAAAHsAAAB7AAAAewAAAHsAAAB7AAAAewAAAHsAAAB7AAAAewAA + AHMAAAAJAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAkAAABzAQEBewEBAXsBAQF7AQEBewEBAXsBAQF7AQEBewEB + AXsBAQF7AQEBewAAAHMAAAAJAAAAAQAAAAEAAAAJAAAAcwEBAXsBAQF7AQEBewEBAXsBAQF7AQEBewEB + AXsBAQF7AQEBewEBAXsAAABzAAAACQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAACAAAABAAAAAAQAgAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAHwAAANkBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AAAA2QAAAB8AAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAfAAAA2QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUAAADZAAAAHwAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAFAAAAIQAAACUAAAAlAAAAJQAAACUAAAAlAAAAJQAA + ACUAAAAlAAAAJQAAACUAAAAlAAAAJQAAACUAAAAlAAAAJQAAACUAAAAlAAAAJQAAACUAAAAlAAAAJQAA + ACUAAAAhAAAABQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQEBARsAAAC5AAAA0QAAANEAAADRAAAA0QAA + ANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAA + ANEAAADRAAAA0QAAALkBAQEbAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAQEBGwEBAbkAAADRAAAA0QAA + ANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAAANEAAADRAAAA0QAA + ANEAAADRAAAA0QAAANEAAADRAQEBuQEBARsAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAFAQEBIQEB + ASUBAQElAQEBJQEBASUBAQElAQEBJQEBASUBAQElAQEBJQEBASUBAQElAQEBJQEBASUBAQElAQEBJQEB + ASUBAQElAQEBJQEBASUBAQElAQEBJQEBASUBAQEhAAAABQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAfAAAA2QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUAAADZAAAAHwAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAB8AAADZAQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEBAfUBAQH1AQEB9QEB + AfUBAQH1AQEB9QEBAfUBAQH1AQEB9QAAANkAAAAfAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAwAAAAYAAAAAEA + IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAABUAAABdAQEBcQAA + AHEBAQFxAQEBcQAAAHEBAQFxAQEBcQAAAHEBAQFxAAAAcQAAAHEAAABxAQEBcQAAAHEBAQFxAAAAcQEB + AXEAAABxAAAAcQEBAXEAAABxAQEBcQAAAHEBAQFxAQEBcQAAAHEAAABxAQEBcQAAAHEAAABxAQEBcQAA + AHEAAABxAQEBcQEBAV0AAAAVAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQEB + AS8AAADTAAAA/wAAAP8AAAD/AAAA/wAAAP8BAQH/AAAA/wAAAP8AAAD/AQEB/wAAAP8AAAD/AQEB/wAA + AP8AAAD/AQEB/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEB/wAAAP8BAQH/AAAA/wEBAf8AAAD/AAAA/wEB + Af8BAQH/AAAA/wEBAf8BAQH/AAAA/wAAANMAAAAvAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQEBAS8AAADTAAAA/wEBAf8AAAD/AAAA/wEBAf8BAQH/AAAA/wAAAP8AAAD/AQEB/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AQEB/wAAAP8AAAD/AQEB/wAAAP8AAAD/AQEB/wAAAP8AAAD/AAAA/wEB + Af8AAAD/AAAA/wEBAf8BAQH/AAAA/wEBAf8BAQH/AAAA/wAAANMAAAAvAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAABUAAABdAQEBcQEBAXEBAQFxAQEBcQEBAXEBAQFxAQEBcQEB + AXEBAQFxAAAAcQAAAHEAAABxAQEBcQAAAHEBAQFxAAAAcQEBAXEAAABxAAAAcQEBAXEAAABxAQEBcQAA + AHEBAQFxAQEBcQAAAHEAAABxAQEBcQAAAHEAAABxAQEBcQAAAHEAAABxAQEBcQEBAV0AAAAVAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAABcAAABhAQEBdwAAAHcBAQF3AAAAdwEBAXcBAQF3AAAAdwEBAXcAAAB3AAAAdwEB + AXcAAAB3AQEBdwAAAHcAAAB3AAAAdwEBAXcBAQF3AAAAdwAAAHcAAAB3AQEBdwAAAHcBAQF3AQEBdwAA + AHcBAQF3AQEBdwAAAHcBAQF3AQEBdwAAAHcBAQF3AQEBdwAAAGEAAAAXAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAC8AAADPAQEB+QEBAfkAAAD5AAAA+QEBAfkBAQH5AAAA+QAA + APkAAAD5AAAA+QAAAPkAAAD5AAAA+QEBAfkAAAD5AAAA+QAAAPkAAAD5AAAA+QAAAPkBAQH5AAAA+QAA + APkAAAD5AAAA+QAAAPkAAAD5AAAA+QAAAPkAAAD5AAAA+QAAAPkAAAD5AAAA+QEBAc8AAAAvAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAC8AAADPAAAA+QAAAPkAAAD5AQEB+QAA + APkAAAD5AQEB+QEBAfkAAAD5AQEB+QAAAPkAAAD5AAAA+QEBAfkAAAD5AAAA+QEBAfkBAQH5AAAA+QEB + AfkBAQH5AAAA+QEBAfkAAAD5AAAA+QEBAfkAAAD5AAAA+QEBAfkBAQH5AQEB+QAAAPkBAQH5AQEB+QAA + AM8AAAAvAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQEBARcAAABhAQEBdQEB + AXUBAQF1AAAAdQEBAXUBAQF1AAAAdQEBAXUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAA + AHUAAAB1AQEBdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAAAHUAAAB1AAAAdQAA + AHUAAAB1AAAAdQEBAWEBAQEXAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAABUBAQFdAQEBcQAAAHEBAQFxAQEBcQAA + AHEAAABxAQEBcQEBAXEBAQFxAAAAcQAAAHEAAABxAQEBcQAAAHEBAQFxAAAAcQEBAXEBAQFxAAAAcQEB + AXEAAABxAQEBcQAAAHEBAQFxAAAAcQAAAHEBAQFxAQEBcQEBAXEBAQFxAQEBcQEBAXEAAABxAAAAcQEB + AV0AAAAVAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAC8BAQHTAAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAANMAAAAvAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AC8AAADTAQEB/wAAAP8AAAD/AAAA/wEBAf8BAQH/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AQEB/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wEBAdMAAAAvAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAABUBAQFdAQEBcQAAAHEBAQFxAQEBcQAAAHEAAABxAQEBcQEBAXEBAQFxAAAAcQAA + AHEAAABxAQEBcQAAAHEBAQFxAAAAcQEBAXEBAQFxAAAAcQEBAXEAAABxAQEBcQAAAHEBAQFxAAAAcQAA + AHEBAQFxAQEBcQEBAXEBAQFxAQEBcQEBAXEAAABxAAAAcQEBAV0AAAAVAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAA + AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + \ No newline at end of file diff --git a/Controls/Menu.Designer.cs b/Controls/Menu.Designer.cs new file mode 100644 index 0000000..3c27043 --- /dev/null +++ b/Controls/Menu.Designer.cs @@ -0,0 +1,183 @@ +using SystemTrayMenu.Controls; + +namespace SystemTrayMenu +{ + partial class Menu + { + /// + /// 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(); + } + FadeForm.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() + { + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle(); + System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle(); + this.labelTitle = new System.Windows.Forms.Label(); + this.dgv = new System.Windows.Forms.DataGridView(); + this.ColumnIcon = new System.Windows.Forms.DataGridViewImageColumn(); + this.ColumnText = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + ((System.ComponentModel.ISupportInitialize)(this.dgv)).BeginInit(); + this.tableLayoutPanel.SuspendLayout(); + this.SuspendLayout(); + // + // labelTitle + // + this.labelTitle.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right))); + this.labelTitle.AutoSize = true; + this.labelTitle.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(229)))), ((int)(((byte)(243)))), ((int)(((byte)(255))))); + this.labelTitle.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelTitle.ForeColor = System.Drawing.Color.Black; + this.labelTitle.Location = new System.Drawing.Point(0, 0); + this.labelTitle.Margin = new System.Windows.Forms.Padding(0); + this.labelTitle.Name = "labelTitle"; + this.labelTitle.Padding = new System.Windows.Forms.Padding(3, 0, 0, 1); + this.labelTitle.Size = new System.Drawing.Size(361, 14); + this.labelTitle.TabIndex = 2; + this.labelTitle.Text = "STM"; + this.labelTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.labelTitle.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.LabelTitle_MouseDoubleClick); + this.labelTitle.MouseEnter += new System.EventHandler(this.LabelTitle_MouseEnter); + this.labelTitle.MouseLeave += new System.EventHandler(this.LabelTitle_MouseLeave); + this.labelTitle.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.dgv_MouseWheel); + // + // dgv + // + this.dgv.AllowUserToAddRows = false; + this.dgv.AllowUserToDeleteRows = false; + this.dgv.AllowUserToResizeColumns = false; + this.dgv.AllowUserToResizeRows = false; + this.dgv.BackgroundColor = System.Drawing.Color.White; + this.dgv.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.dgv.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.None; + this.dgv.ClipboardCopyMode = System.Windows.Forms.DataGridViewClipboardCopyMode.Disable; + this.dgv.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.None; + this.dgv.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + this.dgv.ColumnHeadersVisible = false; + this.dgv.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.ColumnIcon, + this.ColumnText}); + this.dgv.Location = new System.Drawing.Point(0, 14); + this.dgv.Margin = new System.Windows.Forms.Padding(0); + this.dgv.Name = "dgv"; + this.dgv.RowHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.None; + this.dgv.RowHeadersVisible = false; + this.dgv.RowHeadersWidthSizeMode = System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing; + dataGridViewCellStyle3.Font = new System.Drawing.Font("Segoe UI", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Pixel, ((byte)(0))); + this.dgv.RowsDefaultCellStyle = dataGridViewCellStyle3; + this.dgv.RowTemplate.DefaultCellStyle.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.dgv.RowTemplate.Height = 20; + this.dgv.RowTemplate.ReadOnly = true; + this.dgv.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.dgv.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; + this.dgv.ShowCellErrors = false; + this.dgv.ShowCellToolTips = false; + this.dgv.ShowEditingIcon = false; + this.dgv.ShowRowErrors = false; + this.dgv.Size = new System.Drawing.Size(361, 390); + this.dgv.TabIndex = 4; + this.dgv.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.dgv_MouseWheel); + // + // ColumnIcon + // + dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter; + dataGridViewCellStyle1.NullValue = "System.Drawing.Icon"; + dataGridViewCellStyle1.Padding = new System.Windows.Forms.Padding(3, 2, 6, 2); + this.ColumnIcon.DefaultCellStyle = dataGridViewCellStyle1; + this.ColumnIcon.Frozen = true; + this.ColumnIcon.HeaderText = "ColumnIcon"; + this.ColumnIcon.ImageLayout = System.Windows.Forms.DataGridViewImageCellLayout.Zoom; + this.ColumnIcon.Name = "ColumnIcon"; + this.ColumnIcon.ReadOnly = true; + this.ColumnIcon.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.ColumnIcon.Width = 25; + // + // ColumnText + // + dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft; + dataGridViewCellStyle2.Padding = new System.Windows.Forms.Padding(0, 0, 3, 0); + this.ColumnText.DefaultCellStyle = dataGridViewCellStyle2; + this.ColumnText.Frozen = true; + this.ColumnText.HeaderText = "ColumnText"; + this.ColumnText.MaxInputLength = 40; + this.ColumnText.Name = "ColumnText"; + this.ColumnText.ReadOnly = true; + this.ColumnText.Resizable = System.Windows.Forms.DataGridViewTriState.False; + this.ColumnText.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Programmatic; + this.ColumnText.Width = 50; + // + // tableLayoutPanel + // + this.tableLayoutPanel.AutoScroll = true; + this.tableLayoutPanel.AutoSize = true; + this.tableLayoutPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel.ColumnCount = 1; + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel.Controls.Add(this.dgv, 0, 1); + this.tableLayoutPanel.Controls.Add(this.labelTitle, 0, 0); + this.tableLayoutPanel.Location = new System.Drawing.Point(1, 1); + this.tableLayoutPanel.Margin = new System.Windows.Forms.Padding(0); + this.tableLayoutPanel.Name = "tableLayoutPanel"; + this.tableLayoutPanel.RowCount = 2; + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.Size = new System.Drawing.Size(361, 404); + this.tableLayoutPanel.TabIndex = 3; + this.tableLayoutPanel.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.dgv_MouseWheel); + // + // Menu + // + this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.BackColor = System.Drawing.Color.Black; + this.ClientSize = new System.Drawing.Size(707, 611); + this.Controls.Add(this.tableLayoutPanel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Name = "Menu"; + this.Opacity = 0.01D; + this.Padding = new System.Windows.Forms.Padding(1); + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.Text = "SystemTrayMenu"; + this.TopMost = true; + this.Deactivate += new System.EventHandler(this.Menu_Deactivate); + ((System.ComponentModel.ISupportInitialize)(this.dgv)).EndInit(); + this.tableLayoutPanel.ResumeLayout(false); + this.tableLayoutPanel.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.Label labelTitle; + private System.Windows.Forms.DataGridView dgv; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel; + private System.Windows.Forms.DataGridViewImageColumn ColumnIcon; + private System.Windows.Forms.DataGridViewTextBoxColumn ColumnText; + } +} \ No newline at end of file diff --git a/Controls/Menu.cs b/Controls/Menu.cs new file mode 100644 index 0000000..19ed52a --- /dev/null +++ b/Controls/Menu.cs @@ -0,0 +1,313 @@ +using System; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; +using SystemTrayMenu.Controls; + +namespace SystemTrayMenu +{ + public partial class Menu : Form, IDisposable + { + public new event EventHandler MouseWheel; + public event EventHandler Deactivated; + public event EventHandler UserClickedOpenFolder; + + public event Action CmdKeyProcessed; + + public enum Type + { + Main, + Sub, + Empty, + MaxReached + } + + public bool IsFadingIn + { + get + { + return FadeForm.IsFadingIn; + } + } + + public bool IsFadingOut + { + get + { + return FadeForm.IsFadingOut; + } + } + + public int Level = 0; + FadeForm FadeForm = null; + + public Menu() + { + FadeForm = new FadeForm(this); + InitializeComponent(); + SetDoubleBuffer(dgv, true); + + DataGridViewCellStyle dgvCellStyle = new DataGridViewCellStyle(); + dgvCellStyle.SelectionBackColor = MenuDefines.FileHover; + dgvCellStyle.SelectionForeColor = Color.Black; + this.dgv.DefaultCellStyle = dgvCellStyle; + } + + static void SetDoubleBuffer(Control ctl, bool DoubleBuffered) + { + typeof(Control).InvokeMember("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, + null, ctl, new object[] { DoubleBuffered }); + } + + public void SetTypeSub() + { + SetType(Type.Sub); + } + public void SetTypeEmpty() + { + SetType(Type.Empty); + } + + public void SetType(Type type) + { + switch (type) + { + case Type.Sub: + if (!labelTitle.IsDisposed) + { + labelTitle.Dispose(); + } + break; + case Type.Empty: + SetTitle(Program.Translate("Folder empty")); + labelTitle.BackColor = MenuDefines.Background; + break; + case Type.MaxReached: + SetTitle($"Max {MenuDefines.MenusMax - 1} Menus"); + labelTitle.BackColor = MenuDefines.Background; + break; + case Type.Main: + break; + default: + break; + } + } + + public bool IsVisible() + { + return Visible; + } + + public bool IsActive(Form activeForm) + { + bool isActive = (this == activeForm); + return isActive; + } + + public bool IsMouseOn(Point mousePosition) + { + bool isMouseOn = Visible && Opacity >= MenuDefines.OpacityHalfValue + && ClientRectangle.Contains( + PointToClient(mousePosition)); + return isMouseOn; + } + + public DataGridView GetDataGridView() + { + return dgv; + } + + public void SetTitle(string title) + { + if (title.Length > MenuDefines.LengthMax) + { + title = $"{title.Substring(0, MenuDefines.LengthMax)}..."; + } + labelTitle.Text = title; + } + + public void FadeIn() + { + FadeForm.FadeIn(); + } + + public void FadeHalf() + { + FadeForm.FadeHalf(); + } + + public void FadeOut() + { + FadeForm.FadeOut(); + } + + public void AdjustLocationAndSize(Screen screen) + { + DataGridViewElementStates states = DataGridViewElementStates.None; + dgv.AutoResizeRows(); + int height = (int)(dgv.Rows.GetRowsHeight(states)); + int heightMax = screen.Bounds.Height - + new Taskbar().Size.Height - + labelTitle.Height; + if (height > heightMax) + { + height = heightMax; + } + dgv.Height = height; + AdjustDataGridViewSize(); + int x = screen.Bounds.Right - Width; + int y = heightMax - Height + labelTitle.Height; + + Location = new Point(x, y); + } + + public void AdjustLocationAndSize(int heightMax, int widthPredecessors, + Menu menuPredecessor) + { + DataGridViewElementStates states = DataGridViewElementStates.None; + this.dgv.AutoResizeRows(); + int height = this.dgv.Rows.GetRowsHeight(states); + if (height > heightMax) + { + height = heightMax; + } + this.dgv.Height = height; + + AdjustDataGridViewSize(); + int x = menuPredecessor.Location.X - Width + + (int)Math.Round(Program.ScalingFactor, 0, + MidpointRounding.AwayFromZero); + + RowData trigger = (RowData)Tag; + DataGridView dgv = menuPredecessor.GetDataGridView(); + if (dgv.Rows.Count > trigger.RowIndex) + { + var cellRectangle = dgv.GetCellDisplayRectangle( + 0, trigger.RowIndex, false); + int y = menuPredecessor.Location.Y + + menuPredecessor.dgv.Location.Y + + cellRectangle.Top; + if ((y + Height) > heightMax) + { + y = heightMax - Height; + } + + Location = new Point(x, y); + } + } + + private void AdjustDataGridViewSize() + { + dgv.AutoResizeColumns(); + bool scrollbarShown = false; + foreach (var scroll in dgv.Controls.OfType()) + { + if (scroll.Visible) + { + scroll.Width = 120; + scrollbarShown = true; + } + } + int newWidth = dgv.Columns[0].Width + dgv.Columns[1].Width; + if (scrollbarShown) + { + newWidth += SystemInformation.VerticalScrollBarWidth; + } + dgv.Width = newWidth; + } + + private void dgv_MouseWheel(object sender, MouseEventArgs e) + { + ((HandledMouseEventArgs)e).Handled = true; + int scrollspeed = MenuDefines.Scrollspeed; + if (e.Delta < 0) + { + if (dgv.FirstDisplayedScrollingRowIndex < dgv.Rows.Count - scrollspeed) + { + dgv.FirstDisplayedScrollingRowIndex += scrollspeed; + } + else + { + dgv.FirstDisplayedScrollingRowIndex = dgv.Rows.Count - 1; + } + } + else + { + if (dgv.FirstDisplayedScrollingRowIndex > 0 + scrollspeed) + { + dgv.FirstDisplayedScrollingRowIndex -= scrollspeed; + } + else + { + dgv.FirstDisplayedScrollingRowIndex = 0; + } + } + + dgv.PerformLayout(); + MouseWheel.Invoke(); + } + + private void Menu_Deactivate(object sender, EventArgs e) + { + Deactivated?.Invoke(); + } + + public void SetTitleColorDeactive() + { + this.labelTitle.ForeColor = Color.LightGray; + } + + public void SetTitleColorActive() + { + this.labelTitle.ForeColor = Color.Black; + } + + private void LabelTitle_MouseDoubleClick(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + UserClickedOpenFolder?.Invoke(); + } + } + + private void LabelTitle_MouseEnter(object sender, EventArgs e) + { + this.labelTitle.BackColor = MenuDefines.FileHover; + } + + private void LabelTitle_MouseLeave(object sender, EventArgs e) + { + this.labelTitle.BackColor = MenuDefines.Background; + } + + protected override CreateParams CreateParams + { + get + { + var Params = base.CreateParams; + Params.ExStyle |= 0x80; + return Params; + } + } + + protected override bool ProcessCmdKey(ref Message msg, Keys keys) + { + switch (keys) + { + case Keys.Enter: + case Keys.Up: + case Keys.Down: + case Keys.Left: + case Keys.Right: + case Keys.Escape: + CmdKeyProcessed.Invoke(keys); + return true; + default: + break; + } + return base.ProcessCmdKey(ref msg, keys); + } + } +} \ No newline at end of file diff --git a/Controls/Menu.resx b/Controls/Menu.resx new file mode 100644 index 0000000..b1c3d17 --- /dev/null +++ b/Controls/Menu.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + \ No newline at end of file diff --git a/Controls/MenuData.cs b/Controls/MenuData.cs new file mode 100644 index 0000000..543dd38 --- /dev/null +++ b/Controls/MenuData.cs @@ -0,0 +1,24 @@ +using Clearcove.Logging; +using IWshRuntimeLibrary; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; +using SystemTrayMenu.Helper; +using TAFactory.IconPack; + +namespace SystemTrayMenu.Controls +{ + public struct MenuData + { + public List RowDatas; + public bool Valid; + public int Level; + }; +} \ No newline at end of file diff --git a/Controls/RowData.cs b/Controls/RowData.cs new file mode 100644 index 0000000..b2918b8 --- /dev/null +++ b/Controls/RowData.cs @@ -0,0 +1,480 @@ +using Clearcove.Logging; +using IWshRuntimeLibrary; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; +using SystemTrayMenu.Helper; +using TAFactory.IconPack; + +namespace SystemTrayMenu.Controls +{ + public class RowData : IDisposable + { + public FileInfo FileInfo; + public Icon Icon; + public bool ContainsMenu; + public bool IsContextMenuOpen; + public bool ResolvedFileNotFound; + public string WorkingDirectory; + public string Arguments; + + public bool IsResolvedLnk; + public string TargetFilePath; + public string Text; + + + public Menu SubMenu; + public int RowIndex; + + public bool IsSelected; + public bool IsSelectedByKeyboard; + + public bool ReadIcon(bool isDirectory, bool isResolvedLnk, ref string resolvedLnkPath) + { + bool isLnkDirectory = false; + + Logger log = new Logger(nameof(RowData)); + + if (isResolvedLnk) + { + if (Icon == null) + { + Icon = IconReader.GetFolderIcon(TargetFilePath, + IconReader.FolderType.Open, true); + } + } + else if (isDirectory) + { + Icon = IconReader.GetFolderIcon(TargetFilePath, + IconReader.FolderType.Closed, false); + } + else if (!string.IsNullOrEmpty(TargetFilePath)) + { + bool handled = false; + string fileExtension = Path.GetExtension(TargetFilePath); + + if (fileExtension == ".lnk") + { + handled = SetLnk(log, ref isLnkDirectory, + ref resolvedLnkPath); + } + else if (fileExtension == ".url") + { + handled = SetUrl(log); + } + else if (fileExtension == ".sln") + { + handled = SetSln(log); + } + + if (!handled) + { + try + { + Icon = IconReader.GetFileIcon(TargetFilePath, false); + + // other project -> fails sometimes + //icon = IconHelper.ExtractIcon(TargetFilePath, 0); + + // standard way -> fails sometimes + //icon = Icon.ExtractAssociatedIcon(filePath); + + // API Code Pack -> fails sometimes + //ShellFile shellFile = ShellFile.FromFilePath(filePath); + //Bitmap shellThumb = shellFile.Thumbnail.ExtraLargeBitmap; + } + catch (Exception ex) + { + log.Info($"TargetFilePath:'{TargetFilePath}'"); + log.Error($"{ex.ToString()}"); + } + } + } + + return isLnkDirectory; + } + + private bool SetLnk(Logger log, ref bool isLnkDirectory, + ref string resolvedLnkPath) + { + bool handled = false; + resolvedLnkPath = LnkHelper.ResolveShortcut(TargetFilePath); + if (LnkHelper.IsDirectory(resolvedLnkPath)) + { + Icon = IconReader.GetFolderIcon(TargetFilePath, + IconReader.FolderType.Open, true); + handled = true; + isLnkDirectory = true; + } + else if (string.IsNullOrEmpty(resolvedLnkPath)) + { + ResolvedFileNotFound = true; + log.Info($"Resolve '{TargetFilePath}' not possible => no icon"); + } + else + { + IWshShell shell = new WshShell(); + var lnk = shell.CreateShortcut(TargetFilePath) + as IWshShortcut; + Arguments = lnk.Arguments; + WorkingDirectory = lnk.WorkingDirectory; + string iconLocation = lnk.IconLocation; + if (iconLocation.Length > 2) + { + iconLocation = iconLocation.Substring(0, + iconLocation.Length - 2); + if (System.IO.File.Exists(iconLocation)) + { + try + { + Icon = Icon.ExtractAssociatedIcon(iconLocation); + handled = true; + } + catch (Exception ex) + { + log.Info($"iconLocation:'{iconLocation}'"); + log.Error($"{ex.ToString()}"); + } + } + } + + TargetFilePath = resolvedLnkPath; + } + + SetText($"{FileInfo.Name.Substring(0, FileInfo.Name.Length - 4)}"); + + return handled; + } + + private bool SetUrl(Logger log) + { + bool handled = false; + string iconFile = string.Empty; + try + { + FileIni file = new FileIni(TargetFilePath); + iconFile = file.Value("IconFile", string.Empty); + if (string.IsNullOrEmpty(iconFile)) + { + string browserPath = FileUrl.GetDefaultBrowserPath(); + if (string.IsNullOrEmpty(browserPath)) + { + log.Info($"No default browser found!"); + } + else + { + Icon = IconReader.GetFileIcon(browserPath, false); + handled = true; + } + } + else if (System.IO.File.Exists(iconFile)) + { + Icon = Icon.ExtractAssociatedIcon(iconFile); + handled = true; + } + else + { + log.Info($"Resolve '{TargetFilePath}' not possible => no icon"); + } + } + catch (Exception ex) + { + log.Info($"TargetFilePath:'{TargetFilePath}', " + + $"iconFile:'{iconFile}'"); + log.Error($"{ex.ToString()}"); + } + + SetText($"{FileInfo.Name.Substring(0, FileInfo.Name.Length - 4)}"); + + return handled; + } + + [DllImport("shell32.dll")] + static extern int FindExecutable(string lpFile, string lpDirectory, [Out] StringBuilder lpResult); + private bool SetSln(Logger log) + { + bool handled = false; + var executable = new StringBuilder(1024); + try + { + FindExecutable(TargetFilePath, string.Empty, executable); + // icon = IconReader.GetFileIcon(executable, false); + // e.g. VS 2019 icon, need another icom in imagelist + List extractedIcons = IconHelper.ExtractAllIcons( + executable.ToString()); + Icon = extractedIcons.Last(); + handled = true; + } + catch (Exception ex) + { + log.Info($"TargetFilePath:'{TargetFilePath}', " + + $"executable:'{executable.ToString()}'"); + log.Error($"{ex.ToString()}"); + } + + return handled; + } + + public void SetText(string text) + { + //text = $" {text}"; + if (text.Length > MenuDefines.LengthMax) + { + text = $"{text.Substring(0, MenuDefines.LengthMax)}..."; + } + Text = text; + } + + +#warning sort this class and check for duplicated + + public event Action OpenMenu; + + public bool IsLoading = false; + public bool RestartLoading = false; + public BackgroundWorker Reading = new BackgroundWorker(); + + Icon icon = null; + //FontFamily fontFamily = new FontFamily("Segoe UI"); + //Font font = new Font(new FontFamily("Segoe UI"), 12F, + // FontStyle.Regular, GraphicsUnit.Pixel); + + WaitMenuOpen waitMenuOpen = new WaitMenuOpen(); + bool resolvedFileNotFound = false; + + bool disposed = false; + Logger log = new Logger(nameof(RowData)); + internal string TargetFilePathOrig; + + public RowData() + { + Reading.WorkerSupportsCancellation = true; + + Initialize(); + void Initialize() + { + //Margin = new Padding(0, 0, 0, 0); + //FlatAppearance.BorderSize = 0; + //UseVisualStyleBackColor = true; + //FlatStyle = FlatStyle.Flat; + //BackColor = MenuDefines.File; + //FlatAppearance.BorderColor = MenuDefines.File; + //Anchor = (AnchorStyles.Left | AnchorStyles.Right); + //AutoSize = true; + //AutoSizeMode = AutoSizeMode.GrowAndShrink; + //Font = new Font(fontFamily, 7, FontStyle.Regular, GraphicsUnit.Pixel); + //ForeColor = Color.Black; + waitMenuOpen.DoOpen += WaitMenuOpen_DoOpen; + + //MouseLeave += MenuButton_MouseLeave; + //void MenuButton_MouseLeave(object sender, EventArgs e) + //{ + // if (Tag == null && + // !isContextMenuOpen && + // !ContainsMenu) + // { + // BackColor = MenuDefines.File; + // } + //} + + //MouseEnter += Menubutton_MouseEnter; + //void Menubutton_MouseEnter(object sender, EventArgs e) + //{ + // if (Tag == null && + // !ContainsMenu) + // { + // BackColor = MenuDefines.FileHover; + // } + //} + + //BackColorChanged += MenuButton_BackColorChanged; + //void MenuButton_BackColorChanged(object sender, EventArgs e) + //{ + // FlatAppearance.BorderColor = BackColor; + //} + + + } + } + + //DoubleClick += MenuButton_DoubleClick; + public void DoubleClick() + { + if (ContainsMenu) + { + try + { + Process.Start("explorer.exe", TargetFilePath); + } + catch (Exception ex) + { + log.Info($"TargetFilePath:'{TargetFilePath}', " + + $"=>DirectoryNotFound?"); + log.Error($"{ex.ToString()}"); + ex = new DirectoryNotFoundException(); + MessageBox.Show(ex.Message); + } + } + } + + //MouseDown += MenuButton_MouseDown; + public void MouseDown(DataGridView dgv, MouseEventArgs e) + { + if (ContainsMenu) + { + TriggerMenuOpener(); // Touchscreen + } + + if (IsLoading) + { + waitMenuOpen.Click(); + } + + if (e == null || + e.Button == MouseButtons.Left && + !ContainsMenu) + { + try + { + //https://stackoverflow.com/questions/31627801/ + Process p = new Process(); + p.StartInfo = new ProcessStartInfo(TargetFilePath); + p.StartInfo.Arguments = Arguments; + p.StartInfo.WorkingDirectory = WorkingDirectory; + p.StartInfo.CreateNoWindow = true; + p.Start(); + } + catch (Exception ex) + { + log.Info($"TargetFilePath:'{ TargetFilePath}', " + + $"=>FileNotFound?"); + log.Error($"{ex.ToString()}"); + if (resolvedFileNotFound) + { + ex = new FileNotFoundException(); + } + MessageBox.Show(ex.Message); + } + } + + if (e != null && + e.Button == MouseButtons.Right && + FileInfo != null && + dgv.Rows.Count > RowIndex) + { + IsContextMenuOpen = true; + +#warning is there any other possiblity to raise selection changed event? dataGridView.ClearSelection(); seems to overwrite selected + IsSelected = true; + dgv.Rows[RowIndex].Selected = true; + + try + { + ShellContextMenu ctxMnu = new ShellContextMenu(); + Point location = dgv.FindForm().Location; + Point point = new Point( + e.X + location.X + dgv.Location.X, + e.Y + location.Y + dgv.Location.Y); + if (ContainsMenu) + { + DirectoryInfo[] dir = new DirectoryInfo[1]; + dir[0] = new DirectoryInfo(TargetFilePathOrig); + ctxMnu.ShowContextMenu(dir, point); + } + else + { + FileInfo[] arrFI = new FileInfo[1]; + arrFI[0] = new FileInfo(TargetFilePathOrig); + ctxMnu.ShowContextMenu(arrFI, point); + } + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString() + TargetFilePath); + } + + if (!dgv.IsDisposed) + { + IsSelected = false; + dgv.Rows[RowIndex].Selected = false; + } + + IsContextMenuOpen = false; + } + } + + public void MenuLoaded() + { + waitMenuOpen.MenuLoaded(); + } + + public void StartMenuOpener() + { + if (ContainsMenu) + { + IsLoading = true; + waitMenuOpen.Start(); + } + } + + private void TriggerMenuOpener() + { + if (ContainsMenu && IsLoading) + { + waitMenuOpen.Start(); + } + } + + public void StopLoadMenuAndStartWaitToOpenIt() + { + if (ContainsMenu) + { + waitMenuOpen.Stop(); + //IsLoading = false; + } + } + + private void WaitMenuOpen_DoOpen() + { + IsLoading = false; + OpenMenu?.Invoke(this, null); + } + + public void SetData(RowData data, DataGridView dgv) + { + data.RowIndex = dgv.Rows.Add(); + DataGridViewRow row = dgv.Rows[data.RowIndex]; + + if (Icon == null) + { + Icon = Properties.Resources.SystemTrayMenu; + } + DataGridViewImageCell cellIcon = + (DataGridViewImageCell)row.Cells[0]; + cellIcon.Value = data.Icon; + + DataGridViewTextBoxCell cellName = + (DataGridViewTextBoxCell)row.Cells[1]; + cellName.Value = data.Text; + + row.Tag = data; + } + + public void Dispose() + { + if (!disposed) + { + icon?.Dispose(); + waitMenuOpen.Dispose(); + } + disposed = true; + } + } +} diff --git a/Helper/BringWindowToTop.cs b/Helper/BringWindowToTop.cs new file mode 100644 index 0000000..e49705c --- /dev/null +++ b/Helper/BringWindowToTop.cs @@ -0,0 +1,62 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace SystemTrayMenu.Helper +{ + public class WindowToTop + { + [DllImport("user32.dll")] + static extern bool IsIconic(IntPtr hWnd); + + //DLL's for ForceForgroundWindow + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr GetForegroundWindow(); + [DllImport("user32.dll")] + public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); + [DllImport("kernel32.dll")] + public static extern uint GetCurrentThreadId(); + [DllImport("user32.dll")] + public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach); + [DllImport("user32.dll", SetLastError = true)] + public static extern bool BringWindowToTop(IntPtr hWnd); + //[DllImport("user32.dll", SetLastError = true)] + //public static extern bool BringWindowToTop(HandleRef hWnd); + [DllImport("user32.dll")] + public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + + const int SW_RESTORE = 9; + + public static void ForceProcessToForeground(string processName) + { + Process[] proc = Process.GetProcessesByName(processName); + ForceForegroundWindow(proc[0].MainWindowHandle); + } + public static void ForceForegroundWindow(IntPtr hWnd) + { + uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero); + uint appThread = GetCurrentThreadId(); + const int SW_SHOW = 5; + + int cmdShow = SW_SHOW; + + if (IsIconic(hWnd)) + { + cmdShow = SW_RESTORE; + } + + if (foreThread != appThread) + { + AttachThreadInput(foreThread, appThread, true); + BringWindowToTop(hWnd); + ShowWindow(hWnd, cmdShow); + AttachThreadInput(foreThread, appThread, false); + } + else + { + BringWindowToTop(hWnd); + ShowWindow(hWnd, cmdShow); + } + } + } +} \ No newline at end of file diff --git a/Helper/FadeForm.cs b/Helper/FadeForm.cs new file mode 100644 index 0000000..a0f109f --- /dev/null +++ b/Helper/FadeForm.cs @@ -0,0 +1,169 @@ +using System; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace SystemTrayMenu +{ + public class FadeForm : IDisposable + { + public bool IsFadingIn + { + get + { + return timerFadeIn.Enabled; + } + } + + public bool IsFadingOut + { + get + { + return timerFadeOut.Enabled; + } + } + + Timer timerFadeIn = new Timer(); + Timer timerFadeOut = new Timer(); + Timer timerFadeHalf = new Timer(); + + Form form = null; + bool stopFadeInByHalf = false; + + public FadeForm(Form form) + { + this.form = form; + timerFadeIn.Interval = MenuDefines.IntervalFade; + timerFadeOut.Interval = MenuDefines.IntervalFade; + timerFadeHalf.Interval = MenuDefines.IntervalFade; + timerFadeIn.Tick += TimerFadeIn_Tick; + timerFadeOut.Tick += TimerFadeOut_Tick; + timerFadeHalf.Tick += TimerFadeHalf_Tick; + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + timerFadeIn.Dispose(); + timerFadeOut.Dispose(); + timerFadeHalf.Dispose(); + } + } + + public void FadeOut() + { + timerFadeHalf.Stop(); + timerFadeIn.Stop(); + timerFadeOut.Start(); + } + + public void FadeHalf() + { + if (form.Visible && + form.Opacity < MenuDefines.OpacityHalfValue) + { + stopFadeInByHalf = true; + timerFadeOut.Stop(); + timerFadeHalf.Stop(); + timerFadeIn.Start(); + } + else + { + timerFadeIn.Stop(); + timerFadeOut.Stop(); + timerFadeHalf.Start(); + } + } + + public void FadeIn() + { + stopFadeInByHalf = false; + if (form.Visible) + { + timerFadeOut.Stop(); + timerFadeHalf.Stop(); + timerFadeIn.Start(); + } + else + { + ShowInactiveTopmost(form); + timerFadeOut.Stop(); + timerFadeIn.Start(); + } + } + + private void TimerFadeIn_Tick(object sender, EventArgs e) + { + if (form.Opacity >= 1 || + (stopFadeInByHalf && form.Opacity >= MenuDefines.OpacityHalfValue)) + { + if (stopFadeInByHalf) + { + form.Opacity = MenuDefines.OpacityHalfValue; + stopFadeInByHalf = false; + } + timerFadeIn.Stop(); + } + else + { + form.Opacity += MenuDefines.OpacityInStep; + } + } + + private void TimerFadeOut_Tick(object sender, EventArgs e) + { + if (form.Opacity < 0.01) + { + form.Hide(); + timerFadeOut.Stop(); + } + else + { + form.Opacity -= MenuDefines.OpacityOutStep; + } + } + + private void TimerFadeHalf_Tick(object sender, EventArgs e) + { + if (form.Opacity <= MenuDefines.OpacityHalfValue) + { + form.Opacity = MenuDefines.OpacityHalfValue; + timerFadeHalf.Stop(); + } + else + { + form.Opacity -= MenuDefines.OpacityHalfStep; + } + } + + private const int SW_SHOWNOACTIVATE = 4; + private const int HWND_TOPMOST = -1; + private const uint SWP_NOACTIVATE = 0x0010; + + [DllImport("user32.dll", EntryPoint = "SetWindowPos")] + static extern bool SetWindowPos( + int hWnd, // Window handle + int hWndInsertAfter, // Placement-order handle + int X, // Horizontal position + int Y, // Vertical position + int cx, // Width + int cy, // Height + uint uFlags); // Window positioning flags + + [DllImport("user32.dll")] + static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + + static void ShowInactiveTopmost(Form frm) + { + ShowWindow(frm.Handle, SW_SHOWNOACTIVATE); + SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST, + frm.Left, frm.Top, frm.Width, frm.Height, + SWP_NOACTIVATE); + } + } +} \ No newline at end of file diff --git a/Helper/File/FileIni.cs b/Helper/File/FileIni.cs new file mode 100644 index 0000000..6fc2fc3 --- /dev/null +++ b/Helper/File/FileIni.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace SystemTrayMenu.Helper +{ + public class FileIni + { + Dictionary values; + public FileIni(string path) + { + values = File.ReadLines(path) + .Where(line => (!String.IsNullOrWhiteSpace(line) && !line.StartsWith("#"))) + .Select(line => line.Split(new char[] { '=' }, 2, 0)) + .ToDictionary(parts => parts[0].Trim(), parts => parts.Length > 1 ? parts[1].Trim() : null); + } + public string Value(string name, string value = null) + { + if (values != null && values.ContainsKey(name)) + { + return values[name]; + } + return value; + } + } +} diff --git a/Helper/File/FileLnk.cs b/Helper/File/FileLnk.cs new file mode 100644 index 0000000..538d9f4 --- /dev/null +++ b/Helper/File/FileLnk.cs @@ -0,0 +1,218 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace SystemTrayMenu +{ + class LnkHelper + { + #region Signitures imported from http://pinvoke.net + + [DllImport("shfolder.dll", CharSet = CharSet.Auto)] + internal static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken, int dwFlags, StringBuilder lpszPath); + + [Flags()] + enum SLGP_FLAGS + { + /// Retrieves the standard short (8.3 format) file name + SLGP_SHORTPATH = 0x1, + /// Retrieves the Universal Naming Convention (UNC) path name of the file + SLGP_UNCPRIORITY = 0x2, + /// Retrieves the raw path name. A raw path is something that might not exist and may include environment variables that need to be expanded + SLGP_RAWPATH = 0x4 + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + struct WIN32_FIND_DATAW + { + public uint dwFileAttributes; + public long ftCreationTime; + public long ftLastAccessTime; + public long ftLastWriteTime; + public uint nFileSizeHigh; + public uint nFileSizeLow; + public uint dwReserved0; + public uint dwReserved1; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string cFileName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] + public string cAlternateFileName; + } + + [Flags()] + enum SLR_FLAGS + { + /// + /// Do not display a dialog box if the link cannot be resolved. When SLR_NO_UI is set, + /// the high-order word of fFlags can be set to a time-out value that specifies the + /// maximum amount of time to be spent resolving the link. The function returns if the + /// link cannot be resolved within the time-out duration. If the high-order word is set + /// to zero, the time-out duration will be set to the default value of 3,000 milliseconds + /// (3 seconds). To specify a value, set the high word of fFlags to the desired time-out + /// duration, in milliseconds. + /// + SLR_NO_UI = 0x1, + /// Obsolete and no longer used + SLR_ANY_MATCH = 0x2, + /// If the link object has changed, update its path and list of identifiers. + /// If SLR_UPDATE is set, you do not need to call IPersistFile::IsDirty to determine + /// whether or not the link object has changed. + SLR_UPDATE = 0x4, + /// Do not update the link information + SLR_NOUPDATE = 0x8, + /// Do not execute the search heuristics + SLR_NOSEARCH = 0x10, + /// Do not use distributed link tracking + SLR_NOTRACK = 0x20, + /// Disable distributed link tracking. By default, distributed link tracking tracks + /// removable media across multiple devices based on the volume name. It also uses the + /// Universal Naming Convention (UNC) path to track remote file systems whose drive letter + /// has changed. Setting SLR_NOLINKINFO disables both types of tracking. + SLR_NOLINKINFO = 0x40, + /// Call the Microsoft Windows Installer + SLR_INVOKE_MSI = 0x80 + } + + /// The IShellLink interface allows Shell links to be created, modified, and resolved + [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")] + interface IShellLinkW + { + /// Retrieves the path and file name of a Shell link object + void GetPath([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags); + /// Retrieves the list of item identifiers for a Shell link object + void GetIDList(out IntPtr ppidl); + /// Sets the pointer to an item identifier list (PIDL) for a Shell link object. + void SetIDList(IntPtr pidl); + /// Retrieves the description string for a Shell link object + void GetDescription([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName); + /// Sets the description for a Shell link object. The description can be any application-defined string + void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); + /// Retrieves the name of the working directory for a Shell link object + void GetWorkingDirectory([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); + /// Sets the name of the working directory for a Shell link object + void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); + /// Retrieves the command-line arguments associated with a Shell link object + void GetArguments([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); + /// Sets the command-line arguments for a Shell link object + void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); + /// Retrieves the hot key for a Shell link object + void GetHotkey(out short pwHotkey); + /// Sets a hot key for a Shell link object + void SetHotkey(short wHotkey); + /// Retrieves the show command for a Shell link object + void GetShowCmd(out int piShowCmd); + /// Sets the show command for a Shell link object. The show command sets the initial show state of the window. + void SetShowCmd(int iShowCmd); + /// Retrieves the location (path and index) of the icon for a Shell link object + void GetIconLocation([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, + int cchIconPath, out int piIcon); + /// Sets the location (path and index) of the icon for a Shell link object + void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); + /// Sets the relative path to the Shell link object + void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved); + /// Attempts to find the target of a Shell link, even if it has been moved or renamed + void Resolve(IntPtr hwnd, SLR_FLAGS fFlags); + /// Sets the path and file name of a Shell link object + void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); + + } + + [ComImport, Guid("0000010c-0000-0000-c000-000000000046"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IPersist + { + [PreserveSig] + void GetClassID(out Guid pClassID); + } + + [ComImport, Guid("0000010b-0000-0000-C000-000000000046"), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IPersistFile : IPersist + { + new void GetClassID(out Guid pClassID); + [PreserveSig] + int IsDirty(); + + [PreserveSig] + void Load([In, MarshalAs(UnmanagedType.LPWStr)] + string pszFileName, uint dwMode); + + [PreserveSig] + void Save([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName, + [In, MarshalAs(UnmanagedType.Bool)] bool fRemember); + + [PreserveSig] + void SaveCompleted([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName); + + [PreserveSig] + void GetCurFile([In, MarshalAs(UnmanagedType.LPWStr)] string ppszFileName); + } + + const uint STGM_READ = 0; + const int MAX_PATH = 260; + + // CLSID_ShellLink from ShlGuid.h + [ + ComImport(), + Guid("00021401-0000-0000-C000-000000000046") + ] + public class ShellLink + { + } + + #endregion + + public static string ResolveShortcut(string filename) + { + ShellLink link = new ShellLink(); + ((IPersistFile)link).Load(filename, STGM_READ); + // TODO: if I can get hold of the hwnd call resolve first. This handles moved and renamed files. + // ((IShellLinkW)link).Resolve(hwnd, 0) + StringBuilder sb = new StringBuilder(MAX_PATH); + WIN32_FIND_DATAW data = new WIN32_FIND_DATAW(); + ((IShellLinkW)link).GetPath(sb, sb.Capacity, out data, 0); + string resolvedPath = sb.ToString(); + if (!IsDirectory(resolvedPath) && + !File.Exists(resolvedPath)) + { + //For some lnk e.g. WinRar SkypeForBuisness + //resolved path wrong to Program Files (x86) + resolvedPath = ReplaceFirst(resolvedPath, + @"\Program Files (x86)\", + @"\Program Files\"); + if (!File.Exists(resolvedPath)) + { + resolvedPath = string.Empty; + } + } + return resolvedPath; + } + + public static bool IsDirectory(string filePath) + { + bool isDirectory = false; + if (Directory.Exists(filePath)) + { + FileAttributes attr = File.GetAttributes(filePath); + if ((attr & FileAttributes.Directory) == FileAttributes.Directory) + { + isDirectory = true; + } + } + + return isDirectory; + } + + public static string ReplaceFirst(string text, string search, string replace) + { + int pos = text.IndexOf(search); + if (pos < 0) + { + return text; + } + return text.Substring(0, pos) + replace + + text.Substring(pos + search.Length); + } + } +} \ No newline at end of file diff --git a/Helper/File/FileUrl.cs b/Helper/File/FileUrl.cs new file mode 100644 index 0000000..7dfdaef --- /dev/null +++ b/Helper/File/FileUrl.cs @@ -0,0 +1,65 @@ +using Microsoft.Win32; +using System; + +namespace SystemTrayMenu.Helper +{ + public class FileUrl + { + private static string browserPath = string.Empty; + public static string GetDefaultBrowserPath() + { + string urlAssociation = @"Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http"; + string browserPathKey = @"$BROWSER$\shell\open\command"; + + RegistryKey userChoiceKey = null; + string browserPath = FileUrl.browserPath; + + if (string.IsNullOrEmpty(browserPath)) + { + //Read default browser path from userChoiceLKey + userChoiceKey = Registry.CurrentUser.OpenSubKey(urlAssociation + @"\UserChoice", false); + + //If user choice was not found, try machine default + if (userChoiceKey == null) + { + //Read default browser path from Win XP registry key + var browserKey = Registry.ClassesRoot.OpenSubKey(@"HTTP\shell\open\command", false); + + //If browser path wasn’t found, try Win Vista (and newer) registry key + if (browserKey == null) + { + browserKey = + Registry.CurrentUser.OpenSubKey( + urlAssociation, false); + } + var path = CleanifyBrowserPath(browserKey.GetValue(null) as string); + browserKey.Close(); + return path; + } + else + { + // user defined browser choice was found + string progId = (userChoiceKey.GetValue("ProgId").ToString()); + userChoiceKey.Close(); + + // now look up the path of the executable + string concreteBrowserKey = browserPathKey.Replace("$BROWSER$", progId); + var kp = Registry.ClassesRoot.OpenSubKey(concreteBrowserKey, false); + browserPath = CleanifyBrowserPath(kp.GetValue(null) as string); + kp.Close(); + } + + FileUrl.browserPath = browserPath; + } + + return browserPath; + } + + private static string CleanifyBrowserPath(string p) + { + string[] url = p.Split('"'); + string clean = url[1]; + return clean; + } + } +} diff --git a/Helper/File/IconReader.cs b/Helper/File/IconReader.cs new file mode 100644 index 0000000..7b02cf8 --- /dev/null +++ b/Helper/File/IconReader.cs @@ -0,0 +1,299 @@ +using Clearcove.Logging; +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace SystemTrayMenu.Helper +{ + // from https://www.codeproject.com/Articles/2532/Obtaining-and-managing-file-and-folder-icons-using + // added ImageList_GetIcon + + /// + /// Provides static methods to read system icons for both folders and files. + /// + /// + /// IconReader.GetFileIcon("c:\\general.xls"); + /// + public class IconReader + { + /// + /// Options to specify the size of icons to return. + /// + public enum IconSize + { + /// + /// Specify large icon - 32 pixels by 32 pixels. + /// + Large = 0, + /// + /// Specify small icon - 16 pixels by 16 pixels. + /// + Small = 1 + } + + /// + /// Options to specify whether folders should be in the open or closed state. + /// + public enum FolderType + { + /// + /// Specify open folder. + /// + Open = 0, + /// + /// Specify closed folder. + /// + Closed = 1 + } + + /// + /// Returns an icon for a given file - indicated by the name parameter. + /// + /// System.Drawing.Icon + public static Icon GetFileIcon(string filePath, bool linkOverlay, + IconSize size = IconSize.Small) + { + Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO(); + uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_SYSICONINDEX; + + //MH: Removed, otherwise wrong icon + // | Shell32.SHGFI_USEFILEATTRIBUTES ; + + if (true == linkOverlay) flags += Shell32.SHGFI_LINKOVERLAY; + + /* Check the size specified for return. */ + if (IconSize.Small == size) + { + flags += Shell32.SHGFI_SMALLICON; + } + else + { + flags += Shell32.SHGFI_LARGEICON; + } + + IntPtr hImageList = Shell32.SHGetFileInfo(filePath, + Shell32.FILE_ATTRIBUTE_NORMAL, + ref shfi, + (uint)System.Runtime.InteropServices.Marshal.SizeOf(shfi), + flags); + + Icon icon = null; + if (linkOverlay) + { + //MH: Added try catch, FromHandle can fail + try + { + // Copy (clone) the returned icon to a new object, thus allowing us to clean-up properly + icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone(); + } + catch (Exception ex) + { + Logger log = new Logger(nameof(IconReader)); + log.Info($"filePath:'{filePath}'"); + log.Error($"{ex.ToString()}"); + } + } + else + { + //MH: Added ImageList_GetIcon, to get the correct icon from .ink without overlay + IntPtr hIcon = Shell32.ImageList_GetIcon(hImageList, shfi.iIcon, Shell32.ILD_TRANSPARENT); + + //MH: Added try catch, FromHandle can fail + try + { + icon = (Icon)Icon.FromHandle(hIcon).Clone(); + } + catch (Exception ex) + { + Logger log = new Logger(nameof(IconReader)); + log.Info($"filePath:'{filePath}'"); + log.Error($"{ex.ToString()}"); + } + + // Additionally Cleanup + User32.DestroyIcon(hIcon); + } + + // Cleanup + User32.DestroyIcon(shfi.hIcon); + return icon; + } + + public static Icon GetFolderIcon(string directoryPath, + FolderType folderType, bool linkOverlay, + IconSize size = IconSize.Small) + { + // Need to add size check, although errors generated at present! + //uint flags = Shell32.SHGFI_ICON | Shell32.SHGFI_USEFILEATTRIBUTES; + + //MH: Removed SHGFI_USEFILEATTRIBUTES, otherwise was wrong folder icon + uint flags = Shell32.SHGFI_ICON; // | Shell32.SHGFI_USEFILEATTRIBUTES; + + if (true == linkOverlay) flags += Shell32.SHGFI_LINKOVERLAY; + + if (FolderType.Open == folderType) + { + flags += Shell32.SHGFI_OPENICON; + } + + if (IconSize.Small == size) + { + flags += Shell32.SHGFI_SMALLICON; + } + else + { + flags += Shell32.SHGFI_LARGEICON; + } + + // Get the folder icon + Shell32.SHFILEINFO shfi = new Shell32.SHFILEINFO(); + Shell32.SHGetFileInfo(directoryPath, + Shell32.FILE_ATTRIBUTE_DIRECTORY, + ref shfi, + (uint)Marshal.SizeOf(shfi), + flags); + + //MH: Added try catch, FromHandle can fail + Icon icon = null; + try + { + Icon.FromHandle(shfi.hIcon); // Load the icon from an HICON handle + + // Now clone the icon, so that it can be successfully stored in an ImageList + icon = (Icon)Icon.FromHandle(shfi.hIcon).Clone(); + + User32.DestroyIcon(shfi.hIcon); // Cleanup + } + catch (Exception ex) + { + Logger log = new Logger(nameof(IconReader)); + log.Info($"directoryPath:'{directoryPath}'"); + log.Error($"{ex.ToString()}"); + } + return icon; + } + } + + /// + /// Wraps necessary Shell32.dll structures and functions required to retrieve Icon Handles using SHGetFileInfo. Code + /// courtesy of MSDN Cold Rooster Consulting case study. + /// + /// + + // This code has been left largely untouched from that in the CRC example. The main changes have been moving + // the icon reading code over to the IconReader type. + public class Shell32 + { + + public const int MAX_PATH = 256; + [StructLayout(LayoutKind.Sequential)] + public struct SHITEMID + { + public ushort cb; + [MarshalAs(UnmanagedType.LPArray)] + public byte[] abID; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ITEMIDLIST + { + public SHITEMID mkid; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BROWSEINFO + { + public IntPtr hwndOwner; + public IntPtr pidlRoot; + public IntPtr pszDisplayName; + [MarshalAs(UnmanagedType.LPTStr)] + public string lpszTitle; + public uint ulFlags; + public IntPtr lpfn; + public int lParam; + public IntPtr iImage; + } + + // Browsing for directory. + public const uint BIF_RETURNONLYFSDIRS = 0x0001; + public const uint BIF_DONTGOBELOWDOMAIN = 0x0002; + public const uint BIF_STATUSTEXT = 0x0004; + public const uint BIF_RETURNFSANCESTORS = 0x0008; + public const uint BIF_EDITBOX = 0x0010; + public const uint BIF_VALIDATE = 0x0020; + public const uint BIF_NEWDIALOGSTYLE = 0x0040; + public const uint BIF_USENEWUI = (BIF_NEWDIALOGSTYLE | BIF_EDITBOX); + public const uint BIF_BROWSEINCLUDEURLS = 0x0080; + public const uint BIF_BROWSEFORCOMPUTER = 0x1000; + public const uint BIF_BROWSEFORPRINTER = 0x2000; + public const uint BIF_BROWSEINCLUDEFILES = 0x4000; + public const uint BIF_SHAREABLE = 0x8000; + + [StructLayout(LayoutKind.Sequential)] + public struct SHFILEINFO + { + public const int NAMESIZE = 80; + public IntPtr hIcon; + public int iIcon; + public uint dwAttributes; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] + public string szDisplayName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAMESIZE)] + public string szTypeName; + }; + + public const uint SHGFI_ICON = 0x000000100; // get icon + public const uint SHGFI_DISPLAYNAME = 0x000000200; // get display name + public const uint SHGFI_TYPENAME = 0x000000400; // get type name + public const uint SHGFI_ATTRIBUTES = 0x000000800; // get attributes + public const uint SHGFI_ICONLOCATION = 0x000001000; // get icon location + public const uint SHGFI_EXETYPE = 0x000002000; // return exe type + public const uint SHGFI_SYSICONINDEX = 0x000004000; // get system icon index + public const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon + public const uint SHGFI_SELECTED = 0x000010000; // show icon in selected state + public const uint SHGFI_ATTR_SPECIFIED = 0x000020000; // get only specified attributes + public const uint SHGFI_LARGEICON = 0x000000000; // get large icon + public const uint SHGFI_SMALLICON = 0x000000001; // get small icon + public const uint SHGFI_OPENICON = 0x000000002; // get open icon + public const uint SHGFI_SHELLICONSIZE = 0x000000004; // get shell size icon + public const uint SHGFI_PIDL = 0x000000008; // pszPath is a pidl + public const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute + public const uint SHGFI_ADDOVERLAYS = 0x000000020; // apply the appropriate overlays + public const uint SHGFI_OVERLAYINDEX = 0x000000040; // Get the index of the overlay + + public const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010; + public const uint FILE_ATTRIBUTE_NORMAL = 0x00000080; + + public const int ILD_TRANSPARENT = 0x00000001; + + [DllImport("Shell32.dll")] + public static extern IntPtr SHGetFileInfo( + string pszPath, + uint dwFileAttributes, + ref SHFILEINFO psfi, + uint cbFileInfo, + uint uFlags + ); + + [DllImport("comctl32")] + internal static extern IntPtr ImageList_GetIcon( + IntPtr himl, + int i, + int flags); + } + + /// + /// Wraps necessary functions imported from User32.dll. Code courtesy of MSDN Cold Rooster Consulting example. + /// + public class User32 + { + /// + /// Provides access to function required to delete handle. This method is used internally + /// and is not required to be called separately. + /// + /// Pointer to icon handle. + /// N/A + [DllImport("User32.dll")] + public static extern int DestroyIcon(IntPtr hIcon); + } +} \ No newline at end of file diff --git a/Helper/KeyboardHook.cs b/Helper/KeyboardHook.cs new file mode 100644 index 0000000..85e9b27 --- /dev/null +++ b/Helper/KeyboardHook.cs @@ -0,0 +1,148 @@ +using System; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace SystemTrayMenu.Helper +{ + public sealed class KeyboardHook : IDisposable + { + // Registers a hot key with Windows. + [DllImport("user32.dll")] + private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); + // Unregisters the hot key with Windows. + [DllImport("user32.dll")] + private static extern bool UnregisterHotKey(IntPtr hWnd, int id); + + /// + /// Represents the window that is used internally to get the messages. + /// + private class Window : NativeWindow, IDisposable + { + private static int WM_HOTKEY = 0x0312; + + public Window() + { + // create the handle for the window. + this.CreateHandle(new CreateParams()); + } + + /// + /// Overridden to get the notifications. + /// + /// + protected override void WndProc(ref Message m) + { + base.WndProc(ref m); + + // check if we got a hot key pressed. + if (m.Msg == WM_HOTKEY) + { + // get the keys. + Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF); + KeyboardHookModifierKeys modifier = (KeyboardHookModifierKeys)((int)m.LParam & 0xFFFF); + + // invoke the event to notify the parent. + if (KeyPressed != null) + KeyPressed(this, new KeyPressedEventArgs(modifier, key)); + } + } + + public event EventHandler KeyPressed; + + #region IDisposable Members + + public void Dispose() + { + this.DestroyHandle(); + } + + #endregion + } + + private Window _window = new Window(); + private int _currentId; + + public KeyboardHook() + { + // register the event of the inner native window. + _window.KeyPressed += delegate (object sender, KeyPressedEventArgs args) + { + if (KeyPressed != null) + KeyPressed(this, args); + }; + } + + /// + /// Registers a hot key in the system. + /// + /// The modifiers that are associated with the hot key. + /// The key itself that is associated with the hot key. + public void RegisterHotKey(KeyboardHookModifierKeys modifier, Keys key) + { + // increment the counter. + _currentId = _currentId + 1; + + // register the hot key. + if (!RegisterHotKey(_window.Handle, _currentId, (uint)modifier, (uint)key)) + throw new InvalidOperationException("Couldn’t register the hot key."); + } + + /// + /// A hot key has been pressed. + /// + public event EventHandler KeyPressed; + + #region IDisposable Members + + public void Dispose() + { + // unregister all the registered hot keys. + for (int i = _currentId; i > 0; i--) + { + UnregisterHotKey(_window.Handle, i); + } + + // dispose the inner native window. + _window.Dispose(); + } + + #endregion + } + + /// + /// Event Args for the event that is fired after the hot key has been pressed. + /// + public class KeyPressedEventArgs : EventArgs + { + private KeyboardHookModifierKeys _modifier; + private Keys _key; + + internal KeyPressedEventArgs(KeyboardHookModifierKeys modifier, Keys key) + { + _modifier = modifier; + _key = key; + } + + public KeyboardHookModifierKeys Modifier + { + get { return _modifier; } + } + + public Keys Key + { + get { return _key; } + } + } + + /// + /// The enumeration of possible modifiers. + /// + [Flags] + public enum KeyboardHookModifierKeys : uint + { + Alt = 1, + Control = 2, + Shift = 4, + Win = 8 + } +} diff --git a/Helper/MessageFilter.cs b/Helper/MessageFilter.cs new file mode 100644 index 0000000..916ae87 --- /dev/null +++ b/Helper/MessageFilter.cs @@ -0,0 +1,33 @@ +using System.Windows.Forms; + +namespace SystemTrayMenu +{ + public delegate void EventHandler(); + + class MessageFilter : IMessageFilter + { + const int WM_MOUSELEAVE = 0x02A3; + const int WM_MOUSEMOVE = 0x0200; + const int WM_NCMOUSEMOVE = 0x00A0; + public event EventHandler MouseLeave; + public event EventHandler MouseMove; + public event EventHandler ScrollBarMouseMove; + + public bool PreFilterMessage(ref Message message) + { + if (message.Msg == WM_MOUSELEAVE) + { + MouseLeave?.Invoke(); + } + else if (message.Msg == WM_MOUSEMOVE) + { + MouseMove?.Invoke(); + } + else if (message.Msg == WM_NCMOUSEMOVE) + { + ScrollBarMouseMove?.Invoke(); + } + return false; + } + } +} diff --git a/Helper/ScreenMouse.cs b/Helper/ScreenMouse.cs new file mode 100644 index 0000000..76a6253 --- /dev/null +++ b/Helper/ScreenMouse.cs @@ -0,0 +1,30 @@ +using System.Drawing; +using System.Windows.Forms; + +namespace SystemTrayMenu.Helper +{ + public class ScreenMouse + { + public static Screen GetScreen() + { + return Screen.PrimaryScreen; + // Maybe we need for later feature + // Show on mouse position + //return GetScreenFromMousePosition( + // Cursor.Position.X, Cursor.Position.Y); + } + + //public static Screen GetScreenFromMousePosition(int x, int y) + //{ + // Screen clickedScreen = null; + // foreach (Screen screen in Screen.AllScreens) + // { + // if (screen.Bounds.Contains(new Point(x, y))) + // { + // clickedScreen = screen; + // } + // } + // return clickedScreen; + //} + } +} diff --git a/Helper/ShellContextMenu.cs b/Helper/ShellContextMenu.cs new file mode 100644 index 0000000..5dfe196 --- /dev/null +++ b/Helper/ShellContextMenu.cs @@ -0,0 +1,1640 @@ +using System; +using System.Drawing; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; + +namespace SystemTrayMenu.Helper +{ + /// + /// "Stand-alone" shell context menu + /// + /// It isn't really debugged but is mostly working. + /// Create an instance and call ShowContextMenu with a list of FileInfo for the files. + /// Limitation is that it only handles files in the same directory but it can be fixed + /// by changing the way files are translated into PIDLs. + /// + /// Based on FileBrowser in C# from CodeProject + /// http://www.codeproject.com/useritems/FileBrowser.asp + /// + /// Hooking class taken from MSDN Magazine Cutting Edge column + /// http://msdn.microsoft.com/msdnmag/issues/02/10/CuttingEdge/ + /// + /// Andreas Johansson + /// afjohansson@hotmail.com + /// http://afjohansson.spaces.live.com + /// + /// + /// ShellContextMenu scm = new ShellContextMenu(); + /// FileInfo[] files = new FileInfo[1]; + /// files[0] = new FileInfo(@"c:\windows\notepad.exe"); + /// scm.ShowContextMenu(this.Handle, files, Cursor.Position); + /// + public class ShellContextMenu : NativeWindow + { + #region Constructor + /// Default constructor + public ShellContextMenu() + { + this.CreateHandle(new CreateParams()); + } + #endregion + + #region Destructor + /// Ensure all resources get released + ~ShellContextMenu() + { + ReleaseAll(); + } + #endregion + + #region GetContextMenuInterfaces() + /// Gets the interfaces to the context menu + /// Parent folder + /// PIDLs + /// true if it got the interfaces, otherwise false + private bool GetContextMenuInterfaces(IShellFolder oParentFolder, IntPtr[] arrPIDLs, out IntPtr ctxMenuPtr) + { + int nResult = oParentFolder.GetUIObjectOf( + IntPtr.Zero, + (uint)arrPIDLs.Length, + arrPIDLs, + ref IID_IContextMenu, + IntPtr.Zero, + out ctxMenuPtr); + + if (S_OK == nResult) + { + _oContextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown(ctxMenuPtr, typeof(IContextMenu)); + + /*IntPtr pUnknownContextMenu2 = IntPtr.Zero; + if (S_OK == Marshal.QueryInterface(pUnknownContextMenu, ref IID_IContextMenu2, out pUnknownContextMenu2)) + { + _oContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(pUnknownContextMenu2, typeof(IContextMenu2)); + } + IntPtr pUnknownContextMenu3 = IntPtr.Zero; + if (S_OK == Marshal.QueryInterface(pUnknownContextMenu, ref IID_IContextMenu3, out pUnknownContextMenu3)) + { + _oContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(pUnknownContextMenu3, typeof(IContextMenu3)); + }*/ + + return true; + } + else + { + ctxMenuPtr = IntPtr.Zero; + _oContextMenu = null; + return false; + } + } + #endregion + + #region Override + + /// + /// This method receives WindowMessages. It will make the "Open With" and "Send To" work + /// by calling HandleMenuMsg and HandleMenuMsg2. It will also call the OnContextMenuMouseHover + /// method of Browser when hovering over a ContextMenu item. + /// + /// the Message of the Browser's WndProc + /// true if the message has been handled, false otherwise + protected override void WndProc(ref Message m) + { + #region IContextMenu + + if (_oContextMenu != null && + m.Msg == (int)WM.MENUSELECT && + ((int)ShellHelper.HiWord(m.WParam) & (int)MFT.SEPARATOR) == 0 && + ((int)ShellHelper.HiWord(m.WParam) & (int)MFT.POPUP) == 0) + { + string info = string.Empty; + + if (ShellHelper.LoWord(m.WParam) == (int)CMD_CUSTOM.ExpandCollapse) + info = "Expands or collapses the current selected item"; + else + { + info = "";/* ContextMenuHelper.GetCommandString( + _oContextMenu, + ShellHelper.LoWord(m.WParam) - CMD_FIRST, + false);*/ + } + + //br.OnContextMenuMouseHover(new ContextMenuMouseHoverEventArgs(info.ToString())); + } + + #endregion + + #region IContextMenu2 + + if (_oContextMenu2 != null && + (m.Msg == (int)WM.INITMENUPOPUP || + m.Msg == (int)WM.MEASUREITEM || + m.Msg == (int)WM.DRAWITEM)) + { + if (_oContextMenu2.HandleMenuMsg( + (uint)m.Msg, m.WParam, m.LParam) == S_OK) + return; + } + + #endregion + + #region IContextMenu3 + + if (_oContextMenu3 != null && + m.Msg == (int)WM.MENUCHAR) + { + if (_oContextMenu3.HandleMenuMsg2( + (uint)m.Msg, m.WParam, m.LParam, IntPtr.Zero) == S_OK) + return; + } + + #endregion + + base.WndProc(ref m); + } + + #endregion + + #region InvokeCommand + private void InvokeCommand(IContextMenu oContextMenu, uint nCmd, string strFolder, Point pointInvoke) + { + CMINVOKECOMMANDINFOEX invoke = new CMINVOKECOMMANDINFOEX(); + invoke.cbSize = cbInvokeCommand; + invoke.lpVerb = (IntPtr)(nCmd - CMD_FIRST); + invoke.lpDirectory = strFolder; + invoke.lpVerbW = (IntPtr)(nCmd - CMD_FIRST); + invoke.lpDirectoryW = strFolder; + invoke.fMask = CMIC.UNICODE | CMIC.PTINVOKE | + ((Control.ModifierKeys & Keys.Control) != 0 ? CMIC.CONTROL_DOWN : 0) | + ((Control.ModifierKeys & Keys.Shift) != 0 ? CMIC.SHIFT_DOWN : 0); + invoke.ptInvoke = new POINT(pointInvoke.X, pointInvoke.Y); + invoke.nShow = SW.SHOWNORMAL; + + oContextMenu.InvokeCommand(ref invoke); + } + #endregion + + #region ReleaseAll() + /// + /// Release all allocated interfaces, PIDLs + /// + private void ReleaseAll() + { + if (null != _oContextMenu) + { + Marshal.ReleaseComObject(_oContextMenu); + _oContextMenu = null; + } + if (null != _oContextMenu2) + { + Marshal.ReleaseComObject(_oContextMenu2); + _oContextMenu2 = null; + } + if (null != _oContextMenu3) + { + Marshal.ReleaseComObject(_oContextMenu3); + _oContextMenu3 = null; + } + if (null != _oDesktopFolder) + { + Marshal.ReleaseComObject(_oDesktopFolder); + _oDesktopFolder = null; + } + if (null != _oParentFolder) + { + Marshal.ReleaseComObject(_oParentFolder); + _oParentFolder = null; + } + if (null != _arrPIDLs) + { + FreePIDLs(_arrPIDLs); + _arrPIDLs = null; + } + } + #endregion + + #region GetDesktopFolder() + /// + /// Gets the desktop folder + /// + /// IShellFolder for desktop folder + private IShellFolder GetDesktopFolder() + { + IntPtr pUnkownDesktopFolder = IntPtr.Zero; + + if (null == _oDesktopFolder) + { + // Get desktop IShellFolder + int nResult = SHGetDesktopFolder(out pUnkownDesktopFolder); + if (S_OK != nResult) + { + throw new ShellContextMenuException("Failed to get the desktop shell folder"); + } + _oDesktopFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnkownDesktopFolder, typeof(IShellFolder)); + } + + return _oDesktopFolder; + } + #endregion + + #region GetParentFolder() + /// + /// Gets the parent folder + /// + /// Folder path + /// IShellFolder for the folder (relative from the desktop) + private IShellFolder GetParentFolder(string folderName) + { + if (null == _oParentFolder) + { + IShellFolder oDesktopFolder = GetDesktopFolder(); + if (null == oDesktopFolder) + { + return null; + } + + // Get the PIDL for the folder file is in + IntPtr pPIDL = IntPtr.Zero; + uint pchEaten = 0; + SFGAO pdwAttributes = 0; + int nResult = oDesktopFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, folderName, ref pchEaten, out pPIDL, ref pdwAttributes); + if (S_OK != nResult) + { + return null; + } + + IntPtr pStrRet = Marshal.AllocCoTaskMem(MAX_PATH * 2 + 4); + Marshal.WriteInt32(pStrRet, 0, 0); + nResult = _oDesktopFolder.GetDisplayNameOf(pPIDL, SHGNO.FORPARSING, pStrRet); + StringBuilder strFolder = new StringBuilder(MAX_PATH); + StrRetToBuf(pStrRet, pPIDL, strFolder, MAX_PATH); + Marshal.FreeCoTaskMem(pStrRet); + pStrRet = IntPtr.Zero; + _strParentFolder = strFolder.ToString(); + + // Get the IShellFolder for folder + IntPtr pUnknownParentFolder = IntPtr.Zero; + nResult = oDesktopFolder.BindToObject(pPIDL, IntPtr.Zero, ref IID_IShellFolder, out pUnknownParentFolder); + // Free the PIDL first + Marshal.FreeCoTaskMem(pPIDL); + if (S_OK != nResult) + { + return null; + } + _oParentFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnknownParentFolder, typeof(IShellFolder)); + } + + return _oParentFolder; + } + #endregion + + #region GetPIDLs() + /// + /// Get the PIDLs + /// + /// Array of FileInfo + /// Array of PIDLs + protected IntPtr[] GetPIDLs(FileInfo[] arrFI) + { + if (null == arrFI || 0 == arrFI.Length) + { + return null; + } + + IShellFolder oParentFolder = GetParentFolder(arrFI[0].DirectoryName); + if (null == oParentFolder) + { + return null; + } + + IntPtr[] arrPIDLs = new IntPtr[arrFI.Length]; + int n = 0; + foreach (FileInfo fi in arrFI) + { + // Get the file relative to folder + uint pchEaten = 0; + SFGAO pdwAttributes = 0; + IntPtr pPIDL = IntPtr.Zero; + int nResult = oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, fi.Name, ref pchEaten, out pPIDL, ref pdwAttributes); + if (S_OK != nResult) + { + FreePIDLs(arrPIDLs); + return null; + } + arrPIDLs[n] = pPIDL; + n++; + } + + return arrPIDLs; + } + + /// + /// Get the PIDLs + /// + /// Array of DirectoryInfo + /// Array of PIDLs + protected IntPtr[] GetPIDLs(DirectoryInfo[] arrFI) + { + if (null == arrFI || 0 == arrFI.Length) + { + return null; + } + + IShellFolder oParentFolder = GetParentFolder(arrFI[0].Parent.FullName); + if (null == oParentFolder) + { + return null; + } + + IntPtr[] arrPIDLs = new IntPtr[arrFI.Length]; + int n = 0; + foreach (DirectoryInfo fi in arrFI) + { + // Get the file relative to folder + uint pchEaten = 0; + SFGAO pdwAttributes = 0; + IntPtr pPIDL = IntPtr.Zero; + int nResult = oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, fi.Name, ref pchEaten, out pPIDL, ref pdwAttributes); + if (S_OK != nResult) + { + FreePIDLs(arrPIDLs); + return null; + } + arrPIDLs[n] = pPIDL; + n++; + } + + return arrPIDLs; + } + #endregion + + #region FreePIDLs() + /// + /// Free the PIDLs + /// + /// Array of PIDLs (IntPtr) + protected void FreePIDLs(IntPtr[] arrPIDLs) + { + if (null != arrPIDLs) + { + for (int n = 0; n < arrPIDLs.Length; n++) + { + if (arrPIDLs[n] != IntPtr.Zero) + { + Marshal.FreeCoTaskMem(arrPIDLs[n]); + arrPIDLs[n] = IntPtr.Zero; + } + } + } + } + #endregion + + #region InvokeContextMenuDefault + private void InvokeContextMenuDefault(FileInfo[] arrFI) + { + // Release all resources first. + ReleaseAll(); + + IntPtr pMenu = IntPtr.Zero, + iContextMenuPtr = IntPtr.Zero; + + try + { + _arrPIDLs = GetPIDLs(arrFI); + if (null == _arrPIDLs) + { + ReleaseAll(); + return; + } + + if (false == GetContextMenuInterfaces(_oParentFolder, _arrPIDLs, out iContextMenuPtr)) + { + ReleaseAll(); + return; + } + + pMenu = CreatePopupMenu(); + + int nResult = _oContextMenu.QueryContextMenu( + pMenu, + 0, + CMD_FIRST, + CMD_LAST, + CMF.DEFAULTONLY | + ((Control.ModifierKeys & Keys.Shift) != 0 ? CMF.EXTENDEDVERBS : 0)); + + uint nDefaultCmd = (uint)GetMenuDefaultItem(pMenu, false, 0); + if (nDefaultCmd >= CMD_FIRST) + { + InvokeCommand(_oContextMenu, nDefaultCmd, arrFI[0].DirectoryName, Control.MousePosition); + } + + DestroyMenu(pMenu); + pMenu = IntPtr.Zero; + } + catch + { + throw; + } + finally + { + if (pMenu != IntPtr.Zero) + { + DestroyMenu(pMenu); + } + ReleaseAll(); + } + } + #endregion + + #region ShowContextMenu() + + /// + /// Shows the context menu + /// + /// FileInfos (should all be in same directory) + /// Where to show the menu + public void ShowContextMenu(FileInfo[] files, Point pointScreen) + { + // Release all resources first. + ReleaseAll(); + _arrPIDLs = GetPIDLs(files); + this.ShowContextMenu(pointScreen); + } + + /// + /// Shows the context menu + /// + /// DirectoryInfos (should all be in same directory) + /// Where to show the menu + public void ShowContextMenu(DirectoryInfo[] dirs, Point pointScreen) + { + // Release all resources first. + ReleaseAll(); + _arrPIDLs = GetPIDLs(dirs); + this.ShowContextMenu(pointScreen); + } + + /// + /// Shows the context menu + /// + /// FileInfos (should all be in same directory) + /// Where to show the menu + public void ShowContextMenu(Point pointScreen) + { + IntPtr pMenu = IntPtr.Zero, + iContextMenuPtr = IntPtr.Zero, + iContextMenuPtr2 = IntPtr.Zero, + iContextMenuPtr3 = IntPtr.Zero; + //LocalWindowsHook hook = new LocalWindowsHook(HookType.WH_CALLWNDPROC); + //hook.HookInvoked += new LocalWindowsHook.HookEventHandler(WindowsHookInvoked); + + try + { + //Application.AddMessageFilter(this); + + //_arrPIDLs = GetPIDLs(arrFI); + if (null == _arrPIDLs) + { + ReleaseAll(); + return; + } + + if (false == GetContextMenuInterfaces(_oParentFolder, _arrPIDLs, out iContextMenuPtr)) + { + ReleaseAll(); + return; + } + + pMenu = CreatePopupMenu(); + + int nResult = _oContextMenu.QueryContextMenu( + pMenu, + 0, + CMD_FIRST, + CMD_LAST, + CMF.EXPLORE | + CMF.NORMAL | + ((Control.ModifierKeys & Keys.Shift) != 0 ? CMF.EXTENDEDVERBS : 0)); + + Marshal.QueryInterface(iContextMenuPtr, ref IID_IContextMenu2, out iContextMenuPtr2); + Marshal.QueryInterface(iContextMenuPtr, ref IID_IContextMenu3, out iContextMenuPtr3); + + _oContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr2, typeof(IContextMenu2)); + _oContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr3, typeof(IContextMenu3)); + + //hook.Install(); + + uint nSelected = TrackPopupMenuEx( + pMenu, + TPM.RETURNCMD, + pointScreen.X, + pointScreen.Y, + this.Handle, + IntPtr.Zero); + + DestroyMenu(pMenu); + pMenu = IntPtr.Zero; + + if (nSelected != 0) + { + InvokeCommand(_oContextMenu, nSelected, _strParentFolder, pointScreen); + } + } + catch + { + throw; + } + finally + { + //hook.Uninstall(); + if (pMenu != IntPtr.Zero) + { + DestroyMenu(pMenu); + } + + if (iContextMenuPtr != IntPtr.Zero) + Marshal.Release(iContextMenuPtr); + + if (iContextMenuPtr2 != IntPtr.Zero) + Marshal.Release(iContextMenuPtr2); + + if (iContextMenuPtr3 != IntPtr.Zero) + Marshal.Release(iContextMenuPtr3); + + ReleaseAll(); + } + } + #endregion + + #region WindowsHookInvoked() + /// + /// Handle messages for context menu + /// + private void WindowsHookInvoked(object sender, HookEventArgs e) + { + CWPSTRUCT cwp = (CWPSTRUCT)Marshal.PtrToStructure(e.lParam, typeof(CWPSTRUCT)); + + if (_oContextMenu2 != null && + (cwp.message == (int)WM.INITMENUPOPUP || + cwp.message == (int)WM.MEASUREITEM || + cwp.message == (int)WM.DRAWITEM)) + { + if (_oContextMenu2.HandleMenuMsg((uint)cwp.message, cwp.wparam, cwp.lparam) == S_OK) + { + return; + } + } + + if (_oContextMenu3 != null && cwp.message == (int)WM.MENUCHAR) + { + if (_oContextMenu3.HandleMenuMsg2((uint)cwp.message, cwp.wparam, cwp.lparam, IntPtr.Zero) == S_OK) + { + return; + } + } + + return; + } + #endregion + + #region Local variabled + private IContextMenu _oContextMenu; + private IContextMenu2 _oContextMenu2; + private IContextMenu3 _oContextMenu3; + private IShellFolder _oDesktopFolder; + private IShellFolder _oParentFolder; + private IntPtr[] _arrPIDLs; + private string _strParentFolder; + #endregion + + #region Variables and Constants + + private const int MAX_PATH = 260; + private const uint CMD_FIRST = 1; + private const uint CMD_LAST = 30000; + + private const int S_OK = 0; + private const int S_FALSE = 1; + + private static int cbMenuItemInfo = Marshal.SizeOf(typeof(MENUITEMINFO)); + private static int cbInvokeCommand = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX)); + + #endregion + + #region DLL Import + + // Retrieves the IShellFolder interface for the desktop folder, which is the root of the Shell's namespace. + [DllImport("shell32.dll")] + private static extern Int32 SHGetDesktopFolder(out IntPtr ppshf); + + // Takes a STRRET structure returned by IShellFolder::GetDisplayNameOf, converts it to a string, and places the result in a buffer. + [DllImport("shlwapi.dll", EntryPoint = "StrRetToBuf", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)] + private static extern Int32 StrRetToBuf(IntPtr pstr, IntPtr pidl, StringBuilder pszBuf, int cchBuf); + + // The TrackPopupMenuEx function displays a shortcut menu at the specified location and tracks the selection of items on the shortcut menu. The shortcut menu can appear anywhere on the screen. + [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] + private static extern uint TrackPopupMenuEx(IntPtr hmenu, TPM flags, int x, int y, IntPtr hwnd, IntPtr lptpm); + + // The CreatePopupMenu function creates a drop-down menu, submenu, or shortcut menu. The menu is initially empty. You can insert or append menu items by using the InsertMenuItem function. You can also use the InsertMenu function to insert menu items and the AppendMenu function to append menu items. + [DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)] + private static extern IntPtr CreatePopupMenu(); + + // The DestroyMenu function destroys the specified menu and frees any memory that the menu occupies. + [DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)] + private static extern bool DestroyMenu(IntPtr hMenu); + + // Determines the default menu item on the specified menu + [DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)] + private static extern int GetMenuDefaultItem(IntPtr hMenu, bool fByPos, uint gmdiFlags); + + #endregion + + #region Shell GUIDs + + private static Guid IID_IShellFolder = new Guid("{000214E6-0000-0000-C000-000000000046}"); + private static Guid IID_IContextMenu = new Guid("{000214e4-0000-0000-c000-000000000046}"); + private static Guid IID_IContextMenu2 = new Guid("{000214f4-0000-0000-c000-000000000046}"); + private static Guid IID_IContextMenu3 = new Guid("{bcfce0a0-ec17-11d0-8d10-00a0c90f2719}"); + + #endregion + + #region Structs + + [StructLayout(LayoutKind.Sequential)] + private struct CWPSTRUCT + { + public IntPtr lparam; + public IntPtr wparam; + public int message; + public IntPtr hwnd; + } + + // Contains extended information about a shortcut menu command + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + private struct CMINVOKECOMMANDINFOEX + { + public int cbSize; + public CMIC fMask; + public IntPtr hwnd; + public IntPtr lpVerb; + [MarshalAs(UnmanagedType.LPStr)] + public string lpParameters; + [MarshalAs(UnmanagedType.LPStr)] + public string lpDirectory; + public SW nShow; + public int dwHotKey; + public IntPtr hIcon; + [MarshalAs(UnmanagedType.LPStr)] + public string lpTitle; + public IntPtr lpVerbW; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpParametersW; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpDirectoryW; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpTitleW; + public POINT ptInvoke; + } + + // Contains information about a menu item + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + private struct MENUITEMINFO + { + public MENUITEMINFO(string text) + { + cbSize = cbMenuItemInfo; + dwTypeData = text; + cch = text.Length; + fMask = 0; + fType = 0; + fState = 0; + wID = 0; + hSubMenu = IntPtr.Zero; + hbmpChecked = IntPtr.Zero; + hbmpUnchecked = IntPtr.Zero; + dwItemData = IntPtr.Zero; + hbmpItem = IntPtr.Zero; + } + + public int cbSize; + public MIIM fMask; + public MFT fType; + public MFS fState; + public uint wID; + public IntPtr hSubMenu; + public IntPtr hbmpChecked; + public IntPtr hbmpUnchecked; + public IntPtr dwItemData; + [MarshalAs(UnmanagedType.LPTStr)] + public string dwTypeData; + public int cch; + public IntPtr hbmpItem; + } + + // A generalized global memory handle used for data transfer operations by the + // IAdviseSink, IDataObject, and IOleCache interfaces + [StructLayout(LayoutKind.Sequential)] + private struct STGMEDIUM + { + public TYMED tymed; + public IntPtr hBitmap; + public IntPtr hMetaFilePict; + public IntPtr hEnhMetaFile; + public IntPtr hGlobal; + public IntPtr lpszFileName; + public IntPtr pstm; + public IntPtr pstg; + public IntPtr pUnkForRelease; + } + + // Defines the x- and y-coordinates of a point + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + private struct POINT + { + public POINT(int x, int y) + { + this.x = x; + this.y = y; + } + + public int x; + public int y; + } + + #endregion + + #region Enums + + // Defines the values used with the IShellFolder::GetDisplayNameOf and IShellFolder::SetNameOf + // methods to specify the type of file or folder names used by those methods + [Flags] + private enum SHGNO + { + NORMAL = 0x0000, + INFOLDER = 0x0001, + FOREDITING = 0x1000, + FORADDRESSBAR = 0x4000, + FORPARSING = 0x8000 + } + + // The attributes that the caller is requesting, when calling IShellFolder::GetAttributesOf + [Flags] + private enum SFGAO : uint + { + BROWSABLE = 0x8000000, + CANCOPY = 1, + CANDELETE = 0x20, + CANLINK = 4, + CANMONIKER = 0x400000, + CANMOVE = 2, + CANRENAME = 0x10, + CAPABILITYMASK = 0x177, + COMPRESSED = 0x4000000, + CONTENTSMASK = 0x80000000, + DISPLAYATTRMASK = 0xfc000, + DROPTARGET = 0x100, + ENCRYPTED = 0x2000, + FILESYSANCESTOR = 0x10000000, + FILESYSTEM = 0x40000000, + FOLDER = 0x20000000, + GHOSTED = 0x8000, + HASPROPSHEET = 0x40, + HASSTORAGE = 0x400000, + HASSUBFOLDER = 0x80000000, + HIDDEN = 0x80000, + ISSLOW = 0x4000, + LINK = 0x10000, + NEWCONTENT = 0x200000, + NONENUMERATED = 0x100000, + READONLY = 0x40000, + REMOVABLE = 0x2000000, + SHARE = 0x20000, + STORAGE = 8, + STORAGEANCESTOR = 0x800000, + STORAGECAPMASK = 0x70c50008, + STREAM = 0x400000, + VALIDATE = 0x1000000 + } + + // Determines the type of items included in an enumeration. + // These values are used with the IShellFolder::EnumObjects method + [Flags] + private enum SHCONTF + { + FOLDERS = 0x0020, + NONFOLDERS = 0x0040, + INCLUDEHIDDEN = 0x0080, + INIT_ON_FIRST_NEXT = 0x0100, + NETPRINTERSRCH = 0x0200, + SHAREABLE = 0x0400, + STORAGE = 0x0800, + } + + // Specifies how the shortcut menu can be changed when calling IContextMenu::QueryContextMenu + [Flags] + private enum CMF : uint + { + NORMAL = 0x00000000, + DEFAULTONLY = 0x00000001, + VERBSONLY = 0x00000002, + EXPLORE = 0x00000004, + NOVERBS = 0x00000008, + CANRENAME = 0x00000010, + NODEFAULT = 0x00000020, + INCLUDESTATIC = 0x00000040, + EXTENDEDVERBS = 0x00000100, + RESERVED = 0xffff0000 + } + + // Flags specifying the information to return when calling IContextMenu::GetCommandString + [Flags] + private enum GCS : uint + { + VERBA = 0, + HELPTEXTA = 1, + VALIDATEA = 2, + VERBW = 4, + HELPTEXTW = 5, + VALIDATEW = 6 + } + + // Specifies how TrackPopupMenuEx positions the shortcut menu horizontally + [Flags] + private enum TPM : uint + { + LEFTBUTTON = 0x0000, + RIGHTBUTTON = 0x0002, + LEFTALIGN = 0x0000, + CENTERALIGN = 0x0004, + RIGHTALIGN = 0x0008, + TOPALIGN = 0x0000, + VCENTERALIGN = 0x0010, + BOTTOMALIGN = 0x0020, + HORIZONTAL = 0x0000, + VERTICAL = 0x0040, + NONOTIFY = 0x0080, + RETURNCMD = 0x0100, + RECURSE = 0x0001, + HORPOSANIMATION = 0x0400, + HORNEGANIMATION = 0x0800, + VERPOSANIMATION = 0x1000, + VERNEGANIMATION = 0x2000, + NOANIMATION = 0x4000, + LAYOUTRTL = 0x8000 + } + + // The cmd for a custom added menu item + private enum CMD_CUSTOM + { + ExpandCollapse = (int)CMD_LAST + 1 + } + + // Flags used with the CMINVOKECOMMANDINFOEX structure + [Flags] + private enum CMIC : uint + { + HOTKEY = 0x00000020, + ICON = 0x00000010, + FLAG_NO_UI = 0x00000400, + UNICODE = 0x00004000, + NO_CONSOLE = 0x00008000, + ASYNCOK = 0x00100000, + NOZONECHECKS = 0x00800000, + SHIFT_DOWN = 0x10000000, + CONTROL_DOWN = 0x40000000, + FLAG_LOG_USAGE = 0x04000000, + PTINVOKE = 0x20000000 + } + + // Specifies how the window is to be shown + [Flags] + private enum SW + { + HIDE = 0, + SHOWNORMAL = 1, + NORMAL = 1, + SHOWMINIMIZED = 2, + SHOWMAXIMIZED = 3, + MAXIMIZE = 3, + SHOWNOACTIVATE = 4, + SHOW = 5, + MINIMIZE = 6, + SHOWMINNOACTIVE = 7, + SHOWNA = 8, + RESTORE = 9, + SHOWDEFAULT = 10, + } + + // Window message flags + [Flags] + private enum WM : uint + { + ACTIVATE = 0x6, + ACTIVATEAPP = 0x1C, + AFXFIRST = 0x360, + AFXLAST = 0x37F, + APP = 0x8000, + ASKCBFORMATNAME = 0x30C, + CANCELJOURNAL = 0x4B, + CANCELMODE = 0x1F, + CAPTURECHANGED = 0x215, + CHANGECBCHAIN = 0x30D, + CHAR = 0x102, + CHARTOITEM = 0x2F, + CHILDACTIVATE = 0x22, + CLEAR = 0x303, + CLOSE = 0x10, + COMMAND = 0x111, + COMPACTING = 0x41, + COMPAREITEM = 0x39, + CONTEXTMENU = 0x7B, + COPY = 0x301, + COPYDATA = 0x4A, + CREATE = 0x1, + CTLCOLORBTN = 0x135, + CTLCOLORDLG = 0x136, + CTLCOLOREDIT = 0x133, + CTLCOLORLISTBOX = 0x134, + CTLCOLORMSGBOX = 0x132, + CTLCOLORSCROLLBAR = 0x137, + CTLCOLORSTATIC = 0x138, + CUT = 0x300, + DEADCHAR = 0x103, + DELETEITEM = 0x2D, + DESTROY = 0x2, + DESTROYCLIPBOARD = 0x307, + DEVICECHANGE = 0x219, + DEVMODECHANGE = 0x1B, + DISPLAYCHANGE = 0x7E, + DRAWCLIPBOARD = 0x308, + DRAWITEM = 0x2B, + DROPFILES = 0x233, + ENABLE = 0xA, + ENDSESSION = 0x16, + ENTERIDLE = 0x121, + ENTERMENULOOP = 0x211, + ENTERSIZEMOVE = 0x231, + ERASEBKGND = 0x14, + EXITMENULOOP = 0x212, + EXITSIZEMOVE = 0x232, + FONTCHANGE = 0x1D, + GETDLGCODE = 0x87, + GETFONT = 0x31, + GETHOTKEY = 0x33, + GETICON = 0x7F, + GETMINMAXINFO = 0x24, + GETOBJECT = 0x3D, + GETSYSMENU = 0x313, + GETTEXT = 0xD, + GETTEXTLENGTH = 0xE, + HANDHELDFIRST = 0x358, + HANDHELDLAST = 0x35F, + HELP = 0x53, + HOTKEY = 0x312, + HSCROLL = 0x114, + HSCROLLCLIPBOARD = 0x30E, + ICONERASEBKGND = 0x27, + IME_CHAR = 0x286, + IME_COMPOSITION = 0x10F, + IME_COMPOSITIONFULL = 0x284, + IME_CONTROL = 0x283, + IME_ENDCOMPOSITION = 0x10E, + IME_KEYDOWN = 0x290, + IME_KEYLAST = 0x10F, + IME_KEYUP = 0x291, + IME_NOTIFY = 0x282, + IME_REQUEST = 0x288, + IME_SELECT = 0x285, + IME_SETCONTEXT = 0x281, + IME_STARTCOMPOSITION = 0x10D, + INITDIALOG = 0x110, + INITMENU = 0x116, + INITMENUPOPUP = 0x117, + INPUTLANGCHANGE = 0x51, + INPUTLANGCHANGEREQUEST = 0x50, + KEYDOWN = 0x100, + KEYFIRST = 0x100, + KEYLAST = 0x108, + KEYUP = 0x101, + KILLFOCUS = 0x8, + LBUTTONDBLCLK = 0x203, + LBUTTONDOWN = 0x201, + LBUTTONUP = 0x202, + LVM_GETEDITCONTROL = 0x1018, + LVM_SETIMAGELIST = 0x1003, + MBUTTONDBLCLK = 0x209, + MBUTTONDOWN = 0x207, + MBUTTONUP = 0x208, + MDIACTIVATE = 0x222, + MDICASCADE = 0x227, + MDICREATE = 0x220, + MDIDESTROY = 0x221, + MDIGETACTIVE = 0x229, + MDIICONARRANGE = 0x228, + MDIMAXIMIZE = 0x225, + MDINEXT = 0x224, + MDIREFRESHMENU = 0x234, + MDIRESTORE = 0x223, + MDISETMENU = 0x230, + MDITILE = 0x226, + MEASUREITEM = 0x2C, + MENUCHAR = 0x120, + MENUCOMMAND = 0x126, + MENUDRAG = 0x123, + MENUGETOBJECT = 0x124, + MENURBUTTONUP = 0x122, + MENUSELECT = 0x11F, + MOUSEACTIVATE = 0x21, + MOUSEFIRST = 0x200, + MOUSEHOVER = 0x2A1, + MOUSELAST = 0x20A, + MOUSELEAVE = 0x2A3, + MOUSEMOVE = 0x200, + MOUSEWHEEL = 0x20A, + MOVE = 0x3, + MOVING = 0x216, + NCACTIVATE = 0x86, + NCCALCSIZE = 0x83, + NCCREATE = 0x81, + NCDESTROY = 0x82, + NCHITTEST = 0x84, + NCLBUTTONDBLCLK = 0xA3, + NCLBUTTONDOWN = 0xA1, + NCLBUTTONUP = 0xA2, + NCMBUTTONDBLCLK = 0xA9, + NCMBUTTONDOWN = 0xA7, + NCMBUTTONUP = 0xA8, + NCMOUSEHOVER = 0x2A0, + NCMOUSELEAVE = 0x2A2, + NCMOUSEMOVE = 0xA0, + NCPAINT = 0x85, + NCRBUTTONDBLCLK = 0xA6, + NCRBUTTONDOWN = 0xA4, + NCRBUTTONUP = 0xA5, + NEXTDLGCTL = 0x28, + NEXTMENU = 0x213, + NOTIFY = 0x4E, + NOTIFYFORMAT = 0x55, + NULL = 0x0, + PAINT = 0xF, + PAINTCLIPBOARD = 0x309, + PAINTICON = 0x26, + PALETTECHANGED = 0x311, + PALETTEISCHANGING = 0x310, + PARENTNOTIFY = 0x210, + PASTE = 0x302, + PENWINFIRST = 0x380, + PENWINLAST = 0x38F, + POWER = 0x48, + PRINT = 0x317, + PRINTCLIENT = 0x318, + QUERYDRAGICON = 0x37, + QUERYENDSESSION = 0x11, + QUERYNEWPALETTE = 0x30F, + QUERYOPEN = 0x13, + QUEUESYNC = 0x23, + QUIT = 0x12, + RBUTTONDBLCLK = 0x206, + RBUTTONDOWN = 0x204, + RBUTTONUP = 0x205, + RENDERALLFORMATS = 0x306, + RENDERFORMAT = 0x305, + SETCURSOR = 0x20, + SETFOCUS = 0x7, + SETFONT = 0x30, + SETHOTKEY = 0x32, + SETICON = 0x80, + SETMARGINS = 0xD3, + SETREDRAW = 0xB, + SETTEXT = 0xC, + SETTINGCHANGE = 0x1A, + SHOWWINDOW = 0x18, + SIZE = 0x5, + SIZECLIPBOARD = 0x30B, + SIZING = 0x214, + SPOOLERSTATUS = 0x2A, + STYLECHANGED = 0x7D, + STYLECHANGING = 0x7C, + SYNCPAINT = 0x88, + SYSCHAR = 0x106, + SYSCOLORCHANGE = 0x15, + SYSCOMMAND = 0x112, + SYSDEADCHAR = 0x107, + SYSKEYDOWN = 0x104, + SYSKEYUP = 0x105, + TCARD = 0x52, + TIMECHANGE = 0x1E, + TIMER = 0x113, + TVM_GETEDITCONTROL = 0x110F, + TVM_SETIMAGELIST = 0x1109, + UNDO = 0x304, + UNINITMENUPOPUP = 0x125, + USER = 0x400, + USERCHANGED = 0x54, + VKEYTOITEM = 0x2E, + VSCROLL = 0x115, + VSCROLLCLIPBOARD = 0x30A, + WINDOWPOSCHANGED = 0x47, + WINDOWPOSCHANGING = 0x46, + WININICHANGE = 0x1A, + SH_NOTIFY = 0x0401 + } + + // Specifies the content of the new menu item + [Flags] + private enum MFT : uint + { + GRAYED = 0x00000003, + DISABLED = 0x00000003, + CHECKED = 0x00000008, + SEPARATOR = 0x00000800, + RADIOCHECK = 0x00000200, + BITMAP = 0x00000004, + OWNERDRAW = 0x00000100, + MENUBARBREAK = 0x00000020, + MENUBREAK = 0x00000040, + RIGHTORDER = 0x00002000, + BYCOMMAND = 0x00000000, + BYPOSITION = 0x00000400, + POPUP = 0x00000010 + } + + // Specifies the state of the new menu item + [Flags] + private enum MFS : uint + { + GRAYED = 0x00000003, + DISABLED = 0x00000003, + CHECKED = 0x00000008, + HILITE = 0x00000080, + ENABLED = 0x00000000, + UNCHECKED = 0x00000000, + UNHILITE = 0x00000000, + DEFAULT = 0x00001000 + } + + // Specifies the content of the new menu item + [Flags] + private enum MIIM : uint + { + BITMAP = 0x80, + CHECKMARKS = 0x08, + DATA = 0x20, + FTYPE = 0x100, + ID = 0x02, + STATE = 0x01, + STRING = 0x40, + SUBMENU = 0x04, + TYPE = 0x10 + } + + // Indicates the type of storage medium being used in a data transfer + [Flags] + private enum TYMED + { + ENHMF = 0x40, + FILE = 2, + GDI = 0x10, + HGLOBAL = 1, + ISTORAGE = 8, + ISTREAM = 4, + MFPICT = 0x20, + NULL = 0 + } + + #endregion + + #region IShellFolder + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("000214E6-0000-0000-C000-000000000046")] + private interface IShellFolder + { + // Translates a file object's or folder's display name into an item identifier list. + // Return value: error code, if any + [PreserveSig] + Int32 ParseDisplayName( + IntPtr hwnd, + IntPtr pbc, + [MarshalAs(UnmanagedType.LPWStr)] + string pszDisplayName, + ref uint pchEaten, + out IntPtr ppidl, + ref SFGAO pdwAttributes); + + // Allows a client to determine the contents of a folder by creating an item + // identifier enumeration object and returning its IEnumIDList interface. + // Return value: error code, if any + [PreserveSig] + Int32 EnumObjects( + IntPtr hwnd, + SHCONTF grfFlags, + out IntPtr enumIDList); + + // Retrieves an IShellFolder object for a subfolder. + // Return value: error code, if any + [PreserveSig] + Int32 BindToObject( + IntPtr pidl, + IntPtr pbc, + ref Guid riid, + out IntPtr ppv); + + // Requests a pointer to an object's storage interface. + // Return value: error code, if any + [PreserveSig] + Int32 BindToStorage( + IntPtr pidl, + IntPtr pbc, + ref Guid riid, + out IntPtr ppv); + + // Determines the relative order of two file objects or folders, given their + // item identifier lists. Return value: If this method is successful, the + // CODE field of the HRESULT contains one of the following values (the code + // can be retrived using the helper function GetHResultCode): Negative A + // negative return value indicates that the first item should precede + // the second (pidl1 < pidl2). + + // Positive A positive return value indicates that the first item should + // follow the second (pidl1 > pidl2). Zero A return value of zero + // indicates that the two items are the same (pidl1 = pidl2). + [PreserveSig] + Int32 CompareIDs( + IntPtr lParam, + IntPtr pidl1, + IntPtr pidl2); + + // Requests an object that can be used to obtain information from or interact + // with a folder object. + // Return value: error code, if any + [PreserveSig] + Int32 CreateViewObject( + IntPtr hwndOwner, + Guid riid, + out IntPtr ppv); + + // Retrieves the attributes of one or more file objects or subfolders. + // Return value: error code, if any + [PreserveSig] + Int32 GetAttributesOf( + uint cidl, + [MarshalAs(UnmanagedType.LPArray)] + IntPtr[] apidl, + ref SFGAO rgfInOut); + + // Retrieves an OLE interface that can be used to carry out actions on the + // specified file objects or folders. + // Return value: error code, if any + [PreserveSig] + Int32 GetUIObjectOf( + IntPtr hwndOwner, + uint cidl, + [MarshalAs(UnmanagedType.LPArray)] + IntPtr[] apidl, + ref Guid riid, + IntPtr rgfReserved, + out IntPtr ppv); + + // Retrieves the display name for the specified file object or subfolder. + // Return value: error code, if any + [PreserveSig()] + Int32 GetDisplayNameOf( + IntPtr pidl, + SHGNO uFlags, + IntPtr lpName); + + // Sets the display name of a file object or subfolder, changing the item + // identifier in the process. + // Return value: error code, if any + [PreserveSig] + Int32 SetNameOf( + IntPtr hwnd, + IntPtr pidl, + [MarshalAs(UnmanagedType.LPWStr)] + string pszName, + SHGNO uFlags, + out IntPtr ppidlOut); + } + #endregion + + #region IContextMenu + [ComImport()] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [GuidAttribute("000214e4-0000-0000-c000-000000000046")] + private interface IContextMenu + { + // Adds commands to a shortcut menu + [PreserveSig()] + Int32 QueryContextMenu( + IntPtr hmenu, + uint iMenu, + uint idCmdFirst, + uint idCmdLast, + CMF uFlags); + + // Carries out the command associated with a shortcut menu item + [PreserveSig()] + Int32 InvokeCommand( + ref CMINVOKECOMMANDINFOEX info); + + // Retrieves information about a shortcut menu command, + // including the help string and the language-independent, + // or canonical, name for the command + [PreserveSig()] + Int32 GetCommandString( + uint idcmd, + GCS uflags, + uint reserved, + [MarshalAs(UnmanagedType.LPArray)] + byte[] commandstring, + int cch); + } + + [ComImport, Guid("000214f4-0000-0000-c000-000000000046")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IContextMenu2 + { + // Adds commands to a shortcut menu + [PreserveSig()] + Int32 QueryContextMenu( + IntPtr hmenu, + uint iMenu, + uint idCmdFirst, + uint idCmdLast, + CMF uFlags); + + // Carries out the command associated with a shortcut menu item + [PreserveSig()] + Int32 InvokeCommand( + ref CMINVOKECOMMANDINFOEX info); + + // Retrieves information about a shortcut menu command, + // including the help string and the language-independent, + // or canonical, name for the command + [PreserveSig()] + Int32 GetCommandString( + uint idcmd, + GCS uflags, + uint reserved, + [MarshalAs(UnmanagedType.LPWStr)] + StringBuilder commandstring, + int cch); + + // Allows client objects of the IContextMenu interface to + // handle messages associated with owner-drawn menu items + [PreserveSig] + Int32 HandleMenuMsg( + uint uMsg, + IntPtr wParam, + IntPtr lParam); + } + + [ComImport, Guid("bcfce0a0-ec17-11d0-8d10-00a0c90f2719")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface IContextMenu3 + { + // Adds commands to a shortcut menu + [PreserveSig()] + Int32 QueryContextMenu( + IntPtr hmenu, + uint iMenu, + uint idCmdFirst, + uint idCmdLast, + CMF uFlags); + + // Carries out the command associated with a shortcut menu item + [PreserveSig()] + Int32 InvokeCommand( + ref CMINVOKECOMMANDINFOEX info); + + // Retrieves information about a shortcut menu command, + // including the help string and the language-independent, + // or canonical, name for the command + [PreserveSig()] + Int32 GetCommandString( + uint idcmd, + GCS uflags, + uint reserved, + [MarshalAs(UnmanagedType.LPWStr)] + StringBuilder commandstring, + int cch); + + // Allows client objects of the IContextMenu interface to + // handle messages associated with owner-drawn menu items + [PreserveSig] + Int32 HandleMenuMsg( + uint uMsg, + IntPtr wParam, + IntPtr lParam); + + // Allows client objects of the IContextMenu3 interface to + // handle messages associated with owner-drawn menu items + [PreserveSig] + Int32 HandleMenuMsg2( + uint uMsg, + IntPtr wParam, + IntPtr lParam, + IntPtr plResult); + } + #endregion + } + + #region ShellContextMenuException + public class ShellContextMenuException : Exception + { + /// Default contructor + public ShellContextMenuException() + { + } + + /// Constructor with message + /// Message + public ShellContextMenuException(string message) + : base(message) + { + } + } + #endregion + + #region Class HookEventArgs + public class HookEventArgs : EventArgs + { + public int HookCode; // Hook code + public IntPtr wParam; // WPARAM argument + public IntPtr lParam; // LPARAM argument + } + #endregion + + #region Enum HookType + // Hook Types + public enum HookType : int + { + WH_JOURNALRECORD = 0, + WH_JOURNALPLAYBACK = 1, + WH_KEYBOARD = 2, + WH_GETMESSAGE = 3, + WH_CALLWNDPROC = 4, + WH_CBT = 5, + WH_SYSMSGFILTER = 6, + WH_MOUSE = 7, + WH_HARDWARE = 8, + WH_DEBUG = 9, + WH_SHELL = 10, + WH_FOREGROUNDIDLE = 11, + WH_CALLWNDPROCRET = 12, + WH_KEYBOARD_LL = 13, + WH_MOUSE_LL = 14 + } + #endregion + + #region Class LocalWindowsHook + public class LocalWindowsHook + { + // ************************************************************************ + // Filter function delegate + public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam); + // ************************************************************************ + + // ************************************************************************ + // Internal properties + protected IntPtr m_hhook = IntPtr.Zero; + protected HookProc m_filterFunc = null; + protected HookType m_hookType; + // ************************************************************************ + + // ************************************************************************ + // Event delegate + public delegate void HookEventHandler(object sender, HookEventArgs e); + // ************************************************************************ + + // ************************************************************************ + // Event: HookInvoked + public event HookEventHandler HookInvoked; + protected void OnHookInvoked(HookEventArgs e) + { + if (HookInvoked != null) + HookInvoked(this, e); + } + // ************************************************************************ + + // ************************************************************************ + // Class constructor(s) + public LocalWindowsHook(HookType hook) + { + m_hookType = hook; + m_filterFunc = new HookProc(this.CoreHookProc); + } + public LocalWindowsHook(HookType hook, HookProc func) + { + m_hookType = hook; + m_filterFunc = func; + } + // ************************************************************************ + + // ************************************************************************ + // Default filter function + protected int CoreHookProc(int code, IntPtr wParam, IntPtr lParam) + { + if (code < 0) + return CallNextHookEx(m_hhook, code, wParam, lParam); + + // Let clients determine what to do + HookEventArgs e = new HookEventArgs(); + e.HookCode = code; + e.wParam = wParam; + e.lParam = lParam; + OnHookInvoked(e); + + // Yield to the next hook in the chain + return CallNextHookEx(m_hhook, code, wParam, lParam); + } + // ************************************************************************ + + // ************************************************************************ + // Install the hook + public void Install() + { + m_hhook = SetWindowsHookEx( + m_hookType, + m_filterFunc, + IntPtr.Zero, +#pragma warning disable CS0618 // depricated + (int)AppDomain.GetCurrentThreadId()); +#pragma warning restore CS0618 // depricated + } + // ************************************************************************ + + // ************************************************************************ + // Uninstall the hook + public void Uninstall() + { + UnhookWindowsHookEx(m_hhook); + } + // ************************************************************************ + + + #region Win32 Imports + // ************************************************************************ + // Win32: SetWindowsHookEx() + [DllImport("user32.dll")] + protected static extern IntPtr SetWindowsHookEx(HookType code, + HookProc func, + IntPtr hInstance, + int threadID); + // ************************************************************************ + + // ************************************************************************ + // Win32: UnhookWindowsHookEx() + [DllImport("user32.dll")] + protected static extern int UnhookWindowsHookEx(IntPtr hhook); + // ************************************************************************ + + // ************************************************************************ + // Win32: CallNextHookEx() + [DllImport("user32.dll")] + protected static extern int CallNextHookEx(IntPtr hhook, + int code, IntPtr wParam, IntPtr lParam); + // ************************************************************************ + #endregion + } + #endregion + + #region ShellHelper + + internal static class ShellHelper + { + #region Low/High Word + + /// + /// Retrieves the High Word of a WParam of a WindowMessage + /// + /// The pointer to the WParam + /// The unsigned integer for the High Word + public static uint HiWord(IntPtr ptr) + { + uint param32 = (uint)(ptr.ToInt64() | 0xffffffffL); + if ((param32 & 0x80000000) == 0x80000000) + return (param32 >> 16); + else + return (param32 >> 16) & 0xffff; + } + + /// + /// Retrieves the Low Word of a WParam of a WindowMessage + /// + /// The pointer to the WParam + /// The unsigned integer for the Low Word + public static uint LoWord(IntPtr ptr) + { + uint param32 = (uint)(ptr.ToInt64() | 0xffffffffL); + return (param32 & 0xffff); + } + + #endregion + } + + #endregion +} diff --git a/Helper/Taskbar.cs b/Helper/Taskbar.cs new file mode 100644 index 0000000..74efc79 --- /dev/null +++ b/Helper/Taskbar.cs @@ -0,0 +1,143 @@ +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace SystemTrayMenu +{ + public enum TaskbarPosition + { + Unknown = -1, + Left, + Top, + Right, + Bottom, + } + + public sealed class Taskbar + { + private const string ClassName = "Shell_TrayWnd"; + + public Rectangle Bounds + { + get; + private set; + } + public TaskbarPosition Position + { + get; + private set; + } + public Point Location + { + get + { + return Bounds.Location; + } + } + public Size Size + { + get + { + return Bounds.Size; + } + } + //Always returns false under Windows 7 + public bool AlwaysOnTop + { + get; + private set; + } + public bool AutoHide + { + get; + private set; + } + + public Taskbar() + { + IntPtr taskbarHandle = User32.FindWindow(Taskbar.ClassName, null); + + APPBARDATA data = new APPBARDATA(); + data.cbSize = (uint)Marshal.SizeOf(typeof(APPBARDATA)); + data.hWnd = taskbarHandle; + IntPtr result = Shell32.SHAppBarMessage(ABM.GetTaskbarPos, ref data); + if (result == IntPtr.Zero) + { + //throw new InvalidOperationException(); + Bounds = new Rectangle(20, 20, 20, 20); + } + else + { + 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); + int state = result.ToInt32(); + this.AlwaysOnTop = (state & ABS.AlwaysOnTop) == ABS.AlwaysOnTop; + this.AutoHide = (state & ABS.Autohide) == ABS.Autohide; + } + } + } + + 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; + } +} diff --git a/Helper/WaitFastLeave.cs b/Helper/WaitFastLeave.cs new file mode 100644 index 0000000..7d1466c --- /dev/null +++ b/Helper/WaitFastLeave.cs @@ -0,0 +1,39 @@ +using System; +using Timer = System.Windows.Forms.Timer; + +namespace SystemTrayMenu.Helper +{ + class WaitFastLeave : IDisposable + { + public event EventHandler Leave; + + Timer timerSecondLeaveCheck = new Timer(); + + public WaitFastLeave() + { + timerSecondLeaveCheck.Interval = 200; + timerSecondLeaveCheck.Tick += LeaveWorkaround_Tick; + } + + // When menu not activated and mouse leaves menu very fast, + // mouse still on menu but we not get leave event again + // as workaround we call the check again (200ms later) + public void Start() + { + Leave.Invoke(); + timerSecondLeaveCheck.Stop(); + timerSecondLeaveCheck.Start(); + } + + private void LeaveWorkaround_Tick(object sender, EventArgs e) + { + timerSecondLeaveCheck.Stop(); + Leave.Invoke(); + } + + public void Dispose() + { + timerSecondLeaveCheck.Dispose(); + } + } +} diff --git a/Helper/WaitMenuOpen.cs b/Helper/WaitMenuOpen.cs new file mode 100644 index 0000000..c61e005 --- /dev/null +++ b/Helper/WaitMenuOpen.cs @@ -0,0 +1,75 @@ +using System; +using Timer = System.Windows.Forms.Timer; + +namespace SystemTrayMenu.Helper +{ + class WaitMenuOpen : IDisposable + { + public event EventHandler DoOpen; + + Timer waitOpen = new Timer(); + bool waitedDone = false; + bool clicked = false; + bool menuLoaded = false; + + public WaitMenuOpen() + { + waitOpen.Interval = MenuDefines.WaitMenuOpen; + waitOpen.Tick += WaitOpen_Tick; + } + + private void WaitOpen_Tick(object sender, EventArgs e) + { + waitOpen.Stop(); + waitedDone = true; + CheckConditionsToOpenMenu(); + } + + private void CheckConditionsToOpenMenu() + { + if ((waitedDone || clicked) && + menuLoaded) + { + Stop(); + DoOpen?.Invoke(); + } + } + + // When mouse on menu, wait x ms until open it + // meanwhile load content, click opens when loaded + // (to not interrupt user when he moves into a submenu) + public void Start() + { + if (!waitedDone) + { + waitOpen.Start(); + } + } + + public void Stop() + { + clicked = false; + waitedDone = false; + menuLoaded = false; + waitOpen.Stop(); + } + + public void Click() + { + clicked = true; + CheckConditionsToOpenMenu(); + } + + public void MenuLoaded() + { + menuLoaded = true; + CheckConditionsToOpenMenu(); + } + + public void Dispose() + { + Stop(); + waitOpen.Dispose(); + } + } +} \ No newline at end of file diff --git a/MenuDefines.cs b/MenuDefines.cs new file mode 100644 index 0000000..44fc732 --- /dev/null +++ b/MenuDefines.cs @@ -0,0 +1,41 @@ +using System.Drawing; + +namespace SystemTrayMenu +{ + public static class MenuDefines + { + // windows explorer background white + public static Color File = Color.White; + public static Color Folder = Color.White; + + // windows explorer selected text + public static Color FileHover = Color.FromArgb(204, 232, 255); + + // windows explorer highlighted text + public static Color FolderOpen = Color.FromArgb(229, 243, 255); + public static Color Background = Color.FromArgb(229, 243, 255); + internal static Color KeyBoardSelection = Color.Yellow; + internal static int KeySearchInterval = 1000; + public const int MenuRowsHeight = 18; + public const int LengthMax = 37; + public const int ButtonTextPaddingLeft = 18; + public const int ButtonTextPaddingRight= 12; + + public const int Scrollspeed = 4; + + public const int WaitMenuOpen = 200; + + // 60 fps => 1000ms/60fps =~ 16.6ms + public const int IntervalFade = 16; + + // 60 fps => 1000ms/60fps =~ 16.6ms + public const int IntervalLoad = 16; + + public const double OpacityHalfValue = 0.80; + public const double OpacityInStep = 0.20; + public const double OpacityOutStep = 0.05; + public const double OpacityHalfStep = 0.01; + + public const int MenusMax = 50; + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..874a6d9 --- /dev/null +++ b/Program.cs @@ -0,0 +1,183 @@ +using Clearcove.Logging; +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Resources; +using System.Runtime.InteropServices; +using System.Threading; +using System.Windows.Forms; + +namespace SystemTrayMenu +{ + static class Program + { + public static readonly List Languages = + new List() { "en", "de" }; + public static CultureInfo Culture; + public static float ScalingFactor = 1; + + private const string IconDir = "Icons\\"; + + + [System.Runtime.InteropServices.DllImport("user32.dll")] + private static extern bool SetProcessDPIAware(); + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + if (IsAppAlreadyRunning("SystemTrayMenu")) + { + KillOtherSystemTrayMenus(); + } + + GetDefaultLanguage(); + + ScalingFactor = GetScalingFactor(); + if (Environment.OSVersion.Version.Major >= 6) + { + SetProcessDPIAware(); + } + + Logger log = new Logger(nameof(Program)); + Logger.Start(new FileInfo(GetLogFilePath())); + try + { + bool cancelAppRun = false; + using (SystemTrayMenuHandler stm = + new SystemTrayMenuHandler(ref cancelAppRun)) + { + if (!cancelAppRun) + { + Application.Run(); + } + } + } + catch (Exception ex) + { + log.Error($"{ex.ToString()}"); + } + finally + { + Logger.ShutDown(); + } + } + + static bool KillOtherSystemTrayMenus() + { + bool killedAProcess = false; + int ownPID = Process.GetCurrentProcess().Id; + + foreach (Process p in Process.GetProcessesByName("SystemTrayMenu"). + Where(p => p.Id != ownPID)) + { + try + { + p.Kill(); + p.WaitForExit(); + killedAProcess = true; + } + catch (Win32Exception winException) + { + Logger log = new Logger(nameof(Program)); + log.Error($"{winException.ToString()}"); + MessageBox.Show(winException.ToString()); + Application.Exit(); + } + catch (InvalidOperationException invalidException) + { + Logger log = new Logger(nameof(Program)); + log.Error($"{invalidException.ToString()}"); + MessageBox.Show(invalidException.ToString()); + Application.Exit(); + } + } + + return killedAProcess; + } + + static bool IsAppAlreadyRunning(string processName) + { + foreach (Process p in Process.GetProcessesByName(processName). + Where(s => s.Id != Process.GetCurrentProcess().Id)) + { + return true; + } + + return false; + } + + internal static string GetLogFilePath() + { + return Path.Combine(Path.GetDirectoryName( + System.Reflection.Assembly.GetExecutingAssembly().Location), + $"log-{System.Environment.MachineName}.txt"); + } + + private static void GetDefaultLanguage() + { + if (string.IsNullOrEmpty(Properties.Settings.Default. + CurrentCultureInfoName)) + { + Properties.Settings.Default.CurrentCultureInfoName = "en"; + CultureInfo currentCulture = Thread.CurrentThread. + CurrentCulture; + foreach (string language in Languages) + { + string twoLetter = currentCulture.Name.Substring(0, 2); + if (language == currentCulture.Name || + language == twoLetter) + { + Properties.Settings.Default.CurrentCultureInfoName = + language; + } + } + Properties.Settings.Default.Save(); + } + + Culture = CultureInfo.CreateSpecificCulture( + Properties.Settings.Default.CurrentCultureInfoName); + } + + [DllImport("gdi32.dll")] + static extern int GetDeviceCaps(IntPtr hdc, int nIndex); + public enum DeviceCap + { + VERTRES = 10, + DESKTOPVERTRES = 117, + + // http://pinvoke.net/default.aspx/gdi32/GetDeviceCaps.html + } + + static float GetScalingFactor() + { + Graphics g = Graphics.FromHwnd(IntPtr.Zero); + IntPtr desktop = g.GetHdc(); + int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES); + int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES); + + float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight; + + return ScreenScalingFactor; // 1.25 = 125% + } + + internal static string Translate(string id) + { + ResourceManager rm = new ResourceManager( + "SystemTrayMenu.Resources.lang", + typeof(Menu).Assembly); + return rm.GetString(id, Culture); + } + } +} \ No newline at end of file diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c09064b --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +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("SystemTrayMenu")] +[assembly: AssemblyDescription("AN IMPROVED WINDOWS TOOLBAR")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("TAMAHO")] +[assembly: AssemblyProduct("TAMAHO SystemTrayMenu")] +[assembly: AssemblyCopyright("Copyright © 2019, TAMAHO")] +[assembly: AssemblyTrademark("TAMAHO")] +[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("116c8741-a9b0-4560-8e82-7cf412894340")] + +// 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("0.9.1.233")] +[assembly: AssemblyFileVersion("0.9.1.233")] diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs new file mode 100644 index 0000000..94d1ba7 --- /dev/null +++ b/Properties/Resources.Designer.cs @@ -0,0 +1,293 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace SystemTrayMenu.Properties { + using System; + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. + // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen + // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public 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() { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SystemTrayMenu.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Ãœberschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap hintDragDrop { + get { + object obj = ResourceManager.GetObject("hintDragDrop", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L010 { + get { + object obj = ResourceManager.GetObject("L010", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L020 { + get { + object obj = ResourceManager.GetObject("L020", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L030 { + get { + object obj = ResourceManager.GetObject("L030", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L040 { + get { + object obj = ResourceManager.GetObject("L040", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L050 { + get { + object obj = ResourceManager.GetObject("L050", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L060 { + get { + object obj = ResourceManager.GetObject("L060", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L070 { + get { + object obj = ResourceManager.GetObject("L070", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L080 { + get { + object obj = ResourceManager.GetObject("L080", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L090 { + get { + object obj = ResourceManager.GetObject("L090", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L100 { + get { + object obj = ResourceManager.GetObject("L100", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L110 { + get { + object obj = ResourceManager.GetObject("L110", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L120 { + get { + object obj = ResourceManager.GetObject("L120", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L130 { + get { + object obj = ResourceManager.GetObject("L130", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L140 { + get { + object obj = ResourceManager.GetObject("L140", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L150 { + get { + object obj = ResourceManager.GetObject("L150", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L160 { + get { + object obj = ResourceManager.GetObject("L160", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L170 { + get { + object obj = ResourceManager.GetObject("L170", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon L180 { + get { + object obj = ResourceManager.GetObject("L180", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap NotSelected { + get { + object obj = ResourceManager.GetObject("NotSelected", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap Selected { + get { + object obj = ResourceManager.GetObject("Selected", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + public static System.Drawing.Bitmap STM { + get { + object obj = ResourceManager.GetObject("STM", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + public static System.Drawing.Icon SystemTrayMenu { + get { + object obj = ResourceManager.GetObject("SystemTrayMenu", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + } +} diff --git a/Properties/Resources.resx b/Properties/Resources.resx new file mode 100644 index 0000000..9eda6af --- /dev/null +++ b/Properties/Resources.resx @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\SystemTrayMenu.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\STM.ico;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\resources\Selected.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\hintDragDrop.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L010.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L020.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L030.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L040.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L050.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L060.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L070.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L080.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L090.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L100.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L110.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L120.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L130.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L140.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L150.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L160.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L170.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\L180.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\NotSelected.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs new file mode 100644 index 0000000..5064ec5 --- /dev/null +++ b/Properties/Settings.Designer.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace SystemTrayMenu.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.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.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string CurrentCultureInfoName { + get { + return ((string)(this["CurrentCultureInfoName"])); + } + set { + this["CurrentCultureInfoName"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string PathDirectory { + get { + return ((string)(this["PathDirectory"])); + } + set { + this["PathDirectory"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool IsAutostartActivated { + get { + return ((bool)(this["IsAutostartActivated"])); + } + set { + this["IsAutostartActivated"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string HotKey { + get { + return ((string)(this["HotKey"])); + } + set { + this["HotKey"] = value; + } + } + } +} diff --git a/Properties/Settings.settings b/Properties/Settings.settings new file mode 100644 index 0000000..e9f3f3b --- /dev/null +++ b/Properties/Settings.settings @@ -0,0 +1,18 @@ + + + + + + + + + + + + False + + + + + + \ No newline at end of file diff --git a/Resources/L010.ico b/Resources/L010.ico new file mode 100644 index 0000000..c5287ff Binary files /dev/null and b/Resources/L010.ico differ diff --git a/Resources/L020.ico b/Resources/L020.ico new file mode 100644 index 0000000..0a95231 Binary files /dev/null and b/Resources/L020.ico differ diff --git a/Resources/L030.ico b/Resources/L030.ico new file mode 100644 index 0000000..09a8647 Binary files /dev/null and b/Resources/L030.ico differ diff --git a/Resources/L040.ico b/Resources/L040.ico new file mode 100644 index 0000000..e21a608 Binary files /dev/null and b/Resources/L040.ico differ diff --git a/Resources/L050.ico b/Resources/L050.ico new file mode 100644 index 0000000..3898518 Binary files /dev/null and b/Resources/L050.ico differ diff --git a/Resources/L060.ico b/Resources/L060.ico new file mode 100644 index 0000000..af72fdd Binary files /dev/null and b/Resources/L060.ico differ diff --git a/Resources/L070.ico b/Resources/L070.ico new file mode 100644 index 0000000..eff1c80 Binary files /dev/null and b/Resources/L070.ico differ diff --git a/Resources/L080.ico b/Resources/L080.ico new file mode 100644 index 0000000..c62f41f Binary files /dev/null and b/Resources/L080.ico differ diff --git a/Resources/L090.ico b/Resources/L090.ico new file mode 100644 index 0000000..34488ce Binary files /dev/null and b/Resources/L090.ico differ diff --git a/Resources/L100.ico b/Resources/L100.ico new file mode 100644 index 0000000..ced488e Binary files /dev/null and b/Resources/L100.ico differ diff --git a/Resources/L110.ico b/Resources/L110.ico new file mode 100644 index 0000000..edf1b5f Binary files /dev/null and b/Resources/L110.ico differ diff --git a/Resources/L120.ico b/Resources/L120.ico new file mode 100644 index 0000000..b7a37a7 Binary files /dev/null and b/Resources/L120.ico differ diff --git a/Resources/L130.ico b/Resources/L130.ico new file mode 100644 index 0000000..6475d85 Binary files /dev/null and b/Resources/L130.ico differ diff --git a/Resources/L140.ico b/Resources/L140.ico new file mode 100644 index 0000000..c29be1d Binary files /dev/null and b/Resources/L140.ico differ diff --git a/Resources/L150.ico b/Resources/L150.ico new file mode 100644 index 0000000..a165b91 Binary files /dev/null and b/Resources/L150.ico differ diff --git a/Resources/L160.ico b/Resources/L160.ico new file mode 100644 index 0000000..b9ec506 Binary files /dev/null and b/Resources/L160.ico differ diff --git a/Resources/L170.ico b/Resources/L170.ico new file mode 100644 index 0000000..243ba51 Binary files /dev/null and b/Resources/L170.ico differ diff --git a/Resources/L180.ico b/Resources/L180.ico new file mode 100644 index 0000000..d5338b1 Binary files /dev/null and b/Resources/L180.ico differ diff --git a/Resources/NotSelected.png b/Resources/NotSelected.png new file mode 100644 index 0000000..9eb07d2 Binary files /dev/null and b/Resources/NotSelected.png differ diff --git a/Resources/STM.ico b/Resources/STM.ico new file mode 100644 index 0000000..129a4e9 Binary files /dev/null and b/Resources/STM.ico differ diff --git a/Resources/STM_black.ico b/Resources/STM_black.ico new file mode 100644 index 0000000..c35ef8b Binary files /dev/null and b/Resources/STM_black.ico differ diff --git a/Resources/Selected.png b/Resources/Selected.png new file mode 100644 index 0000000..a1ae604 Binary files /dev/null and b/Resources/Selected.png differ diff --git a/Resources/SystemTrayMenu.ico b/Resources/SystemTrayMenu.ico new file mode 100644 index 0000000..129a4e9 Binary files /dev/null and b/Resources/SystemTrayMenu.ico differ diff --git a/Resources/hintDragDrop.png b/Resources/hintDragDrop.png new file mode 100644 index 0000000..ea8a44a Binary files /dev/null and b/Resources/hintDragDrop.png differ diff --git a/Resources/lang.Designer.cs b/Resources/lang.Designer.cs new file mode 100644 index 0000000..389745c --- /dev/null +++ b/Resources/lang.Designer.cs @@ -0,0 +1,243 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace SystemTrayMenu.Resources { + using System; + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. + // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen + // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class lang { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal lang() { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [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("SystemTrayMenu.Resources.lang", typeof(lang).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Ãœberschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die (e.g. F12) ähnelt. + /// + internal static string _e_g__F12_ { + get { + return ResourceManager.GetString("(e.g. F12)", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die About ähnelt. + /// + internal static string About { + get { + return ResourceManager.GetString("About", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Activate autostart ähnelt. + /// + internal static string Activate_autostart { + get { + return ResourceManager.GetString("Activate autostart", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die ALT ähnelt. + /// + internal static string ALT { + get { + return ResourceManager.GetString("ALT", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Autostart ähnelt. + /// + internal static string Autostart { + get { + return ResourceManager.GetString("Autostart", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Details ähnelt. + /// + internal static string buttonDetails { + get { + return ResourceManager.GetString("buttonDetails", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die OK ähnelt. + /// + internal static string buttonOk { + get { + return ResourceManager.GetString("buttonOk", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die System Info ähnelt. + /// + internal static string buttonSystemInfo { + get { + return ResourceManager.GetString("buttonSystemInfo", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die CTRL ähnelt. + /// + internal static string CTRL { + get { + return ResourceManager.GetString("CTRL", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die English ähnelt. + /// + internal static string English { + get { + return ResourceManager.GetString("English", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Exit ähnelt. + /// + internal static string Exit { + get { + return ResourceManager.GetString("Exit", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Folder ähnelt. + /// + internal static string Folder { + get { + return ResourceManager.GetString("Folder", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Folder empty ähnelt. + /// + internal static string Folder_empty { + get { + return ResourceManager.GetString("Folder empty", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Deutsch ähnelt. + /// + internal static string German { + get { + return ResourceManager.GetString("German", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Move the NotifyIcon per DragDrop from the SystemTray into the Taskbar ähnelt. + /// + internal static string HintDragDropText { + get { + return ResourceManager.GetString("HintDragDropText", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die SystemTrayMenu - Hint ähnelt. + /// + internal static string HintDragDropTitle { + get { + return ResourceManager.GetString("HintDragDropTitle", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Language ähnelt. + /// + internal static string Language { + get { + return ResourceManager.GetString("Language", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Log File ähnelt. + /// + internal static string Log_File { + get { + return ResourceManager.GetString("Log File", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Restart ähnelt. + /// + internal static string Restart { + get { + return ResourceManager.GetString("Restart", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Shortcut key ähnelt. + /// + internal static string Shortcut_key { + get { + return ResourceManager.GetString("Shortcut key", resourceCulture); + } + } + } +} diff --git a/Resources/lang.de-DE.Designer.cs b/Resources/lang.de-DE.Designer.cs new file mode 100644 index 0000000..e69de29 diff --git a/Resources/lang.de-DE.resx b/Resources/lang.de-DE.resx new file mode 100644 index 0000000..efffcb6 --- /dev/null +++ b/Resources/lang.de-DE.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Ãœber + + + Autostart aktivieren + + + OK + + + Autostart + + + Beenden + + + Ordner + + + Ziehe das Notify-Icon per DragDrop vom SystemTray in die Taskleiste + + + SystemTrayMenu - Hinweis + + + Sprache + + + Log Datei + + + Neustart + + + Ordner leer + + + ALT + + + STRG + + + Tastenkombination + + + English + + + Deutsch + + + (z.B. F12) + + + Details + + + System Info + + \ No newline at end of file diff --git a/Resources/lang.resx b/Resources/lang.resx new file mode 100644 index 0000000..054b5ae --- /dev/null +++ b/Resources/lang.resx @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + About + + + Activate autostart + + + OK + + + Autostart + + + English + + + Exit + + + Folder + + + Deutsch + + + Move the NotifyIcon per DragDrop from the SystemTray into the Taskbar + + + SystemTrayMenu - Hint + + + Language + + + Log File + + + Restart + + + Folder empty + + + ALT + + + CTRL + + + Shortcut key + + + (e.g. F12) + + + Details + + + System Info + + \ No newline at end of file diff --git a/STM Request Norton.txt b/STM Request Norton.txt new file mode 100644 index 0000000..b56f09a --- /dev/null +++ b/STM Request Norton.txt @@ -0,0 +1,59 @@ +Hello Symantec Team, + +I am the owner/ developer of my software TAMAHO SystemTrayMenu / systemtraymenu.exe + +My software is a improved windows toolbar. +Please find more informations on my website: +http://www.hofknecht.eu/systemtraymenu/ +(There i am frequently providing updates during beta phase) + +It not contains any other functionalities, no hidden doors. +My software exactly only makes what described on website. + +Current version is 0.9.1.224 +Later versions will be released under same homepage. Links look then like (current version): +http://hofknecht.eu/systemtraymenu/0.9.1.224/SystemTrayMenu-0.9.1.224-beta.zip + +It will probably become Open Source as soon it is good enough ;) + +A user reported, that Norton detects systemtraymenu.exe as unsafe and he needs to allow it explicitly. + +Here my product clipboard: +------------------------------ +SystemTrayMenu - An improved Windows Toolbar +Code from © 2019, TAMAHO, All Rights Reserved. Developer: +Markus Hofknecht (mailto:Markus@Hofknecht.eu) +Tanja Kauth (Tanja@Hofknecht.eu) + +http://www.hofknecht.eu/systemtraymenu/ +------------------------------ + +If you have any questions please don't hesitate to contact me. + +Best Regards + +Markus Hofknecht +Software Engineer + + + +Was sent to Norton: +------------------------------ +CONFIRMATION +Your submission has been sent Fri Jun 21 21:10:37 UTC 2019. To make another submission, click here. + +Sincerely, + +Symantec Security Response +------------------------------ + +Was sent to AVAST: +------------------------------ +Thank you! We have received the URL you submitted. + +If we need any further information we will contact you. Otherwise, we will reply when the analysis is complete to let you know what action we’ve taken. + +Kind regards, +The Support Team +AVAST Software +------------------------------ \ No newline at end of file diff --git a/SystemTrayMenu.csproj b/SystemTrayMenu.csproj new file mode 100644 index 0000000..388ee23 --- /dev/null +++ b/SystemTrayMenu.csproj @@ -0,0 +1,236 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {F317AF2E-9704-4A2A-BDAE-B4662ED9483B} + WinExe + Properties + SystemTrayMenu + SystemTrayMenu + v4.7.2 + + + 512 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + SystemTrayMenu.Program + + + Resources\SystemTrayMenu.ico + + + + ..\CodeProjects\SimpleLogger\SimpleLogger\Clearcove.Logging\bin\Debug\Clearcove.Logging.dll + + + ..\ThirdParty\Windows-API-Code-Pack-1.1-master\source\WindowsAPICodePack\Shell\bin\Debug\Microsoft.WindowsAPICodePack.Shell.dll + + + + + + + + + + + + + ..\CodeProjects\IconPack\TAFactory.IconPack.dll + + + + + + Form + + + AboutBox.cs + + + Form + + + AskHotKeyForm.cs + + + Form + + + DragDropHintForm.cs + + + + + + + + + + + + + + + + True + True + Resources.resx + + + lang.de-DE.resx + True + True + + + True + True + lang.resx + + + + + + Form + + + Menu.cs + + + + + + + + AboutBox.cs + + + AskHotKeyForm.cs + + + DragDropHintForm.cs + + + Menu.cs + + + ResXFileCodeGenerator + lang.de-DE.Designer.cs + + + ResXFileCodeGenerator + lang.Designer.cs + + + PublicResXFileCodeGenerator + Designer + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} + 1 + 0 + 0 + tlbimp + False + True + + + + + False + Microsoft .NET Framework 4.7.2 %28x86 und x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + \ No newline at end of file diff --git a/SystemTrayMenu.sln b/SystemTrayMenu.sln new file mode 100644 index 0000000..76a3df2 --- /dev/null +++ b/SystemTrayMenu.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28010.2046 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemTrayMenu", "SystemTrayMenu.csproj", "{F317AF2E-9704-4A2A-BDAE-B4662ED9483B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F317AF2E-9704-4A2A-BDAE-B4662ED9483B}.Debug|x86.ActiveCfg = Debug|x86 + {F317AF2E-9704-4A2A-BDAE-B4662ED9483B}.Debug|x86.Build.0 = Debug|x86 + {F317AF2E-9704-4A2A-BDAE-B4662ED9483B}.Release|x86.ActiveCfg = Release|x86 + {F317AF2E-9704-4A2A-BDAE-B4662ED9483B}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {ECA870FE-709A-4EC0-9F28-206977283A13} + EndGlobalSection +EndGlobal diff --git a/SystemTrayMenuHandler.cs b/SystemTrayMenuHandler.cs new file mode 100644 index 0000000..e9955cc --- /dev/null +++ b/SystemTrayMenuHandler.cs @@ -0,0 +1,1098 @@ +using Clearcove.Logging; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using SystemTrayMenu.Controls; +using SystemTrayMenu.Helper; + +namespace SystemTrayMenu +{ + #region Enable debug log by putting this code into each function + //MethodBase m = MethodBase.GetCurrentMethod(); + //log.Debug($"Executing {m.ReflectedType.Name}, {m.Name}"); + #endregion + class SystemTrayMenuHandler : IDisposable + { + Logger log = new Logger(nameof(SystemTrayMenuHandler)); + + KeyboardHook hook = new KeyboardHook(); + Timer timerKeySearch = new Timer(); + int iRowKey = -1; + int iMenuKey = 0; + string keyInput = string.Empty; + + MenuNotifyIcon menuNotifyIcon = new MenuNotifyIcon(); + WaitFastLeave fastLeave = new WaitFastLeave(); + Menu[] menus = new Menu[MenuDefines.MenusMax]; + bool isMainMenuOpen = false; + + BackgroundWorker worker = new BackgroundWorker(); + bool restartLoading = false; + Screen screen = null; + + public SystemTrayMenuHandler(ref bool cancelAppRun) + { + log.Info("Application Start " + + Assembly.GetExecutingAssembly(). + GetName().Version.ToString() + + $" ScalingFactor={Program.ScalingFactor}"); + + if (!string.IsNullOrEmpty(Properties.Settings.Default.HotKey)) + { + var cvt = new KeysConverter(); + var key = (Keys)cvt.ConvertFrom( + Properties.Settings.Default.HotKey); + try + { + hook.RegisterHotKey( + KeyboardHookModifierKeys.Control | + KeyboardHookModifierKeys.Alt, + key); + hook.KeyPressed += hook_KeyPressed; + } + catch (Exception ex) + { + log.Info($"key:'{key.ToString()}'"); + log.Error($"{ex.ToString()}"); + Properties.Settings.Default.HotKey = string.Empty; + Properties.Settings.Default.Save(); + MessageBox.Show(ex.Message); + ApplicationRestart(); + } + } + void hook_KeyPressed(object sender, KeyPressedEventArgs e) + { + SwitchOpenClose(); + } + + timerKeySearch.Interval = MenuDefines.KeySearchInterval; + timerKeySearch.Tick += TimerKeySearch_Tick; + menus[0] = new Menu(); + MessageFilter messageFilter = new MessageFilter(); + Application.AddMessageFilter(messageFilter); + menuNotifyIcon.Exit += Application.Exit; + + menuNotifyIcon.HandleClick += SwitchOpenClose; + void SwitchOpenClose() + { + if (Config.Path == string.Empty) + { + //Case when Folder Dialog open + } + else if (isMainMenuOpen && menus[0].Visible) + { + isMainMenuOpen = false; + MenusFadeOut(); + if (worker.IsBusy) + { + worker.CancelAsync(); + } + } + else if (worker.IsBusy) + { + restartLoading = true; + worker.CancelAsync(); + } + else + { + isMainMenuOpen = true; + if (menus[0].Visible) + { + ActivateMenu(); + } + else + { + screen = ScreenMouse.GetScreen(); + bool IsNotifyIconInTaskbar() + { + bool isNotifyIconInTaskbar = false; + int height = screen.Bounds.Height - + new Taskbar().Size.Height; + if (Cursor.Position.Y >= height) + { + isNotifyIconInTaskbar = true; + } + return isNotifyIconInTaskbar; + } + if (!IsNotifyIconInTaskbar()) + { + //DragDropHintForm hintForm = new DragDropHintForm( + // Program.Translate("HintDragDropTitle"), + // Program.Translate("HintDragDropText"), + // Program.Translate("buttonOk")); + //hintForm.Show(); + } + + menuNotifyIcon.LoadingStart(); + worker.RunWorkerAsync(); + } + } + } + + worker.WorkerSupportsCancellation = true; + worker.DoWork += Worker_DoWork; + void Worker_DoWork(object senderDoWork, + DoWorkEventArgs eDoWork) + { + int level = 0; + BackgroundWorker worker = (BackgroundWorker)senderDoWork; + restartLoading = false; + eDoWork.Result = ReadMenu(worker, Config.Path, level); + } + + worker.RunWorkerCompleted += Worker_RunWorkerCompleted; + void Worker_RunWorkerCompleted(object sender, + RunWorkerCompletedEventArgs e) + { + if (restartLoading) + { + worker.RunWorkerAsync(); + } + else + { + ResetSelectedByKey(); + menuNotifyIcon.LoadingStop(); + MenuData menuData = (MenuData)e.Result; + if (menuData.Valid) + { + menus[0] = CreateMenu(menuData, Path.GetFileName(Config.Path)); + menus[0].AdjustLocationAndSize(screen); + ActivateMenu(); + menus[0].AdjustLocationAndSize(screen); + } + } + } + + void ActivateMenu() + { + Menus().ToList().ForEach(menu => + { + menu.FadeIn(); + menu.FadeHalf(); + }); + menus[0].SetTitleColorActive(); + menus[0].Activate(); + WindowToTop.ForceForegroundWindow(menus[0].Handle); + } + + menuNotifyIcon.ChangeFolder += ChangeFolder; + void ChangeFolder() + { + if (Config.SetFolderByUser()) + { + ApplicationRestart(); + } + } + + menuNotifyIcon.OpenLog += OpenLog; + void OpenLog() + { + Process.Start(Program.GetLogFilePath()); + } + + menuNotifyIcon.Restart += ApplicationRestart; + void ApplicationRestart() + { + Dispose(); + Process.Start(Assembly.GetExecutingAssembly(). + ManifestModule.FullyQualifiedName); + } + + messageFilter.MouseMove += FadeInIfNeeded; + messageFilter.ScrollBarMouseMove += FadeInIfNeeded; + + messageFilter.MouseLeave += fastLeave.Start; + fastLeave.Leave += FadeHalfOrOutIfNeeded; + + if (!Config.LoadOrSetByUser()) + { + cancelAppRun = true; + } + } + void FadeInIfNeeded() + { + if (menus[0].Visible && + !menus[0].IsFadingIn && + !menus[0].IsFadingOut) + { + if (Menus().Any(m => m.Opacity < 1)) + { + Menus().ToList().ForEach(menu => menu.FadeIn()); + } + } + } + + void FadeHalfOrOutIfNeeded() + { + Point mousePosition = Control.MousePosition; + bool isMouseOnAnyMenu = + !Menus().Any(m => m.IsMouseOn(mousePosition)); + bool isAnyMenuActive = IsAnyMenuActive(); + + if (isMouseOnAnyMenu) + { + if (isAnyMenuActive && isMainMenuOpen) + { + if (!IsAnyMenuSelectedByKey()) + { + Menus().ToList().ForEach(menu => menu.FadeHalf()); + } + } + else + { + MenusFadeOut(); + } + } + } + + private void ResetSelectedByKey() + { + iRowKey = -1; + iMenuKey = 0; + } + + public void Dispose() + { + hook.Dispose(); + menuNotifyIcon.Dispose(); + fastLeave.Dispose(); + DisposeMenu(menus[0]); + } + + void DisposeMenu(Menu menuToDispose) + { + if (menuToDispose != null) + { + DataGridView dgv = menuToDispose.GetDataGridView(); + foreach (DataGridViewRow row in dgv.Rows) + { + RowData rowData = (RowData)row.Tag; + rowData.Dispose(); + DisposeMenu(rowData.SubMenu); + } + dgv.ClearSelection(); + menuToDispose.Dispose(); + menuToDispose = null; + } + } + + void DisposeWhenHidden(object sender, EventArgs e) + { + Menu menuToDispose = (Menu)sender; + if (!menuToDispose.Visible) + { + DisposeMenu(menuToDispose); + } + } + + void AdjustSubMenusLocationAndSize() + { + Screen screen = ScreenMouse.GetScreen(); + int heightMax = screen.Bounds.Height - + new Taskbar().Size.Height; + Menu menuPredecessor = menus[0]; + int widthPredecessors = -1; // -1 padding + bool directionToRight = false; + + foreach (Menu menu in Menus().Skip(1)) + { + // -1*2 padding + int newWith = (menu.Width - 2 + menuPredecessor.Width); + if (directionToRight) + { +#warning is this still correct? + if (widthPredecessors - menu.Width <= -2) // -1*2 padding + { + directionToRight = false; + } + else + { + widthPredecessors -= newWith; + } + } + else if (screen.Bounds.Width < + widthPredecessors + menuPredecessor.Width + menu.Width) + { + directionToRight = true; + widthPredecessors -= newWith; + } + + menu.AdjustLocationAndSize(heightMax, + widthPredecessors, menuPredecessor); + widthPredecessors += menu.Width - 1; // -1 padding + menuPredecessor = menu; + } + } + + void OpenSubMenu(object sender, EventArgs e) + { + RowData trigger = (RowData)sender; + Menu menuTriggered = trigger.SubMenu; + Menu menuFromTrigger = menus[menuTriggered.Level - 1]; + + for (int level = menuTriggered.Level; + level < MenuDefines.MenusMax; level++) + { + if (menus[level] != null) + { + Menu menuToClose = menus[level]; + RowData oldTrigger = (RowData)menuToClose.Tag; + DataGridView dgv = menuFromTrigger.GetDataGridView(); + foreach (DataGridViewRow row in dgv.Rows) + { + RowData rowData = (RowData)row.Tag; + rowData.IsSelected = false; + } + trigger.IsSelected = true; + dgv.ClearSelection(); + dgv.Rows[trigger.RowIndex].Selected = true; + menuToClose.FadeOut(); + menuToClose.VisibleChanged += DisposeWhenHidden; + menus[level] = null; + } + } + + menus[menuTriggered.Level] = menuTriggered; + AdjustSubMenusLocationAndSize(); + menus[menuTriggered.Level].FadeIn(); + AdjustSubMenusLocationAndSize(); + IsAnyMenuActive(); + } + + void Activated(object sender, EventArgs e) + { + Menu triggeredMenu = (Menu)sender; + menus[0].SetTitleColorActive(); + } + + bool IsAnyMenuActive() + { + bool isAnyMenuActive; + Form activeForm = Form.ActiveForm; + //isAnyMenuActive = Menus().Any(m => m.IsActive(activeForm)); + isAnyMenuActive = activeForm is Menu; + if (!isAnyMenuActive) + { + menus[0].SetTitleColorDeactive(); + CheckMenuOpenerStop(iMenuKey, iRowKey); + ClearIsSelectedByKey(iMenuKey, iRowKey); + ResetSelectedByKey(); + } + else + { + menus[0].SetTitleColorActive(); + } + + return isAnyMenuActive; + } + + MenuData ReadMenu(BackgroundWorker worker, string path, int level) + { + MenuData menuData = new MenuData(); + menuData.RowDatas = new List(); + menuData.Valid = false; + menuData.Level = level; + if (!worker.CancellationPending) + { + string[] directories = new string[] { }; + + try + { + directories = Directory.GetDirectories(path); + Array.Sort(directories, new WindowsExplorerSort()); + } + catch (Exception ex) + { + log.Info($"path:'{path}'"); + log.Error($"{ex.ToString()}"); + } + + foreach (string directory in directories) + { + if (worker != null && worker.CancellationPending) + { + break; + } + + RowData menuButtonData = ReadMenuButtonData(directory, false); + menuButtonData.ContainsMenu = true; + string resolvedLnkPath = string.Empty; + menuButtonData.ReadIcon(true, false, ref resolvedLnkPath); + menuData.RowDatas.Add(menuButtonData); + } + } + + if (!worker.CancellationPending) + { + string[] files = new string[] { }; + + try + { + files = Directory.GetFiles(path). + Where(p => Path.GetFileName(p) != "desktop.ini").ToArray(); + Array.Sort(files, new WindowsExplorerSort()); + } + catch (Exception ex) + { + log.Info($"path:'{path}'"); + log.Error($"{ex.ToString()}"); + } + + foreach (string file in files) + { + if (worker != null && worker.CancellationPending) + { + break; + } + + RowData menuButtonData = ReadMenuButtonData(file, false); + string resolvedLnkPath = string.Empty; + if (menuButtonData.ReadIcon(false, + false, ref resolvedLnkPath)) + { + menuButtonData = ReadMenuButtonData(resolvedLnkPath, true, file); + menuButtonData.ContainsMenu = true; + menuButtonData.ReadIcon(true, true, ref resolvedLnkPath); + } + + menuData.RowDatas.Add(menuButtonData); + } + } + + if (!worker.CancellationPending) + { + menuData.Valid = true; + } + + return menuData; + } + + RowData ReadMenuButtonData(string fileName, + bool isResolvedLnk, string fileUnresolved = null) + { + RowData menuButtonData = new RowData(); + menuButtonData.IsResolvedLnk = isResolvedLnk; + + try + { + menuButtonData.FileInfo = new FileInfo(fileName); + menuButtonData.TargetFilePath = menuButtonData.FileInfo.FullName; + menuButtonData.SetText($"{menuButtonData.FileInfo.Name}"); + if(string.IsNullOrEmpty(fileUnresolved)) + { + menuButtonData.TargetFilePathOrig = menuButtonData.TargetFilePath; + } + else + { + menuButtonData.TargetFilePathOrig = fileUnresolved; + } + } + catch (Exception ex) + { + log.Info($"fileName:'{fileName}'"); + log.Error($"{ex.ToString()}"); + } + + return menuButtonData; + } + + private void Dgv_MouseDoubleClick(object sender, MouseEventArgs e) + { + DataGridView dgv = (DataGridView)sender; + DataGridView.HitTestInfo hitTestInfo; + hitTestInfo = dgv.HitTest(e.X, e.Y); + if (hitTestInfo.RowIndex > -1 && + dgv.Rows.Count > hitTestInfo.RowIndex) + { + RowData trigger = (RowData)dgv.Rows[hitTestInfo.RowIndex].Tag; + trigger.DoubleClick(); + } + } + + private void Dgv_MouseDown(object sender, MouseEventArgs e) + { + DataGridView dgv = (DataGridView)sender; + DataGridView.HitTestInfo hitTestInfo; + hitTestInfo = dgv.HitTest(e.X, e.Y); + if (hitTestInfo.RowIndex > -1 && + dgv.Rows.Count > hitTestInfo.RowIndex) + { + RowData trigger = (RowData)dgv.Rows[hitTestInfo.RowIndex].Tag; + trigger.MouseDown(dgv, e); + } + } + + private void Dgv_MouseEnter(object sender, DataGridViewCellEventArgs e) + { + DataGridView dgv = (DataGridView)sender; + CheckMenuOpenerStart(dgv, e.RowIndex); + } + + private void CheckMenuOpenerStart(DataGridView dgv, int rowIndex) + { + if (rowIndex > -1 && + dgv.Rows.Count > rowIndex) + { + RowData trigger = (RowData)dgv.Rows[rowIndex].Tag; + trigger.IsSelected = true; + dgv.Rows[rowIndex].Selected = true; + Menu menuFromTrigger = (Menu)dgv.FindForm(); + Menu menuTriggered = trigger.SubMenu; + int level = menuFromTrigger.Level + 1; + + if (trigger.ContainsMenu && + level < MenuDefines.MenusMax && + !menus[0].IsFadingOut && + !menuFromTrigger.IsFadingOut && + (menus[level] == null || + menus[level] != menuTriggered)) + { + trigger.StopLoadMenuAndStartWaitToOpenIt(); + trigger.StartMenuOpener(); + + if (trigger.Reading.IsBusy) + { + trigger.RestartLoading = true; + } + else + { + menuNotifyIcon.LoadingStart(); + trigger.Reading.RunWorkerAsync(level); + } + } + } + } + + private void Dgv_MouseLeave(object sender, DataGridViewCellEventArgs e) + { + DataGridView dgv = (DataGridView)sender; + Menu menu = (Menu)dgv.FindForm(); + CheckMenuOpenerStop(menu.Level, e.RowIndex, dgv); + } + + private void CheckMenuOpenerStop(int menuIndex, int rowIndex, DataGridView dgv = null) + { + Menu menu = menus[menuIndex]; + if (menu != null && + rowIndex > -1) + { + if (dgv == null) + { + dgv = menu.GetDataGridView(); + } + if (dgv.Rows.Count > rowIndex) + { + RowData trigger = (RowData)dgv.Rows[rowIndex].Tag; + if (trigger.Reading.IsBusy) + { + if (!trigger.IsContextMenuOpen) + { + trigger.IsSelected = false; + dgv.Rows[rowIndex].Selected = false; + } + trigger.Reading.CancelAsync(); + } + else if (trigger.ContainsMenu && !trigger.IsLoading) + { + trigger.IsSelected = true; + dgv.Rows[rowIndex].Selected = true; + } + else + { + if (!trigger.IsContextMenuOpen) + { + trigger.IsSelected = false; + dgv.Rows[rowIndex].Selected = false; + } + } + if (trigger.IsLoading) + { + trigger.StopLoadMenuAndStartWaitToOpenIt(); + trigger.IsLoading = false; + } + } + } + } + + private void Dgv_SelectionChanged(object sender, EventArgs e) + { + DataGridView dgv = (DataGridView)sender; + foreach (DataGridViewRow row in dgv.Rows) + { + RowData rowData = (RowData)row.Tag; + if (rowData.IsSelectedByKeyboard) + { + row.DefaultCellStyle.SelectionBackColor = + MenuDefines.KeyBoardSelection; + row.Selected = true; + } + else if (rowData.IsSelected) + { + row.DefaultCellStyle.SelectionBackColor = + MenuDefines.FolderOpen; + row.Selected = true; + } + else + { + rowData.IsSelected = false; + row.Selected = false; + } + } + } + + IEnumerable Menus() + { + return menus.Where(m => m != null); + } + + void MenusFadeOut() + { + Menus().ToList().ForEach(menu => + { + if (menu.Level > 0) + { + menus[menu.Level] = null; + } + menu.FadeOut(); + }); + } + + Menu CreateMenu(MenuData menuData, string title = null) + { + Menu menu = new Menu(); + if (title != null) + { + if (title == string.Empty) + { + title = Path.GetPathRoot(Config.Path); + } + + menu.SetTitle(title); + menu.UserClickedOpenFolder += OpenFolder; + void OpenFolder() + { + Process.Start("explorer.exe", Config.Path); + } + } + menu.Level = menuData.Level; + menu.MouseWheel += AdjustSubMenusLocationAndSize; + DataGridView dgv = menu.GetDataGridView(); + dgv.CellMouseEnter += Dgv_MouseEnter; + dgv.CellMouseLeave += Dgv_MouseLeave; + dgv.MouseDoubleClick += Dgv_MouseDoubleClick; + dgv.MouseDown += Dgv_MouseDown; + dgv.SelectionChanged += Dgv_SelectionChanged; + menu.KeyPress += KeyPress; + menu.CmdKeyProcessed += CmdKeyProcessed; + menu.Activated += Activated; + menu.Deactivated += fastLeave.Start; + menu.VisibleChanged += DisposeWhenHidden; + AddItemsToMenu(menuData.RowDatas, menu); + return menu; + } + + private void KeyPress(object sender, KeyPressEventArgs e) + { + if (char.IsLetterOrDigit(e.KeyChar) || + char.IsPunctuation(e.KeyChar) || + char.IsWhiteSpace(e.KeyChar) || + char.IsSeparator(e.KeyChar)) + { + string letter = e.KeyChar.ToString(); + + if (string.IsNullOrEmpty(keyInput)) + { + keyInput = letter; + Search(keyInput, true); + } + else if (keyInput.LastOrDefault().ToString() == letter) + { + keyInput += letter; + Search(letter, true); + timerKeySearch.Stop(); + } + else + { + keyInput += letter; + Search(keyInput, false); + timerKeySearch.Stop(); + } + timerKeySearch.Start(); + e.Handled = true; + } + } + + private void TimerKeySearch_Tick(object sender, EventArgs e) + { + timerKeySearch.Stop(); + //Search(keyInput); + keyInput = string.Empty; + } + +#warning better word than force + private void Search(string keyInput, bool force) + { + SelectByKey(Keys.None, keyInput, force); + } + + private void CmdKeyProcessed(Keys keys) + { + SelectByKey(keys); + } + + private bool IsAnyMenuSelectedByKey() + { + Menu menu = null; + DataGridView dgv = null; + string textselected = string.Empty; + return IsAnyMenuSelectedByKey(ref dgv, ref menu, ref textselected); + } + + private bool IsAnyMenuSelectedByKey( + ref DataGridView dgv, + ref Menu menuFromSelected, + ref string textselected) + { + Menu menu = menus[iMenuKey]; + bool isStillSelected = false; + if (menu != null && + iRowKey > -1) + { + dgv = menu.GetDataGridView(); + if (dgv.Rows.Count > iRowKey) + { + RowData rowData = (RowData)dgv. + Rows[iRowKey].Tag; + if (rowData.IsSelectedByKeyboard) + { + isStillSelected = true; + menuFromSelected = rowData.SubMenu; +#warning refactor datagridviewrow get + textselected = dgv.Rows[iRowKey]. + Cells[1].Value.ToString(); + } + } + } + + return isStillSelected; + } + + private void SelectByKey(Keys keys, string keyInput = "", + bool force = true) + { + int iRowBefore = iRowKey; + int iMenuBefore = iMenuKey; + + Menu menu = menus[iMenuKey]; + DataGridView dgv = null; + DataGridView dgvBefore = null; + Menu menuFromSelected = null; + string textselected = string.Empty; + bool isStillSelected = IsAnyMenuSelectedByKey( + ref dgv, ref menuFromSelected, ref textselected); + if (isStillSelected) + { + dgvBefore = dgv; + if (!force && + textselected.ToLower().StartsWith(keyInput.ToLower())) + { +#warning rewrite function should not return here + return; // is that ok? check twice + } + } + else + { + ResetSelectedByKey(); + menu = menus[iMenuKey]; + dgv = menu.GetDataGridView(); + } + + bool toClear = false; + switch (keys) + { + case Keys.Enter: + if (iRowKey > -1 && + dgv.Rows.Count > iRowKey) + { + RowData trigger = (RowData)dgv.Rows[iRowKey].Tag; + trigger.MouseDown(dgv, null); + //trigger.DoubleClick(); + } + break; + case Keys.Up: + FadeInIfNeeded(); + if (SelectMatchedReverse(dgv, iRowKey) || + SelectMatchedReverse(dgv, dgv.Rows.Count - 1)) + { + CheckMenuOpenerStop(iMenuBefore, iRowBefore, dgvBefore); + CheckMenuOpenerStart(dgv, iRowKey); + toClear = true; + } + break; + case Keys.Down: + FadeInIfNeeded(); + if (SelectMatched(dgv, iRowKey) || + SelectMatched(dgv, 0)) + { + CheckMenuOpenerStop(iMenuBefore, iRowBefore, dgvBefore); + CheckMenuOpenerStart(dgv, iRowKey); + toClear = true; + } + break; + case Keys.Left: + FadeInIfNeeded(); + int iMenuKeyNext = iMenuKey + 1; + if (isStillSelected) + { + if (menuFromSelected != null && + menuFromSelected == menus[iMenuKeyNext]) + { + dgv = menuFromSelected.GetDataGridView(); + if (dgv.Rows.Count > 0) + { + iMenuKey += 1; + iRowKey = -1; + if (SelectMatched(dgv, iRowKey) || + SelectMatched(dgv, 0)) + { + CheckMenuOpenerStop(iMenuBefore, + iRowBefore, dgvBefore); + CheckMenuOpenerStart(dgv, iRowKey); + toClear = true; + } + } + } + } + else + { + iRowKey = -1; + iMenuKey = menus.Where(m => m != null).Count() - 1; + if (menus[iMenuKey] != null) + { + dgv = menus[iMenuKey].GetDataGridView(); + if (SelectMatched(dgv, iRowKey) || + SelectMatched(dgv, 0)) + { + CheckMenuOpenerStop(iMenuBefore, iRowBefore, dgvBefore); + CheckMenuOpenerStart(dgv, iRowKey); + toClear = true; + } + } + else + { + log.Info("indexMenuByKey = menus.Where(m => m != null).Count()" + + "=> menus[iMenuKey] == null"); + } + } + break; + case Keys.Right: + if (iMenuKey > 0) + { + if (menus[iMenuKey - 1] != null) + { + iMenuKey -= 1; + iRowKey = -1; + menu = menus[iMenuKey]; + dgv = menu.GetDataGridView(); + if (SelectMatched(dgv, dgv.SelectedRows[0].Index) || + SelectMatched(dgv, 0)) + { + CheckMenuOpenerStop(iMenuBefore, iRowBefore, dgvBefore); + CheckMenuOpenerStart(dgv, iRowKey); + toClear = true; + } + } + } + else + { + CheckMenuOpenerStop(iMenuBefore, iRowBefore, dgvBefore); + iMenuKey = 0; + iRowKey = -1; + toClear = true; + FadeHalfOrOutIfNeeded(); + } + break; + case Keys.Escape: + CheckMenuOpenerStop(iMenuBefore, iRowBefore, dgvBefore); + iMenuKey = 0; + iRowKey = -1; + toClear = true; + isMainMenuOpen = false; + MenusFadeOut(); + break; + default: + if (!string.IsNullOrEmpty(keyInput) && + (SelectMatched(dgv, iRowKey, keyInput) || + SelectMatched(dgv, 0, keyInput))) + { + FadeInIfNeeded(); + CheckMenuOpenerStop(iMenuBefore, iRowBefore); + CheckMenuOpenerStart(dgv, iRowKey); + toClear = true; + } + break; + } + if (isStillSelected && toClear) + { + ClearIsSelectedByKey(iMenuBefore, + iRowBefore); + } + + } + + private bool SelectMatched(DataGridView dgv, + int indexStart, string keyInput = "") + { + bool found = false; + for (int i = indexStart; i < dgv.Rows.Count; i++) + { + if (Select(dgv, i, keyInput)) + { + found = true; + break; + } + } + return found; + } + + private bool SelectMatchedReverse(DataGridView dgv, + int indexStart, string keyInput = "") + { + bool found = false; + for (int i = indexStart; i > -1; i--) + { + if (Select(dgv, i, keyInput)) + { + found = true; + break; + } + } + return found; + } + + private bool Select(DataGridView dgv, int i, + string keyInput = "") + { + bool found = false; + if (i > -1 && + i != iRowKey && + dgv.Rows.Count > i) + { + DataGridViewRow row = dgv.Rows[i]; + RowData rowData = (RowData)row.Tag; + string text = row.Cells[1].Value.ToString(); + if (text.ToLower().StartsWith(keyInput.ToLower())) + { + iRowKey = rowData.RowIndex; + rowData.IsSelectedByKeyboard = true; + row.Selected = false; //event trigger + row.Selected = true; //event trigger + if (row.Index < dgv.FirstDisplayedScrollingRowIndex) + { + dgv.FirstDisplayedScrollingRowIndex = row.Index; + } + else if(row.Index >= + dgv.FirstDisplayedScrollingRowIndex + + dgv.DisplayedRowCount(false)) + { + dgv.FirstDisplayedScrollingRowIndex = row.Index - + dgv.DisplayedRowCount(false) + 1; + } + + found = true; + } + } + return found; + } + + private void ClearIsSelectedByKey(int menuIndex, int rowIndex) + { + Menu menu = menus[menuIndex]; + if (menu != null && rowIndex > -1) + { + DataGridView dgv = menu.GetDataGridView(); + if (dgv.Rows.Count > rowIndex) + { + DataGridViewRow row = dgv.Rows[rowIndex]; + RowData rowData = (RowData)row.Tag; + rowData.IsSelectedByKeyboard = false; + row.Selected = false; //event trigger + } + } + } + + private void AddItemsToMenu(List data, Menu menu) + { + foreach (RowData rowData in data) + { + CreateMenuRow(rowData, menu); + } + } + + private void CreateMenuRow(RowData rowData, Menu menu) + { + rowData.SetData(rowData, menu.GetDataGridView()); + rowData.OpenMenu += OpenSubMenu; + rowData.Reading.WorkerSupportsCancellation = true; + rowData.Reading.DoWork += ReadMenu_DoWork; + void ReadMenu_DoWork(object senderDoWork, + DoWorkEventArgs eDoWork) + { + int level = (int)eDoWork.Argument; + BackgroundWorker worker = (BackgroundWorker)senderDoWork; + rowData.RestartLoading = false; + eDoWork.Result = ReadMenu(worker, rowData.TargetFilePath, level); + } + + rowData.Reading.RunWorkerCompleted += ReadMenu_RunWorkerCompleted; + void ReadMenu_RunWorkerCompleted(object senderCompleted, + RunWorkerCompletedEventArgs e) + { + MenuData menuData = (MenuData)e.Result; + if (rowData.RestartLoading) + { + rowData.Reading.RunWorkerAsync(menuData.Level); + } + else + { + menuNotifyIcon.LoadingStop(); + menuNotifyIcon.LoadWait(); + if (menuData.Valid) + { + menu = CreateMenu(menuData); + if (menuData.RowDatas.Count > 0) + { + menu.SetTypeSub(); + } + else + { + menu.SetTypeEmpty(); + } + menu.Tag = rowData; + rowData.SubMenu = menu; + rowData.MenuLoaded(); + } + menuNotifyIcon.LoadStop(); + } + } + } + } + + class WindowsExplorerSort : IComparer + { + [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] + static extern int StrCmpLogicalW(String x, String y); + + public int Compare(string x, string y) + { + return StrCmpLogicalW(x, y); + } + } +} \ No newline at end of file diff --git a/app.config b/app.config new file mode 100644 index 0000000..c25b42e --- /dev/null +++ b/app.config @@ -0,0 +1,37 @@ + + + + +
+ + + + + + + + + + + + False + + + + + + + +