From 70531ac442e6ae8147b841d82d2ab0b8ab4ebaa1 Mon Sep 17 00:00:00 2001 From: Yaakov Date: Thu, 21 May 2020 17:38:01 +1000 Subject: [PATCH 01/11] Also search for Notepad windows with changes. Fixes #3. --- Notepad.Extensions.Logging/NotepadLogger.cs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Notepad.Extensions.Logging/NotepadLogger.cs b/Notepad.Extensions.Logging/NotepadLogger.cs index f365058..2636b13 100644 --- a/Notepad.Extensions.Logging/NotepadLogger.cs +++ b/Notepad.Extensions.Logging/NotepadLogger.cs @@ -84,10 +84,29 @@ namespace Microsoft.Extensions.Logging static void WriteToNotepad(string message) { - IntPtr hwnd = NativeMethods.FindWindow(null, "Untitled - Notepad"); + IntPtr hwnd = FindNotepadWindow(); IntPtr edit = NativeMethods.FindWindowEx(hwnd, IntPtr.Zero, "EDIT", null); NativeMethods.SendMessage(edit, NativeMethods.EM_REPLACESEL, (IntPtr)1, message); } + + static IntPtr FindNotepadWindow() + { + IntPtr hwnd; + + hwnd = NativeMethods.FindWindow(null, "Untitled - Notepad"); + if (hwnd != IntPtr.Zero) + { + return hwnd; + } + + hwnd = NativeMethods.FindWindow(null, "*Untitled - Notepad"); + if (hwnd != IntPtr.Zero) + { + return hwnd; + } + + return IntPtr.Zero; + } } static class NativeMethods From 75db9915a53bd2d22a6e54b74e90c01ca2e26772 Mon Sep 17 00:00:00 2001 From: Yaakov Date: Thu, 21 May 2020 17:39:57 +1000 Subject: [PATCH 02/11] Move FindWindow to new file --- Notepad.Extensions.Logging/NativeMethods.cs | 19 +++++++++++ Notepad.Extensions.Logging/NotepadLogger.cs | 35 +-------------------- Notepad.Extensions.Logging/WindowFinder.cs | 26 +++++++++++++++ 3 files changed, 46 insertions(+), 34 deletions(-) create mode 100644 Notepad.Extensions.Logging/NativeMethods.cs create mode 100644 Notepad.Extensions.Logging/WindowFinder.cs diff --git a/Notepad.Extensions.Logging/NativeMethods.cs b/Notepad.Extensions.Logging/NativeMethods.cs new file mode 100644 index 0000000..6de089f --- /dev/null +++ b/Notepad.Extensions.Logging/NativeMethods.cs @@ -0,0 +1,19 @@ +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.Extensions.Logging +{ + static class NativeMethods + { + [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + + [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow); + + public const int EM_REPLACESEL = 0x00C2; + + [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam); + } +} diff --git a/Notepad.Extensions.Logging/NotepadLogger.cs b/Notepad.Extensions.Logging/NotepadLogger.cs index 2636b13..c4e37b1 100644 --- a/Notepad.Extensions.Logging/NotepadLogger.cs +++ b/Notepad.Extensions.Logging/NotepadLogger.cs @@ -84,42 +84,9 @@ namespace Microsoft.Extensions.Logging static void WriteToNotepad(string message) { - IntPtr hwnd = FindNotepadWindow(); + IntPtr hwnd = WindowFinder.FindNotepadWindow(); IntPtr edit = NativeMethods.FindWindowEx(hwnd, IntPtr.Zero, "EDIT", null); NativeMethods.SendMessage(edit, NativeMethods.EM_REPLACESEL, (IntPtr)1, message); } - - static IntPtr FindNotepadWindow() - { - IntPtr hwnd; - - hwnd = NativeMethods.FindWindow(null, "Untitled - Notepad"); - if (hwnd != IntPtr.Zero) - { - return hwnd; - } - - hwnd = NativeMethods.FindWindow(null, "*Untitled - Notepad"); - if (hwnd != IntPtr.Zero) - { - return hwnd; - } - - return IntPtr.Zero; - } - } - - static class NativeMethods - { - [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); - - [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern IntPtr FindWindowEx(IntPtr hWndParent, IntPtr hWndChildAfter, string lpszClass, string lpszWindow); - - public const int EM_REPLACESEL = 0x00C2; - - [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam); } } diff --git a/Notepad.Extensions.Logging/WindowFinder.cs b/Notepad.Extensions.Logging/WindowFinder.cs new file mode 100644 index 0000000..0027600 --- /dev/null +++ b/Notepad.Extensions.Logging/WindowFinder.cs @@ -0,0 +1,26 @@ +using System; + +namespace Microsoft.Extensions.Logging +{ + static class WindowFinder + { + public static IntPtr FindNotepadWindow() + { + IntPtr hwnd; + + hwnd = NativeMethods.FindWindow(null, "Untitled - Notepad"); + if (hwnd != IntPtr.Zero) + { + return hwnd; + } + + hwnd = NativeMethods.FindWindow(null, "*Untitled - Notepad"); + if (hwnd != IntPtr.Zero) + { + return hwnd; + } + + return IntPtr.Zero; + } + } +} From e512889b17c4569466c5413bdde68d4fb1b918fb Mon Sep 17 00:00:00 2001 From: Yaakov Date: Thu, 21 May 2020 17:40:53 +1000 Subject: [PATCH 03/11] Move edit window lookup too --- Notepad.Extensions.Logging/NotepadLogger.cs | 3 +-- Notepad.Extensions.Logging/WindowFinder.cs | 7 +++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Notepad.Extensions.Logging/NotepadLogger.cs b/Notepad.Extensions.Logging/NotepadLogger.cs index c4e37b1..754fd9b 100644 --- a/Notepad.Extensions.Logging/NotepadLogger.cs +++ b/Notepad.Extensions.Logging/NotepadLogger.cs @@ -85,8 +85,7 @@ namespace Microsoft.Extensions.Logging static void WriteToNotepad(string message) { IntPtr hwnd = WindowFinder.FindNotepadWindow(); - IntPtr edit = NativeMethods.FindWindowEx(hwnd, IntPtr.Zero, "EDIT", null); - NativeMethods.SendMessage(edit, NativeMethods.EM_REPLACESEL, (IntPtr)1, message); + NativeMethods.SendMessage(hwnd, NativeMethods.EM_REPLACESEL, (IntPtr)1, message); } } } diff --git a/Notepad.Extensions.Logging/WindowFinder.cs b/Notepad.Extensions.Logging/WindowFinder.cs index 0027600..a033593 100644 --- a/Notepad.Extensions.Logging/WindowFinder.cs +++ b/Notepad.Extensions.Logging/WindowFinder.cs @@ -5,6 +5,13 @@ namespace Microsoft.Extensions.Logging static class WindowFinder { public static IntPtr FindNotepadWindow() + { + var hwnd = FindMainWindow(); + IntPtr edit = NativeMethods.FindWindowEx(hwnd, IntPtr.Zero, "EDIT", null); + return edit; + } + + static IntPtr FindMainWindow() { IntPtr hwnd; From fa24ae3022fdd83b51e3707b31ecd462549c842b Mon Sep 17 00:00:00 2001 From: Yaakov Date: Thu, 21 May 2020 17:51:59 +1000 Subject: [PATCH 04/11] Use EnumWindows instead of FindWindow --- .../Program.cs | 12 +++- Notepad.Extensions.Logging/NativeMethods.cs | 9 +++ Notepad.Extensions.Logging/WindowFinder.cs | 64 +++++++++++++++---- 3 files changed, 70 insertions(+), 15 deletions(-) diff --git a/Notepad.Extensions.Logging.FunctionalTest/Program.cs b/Notepad.Extensions.Logging.FunctionalTest/Program.cs index b8deb88..886a3f2 100644 --- a/Notepad.Extensions.Logging.FunctionalTest/Program.cs +++ b/Notepad.Extensions.Logging.FunctionalTest/Program.cs @@ -18,9 +18,15 @@ namespace Notepad.Extensions.Logging.FunctionalTest var sp = sc.BuildServiceProvider(); var logger = sp.GetRequiredService>(); - logger.LogWarning("Here is a warning."); - logger.LogError(GetException(), "oh no!."); - logger.LogInformation("Here is some info."); + //logger.LogWarning("Here is a warning."); + //logger.LogError(GetException(), "oh no!."); + //logger.LogInformation("Here is some info."); + //logger.LogInformation("here, have a nice 😋 emoji."); + logger.LogInformation(@"💧 Paul +@paws101 +Replying to +@yaakov_h +But does it handle emoji injection?."); } static Exception GetException() diff --git a/Notepad.Extensions.Logging/NativeMethods.cs b/Notepad.Extensions.Logging/NativeMethods.cs index 6de089f..9426460 100644 --- a/Notepad.Extensions.Logging/NativeMethods.cs +++ b/Notepad.Extensions.Logging/NativeMethods.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using System.Text; namespace Microsoft.Extensions.Logging { @@ -15,5 +16,13 @@ namespace Microsoft.Extensions.Logging [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam); + + public delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lParam); + + [DllImport("user32.dll")] + public static extern bool EnumWindows(EnumWindowsDelegate lpEnumFunc, IntPtr lParam); + + [DllImport("User32.dll")] + public static extern int GetWindowText(IntPtr hWndParent, StringBuilder sb, int maxCount); } } diff --git a/Notepad.Extensions.Logging/WindowFinder.cs b/Notepad.Extensions.Logging/WindowFinder.cs index a033593..19faae1 100644 --- a/Notepad.Extensions.Logging/WindowFinder.cs +++ b/Notepad.Extensions.Logging/WindowFinder.cs @@ -1,4 +1,6 @@ using System; +using System.ComponentModel; +using System.Text; namespace Microsoft.Extensions.Logging { @@ -6,28 +8,66 @@ namespace Microsoft.Extensions.Logging { public static IntPtr FindNotepadWindow() { - var hwnd = FindMainWindow(); - IntPtr edit = NativeMethods.FindWindowEx(hwnd, IntPtr.Zero, "EDIT", null); - return edit; + sb ??= new StringBuilder(4096); + + try + { + FindMainWindow(); + if (handle == IntPtr.Zero) + { + return handle; + } + + IntPtr edit = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "EDIT", null); + return edit; + } + finally + { + handle = IntPtr.Zero; + sb.Clear(); + } } static IntPtr FindMainWindow() { - IntPtr hwnd; - - hwnd = NativeMethods.FindWindow(null, "Untitled - Notepad"); - if (hwnd != IntPtr.Zero) + NativeMethods.EnumWindows(enumWindowsDelegate, IntPtr.Zero); + return handle; + } + + static NativeMethods.EnumWindowsDelegate enumWindowsDelegate = new NativeMethods.EnumWindowsDelegate(EnumWindowsCallback); + + static bool EnumWindowsCallback(IntPtr hWnd, IntPtr lParam) + { + var result = NativeMethods.GetWindowText(hWnd, sb, sb.Capacity); + if (result < 0) { - return hwnd; + throw new Win32Exception(result); } - hwnd = NativeMethods.FindWindow(null, "*Untitled - Notepad"); - if (hwnd != IntPtr.Zero) + if (IsKnownNotepadWindow(sb.ToString())) { - return hwnd; + WindowFinder.handle = hWnd; + return false; + } + return true; + } + + [ThreadStatic] + static IntPtr handle; + + [ThreadStatic] + static StringBuilder sb; + + static bool IsKnownNotepadWindow(string titleText) + { + switch (titleText) + { + case "Untitled - Notepad": + case "*Untitled - Notepad": + return true; } - return IntPtr.Zero; + return false; } } } From 1d1f92c608d39e2aea5bfd47f6e49a5e2557062c Mon Sep 17 00:00:00 2001 From: Yaakov Date: Thu, 21 May 2020 17:52:07 +1000 Subject: [PATCH 05/11] Revert "Use EnumWindows instead of FindWindow" This reverts commit fa24ae3022fdd83b51e3707b31ecd462549c842b. --- .../Program.cs | 12 +--- Notepad.Extensions.Logging/NativeMethods.cs | 9 --- Notepad.Extensions.Logging/WindowFinder.cs | 64 ++++--------------- 3 files changed, 15 insertions(+), 70 deletions(-) diff --git a/Notepad.Extensions.Logging.FunctionalTest/Program.cs b/Notepad.Extensions.Logging.FunctionalTest/Program.cs index 886a3f2..b8deb88 100644 --- a/Notepad.Extensions.Logging.FunctionalTest/Program.cs +++ b/Notepad.Extensions.Logging.FunctionalTest/Program.cs @@ -18,15 +18,9 @@ namespace Notepad.Extensions.Logging.FunctionalTest var sp = sc.BuildServiceProvider(); var logger = sp.GetRequiredService>(); - //logger.LogWarning("Here is a warning."); - //logger.LogError(GetException(), "oh no!."); - //logger.LogInformation("Here is some info."); - //logger.LogInformation("here, have a nice 😋 emoji."); - logger.LogInformation(@"💧 Paul -@paws101 -Replying to -@yaakov_h -But does it handle emoji injection?."); + logger.LogWarning("Here is a warning."); + logger.LogError(GetException(), "oh no!."); + logger.LogInformation("Here is some info."); } static Exception GetException() diff --git a/Notepad.Extensions.Logging/NativeMethods.cs b/Notepad.Extensions.Logging/NativeMethods.cs index 9426460..6de089f 100644 --- a/Notepad.Extensions.Logging/NativeMethods.cs +++ b/Notepad.Extensions.Logging/NativeMethods.cs @@ -1,6 +1,5 @@ using System; using System.Runtime.InteropServices; -using System.Text; namespace Microsoft.Extensions.Logging { @@ -16,13 +15,5 @@ namespace Microsoft.Extensions.Logging [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam); - - public delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lParam); - - [DllImport("user32.dll")] - public static extern bool EnumWindows(EnumWindowsDelegate lpEnumFunc, IntPtr lParam); - - [DllImport("User32.dll")] - public static extern int GetWindowText(IntPtr hWndParent, StringBuilder sb, int maxCount); } } diff --git a/Notepad.Extensions.Logging/WindowFinder.cs b/Notepad.Extensions.Logging/WindowFinder.cs index 19faae1..a033593 100644 --- a/Notepad.Extensions.Logging/WindowFinder.cs +++ b/Notepad.Extensions.Logging/WindowFinder.cs @@ -1,6 +1,4 @@ using System; -using System.ComponentModel; -using System.Text; namespace Microsoft.Extensions.Logging { @@ -8,66 +6,28 @@ namespace Microsoft.Extensions.Logging { public static IntPtr FindNotepadWindow() { - sb ??= new StringBuilder(4096); - - try - { - FindMainWindow(); - if (handle == IntPtr.Zero) - { - return handle; - } - - IntPtr edit = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "EDIT", null); - return edit; - } - finally - { - handle = IntPtr.Zero; - sb.Clear(); - } + var hwnd = FindMainWindow(); + IntPtr edit = NativeMethods.FindWindowEx(hwnd, IntPtr.Zero, "EDIT", null); + return edit; } static IntPtr FindMainWindow() { - NativeMethods.EnumWindows(enumWindowsDelegate, IntPtr.Zero); - return handle; - } - - static NativeMethods.EnumWindowsDelegate enumWindowsDelegate = new NativeMethods.EnumWindowsDelegate(EnumWindowsCallback); - - static bool EnumWindowsCallback(IntPtr hWnd, IntPtr lParam) - { - var result = NativeMethods.GetWindowText(hWnd, sb, sb.Capacity); - if (result < 0) + IntPtr hwnd; + + hwnd = NativeMethods.FindWindow(null, "Untitled - Notepad"); + if (hwnd != IntPtr.Zero) { - throw new Win32Exception(result); + return hwnd; } - if (IsKnownNotepadWindow(sb.ToString())) + hwnd = NativeMethods.FindWindow(null, "*Untitled - Notepad"); + if (hwnd != IntPtr.Zero) { - WindowFinder.handle = hWnd; - return false; - } - return true; - } - - [ThreadStatic] - static IntPtr handle; - - [ThreadStatic] - static StringBuilder sb; - - static bool IsKnownNotepadWindow(string titleText) - { - switch (titleText) - { - case "Untitled - Notepad": - case "*Untitled - Notepad": - return true; + return hwnd; } - return false; + return IntPtr.Zero; } } } From 1a934be05f68a78207a398b4bea7e940de570733 Mon Sep 17 00:00:00 2001 From: Yaakov Date: Thu, 21 May 2020 17:51:59 +1000 Subject: [PATCH 06/11] Use EnumWindows instead of FindWindow --- Notepad.Extensions.Logging/NativeMethods.cs | 9 +++ Notepad.Extensions.Logging/WindowFinder.cs | 64 +++++++++++++++++---- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/Notepad.Extensions.Logging/NativeMethods.cs b/Notepad.Extensions.Logging/NativeMethods.cs index 6de089f..9426460 100644 --- a/Notepad.Extensions.Logging/NativeMethods.cs +++ b/Notepad.Extensions.Logging/NativeMethods.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using System.Text; namespace Microsoft.Extensions.Logging { @@ -15,5 +16,13 @@ namespace Microsoft.Extensions.Logging [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam); + + public delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lParam); + + [DllImport("user32.dll")] + public static extern bool EnumWindows(EnumWindowsDelegate lpEnumFunc, IntPtr lParam); + + [DllImport("User32.dll")] + public static extern int GetWindowText(IntPtr hWndParent, StringBuilder sb, int maxCount); } } diff --git a/Notepad.Extensions.Logging/WindowFinder.cs b/Notepad.Extensions.Logging/WindowFinder.cs index a033593..19faae1 100644 --- a/Notepad.Extensions.Logging/WindowFinder.cs +++ b/Notepad.Extensions.Logging/WindowFinder.cs @@ -1,4 +1,6 @@ using System; +using System.ComponentModel; +using System.Text; namespace Microsoft.Extensions.Logging { @@ -6,28 +8,66 @@ namespace Microsoft.Extensions.Logging { public static IntPtr FindNotepadWindow() { - var hwnd = FindMainWindow(); - IntPtr edit = NativeMethods.FindWindowEx(hwnd, IntPtr.Zero, "EDIT", null); - return edit; + sb ??= new StringBuilder(4096); + + try + { + FindMainWindow(); + if (handle == IntPtr.Zero) + { + return handle; + } + + IntPtr edit = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "EDIT", null); + return edit; + } + finally + { + handle = IntPtr.Zero; + sb.Clear(); + } } static IntPtr FindMainWindow() { - IntPtr hwnd; - - hwnd = NativeMethods.FindWindow(null, "Untitled - Notepad"); - if (hwnd != IntPtr.Zero) + NativeMethods.EnumWindows(enumWindowsDelegate, IntPtr.Zero); + return handle; + } + + static NativeMethods.EnumWindowsDelegate enumWindowsDelegate = new NativeMethods.EnumWindowsDelegate(EnumWindowsCallback); + + static bool EnumWindowsCallback(IntPtr hWnd, IntPtr lParam) + { + var result = NativeMethods.GetWindowText(hWnd, sb, sb.Capacity); + if (result < 0) { - return hwnd; + throw new Win32Exception(result); } - hwnd = NativeMethods.FindWindow(null, "*Untitled - Notepad"); - if (hwnd != IntPtr.Zero) + if (IsKnownNotepadWindow(sb.ToString())) { - return hwnd; + WindowFinder.handle = hWnd; + return false; + } + return true; + } + + [ThreadStatic] + static IntPtr handle; + + [ThreadStatic] + static StringBuilder sb; + + static bool IsKnownNotepadWindow(string titleText) + { + switch (titleText) + { + case "Untitled - Notepad": + case "*Untitled - Notepad": + return true; } - return IntPtr.Zero; + return false; } } } From b23e186617a35faaa0b8f597c19bd79769ece6c0 Mon Sep 17 00:00:00 2001 From: Yaakov Date: Thu, 21 May 2020 18:09:11 +1000 Subject: [PATCH 07/11] try notepad++ --- Notepad.Extensions.Logging/WindowFinder.cs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Notepad.Extensions.Logging/WindowFinder.cs b/Notepad.Extensions.Logging/WindowFinder.cs index 19faae1..8c9b084 100644 --- a/Notepad.Extensions.Logging/WindowFinder.cs +++ b/Notepad.Extensions.Logging/WindowFinder.cs @@ -1,6 +1,7 @@ using System; using System.ComponentModel; using System.Text; +using System.Text.RegularExpressions; namespace Microsoft.Extensions.Logging { @@ -13,13 +14,7 @@ namespace Microsoft.Extensions.Logging try { FindMainWindow(); - if (handle == IntPtr.Zero) - { - return handle; - } - - IntPtr edit = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "EDIT", null); - return edit; + return handle; } finally { @@ -44,9 +39,10 @@ namespace Microsoft.Extensions.Logging throw new Win32Exception(result); } + WindowFinder.handle = hWnd; + if (IsKnownNotepadWindow(sb.ToString())) { - WindowFinder.handle = hWnd; return false; } return true; @@ -58,15 +54,24 @@ namespace Microsoft.Extensions.Logging [ThreadStatic] static StringBuilder sb; + static Regex notepadPlusPlusRegex = new Regex(@"^new \d+ - Notepad\+\+$", RegexOptions.Compiled); + static bool IsKnownNotepadWindow(string titleText) { switch (titleText) { case "Untitled - Notepad": case "*Untitled - Notepad": + handle = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "EDIT", null); return true; } + if (notepadPlusPlusRegex.IsMatch(titleText)) + { + handle = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "SysTabControl32", null); + return true; + } + return false; } } From 4f1ff2530c9b6778c371190d9cddeb667d08b4ab Mon Sep 17 00:00:00 2001 From: Yaakov Date: Fri, 22 May 2020 14:25:26 +1000 Subject: [PATCH 08/11] Add support for Notepad++ Closes #1. --- .../LoggingBuilderExtensions.cs | 4 +- Notepad.Extensions.Logging/NativeMethods.cs | 25 +++++++- .../Notepad.Extensions.Logging.csproj | 1 + Notepad.Extensions.Logging/NotepadLogger.cs | 58 ++++++++++++++++++- .../NotepadLoggerProvider.cs | 3 +- Notepad.Extensions.Logging/NullDisposable.cs | 2 +- Notepad.Extensions.Logging/WindowFinder.cs | 22 +++++-- Notepad.Extensions.Logging/WindowKind.cs | 9 +++ 8 files changed, 112 insertions(+), 12 deletions(-) create mode 100644 Notepad.Extensions.Logging/WindowKind.cs diff --git a/Notepad.Extensions.Logging/LoggingBuilderExtensions.cs b/Notepad.Extensions.Logging/LoggingBuilderExtensions.cs index 77a6920..5caaf34 100644 --- a/Notepad.Extensions.Logging/LoggingBuilderExtensions.cs +++ b/Notepad.Extensions.Logging/LoggingBuilderExtensions.cs @@ -1,4 +1,6 @@ -namespace Microsoft.Extensions.Logging +using Notepad.Extensions.Logging; + +namespace Microsoft.Extensions.Logging { public static class LoggingBuilderExtensions { diff --git a/Notepad.Extensions.Logging/NativeMethods.cs b/Notepad.Extensions.Logging/NativeMethods.cs index 9426460..873b5de 100644 --- a/Notepad.Extensions.Logging/NativeMethods.cs +++ b/Notepad.Extensions.Logging/NativeMethods.cs @@ -2,7 +2,7 @@ using System.Runtime.InteropServices; using System.Text; -namespace Microsoft.Extensions.Logging +namespace Notepad.Extensions.Logging { static class NativeMethods { @@ -17,6 +17,11 @@ namespace Microsoft.Extensions.Logging [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam); + public const int SCI_ADDTEXT = 2001; + + [DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); + public delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lParam); [DllImport("user32.dll")] @@ -24,5 +29,23 @@ namespace Microsoft.Extensions.Logging [DllImport("User32.dll")] public static extern int GetWindowText(IntPtr hWndParent, StringBuilder sb, int maxCount); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, IntPtr dwSize, int flAllocationType, int flProtect); + + public const int MEM_COMMIT = 0x00001000; + public const int MEM_RESERVE = 0x00002000; + public const int MEM_RELEASE = 0x8000; + public const int PAGE_READWRITE = 0x04; + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, IntPtr dwSize, int dwFreeType); + + [DllImport("User32.dll")] + public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, IntPtr nSize, out IntPtr lpNumberOfBytesWritten); } } diff --git a/Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj b/Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj index 6249221..7254b23 100644 --- a/Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj +++ b/Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj @@ -10,6 +10,7 @@ git Apache-2.0 true + true diff --git a/Notepad.Extensions.Logging/NotepadLogger.cs b/Notepad.Extensions.Logging/NotepadLogger.cs index 754fd9b..f5552e5 100644 --- a/Notepad.Extensions.Logging/NotepadLogger.cs +++ b/Notepad.Extensions.Logging/NotepadLogger.cs @@ -1,9 +1,14 @@ using System; +using System.Buffers; +using System.ComponentModel; +using System.Diagnostics; using System.Runtime.InteropServices; using System.Text; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.ObjectPool; +using static Notepad.Extensions.Logging.NativeMethods; -namespace Microsoft.Extensions.Logging +namespace Notepad.Extensions.Logging { class NotepadLogger : ILogger { @@ -84,8 +89,55 @@ namespace Microsoft.Extensions.Logging static void WriteToNotepad(string message) { - IntPtr hwnd = WindowFinder.FindNotepadWindow(); - NativeMethods.SendMessage(hwnd, NativeMethods.EM_REPLACESEL, (IntPtr)1, message); + var (kind, hwnd) = WindowFinder.FindNotepadWindow(); + switch (kind) + { + case WindowKind.Notepad: + SendMessage(hwnd, EM_REPLACESEL, (IntPtr)1, message); + break; + + case WindowKind.NotepadPlusPlus: + { + WriteToNotepadPlusPlus(hwnd, message); + break; + } + } + } + + unsafe 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. + // + + var threadID = 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); + if (mem == IntPtr.Zero) throw new Win32Exception(); + + try + { + var data = ArrayPool.Shared.Rent(dataLength); + try + { + var idx = Encoding.UTF8.GetBytes(message, 0, message.Length, data, 0); + + WriteProcessMemory(remoteProcess.Handle, mem, data, (IntPtr)dataLength, out var bytesWritten); + SendMessage(hwnd, SCI_ADDTEXT, (IntPtr)dataLength, mem); + } + finally + { + ArrayPool.Shared.Return(data); + } + } + finally + { + VirtualFreeEx(remoteProcess.Handle, IntPtr.Zero, IntPtr.Zero, MEM_RELEASE); + } } } } diff --git a/Notepad.Extensions.Logging/NotepadLoggerProvider.cs b/Notepad.Extensions.Logging/NotepadLoggerProvider.cs index e8c87b6..601cb8a 100644 --- a/Notepad.Extensions.Logging/NotepadLoggerProvider.cs +++ b/Notepad.Extensions.Logging/NotepadLoggerProvider.cs @@ -1,7 +1,8 @@ using System.Text; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.ObjectPool; -namespace Microsoft.Extensions.Logging +namespace Notepad.Extensions.Logging { class NotepadLoggerProvider : ILoggerProvider { diff --git a/Notepad.Extensions.Logging/NullDisposable.cs b/Notepad.Extensions.Logging/NullDisposable.cs index 4e3e782..a8b7db3 100644 --- a/Notepad.Extensions.Logging/NullDisposable.cs +++ b/Notepad.Extensions.Logging/NullDisposable.cs @@ -1,6 +1,6 @@ using System; -namespace Microsoft.Extensions.Logging +namespace Notepad.Extensions.Logging { class NullDisposable : IDisposable { diff --git a/Notepad.Extensions.Logging/WindowFinder.cs b/Notepad.Extensions.Logging/WindowFinder.cs index 8c9b084..a5875ba 100644 --- a/Notepad.Extensions.Logging/WindowFinder.cs +++ b/Notepad.Extensions.Logging/WindowFinder.cs @@ -3,23 +3,25 @@ using System.ComponentModel; using System.Text; using System.Text.RegularExpressions; -namespace Microsoft.Extensions.Logging +namespace Notepad.Extensions.Logging { static class WindowFinder { - public static IntPtr FindNotepadWindow() + + public static (WindowKind kind, IntPtr hwnd) FindNotepadWindow() { sb ??= new StringBuilder(4096); try { FindMainWindow(); - return handle; + return (windowKind, handle); } finally { handle = IntPtr.Zero; sb.Clear(); + windowKind = WindowKind.Invalid; } } @@ -41,6 +43,12 @@ namespace Microsoft.Extensions.Logging WindowFinder.handle = hWnd; + if (sb.Length > 0 && sb[0] == '*') + { + // Notepad and Notepad++ both mark dirty documents by adding a leading asterisk to the window name. + sb.Remove(0, 1); + } + if (IsKnownNotepadWindow(sb.ToString())) { return false; @@ -51,6 +59,9 @@ namespace Microsoft.Extensions.Logging [ThreadStatic] static IntPtr handle; + [ThreadStatic] + static WindowKind windowKind; + [ThreadStatic] static StringBuilder sb; @@ -61,14 +72,15 @@ namespace Microsoft.Extensions.Logging switch (titleText) { case "Untitled - Notepad": - case "*Untitled - Notepad": + windowKind = WindowKind.Notepad; handle = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "EDIT", null); return true; } if (notepadPlusPlusRegex.IsMatch(titleText)) { - handle = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "SysTabControl32", null); + windowKind = WindowKind.NotepadPlusPlus; + handle = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "Scintilla", null); return true; } diff --git a/Notepad.Extensions.Logging/WindowKind.cs b/Notepad.Extensions.Logging/WindowKind.cs new file mode 100644 index 0000000..d79e383 --- /dev/null +++ b/Notepad.Extensions.Logging/WindowKind.cs @@ -0,0 +1,9 @@ +namespace Notepad.Extensions.Logging +{ + public enum WindowKind + { + Invalid, + Notepad, + NotepadPlusPlus + } +} From 8b348b3dd373c84cf8897c3c8a5c58e25dcf3300 Mon Sep 17 00:00:00 2001 From: Yaakov Date: Fri, 22 May 2020 14:33:01 +1000 Subject: [PATCH 09/11] dont crash if virtualallocex fails --- Notepad.Extensions.Logging/NotepadLogger.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Notepad.Extensions.Logging/NotepadLogger.cs b/Notepad.Extensions.Logging/NotepadLogger.cs index f5552e5..7679e7b 100644 --- a/Notepad.Extensions.Logging/NotepadLogger.cs +++ b/Notepad.Extensions.Logging/NotepadLogger.cs @@ -97,10 +97,10 @@ namespace Notepad.Extensions.Logging break; case WindowKind.NotepadPlusPlus: - { - WriteToNotepadPlusPlus(hwnd, message); - break; - } + { + WriteToNotepadPlusPlus(hwnd, message); + break; + } } } @@ -114,10 +114,13 @@ namespace Notepad.Extensions.Logging // Look away now, before its too late. // - var threadID = GetWindowThreadProcessId(hwnd, out var remoteProcessId); + /* 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); - if (mem == IntPtr.Zero) throw new Win32Exception(); + if (mem == IntPtr.Zero) + { + return; + } try { From ed27e64d427d3bb4228d979a0f86dfed1d547f43 Mon Sep 17 00:00:00 2001 From: Yaakov Date: Fri, 22 May 2020 14:33:10 +1000 Subject: [PATCH 10/11] remove whitespace --- Notepad.Extensions.Logging/WindowFinder.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Notepad.Extensions.Logging/WindowFinder.cs b/Notepad.Extensions.Logging/WindowFinder.cs index a5875ba..b716ec9 100644 --- a/Notepad.Extensions.Logging/WindowFinder.cs +++ b/Notepad.Extensions.Logging/WindowFinder.cs @@ -7,7 +7,6 @@ namespace Notepad.Extensions.Logging { static class WindowFinder { - public static (WindowKind kind, IntPtr hwnd) FindNotepadWindow() { sb ??= new StringBuilder(4096); From b817c75720c05c2ca935e071de64bfc09f07f111 Mon Sep 17 00:00:00 2001 From: Yaakov Date: Fri, 22 May 2020 14:33:19 +1000 Subject: [PATCH 11/11] bump version 1.0.1 --- Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj b/Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj index 7254b23..b0ec7db 100644 --- a/Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj +++ b/Notepad.Extensions.Logging/Notepad.Extensions.Logging.csproj @@ -11,6 +11,7 @@ Apache-2.0 true true + 1.0.1