diff --git a/Shared/Scintilla.cs b/Shared/Scintilla.cs index 0ae27a5..f5d4b75 100644 --- a/Shared/Scintilla.cs +++ b/Shared/Scintilla.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Drawing; @@ -22,79 +23,71 @@ public class Scintilla : Control { static Scintilla() { - var basePath = LocateNativeDllDirectory(); - modulePathScintilla = Path.Combine(basePath, "Scintilla.dll"); - modulePathLexilla = Path.Combine(basePath, "Lexilla.dll"); - - try - { - var info = FileVersionInfo.GetVersionInfo(modulePathScintilla); - scintillaVersion = info.ProductVersion ?? info.FileVersion; - info = FileVersionInfo.GetVersionInfo(modulePathLexilla); - lexillaVersion = info.ProductVersion ?? info.FileVersion; - } - catch + List searchedPathList = new List(); + foreach (string path in EnumerateSatelliteLibrarySearchPaths()) { - scintillaVersion = "ERROR"; - lexillaVersion = "ERROR"; - // the path to the following .NET or .NET Framework satellite assemblies exists but the assemblies are not found in the directory. - // (surely a problem in the package itself or in its installation of the project). - throw new InvalidOperationException(@$"Scintilla.NET satellite assemblies not found in {basePath}"); + string scintillaDllPath = Path.Combine(path, "Scintilla.dll"); + string lexillaDllPath = Path.Combine(path, "Lexilla.dll"); + if (File.Exists(scintillaDllPath) && File.Exists(lexillaDllPath)) + { + modulePathScintilla = scintillaDllPath; + modulePathLexilla = lexillaDllPath; + try + { + var info = FileVersionInfo.GetVersionInfo(modulePathScintilla); + scintillaVersion = info.ProductVersion ?? info.FileVersion; + info = FileVersionInfo.GetVersionInfo(modulePathLexilla); + lexillaVersion = info.ProductVersion ?? info.FileVersion; + return; + } + catch + { + searchedPathList.Add(path); + } + } + else + searchedPathList.Add(path); } + + string searchedPaths = string.Join("\n", searchedPathList); + + scintillaVersion = "ERROR"; + lexillaVersion = "ERROR"; + // the path to the following .NET or .NET Framework satellite assemblies exists but the assemblies are not found in the directory. + // (surely a problem in the package itself or in its installation of the project). + throw new InvalidOperationException($"Scintilla.NET satellite assemblies not found in any of the following paths:\n{searchedPaths}"); } - private static string LocateNativeDllDirectory() + public static IEnumerable EnumerateSatelliteLibrarySearchPaths() { // check run-time paths string platform = Environment.Is64BitProcess ? "x64" : "x86"; - Assembly runtimeAssembly = Assembly.GetExecutingAssembly(); - string managedLocation = Path.GetDirectoryName(runtimeAssembly.Location) ?? AppDomain.CurrentDomain.BaseDirectory; - string basePath = Path.Combine(managedLocation, platform); - - if (Directory.Exists(basePath)) - { - return basePath; - } + var runtimeAssembly = Assembly.GetExecutingAssembly(); + string managedLocation = Path.GetDirectoryName(runtimeAssembly.Location) ?? AppDomain.CurrentDomain.BaseDirectory; + yield return Path.Combine(managedLocation, platform); // check design-mode paths string frameworkName = runtimeAssembly?.GetCustomAttribute()?.FrameworkName; + if (frameworkName.Contains("NETFramework")) { - // In.NET Framework, look for the assemblies in the nuget global packages folder - Assembly designtimeAssembly = Assembly.GetAssembly(typeof(Scintilla)); - string nugetScintillaPackageFolder = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + @"\.nuget\packages\scintilla5.net\"; + // In .NET Framework, look for the assemblies in the nuget global packages folder + var designtimeAssembly = Assembly.GetAssembly(typeof(Scintilla)); + string nugetScintillaPackageFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), @".nuget\packages\scintilla5.net"); string nugetScintillaPackageVersion = designtimeAssembly.GetName().Version.ToString(); - basePath = Path.Combine(nugetScintillaPackageFolder + nugetScintillaPackageVersion + @"\build\" + platform); - - if (Directory.Exists(basePath)) - { - return basePath; - } + yield return Path.Combine(nugetScintillaPackageFolder, nugetScintillaPackageVersion, "build", platform); // then check the project folder using the Scintilla.NET assembly location // move up a few levels to the host project folder and append the location nuget used at install string nugetScintillaNETLocation = designtimeAssembly.Location; string nugetScintillaPackageName = designtimeAssembly.GetName().Name; - string rootProjectFolder = Path.GetFullPath(Path.Combine(nugetScintillaNETLocation, @"..\..\..\..\")); - basePath = Path.Combine(rootProjectFolder, @"packages\" + nugetScintillaPackageName + "." + nugetScintillaPackageVersion + @"\build\" + platform); - - if (Directory.Exists(basePath)) - { - return basePath; - } - - throw new InvalidOperationException(@$"Unable to locate the Scintilla.NET satellite assemblies : directory '{basePath}' not found"); + string rootProjectFolder = Path.GetFullPath(Path.Combine(nugetScintillaNETLocation, @"..\..\..\..")); + yield return Path.Combine(rootProjectFolder, "packages", nugetScintillaPackageName + "." + nugetScintillaPackageVersion, "build", platform); } else { // if .NET in design mode - basePath = Path.GetFullPath(Path.Combine(managedLocation, "..", "..", "build", platform)); - if (Directory.Exists(basePath)) - { - return basePath; - } - - throw new InvalidOperationException(@$"Unable to locate the Scintilla.NET satellite assemblies : directory '{basePath}' not found"); + yield return Path.GetFullPath(Path.Combine(managedLocation, @"..\..\build", platform)); } } @@ -1818,7 +1811,8 @@ protected override unsafe void OnHandleCreated(EventArgs e) // ways to solve this, but my favorite is to revoke drag and drop from the // native Scintilla control before base.OnHandleCreated does the standard // processing of AllowDrop. - NativeMethods.RevokeDragDrop(Handle); + if (!this._ScintillaManagedDragDrop) + NativeMethods.RevokeDragDrop(this.Handle); base.OnHandleCreated(e); } @@ -3276,6 +3270,18 @@ public unsafe void ClearRepresentation(string encodedString) #region Properties + /// + /// Gets or sets whether Scintilla's native drag & drop should be used instead of WinForms based one. + /// + /// true if Scintilla's native drag & drop should be used; otherwise, false. The default is false. + [DefaultValue(false)] + [Category("Behaviour")] + [Description("Indicates whether Scintilla's native drag & drop should be used instead of WinForms based one.")] + public bool _ScintillaManagedDragDrop { get; set; } + // Underscore is used so that WinForms Designer sets it before any other + // property. Otherwise ApplyResources gets called on the control before + // the property is set, which then triggers OnHandleCreated before we + // have the final value. /// /// Gets or sets the bi-directionality of the Scintilla control.