diff --git a/.gitignore b/.gitignore index bb6b332..e1d2199 100644 --- a/.gitignore +++ b/.gitignore @@ -114,6 +114,7 @@ UpgradeLog*.XML *.pyc Visual Studio Project Template C#/$projectname$.sln -NppCSharpPluginPack/.vs +**/.vs +!NppCSharpPluginPack/Dependencies/x64 NppCSharpPluginPack/UpgradeLog.htm !testfiles/**/*example*.log \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index bc5226f..13f12d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Avoid plugin crash when too-large int values are entered in the selection-remembering form. - Holding down `Enter` in a multiline textbox does not add multiple new lines; it only adds one newline on keyup. +## [0.0.4] - (UNRELEASED) YYYY-MM-DD + +### Added + +1. Make it much easier to [include third-party dependencies](/docs/README.md#loading-third-party-dependencies) in your plugin. + ## [0.0.3] - 2024-02-26 ### Added diff --git a/ExampleDependency/ExampleClass.cs b/ExampleDependency/ExampleClass.cs new file mode 100644 index 0000000..addd377 --- /dev/null +++ b/ExampleDependency/ExampleClass.cs @@ -0,0 +1,31 @@ +namespace ExampleDependency +{ + public class ExampleClass + { + public static int ExampleClassInstancesCreated = 0; + public string Name = ""; + public int InstancesCreatedBeforeThis { get; private set; } + + public ExampleClass(string name) + { + Name = name; + InstancesCreatedBeforeThis = ExampleClassInstancesCreated; + ExampleClassInstancesCreated = Add(ExampleClassInstancesCreated, 1); + } + + public override string ToString() + { + return $"ExampleClass(\"{Name}\") ({InstancesCreatedBeforeThis} instances created before it)"; + } + + public static int Add(int x, int y) + { + return x + y; + } + + public static int Subtract(int x, int y) + { + return x - y; + } + } +} diff --git a/ExampleDependency/ExampleDependency.csproj b/ExampleDependency/ExampleDependency.csproj new file mode 100644 index 0000000..0d60b35 --- /dev/null +++ b/ExampleDependency/ExampleDependency.csproj @@ -0,0 +1,57 @@ + + + + Debug + x86 + net4.8 + AnyCPU;x64;x86 + + + true + full + false + bin\Debug + DEBUG;TRACE + prompt + 4 + x86 + true + + + none + true + bin\Release + prompt + 4 + 512 + x86 + AllRules.ruleset + true + + + true + full + false + bin\Debug-x64 + DEBUG;TRACE + prompt + 4 + x64 + true + + + none + true + bin\Release-x64 + prompt + 4 + 512 + x64 + AllRules.ruleset + true + + + + + + diff --git a/ExampleDependency/ExampleDependency.sln b/ExampleDependency/ExampleDependency.sln new file mode 100644 index 0000000..8f199b0 --- /dev/null +++ b/ExampleDependency/ExampleDependency.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34330.188 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExampleDependency", "ExampleDependency.csproj", "{76493ED8-B97B-4C27-91EE-CE065270D87F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {76493ED8-B97B-4C27-91EE-CE065270D87F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {76493ED8-B97B-4C27-91EE-CE065270D87F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76493ED8-B97B-4C27-91EE-CE065270D87F}.Debug|x64.ActiveCfg = Debug|x64 + {76493ED8-B97B-4C27-91EE-CE065270D87F}.Debug|x64.Build.0 = Debug|x64 + {76493ED8-B97B-4C27-91EE-CE065270D87F}.Debug|x86.ActiveCfg = Debug|x86 + {76493ED8-B97B-4C27-91EE-CE065270D87F}.Debug|x86.Build.0 = Debug|x86 + {76493ED8-B97B-4C27-91EE-CE065270D87F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {76493ED8-B97B-4C27-91EE-CE065270D87F}.Release|Any CPU.Build.0 = Release|Any CPU + {76493ED8-B97B-4C27-91EE-CE065270D87F}.Release|x64.ActiveCfg = Release|x64 + {76493ED8-B97B-4C27-91EE-CE065270D87F}.Release|x64.Build.0 = Release|x64 + {76493ED8-B97B-4C27-91EE-CE065270D87F}.Release|x86.ActiveCfg = Release|Any CPU + {76493ED8-B97B-4C27-91EE-CE065270D87F}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5D7E4DE6-C9EA-4A10-A65B-AC464D1711B7} + EndGlobalSection +EndGlobal diff --git a/NppCSharpPluginPack/Dependencies/x64/ExampleDependency.dll b/NppCSharpPluginPack/Dependencies/x64/ExampleDependency.dll new file mode 100644 index 0000000..9257d53 Binary files /dev/null and b/NppCSharpPluginPack/Dependencies/x64/ExampleDependency.dll differ diff --git a/NppCSharpPluginPack/Dependencies/x86/ExampleDependency.dll b/NppCSharpPluginPack/Dependencies/x86/ExampleDependency.dll new file mode 100644 index 0000000..9fbdb27 Binary files /dev/null and b/NppCSharpPluginPack/Dependencies/x86/ExampleDependency.dll differ diff --git a/NppCSharpPluginPack/Forms/PopupDialog.cs b/NppCSharpPluginPack/Forms/PopupDialog.cs index a8d1488..5fbcd5f 100644 --- a/NppCSharpPluginPack/Forms/PopupDialog.cs +++ b/NppCSharpPluginPack/Forms/PopupDialog.cs @@ -1,6 +1,7 @@ using NppDemo.Utils; using Kbg.NppPluginNET; using System.Windows.Forms; +using ExampleDependency; namespace NppDemo.Forms { @@ -21,10 +22,12 @@ private void ComboBox1EnabledCheckBox_CheckedChanged(object sender, System.Event private void button1_Click(object sender, System.EventArgs e) { + string msg = ComboBox1.Enabled ? $"ComboBox1 selected value = {ComboBox1.Text}" : "ComboBox1 is disabled"; - MessageBox.Show(msg); + var exampleClassMember = new ExampleClass(msg); + MessageBox.Show(exampleClassMember.ToString()); } /// diff --git a/NppCSharpPluginPack/Forms/SelectionRememberingForm.cs b/NppCSharpPluginPack/Forms/SelectionRememberingForm.cs index 68e4c25..4ac16e4 100644 --- a/NppCSharpPluginPack/Forms/SelectionRememberingForm.cs +++ b/NppCSharpPluginPack/Forms/SelectionRememberingForm.cs @@ -1,16 +1,11 @@ using NppDemo.Utils; using System; using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; using Kbg.NppPluginNET; using System.IO; -using System.Runtime.CompilerServices; namespace NppDemo.Forms { diff --git a/NppCSharpPluginPack/Main.cs b/NppCSharpPluginPack/Main.cs index aa6b80d..db0573f 100644 --- a/NppCSharpPluginPack/Main.cs +++ b/NppCSharpPluginPack/Main.cs @@ -17,6 +17,7 @@ using System.Text.RegularExpressions; using System.Text; using System.IO; +using System.Reflection; namespace Kbg.NppPluginNET { @@ -50,6 +51,9 @@ class Main static internal void CommandMenuInit() { + // first make it so that all references to any third-party dependencies point to the correct location + // see https://github.com/oleg-shilo/cs-script.npp/issues/66#issuecomment-1086657272 for more info + AppDomain.CurrentDomain.AssemblyResolve += LoadDependency; // Initialization of your plugin commands // with function : @@ -97,7 +101,19 @@ static internal void CommandMenuInit() } - static internal void SetToolBarIcons() + private static Assembly LoadDependency(object sender, ResolveEventArgs args) + { + // Path.GetFullPath(".") will return the path to the Notepad++ executable + // I have *very rarely* seen it instead return another path, but in general this should work properly. + // Unfortunately Npp.notepad.GetNppPath() cannot be used here for reasons discussed in this comment by rdipardo: + // https://github.com/molsonkiko/NppCSharpPluginPack/issues/5#issuecomment-1982167513 + string assemblyFile = Path.Combine(Path.GetFullPath("."), "plugins", PluginName, new AssemblyName(args.Name).Name) + ".dll"; + if (File.Exists(assemblyFile)) + return Assembly.LoadFrom(assemblyFile); + return null; + } + + static internal void SetToolBarIcons() { string iconsToUseChars = settings.toolbar_icons.ToLower(); var iconInfo = new (Bitmap bmp, Icon icon, Icon iconDarkMode, int id, char representingChar)[] diff --git a/NppCSharpPluginPack/NppCSharpPluginPack.csproj b/NppCSharpPluginPack/NppCSharpPluginPack.csproj index 3179164..b7f65b1 100644 --- a/NppCSharpPluginPack/NppCSharpPluginPack.csproj +++ b/NppCSharpPluginPack/NppCSharpPluginPack.csproj @@ -145,6 +145,21 @@ + + + + + + + + + + + + + + + @@ -153,6 +168,10 @@ + + + @(DEPENDENCY_DIR)\ExampleDependency.dll + @@ -191,37 +210,32 @@ - + - + + + + + - - - - - - + + + + + + + + + + + + \ No newline at end of file diff --git a/NppCSharpPluginPack/PluginInfrastructure/NppPluginNETHelper.cs b/NppCSharpPluginPack/PluginInfrastructure/NppPluginNETHelper.cs index e1fc988..a15ac00 100644 --- a/NppCSharpPluginPack/PluginInfrastructure/NppPluginNETHelper.cs +++ b/NppCSharpPluginPack/PluginInfrastructure/NppPluginNETHelper.cs @@ -175,11 +175,14 @@ public enum DockMgrMsg : uint //nmhdr.hwndFrom = hwndNpp; //nmhdr.IdFrom = ctrlIdNpp; - DMN_DOCK = (DMN_FIRST + 2), - DMN_FLOAT = (DMN_FIRST + 3) - //nmhdr.Code = DWORD(DMN_XXX, int newContainer); - //nmhdr.hwndFrom = hwndNpp; - //nmhdr.IdFrom = ctrlIdNpp; + DMN_DOCK = (DMN_FIRST + 2), + DMN_FLOAT = (DMN_FIRST + 3), + DMN_SWITCHIN = (DMN_FIRST + 4), + DMN_SWITCHOFF = (DMN_FIRST + 5), + DMN_FLOATDROPPED = (DMN_FIRST + 6), + //nmhdr.Code = DWORD(DMN_XXX, int newContainer); + //nmhdr.hwndFrom = hwndNpp; + //nmhdr.IdFrom = ctrlIdNpp; } [StructLayout(LayoutKind.Sequential)] diff --git a/NppCSharpPluginPack/Properties/AssemblyInfo.cs b/NppCSharpPluginPack/Properties/AssemblyInfo.cs index 86dc2a4..7a1427c 100644 --- a/NppCSharpPluginPack/Properties/AssemblyInfo.cs +++ b/NppCSharpPluginPack/Properties/AssemblyInfo.cs @@ -28,5 +28,5 @@ // Build Number // Revision // -[assembly: AssemblyVersion("0.0.3.0")] -[assembly: AssemblyFileVersion("0.0.3.0")] +[assembly: AssemblyVersion("0.0.3.1")] +[assembly: AssemblyFileVersion("0.0.3.1")] diff --git a/PluginPackArchitecture.md b/PluginPackArchitecture.md index d7f5464..41d914b 100644 --- a/PluginPackArchitecture.md +++ b/PluginPackArchitecture.md @@ -35,7 +35,7 @@ Many of the files in the [PluginInfrastructure folder](/NppCSharpPluginPack/Plug The way to regenerate the auto-generated portions of these code is to download the Notepad++ source code from master and run the Python scripts in [ToolsForMaintainersOfTheProjectTemplate](/ToolsForMaintainersOfTheProjectTemplate/) folder. Read the documentation of those scripts if you're still unsure how to proceed. -## Plugins using this pluginpack (or the original) +## Plugins using this pluginpack (or kbilsted's original) * https://github.com/kbilsted/NppPluginGuidHelper * https://github.com/zkirkland/FirstUpper diff --git a/docs/README.md b/docs/README.md index 5070162..0a7d0ce 100644 --- a/docs/README.md +++ b/docs/README.md @@ -137,6 +137,29 @@ Here are some important ways that the popup dialog differs from other dialogs: ![Popup dialog](/docs/popup%20dialog.PNG) +## Loading third-party dependencies ## + +There are two ways that I (Mark J. Olson) know of to incorporate third-party dependencies into the project, using [NuGet](https://www.nuget.org/) and loading locally installed DLL's. Each will be covered below. + +Regardless of which type of dependency you use, __make sure that the depenendencies work for both 32-bit and 64-bit Notepad++.__ + +Note that the first version of this project to directly support 3rd-party DLL's in this way is `0.0.3.1`. + +### Including NuGet packages in your project ### + +I have tested this (as of version `0.0.3.1`) by installing [ExcelDataReader 3.6.0](https://www.nuget.org/packages/ExcelDataReader/3.6.0), adding some ExcelDataReader method calls to the [PopupDialog](#popup-dialog), and verifying that the method calls run successfully. + +1. Install the NuGet package. In Visual Studio, this entails going to `Project->Manage NuGet packages...` from the main menu, then installing a package. +2. Build the project as normal. The NuGet package should be usable as expected. + +### Including locally installed DLL's in your project ### + +This is demonstrated with the [ExampleDependency](/ExampleDependency) example dependency, which is referenced in the [Popup Dialog](/NppCSharpPluginPack/Forms/PopupDialog.cs). + +1. Add a *64-bit* build of the DLL to the [NppCSharpPluginPack\Dependencies\x64](/NppCSharpPluginPack/Dependencies/x64) directory. +2. Add a *32-bit* build of the DLL to the [NppCSharpPluginPackDependencies\x86](/NppCSharpPluginPack/Dependencies/x86) directory. +3. Build the project for 64-bit and 32-bit Notepad++. Verify that any 3rd-party DLL's are usable as normal. + ## Running tests ## I (Mark J. Olson) believe that without a robust automated test suite, it is hard to make major changes to any large project without breaking things unexpectedly. Over the course of developing my JsonTools plugin, I developed a strategy for running automated tests and performance benchmarks inside of Notepad++. diff --git a/most recent errors.txt b/most recent errors.txt index 0655164..95e65f2 100644 --- a/most recent errors.txt +++ b/most recent errors.txt @@ -1,4 +1,4 @@ -Test results for CSharpPluginPack v0.0.2.4 on Notepad++ 8.6.4 64bit +Test results for CSharpPluginPack v0.0.3.1 on Notepad++ 8.6.4 64bit NOTE: Ctrl-F (regular expressions *on*) for "Failed [1-9]\d*" to find all failed tests No tests failed ========================= @@ -21,8 +21,8 @@ Testing Performance of something Performance tests for My benchmarks (test1) ========================= -To run query "foo" on file of size 7913 into took 0 +/- 0 ms over 32 trials -Query times (ms): 0.002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +To run query "foo" on file of size 7913 into took 0 +/- 0.001 ms over 32 trials +Query times (ms): 0.003, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 Preview of result: Preview of result ========================= Performance tests for My benchmarks (test2)