diff --git a/exeinfogui/NE/PanelNeAccelerators.xeto b/exeinfogui/NE/PanelNeAccelerators.xeto new file mode 100644 index 0000000..3a9b952 --- /dev/null +++ b/exeinfogui/NE/PanelNeAccelerators.xeto @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/exeinfogui/NE/PanelNeAccelerators.xeto.cs b/exeinfogui/NE/PanelNeAccelerators.xeto.cs new file mode 100644 index 0000000..9f01b84 --- /dev/null +++ b/exeinfogui/NE/PanelNeAccelerators.xeto.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Linq; +using Eto.Forms; +using Eto.Serialization.Xaml; + +namespace exeinfogui.NE +{ + public class PanelNeAccelerators : Panel + { + GridView grdAccelerators; + Label lblCodepage; + TextBox txtCodepage; + + public PanelNeAccelerators() + { + XamlReader.Load(this); + + grdAccelerators.Columns.Add(new GridColumn + { + DataCell = new TextBoxCell {Binding = Binding.Property(a => $"{a.Type}")}, + HeaderText = "Type" + }); + + grdAccelerators.Columns.Add(new GridColumn + { + DataCell = new TextBoxCell {Binding = Binding.Property(a => $"{a.Key}")}, + HeaderText = "Key" + }); + + grdAccelerators.Columns.Add(new GridColumn + { + DataCell = new TextBoxCell {Binding = Binding.Property(a => $"{a.Command}")}, + HeaderText = "Command" + }); + } + + public void Update(byte[] data, libexeinfo.NE.TargetOS targetOs) + { + grdAccelerators.DataStore = null; + List accelerators = new List(); + + if(targetOs == libexeinfo.NE.TargetOS.OS2) + { + libexeinfo.NE.Os2AcceleratorTable table = libexeinfo.NE.GetOs2Accelerators(data); + lblCodepage.Visible = true; + txtCodepage.Visible = true; + txtCodepage.Text = $"{table.CodePage}"; + accelerators.AddRange(table.Accelerators.Select(accel => new Accelerator + { + Type = $"{accel.Type}", + Key = $"{accel.Key}", + Command = accel.Command + })); + } + else + { + lblCodepage.Visible = false; + txtCodepage.Visible = false; + accelerators.AddRange(libexeinfo.NE.GetWinAccelerators(data) + .Select(accel => new Accelerator + { + Type = $"{accel.Flags}", + Key = $"{accel.Key}", + Command = accel.Command + })); + } + + if(accelerators.Count > 0) grdAccelerators.DataStore = accelerators; + } + + class Accelerator + { + public ushort Command; + public string Key; + public string Type; + } + } +} \ No newline at end of file diff --git a/exeinfogui/NE/TabNeResources.xeto.cs b/exeinfogui/NE/TabNeResources.xeto.cs index f7c5949..aa1f2ef 100644 --- a/exeinfogui/NE/TabNeResources.xeto.cs +++ b/exeinfogui/NE/TabNeResources.xeto.cs @@ -35,11 +35,12 @@ namespace exeinfogui.NE { public class TabNeResources : TabPage { + PanelNeAccelerators panelNeAccelerators; + PanelNeStrings panelNeStrings; + PanelWin16Version panelWin16Version; Panel pnlResource; TreeGridItemCollection treeData; TreeGridView treeResources; - PanelWin16Version panelWin16Version; - PanelNeStrings panelNeStrings; public TabNeResources() { @@ -51,9 +52,10 @@ namespace exeinfogui.NE treeResources.AllowMultipleSelection = false; treeResources.SelectionChanged += TreeResourcesOnSelectionChanged; - - panelWin16Version = new PanelWin16Version(); - panelNeStrings = new PanelNeStrings(); + + panelWin16Version = new PanelWin16Version(); + panelNeStrings = new PanelNeStrings(); + panelNeAccelerators = new PanelNeAccelerators(); } public void Update(IEnumerable resourceTypes, libexeinfo.NE.TargetOS os) @@ -93,7 +95,7 @@ namespace exeinfogui.NE } byte[] data = ((libexeinfo.NE.Resource)((TreeGridItem)treeResources.SelectedItem).Values[5]).data; - + switch(((TreeGridItem)treeResources.SelectedItem).Values[3]) { case "RT_VERSION": @@ -102,7 +104,16 @@ namespace exeinfogui.NE break; case "RT_STRING": pnlResource.Content = panelNeStrings; - panelNeStrings.Update(data, (libexeinfo.NE.TargetOS)((TreeGridItem)treeResources.SelectedItem).Values[4]); + panelNeStrings.Update(data, + (libexeinfo.NE.TargetOS)((TreeGridItem)treeResources.SelectedItem).Values[4]); + break; + case "RT_ACCELERATOR": + pnlResource.Content = panelNeAccelerators; + panelNeAccelerators.Update(data, libexeinfo.NE.TargetOS.Windows); + break; + case "RT_ACCELTABLE": + pnlResource.Content = panelNeAccelerators; + panelNeAccelerators.Update(data, libexeinfo.NE.TargetOS.OS2); break; default: pnlResource.Content = null; diff --git a/libexeinfo/NE/Accelerators.cs b/libexeinfo/NE/Accelerators.cs new file mode 100644 index 0000000..b6a4163 --- /dev/null +++ b/libexeinfo/NE/Accelerators.cs @@ -0,0 +1,331 @@ +// +// Accelerator.cs +// +// Author: +// Natalia Portillo +// +// Copyright (c) 2017 Copyright © Claunia.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +// ReSharper disable InconsistentNaming + +namespace libexeinfo +{ + public partial class NE + { + [Flags] + public enum Os2AcceleratorFlags : ushort + { + AF_CHAR = 0x0001, + AF_VIRTUALKEY = 0x0002, + AF_SCANCODE = 0x0004, + AF_SHIFT = 0x0008, + AF_CONTROL = 0x0010, + AF_ALT = 0x0020, + AF_LONEKEY = 0x0040, + AF_SYSCOMMAND = 0x0100, + AF_HELP = 0x0200 + } + + public enum Os2VirtualKey : ushort + { + VK_BUTTON1 = 0x01, + VK_BUTTON2 = 0x02, + VK_BUTTON3 = 0x03, + VK_BREAK = 0x04, + VK_BACKSPACE = 0x05, + VK_TAB = 0x06, + VK_BACKTAB = 0x07, + VK_NEWLINE = 0x08, + VK_SHIFT = 0x09, + VK_CTRL = 0x0A, + VK_ALT = 0x0B, + VK_ALTGRAF = 0x0C, + VK_PAUSE = 0x0D, + VK_CAPSLOCK = 0x0E, + VK_ESC = 0x0F, + VK_SPACE = 0x10, + VK_PAGEUP = 0x11, + VK_PAGEDOWN = 0x12, + VK_END = 0x13, + VK_HOME = 0x14, + VK_LEFT = 0x15, + VK_UP = 0x16, + VK_RIGHT = 0x17, + VK_DOWN = 0x18, + VK_PRINTSCRN = 0x19, + VK_INSERT = 0x1A, + VK_DELETE = 0x1B, + VK_SCRLLOCK = 0x1C, + VK_NUMLOCK = 0x1D, + VK_ENTER = 0x1E, + VK_SYSRQ = 0x1F, + VK_F1 = 0x20, + VK_F2 = 0x21, + VK_F3 = 0x22, + VK_F4 = 0x23, + VK_F5 = 0x24, + VK_F6 = 0x25, + VK_F7 = 0x26, + VK_F8 = 0x27, + VK_F9 = 0x28, + VK_F10 = 0x29, + VK_F11 = 0x2A, + VK_F12 = 0x2B, + VK_F13 = 0x2C, + VK_F14 = 0x2D, + VK_F15 = 0x2E, + VK_F16 = 0x2F, + VK_F17 = 0x30, + VK_F18 = 0x31, + VK_F19 = 0x32, + VK_F20 = 0x33, + VK_F21 = 0x34, + VK_F22 = 0x35, + VK_F23 = 0x36, + VK_F24 = 0x37 + } + + [Flags] + public enum WinAcceleratorFlags : byte + { + VirtualKey = 0x01, + NoInvert = 0x02, + Shift = 0x04, + Control = 0x08, + Alt = 0x10, + Last = 0x80 + } + + public enum WinVirtualKey : byte + { + VK_LBUTTON = 0x01, + VK_RBUTTON = 0x02, + VK_CANCEL = 0x03, + VK_MBUTTON = 0x04, + VK_BACK = 0x08, + VK_TAB = 0x09, + VK_CLEAR = 0x0C, + VK_RETURN = 0x0D, + VK_SHIFT = 0x10, + VK_CONTROL = 0x11, + VK_MENU = 0x12, + VK_PAUSE = 0x13, + VK_CAPITAL = 0x14, + VK_ESCAPE = 0x1B, + VK_SPACE = 0x20, + VK_PRIOR = 0x21, + VK_NEXT = 0x22, + VK_END = 0x23, + VK_HOME = 0x24, + VK_LEFT = 0x25, + VK_UP = 0x26, + VK_RIGHT = 0x27, + VK_DOWN = 0x28, + VK_SELECT = 0x29, + VK_PRINT = 0x2A, + VK_EXECUTE = 0x2B, + VK_SNAPSHOT = 0x2C, + VK_INSERT = 0x2D, + VK_DELETE = 0x2E, + VK_HELP = 0x2F, + VK_0 = 0x30, + VK_1 = 0x31, + VK_2 = 0x32, + VK_3 = 0x33, + VK_4 = 0x34, + VK_5 = 0x35, + VK_6 = 0x36, + VK_7 = 0x37, + VK_8 = 0x38, + VK_9 = 0x39, + VK_A = 0x41, + VK_B = 0x42, + VK_C = 0x43, + VK_D = 0x44, + VK_E = 0x45, + VK_F = 0x46, + VK_G = 0x47, + VK_H = 0x48, + VK_I = 0x49, + VK_J = 0x4A, + VK_K = 0x4B, + VK_L = 0x4C, + VK_M = 0x4D, + VK_N = 0x4E, + VK_O = 0x4F, + VK_P = 0x50, + VK_Q = 0x51, + VK_R = 0x52, + VK_S = 0x53, + VK_T = 0x54, + VK_U = 0x55, + VK_V = 0x56, + VK_W = 0x57, + VK_X = 0x58, + VK_Y = 0x59, + VK_Z = 0x5A, + VK_NUMPAD0 = 0x60, + VK_NUMPAD1 = 0x61, + VK_NUMPAD2 = 0x62, + VK_NUMPAD3 = 0x63, + VK_NUMPAD4 = 0x64, + VK_NUMPAD5 = 0x65, + VK_NUMPAD6 = 0x66, + VK_NUMPAD7 = 0x67, + VK_NUMPAD8 = 0x68, + VK_NUMPAD9 = 0x69, + VK_MULTIPLY = 0x6A, + VK_ADD = 0x6B, + VK_SEPARATOR = 0x6C, + VK_SUBTRACT = 0x6D, + VK_DECIMAL = 0x6E, + VK_DIVIDE = 0x6F, + VK_F1 = 0x70, + VK_F2 = 0x71, + VK_F3 = 0x72, + VK_F4 = 0x73, + VK_F5 = 0x74, + VK_F6 = 0x75, + VK_F7 = 0x76, + VK_F8 = 0x77, + VK_F9 = 0x78, + VK_F10 = 0x79, + VK_F11 = 0x7A, + VK_F12 = 0x7B, + VK_F13 = 0x7C, + VK_F14 = 0x7D, + VK_F15 = 0x7E, + VK_F16 = 0x7F, + VK_F17 = 0x80, + VK_F18 = 0x81, + VK_F19 = 0x82, + VK_F20 = 0x83, + VK_F21 = 0x84, + VK_F22 = 0x85, + VK_F23 = 0x86, + VK_F24 = 0x87, + VK_NUMLOCK = 0x90, + VK_SCROLL = 0x91 + } + + public static WinAccelerator[] GetWinAccelerators(byte[] data) + { + int pos = 0; + List accelerators = new List(); + + while(pos + 8 < data.Length) + { + byte[] accelBytes = new byte[Marshal.SizeOf(typeof(WinAccelerator))]; + Array.Copy(data, pos, accelBytes, 0, accelBytes.Length); + WinAccelerator accelerator = + BigEndianMarshal.ByteArrayToStructureLittleEndian(accelBytes); + + accelerators.Add(accelerator); + + if(accelerator.Flags.HasFlag(WinAcceleratorFlags.Last)) break; + + pos += accelBytes.Length; + } + + return accelerators.ToArray(); + } + + public static Os2AcceleratorTable GetOs2Accelerators(byte[] data) + { + int pos = 4; + Os2AcceleratorTable table = new Os2AcceleratorTable + { + Count = BitConverter.ToUInt16(data, 0), + CodePage = BitConverter.ToUInt16(data, 2) + }; + table.Accelerators = new Os2Accelerator[table.Count]; + + for(int i = 0; i < table.Count; i++) + { + byte[] accelBytes = new byte[Marshal.SizeOf(typeof(Os2Accelerator))]; + if(pos + accelBytes.Length > data.Length) break; + + table.Accelerators[i] = BigEndianMarshal.ByteArrayToStructureLittleEndian(accelBytes); + pos += accelBytes.Length; + } + + return table; + } + + public struct Os2AcceleratorTable + { + /// + /// How many accelerators are included in this table + /// + public ushort Count; + /// + /// Table's codepage + /// + public ushort CodePage; + /// + /// Array of accelerators + /// + public Os2Accelerator[] Accelerators; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct Os2Accelerator + { + /// + /// Accelerator type + /// + public Os2AcceleratorFlags Type; + /// + /// Accelerator key + /// + public Os2VirtualKey Key; + /// + /// Accelerator command + /// + public ushort Command; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct WinAccelerator + { + /// + /// Accelerator flags + /// + public WinAcceleratorFlags Flags; + /// + /// Accelerator key + /// + public WinVirtualKey Key; + /// + /// Padding + /// + public byte Padding; + /// + /// Accelerator command + /// + public byte Command; + } + } +} \ No newline at end of file diff --git a/libexeinfo/libexeinfo.csproj b/libexeinfo/libexeinfo.csproj index 4c9f932..69655d5 100644 --- a/libexeinfo/libexeinfo.csproj +++ b/libexeinfo/libexeinfo.csproj @@ -56,6 +56,7 @@ +