From d58d1f6e368b38f5f5806ca4a209cda2be16870c Mon Sep 17 00:00:00 2001 From: nerd Date: Sun, 1 Jan 2017 23:20:33 -0600 Subject: [PATCH 01/14] Added .NET Framework interoperability to the core and started a c# binding library --- .gitignore | 11 +- LsapiSharp.Test/LsapiSharp.Test.csproj | 139 ++++++ LsapiSharp.Test/LsapiSharpTest.cs | 355 +++++++++++++++ LsapiSharp.Test/Properties/AssemblyInfo.cs | 36 ++ LsapiSharp.Test/packages.config | 12 + LsapiSharp.Test/step.rc | 19 + LsapiSharp/LsapiSharp.csproj | 76 ++++ LsapiSharp/NativeMethods.cs | 333 ++++++++++++++ LsapiSharp/Properties/AssemblyInfo.cs | 10 + litestep.sln | 78 +++- litestep/CLRModule.cpp | 260 +++++++++++ litestep/CLRModule.h | 51 +++ litestep/Module.cpp | 402 +---------------- litestep/Module.h | 184 ++------ litestep/ModuleManager.cpp | 6 +- litestep/NativeModule.cpp | 417 ++++++++++++++++++ litestep/NativeModule.h | 153 +++++++ litestep/litestep.vcxproj | 15 +- lsapi/lsapi.vcxproj | 4 + lsapi/lsapiInit.cpp | 1 + lsapi/lsapidefines.h | 1 + sdk/examples/HelloCLR/App.config | 6 + sdk/examples/HelloCLR/HelloCLR.csproj | 74 ++++ sdk/examples/HelloCLR/LSModule.cs | 67 +++ .../HelloCLR/Properties/AssemblyInfo.cs | 36 ++ 25 files changed, 2203 insertions(+), 543 deletions(-) create mode 100644 LsapiSharp.Test/LsapiSharp.Test.csproj create mode 100644 LsapiSharp.Test/LsapiSharpTest.cs create mode 100644 LsapiSharp.Test/Properties/AssemblyInfo.cs create mode 100644 LsapiSharp.Test/packages.config create mode 100644 LsapiSharp.Test/step.rc create mode 100644 LsapiSharp/LsapiSharp.csproj create mode 100644 LsapiSharp/NativeMethods.cs create mode 100644 LsapiSharp/Properties/AssemblyInfo.cs create mode 100644 litestep/CLRModule.cpp create mode 100644 litestep/CLRModule.h create mode 100644 litestep/NativeModule.cpp create mode 100644 litestep/NativeModule.h create mode 100644 sdk/examples/HelloCLR/App.config create mode 100644 sdk/examples/HelloCLR/HelloCLR.csproj create mode 100644 sdk/examples/HelloCLR/LSModule.cs create mode 100644 sdk/examples/HelloCLR/Properties/AssemblyInfo.cs diff --git a/.gitignore b/.gitignore index 75c71d7..a8f95db 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,13 @@ -Release_* -Debug_* -*/Debug_* -*/Release_* +Release* +Debug* +*/Debug* +*/Release* *.user *.opensdf *.sdf *.suo *.ncb *.aps +.vs +*.VC* +packages \ No newline at end of file diff --git a/LsapiSharp.Test/LsapiSharp.Test.csproj b/LsapiSharp.Test/LsapiSharp.Test.csproj new file mode 100644 index 0000000..1b47bed --- /dev/null +++ b/LsapiSharp.Test/LsapiSharp.Test.csproj @@ -0,0 +1,139 @@ + + + + Debug + AnyCPU + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527} + Library + Properties + LsapiSharp.Test + LsapiSharp.Test + v4.6.1 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + x64 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + x64 + bin\x64\Debug\ + false + false + + + x64 + bin\x64\Release\ + false + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + false + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + false + + + + ..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll + True + + + + + + + + + + + + + + + + + + + + + + {7f8140dc-7815-4368-94f8-a7ed7cf04a2a} + LsapiSharp + + + + + Always + + + + + + + + + + False + + + False + + + False + + + False + + + + + + + + copy $(SolutionDir)bin\$(ConfigurationName)_$(PlatformName)\lsapi.dll $(TargetDir) + + + \ No newline at end of file diff --git a/LsapiSharp.Test/LsapiSharpTest.cs b/LsapiSharp.Test/LsapiSharpTest.cs new file mode 100644 index 0000000..9575db2 --- /dev/null +++ b/LsapiSharp.Test/LsapiSharpTest.cs @@ -0,0 +1,355 @@ +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// This is a part of the Litestep Shell source code. +// +// Copyright (C) 1997-2015 LiteStep Development Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +using System; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; + +using NUnit.Framework; + +using static LsapiSharp.NativeMethods; + +namespace LsapiSharp.Test +{ + [TestFixture] + [Author("Donelle Sanders Jr", "donelle@donellesandersjr.com")] + public class LsapiSharpTest + { + const int MAX_LINE_LENGTH = 4096; + const int MAX_COMMAND = 64; + + static string stepRCPath; + + [OneTimeSetUp()] + public static void Initialize() + { + var location = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + var initialized = LSAPIInitialize(location, stepRCPath = Path.Combine(location, "step.rc")); + Assert.IsTrue(initialized); + } + + [TestCase] + [Category("Configuration")] + public void LCOpen_LCClose_Test() + { + IntPtr hfile = LCOpen(null); + Assert.NotZero(hfile.ToInt64()); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void LCTokenize_Test() + { + const string LINE = "*Setting option1 option2 option3 option4 somemore stuff"; + + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + string[] tokens = new string[5]; + StringBuilder extraConfig = new StringBuilder(25); + + int len = Tokenize(LINE, tokens, extraConfig); + string extraParams = extraConfig.ToString(); + + Assert.AreEqual(tokens.Length, len); + Assert.AreEqual("*Setting", tokens[0]); + Assert.AreEqual("option1", tokens[1]); + Assert.AreEqual("option2", tokens[2]); + Assert.AreEqual("option3", tokens[3]); + Assert.AreEqual("option4", tokens[4]); + Assert.IsTrue(extraParams.StartsWith("somemore")); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void LCReadNextCommand_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + StringBuilder buffer = new StringBuilder(MAX_LINE_LENGTH); + bool retval = LCReadNextCommand(hfile, buffer, MAX_LINE_LENGTH); + string line = buffer.ToString(); + + Assert.IsTrue(retval); + Assert.NotZero(line.Length); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void LCReadNextConfig_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + StringBuilder buffer = new StringBuilder(MAX_LINE_LENGTH); + bool retval = LCReadNextConfig(hfile, "*Config", buffer, MAX_LINE_LENGTH); + Assert.IsTrue(retval); + + string line = buffer.ToString(); + string [] tokens = new string[4]; + int len = Tokenize(line, tokens); + + Assert.AreEqual(tokens.Length, len); + Assert.AreEqual("*Config", tokens[0]); + Assert.AreEqual("option1", tokens[1]); + Assert.AreEqual("option2", tokens[2]); + Assert.AreEqual("option3", tokens[3]); + + tokens = new string[2]; + + retval = LCReadNextConfig(hfile, "*Config", buffer, MAX_LINE_LENGTH); + Assert.IsTrue(retval); + + line = buffer.ToString(); + len = Tokenize(line, tokens); + + Assert.AreEqual(tokens.Length, len); + Assert.AreEqual("*Config", tokens[0]); + Assert.AreEqual("option1", tokens[1]); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void LCReadNextLine_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + StringBuilder buffer = new StringBuilder(MAX_LINE_LENGTH); + bool retval = LCReadNextLine(hfile, buffer, MAX_LINE_LENGTH); + string line = buffer.ToString(); + + Assert.IsTrue(retval); + Assert.NotZero(line.Length); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void GetRCInt_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + int retval = GetRCInt("VarB", 0); + Assert.AreEqual(15, retval); + + retval = GetRCInt("SomeSetting", 0); + Assert.AreEqual(0, retval); + + long retval64 = GetRCInt64("VarD", 0); + Assert.AreEqual(9223372036854775800L, retval64); + + retval64 = GetRCInt("SomeSetting", 0); + Assert.AreEqual(0, retval64); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void GetRCFloat_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + float retval = GetRCFloat("VarF", 0); + Assert.AreEqual(53.675f, retval); + + retval = GetRCFloat("SomeSetting", 0); + Assert.AreEqual(0, retval); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void GetRCDouble_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + double retval = GetRCDouble("VarG", 0); + Assert.AreEqual(1.7E+3d, retval); + + retval = GetRCFloat("SomeSetting", 0); + Assert.AreEqual(0, retval); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void GetRCBoolDef_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + bool retval = GetRCBoolDef("VarA", false); + Assert.IsTrue(retval); + + retval = GetRCBoolDef("VarH", false); + Assert.IsTrue(retval); + + retval = GetRCBoolDef("SomeSetting", false); + Assert.IsFalse(retval); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void GetRCBool_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + bool retval = GetRCBool("VarA", false); + Assert.IsFalse(retval); + + retval = GetRCBool("VarA", true); + Assert.IsTrue(retval); + + retval = GetRCBool("SomeSetting", false); + Assert.IsTrue(retval); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void GetRCString_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + StringBuilder buffer = new StringBuilder(MAX_COMMAND); + bool retval = GetRCString("VarC", buffer, "Test", MAX_COMMAND); + string rcVal = buffer.ToString(); + + Assert.IsTrue(retval); + Assert.AreEqual("Command3", rcVal); + + retval = GetRCString("SomeSetting", buffer, "Test", MAX_COMMAND); + rcVal = buffer.ToString(); + + Assert.IsFalse(retval); + Assert.AreEqual("Test", rcVal); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void GetRCLine_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + StringBuilder buffer = new StringBuilder(MAX_LINE_LENGTH); + bool retval = GetRCLine("*Script", buffer, MAX_LINE_LENGTH, null); + + Assert.IsTrue(retval); + + string[] tokens = new string[6]; + Tokenize(buffer.ToString(), tokens); + + Assert.AreEqual("exec", tokens[0]); + Assert.AreEqual("!LabelSetAlpha", tokens[1]); + Assert.AreEqual("Initialising", tokens[2]); + Assert.AreEqual("250", tokens[3]); + Assert.AreEqual("3", tokens[4]); + Assert.AreEqual("10", tokens[5]); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void GetRCColor_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + var defaultVal = new COLORREF(0); + COLORREF retval = GetRCColor("VarJ", defaultVal); + + Assert.AreEqual(70, retval.R); + Assert.AreEqual(130, retval.G); + Assert.AreEqual(180, retval.B); + Assert.AreEqual(11829830, retval.Value); + + retval = GetRCColor("SomethingElse", defaultVal); + + Assert.AreEqual(defaultVal.Value, retval.Value); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + private static int Tokenize(string line, string [] tokens, StringBuilder extra = null) + { + int intPtrSize = Marshal.SizeOf(typeof(IntPtr)); + IntPtr tokensPtr = Marshal.AllocHGlobal(intPtrSize * tokens.Length); + for (int i = 0; i < tokens.Length; i++) + { + IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(char)) * MAX_COMMAND); + Marshal.WriteIntPtr(tokensPtr, i * intPtrSize, ptr); + } + + int tokenLen = LCTokenize(line, tokensPtr, tokens.Length, extra); + + for (int i = 0; i < tokens.Length; i++) + { + IntPtr ptr = Marshal.ReadIntPtr(tokensPtr, i * intPtrSize); + tokens[i] = Marshal.PtrToStringUni(ptr); + Marshal.FreeHGlobal(ptr); + } + + return tokenLen; + } + } +} diff --git a/LsapiSharp.Test/Properties/AssemblyInfo.cs b/LsapiSharp.Test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..391cc6b --- /dev/null +++ b/LsapiSharp.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +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("LsapiSharp.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("LsapiSharp.Test")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[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("580b3cbe-9e12-41a2-b723-6ce9bbcb7527")] + +// 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("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/LsapiSharp.Test/packages.config b/LsapiSharp.Test/packages.config new file mode 100644 index 0000000..756e55e --- /dev/null +++ b/LsapiSharp.Test/packages.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/LsapiSharp.Test/step.rc b/LsapiSharp.Test/step.rc new file mode 100644 index 0000000..7211a6e --- /dev/null +++ b/LsapiSharp.Test/step.rc @@ -0,0 +1,19 @@ +; test configurations + +VarA TRUE +VarB 15 +VarC "Command3" +VarD 9223372036854775800 +VarF 53.675 +VarG 1.7E+3 +VarH 1 +VarJ 4682B4 + +; LCReadNextConfig test configurations + +*Config option1 option2 option3 +*Config option1 + +; GetRCLine test configurations + +*Script exec !LabelSetAlpha Initialising 250 3 10 \ No newline at end of file diff --git a/LsapiSharp/LsapiSharp.csproj b/LsapiSharp/LsapiSharp.csproj new file mode 100644 index 0000000..a84c4ba --- /dev/null +++ b/LsapiSharp/LsapiSharp.csproj @@ -0,0 +1,76 @@ + + + + + Debug + AnyCPU + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A} + Library + Properties + LsapiSharp + LsapiSharp + v2.0 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + x64 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + x64 + bin\x64\Debug\ + true + + + x64 + bin\x64\Release\ + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + prompt + MinimumRecommendedRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + prompt + MinimumRecommendedRules.ruleset + + + + + + + + + + + \ No newline at end of file diff --git a/LsapiSharp/NativeMethods.cs b/LsapiSharp/NativeMethods.cs new file mode 100644 index 0000000..3e98ef0 --- /dev/null +++ b/LsapiSharp/NativeMethods.cs @@ -0,0 +1,333 @@ +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// This is a part of the Litestep Shell source code. +// +// Copyright (C) 1997-2015 LiteStep Development Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +using System; +using System.Runtime.InteropServices; +using System.Text; + +[assembly: CLSCompliant(true)] + +namespace LsapiSharp +{ + public static class NativeMethods + { + private const string LSAPI = "lsapi.dll"; + + /// + /// Logging Level Error + /// + public const int LS_LOG_ERROR = 1; + + /// + /// Logging Level Warning + /// + public const int LS_LOG_WARNING = 2; + + /// + /// Logging Level Notice (Info) + /// + public const int LS_LOG_NOTICE = 3; + + /// + /// Logging Level Debug + /// + public const int LS_LOG_DEBUG = 4; + + /// + /// Win32 representation of DWORD value + /// + [StructLayout(LayoutKind.Explicit, Size = 4)] + public struct COLORREF + { + public COLORREF(byte r, byte g, byte b) + { + this.Value = 0; + this.R = r; + this.G = g; + this.B = b; + } + + public COLORREF(int value) + { + this.R = 0; + this.G = 0; + this.B = 0; + this.Value = value & 0x00FFFFFF; + } + + [FieldOffset(0)] + public byte R; + + [FieldOffset(1)] + public byte G; + + [FieldOffset(2)] + public byte B; + + [FieldOffset(0)] + public int Value; + } + + /// + /// Initializes the Litestep API which is the main entry point into library + /// + /// Litestep's working directory + /// Path to Litestep's configuration file + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern bool LSAPIInitialize(string litestepPath, string steprcPath); + + /// + /// Opens a configuration file for sequential access to its contents. + /// + /// + /// The file contents can be read with {@link #LCReadNextConfig} or {@link #LCReadNextLineOrCommand}. + /// The file should be closed with a call to {@link #LCClose} when it is no longer needed. + /// + /// If the argument is NULL, opens the global settings + /// for sequential access. + /// + /// Full path to the file to open + /// File handle on success or NULL if the file could not be opened + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern IntPtr LCOpen(string filePath); + + /// + /// Closes a configuration file opened with {@link #LCOpen}. + /// + /// A valid file handle reference + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern bool LCClose(IntPtr hFile); + + /// + /// Retrieves the next none config line (one that does not start with a '*' from a + /// configuration file. The entire line (including the setting name) is placed in the buffer. + /// + /// + /// Call this function repeatedly until it returns FALSE to retrieve all non config lines in the file. + /// + /// File handle returned by LCOpen + /// Buffer to receive line + /// Size of buffer + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern bool LCReadNextCommand(IntPtr hFile, StringBuilder buffer, int size); + + /// + /// Retrieves the next config line (one that starts with a '*') that begins with the + /// specified setting name from a configuration file. The entire line (including the setting name) + /// is placed in the buffer. + /// + /// + /// Call this function repeatedly until it returns FALSE to retrieve all the + /// lines that begin with the specified setting name. + /// + /// File handle returned by LCOpen + /// Setting name + /// Buffer to receive line + /// Size of buffer + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern bool LCReadNextConfig(IntPtr hFile, string config, StringBuilder buffer, int size); + + /// + /// Retrieves the next line from a configuration file. The entire line (including the setting name) is placed in the buffer. + /// + /// + /// Call this function repeatedly until it returns FALSE to retrieve all non config lines in the file. + /// + /// File handle returned by LCOpen + /// Buffer to receive line + /// Size of buffer + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern bool LCReadNextLine(IntPtr hFile, StringBuilder buffer, int size); + + /// + /// Parses and retrieves the values in a config line (one that starts with a '*') that begins with the + /// specified setting name from a configuration file. + /// + /// + /// Call this function repeatedly until it returns 0 to retrieve all config lines for the specified config name. + /// + /// Setting name + /// An array of buffers to receive the values + /// The number of tokens expected to retrieve + /// The remaining part of the config line that was not collected in the buffer + /// Returns the number of tokens found in the configuration line + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern int LCTokenize(string config, IntPtr tokens, int tokenLen, StringBuilder extraParams); + + /// + /// Retrieves an integer value from the global settings. Returns + /// if the setting does not exist. + /// + /// Setting name + /// Default value + /// The setting value or default value + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern int GetRCInt(string settingName, int defaultVal); + + /// + /// Retrieves an integer value from the global settings. Returns + /// if the setting does not exist. + /// + /// Setting name + /// Default value + /// The setting value or default value + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern long GetRCInt64(string settingName, long defaultVal); + + /// + /// Retrieves an integer value from the global settings. Returns + /// if the setting does not exist. + /// + /// Setting name + /// Default value + /// The setting value or default value + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern float GetRCFloat(string settingName, float defaultVal); + + /// + /// Retrieves an integer value from the global settings. Returns + /// if the setting does not exist. + /// + /// Setting name + /// Default value + /// The setting value or default value + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern double GetRCDouble(string settingName, double defaultVal); + + /// + /// Retrieves an integer value from the global settings. Returns + /// if the setting does not exist. + /// + /// Setting name + /// Default value + /// The setting value or default value + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern bool GetRCBoolDef(string settingName, bool defaultVal); + + /// + /// Retrieves a Boolean value from the global settings. Returns + /// if the setting exists and ! if it does not. + /// + /// Setting name + /// Value to return if setting is found + /// The setting value + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern bool GetRCBool(string settingName, bool ifFound); + + /// + /// Retrieves a string value from the global settings. Returns FALSE if + /// the setting does not exist copies into the buffer and returns + /// FALSE. may be null in which case + /// nothing is copied into the buffer. + /// + /// + /// The raw setting value is parsed and the first space-delimited token or quoted string is the value returned. + /// + /// Setting name + /// Buffer to receive value + /// Default value + /// Size of buffer + /// Returns true if it exists otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern bool GetRCString(string settingName, StringBuilder buffer, string defaultVal, int size); + + /// + /// Retrieves a raw string value from the global settings. If setting does not exist, copies + /// into the buffer and returns FALSE. may be null in which case + /// nothing is copied into the buffer. + /// + /// + /// GetRCLine does not parse the string value like GetRCString does. Its purpose is for retreiving command + /// lines for applications and bang commands. + /// + /// Setting name + /// Buffer to receive value + /// Size of buffer + /// Default value + /// TRUE if setting exists or FALSE otherwise + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern bool GetRCLine(string settingName, StringBuilder buffer, int size, string defaultVal); + + /// + /// Retrieves a color value from the global settings. Returns if the setting does not exist. + /// + /// Setting name + /// Default value + /// The setting value or default value + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern COLORREF GetRCColor(string settingsName, COLORREF defaultVal); + + /// + /// Bang command callback + /// + /// The window handle sent the command + /// The arguments associated with the command + /// + /// typedef void (__cdecl *BangCommandW)(HWND hSender, LPCWSTR pszArgs); + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public delegate void BangCommandDelegate(int hWndSender, string args); + + /// + /// Registers bang commands + /// + /// the command identifier that starts with an exclamation point (!) + /// the callback method associated with the command + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern bool AddBangCommand(string command, [MarshalAs(UnmanagedType.FunctionPtr)] BangCommandDelegate commandDelegate); + + /// + /// Removes a bang command from the list. + /// + /// bang command name + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern bool RemoveBangCommand(string command); + + /// + /// Self explanatory :-) + /// + /// The level to log to + /// The name of the module logging from + /// The content to write to file + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern bool LSLog(int level, string module, string message); + + /// + /// Self explanatory :-) + /// + /// The level to log to + /// The name of the module logging from + /// The formatting instructions + /// The values toreplace the tokens in the formatting instruction + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "LSLogPrintf")] + public static extern bool LSLog(int level, string module, string format, params object [] args); + } +} diff --git a/LsapiSharp/Properties/AssemblyInfo.cs b/LsapiSharp/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e13f53d --- /dev/null +++ b/LsapiSharp/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("LsapiSharp")] +[assembly: AssemblyDescription(".NET Framework Interop for Litestep")] +[assembly: AssemblyProduct("LsapiSharp")] +[assembly: AssemblyCopyright("Copyright © 2016 LiteStep Development Team")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/litestep.sln b/litestep.sln index f9c5fa9..1753167 100644 --- a/litestep.sln +++ b/litestep.sln @@ -1,6 +1,6 @@ -Microsoft Visual Studio Solution File, Format Version 14.00 -# Visual Studio 2015 -VisualStudioVersion = 14.0.22310.1 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 14.0.22310.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "litestep", "litestep\litestep.vcxproj", "{994556EE-2F21-4811-A85D-6925F7F84B0D}" EndProject @@ -110,43 +110,115 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{DEC29FCD-9 sdk\docs\lsapi\VarExpansionEx.xml = sdk\docs\lsapi\VarExpansionEx.xml EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{CF23F811-B9C1-4EAA-AB0E-8E5FE32AA968}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LsapiSharp", "LsapiSharp\LsapiSharp.csproj", "{7F8140DC-7815-4368-94F8-A7ED7CF04A2A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hello", "sdk\examples\hello\hello.vcxproj", "{CECF0543-6AEB-49CA-9B14-D64155631FE4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloCLR", "sdk\examples\HelloCLR\HelloCLR.csproj", "{2A700A3B-CEFB-488E-BC28-5679FB19712E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LsapiSharp.Test", "LsapiSharp.Test\LsapiSharp.Test.csproj", "{580B3CBE-9E12-41A2-B723-6CE9BBCB7527}" + ProjectSection(ProjectDependencies) = postProject + {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA} = {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA} + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CLR", "CLR", "{757E055D-EC8C-4038-B2F3-E6C978057563}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {994556EE-2F21-4811-A85D-6925F7F84B0D}.Debug|Any CPU.ActiveCfg = Debug|Win32 {994556EE-2F21-4811-A85D-6925F7F84B0D}.Debug|Win32.ActiveCfg = Debug|Win32 {994556EE-2F21-4811-A85D-6925F7F84B0D}.Debug|Win32.Build.0 = Debug|Win32 {994556EE-2F21-4811-A85D-6925F7F84B0D}.Debug|x64.ActiveCfg = Debug|x64 {994556EE-2F21-4811-A85D-6925F7F84B0D}.Debug|x64.Build.0 = Debug|x64 + {994556EE-2F21-4811-A85D-6925F7F84B0D}.Release|Any CPU.ActiveCfg = Release|Win32 {994556EE-2F21-4811-A85D-6925F7F84B0D}.Release|Win32.ActiveCfg = Release|Win32 {994556EE-2F21-4811-A85D-6925F7F84B0D}.Release|Win32.Build.0 = Release|Win32 {994556EE-2F21-4811-A85D-6925F7F84B0D}.Release|x64.ActiveCfg = Release|x64 {994556EE-2F21-4811-A85D-6925F7F84B0D}.Release|x64.Build.0 = Release|x64 + {2213036F-018C-416A-8A6A-7934C936CFFC}.Debug|Any CPU.ActiveCfg = Debug|Win32 {2213036F-018C-416A-8A6A-7934C936CFFC}.Debug|Win32.ActiveCfg = Debug|Win32 {2213036F-018C-416A-8A6A-7934C936CFFC}.Debug|Win32.Build.0 = Debug|Win32 {2213036F-018C-416A-8A6A-7934C936CFFC}.Debug|x64.ActiveCfg = Debug|x64 {2213036F-018C-416A-8A6A-7934C936CFFC}.Debug|x64.Build.0 = Debug|x64 + {2213036F-018C-416A-8A6A-7934C936CFFC}.Release|Any CPU.ActiveCfg = Release|Win32 {2213036F-018C-416A-8A6A-7934C936CFFC}.Release|Win32.ActiveCfg = Release|Win32 {2213036F-018C-416A-8A6A-7934C936CFFC}.Release|Win32.Build.0 = Release|Win32 {2213036F-018C-416A-8A6A-7934C936CFFC}.Release|x64.ActiveCfg = Release|x64 {2213036F-018C-416A-8A6A-7934C936CFFC}.Release|x64.Build.0 = Release|x64 + {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA}.Debug|Any CPU.ActiveCfg = Debug|Win32 {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA}.Debug|Win32.ActiveCfg = Debug|Win32 {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA}.Debug|Win32.Build.0 = Debug|Win32 {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA}.Debug|x64.ActiveCfg = Debug|x64 {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA}.Debug|x64.Build.0 = Debug|x64 + {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA}.Release|Any CPU.ActiveCfg = Release|Win32 {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA}.Release|Win32.ActiveCfg = Release|Win32 {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA}.Release|Win32.Build.0 = Release|Win32 {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA}.Release|x64.ActiveCfg = Release|x64 {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA}.Release|x64.Build.0 = Release|x64 + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Debug|Win32.ActiveCfg = Debug|x86 + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Debug|Win32.Build.0 = Debug|x86 + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Debug|x64.ActiveCfg = Debug|x64 + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Debug|x64.Build.0 = Debug|x64 + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|Any CPU.Build.0 = Release|Any CPU + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|Win32.ActiveCfg = Release|Any CPU + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|Win32.Build.0 = Release|Any CPU + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|x64.ActiveCfg = Release|Any CPU + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|x64.Build.0 = Release|Any CPU + {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Debug|Win32.ActiveCfg = Debug|Win32 + {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Debug|Win32.Build.0 = Debug|Win32 + {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Debug|x64.ActiveCfg = Debug|Win32 + {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Release|Any CPU.ActiveCfg = Release|Win32 + {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Release|Win32.ActiveCfg = Release|Win32 + {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Release|Win32.Build.0 = Release|Win32 + {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Release|x64.ActiveCfg = Release|Win32 + {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Debug|Win32.ActiveCfg = Debug|x86 + {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Debug|Win32.Build.0 = Debug|x86 + {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Debug|x64.ActiveCfg = Debug|x64 + {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Debug|x64.Build.0 = Debug|x64 + {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Release|Any CPU.Build.0 = Release|Any CPU + {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Release|Win32.ActiveCfg = Release|Any CPU + {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Release|Win32.Build.0 = Release|Any CPU + {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Release|x64.ActiveCfg = Release|Any CPU + {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Release|x64.Build.0 = Release|Any CPU + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|Any CPU.Build.0 = Debug|Any CPU + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|Win32.ActiveCfg = Debug|x86 + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|Win32.Build.0 = Debug|x86 + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|x64.ActiveCfg = Debug|x64 + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|x64.Build.0 = Debug|x64 + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|Any CPU.ActiveCfg = Release|Any CPU + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|Any CPU.Build.0 = Release|Any CPU + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|Win32.ActiveCfg = Release|Any CPU + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|Win32.Build.0 = Release|Any CPU + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|x64.ActiveCfg = Release|Any CPU + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {DEC29FCD-986F-4AAB-A697-AE091EFEF71A} = {0CB7B995-8934-4494-8EB9-968D5407C6E5} + {CF23F811-B9C1-4EAA-AB0E-8E5FE32AA968} = {0CB7B995-8934-4494-8EB9-968D5407C6E5} + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A} = {757E055D-EC8C-4038-B2F3-E6C978057563} + {CECF0543-6AEB-49CA-9B14-D64155631FE4} = {CF23F811-B9C1-4EAA-AB0E-8E5FE32AA968} + {2A700A3B-CEFB-488E-BC28-5679FB19712E} = {CF23F811-B9C1-4EAA-AB0E-8E5FE32AA968} + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527} = {757E055D-EC8C-4038-B2F3-E6C978057563} EndGlobalSection EndGlobal diff --git a/litestep/CLRModule.cpp b/litestep/CLRModule.cpp new file mode 100644 index 0000000..a70a19d --- /dev/null +++ b/litestep/CLRModule.cpp @@ -0,0 +1,260 @@ +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// This is a part of the Litestep Shell source code. +// +// Copyright (C) 1997-2015 LiteStep Development Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +#include "CLRModule.h" +#include +#include "../utility/core.hpp" + +#import "mscorlib.tlb" raw_interfaces_only \ + high_property_prefixes("_get","_put","_putref") \ + rename("ReportEvent", "InteropServices_ReportEvent") +using namespace mscorlib; + + +CLRModule::CLRModule(const std::wstring& sLocation, DWORD dwFlags) + : Module(sLocation, dwFlags) +{ + m_pCorRuntimeHost = nullptr; + m_pMetaHost = nullptr; + m_pRuntimeInfo = nullptr; +} + + +CLRModule::~CLRModule() +{ + _Dispose(); +} + + +bool CLRModule::Init(HWND hMainWindow, const std::wstring& sAppPath) +{ + HRESULT hr = E_FAIL; + + if (_Initialize()) + { + SAFEARRAY *args = SafeArrayCreateVector(VT_VARIANT, 0, 2); + variant_t vtWndArg, vtAppPathArg(sAppPath.c_str()); + + do { + LONG index = 0; + + V_VT(&vtWndArg) = VT_INT; + vtWndArg.byref = hMainWindow; + hr = SafeArrayPutElement(args, &index, &vtWndArg); + if (FAILED(hr)) + { + break; + } + + index = 1; + hr = SafeArrayPutElement(args, &index, &vtAppPathArg); + if (FAILED(hr)) + { + break; + } + + hr = _InvokeMethod(L"initModule", args); + } while (false); + + SafeArrayDestroy(args); + args = nullptr; + } + + return SUCCEEDED(hr); +} + + +void CLRModule::Quit() +{ + SAFEARRAY * args = SafeArrayCreateVector(VT_VARIANT, 0, 0); + + _InvokeMethod(L"quitModule", args); + _Dispose(); + + SafeArrayDestroy(args); + args = nullptr; +} + + +HINSTANCE CLRModule::GetInstance() const +{ + return HINSTANCE(); +} + + +bool CLRModule::_Initialize() +{ + static const WCHAR DEFAULT_CLRVERSION[] = L"v2.0.50727"; + + HRESULT hr; + + do { + hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&m_pMetaHost)); + if (FAILED(hr)) + { + LSLogPrintf(LOG_ERROR, "CLRModule", "CLRCreateInstance failed w/hr 0x%08lx\n", hr); + break; + } + + wchar_t clrVersion[MAX_PATH]; + GetRCStringW(L"LSCLRVersion", clrVersion, DEFAULT_CLRVERSION, MAX_PATH); + + hr = m_pMetaHost->GetRuntime(clrVersion, IID_PPV_ARGS(&m_pRuntimeInfo)); + if (FAILED(hr)) + { + LSLogPrintf(LOG_ERROR, "CLRModule", "ICLRMetaHost::GetRuntime failed w/hr 0x%08lx\n", hr); + break; + } + + BOOL fLoadable; + hr = m_pRuntimeInfo->IsLoadable(&fLoadable); + if (FAILED(hr)) + { + LSLogPrintf(LOG_ERROR, "CLRModule", "ICLRRuntimeInfo::IsLoadable failed w/hr 0x%08lx\n", hr); + break; + } + + if (!fLoadable) + { + LSLogPrintf(LOG_ERROR, "CLRModule", ".NET runtime %s cannot be loaded\n", clrVersion); + break; + } + + hr = m_pRuntimeInfo->GetInterface(CLSID_CorRuntimeHost, IID_PPV_ARGS(&m_pCorRuntimeHost)); + if (FAILED(hr)) + { + LSLogPrintf(LOG_ERROR, "CLRModule", "ICLRRuntimeInfo::GetInterface failed w/hr 0x%08lx\n", hr); + break; + } + + hr = m_pCorRuntimeHost->Start(); + if (FAILED(hr)) + { + LSLogPrintf(LOG_ERROR, "CLRModule", "CLR failed to start w/hr 0x%08lx\n", hr); + break; + } + } while (false); + + // + // If we fail for any reason then cleanup + // + if (FAILED(hr)) + { + _Dispose(); + } + + return m_pCorRuntimeHost != nullptr; +} + + +void CLRModule::_Dispose() +{ + if (m_pMetaHost) + { + m_pMetaHost->Release(); + m_pMetaHost = NULL; + } + + if (m_pRuntimeInfo) + { + m_pRuntimeInfo->Release(); + m_pRuntimeInfo = NULL; + } + + if (m_pCorRuntimeHost) + { + m_pCorRuntimeHost->Release(); + m_pCorRuntimeHost = NULL; + } +} + + +HRESULT CLRModule::_InvokeMethod(LPCWSTR szMethodName, SAFEARRAY * pArgs) +{ + HRESULT hr; + + IUnknownPtr pAppDomainThunk = NULL; + _AppDomainPtr pDefaultAppDomain = NULL; + + do { + hr = m_pCorRuntimeHost->GetDefaultDomain(&pAppDomainThunk); + if (FAILED(hr)) + { + LSLogPrintf(LOG_ERROR, "CLRModule", "ICorRuntimeHost::GetDefaultDomain failed w/hr 0x%08lx\n", hr); + break; + } + + hr = pAppDomainThunk->QueryInterface(IID_PPV_ARGS(&pDefaultAppDomain)); + if (FAILED(hr)) + { + LSLogPrintf(LOG_ERROR, "CLRModule", "Failed to get default AppDomain w/hr 0x%08lx\n", hr); + break; + } + + __wchar_t * location = (__wchar_t *) malloc(sizeof(__wchar_t) * MAX_PATH_LENGTH); + ZeroMemory(location, sizeof(__wchar_t) * MAX_PATH_LENGTH); + StringCchCopy(location, MAX_PATH, GetLocation()); + + __wchar_t * classlibrary = PathFindFileName(location); + PathRemoveExtension(classlibrary); + + bstr_t bstrAssemblyName(classlibrary); + _AssemblyPtr pAssembly = NULL; + free(location); + + hr = pDefaultAppDomain->Load_2(bstrAssemblyName, &pAssembly); + if (FAILED(hr)) + { + LSLogPrintf(LOG_ERROR, "CLRModule", "Failed to load the assembly w/hr 0x%08lx\n", hr); + break; + } + + // Get the Type of ClassLibrary.LSModule + bstr_t bstrClassName(bstrAssemblyName + L".LSModule"); + _TypePtr pType = NULL; + + hr = pAssembly->GetType_2(bstrClassName, &pType); + if (FAILED(hr)) + { + LSLogPrintf(LOG_ERROR, "CLRModule", "Failed to get the Type interface w/hr 0x%08lx\n", hr); + break; + } + + bstr_t bstrStaticMethodName(szMethodName); + variant_t vtEmpty, vtRetVal; + + try { + hr = pType->InvokeMember_3(bstrStaticMethodName, static_cast( + BindingFlags_InvokeMethod | BindingFlags_Static | BindingFlags_Public), + NULL, vtEmpty, pArgs, &vtRetVal); + if (FAILED(hr)) + { + LSLogPrintf(LOG_ERROR, "CLRModule", "Failed to invoke %s w/hr 0x%08lx\n", szMethodName, hr); + } + } + catch (...) { + LSLogPrintf(LOG_ERROR, "CLRModule", "A fatal error occured invoking %s\n", szMethodName); + } + + } while (false); + + return hr; +} \ No newline at end of file diff --git a/litestep/CLRModule.h b/litestep/CLRModule.h new file mode 100644 index 0000000..c016493 --- /dev/null +++ b/litestep/CLRModule.h @@ -0,0 +1,51 @@ +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// This is a part of the Litestep Shell source code. +// +// Copyright (C) 1997-2015 LiteStep Development Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +#if !defined(CLRMODULE_H) +#define CLRMODULE_H + +#include "Module.h" +#include + +#include + +class CLRModule : public Module +{ +private: + ICorRuntimeHost *m_pCorRuntimeHost; + ICLRMetaHost *m_pMetaHost; + ICLRRuntimeInfo *m_pRuntimeInfo; + +public: + CLRModule(const std::wstring& sLocation, DWORD dwFlags); + ~CLRModule(); + + bool Init(HWND hMainWindow, const std::wstring& sAppPath); + void Quit(); + HINSTANCE GetInstance() const; + +private: + bool _Initialize(); + void _Dispose(); + HRESULT _InvokeMethod(LPCWSTR szMethodName, SAFEARRAY * pArgs); +}; + +#endif \ No newline at end of file diff --git a/litestep/Module.cpp b/litestep/Module.cpp index 6e842bf..22435b8 100755 --- a/litestep/Module.cpp +++ b/litestep/Module.cpp @@ -19,401 +19,13 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -#include "module.h" -#include "../lsapi/ThreadedBangCommand.h" -#include "../utility/macros.h" -#include "../utility/core.hpp" -#include "../utility/stringutility.h" +#include "CLRModule.h" +#include "NativeModule.h" -#include - - -Module::Module(const std::wstring& sLocation, DWORD dwFlags) -{ - m_hInstance = nullptr; - m_hThread = nullptr; - m_pInit = nullptr; - m_hInitEvent = nullptr; - m_hInitCopyEvent = nullptr; - m_pQuit = nullptr; - m_dwFlags = dwFlags; - m_dwLoadTime = 0; - m_wzLocation = sLocation; -} - - -static WORD GetModuleArchitecture(LPCWSTR wzModuleName) -{ - WORD wRet = 0; - HANDLE hFile = CreateFileW(wzModuleName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (hFile != INVALID_HANDLE_VALUE) - { - HANDLE hFileMapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL); - if (hFileMapping != nullptr) - { - LPVOID lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0); - if (lpFileBase != nullptr) - { - PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpFileBase; - PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((LPBYTE)pDosHeader + pDosHeader->e_lfanew); - wRet = pNTHeader->OptionalHeader.Magic; - UnmapViewOfFile(lpFileBase); - } - CloseHandle(hFileMapping); - } - CloseHandle(hFile); - } - return wRet; -} - - -// -// This is a workaround because Microsofts std::function implementation is bugged -// -template -void AssignToFunction(std::function &func, T* value) -{ - if (value == nullptr) - { - func = nullptr; - } - else - { - func = value; - } -} - - -bool Module::_LoadDll() -{ - bool bReturn = false; - - if (!m_hInstance) - { - // Modules like popup2 like to call SetErrorMode. While that may not be - // good style, there is little we can do about it. However, LoadLibrary - // usually produces helpful error messages such as - // "msvcp70.dll not found" which are not displayed if a module has - // disabled them via SetErrorMode. We force their display here. - // First, make Windows display all errors - UINT uOldMode = SetErrorMode(0); - - if ((m_hInstance = LoadLibraryW(m_wzLocation.c_str())) != nullptr) - { - AssignToFunction(m_pInit, (initModuleProc) GetProcAddress( - m_hInstance, "initModuleW")); - - if (!m_pInit) // Might be a legacy module, check for initModuleEx - { - initModuleProcA pInit = (initModuleProcA)GetProcAddress( - m_hInstance, "initModuleEx"); - - if (!pInit) // Might be a BC module, check for underscore - { - pInit = (initModuleProcA)GetProcAddress( - m_hInstance, "_initModuleEx"); - } - - if (pInit) - { - m_pInit = [pInit] (HWND hWnd, HINSTANCE hInst, LPCWSTR pwzPath) -> int { - char szPath[MAX_PATH]; - WideCharToMultiByte(CP_ACP, 0, pwzPath, -1, - szPath, sizeof(szPath), "", nullptr); - return pInit(hWnd, hInst, szPath); - }; - } - } - - m_pQuit = (quitModuleProc)GetProcAddress( - m_hInstance, "quitModule"); - - if (!m_pQuit) // Might be a BC module, check for underscore - { - m_pQuit = (quitModuleProc)GetProcAddress( - m_hInstance, "_quitModule"); - } - - if (m_pInit == nullptr) - { - RESOURCE_STR(nullptr, IDS_INITMODULEEXNOTFOUND_ERROR, - L"Error: Could not find initModule().\n" - L"\n" - L"Please confirm that the dll is a LiteStep module,\n" - L"and check with the author for updates."); - } - else if (m_pQuit == nullptr) - { - RESOURCE_STR(nullptr, IDS_QUITMODULENOTFOUND_ERROR, - L"Error: Could not find quitModule().\n" - L"\n" - L"Please confirm that the dll is a LiteStep module."); - } - else - { - bReturn = true; - } - } - else - { - HRESULT hrError = HrGetLastError(); - -#if defined(_WIN64) - if (GetModuleArchitecture(m_wzLocation.c_str()) == IMAGE_NT_OPTIONAL_HDR32_MAGIC) - { - RESOURCE_STR(nullptr, IDS_MODULEWRONGARCH64_ERROR, - L"Error: Could not load module.\n" - L"\n" - L"The module seems to compiled for 32-bit LiteStep. This is a 64-bit version of LiteStep, which can only load 64-bit modules."); - } -#else - if (GetModuleArchitecture(m_wzLocation.c_str()) == IMAGE_NT_OPTIONAL_HDR64_MAGIC) - { - RESOURCE_STR(nullptr, IDS_MODULEWRONGARCH32_ERROR, - L"Error: Could not load module.\n" - L"\n" - L"The module seems to compiled for 64-bit LiteStep. This is a 32-bit version of LiteStep, which can only load 32-bit modules."); - } -#endif - else if (PathFileExistsW(m_wzLocation.c_str())) - { - RESOURCE_STR(nullptr, IDS_MODULEDEPENDENCY_ERROR, - L"Error: Could not load module.\n" - L"\n" - L"This is likely a case of a missing C Run-Time Library" - L"or other dependency." - L"\n" - L"Error Information:" - L"\n"); - - size_t nLen = 0; - StringCchLengthW(resourceTextBuffer, _countof(resourceTextBuffer), &nLen); - DescriptionFromHR(hrError, resourceTextBuffer + nLen, _countof(resourceTextBuffer) - nLen); - } - else - { - RESOURCE_STR(nullptr, IDS_MODULENOTFOUND_ERROR, - L"Error: Could not locate module.\n" - L"\n" - L"Please check your configuration."); - } - } - - // Second, restore the old state - SetErrorMode(uOldMode); - - if (!bReturn) - { - LPCWSTR pwzFileName = PathFindFileNameW(m_wzLocation.c_str()); - - RESOURCE_MSGBOX_F(pwzFileName, MB_ICONERROR); - - if (m_hInstance) - { - FreeLibrary(m_hInstance); - m_hInstance = nullptr; - } - } - } - - return bReturn; -} - - -Module::~Module() -{ - if (m_dwFlags & LS_MODULE_THREADED) - { - // Note: - // - This is problematic because these handles may currently - // be used in _WaitForModules(), and by closing the handle - // here before it is done being used, we may cause invalid - // behavior of that function, with potential lockups. - // - The solution within our current structure, is to allow - // an external procedure to take ownership of these handles. - // Meaning, whoever calls _WaitForModules would be required - // to free these objects when done with them, instead of us - // releasing them here. (See: TakeThread() TakeInitEvent()) - // - The correct solution is re-writing our module threading - // behavior, which we will be doing on the trunk code. - if (m_hInitEvent) - { - CloseHandle(m_hInitEvent); - m_hInitEvent = NULL; - } - - if (m_hThread) - { - CloseHandle(m_hThread); - m_hThread = NULL; - } - } - - if (m_hInstance) - { - FreeLibrary(m_hInstance); - m_hInstance = NULL; - } -} - - -bool Module::Init(HWND hMainWindow, const std::wstring& sAppPath) -{ - ASSERT(NULL == m_hInstance); - - DWORD dwStartTime = 0; - __int64 iStartTime, iEndTime, iFrequency; - bool bResult = false; - - if (QueryPerformanceCounter((LARGE_INTEGER*)&iStartTime) == FALSE) - { - dwStartTime = GetTickCount(); - } - - // delaying the LoadLibrary call until this point is necessary to make - // grdtransparent work (it hooks LoadLibrary) - if (_LoadDll()) - { - ASSERT(nullptr != m_pInit); - ASSERT(nullptr != m_pQuit); - - m_hMainWindow = hMainWindow; - m_wzAppPath = sAppPath; - - if (m_dwFlags & LS_MODULE_THREADED) - { - SECURITY_ATTRIBUTES sa; - - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = nullptr; - sa.bInheritHandle = FALSE; - - m_hInitCopyEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); - m_hInitEvent = m_hInitCopyEvent; - // using _beginthreadex instead of CreateThread because modules - // might use CRT functions - m_hThread = (HANDLE)_beginthreadex(&sa, 0, Module::ThreadProc, - this, 0, (UINT*)&m_dwThreadID); - bResult = true; - } - else - { - bResult = CallInit() == 0; - } - - if (QueryPerformanceCounter((LARGE_INTEGER*)&iEndTime) == FALSE || - QueryPerformanceFrequency((LARGE_INTEGER*)&iFrequency) == FALSE) - { - m_dwLoadTime = GetTickCount() - dwStartTime; - } - else - { - m_dwLoadTime = (DWORD)((iEndTime - iStartTime)*1000/iFrequency); - } - } - - return bResult; -} - - -int Module::CallInit() -{ - ASSERT(m_pInit != nullptr); - return m_pInit(m_hMainWindow, m_hInstance, m_wzAppPath.c_str()); -} - - -void Module::CallQuit() -{ - ASSERT(m_pQuit != NULL); - m_pQuit(m_hInstance); -} - - -void Module::Quit() -{ - if (m_hInstance) - { - if (m_dwFlags & LS_MODULE_THREADED) - { - PostThreadMessage(m_dwThreadID, WM_DESTROY, 0, (LPARAM)this); - } - else - { - CallQuit(); - } - } -} - - -UINT __stdcall Module::ThreadProc(void* dllModPtr) -{ - Module* dllMod = (Module*)dllModPtr; - -#if defined(MSVC_DEBUG) - LPCTSTR pszFileName = PathFindFileName(dllMod->m_wzLocation.c_str()); - DbgSetCurrentThreadName(WCSTOMBS(pszFileName)); -#endif - - dllMod->CallInit(); - - // We must use a copy of our event, and hope no one has closed it before - // waiting for it to be signaled. See: TakeThread() member function. - SetEvent(dllMod->m_hInitCopyEvent); - - MSG msg; - - while (GetMessage(&msg, 0, 0, 0) > 0) - { - if (msg.hwnd == NULL) - { - // Thread message - HandleThreadMessage(msg); - } - else - { - // Window message - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - return 0; -} - - -void Module::HandleThreadMessage(MSG &msg) +Module * Module::CreateInstance(const std::wstring & sLocation, DWORD dwFlags) { - switch (msg.message) - { - case LM_THREAD_BANGCOMMAND: - { - ThreadedBangCommand * pInfo = (ThreadedBangCommand*)msg.wParam; - - if (pInfo != NULL) - { - pInfo->Execute(); - pInfo->Release(); //check BangCommand.cpp for the reason - } - } - break; - - case WM_DESTROY: - { - Module *dll_mod = (Module*)msg.lParam; - - if (dll_mod) - { - dll_mod->CallQuit(); - PostQuitMessage(0); - } - } - break; - - default: - { - // do nothing - } - break; - } + if (dwFlags & LS_MODULE_CLR) + return new CLRModule(sLocation, dwFlags); + + return new NativeModule(sLocation, dwFlags); } diff --git a/litestep/Module.h b/litestep/Module.h index eae2a3e..bec12e3 100755 --- a/litestep/Module.h +++ b/litestep/Module.h @@ -25,8 +25,6 @@ #include "../lsapi/lsapidefines.h" #include "../utility/common.h" #include -#include - /** * Dynamically-loadable module. @@ -34,41 +32,20 @@ class Module { private: - /** Instance handle of module's DLL */ - HINSTANCE m_hInstance; - - /** Thread handle */ - HANDLE m_hThread; - - /** LiteStep's main window handle */ - HWND m_hMainWindow; - - /** Thread ID */ - DWORD m_dwThreadID; - - /** Path to module's DLL */ - std::basic_string m_wzLocation; + /** Flags used to load module */ + DWORD m_dwFlags; - /** Path to LiteStep's root directory */ - std::basic_string m_wzAppPath; + /** Path to module's DLL */ + std::basic_string m_wzLocation; - /** Pointer to initModuleEx function */ - std::function m_pInit; + /** The amount of time it took to load the module */ + DWORD m_dwLoadTime; - /** Pointer to quitModule function */ - quitModuleProc m_pQuit; - - /** Flags used to load module */ - DWORD m_dwFlags; - - /** The amount of time it took to load the module */ - DWORD m_dwLoadTime; - - /** - * Event that is triggered when a threaded module completes initialization - */ - HANDLE m_hInitEvent; - HANDLE m_hInitCopyEvent; +protected: + void SetLoadTime(DWORD dwLoadTime) + { + m_dwLoadTime = dwLoadTime; + } public: /** @@ -77,12 +54,12 @@ class Module * @param sLocation path to the module's DLL * @param dwFlags set of flags that control how the module is loaded */ - Module(const std::wstring& sLocation, DWORD dwFlags); - - /** - * Destructor. - */ - virtual ~Module(); + Module(const std::wstring& sLocation, DWORD dwFlags) + { + m_wzLocation = sLocation; + m_dwFlags = dwFlags; + m_dwLoadTime = 0; + } /** * Loads and initializes the module. If the module is loaded in its own @@ -95,47 +72,26 @@ class Module * @param sAppPath path to LiteStep's root directory * @return true if successful or false otherwise */ - bool Init(HWND hMainWindow, const std::wstring& sAppPath); + virtual bool Init(HWND hMainWindow, const std::wstring& sAppPath) = 0; /** * Shuts down the module and unloads it. If the module was loaded in its * own thread then shutdown is done asynchronously. Use event handle * returned by GetQuitEvent to wait for shutdown to complete. */ - void Quit(); - - /** - * Entry point for the module's main thread. - * - * @param dllModPtr pointer to this - * @return unused - */ - static UINT __stdcall ThreadProc(void* dllModPtr); - - /** - * Handles messages sent to the module's main thread. - * - * @param msg message information - */ - static void HandleThreadMessage(MSG &msg); + virtual void Quit() = 0; /** * Returns this module's DLL instance handle. */ - HINSTANCE GetInstance() const - { - return m_hInstance; - } + virtual HINSTANCE GetInstance() const = 0; /** * Returns this module's thread handle. Returns NULL if the * module was not loaded in its own thread. */ - HANDLE GetThread() const - { - return m_hThread; - } - + virtual HANDLE GetThread() const { return nullptr; } + /** * Returns this module's thread handle. Returns NULL if the * module was not loaded in its own thread. @@ -143,21 +99,12 @@ class Module * Caller is responsible for calling CloseHandle() on the return value. * Caller must NOT call CloseHandle() until the thread has an exit signal. */ - HANDLE TakeThread() - { - HANDLE hTemp = m_hThread; - m_hThread = nullptr; - - return hTemp; - } - + virtual HANDLE TakeThread() { return nullptr; }; + /** * Returns an event that is set once this module has been initialized. */ - HANDLE GetInitEvent() const - { - return m_hInitEvent; - } + virtual HANDLE GetInitEvent() const { return nullptr; } /** * Returns an event that is set once this module has been initialized. @@ -166,21 +113,7 @@ class Module * Caller must NOT call CloseHandle() until the event has been set to * signaled. */ - HANDLE TakeInitEvent() - { - HANDLE hTemp = m_hInitEvent; - m_hInitEvent = nullptr; - - return hTemp; - } - - /** - * Returns the path to this module's DLL. - */ - LPCWSTR GetLocation() const - { - return m_wzLocation.c_str(); - } + virtual HANDLE TakeInitEvent() { return nullptr; } /** * Returns the set of flags used to load this module. @@ -190,51 +123,26 @@ class Module return m_dwFlags; } - /** - * Returns how long this module took to load. - */ - DWORD GetLoadTime() const - { - return m_dwLoadTime; - } - - /** - * Returns a pointer to this module's quitModule function. - */ - decltype(m_pQuit) GetQuit() const - { - return m_pQuit; - } - - /** - * Returns a pointer to this module's initModuleEx function. - */ - decltype(m_pInit) GetInit() const - { - return m_pInit; - } - -private: - /** - * Loads this module's DLL. - * - * @return true if successful or - * false if an error occurs - */ - bool _LoadDll(); - - /** - * Calls this module's initModuleEx function. - * - * @return return value from initModuleEx - */ - int CallInit(); - - /** - * Calls this module's quitModule function. - */ - void CallQuit(); + /** + * Returns the path to this module's DLL. + */ + LPCWCHAR GetLocation() const + { + return m_wzLocation.c_str(); + } + + /** + * Returns how long this module took to load. + */ + DWORD GetLoadTime() const + { + return m_dwLoadTime; + } + + /** + * Module factory + */ + static Module * CreateInstance(const std::wstring& sLocation, DWORD dwFlags); }; - #endif // MODULE_H diff --git a/litestep/ModuleManager.cpp b/litestep/ModuleManager.cpp index 537cc43..b45e876 100755 --- a/litestep/ModuleManager.cpp +++ b/litestep/ModuleManager.cpp @@ -152,6 +152,10 @@ UINT ModuleManager::_LoadModules() { dwFlags |= LS_MODULE_THREADED; } + else if (_wcsicmp(wzToken2, L"clr") == 0) + { + dwFlags |= LS_MODULE_CLR; + } Module* pModule = _MakeModule(wzToken1, dwFlags); @@ -189,7 +193,7 @@ BOOL ModuleManager::LoadModule(LPCWSTR pwzLocation, DWORD dwFlags) Module* ModuleManager::_MakeModule(LPCWSTR pwzLocation, DWORD dwFlags) { - return new Module(pwzLocation, dwFlags); + return Module::CreateInstance(pwzLocation, dwFlags); } diff --git a/litestep/NativeModule.cpp b/litestep/NativeModule.cpp new file mode 100644 index 0000000..316395b --- /dev/null +++ b/litestep/NativeModule.cpp @@ -0,0 +1,417 @@ +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// This is a part of the Litestep Shell source code. +// +// Copyright (C) 1997-2015 LiteStep Development Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#include "NativeModule.h" +#include "../lsapi/ThreadedBangCommand.h" +#include "../utility/macros.h" +#include "../utility/core.hpp" +#include "../utility/stringutility.h" + +#include + +static WORD GetModuleArchitecture(LPCWSTR wzModuleName) +{ + WORD wRet = 0; + HANDLE hFile = CreateFileW(wzModuleName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (hFile != INVALID_HANDLE_VALUE) + { + HANDLE hFileMapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if (hFileMapping != nullptr) + { + LPVOID lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0); + if (lpFileBase != nullptr) + { + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpFileBase; + PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((LPBYTE)pDosHeader + pDosHeader->e_lfanew); + wRet = pNTHeader->OptionalHeader.Magic; + UnmapViewOfFile(lpFileBase); + } + CloseHandle(hFileMapping); + } + CloseHandle(hFile); + } + return wRet; +} + + +// +// This is a workaround because Microsofts std::function implementation is bugged +// +template +void AssignToFunction(std::function &func, T* value) +{ + if (value == nullptr) + { + func = nullptr; + } + else + { + func = value; + } +} + + +NativeModule::NativeModule(const std::wstring& sLocation, DWORD dwFlags) + : Module(sLocation, dwFlags) +{ + m_hInstance = nullptr; + m_hThread = nullptr; + m_pInit = nullptr; + m_hInitEvent = nullptr; + m_hInitCopyEvent = nullptr; + m_pQuit = nullptr; +} + + +NativeModule::~NativeModule() +{ + if (GetFlags() & LS_MODULE_THREADED) + { + // Note: + // - This is problematic because these handles may currently + // be used in _WaitForModules(), and by closing the handle + // here before it is done being used, we may cause invalid + // behavior of that function, with potential lockups. + // - The solution within our current structure, is to allow + // an external procedure to take ownership of these handles. + // Meaning, whoever calls _WaitForModules would be required + // to free these objects when done with them, instead of us + // releasing them here. (See: TakeThread() TakeInitEvent()) + // - The correct solution is re-writing our module threading + // behavior, which we will be doing on the trunk code. + if (m_hInitEvent) + { + CloseHandle(m_hInitEvent); + m_hInitEvent = NULL; + } + + if (m_hThread) + { + CloseHandle(m_hThread); + m_hThread = NULL; + } + } + + if (m_hInstance) + { + FreeLibrary(m_hInstance); + m_hInstance = NULL; + } +} + +bool NativeModule::Init(HWND hMainWindow, const std::wstring& sAppPath) +{ + ASSERT(NULL == m_hInstance); + + DWORD dwStartTime = 0; + __int64 iStartTime, iEndTime, iFrequency; + bool bResult = false; + + if (QueryPerformanceCounter((LARGE_INTEGER*)&iStartTime) == FALSE) + { + dwStartTime = GetTickCount(); + } + + // delaying the LoadLibrary call until this point is necessary to make + // grdtransparent work (it hooks LoadLibrary) + if (_LoadDll()) + { + ASSERT(nullptr != m_pInit); + ASSERT(nullptr != m_pQuit); + + m_hMainWindow = hMainWindow; + m_wzAppPath = sAppPath; + + if (GetFlags() & LS_MODULE_THREADED) + { + SECURITY_ATTRIBUTES sa; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = nullptr; + sa.bInheritHandle = FALSE; + + m_hInitCopyEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); + m_hInitEvent = m_hInitCopyEvent; + // using _beginthreadex instead of CreateThread because modules + // might use CRT functions + m_hThread = (HANDLE)_beginthreadex(&sa, 0, NativeModule::ThreadProc, + this, 0, (UINT*)&m_dwThreadID); + bResult = true; + } + else + { + bResult = _CallInit() == 0; + } + + if (QueryPerformanceCounter((LARGE_INTEGER*)&iEndTime) == FALSE || + QueryPerformanceFrequency((LARGE_INTEGER*)&iFrequency) == FALSE) + { + SetLoadTime(GetTickCount() - dwStartTime); + } + else + { + SetLoadTime((DWORD)((iEndTime - iStartTime) * 1000 / iFrequency)); + } + } + + return bResult; +} + + +void NativeModule::Quit() +{ + if (m_hInstance) + { + if (GetFlags() & LS_MODULE_THREADED) + { + PostThreadMessage(m_dwThreadID, WM_DESTROY, 0, (LPARAM)this); + } + else + { + _CallQuit(); + } + } +} + + +bool NativeModule::_LoadDll() +{ + bool bReturn = false; + + if (!m_hInstance) + { + // Modules like popup2 like to call SetErrorMode. While that may not be + // good style, there is little we can do about it. However, LoadLibrary + // usually produces helpful error messages such as + // "msvcp70.dll not found" which are not displayed if a module has + // disabled them via SetErrorMode. We force their display here. + // First, make Windows display all errors + UINT uOldMode = SetErrorMode(0); + + if ((m_hInstance = LoadLibraryW(GetLocation())) != nullptr) + { + AssignToFunction(m_pInit, (initModuleProc)GetProcAddress( + m_hInstance, "initModuleW")); + + if (!m_pInit) // Might be a legacy module, check for initModuleEx + { + initModuleProcA pInit = (initModuleProcA)GetProcAddress( + m_hInstance, "initModuleEx"); + + if (!pInit) // Might be a BC module, check for underscore + { + pInit = (initModuleProcA)GetProcAddress( + m_hInstance, "_initModuleEx"); + } + + if (pInit) + { + m_pInit = [pInit](HWND hWnd, HINSTANCE hInst, LPCWSTR pwzPath) -> int { + char szPath[MAX_PATH]; + WideCharToMultiByte(CP_ACP, 0, pwzPath, -1, + szPath, sizeof(szPath), "", nullptr); + return pInit(hWnd, hInst, szPath); + }; + } + } + + m_pQuit = (quitModuleProc)GetProcAddress( + m_hInstance, "quitModule"); + + if (!m_pQuit) // Might be a BC module, check for underscore + { + m_pQuit = (quitModuleProc)GetProcAddress( + m_hInstance, "_quitModule"); + } + + if (m_pInit == nullptr) + { + RESOURCE_STR(nullptr, IDS_INITMODULEEXNOTFOUND_ERROR, + L"Error: Could not find initModule().\n" + L"\n" + L"Please confirm that the dll is a LiteStep module,\n" + L"and check with the author for updates."); + } + else if (m_pQuit == nullptr) + { + RESOURCE_STR(nullptr, IDS_QUITMODULENOTFOUND_ERROR, + L"Error: Could not find quitModule().\n" + L"\n" + L"Please confirm that the dll is a LiteStep module."); + } + else + { + bReturn = true; + } + } + else + { + HRESULT hrError = HrGetLastError(); + +#if defined(_WIN64) + if (GetModuleArchitecture(GetLocation()) == IMAGE_NT_OPTIONAL_HDR32_MAGIC) + { + RESOURCE_STR(nullptr, IDS_MODULEWRONGARCH64_ERROR, + L"Error: Could not load module.\n" + L"\n" + L"The module seems to compiled for 32-bit LiteStep. This is a 64-bit version of LiteStep, which can only load 64-bit modules."); + } +#else + if (GetModuleArchitecture(GetLocation()) == IMAGE_NT_OPTIONAL_HDR64_MAGIC) + { + RESOURCE_STR(nullptr, IDS_MODULEWRONGARCH32_ERROR, + L"Error: Could not load module.\n" + L"\n" + L"The module seems to compiled for 64-bit LiteStep. This is a 32-bit version of LiteStep, which can only load 32-bit modules."); + } +#endif + else if (PathFileExistsW(GetLocation())) + { + RESOURCE_STR(nullptr, IDS_MODULEDEPENDENCY_ERROR, + L"Error: Could not load module.\n" + L"\n" + L"This is likely a case of a missing C Run-Time Library" + L"or other dependency." + L"\n" + L"Error Information:" + L"\n"); + + size_t nLen = 0; + StringCchLengthW(resourceTextBuffer, _countof(resourceTextBuffer), &nLen); + DescriptionFromHR(hrError, resourceTextBuffer + nLen, _countof(resourceTextBuffer) - nLen); + } + else + { + RESOURCE_STR(nullptr, IDS_MODULENOTFOUND_ERROR, + L"Error: Could not locate module.\n" + L"\n" + L"Please check your configuration."); + } + } + + // Second, restore the old state + SetErrorMode(uOldMode); + + if (!bReturn) + { + LPCWSTR pwzFileName = PathFindFileNameW(GetLocation()); + + RESOURCE_MSGBOX_F(pwzFileName, MB_ICONERROR); + + if (m_hInstance) + { + FreeLibrary(m_hInstance); + m_hInstance = nullptr; + } + } + } + + return bReturn; +} + + +int NativeModule::_CallInit() +{ + ASSERT(m_pInit != nullptr); + return m_pInit(m_hMainWindow, m_hInstance, m_wzAppPath.c_str()); +} + + +void NativeModule::_CallQuit() +{ + ASSERT(m_pQuit != NULL); + m_pQuit(m_hInstance); +} + + + +UINT __stdcall NativeModule::ThreadProc(void* dllModPtr) +{ + NativeModule* dllMod = (NativeModule*)dllModPtr; + +#if defined(MSVC_DEBUG) + LPCTSTR pszFileName = PathFindFileName(dllMod->GetLocation()); + DbgSetCurrentThreadName(WCSTOMBS(pszFileName)); +#endif + + dllMod->_CallInit(); + + // We must use a copy of our event, and hope no one has closed it before + // waiting for it to be signaled. See: TakeThread() member function. + SetEvent(dllMod->m_hInitCopyEvent); + + MSG msg; + + while (GetMessage(&msg, 0, 0, 0) > 0) + { + if (msg.hwnd == NULL) + { + // Thread message + HandleThreadMessage(msg); + } + else + { + // Window message + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + return 0; +} + + +void NativeModule::HandleThreadMessage(MSG &msg) +{ + switch (msg.message) + { + case LM_THREAD_BANGCOMMAND: + { + ThreadedBangCommand * pInfo = (ThreadedBangCommand*)msg.wParam; + + if (pInfo != NULL) + { + pInfo->Execute(); + pInfo->Release(); //check BangCommand.cpp for the reason + } + } + break; + + case WM_DESTROY: + { + NativeModule *dll_mod = (NativeModule*)msg.lParam; + + if (dll_mod) + { + dll_mod->_CallQuit(); + PostQuitMessage(0); + } + } + break; + + default: + { + // do nothing + } + break; + } +} diff --git a/litestep/NativeModule.h b/litestep/NativeModule.h new file mode 100644 index 0000000..5d0991d --- /dev/null +++ b/litestep/NativeModule.h @@ -0,0 +1,153 @@ +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// This is a part of the Litestep Shell source code. +// +// Copyright (C) 1997-2015 LiteStep Development Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +#if !defined(NATIVE_MODULE_H) +#define NATIVE_MODULE_H + +#include "Module.h" +#include + +class NativeModule : public Module +{ +private: + /** Instance handle of module's DLL */ + HINSTANCE m_hInstance; + + /** Thread handle */ + HANDLE m_hThread; + + /** LiteStep's main window handle */ + HWND m_hMainWindow; + + /** Thread ID */ + DWORD m_dwThreadID; + + /** Path to LiteStep's root directory */ + std::basic_string m_wzAppPath; + + /** Pointer to initModuleEx function */ + std::function m_pInit; + + /** Pointer to quitModule function */ + quitModuleProc m_pQuit; + + /** + * Event that is triggered when a threaded module completes initialization + */ + HANDLE m_hInitEvent; + HANDLE m_hInitCopyEvent; + +public: + NativeModule(const std::wstring& sLocation, DWORD dwFlags); + virtual ~NativeModule(); + + + bool Init(HWND hMainWindow, const std::wstring& sAppPath); + + void Quit(); + + HINSTANCE GetInstance() const + { + return m_hInstance; + } + + HANDLE GetThread() const + { + return m_hThread; + } + + HANDLE TakeThread() + { + HANDLE hTemp = m_hThread; + m_hThread = nullptr; + + return hTemp; + } + + HANDLE GetInitEvent() const + { + return m_hInitEvent; + } + + HANDLE TakeInitEvent() + { + HANDLE hTemp = m_hInitEvent; + m_hInitEvent = nullptr; + + return hTemp; + } + + + /** + * Returns a pointer to this module's quitModule function. + */ + decltype(m_pQuit) GetQuit() const + { + return m_pQuit; + } + + /** + * Returns a pointer to this module's initModuleEx function. + */ + decltype(m_pInit) GetInit() const + { + return m_pInit; + } + + /** + * Entry point for the module's main thread. + * + * @param dllModPtr pointer to this + * @return unused + */ + static UINT __stdcall ThreadProc(void* dllModPtr); + + /** + * Handles messages sent to the module's main thread. + * + * @param msg message information + */ + static void HandleThreadMessage(MSG &msg); + +private: + /** + * Loads this module's DLL. + * + * @return true if successful or + * false if an error occurs + */ + bool _LoadDll(); + + /** + * Calls this module's initModuleEx function. + * + * @return return value from initModuleEx + */ + int _CallInit(); + + /** + * Calls this module's quitModule function. + */ + void _CallQuit(); + +}; + +#endif \ No newline at end of file diff --git a/litestep/litestep.vcxproj b/litestep/litestep.vcxproj index 8972b19..29197a9 100644 --- a/litestep/litestep.vcxproj +++ b/litestep/litestep.vcxproj @@ -23,6 +23,7 @@ {994556EE-2F21-4811-A85D-6925F7F84B0D} litestep Win32Proj + "Windows" @@ -63,12 +64,17 @@ + + $(LibraryPath) + $(SolutionDir)bin\$(Configuration)_$(PlatformTarget) + LSAPI_PRIVATE;%(PreprocessorDefinitions) + false - advapi32.lib;gdi32.lib;ole32.lib;shell32.lib;shlwapi.lib;userenv.lib;uuid.lib;%(AdditionalDependencies) + advapi32.lib;gdi32.lib;ole32.lib;oleaut32.lib;shell32.lib;shlwapi.lib;userenv.lib;uuid.lib;mscoree.lib;comsuppw.lib;%(AdditionalDependencies) PerMonitorHighDPIAware @@ -77,9 +83,10 @@ LSAPI_PRIVATE;%(PreprocessorDefinitions) + false - advapi32.lib;gdi32.lib;ole32.lib;shell32.lib;shlwapi.lib;userenv.lib;uuid.lib;%(AdditionalDependencies) + advapi32.lib;gdi32.lib;ole32.lib;oleaut32.lib;shell32.lib;shlwapi.lib;userenv.lib;uuid.lib;mscoree.lib;comsuppw.lib;%(AdditionalDependencies) PerMonitorHighDPIAware @@ -108,6 +115,7 @@ + @@ -121,6 +129,7 @@ + @@ -132,6 +141,7 @@ + @@ -146,6 +156,7 @@ + diff --git a/lsapi/lsapi.vcxproj b/lsapi/lsapi.vcxproj index c9d6408..97d89ef 100644 --- a/lsapi/lsapi.vcxproj +++ b/lsapi/lsapi.vcxproj @@ -23,6 +23,7 @@ {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA} lsapi Win32Proj + "Windows" @@ -63,6 +64,9 @@ + + $(SolutionDir)bin\$(Configuration)_$(PlatformTarget)\ + LSAPI_INTERNAL;LSAPI_PRIVATE;%(PreprocessorDefinitions) diff --git a/lsapi/lsapiInit.cpp b/lsapi/lsapiInit.cpp index e65af87..006fe7d 100755 --- a/lsapi/lsapiInit.cpp +++ b/lsapi/lsapiInit.cpp @@ -254,6 +254,7 @@ void LSAPIInit::setLitestepVars() { WINVER_WIN7, L"Win7" }, { WINVER_WIN8, L"Win8" }, { WINVER_WIN81, L"Win81" }, + { WINVER_WIN10, L"Win10" }, { WINVER_WIN2003, L"Win2003" }, { WINVER_WHS, L"Win2003" }, // WHS is Win2003 in disguise diff --git a/lsapi/lsapidefines.h b/lsapi/lsapidefines.h index 1837747..7eabcf8 100755 --- a/lsapi/lsapidefines.h +++ b/lsapi/lsapidefines.h @@ -326,6 +326,7 @@ typedef struct LSDESKTOPINFO // ELD_MODULES: possible dwFlags values #define LS_MODULE_THREADED 0x0001 // LS_MODULE_NOTPUMPED 0x0002 no longer used +#define LS_MODULE_CLR 0x0003 typedef BOOL (CALLBACK* LSENUMBANGSPROCA)(LPCSTR, LPARAM); typedef BOOL (CALLBACK* LSENUMBANGSPROCW)(LPCWSTR, LPARAM); diff --git a/sdk/examples/HelloCLR/App.config b/sdk/examples/HelloCLR/App.config new file mode 100644 index 0000000..e74de46 --- /dev/null +++ b/sdk/examples/HelloCLR/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/sdk/examples/HelloCLR/HelloCLR.csproj b/sdk/examples/HelloCLR/HelloCLR.csproj new file mode 100644 index 0000000..b073ca9 --- /dev/null +++ b/sdk/examples/HelloCLR/HelloCLR.csproj @@ -0,0 +1,74 @@ + + + + + Debug + AnyCPU + {2A700A3B-CEFB-488E-BC28-5679FB19712E} + Library + Properties + HelloCLR + HelloCLR + v2.0 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + x64 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + x64 + bin\x64\Debug\ + + + x64 + bin\x64\Release\ + + + x86 + bin\x86\Debug\ + + + x86 + bin\x86\Release\ + + + + + + + + + + + {7f8140dc-7815-4368-94f8-a7ed7cf04a2a} + LsapiSharp + + + + + + + + \ No newline at end of file diff --git a/sdk/examples/HelloCLR/LSModule.cs b/sdk/examples/HelloCLR/LSModule.cs new file mode 100644 index 0000000..3cf5d5e --- /dev/null +++ b/sdk/examples/HelloCLR/LSModule.cs @@ -0,0 +1,67 @@ +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +// +// This is a part of the Litestep Shell source code. +// +// Copyright (C) 1997-2015 LiteStep Development Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +using System; +using System.Runtime.InteropServices; +using static LsapiSharp.NativeMethods; + +namespace HelloCLR +{ + public static class LSModule + { + const string BANG_COMMAND = "!HelloClr"; + + // Implements the !Hello bang command + static BangCommandDelegate BangHello = (sender, cmd) => + { + LSLog(LS_LOG_DEBUG, typeof(LSModule).FullName, "BangHello called"); + MessageBox(IntPtr.Zero, "Hello, Litestep!", typeof(LSModule).FullName, 0); + }; + + /// + /// Litestep calls this function after it loads the module. This is where the + /// module should register bang commands and create windows. If initialization + /// succeeds, return zero. If an error occurs, return a nonzero value. + /// + /// + /// + public static void initModule(Int32 hWndMain, String appPath) + { + LSLog(LS_LOG_DEBUG, typeof(LSModule).FullName, "initModule called"); + AddBangCommand(BANG_COMMAND, BangHello); + } + + /// + /// Litestep calls this function before it unloads the module. This function + /// should unregister bang commands and destroy windows. + /// + public static void quitModule() + { + LSLog(LS_LOG_DEBUG, typeof(LSModule).FullName, "quitModule called"); + RemoveBangCommand(BANG_COMMAND); + } + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + static extern int MessageBox(IntPtr hWnd, String text, String caption, int options); + } + +} diff --git a/sdk/examples/HelloCLR/Properties/AssemblyInfo.cs b/sdk/examples/HelloCLR/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..860b618 --- /dev/null +++ b/sdk/examples/HelloCLR/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +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("HelloCLR")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("HelloCLR")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[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("2a700a3b-cefb-488e-bc28-5679fb19712e")] + +// 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("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] From 18fbf7af5b6be50cf485c777322f2110a836d8cf Mon Sep 17 00:00:00 2001 From: nerd Date: Mon, 9 Jan 2017 00:08:24 -0600 Subject: [PATCH 02/14] Added more lsapi pinvokes to lsapi# along with unit tests --- LsapiSharp.Test/LsapiSharpTest.cs | 305 ++++++++++++++++++-- LsapiSharp.Test/step.rc | 6 +- LsapiSharp/NativeMethods.cs | 457 +++++++++++++++++++++++++++++- litestep.sln | 29 -- 4 files changed, 727 insertions(+), 70 deletions(-) diff --git a/LsapiSharp.Test/LsapiSharpTest.cs b/LsapiSharp.Test/LsapiSharpTest.cs index 9575db2..f224618 100644 --- a/LsapiSharp.Test/LsapiSharpTest.cs +++ b/LsapiSharp.Test/LsapiSharpTest.cs @@ -34,8 +34,9 @@ namespace LsapiSharp.Test { [TestFixture] [Author("Donelle Sanders Jr", "donelle@donellesandersjr.com")] - public class LsapiSharpTest + public class LsapiSharpTest { + const int MAX_PATH = 256; const int MAX_LINE_LENGTH = 4096; const int MAX_COMMAND = 64; @@ -66,13 +67,10 @@ public void LCTokenize_Test() { const string LINE = "*Setting option1 option2 option3 option4 somemore stuff"; - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - string[] tokens = new string[5]; StringBuilder extraConfig = new StringBuilder(25); - int len = Tokenize(LINE, tokens, extraConfig); + int len = Tokenize(LCTokenize, LINE, tokens, extraConfig); string extraParams = extraConfig.ToString(); Assert.AreEqual(tokens.Length, len); @@ -82,9 +80,55 @@ public void LCTokenize_Test() Assert.AreEqual("option3", tokens[3]); Assert.AreEqual("option4", tokens[4]); Assert.IsTrue(extraParams.StartsWith("somemore")); + } - var closed = LCClose(hfile); - Assert.IsTrue(closed); + [TestCase] + [Category("Configuration")] + public void CommandTokenize_Test() + { + const string LINE = "*Setting !commandA [!command1][!command2] somemore stuff"; + + string[] tokens = new string[4]; + StringBuilder extraConfig = new StringBuilder(25); + + int len = Tokenize(CommandTokenize, LINE, tokens, extraConfig); + string extraParams = extraConfig.ToString(); + + Assert.AreEqual(tokens.Length, len); + Assert.AreEqual("*Setting", tokens[0]); + Assert.AreEqual("!commandA", tokens[1]); + Assert.AreEqual("!command1", tokens[2]); + Assert.AreEqual("!command2", tokens[3]); + Assert.IsTrue(extraParams.StartsWith("somemore")); + } + + [TestCase] + [Category("Configuration")] + public void CommandParse_Test() + { + string line = "[!command1][!command2][!command3 !command4]"; + + string cmd = "!command1"; + StringBuilder cmdbuffer = new StringBuilder(cmd.Length + 1), + argbuffer = new StringBuilder(line.Length + 1); + + CommandParse(line, cmdbuffer, argbuffer, cmdbuffer.Capacity, argbuffer.Capacity); + Assert.AreEqual(cmd, cmdbuffer.ToString()); + + line = argbuffer.ToString(); + cmd = "!command2"; + cmdbuffer = new StringBuilder(cmd.Length + 1); + argbuffer = new StringBuilder(line.Length + 1); + + CommandParse(line, cmdbuffer, argbuffer, cmdbuffer.Capacity, argbuffer.Capacity); + Assert.AreEqual(cmd, cmdbuffer.ToString()); + + line = argbuffer.ToString(); + cmd = "!command3 !command4"; + cmdbuffer = new StringBuilder(cmd.Length + 1); + + CommandParse(line, cmdbuffer, null, cmdbuffer.Capacity, 0); + Assert.AreEqual(cmd, cmdbuffer.ToString()); } [TestCase] @@ -95,12 +139,12 @@ public void LCReadNextCommand_Test() Assert.AreNotEqual(0, hfile.ToInt64()); StringBuilder buffer = new StringBuilder(MAX_LINE_LENGTH); - bool retval = LCReadNextCommand(hfile, buffer, MAX_LINE_LENGTH); + bool retval = LCReadNextCommand(hfile, buffer, buffer.Capacity); string line = buffer.ToString(); Assert.IsTrue(retval); Assert.NotZero(line.Length); - + var closed = LCClose(hfile); Assert.IsTrue(closed); } @@ -113,12 +157,12 @@ public void LCReadNextConfig_Test() Assert.AreNotEqual(0, hfile.ToInt64()); StringBuilder buffer = new StringBuilder(MAX_LINE_LENGTH); - bool retval = LCReadNextConfig(hfile, "*Config", buffer, MAX_LINE_LENGTH); + bool retval = LCReadNextConfig(hfile, "*Config", buffer, buffer.Capacity); Assert.IsTrue(retval); string line = buffer.ToString(); - string [] tokens = new string[4]; - int len = Tokenize(line, tokens); + string[] tokens = new string[4]; + int len = Tokenize(LCTokenize, line, tokens); Assert.AreEqual(tokens.Length, len); Assert.AreEqual("*Config", tokens[0]); @@ -128,16 +172,16 @@ public void LCReadNextConfig_Test() tokens = new string[2]; - retval = LCReadNextConfig(hfile, "*Config", buffer, MAX_LINE_LENGTH); + retval = LCReadNextConfig(hfile, "*Config", buffer, buffer.Capacity); Assert.IsTrue(retval); line = buffer.ToString(); - len = Tokenize(line, tokens); + len = Tokenize(LCTokenize, line, tokens); Assert.AreEqual(tokens.Length, len); Assert.AreEqual("*Config", tokens[0]); Assert.AreEqual("option1", tokens[1]); - + var closed = LCClose(hfile); Assert.IsTrue(closed); } @@ -150,7 +194,7 @@ public void LCReadNextLine_Test() Assert.AreNotEqual(0, hfile.ToInt64()); StringBuilder buffer = new StringBuilder(MAX_LINE_LENGTH); - bool retval = LCReadNextLine(hfile, buffer, MAX_LINE_LENGTH); + bool retval = LCReadNextLine(hfile, buffer, buffer.Capacity); string line = buffer.ToString(); Assert.IsTrue(retval); @@ -265,13 +309,13 @@ public void GetRCString_Test() Assert.AreNotEqual(0, hfile.ToInt64()); StringBuilder buffer = new StringBuilder(MAX_COMMAND); - bool retval = GetRCString("VarC", buffer, "Test", MAX_COMMAND); + bool retval = GetRCString("VarC", buffer, "Test", buffer.Capacity); string rcVal = buffer.ToString(); Assert.IsTrue(retval); Assert.AreEqual("Command3", rcVal); - retval = GetRCString("SomeSetting", buffer, "Test", MAX_COMMAND); + retval = GetRCString("SomeSetting", buffer, "Test", buffer.Capacity); rcVal = buffer.ToString(); Assert.IsFalse(retval); @@ -289,12 +333,12 @@ public void GetRCLine_Test() Assert.AreNotEqual(0, hfile.ToInt64()); StringBuilder buffer = new StringBuilder(MAX_LINE_LENGTH); - bool retval = GetRCLine("*Script", buffer, MAX_LINE_LENGTH, null); + bool retval = GetRCLine("*Script", buffer, buffer.Capacity, null); Assert.IsTrue(retval); string[] tokens = new string[6]; - Tokenize(buffer.ToString(), tokens); + Tokenize(LCTokenize, buffer.ToString(), tokens); Assert.AreEqual("exec", tokens[0]); Assert.AreEqual("!LabelSetAlpha", tokens[1]); @@ -314,8 +358,8 @@ public void GetRCColor_Test() IntPtr hfile = LCOpen(stepRCPath); Assert.AreNotEqual(0, hfile.ToInt64()); - var defaultVal = new COLORREF(0); - COLORREF retval = GetRCColor("VarJ", defaultVal); + var defaultVal = new LSColorRef(0); + LSColorRef retval = GetRCColor("VarJ", defaultVal); Assert.AreEqual(70, retval.R); Assert.AreEqual(130, retval.G); @@ -330,25 +374,236 @@ public void GetRCColor_Test() Assert.IsTrue(closed); } - private static int Tokenize(string line, string [] tokens, StringBuilder extra = null) + [TestCase] + [Category("Configuration")] + public void LSGetVariable_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + StringBuilder value = new StringBuilder(MAX_LINE_LENGTH); + var retval = LSGetVariable("VarJ", value); + + Assert.IsTrue(retval); + Assert.AreEqual("4682B4", value.ToString()); + + value = new StringBuilder(2); + retval = LSGetVariable("at", value, value.Capacity); + + Assert.IsTrue(retval); + Assert.AreEqual("@", value.ToString()); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void LSSetVariable_Test() + { + string val = "1234"; + LSSetVariable("Test", val); + + StringBuilder value = new StringBuilder(4); + var retval = LSGetVariable("Test", value); + + Assert.IsTrue(retval); + Assert.AreEqual(val, value.ToString()); + } + + [TestCase] + [Category("Configuration")] + public void VarExpansion_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + StringBuilder buffer = new StringBuilder(10); + VarExpansion(buffer, "$VarA$"); + + Assert.AreEqual("TRUE", buffer.ToString()); + + buffer = new StringBuilder(MAX_COMMAND); + VarExpansion(buffer, "$VarB$", buffer.Capacity); + + Assert.AreEqual("15", buffer.ToString()); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void GetToken_Test() + { + string line = "*Script exec !LabelSetAlpha Initialising 250 3 10"; + string[] tokens = line.Split(' '); + + foreach (var token in tokens) + { + StringBuilder buffer = new StringBuilder(token.Length); + + IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(char)) * line.Length); + IntPtr nextToken = Marshal.AllocHGlobal(Marshal.SizeOf(ptr)); + Marshal.WriteIntPtr(nextToken, ptr); + + var retval = GetToken(line, buffer, nextToken, false); + + Assert.IsTrue(retval); + Assert.AreEqual(token, buffer.ToString()); + + ptr = Marshal.ReadIntPtr(nextToken); + line = Marshal.PtrToStringAuto(ptr); + + Marshal.FreeHGlobal(nextToken); + } + } + + [TestCase] + [Category("Configuration")] + public void Match_Test() + { + var retval = Match("ex?c", "exec"); + Assert.IsTrue(retval); + + retval = Match("ex*", "exec"); + Assert.IsTrue(retval); + + retval = Match("exec", "exec "); + Assert.IsFalse(retval); + + var iretval = MatchE("[A-Z", "exec"); + Assert.AreEqual(MATCH_PATTERN, iretval); + + iretval = MatchE("exec", "exec "); + Assert.AreEqual(MATCH_END, iretval); + + iretval = MatchE("[0-9]", "exec"); + Assert.AreEqual(MATCH_RANGE, iretval); + + iretval = MatchE("'exec", "exec"); + Assert.AreEqual(MATCH_LITERAL, iretval); + + iretval = MatchE("exe* ", "exec"); + Assert.AreEqual(MATCH_ABORT, iretval); + } + + [TestCase] + [Category("Configuration")] + public void IsPatternValid_Test() + { + int errorCode = 0; + + var retval = IsPatternValid("exec\\", ref errorCode); + + Assert.IsFalse(retval); + Assert.AreEqual(PATTERN_ESC, errorCode); + + retval = IsPatternValid("[]", ref errorCode); + + Assert.IsFalse(retval); + Assert.AreEqual(PATTERN_EMPTY, errorCode); + + retval = IsPatternValid("[a-z][", ref errorCode); + + Assert.IsFalse(retval); + Assert.AreEqual(PATTERN_CLOSE, errorCode); + + retval = IsPatternValid("[a-]", ref errorCode); + + Assert.IsFalse(retval); + Assert.AreEqual(PATTERN_RANGE, errorCode); + + retval = IsPatternValid("[a-zA-Z_0-9]", ref errorCode); + + Assert.IsTrue(retval); + Assert.AreEqual(PATTERN_VALID, errorCode); + } + + [TestCase] + [Category("Diagnostics")] + public void LSLog_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + Assert.IsTrue(GetRCBool("LSLogFile", true)); + + var loglevel = GetRCInt("LSLogLevel", LS_LOG_DEBUG); + + var retval = LSLog(loglevel, "LsapiSharpTest", "Logging test"); + Assert.IsTrue(retval); + + retval = LSLog(loglevel, "LsapiSharpTest", "Logging Test with logging level %i", loglevel); + Assert.IsTrue(retval); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + [TestCase] + [Category("Configuration")] + public void EnumLSData_Test() + { + IntPtr hfile = LCOpen(stepRCPath); + Assert.AreNotEqual(0, hfile.ToInt64()); + + EnumBangDelegate bangCb = (cmd, lparam) => + { + LSLog(LS_LOG_DEBUG, "LsapiSharpTest", "Enum Bang command: " + cmd); + return true; + }; + + EnumBangV2Delegate bangV2Cb = (hInst, cmd, lparam) => + { + LSLog(LS_LOG_DEBUG, "LsapiSharpTest", "Enum Bang V2 command: " + cmd); + return true; + }; + + EnumRevIdsDelegate revIdCb = (revId, lparam) => + { + LSLog(LS_LOG_DEBUG, "LsapiSharpTest", "Enum RevId: " + revId); + return true; + }; + + var retval = EnumLSData(ELD_BANGS, bangCb, IntPtr.Zero); + Assert.AreEqual(HResult.S_OK, retval.Value); + + retval = EnumLSData(ELD_BANGS_V2, bangV2Cb, IntPtr.Zero); + Assert.AreEqual(HResult.S_OK, retval.Value); + + retval = EnumLSData(ELD_REVIDS, revIdCb, IntPtr.Zero); + Assert.AreEqual(HResult.S_OK, retval.Value); + + var closed = LCClose(hfile); + Assert.IsTrue(closed); + } + + private static int Tokenize( + Func tokenize, + string line, + string [] tokens, + StringBuilder extra = null) { int intPtrSize = Marshal.SizeOf(typeof(IntPtr)); IntPtr tokensPtr = Marshal.AllocHGlobal(intPtrSize * tokens.Length); + for (int i = 0; i < tokens.Length; i++) { IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(char)) * MAX_COMMAND); Marshal.WriteIntPtr(tokensPtr, i * intPtrSize, ptr); } - int tokenLen = LCTokenize(line, tokensPtr, tokens.Length, extra); + int tokenLen = tokenize(line, tokensPtr, tokens.Length, extra); for (int i = 0; i < tokens.Length; i++) { IntPtr ptr = Marshal.ReadIntPtr(tokensPtr, i * intPtrSize); - tokens[i] = Marshal.PtrToStringUni(ptr); + tokens[i] = Marshal.PtrToStringAuto(ptr); Marshal.FreeHGlobal(ptr); } + Marshal.FreeHGlobal(tokensPtr); return tokenLen; } } diff --git a/LsapiSharp.Test/step.rc b/LsapiSharp.Test/step.rc index 7211a6e..bb7121f 100644 --- a/LsapiSharp.Test/step.rc +++ b/LsapiSharp.Test/step.rc @@ -16,4 +16,8 @@ VarJ 4682B4 ; GetRCLine test configurations -*Script exec !LabelSetAlpha Initialising 250 3 10 \ No newline at end of file +*Script exec !LabelSetAlpha Initialising 250 3 10 + +; LSLog test +LSLogFile $LiteStepDir$log.txt +LSLogLevel 4 \ No newline at end of file diff --git a/LsapiSharp/NativeMethods.cs b/LsapiSharp/NativeMethods.cs index 3e98ef0..a23a85a 100644 --- a/LsapiSharp/NativeMethods.cs +++ b/LsapiSharp/NativeMethods.cs @@ -52,13 +52,105 @@ public static class NativeMethods /// public const int LS_LOG_DEBUG = 4; + /// + /// Valid match + /// + public const int MATCH_VALID = 1; + + /// + /// Premature end of pattern string + /// + public const int MATCH_END = 2; + + /// + /// Premature end of text string + /// + public const int MATCH_ABORT = 3; + + /// + /// Match failure on [..] construct + /// + public const int MATCH_RANGE = 4; + + /// + /// Match failure on literal match + /// + public const int MATCH_LITERAL = 5; + + /// + /// Bad pattern + /// + public const int MATCH_PATTERN = 6; + + /// + /// Valid pattern + /// + public const int PATTERN_VALID = 0; + + /// + /// Literal escape at end of pattern + /// + public const int PATTERN_ESC = -1; + + /// + /// Malformed range in [..] construct + /// + public const int PATTERN_RANGE = -2; + + /// + /// No end bracket in [..] construct + /// + public const int PATTERN_CLOSE = -3; + + /// + /// [..] contstruct is empty + /// + public const int PATTERN_EMPTY = -4; + + /// + /// + /// + public const int ELD_BANGS = 1; + + /// + /// + /// + public const int ELD_MODULES = 2; + + /// + /// + /// + public const int ELD_REVIDS = 3; + + /// + /// + /// + public const int ELD_BANGS_V2 = 4; + + /// + /// + /// + public const int ELD_PERFORMANCE = 5; + /// /// Win32 representation of DWORD value /// [StructLayout(LayoutKind.Explicit, Size = 4)] - public struct COLORREF + public struct LSColorRef { - public COLORREF(byte r, byte g, byte b) + [FieldOffset(0)] + public byte R; + + [FieldOffset(1)] + public byte G; + + [FieldOffset(2)] + public byte B; + + [FieldOffset(0)] + public int Value; + + public LSColorRef(byte r, byte g, byte b) { this.Value = 0; this.R = r; @@ -66,25 +158,67 @@ public COLORREF(byte r, byte g, byte b) this.B = b; } - public COLORREF(int value) + public LSColorRef(int value) { this.R = 0; this.G = 0; this.B = 0; this.Value = value & 0x00FFFFFF; } + } - [FieldOffset(0)] - public byte R; + /// + /// Win32 representation of the HRESULT value + /// + [StructLayout(LayoutKind.Sequential, Size = 4)] + public struct HResult + { + /// + ///Success code + /// + public const int S_OK = unchecked((int)0x00000000); + + /// + ///Success code false + /// + public const int S_FALSE = unchecked((int)0x00000001); + + /// + ///Catastrophic failure + /// + public const int E_UNEXPECTED = unchecked((int)0x8000FFFF); + + /// + ///One or more arguments are invalid + /// + public const int E_INVALIDARG = unchecked((int)0x80070057); + + /// + ///Invalid pointer + /// + public const int E_POINTER = unchecked((int)0x80004003); + + /// + ///Unspecified error + /// + public const int E_FAIL = unchecked((int)0x80004005); - [FieldOffset(1)] - public byte G; + public int Value; - [FieldOffset(2)] - public byte B; + public HResult(int value) + { + this.Value = value; + } - [FieldOffset(0)] - public int Value; + public static implicit operator int(HResult hr) + { + return hr.Value; + } + + public static implicit operator HResult(int hr) + { + return new HResult(hr); + } } /// @@ -178,6 +312,44 @@ public COLORREF(int value) [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] public static extern int LCTokenize(string config, IntPtr tokens, int tokenLen, StringBuilder extraParams); + /// + /// Parses and retrieves the values in a config line (one that starts with a '*') that begins with the + /// specified setting name from a configuration file. + /// + /// + /// Parses lines that contain commands within brackes i.e [!command] + /// + /// Command name + /// An array of buffers to receive the values + /// The number of tokens expected to retrieve + /// The remaining part of the config line that was not collected in the buffer + /// Returns the number of tokens found in the configuration line + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern int CommandTokenize(string config, IntPtr tokens, int tokenLen, StringBuilder extraParams); + + /// + /// Parses and retrieves the commands in a config line + /// + /// A line in a configuration file + /// The buffer to receive the parsed command + /// The buffer to receive the arguments + /// The size of the buffer + /// The size of the buffer + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern void CommandParse(string line, StringBuilder command, StringBuilder args, int commandLen, int argsLen); + + /// + /// Cycles through a list of tokens parsing and retreiving values in a config line (one that starts with a '*') + /// that begins with the specified setting name from a configuration file. + /// + /// A line in a configuration file + /// The buffer to receive the next token + /// The next token in the line + /// parse tokens between brackes '[]' + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern bool GetToken(string line, StringBuilder token, IntPtr nextToken, bool useBrackets); + /// /// Retrieves an integer value from the global settings. Returns /// if the setting does not exist. @@ -219,7 +391,7 @@ public COLORREF(int value) public static extern double GetRCDouble(string settingName, double defaultVal); /// - /// Retrieves an integer value from the global settings. Returns + /// Retrieves an boolean value from the global settings. Returns /// if the setting does not exist. /// /// Setting name @@ -279,8 +451,142 @@ public COLORREF(int value) /// Default value /// The setting value or default value [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] - public static extern COLORREF GetRCColor(string settingsName, COLORREF defaultVal); + public static extern LSColorRef GetRCColor(string settingsName, LSColorRef defaultVal); + /// + /// FILL ME IN + /// + /// Setting name + /// Default value + /// Max value + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern int GetRCCoordinate(string settingName, int defaultVal, int maxVal); + + /// + /// Parses the coordinate from the line + /// + /// + /// Default value + /// Max value + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern int ParseCoordinate(string line, int defaultVal, int maxVal); + + /// + /// Retrieves a string value from the global settings. Returns FALSE if the setting + /// does not exist. Performs the same operation as {@link #GetRCString}. + /// + /// The setting name + /// Buffer to receive value + /// TRUE if setting exists or FALSE otherwise + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern bool LSGetVariable(string settingName, StringBuilder settingVal); + + /// + /// Retrieves a string value from the global settings. Returns FALSE if the setting + /// does not exist. Performs the same operation as {@link #GetRCString}. + /// + /// The setting name + /// Buffer to receive value + /// The size of buffer + /// TRUE if setting exists or FALSE otherwise + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "LSGetVariableExW")] + public static extern bool LSGetVariable(string settingName, StringBuilder settingVal, long size); + + /// + /// Assigns a new value to a global setting. If the setting already exists its previous value + /// is overwritten, otherwise a new setting is created. + /// + /// The setting name + /// New setting value + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern void LSSetVariable(string settingName, string settingVal); + + /// + /// Expands variable references. The template string is copied into the buffer with + /// all variable references ($var$) replaced by the value of the variable. + /// + /// buffer to received the expanded string + /// string to be expanded + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern void VarExpansion(StringBuilder buffer, string template); + + /// + /// Expands variable references. The template string is copied into the buffer with + /// all variable references ($var$) replaced by the value of the variable. + /// + /// buffer to received the expanded string + /// string to be expanded + /// The size of buffer + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "VarExpansionExW")] + public static extern void VarExpansion(StringBuilder buffer, string template, int size); + + /// + /// Match the pattern against a text value + /// + /// + /// A match means the entire string is used up in matching. + /// + /// A pattern expression + /// The string value to evaluate + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "matchW")] + public static extern bool Match(string pattern, string text); + + /// + /// Match the pattern against a text value + /// + /// A pattern expression + /// The string value to evaluate + /// + /// returns MATCH_VALID if pattern matches, or an errorcode as follows + /// otherwise: + /// + /// MATCH_PATTERN - bad pattern + /// MATCH_LITERAL - match failure on literal mismatch + /// MATCH_RANGE - match failure on[..] construct + /// MATCH_ABORT - premature end of text string + /// MATCH_END - premature end of pattern string + /// MATCH_VALID - valid match + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "matcheW")] + public static extern int MatchE(string pattern, string text); + + /// + /// Determines if a pattern is a well formed regular expression according to the folowing syntax: + /// + /// In the pattern string: + /// `*' matches any sequence of characters (zero or more) + /// `?' matches any character + /// [SET] matches any character in the specified set, + /// [!SET] or[^ SET] matches any character not in the specified set. + /// + /// A set is composed of characters or ranges; a range looks like + /// character hyphen character(as in 0-9 or A-Z). [0-9a-zA-Z_] is the + /// minimal set of characters allowed in the[..] pattern construct. + /// Other characters are allowed(ie. 8 bit characters) if your _tsystem + /// will support them. + /// + /// To suppress the special syntactic significance of any of `[]*?!^-\', + /// and match the character exactly, precede it with a `\'. + /// + /// + /// Zero is returned in error_type if the pattern is a valid one. + /// error_type return values are as follows: + /// + /// PATTERN_VALID - pattern is well formed + /// PATTERN_ESC - pattern has invalid escape('\' at end of pattern) + /// PATTERN_RANGE - [..] construct has a no end range in a '-' pair (ie[a -]) + /// PATTERN_CLOSE - [..] construct has no end bracket(ie[abc - g ) + /// PATTERN_EMPTY - [..] construct is empty(ie[]) + /// + /// A regular expression + /// Is a return code based on the type of pattern error + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "is_valid_patternW")] + public static extern bool IsPatternValid(string pattern, ref int errorCode); + /// /// Bang command callback /// @@ -309,6 +615,16 @@ public COLORREF(int value) [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] public static extern bool RemoveBangCommand(string command); + /// + /// Executes a bang command !command + /// + /// The window handle sent the command + /// The identifier representing the command + /// The arguments associated with the command + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "ParseBangCommandW")] + public static extern bool ExecuteBangCommand(int hwndCaller, string command, string args); + /// /// Self explanatory :-) /// @@ -316,7 +632,7 @@ public COLORREF(int value) /// The name of the module logging from /// The content to write to file /// Returns true on success otherwise false - [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + [DllImport(LSAPI, CallingConvention = CallingConvention.Winapi)] public static extern bool LSLog(int level, string module, string message); /// @@ -328,6 +644,117 @@ public COLORREF(int value) /// The values toreplace the tokens in the formatting instruction /// Returns true on success otherwise false [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "LSLogPrintf")] - public static extern bool LSLog(int level, string module, string format, params object [] args); + public static extern bool LSLog(int level, string module, string format, params object[] args); + + /// + /// Loads a string resource from the executable file associated with a specified module, + /// copies the string into a buffer, and appends a terminating null character. + /// + /// A handle to an instance of the module whose executable file contains the string resource. + /// The identifier of the string to be loaded. + /// The buffer is to receive the string. Must be of sufficient length to hold a pointer (8 bytes). + /// + /// The size of the buffer, in characters. The string is truncated and null-terminated if it is longer + /// than the number of characters specified. If this parameter is 0, then lpBuffer receives a read-only pointer to the resource itself. + /// + /// The default string to return if the resource was not located + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "GetResStrW")] + public static extern void GetResString(IntPtr hInstance, int resId, StringBuilder resText, int size, string defaultText); + + /// + /// Loads a string resource from the executable file associated with a specified module, + /// copies the string into a buffer, and appends a terminating null character. + /// + /// A handle to an instance of the module whose executable file contains the string resource. + /// The identifier of the string to be loaded. + /// The buffer is to receive the string. Must be of sufficient length to hold a pointer (8 bytes). + /// + /// The size of the buffer, in characters. The string is truncated and null-terminated if it is longer + /// than the number of characters specified. If this parameter is 0, then lpBuffer receives a read-only pointer to the resource itself. + /// + /// The default string to return if the resource was not located + /// Formatting arguements + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "GetResStrExW")] + public static extern void GetResString(IntPtr hInstance, int resId, StringBuilder resText, int size, string defaultText, params object[] args); + + /// + /// Bang enumeration callback + /// + /// + /// typedef BOOL (CALLBACK* LSENUMBANGSPROCW)(LPCWSTR, LPARAM); + /// + /// + /// + /// Returns true on success otherwise false + [UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)] + public delegate bool EnumBangDelegate(string command, IntPtr lparam); + + /// + /// Bang enumeration callback + /// + /// typedef BOOL (CALLBACK* LSENUMBANGSV2PROCW)(HINSTANCE, LPCWSTR, LPARAM); + /// + /// + /// + /// Returns true on success otherwise false + [UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)] + public delegate bool EnumBangV2Delegate(IntPtr hInstance, string command, IntPtr lparam); + + /// + /// Rev ID enumeration callback + /// + /// typedef BOOL (CALLBACK* LSENUMREVIDSPROCW)(LPCWSTR, LPARAM); + /// + /// + /// Returns true on success otherwise false + [UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)] + public delegate bool EnumRevIdsDelegate(string revId, IntPtr lparam); + + /// + /// Module enumeration callback + /// + /// typedef BOOL (CALLBACK* LSENUMMODULESPROCW)(LPCWSTR, DWORD, LPARAM) + /// + /// + /// + /// Returns true on success otherwise false + [UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)] + public delegate bool EnumModuleDelegate(string module, long flags, IntPtr lparam); + + /// + /// Module performance enumeration callback + /// + /// typedef BOOL (CALLBACK* LSENUMPERFORMANCEPROCW)(LPCWSTR, DWORD, LPARAM) + /// + /// + /// + /// Returns true on success otherwise false + [UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Unicode)] + public delegate bool EnumPerformanceDelegate(string module, long flags, IntPtr lparam); + + /// + /// FILL ME IN + /// + /// + /// Enumerates over the following information: + /// - Bang commands + /// - Revision IDs + /// - Loaded Modules + /// - Performance information about the module + /// + /// The type of information to enumerate + /// The delegate to call during enumeration + /// Extra information + /// + /// Return values: + /// E_INVALIDARG - Invalid value for uInfo + /// E_POINTER - Invalid callback + /// E_FAIL - Unspecified error + /// E_UNEXPECTED - Callback crashed or other catastrophic failure + /// S_OK - Enumeration successful, callback always returned TRUE + /// S_FALSE - Enumeration successful, but cancelled by callback + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern HResult EnumLSData(int eldInfo, [MarshalAs(UnmanagedType.FunctionPtr)] Delegate callback, IntPtr lparam); } } diff --git a/litestep.sln b/litestep.sln index 1753167..aa12e14 100644 --- a/litestep.sln +++ b/litestep.sln @@ -110,14 +110,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{DEC29FCD-9 sdk\docs\lsapi\VarExpansionEx.xml = sdk\docs\lsapi\VarExpansionEx.xml EndProjectSection EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{CF23F811-B9C1-4EAA-AB0E-8E5FE32AA968}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LsapiSharp", "LsapiSharp\LsapiSharp.csproj", "{7F8140DC-7815-4368-94F8-A7ED7CF04A2A}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hello", "sdk\examples\hello\hello.vcxproj", "{CECF0543-6AEB-49CA-9B14-D64155631FE4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloCLR", "sdk\examples\HelloCLR\HelloCLR.csproj", "{2A700A3B-CEFB-488E-BC28-5679FB19712E}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LsapiSharp.Test", "LsapiSharp.Test\LsapiSharp.Test.csproj", "{580B3CBE-9E12-41A2-B723-6CE9BBCB7527}" ProjectSection(ProjectDependencies) = postProject {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA} = {2FECA0A4-CB2F-44CA-97AB-DE78EBBDECFA} @@ -177,26 +171,6 @@ Global {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|Win32.Build.0 = Release|Any CPU {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|x64.ActiveCfg = Release|Any CPU {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|x64.Build.0 = Release|Any CPU - {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Debug|Win32.ActiveCfg = Debug|Win32 - {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Debug|Win32.Build.0 = Debug|Win32 - {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Debug|x64.ActiveCfg = Debug|Win32 - {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Release|Any CPU.ActiveCfg = Release|Win32 - {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Release|Win32.ActiveCfg = Release|Win32 - {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Release|Win32.Build.0 = Release|Win32 - {CECF0543-6AEB-49CA-9B14-D64155631FE4}.Release|x64.ActiveCfg = Release|Win32 - {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Debug|Win32.ActiveCfg = Debug|x86 - {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Debug|Win32.Build.0 = Debug|x86 - {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Debug|x64.ActiveCfg = Debug|x64 - {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Debug|x64.Build.0 = Debug|x64 - {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Release|Any CPU.Build.0 = Release|Any CPU - {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Release|Win32.ActiveCfg = Release|Any CPU - {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Release|Win32.Build.0 = Release|Any CPU - {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Release|x64.ActiveCfg = Release|Any CPU - {2A700A3B-CEFB-488E-BC28-5679FB19712E}.Release|x64.Build.0 = Release|Any CPU {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|Any CPU.Build.0 = Debug|Any CPU {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|Win32.ActiveCfg = Debug|x86 @@ -215,10 +189,7 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {DEC29FCD-986F-4AAB-A697-AE091EFEF71A} = {0CB7B995-8934-4494-8EB9-968D5407C6E5} - {CF23F811-B9C1-4EAA-AB0E-8E5FE32AA968} = {0CB7B995-8934-4494-8EB9-968D5407C6E5} {7F8140DC-7815-4368-94F8-A7ED7CF04A2A} = {757E055D-EC8C-4038-B2F3-E6C978057563} - {CECF0543-6AEB-49CA-9B14-D64155631FE4} = {CF23F811-B9C1-4EAA-AB0E-8E5FE32AA968} - {2A700A3B-CEFB-488E-BC28-5679FB19712E} = {CF23F811-B9C1-4EAA-AB0E-8E5FE32AA968} {580B3CBE-9E12-41A2-B723-6CE9BBCB7527} = {757E055D-EC8C-4038-B2F3-E6C978057563} EndGlobalSection EndGlobal From 2817746a3db996a76db8e019cec75c6945d20313 Mon Sep 17 00:00:00 2001 From: nerd Date: Tue, 10 Jan 2017 00:05:14 -0600 Subject: [PATCH 03/14] Completed the addition of the remaining lsapi bindings just need to test and tweak --- LsapiSharp.Test/LsapiSharpTest.cs | 6 +- LsapiSharp/NativeMethods.cs | 475 +++++++++++++++++++++++++++++- 2 files changed, 464 insertions(+), 17 deletions(-) diff --git a/LsapiSharp.Test/LsapiSharpTest.cs b/LsapiSharp.Test/LsapiSharpTest.cs index f224618..05ee607 100644 --- a/LsapiSharp.Test/LsapiSharpTest.cs +++ b/LsapiSharp.Test/LsapiSharpTest.cs @@ -567,13 +567,13 @@ public void EnumLSData_Test() }; var retval = EnumLSData(ELD_BANGS, bangCb, IntPtr.Zero); - Assert.AreEqual(HResult.S_OK, retval.Value); + Assert.AreEqual(LSHResult.S_OK, retval.Value); retval = EnumLSData(ELD_BANGS_V2, bangV2Cb, IntPtr.Zero); - Assert.AreEqual(HResult.S_OK, retval.Value); + Assert.AreEqual(LSHResult.S_OK, retval.Value); retval = EnumLSData(ELD_REVIDS, revIdCb, IntPtr.Zero); - Assert.AreEqual(HResult.S_OK, retval.Value); + Assert.AreEqual(LSHResult.S_OK, retval.Value); var closed = LCClose(hfile); Assert.IsTrue(closed); diff --git a/LsapiSharp/NativeMethods.cs b/LsapiSharp/NativeMethods.cs index a23a85a..9206035 100644 --- a/LsapiSharp/NativeMethods.cs +++ b/LsapiSharp/NativeMethods.cs @@ -170,8 +170,8 @@ public LSColorRef(int value) /// /// Win32 representation of the HRESULT value /// - [StructLayout(LayoutKind.Sequential, Size = 4)] - public struct HResult + [StructLayout(LayoutKind.Sequential)] + public struct LSHResult { /// ///Success code @@ -203,21 +203,129 @@ public struct HResult /// public const int E_FAIL = unchecked((int)0x80004005); + /// + /// No such interface supported + /// + public const int E_NOINTERFACE = unchecked((int)0x80004002); + + /// + /// Class not registered + /// + public const int REGDB_E_CLASSNOTREG = unchecked((int)0x80040154); + + /// + /// Class does not support aggregation (or class object is remote) + /// + public const int CLASS_E_NOAGGREGATION = unchecked((int)0x80040110); + public int Value; - public HResult(int value) + public LSHResult(int value) { this.Value = value; } - public static implicit operator int(HResult hr) + public static implicit operator int(LSHResult hr) { return hr.Value; } - public static implicit operator HResult(int hr) + public static implicit operator LSHResult(int hr) { - return new HResult(hr); + return new LSHResult(hr); + } + } + + /// + /// Win32 representation of the RECT structure + /// + [StructLayout(LayoutKind.Sequential)] + public struct LSRect + { + int Left, Top, Right, Bottom; + + public LSRect(int left, int top, int right, int bottom) + { + Left = left; + Top = top; + Right = right; + Bottom = bottom; + } + + public int X + { + get { return Left; } + set { Right -= (Left - value); Left = value; } + } + + public int Y + { + get { return Top; } + set { Bottom -= (Top - value); Top = value; } + } + + public int Height + { + get { return Bottom - Top; } + set { Bottom = value + Top; } + } + + public int Width + { + get { return Right - Left; } + set { Right = value + Left; } + } + } + + /// + /// Win32 representation of the POINT structure + /// + [StructLayout(LayoutKind.Sequential)] + public struct LSPoint + { + int X; + int Y; + + public LSPoint(int x, int y) + { + this.X = x; + this.Y = y; + } + } + + /// + /// Win32 representation of the MONITORINFO structure + /// + [StructLayout(LayoutKind.Sequential)] + public struct LSMonitorInfo + { + int Size; + LSRect Monitor; + LSRect Work; + int flags; + + public static LSMonitorInfo Create() + { + return new LSMonitorInfo { Size = Marshal.SizeOf(typeof(LSMonitorInfo)) }; + } + } + + /// + /// Win32 representation of the DISPLAY_DEVICEW structure + /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct LSDisplayDevice + { + int cb; + string DeviceName; + string DeviceString; + int StateFlags; + string DeviceID; + string DeviceKey; + + public static LSDisplayDevice Create() + { + return new LSDisplayDevice { cb = Marshal.SizeOf(typeof(LSDisplayDevice)) }; } } @@ -230,6 +338,18 @@ public static implicit operator HResult(int hr) [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] public static extern bool LSAPIInitialize(string litestepPath, string steprcPath); + /// + /// Refreshes the list of bang commands + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern void LSAPIReloadBangs(); + + /// + /// Refreshes the settings + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern void LSAPIReloadSettings(); + /// /// Opens a configuration file for sequential access to its contents. /// @@ -586,17 +706,29 @@ public static implicit operator HResult(int hr) /// Returns true on success otherwise false [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "is_valid_patternW")] public static extern bool IsPatternValid(string pattern, ref int errorCode); - + /// /// Bang command callback /// + /// + /// typedef void (__cdecl *BangCommandW)(HWND hSender, LPCWSTR pszArgs); + /// /// The window handle sent the command /// The arguments associated with the command - /// - /// typedef void (__cdecl *BangCommandW)(HWND hSender, LPCWSTR pszArgs); - /// [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] - public delegate void BangCommandDelegate(int hWndSender, string args); + public delegate void BangCommandDelegate(IntPtr hWndSender, string args); + + /// + /// Bang command callback + /// + /// + /// typedef void (__cdecl *BangCommandExW)(HWND hSender, LPCWSTR pszCommand, LPCWSTR pszArgs); + /// + /// The window handle sent the command + /// + /// The arguments associated with the command + [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public delegate void BangCommandDelegate2(IntPtr hWndSender, string command, string args); /// /// Registers bang commands @@ -605,7 +737,7 @@ public static implicit operator HResult(int hr) /// the callback method associated with the command /// Returns true on success otherwise false [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] - public static extern bool AddBangCommand(string command, [MarshalAs(UnmanagedType.FunctionPtr)] BangCommandDelegate commandDelegate); + public static extern bool AddBangCommand(string command, [MarshalAs(UnmanagedType.FunctionPtr)] Delegate commandDelegate); /// /// Removes a bang command from the list. @@ -623,7 +755,7 @@ public static implicit operator HResult(int hr) /// The arguments associated with the command /// Returns true on success otherwise false [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "ParseBangCommandW")] - public static extern bool ExecuteBangCommand(int hwndCaller, string command, string args); + public static extern bool ExecuteBangCommand(IntPtr hwndCaller, string command, string args); /// /// Self explanatory :-) @@ -755,6 +887,321 @@ public static implicit operator HResult(int hr) /// S_FALSE - Enumeration successful, but cancelled by callback /// [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] - public static extern HResult EnumLSData(int eldInfo, [MarshalAs(UnmanagedType.FunctionPtr)] Delegate callback, IntPtr lparam); + public static extern LSHResult EnumLSData(int eldInfo, [MarshalAs(UnmanagedType.FunctionPtr)] Delegate callback, IntPtr lparam); + + /// + /// Performs an operation on a specified file. + /// + /// A handle to the parent window used for displaying a UI or error messages. + /// A pointer to a null-terminated string that specifies the !bang command on which to execute the + /// + /// The flags that specify how an application is to be displayed when it is opened. If lpFile specifies a + /// document file, the flag is simply passed to the associated application. It is up to the application to + /// decide how to handle it. + /// + /// + /// If the function succeeds, it returns a value greater than 32. If the function fails, + /// it returns an error value that indicates the cause of the failure. + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern IntPtr LSExecute(IntPtr hOwnerWnd, string command, int showCommand); + + /// + /// Performs an operation on a specified file. + /// + /// A handle to the parent window used for displaying a UI or error messages. + /// + /// A pointer to a null-terminated string, referred to in this case as a verb, that specifies the action to + /// be performed. The set of available verbs depends on the particular file or folder. Generally, the actions + /// available from an object's shortcut menu are available verbs. + /// + /// + /// A pointer to a null-terminated string that specifies the file or !bang command on which to execute the + /// specified verb. + /// + /// + /// If lpFile specifies an executable file, this parameter is a pointer to a null-terminated string that specifies the parameters to be passed to + /// the application. The format of this string is determined by the verb that is to be invoked. + /// + /// A pointer to a null-terminated string that specifies the default (working) directory for the action. + /// + /// The flags that specify how an application is to be displayed when it is opened. If lpFile specifies a + /// document file, the flag is simply passed to the associated application. It is up to the application to + /// decide how to handle it. + /// + /// + /// If the function succeeds, it returns a value greater than 32. If the function fails, + /// it returns an error value that indicates the cause of the failure. + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "LSExecuteExW")] + public static extern IntPtr LSExecute(IntPtr hOwnerWnd, string operation, string command, string args, string directory, int nShowCmd); + + /// + /// Sets the main litestep window + /// + /// The handle to the window + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern void LSAPISetLitestepWindow(IntPtr hWnd); + + /// + /// Gets the litestep main window + /// + /// Returns a handle to the litestep main window on success + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "GetLitestepWnd")] + public static extern IntPtr GetLitestepWindow(); + + /// + /// Gets the path to the litestep directory + /// + /// + /// + /// Returns to true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, EntryPoint = "LSGetLitestepPathW")] + public static extern bool LSGetLitestepPath(StringBuilder path, int size); + + /// + /// Gets the path to the image directory + /// + /// + /// + /// Returns to true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode, EntryPoint = "LSGetImagePathW")] + public static extern bool LSGetImagePath(StringBuilder path, int size); + + /// + /// FILL ME IN + /// + /// + /// + /// + /// + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern void Frame3D(IntPtr hDC, LSRect rect, LSColorRef topColor, LSColorRef bottomColor, int width); + + /// + /// FILL ME IN + /// + /// + /// + /// + /// + /// + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr BitmapToRegion(IntPtr hBmp, LSColorRef transparent, LSColorRef tolerance, int xoffset, int yoffset); + + /// + /// FILL ME IN + /// + /// + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr BitmapFromIcon(IntPtr hIcon); + + /// + /// FILL ME IN + /// + /// + /// + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern IntPtr LoadLSImage(string file, string image); + + /// + /// FILL ME IN + /// + /// + /// + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + public static extern IntPtr LoadLSIcon(string image, string file); + + /// + /// FILL ME IN + /// + /// + /// + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern void GetLSBitmapSize( + IntPtr hBitmap, + [MarshalAs(UnmanagedType.LPStruct)] out int width, + [MarshalAs(UnmanagedType.LPStruct)] out int height); + + /// + /// FILL ME IN + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern void TransparentBltLS(IntPtr hDC, int xDest, int yDest, int width, int height, IntPtr tempDC, int xSrc, int ySrc, LSColorRef transparent); + + /// + /// Sets the size of the work area. + /// + /// + /// + /// + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern void SetDesktopArea(int left, int top, int right, int bottom); + + /// + /// Retrieves the specified system metric or system configuration setting. + /// + /// See + /// for details on values + /// The system metric or configuration setting to be retrieved + /// + /// If the function succeeds, the return value is the requested system metric or configuration setting. + /// If the function fails, the return value is 0. GetLastError does not provide extended error information. + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern int LSGetSystemMetrics(int index); + + /// + /// The MonitorFromWindow function retrieves a handle to the display monitor that has + /// the largest area of intersection with the bounding rectangle of a specified window. + /// + /// A handle to the window of interest. + /// Determines the function's return value if the window does not intersect any display monitor. + /// + /// If the window intersects one or more display monitor rectangles, the return value is an HMONITOR handle to the display monitor + /// that has the largest area of intersection with the window. + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr LSMonitorFromWindow(IntPtr hWnd, int flags); + + /// + /// The MonitorFromRect function retrieves a handle to the display monitor that has the + /// largest area of intersection with a specified rectangle. + /// + /// A pointer to a RECT structure that specifies the rectangle of interest in virtual-screen coordinates. + /// Determines the function's return value if the rectangle does not intersect any display monitor. + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr LSMonitorFromRect([In, MarshalAs(UnmanagedType.LPStruct)] LSRect coordinates, int flags); + + /// + /// The MonitorFromPoint function retrieves a handle to the display monitor that contains a specified point. + /// + /// A POINT structure that specifies the point of interest in virtual-screen coordinates. + /// Determines the function's return value if the point is not contained within any display monitor. + /// + /// If the point is contained by a display monitor, the return value is an HMONITOR handle to that display monitor. + /// If the point is not contained by a display monitor, the return value depends on the value of . + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr LSMonitorFromPoint(LSPoint coordinates, int flags); + + /// + /// Retrieves information about a display monitor. + /// + /// A handle to the display monitor of interest. + /// A pointer to a MONITORINFO or MONITORINFOEX structure that receives information + /// about the specified display monitor. + /// + /// If the function succeeds, the return value is nonzero. + /// If the function fails, the return value is zero. + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern bool LSGetMonitorInfo(IntPtr hMonitor, [In, Out, MarshalAs(UnmanagedType.LPStruct)] LSMonitorInfo info); + + /// + /// A MonitorEnumProc function is an application-defined callback function that + /// is called by the EnumDisplayMonitors function. + /// + /// typedef BOOL (CALLBACK* MONITORENUMPROC)(HMONITOR, HDC, LPRECT, LPARAM) + /// A handle to the display monitor. + /// A handle to a device context. + /// A pointer to a RECT structure. + /// Application-defined data that EnumDisplayMonitors passes directly to the enumeration function. + /// To continue the enumeration, return TRUE otherise FALSE. + [UnmanagedFunctionPointer(CallingConvention.Winapi)] + public delegate bool EnumMonitorDelegate(IntPtr hMonitor, IntPtr hDC, LSRect area, IntPtr lparam); + + /// + /// Enumerates display monitors (including invisible pseudo-monitors associated with the mirroring drivers) that + /// intersect a region formed by the intersection of a specified clipping rectangle and the visible region of a device context. + /// + /// A handle to a display device context that defines the visible region of interest. + /// A pointer to a RECT structure that specifies a clipping rectangle. The region of interest is the intersection + /// of the clipping rectangle with the visible region specified by hdc. + /// A pointer to a MonitorEnumProc application-defined callback function. + /// Application-defined data that EnumDisplayMonitors passes directly to the MonitorEnumProc function. + /// If the function succeeds, the return value is nonzero otherwise zero + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern bool LSEnumDisplayMonitors( + IntPtr hDC, + [In, MarshalAs(UnmanagedType.LPStruct)] LSRect clip, + [MarshalAs(UnmanagedType.FunctionPtr)] EnumMonitorDelegate callback, + IntPtr lparam); + + /// + /// Obtains information about the display devices in the current session. + /// + /// A pointer to the device name. + /// An index value that specifies the display device of interest. + /// A pointer to a structure that + /// receives information about the display device specified by . + /// Set this flag to EDD_GET_DEVICE_INTERFACE_NAME (0x00000001) to retrieve + /// the device interface name for GUID_DEVINTERFACE_MONITOR, which is registered by the operating + /// system on a per monitor basis. + /// + /// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. + /// The function fails if is greater than the largest device index. + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern bool LSEnumDisplayDevices( + string device, + int index, + [In, MarshalAs(UnmanagedType.LPStruct)] LSDisplayDevice displayInfo, + int flags); + + /// + /// Creates a single uninitialized object of the class associated with a specified CLSID. + /// + /// The CLSID associated with the data and code that will be used to create the object. + /// + /// If NULL, indicates that the object is not being created as part of an aggregate. If non-NULL, + /// pointer to the aggregate object's IUnknown interface (the controlling IUnknown). + /// + /// Context in which the code that manages the newly created object will run. + /// A reference to the identifier of the interface to be used to communicate with the object. + /// + /// Address of pointer variable that receives the interface pointer requested in riid. + /// Upon successful return, *ppv contains the requested interface pointer. + /// + /// + /// This function can return the following values + /// E_NOINTERFACE - The specified class does not implement the requested interface, or the controlling IUnknown does not expose the requested interface + /// E_POINTER - The ppv parameter is NULL. + /// CLASS_E_NOAGGREGATION - This class cannot be created as part of an aggregate. + /// REGDB_E_CLASSNOTREG - A specified class is not registered in the registration database. + /// S_OK - An instance of the specified object class was successfully created. + /// + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern LSHResult LSCoCreateInstance( + [In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid, + IntPtr pUnkOuter, + int dwClsContext, + [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid, + [MarshalAs(UnmanagedType.IUnknown)] out object ppv); + + + /// + /// Sets the COM interface factory for this API + /// + /// Factory object + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] + public static extern void LSAPISetCOMFactory([In, MarshalAs(UnmanagedType.IUnknown)] object factory); } } From 2333bd0319655e3c1bd24d79d01bb07d63b37215 Mon Sep 17 00:00:00 2001 From: nerd Date: Wed, 11 Jan 2017 21:46:59 -0600 Subject: [PATCH 04/14] Added a few more unit tests and corrected a DllImport --- LsapiSharp.Test/LsapiSharpTest.cs | 190 ++++++++++++++---------------- LsapiSharp.Test/step.rc | 2 + LsapiSharp/NativeMethods.cs | 137 +++++++++++++++++++-- 3 files changed, 216 insertions(+), 113 deletions(-) diff --git a/LsapiSharp.Test/LsapiSharpTest.cs b/LsapiSharp.Test/LsapiSharpTest.cs index 05ee607..c3367ea 100644 --- a/LsapiSharp.Test/LsapiSharpTest.cs +++ b/LsapiSharp.Test/LsapiSharpTest.cs @@ -26,10 +26,12 @@ using System.Runtime.InteropServices; using System.Text; +using Microsoft.Win32.SafeHandles; using NUnit.Framework; using static LsapiSharp.NativeMethods; + namespace LsapiSharp.Test { [TestFixture] @@ -41,25 +43,26 @@ public class LsapiSharpTest const int MAX_COMMAND = 64; static string stepRCPath; + static SafeFileHandle hstepRCFile; [OneTimeSetUp()] - public static void Initialize() + public static void InitializeTest() { var location = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); var initialized = LSAPIInitialize(location, stepRCPath = Path.Combine(location, "step.rc")); Assert.IsTrue(initialized); + + hstepRCFile = LCOpen(stepRCPath); + Assert.IsFalse(hstepRCFile.IsClosed); } - [TestCase] - [Category("Configuration")] - public void LCOpen_LCClose_Test() + [OneTimeTearDown] + public static void FinalizeTest() { - IntPtr hfile = LCOpen(null); - Assert.NotZero(hfile.ToInt64()); - - var closed = LCClose(hfile); + var closed = LCClose(hstepRCFile); Assert.IsTrue(closed); } + [TestCase] [Category("Configuration")] @@ -135,29 +138,20 @@ public void CommandParse_Test() [Category("Configuration")] public void LCReadNextCommand_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - StringBuilder buffer = new StringBuilder(MAX_LINE_LENGTH); - bool retval = LCReadNextCommand(hfile, buffer, buffer.Capacity); + bool retval = LCReadNextCommand(hstepRCFile, buffer, buffer.Capacity); string line = buffer.ToString(); Assert.IsTrue(retval); Assert.NotZero(line.Length); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] [Category("Configuration")] public void LCReadNextConfig_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - StringBuilder buffer = new StringBuilder(MAX_LINE_LENGTH); - bool retval = LCReadNextConfig(hfile, "*Config", buffer, buffer.Capacity); + bool retval = LCReadNextConfig(hstepRCFile, "*Config", buffer, buffer.Capacity); Assert.IsTrue(retval); string line = buffer.ToString(); @@ -172,7 +166,7 @@ public void LCReadNextConfig_Test() tokens = new string[2]; - retval = LCReadNextConfig(hfile, "*Config", buffer, buffer.Capacity); + retval = LCReadNextConfig(hstepRCFile, "*Config", buffer, buffer.Capacity); Assert.IsTrue(retval); line = buffer.ToString(); @@ -181,36 +175,24 @@ public void LCReadNextConfig_Test() Assert.AreEqual(tokens.Length, len); Assert.AreEqual("*Config", tokens[0]); Assert.AreEqual("option1", tokens[1]); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] [Category("Configuration")] public void LCReadNextLine_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - StringBuilder buffer = new StringBuilder(MAX_LINE_LENGTH); - bool retval = LCReadNextLine(hfile, buffer, buffer.Capacity); + bool retval = LCReadNextLine(hstepRCFile, buffer, buffer.Capacity); string line = buffer.ToString(); Assert.IsTrue(retval); Assert.NotZero(line.Length); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] [Category("Configuration")] public void GetRCInt_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - int retval = GetRCInt("VarB", 0); Assert.AreEqual(15, retval); @@ -222,52 +204,34 @@ public void GetRCInt_Test() retval64 = GetRCInt("SomeSetting", 0); Assert.AreEqual(0, retval64); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] [Category("Configuration")] public void GetRCFloat_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - float retval = GetRCFloat("VarF", 0); Assert.AreEqual(53.675f, retval); retval = GetRCFloat("SomeSetting", 0); Assert.AreEqual(0, retval); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] [Category("Configuration")] public void GetRCDouble_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - double retval = GetRCDouble("VarG", 0); Assert.AreEqual(1.7E+3d, retval); retval = GetRCFloat("SomeSetting", 0); Assert.AreEqual(0, retval); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] [Category("Configuration")] public void GetRCBoolDef_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - bool retval = GetRCBoolDef("VarA", false); Assert.IsTrue(retval); @@ -276,18 +240,12 @@ public void GetRCBoolDef_Test() retval = GetRCBoolDef("SomeSetting", false); Assert.IsFalse(retval); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] [Category("Configuration")] public void GetRCBool_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - bool retval = GetRCBool("VarA", false); Assert.IsFalse(retval); @@ -296,18 +254,12 @@ public void GetRCBool_Test() retval = GetRCBool("SomeSetting", false); Assert.IsTrue(retval); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] [Category("Configuration")] public void GetRCString_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - StringBuilder buffer = new StringBuilder(MAX_COMMAND); bool retval = GetRCString("VarC", buffer, "Test", buffer.Capacity); string rcVal = buffer.ToString(); @@ -320,18 +272,12 @@ public void GetRCString_Test() Assert.IsFalse(retval); Assert.AreEqual("Test", rcVal); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] [Category("Configuration")] public void GetRCLine_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - StringBuilder buffer = new StringBuilder(MAX_LINE_LENGTH); bool retval = GetRCLine("*Script", buffer, buffer.Capacity, null); @@ -346,18 +292,12 @@ public void GetRCLine_Test() Assert.AreEqual("250", tokens[3]); Assert.AreEqual("3", tokens[4]); Assert.AreEqual("10", tokens[5]); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] [Category("Configuration")] public void GetRCColor_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - var defaultVal = new LSColorRef(0); LSColorRef retval = GetRCColor("VarJ", defaultVal); @@ -369,18 +309,29 @@ public void GetRCColor_Test() retval = GetRCColor("SomethingElse", defaultVal); Assert.AreEqual(defaultVal.Value, retval.Value); + } - var closed = LCClose(hfile); - Assert.IsTrue(closed); + [TestCase] + [Category("Configuration")] + public void GetRCCoordinate_Test() + { + var retval = GetRCCoordinate("VarK", 0, 0); + Assert.AreEqual(100, retval); + + retval = GetRCCoordinate("VarL", 0, 100); + Assert.AreEqual(20, retval); + + retval = GetRCCoordinate("SomethingElse", 50, 50); + Assert.AreEqual(50, retval); + + retval = ParseCoordinate("1000", 50, 0); + Assert.AreEqual(1000, retval); } [TestCase] [Category("Configuration")] public void LSGetVariable_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - StringBuilder value = new StringBuilder(MAX_LINE_LENGTH); var retval = LSGetVariable("VarJ", value); @@ -392,9 +343,6 @@ public void LSGetVariable_Test() Assert.IsTrue(retval); Assert.AreEqual("@", value.ToString()); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] @@ -415,9 +363,6 @@ public void LSSetVariable_Test() [Category("Configuration")] public void VarExpansion_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - StringBuilder buffer = new StringBuilder(10); VarExpansion(buffer, "$VarA$"); @@ -427,9 +372,6 @@ public void VarExpansion_Test() VarExpansion(buffer, "$VarB$", buffer.Capacity); Assert.AreEqual("15", buffer.ToString()); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] @@ -524,9 +466,6 @@ public void IsPatternValid_Test() [Category("Diagnostics")] public void LSLog_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - Assert.IsTrue(GetRCBool("LSLogFile", true)); var loglevel = GetRCInt("LSLogLevel", LS_LOG_DEBUG); @@ -536,18 +475,12 @@ public void LSLog_Test() retval = LSLog(loglevel, "LsapiSharpTest", "Logging Test with logging level %i", loglevel); Assert.IsTrue(retval); - - var closed = LCClose(hfile); - Assert.IsTrue(closed); } [TestCase] [Category("Configuration")] public void EnumLSData_Test() { - IntPtr hfile = LCOpen(stepRCPath); - Assert.AreNotEqual(0, hfile.ToInt64()); - EnumBangDelegate bangCb = (cmd, lparam) => { LSLog(LS_LOG_DEBUG, "LsapiSharpTest", "Enum Bang command: " + cmd); @@ -574,9 +507,66 @@ public void EnumLSData_Test() retval = EnumLSData(ELD_REVIDS, revIdCb, IntPtr.Zero); Assert.AreEqual(LSHResult.S_OK, retval.Value); + } - var closed = LCClose(hfile); - Assert.IsTrue(closed); + [TestCase] + public void GetLitestepPath_Test() + { + StringBuilder path = new StringBuilder(MAX_PATH); + string lspath = Path.GetDirectoryName(stepRCPath) + @"\"; + + var retval = LSGetLitestepPath(path, MAX_PATH); + Assert.IsTrue(retval); + Assert.AreEqual(lspath, path.ToString()); + } + + [TestCase] + public void LSGetImagePath_Test() + { + StringBuilder path = new StringBuilder(MAX_PATH); + string imgpath = Path.GetDirectoryName(stepRCPath) + @"\images\"; + + var retval = LSGetImagePath(path, MAX_PATH); + Assert.IsTrue(retval); + Assert.AreEqual(imgpath, path.ToString()); + } + + [TestCase] + public void Bang_Test() + { + const string TEST_ARGS = "testarg"; + + BangCommandDelegate bang = (sender, args) => Assert.AreEqual(TEST_ARGS, args); + + BangCommandDelegate2 bang2 = (sender, cmd, args) => + { + Assert.AreEqual("!Test2", cmd); + Assert.AreEqual(TEST_ARGS, args); + }; + + var retval = AddBangCommand("!Test1", bang); + Assert.IsTrue(retval); + + retval = AddBangCommand("!Test2", bang2); + Assert.IsTrue(retval); + + retval = ExecuteBangCommand(IntPtr.Zero, "!Test1", TEST_ARGS); + Assert.IsTrue(retval); + + retval = ExecuteBangCommand(IntPtr.Zero, "!Test2", TEST_ARGS); + Assert.IsTrue(retval); + + retval = RemoveBangCommand("!Test1"); + Assert.IsTrue(retval); + + retval = RemoveBangCommand("!Test2"); + Assert.IsTrue(retval); + + retval = ExecuteBangCommand(IntPtr.Zero, "!Test1", TEST_ARGS); + Assert.IsFalse(retval); + + retval = ExecuteBangCommand(IntPtr.Zero, "!Test2", TEST_ARGS); + Assert.IsFalse(retval); } private static int Tokenize( diff --git a/LsapiSharp.Test/step.rc b/LsapiSharp.Test/step.rc index bb7121f..4ecd9c0 100644 --- a/LsapiSharp.Test/step.rc +++ b/LsapiSharp.Test/step.rc @@ -8,6 +8,8 @@ VarF 53.675 VarG 1.7E+3 VarH 1 VarJ 4682B4 +VarK 100C +VarL -80% ; LCReadNextConfig test configurations diff --git a/LsapiSharp/NativeMethods.cs b/LsapiSharp/NativeMethods.cs index 9206035..f042501 100644 --- a/LsapiSharp/NativeMethods.cs +++ b/LsapiSharp/NativeMethods.cs @@ -24,6 +24,8 @@ using System.Runtime.InteropServices; using System.Text; +using Microsoft.Win32.SafeHandles; + [assembly: CLSCompliant(true)] namespace LsapiSharp @@ -108,30 +110,130 @@ public static class NativeMethods public const int PATTERN_EMPTY = -4; /// - /// + /// FILL ME IN /// public const int ELD_BANGS = 1; /// - /// + /// FILL ME IN /// public const int ELD_MODULES = 2; /// - /// + /// FILL ME IN /// public const int ELD_REVIDS = 3; /// - /// + /// FILL ME IN /// public const int ELD_BANGS_V2 = 4; /// - /// + /// FILL ME IN /// public const int ELD_PERFORMANCE = 5; + /// + /// FILL ME IN + /// + public const int LM_SHUTDOWN = 8889; + + /// + /// FILL ME IN + /// + public const int LM_REPAINT = 8890; + + /// + /// FILL ME IN + /// + public const int LM_BRINGTOFRONT = 8891; + + /// + /// FILL ME IN + /// + public const int LM_SAVEDATA = 8892; + + /// + /// FILL ME IN + /// + public const int LM_RESTOREDATA = 8893; + + /// + /// FILL ME IN + /// + public const int LM_POPUP = 9182; + + /// + /// FILL ME IN + /// + public const int LM_HIDEPOPUP = 9183; + + /// + /// FILL ME IN + /// + public const int LM_LSSELECT = 9185; + + /// + /// FILL ME IN + /// + public const int LM_SENDSYSTRAY = 9213; + + /// + /// FILL ME IN + /// + public const int LM_SYSTRAYA = 9214; + + /// + /// FILL ME IN + /// + public const int LM_SYSTRAYREADY = 9215; + + /// + /// FILL ME IN + /// + public const int LM_SYSTRAYINFOEVENT = 9216; + + /// + /// FILL ME IN + /// + public const int LM_RECYCLE = 9260; + + /// + /// FILL ME IN + /// + public const int LM_REGISTERMESSAGE = 9263; + + /// + /// FILL ME IN + /// + public const int LM_UNREGISTERMESSAGE = 9264; + + /// + /// FILL ME IN + /// + public const int LM_GETREVIDA = 9265; + + /// + /// FILL ME IN + /// + public const int LM_UNLOADMODULEA = 9266; + + /// + /// FILL ME IN + /// + public const int LM_RELOADMODULEA = 9267; + + /// + /// FILL ME IN + /// + public const int LM_SHADETOGGLE = 9300; + + /// + /// FILL ME IN + /// + public const int LM_REFRESH = 9305; + /// /// Win32 representation of DWORD value /// @@ -363,7 +465,7 @@ public static LSDisplayDevice Create() /// Full path to the file to open /// File handle on success or NULL if the file could not be opened [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] - public static extern IntPtr LCOpen(string filePath); + public static extern SafeFileHandle LCOpen(string filePath); /// /// Closes a configuration file opened with {@link #LCOpen}. @@ -371,7 +473,7 @@ public static LSDisplayDevice Create() /// A valid file handle reference /// Returns true on success otherwise false [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] - public static extern bool LCClose(IntPtr hFile); + public static extern bool LCClose(SafeFileHandle hFile); /// /// Retrieves the next none config line (one that does not start with a '*' from a @@ -385,7 +487,7 @@ public static LSDisplayDevice Create() /// Size of buffer /// Returns true on success otherwise false [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] - public static extern bool LCReadNextCommand(IntPtr hFile, StringBuilder buffer, int size); + public static extern bool LCReadNextCommand(SafeFileHandle hFile, StringBuilder buffer, int size); /// /// Retrieves the next config line (one that starts with a '*') that begins with the @@ -402,7 +504,7 @@ public static LSDisplayDevice Create() /// Size of buffer /// Returns true on success otherwise false [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] - public static extern bool LCReadNextConfig(IntPtr hFile, string config, StringBuilder buffer, int size); + public static extern bool LCReadNextConfig(SafeFileHandle hFile, string config, StringBuilder buffer, int size); /// /// Retrieves the next line from a configuration file. The entire line (including the setting name) is placed in the buffer. @@ -415,7 +517,7 @@ public static LSDisplayDevice Create() /// Size of buffer /// Returns true on success otherwise false [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] - public static extern bool LCReadNextLine(IntPtr hFile, StringBuilder buffer, int size); + public static extern bool LCReadNextLine(SafeFileHandle hFile, StringBuilder buffer, int size); /// /// Parses and retrieves the values in a config line (one that starts with a '*') that begins with the @@ -580,7 +682,7 @@ public static LSDisplayDevice Create() /// Default value /// Max value /// - [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] public static extern int GetRCCoordinate(string settingName, int defaultVal, int maxVal); /// @@ -590,7 +692,7 @@ public static LSDisplayDevice Create() /// Default value /// Max value /// - [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl)] public static extern int ParseCoordinate(string line, int defaultVal, int maxVal); /// @@ -737,7 +839,16 @@ public static LSDisplayDevice Create() /// the callback method associated with the command /// Returns true on success otherwise false [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] - public static extern bool AddBangCommand(string command, [MarshalAs(UnmanagedType.FunctionPtr)] Delegate commandDelegate); + public static extern bool AddBangCommand(string command, [MarshalAs(UnmanagedType.FunctionPtr)] BangCommandDelegate commandDelegate); + + /// + /// Registers bang commands + /// + /// the command identifier that starts with an exclamation point (!) + /// the callback method associated with the command + /// Returns true on success otherwise false + [DllImport(LSAPI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "AddBangCommandExW")] + public static extern bool AddBangCommand(string command, [MarshalAs(UnmanagedType.FunctionPtr)] BangCommandDelegate2 commandDelegate); /// /// Removes a bang command from the list. From bc24dbbf47d2f81c45742457a928ffe2a8b53a0a Mon Sep 17 00:00:00 2001 From: Donelle Sanders Jr Date: Wed, 11 Jan 2017 22:16:30 -0600 Subject: [PATCH 05/14] Added ReadMe file --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..a218dca --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# LiteStep +LiteStep Alternative Shell is a replacement shell for the standard Windows® Explorer shell originally created by Francis Gastellu. + +This fork focuses on the interoperability of Litestep and the [.NET Framework].(https://www.microsoft.com/net/framework) + +## Installation + +Please refer to the official [installation guide](http://litestep.info/overview/litestep-manual.html) for information on how to setup and configure Litestep + +## Documentation + +Coming Soon + +## LICENSE + +LiteStep is released under the GNU General Public License Version 2. [link](docs/license.txt) + +## Questions? + +If you have any questions or comments please feel free to drop me a line :-). + +Email: +Follow Me: [@DonelleJr](https://twitter.com/DonelleJr) From 0e61a81c0bdb5af9c7a8a086b5d39c775a9faa89 Mon Sep 17 00:00:00 2001 From: Donelle Sanders Jr Date: Wed, 11 Jan 2017 22:17:07 -0600 Subject: [PATCH 06/14] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a218dca..0316ea8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # LiteStep LiteStep Alternative Shell is a replacement shell for the standard Windows® Explorer shell originally created by Francis Gastellu. -This fork focuses on the interoperability of Litestep and the [.NET Framework].(https://www.microsoft.com/net/framework) +This fork focuses on the interoperability of Litestep and the [.NET Framework](https://www.microsoft.com/net/framework). ## Installation From f1df8fbb5e980a14bcbb438c7991e71018c73b85 Mon Sep 17 00:00:00 2001 From: Donelle Sanders Jr Date: Thu, 12 Jan 2017 22:05:29 -0600 Subject: [PATCH 07/14] Update README.md --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0316ea8..47846ee 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,16 @@ Please refer to the official [installation guide](http://litestep.info/overview/ ## Documentation -Coming Soon +As mentioned above this version of Litestep is focused on the .NET Framework and the following are descriptions of the configurations that should be present in the **step.rc** in order to use .NET. + + ; Set the version of the .NET Runtime that Litestep will use to load modules + ; If the setting is omitted the default runtime is v2.0.50727 + LSCLRVersion v4.0.30319 + + ; Loading modules are the same as described in the Litestep manual + ; To load a module built using the .NET Framework append the "clr" token after the module path + LoadModule $LiteStepDir$HelloCLR.dll clr + ## LICENSE From ee1253c1cd2382e92639d7f2bbca923c7d976c87 Mon Sep 17 00:00:00 2001 From: Donelle Sanders Jr Date: Thu, 12 Jan 2017 22:45:03 -0600 Subject: [PATCH 08/14] Update README.md --- README.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 47846ee..6ded534 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,9 @@ Please refer to the official [installation guide](http://litestep.info/overview/ ## Documentation -As mentioned above this version of Litestep is focused on the .NET Framework and the following are descriptions of the configurations that should be present in the **step.rc** in order to use .NET. +#### Step.rc + +As mentioned above this version of Litestep is focused on the .NET Framework and the following are descriptions of the configurations that should be present in the `step.rc` in order to use .NET. ; Set the version of the .NET Runtime that Litestep will use to load modules ; If the setting is omitted the default runtime is v2.0.50727 @@ -19,6 +21,65 @@ As mentioned above this version of Litestep is focused on the .NET Framework and ; To load a module built using the .NET Framework append the "clr" token after the module path LoadModule $LiteStepDir$HelloCLR.dll clr + +#### .NET Module + +Now that you know how to configure Litestep to load the .NET Runtime the following demonstrates how to create a module with the .NET Framework. The Litestep SDK comes with a library called Lsapi# _(pronounced LSAPI-sharp)_ which is a C# binding for Litestep's API that will enable modules to interact with the shell. + +Following is a list of requirements in order for your module to be loaded by the shell + +1. Add the LsapiSharp assembly as a reference to your project +2. Name the assembly and the entry point namespace the same (ie. MyModule.dll and namespace MyModule {}) +3. The entry point class name must be called **LSModule** with two methods called **initModule** and **quitModule** respectively + +#### Example HelloCLR.dll + +```c# +using System; +using System.Runtime.InteropServices; +using static LsapiSharp.NativeMethods; + +namespace HelloCLR +{ + public static class LSModule + { + const string BANG_COMMAND = "!HelloClr"; + + // Implements the !Hello bang command + static BangCommandDelegate BangHello = (sender, cmd) => + { + LSLog(LS_LOG_DEBUG, typeof(LSModule).FullName, "BangHello called"); + MessageBox(IntPtr.Zero, "Hello, Litestep!", typeof(LSModule).FullName, 0); + }; + + /// + /// Litestep calls this function after it loads the module. This is where the + /// module should register bang commands and create windows. If initialization + /// succeeds, return zero. If an error occurs, return a nonzero value. + /// + /// + /// + public static void initModule(Int32 hWndMain, String appPath) + { + LSLog(LS_LOG_DEBUG, typeof(LSModule).FullName, "initModule called"); + AddBangCommand(BANG_COMMAND, BangHello); + } + + /// + /// Litestep calls this function before it unloads the module. This function + /// should unregister bang commands and destroy windows. + /// + public static void quitModule() + { + LSLog(LS_LOG_DEBUG, typeof(LSModule).FullName, "quitModule called"); + RemoveBangCommand(BANG_COMMAND); + } + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + static extern int MessageBox(IntPtr hWnd, String text, String caption, int options); + } +} +``` ## LICENSE From a522f5630079698f6e6c76b5a4fae0a0f136d132 Mon Sep 17 00:00:00 2001 From: nerd Date: Thu, 12 Jan 2017 23:09:57 -0600 Subject: [PATCH 09/14] Modified the LsapiSharp project to build x86 & x64 correctly as well as adding the LsapiSharp assemblies to the sdk folder --- LsapiSharp/LsapiSharp.csproj | 1 + litestep.sln | 16 ++++++++-------- sdk/lib/LsapiSharp.dll | Bin 0 -> 13824 bytes sdk/lib/LsapiSharp64.dll | Bin 0 -> 12800 bytes 4 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 sdk/lib/LsapiSharp.dll create mode 100644 sdk/lib/LsapiSharp64.dll diff --git a/LsapiSharp/LsapiSharp.csproj b/LsapiSharp/LsapiSharp.csproj index a84c4ba..cc7038e 100644 --- a/LsapiSharp/LsapiSharp.csproj +++ b/LsapiSharp/LsapiSharp.csproj @@ -30,6 +30,7 @@ TRACE prompt 4 + x64 x64 diff --git a/litestep.sln b/litestep.sln index aa12e14..3c50341 100644 --- a/litestep.sln +++ b/litestep.sln @@ -167,10 +167,10 @@ Global {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Debug|x64.Build.0 = Debug|x64 {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|Any CPU.ActiveCfg = Release|Any CPU {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|Any CPU.Build.0 = Release|Any CPU - {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|Win32.ActiveCfg = Release|Any CPU - {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|Win32.Build.0 = Release|Any CPU - {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|x64.ActiveCfg = Release|Any CPU - {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|x64.Build.0 = Release|Any CPU + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|Win32.ActiveCfg = Release|x86 + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|Win32.Build.0 = Release|x86 + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|x64.ActiveCfg = Release|x64 + {7F8140DC-7815-4368-94F8-A7ED7CF04A2A}.Release|x64.Build.0 = Release|x64 {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|Any CPU.Build.0 = Debug|Any CPU {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|Win32.ActiveCfg = Debug|x86 @@ -179,10 +179,10 @@ Global {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Debug|x64.Build.0 = Debug|x64 {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|Any CPU.ActiveCfg = Release|Any CPU {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|Any CPU.Build.0 = Release|Any CPU - {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|Win32.ActiveCfg = Release|Any CPU - {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|Win32.Build.0 = Release|Any CPU - {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|x64.ActiveCfg = Release|Any CPU - {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|x64.Build.0 = Release|Any CPU + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|Win32.ActiveCfg = Release|x86 + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|Win32.Build.0 = Release|x86 + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|x64.ActiveCfg = Release|x64 + {580B3CBE-9E12-41A2-B723-6CE9BBCB7527}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sdk/lib/LsapiSharp.dll b/sdk/lib/LsapiSharp.dll new file mode 100644 index 0000000000000000000000000000000000000000..4cff2e7a470b68c84f5d4478ddc8cdebc98cd29c GIT binary patch literal 13824 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 HXW;(;xS^|y literal 0 HcmV?d00001 diff --git a/sdk/lib/LsapiSharp64.dll b/sdk/lib/LsapiSharp64.dll new file mode 100644 index 0000000000000000000000000000000000000000..355d661f3b538d382550d055eb7d4895fb858303 GIT binary patch literal 12800 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 Date: Sun, 15 Jan 2017 15:15:45 -0600 Subject: [PATCH 10/14] Added more litestep messages definitions to LsapiSharp --- LsapiSharp/NativeMethods.cs | 285 ++++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) diff --git a/LsapiSharp/NativeMethods.cs b/LsapiSharp/NativeMethods.cs index f042501..c2d8458 100644 --- a/LsapiSharp/NativeMethods.cs +++ b/LsapiSharp/NativeMethods.cs @@ -34,6 +34,11 @@ public static class NativeMethods { private const string LSAPI = "lsapi.dll"; + /// + /// Some "magical" shit that the main litestep window uses + /// + public const int MagicDword = 0x49474541; + /// /// Logging Level Error /// @@ -234,6 +239,286 @@ public static class NativeMethods /// public const int LM_REFRESH = 9305; + /// + /// FILL ME IN + /// + public const int LM_VWMUP = 9350; + + /// + /// FILL ME IN + /// + public const int LM_VWMDOWN = 9351; + + /// + /// FILL ME IN + /// + public const int LM_VWMLEFT = 9352; + + /// + /// FILL ME IN + /// + public const int LM_VWMRIGHT = 9353; + + /// + /// FILL ME IN + /// + public const int LM_VWMNAV = 9354; + + /// + /// FILL ME IN + /// + public const int LM_SWITCHTON = 9355; + + /// + /// FILL ME IN + /// + public const int LM_ISSTICKY = 9356; + + /// + /// FILL ME IN + /// + public const int LM_STICK = 9357; + + /// + /// FILL ME IN + /// + public const int LM_UNSTICK = 9358; + + /// + /// FILL ME IN + /// + public const int LM_LISTDESKTOPS = 9359; + + /// + /// FILL ME IN + /// + public const int LM_DESKTOPINFO = 9360; + + /// + /// FILL ME IN + /// + public const int LM_GETDESKTOPOF = 9361; + + /// + /// Internal + /// + private const int LM_SHELLHOOK = 9500; + + /// + /// FILL ME IN + /// + public const int LM_WINDOWCREATED = LM_SHELLHOOK + 1 /*HSHELL_WINDOWCREATED*/; + + /// + /// FILL ME IN + /// + public const int LM_WINDOWDESTROYED = LM_SHELLHOOK + 2 /*HSHELL_WINDOWDESTROYED*/; + + /// + /// FILL ME IN + /// + public const int LM_ACTIVATESHELLWINDOW = LM_SHELLHOOK + 3 /*HSHELL_ACTIVATESHELLWINDOW*/; + + /// + /// FILL ME IN + /// + public const int LM_WINDOWACTIVATED = LM_SHELLHOOK + 4 /*HSHELL_WINDOWACTIVATED*/; + + /// + /// FILL ME IN + /// + public const int LM_GETMINRECT = LM_SHELLHOOK + 5 /*HSHELL_GETMINRECT*/; + + /// + /// FILL ME IN + /// + public const int LM_REDRAW = LM_SHELLHOOK + 6 /*HSHELL_REDRAW*/; + + /// + /// FILL ME IN + /// + public const int LM_TASKMAN = LM_SHELLHOOK + 7 /*HSHELL_TASKMAN*/; + + /// + /// FILL ME IN + /// + public const int LM_LANGUAGE = LM_SHELLHOOK + 8 /*HSHELL_LANGUAGE*/; + + /// + /// FILL ME IN + /// + public const int LM_ACCESSIBILITYSTATE = LM_SHELLHOOK + 11 /*HSHELL_ACCESSIBILITYSTATE*/; + + /// + /// FILL ME IN + /// + public const int LM_APPCOMMAND = LM_SHELLHOOK + 12 /*HSHELL_APPCOMMAND*/; + + /// + /// FILL ME IN + /// + public const int LM_WINDOWREPLACED = LM_SHELLHOOK + 13 /*HSHELL_WINDOWREPLACED*/; + + /// + /// FILL ME IN + /// + public const int LM_WINDOWREPLACING = LM_SHELLHOOK + 14 /*HSHELL_WINDOWREPLACING*/; + + /// + /// FILL ME IN + /// + public const int LM_MONITORCHANGED = LM_SHELLHOOK + 16 /*HSHELL_MONITORCHANGED*/; + + /// + /// FILL ME IN + /// + public const int LM_FULLSCREENACTIVATED = 32768; + + /// + /// FILL ME IN + /// + public const int LM_FULLSCREENDEACTIVATED = 32769; + + /// + /// FILL ME IN + /// + public const int LM_TASK_SETPROGRESSSTATE = 33024; + + /// + /// FILL ME IN + /// + public const int LM_TASK_SETPROGRESSVALUE = 33025; + + /// + /// FILL ME IN + /// + public const int LM_TASK_MARKASACTIVE = 33026; + + /// + /// FILL ME IN + /// + public const int LM_TASK_REGISTERTAB = 33027; + + /// + /// FILL ME IN + /// + public const int LM_TASK_UNREGISTERTAB = 33028; + + /// + /// FILL ME IN + /// + public const int LM_TASK_SETACTIVETAB = 33029; + + /// + /// FILL ME IN + /// + public const int LM_TASK_SETTABORDER = 33030; + + /// + /// FILL ME IN + /// + public const int LM_TASK_SETTABPROPERTIES = 33031; + + /// + /// FILL ME IN + /// + public const int LM_TASK_SETOVERLAYICON = 33032; + + /// + /// FILL ME IN + /// + public const int LM_TASK_SETOVERLAYICONDESC = 33033; + + /// + /// FILL ME IN + /// + public const int LM_TASK_SETTHUMBNAILTOOLTIP = 33034; + + /// + /// FILL ME IN + /// + public const int LM_TASK_SETTHUMBNAILCLIP = 33035; + + /// + /// FILL ME IN + /// + public const int LM_TASK_THUMBBARADDBUTTONS = 33036; + + /// + /// FILL ME IN + /// + public const int LM_TASK_THUMBBARUPDATEBUTTONS = 33037; + + /// + /// FILL ME IN + /// + public const int LM_TASK_THUMBBARSETIMAGELIST = 33038; + + /// + /// FILL ME IN + /// + public const int LM_UNLOADMODULEW = 33281; + + /// + /// FILL ME IN + /// + public const int LM_RELOADMODULEW = 33282; + + /// + /// FILL ME IN + /// + public const int LM_GETREVIDW = 33283; + + /// + /// FILL ME IN + /// + public const int LM_BANGCOMMANDW = 33284; + + /// + /// FILL ME IN + /// + public const int LM_SYSTRAYW = 33285; + + /// + /// FILL ME IN + /// + public const int LM_WALLPAPERCHANGE = 33286; + + /// + /// Win32 representation of THUMBBUTTON value + /// + [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)] + public struct LSThumbButton + { + /// + /// THUMBBUTTONMASK + /// + public int Mask; + public int Id; + public int Bitmap; + public IntPtr hIcon; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 259)] + public string Tip; + + /// + /// THUMBBUTTONFLAGS + /// + public int Flags; + } + + /// + /// Win32 representation of THUMBBUTTONLIST value + /// + [StructLayout(LayoutKind.Sequential)] + public struct LSThumbButtonList + { + int Buttons; + + [MarshalAs(UnmanagedType.LPStruct)] + LSThumbButton Button; + } + /// /// Win32 representation of DWORD value /// From 9a9417b5ae639999822567a44c285c5cba972c42 Mon Sep 17 00:00:00 2001 From: nerd Date: Sun, 27 May 2018 13:54:43 -0500 Subject: [PATCH 11/14] Fixed Release mode to build properly it was failing --- litestep/litestep.vcxproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litestep/litestep.vcxproj b/litestep/litestep.vcxproj index 29197a9..8132491 100644 --- a/litestep/litestep.vcxproj +++ b/litestep/litestep.vcxproj @@ -106,9 +106,10 @@ LSAPI_PRIVATE;%(PreprocessorDefinitions) + false - advapi32.lib;gdi32.lib;ole32.lib;shell32.lib;shlwapi.lib;userenv.lib;uuid.lib;%(AdditionalDependencies) + advapi32.lib;gdi32.lib;ole32.lib;oleaut32.lib;shell32.lib;shlwapi.lib;userenv.lib;uuid.lib;mscoree.lib;comsuppw.lib;%(AdditionalDependencies) PerMonitorHighDPIAware From e78c962624635fbe5b6af9ec7f1910c2d45902db Mon Sep 17 00:00:00 2001 From: Donelle Sanders Jr Date: Sat, 23 Jun 2018 18:10:56 -0700 Subject: [PATCH 12/14] Completed .NET Core integration (#1) * Started work on integrating dotnet core * Able to load .NET Core runtime inside of Litestep * Refactored CLRModule abit --- .gitignore | 3 +- LsapiSharp/LsapiSharp.csproj | 9 + LsapiSharp/LsapiSharp.pfx | Bin 0 -> 1764 bytes LsapiSharpCore/AssemblyInfo.cs | 6 + LsapiSharpCore/LsapiSharp.snk | Bin 0 -> 596 bytes LsapiSharpCore/LsapiSharpCore.csproj | 30 + README.md | 12 +- litestep.sln | 54 +- litestep/CLRModule.cpp | 379 +-- litestep/CLRModule.h | 40 +- litestep/CoreCLRModule.cpp | 428 +++ litestep/CoreCLRModule.h | 81 + litestep/Module.cpp | 11 +- litestep/ModuleManager.cpp | 4 + litestep/litestep.vcxproj | 6 +- litestep/mscoree_core.h | 2930 +++++++++++++++++ lsapi/lsapidefines.h | 1 + sdk/examples/HelloCoreCLR/HelloCoreCLR.csproj | 12 + sdk/examples/HelloCoreCLR/LSModule.cs | 67 + sdk/lib/LsapiSharpCore64.dll | Bin 0 -> 16384 bytes utility/safeutility.h | 59 + utility/utility.vcxproj | 1 + 22 files changed, 3926 insertions(+), 207 deletions(-) create mode 100644 LsapiSharp/LsapiSharp.pfx create mode 100644 LsapiSharpCore/AssemblyInfo.cs create mode 100644 LsapiSharpCore/LsapiSharp.snk create mode 100644 LsapiSharpCore/LsapiSharpCore.csproj create mode 100644 litestep/CoreCLRModule.cpp create mode 100644 litestep/CoreCLRModule.h create mode 100644 litestep/mscoree_core.h create mode 100644 sdk/examples/HelloCoreCLR/HelloCoreCLR.csproj create mode 100644 sdk/examples/HelloCoreCLR/LSModule.cs create mode 100644 sdk/lib/LsapiSharpCore64.dll create mode 100644 utility/safeutility.h diff --git a/.gitignore b/.gitignore index a8f95db..91b4ef0 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ Debug* *.aps .vs *.VC* -packages \ No newline at end of file +packages +obj diff --git a/LsapiSharp/LsapiSharp.csproj b/LsapiSharp/LsapiSharp.csproj index cc7038e..b4da6a7 100644 --- a/LsapiSharp/LsapiSharp.csproj +++ b/LsapiSharp/LsapiSharp.csproj @@ -59,6 +59,12 @@ prompt MinimumRecommendedRules.ruleset + + true + + + LsapiSharp.pfx + @@ -66,6 +72,9 @@ + + +