diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..015702f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,139 @@ +[*.cs] + +# SA1200: Using directives should be placed correctly +dotnet_diagnostic.SA1200.severity = none + +# SA1600: Elements should be documented +dotnet_diagnostic.SA1600.severity = none + +# SA1400: Access modifier should be declared +dotnet_diagnostic.SA1400.severity = none + +# SA1633: File should have header +dotnet_diagnostic.SA1633.severity = none + +# SA1101: Prefix local calls with this +dotnet_diagnostic.SA1101.severity = none + +# SA1201: Elements should appear in the correct order +dotnet_diagnostic.SA1201.severity = none + +# SA1204: Static elements should appear before instance elements +dotnet_diagnostic.SA1204.severity = none + +# SA1602: Enumeration items should be documented +dotnet_diagnostic.SA1602.severity = none + +# CA1303: Do not pass literals as localized parameters +dotnet_diagnostic.CA1303.severity = none + +# SA0001: XML comment analysis is disabled due to project configuration +dotnet_diagnostic.SA0001.severity = none + +# WTG1001: Do not use the 'private' keyword. +dotnet_diagnostic.WTG1001.severity = warning + +# WTG1002: Use the 'var' keyword instead of an explicit type where possible. +dotnet_diagnostic.WTG1002.severity = warning + +# WTG1003: Do not leave whitespace on the end of the line. +dotnet_diagnostic.WTG1003.severity = warning + +# WTG1004: Indent with tabs rather than spaces. +dotnet_diagnostic.WTG1004.severity = none + +# WTG1005: Use consistent line endings. +dotnet_diagnostic.WTG1005.severity = warning + +# WTG1006: Do not use the 'internal' keyword for non-nested type definitions. +dotnet_diagnostic.WTG1006.severity = warning + +# WTG1007: Do not compare bool to a constant value. +dotnet_diagnostic.WTG1007.severity = warning + +# WTG1008: Do not compare bool to a constant value in an expression. +dotnet_diagnostic.WTG1008.severity = warning + +# WTG1009: Using directives must be ordered by kind. +dotnet_diagnostic.WTG1009.severity = warning + +# WTG1010: Use the 'var' keyword instead of an explicit type where possible. +dotnet_diagnostic.WTG1010.severity = warning + +# WTG1011: Use the 'var' keyword once when deconstructing an object. +dotnet_diagnostic.WTG1011.severity = warning + +# WTG1012: Use the 'var' keyword instead of an explicit type where possible. +dotnet_diagnostic.WTG1012.severity = warning + +# WTG1013: Don't use tuple types in public interfaces. +dotnet_diagnostic.WTG1013.severity = warning + +# WTG1014: Don't nest conditional operators. +dotnet_diagnostic.WTG1014.severity = warning + +# WTG1015: Conditional operators should not have multiline values. +dotnet_diagnostic.WTG1015.severity = warning + +# WTG1016: Avoid the discard-coalesce-throw pattern. +dotnet_diagnostic.WTG1016.severity = warning + +# WTG1017: Don't define variables that could be confused with discards. +dotnet_diagnostic.WTG1017.severity = warning + +# WTG2001: Do not use ConfigureAwait from an async void method. +dotnet_diagnostic.WTG2001.severity = warning + +# WTG2002: Avoid conditional compilation based on DEBUG. +dotnet_diagnostic.WTG2002.severity = warning + +# WTG2003: Flags enums should specify explicit values. +dotnet_diagnostic.WTG2003.severity = warning + +# WTG2004: This project does not use Code Contracts. +dotnet_diagnostic.WTG2004.severity = warning + +# WTG2005: Use Correct Emit Overload +dotnet_diagnostic.WTG2005.severity = warning + +# WTG2006: Do not pass the Compiled option into static methods on Regex. +dotnet_diagnostic.WTG2006.severity = warning + +# WTG3001: Remove orphaned suppressions. +dotnet_diagnostic.WTG3001.severity = warning + +# WTG3002: Prefer direct member access over linq. +dotnet_diagnostic.WTG3002.severity = warning + +# WTG3003: Prefer direct member access over linq in an expression. +dotnet_diagnostic.WTG3003.severity = warning + +# WTG3004: Prefer Array.Empty() over creating a new empty array. +dotnet_diagnostic.WTG3004.severity = warning + +# WTG3005: Don't call ToString() on a string. +dotnet_diagnostic.WTG3005.severity = warning + +# WTG3006: Prefer nameof over calling ToString on an enum literal. +dotnet_diagnostic.WTG3006.severity = warning + +# WTG3007: Overrides should not simply call base. +dotnet_diagnostic.WTG3007.severity = warning + +# WTG3008: Do not compare value types with null. +dotnet_diagnostic.WTG3008.severity = warning + +# WTG3009: Prefer Task.CompletedTask when applicable. +dotnet_diagnostic.WTG3009.severity = warning + +# WTG3010: Don't await a trivially completed task. +dotnet_diagnostic.WTG3010.severity = warning + +# WTG3101: Do not nest regions. +dotnet_diagnostic.WTG3101.severity = warning + +# WTG3102: Regions should not split structures. +dotnet_diagnostic.WTG3102.severity = warning + +# WTG3103: Conditional compilation directives should not split structures. +dotnet_diagnostic.WTG3103.severity = warning diff --git a/Notepad.Extensions.Logging.FunctionalTest/Notepad.Extensions.Logging.FunctionalTest.csproj b/Notepad.Extensions.Logging.FunctionalTest/Notepad.Extensions.Logging.FunctionalTest.csproj index 4e854f5..3630bcf 100644 --- a/Notepad.Extensions.Logging.FunctionalTest/Notepad.Extensions.Logging.FunctionalTest.csproj +++ b/Notepad.Extensions.Logging.FunctionalTest/Notepad.Extensions.Logging.FunctionalTest.csproj @@ -1,4 +1,4 @@ - + Exe @@ -6,8 +6,20 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Notepad.Extensions.Logging.FunctionalTest/Program.cs b/Notepad.Extensions.Logging.FunctionalTest/Program.cs index b8deb88..d59181e 100644 --- a/Notepad.Extensions.Logging.FunctionalTest/Program.cs +++ b/Notepad.Extensions.Logging.FunctionalTest/Program.cs @@ -6,13 +6,13 @@ namespace Notepad.Extensions.Logging.FunctionalTest { class Program { - static void Main(string[] args) + static void Main() { var sc = new ServiceCollection(); sc.AddLogging(lb => { lb.AddConsole(); - lb.AddNotepad(); + lb.AddNotepad(o => o.WindowName = "mylog - Notepad++"); }); var sp = sc.BuildServiceProvider(); @@ -29,7 +29,7 @@ namespace Notepad.Extensions.Logging.FunctionalTest { throw new InvalidOperationException("Wheeeeeeee"); } - catch (Exception ex) + catch (InvalidOperationException ex) { return ex; } diff --git a/Notepad.Extensions.Logging.sln b/Notepad.Extensions.Logging.sln index 8b0ca14..e6f47f8 100644 --- a/Notepad.Extensions.Logging.sln +++ b/Notepad.Extensions.Logging.sln @@ -3,9 +3,14 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.30114.105 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Notepad.Extensions.Logging", "Notepad.Extensions.Logging\Notepad.Extensions.Logging.csproj", "{859E3EAB-04EB-42EE-86B2-A6FE90D71731}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Notepad.Extensions.Logging", "Notepad.Extensions.Logging\Notepad.Extensions.Logging.csproj", "{859E3EAB-04EB-42EE-86B2-A6FE90D71731}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Notepad.Extensions.Logging.FunctionalTest", "Notepad.Extensions.Logging.FunctionalTest\Notepad.Extensions.Logging.FunctionalTest.csproj", "{82E1E9EF-9284-4E7B-B350-0318F9B7B411}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Notepad.Extensions.Logging.FunctionalTest", "Notepad.Extensions.Logging.FunctionalTest\Notepad.Extensions.Logging.FunctionalTest.csproj", "{82E1E9EF-9284-4E7B-B350-0318F9B7B411}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1B0EB23C-7148-453B-BC03-AD132DF7E13B}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Notepad.Extensions.Logging/LoggingBuilderExtensions.cs b/Notepad.Extensions.Logging/LoggingBuilderExtensions.cs index af2dc4b..2b76a45 100644 --- a/Notepad.Extensions.Logging/LoggingBuilderExtensions.cs +++ b/Notepad.Extensions.Logging/LoggingBuilderExtensions.cs @@ -1,9 +1,8 @@ -using Microsoft.Extensions.DependencyInjection; +using System; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging.Configuration; -using Microsoft.Extensions.Options; using Notepad.Extensions.Logging; -using System; namespace Microsoft.Extensions.Logging { @@ -11,6 +10,11 @@ namespace Microsoft.Extensions.Logging { public static ILoggingBuilder AddNotepad(this ILoggingBuilder builder) { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + builder.AddConfiguration(); builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton()); @@ -20,10 +24,16 @@ namespace Microsoft.Extensions.Logging public static ILoggingBuilder AddNotepad(this ILoggingBuilder builder, Action configure) { - if (configure == null) + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (configure is null) { throw new ArgumentNullException(nameof(configure)); } + AddNotepad(builder); builder.Services.Configure(configure); return builder; diff --git a/Notepad.Extensions.Logging/NativeMethods.cs b/Notepad.Extensions.Logging/NativeMethods.cs index af5abb8..86de38f 100644 --- a/Notepad.Extensions.Logging/NativeMethods.cs +++ b/Notepad.Extensions.Logging/NativeMethods.cs @@ -27,7 +27,7 @@ namespace Notepad.Extensions.Logging [DllImport("user32.dll")] public static extern bool EnumWindows(EnumWindowsDelegate lpEnumFunc, object lParam); - [DllImport("User32.dll")] + [DllImport("User32.dll", CharSet = CharSet.Unicode)] public static extern int GetWindowText(IntPtr hWndParent, StringBuilder sb, int maxCount); [DllImport("kernel32.dll", SetLastError = true)] diff --git a/Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj b/Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj index 427e3ed..4ede967 100644 --- a/Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj +++ b/Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj @@ -15,9 +15,25 @@ + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + \ No newline at end of file diff --git a/Notepad.Extensions.Logging/NotepadLogger.cs b/Notepad.Extensions.Logging/NotepadLogger.cs index a896938..655b585 100644 --- a/Notepad.Extensions.Logging/NotepadLogger.cs +++ b/Notepad.Extensions.Logging/NotepadLogger.cs @@ -77,18 +77,18 @@ namespace Notepad.Extensions.Logging { stringBuilderPool.Return(builder); } - } - static string GetLogLevelString(LogLevel logLevel) => logLevel switch - { - LogLevel.Trace => "trce", - LogLevel.Debug => "dbug", - LogLevel.Information => "info", - LogLevel.Warning => "warn", - LogLevel.Error => "fail", - LogLevel.Critical => "crit", - _ => throw new ArgumentOutOfRangeException(nameof(logLevel)), - }; + static string GetLogLevelString(LogLevel logLevel) => logLevel switch + { + LogLevel.Trace => "trce", + LogLevel.Debug => "dbug", + LogLevel.Information => "info", + LogLevel.Warning => "warn", + LogLevel.Error => "fail", + LogLevel.Critical => "crit", + _ => throw new ArgumentOutOfRangeException(nameof(logLevel)), + }; + } void WriteToNotepad(string message) { @@ -104,16 +104,14 @@ namespace Notepad.Extensions.Logging } } - unsafe static void WriteToNotepadPlusPlus(IntPtr hwnd, string message) + static void WriteToNotepadPlusPlus(IntPtr hwnd, string message) { var dataLength = Encoding.UTF8.GetByteCount(message); - // // HERE BE DRAGONS // We need to copy the message into Notepad++'s memory so that it can read it. // Look away now, before its too late. - // - + /* unused thread ID */ _ = GetWindowThreadProcessId(hwnd, out var remoteProcessId); using var remoteProcess = Process.GetProcessById(remoteProcessId); var mem = VirtualAllocEx(remoteProcess.Handle, IntPtr.Zero, (IntPtr)dataLength, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); @@ -129,7 +127,7 @@ namespace Notepad.Extensions.Logging { var idx = Encoding.UTF8.GetBytes(message, 0, message.Length, data, 0); - WriteProcessMemory(remoteProcess.Handle, mem, data, (IntPtr)dataLength, out var bytesWritten); + _ = WriteProcessMemory(remoteProcess.Handle, mem, data, (IntPtr)dataLength, out var bytesWritten); SendMessage(hwnd, SCI_ADDTEXT, (IntPtr)dataLength, mem); } finally diff --git a/Notepad.Extensions.Logging/NotepadLoggerProvider.cs b/Notepad.Extensions.Logging/NotepadLoggerProvider.cs index 7407e5b..e3b40c0 100644 --- a/Notepad.Extensions.Logging/NotepadLoggerProvider.cs +++ b/Notepad.Extensions.Logging/NotepadLoggerProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Text; using Microsoft.Extensions.Logging; using Microsoft.Extensions.ObjectPool; @@ -7,8 +8,23 @@ using Microsoft.Extensions.Options; namespace Notepad.Extensions.Logging { [ProviderAlias("Notepad")] + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Instantiated via DI container")] class NotepadLoggerProvider : ILoggerProvider { + public NotepadLoggerProvider(IOptionsMonitor options) + : this() + { + // Filter would be applied on LoggerFactory level + optionsReloadToken = options.OnChange(ReloadLoggerOptions); + ReloadLoggerOptions(options.CurrentValue); + } + + public NotepadLoggerProvider(NotepadLoggerOptions options) + : this() + { + this.options = options; + } + NotepadLoggerProvider() { var poolProvider = new DefaultObjectPoolProvider(); @@ -16,22 +32,11 @@ namespace Notepad.Extensions.Logging windowFinder = new WindowFinder(); } - public NotepadLoggerProvider(IOptionsMonitor options) : this() - { - // Filter would be applied on LoggerFactory level - optionsReloadToken = options.OnChange(ReloadLoggerOptions); - ReloadLoggerOptions(options.CurrentValue); - } - - public NotepadLoggerProvider(NotepadLoggerOptions options) : this() - { - this.options = options; - } readonly ObjectPool stringBuilderPool; readonly IWindowFinder windowFinder; readonly IDisposable optionsReloadToken; NotepadLoggerOptions options; - + public ILogger CreateLogger(string categoryName) => new NotepadLogger(stringBuilderPool, windowFinder, categoryName, options.WindowName); public void Dispose() diff --git a/Notepad.Extensions.Logging/WindowEnumerationState.cs b/Notepad.Extensions.Logging/WindowEnumerationState.cs index bd1a5ad..0f7803c 100644 --- a/Notepad.Extensions.Logging/WindowEnumerationState.cs +++ b/Notepad.Extensions.Logging/WindowEnumerationState.cs @@ -15,8 +15,10 @@ namespace Notepad.Extensions.Logging readonly StringBuilder sb; public IntPtr Handle { get; private set; } + public WindowKind WindowKind { get; private set; } - public string WindowName { get; internal set; } + + public string WindowName { get; set; } public void Reset() { @@ -46,6 +48,7 @@ namespace Notepad.Extensions.Logging { return false; } + return true; } @@ -57,7 +60,7 @@ namespace Notepad.Extensions.Logging { if (WindowName.Equals(titleText, StringComparison.Ordinal)) { - WindowKind = titleText.EndsWith(" - Notepad++") ? WindowKind.NotepadPlusPlus : WindowKind.Notepad; + WindowKind = titleText.EndsWith(" - Notepad++", StringComparison.Ordinal) ? WindowKind.NotepadPlusPlus : WindowKind.Notepad; } } else if (titleText.Equals("Untitled - Notepad", StringComparison.Ordinal)) diff --git a/Notepad.Extensions.Logging/WindowInfo.cs b/Notepad.Extensions.Logging/WindowInfo.cs index 6629774..b7081db 100644 --- a/Notepad.Extensions.Logging/WindowInfo.cs +++ b/Notepad.Extensions.Logging/WindowInfo.cs @@ -11,6 +11,7 @@ namespace Notepad.Extensions.Logging } public WindowKind Kind { get; } + public IntPtr Handle { get; } } } \ No newline at end of file diff --git a/Notepad.Extensions.Logging/WindowKind.cs b/Notepad.Extensions.Logging/WindowKind.cs index cd8c57d..90a56cb 100644 --- a/Notepad.Extensions.Logging/WindowKind.cs +++ b/Notepad.Extensions.Logging/WindowKind.cs @@ -4,6 +4,6 @@ { Invalid, Notepad, - NotepadPlusPlus + NotepadPlusPlus, } }