Skip to content

Commit 1728be2

Browse files
committed
Implementing an alternate way of finding editor handle for new Notepad
* Adding needed interop definitions to enumerate child windows * If first attempt using FindWindowEx with notepad process MainWindowHandle does not find editor handle, the search is done by enumerating child window handles for the notepad process MainWindowHandle.
1 parent 2ab1163 commit 1728be2

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

src/Serilog.Sinks.Notepad/Sinks/Notepad/Interop/NotepadTextWriter.cs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@
1414
//
1515
#endregion
1616

17+
using Serilog.Debugging;
1718
using System;
19+
using System.Collections.Generic;
1820
using System.Diagnostics;
1921
using System.IO;
2022
using System.Linq;
23+
using System.Runtime.InteropServices;
2124
using System.Text;
22-
using Serilog.Debugging;
2325

2426
namespace Serilog.Sinks.Notepad.Interop
2527
{
@@ -120,6 +122,13 @@ private static IntPtr FindNotepadEditorHandle(IntPtr notepadWindowHandle)
120122
return richEditHandle;
121123
}
122124

125+
// Issue #59 - Alternate way of finding the RichEditD2DPT class:
126+
if (FindEditorHandleThroughChildWindows(notepadWindowHandle) is var childRichEditHandle
127+
&& childRichEditHandle != IntPtr.Zero)
128+
{
129+
return childRichEditHandle;
130+
}
131+
123132
return User32.FindWindowEx(notepadWindowHandle, IntPtr.Zero, "Edit", null);
124133
}
125134

@@ -130,5 +139,40 @@ private void EnsureNotDisposed()
130139
throw new ObjectDisposedException(GetType().Name);
131140
}
132141
}
142+
143+
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
144+
{
145+
GCHandle gch = GCHandle.FromIntPtr(pointer);
146+
List<IntPtr> list = gch.Target as List<IntPtr>;
147+
if (list == null)
148+
{
149+
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
150+
}
151+
152+
// We only want windows of class RichEditD2DPT.
153+
if (User32.FindWindowEx(handle, IntPtr.Zero, "RichEditD2DPT", null) != IntPtr.Zero)
154+
{
155+
list.Add(handle);
156+
}
157+
158+
return true;
159+
}
160+
161+
private static IntPtr FindEditorHandleThroughChildWindows(IntPtr notepadWindowHandle)
162+
{
163+
List<IntPtr> result = new List<IntPtr>();
164+
GCHandle listHandle = GCHandle.Alloc(result);
165+
try
166+
{
167+
User32.Win32Callback childProc = new User32.Win32Callback(EnumWindow);
168+
User32.EnumChildWindows(notepadWindowHandle, childProc, GCHandle.ToIntPtr(listHandle));
169+
}
170+
finally
171+
{
172+
if (listHandle.IsAllocated)
173+
listHandle.Free();
174+
}
175+
return result.FirstOrDefault();
176+
}
133177
}
134178
}

src/Serilog.Sinks.Notepad/Sinks/Notepad/Interop/User32.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,16 @@ internal class User32
3535

3636
[DllImport("User32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
3737
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);
38+
39+
40+
[DllImport("user32.dll")]
41+
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
42+
43+
// Needed for EnumChildWindows for registering a call back function.
44+
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
45+
46+
[DllImport("user32.Dll")]
47+
[return: MarshalAs(UnmanagedType.Bool)]
48+
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
3849
}
3950
}

0 commit comments

Comments
 (0)