Skip to content

Commit 836ee36

Browse files
committed
Implemented universal searching of GetTopMostWindow (any applications)
1 parent 6bb6da5 commit 836ee36

7 files changed

Lines changed: 43 additions & 42 deletions

File tree

Src/ScreenGrid.Models.Tests/FlatImageTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ public void FindBordersTest()
6161
}
6262

6363
[Test]
64-
public void FindBoundingsOfInnerImage()
64+
public void FindBoundsOfInnerImage()
6565
{
6666
var flatImage = LoadFlatImageFromResource("ScreenGrid.Models.Tests.Resources.ImageSimple.png");
6767

68-
var result = flatImage.FindBoundingsOfInnerImage();
68+
var result = flatImage.FindBoundsOfInnerImage();
6969

7070
Assert.AreEqual(12, result.X);
7171
Assert.AreEqual(10, result.Y);

Src/ScreenGrid.Models/AppsInterop/NativeWindow.cs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public Bitmap GetShot()
8989
return WinApiInterop.NativeMethods.GetWindowImage(this.hWnd, 0, 0, (rect.Right - rect.Left) + 1, (rect.Bottom - rect.Top) + 1); // TODO: +1 ?
9090
}
9191

92-
public static NativeWindow GetTopMostWindow(IEnumerable<string> classNames)
92+
public static NativeWindow GetTopMostWindow()
9393
{
9494
// Is there are win32 function to get a list off all top level windows
9595
// with a given class name?
@@ -98,23 +98,21 @@ public static NativeWindow GetTopMostWindow(IEnumerable<string> classNames)
9898
// about.
9999

100100
// https://code.msdn.microsoft.com/windowsapps/Enumerate-top-level-9aa9d7c1
101-
102-
var results = new List<IntPtr>();
103-
//WinApiInterop.WinApiUtils.EnumWindows(new WinApiInterop.WinApiUtils.EnumWindowsProc(EnumTheWindows), IntPtr.Zero);
104-
105101
// http://stackoverflow.com/a/296014
106102

103+
var results = new List<NativeWindow>();
107104
WinApiInterop.NativeMethods.EnumWindows((hWnd, lParam) =>
108105
{
109-
var win = new NativeWindow(hWnd);
110-
111-
foreach (var className in classNames)
106+
var window = new NativeWindow(hWnd);
107+
108+
// Skip some
109+
if ((!window.IsMinimized) && (window.IsVisible))
112110
{
113-
if ((String.Compare(win.ClassName, className, StringComparison.OrdinalIgnoreCase) == 0) &&
114-
(!win.IsMinimized) &&
115-
(win.IsVisible))
111+
var className = window.ClassName;
112+
// TODO: better checks for inappropriate windows
113+
if ((className != "Shell_TrayWnd") && (className != "Button") && (!className.Contains("ScreenGrid")))
116114
{
117-
results.Add(hWnd);
115+
results.Add(window);
118116
}
119117
}
120118

@@ -123,12 +121,17 @@ public static NativeWindow GetTopMostWindow(IEnumerable<string> classNames)
123121

124122
if (results.Count > 0)
125123
{
126-
return new NativeWindow(results[0]);
124+
return results[0];
127125
}
128126
else
129127
{
130128
return null;
131129
}
132130
}
131+
132+
public override string ToString()
133+
{
134+
return this.ClassName;
135+
}
133136
}
134137
}

Src/ScreenGrid.Models/FlatImage.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ private IList<IntegerSegment> FindVerticalZeroSegments(int ix, int minimalSegmen
8989
return IntegerSegmentUtils.FindZeroSegments(FlatImage.GetDerivative(this.GetVerticalStripe(ix)), minimalSegmentLength);
9090
}
9191

92-
public Models.Geometry.Rectangle FindBoundingsOfInnerImage()
92+
public Models.Geometry.Rectangle FindBoundsOfInnerImage()
9393
{
9494
// TODO: add tests for this method
9595
const int minimalSegmentLength = 8;

Src/ScreenGrid.ViewModels/ScreenGridViewModel.cs

Lines changed: 10 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public ScreenGridViewModel()
3030
this.RotateCounterClockwiseCommand = new RelayCommand((o) => { this.Rot = Rotator.RotateCounterClockwise(this.Rot); });
3131
this.FlipHorizontalCommand = new RelayCommand((o) => { this.FlipH = !this.FlipH; });
3232
this.FlipVerticalCommand = new RelayCommand((o) => { this.FlipV = !this.FlipV; });
33-
this.SnapCommand = new RelayCommand((o) => { this.SnapToRenderView(); });
33+
this.SnapCommand = new RelayCommand((o) => { this.SnapToImageBounds(); });
3434
}
3535

3636
public ICommand RotateClockwiseCommand { get; private set; }
@@ -260,24 +260,10 @@ public string CaptionText
260260
}
261261
}
262262

263-
private IList<string> GetWindowClassNames()
264-
{
265-
var classNames = new List<string>();
266-
267-
classNames.Add(Models.AppsInterop.PhotoViewerWindow.MainWindowClassName);
268-
269-
var orw = Models.AppsInterop.OctaneRenderWindow.GetFromAllProcesses();
270-
classNames.AddRange(orw.Select(w => w.ClassName));
271-
272-
classNames.Add("MozillaWindowClass"); // TODO: do not use window class names, check any applications with topmost windows
273-
274-
return classNames;
275-
}
276-
277-
public void SnapToRenderView()
263+
public void SnapToImageBounds()
278264
{
279265
// select foreground window from several processes of supported applications
280-
var nativeWindow = Models.AppsInterop.NativeWindow.GetTopMostWindow(this.GetWindowClassNames());
266+
var nativeWindow = Models.AppsInterop.NativeWindow.GetTopMostWindow();
281267

282268
if (nativeWindow != null)
283269
{
@@ -298,26 +284,26 @@ public void SnapToRenderView()
298284
var bitmap = nativeWindow.GetShot();
299285
var flatImage = new Models.FlatImage(bitmap);
300286

301-
Models.Geometry.Rectangle imageBoundings;
287+
Models.Geometry.Rectangle imageBounds;
302288
if (Models.AppsInterop.OctaneRenderWindow.GetFromAllProcesses().Any(w => w.ClassName == nativeWindow.ClassName))
303289
{
304290
// TODO: remove this Octane Render specific code
305-
imageBoundings = Models.AppsInterop.OctaneRenderWindow.FindRenderedImageBorders(flatImage);
291+
imageBounds = Models.AppsInterop.OctaneRenderWindow.FindRenderedImageBorders(flatImage);
306292
}
307293
else
308294
{
309-
imageBoundings = flatImage.FindBoundingsOfInnerImage();
295+
imageBounds = flatImage.FindBoundsOfInnerImage();
310296
}
311297

312298
var nativeWindowLocation = new Models.Geometry.Point(nativeWindow.Location.X, nativeWindow.Location.Y);
313-
return new Tuple<Models.Geometry.Rectangle, Models.Geometry.Point>(imageBoundings, nativeWindowLocation);
299+
return new Tuple<Models.Geometry.Rectangle, Models.Geometry.Point>(imageBounds, nativeWindowLocation);
314300
}).ContinueWith((t) =>
315301
{
316-
var imageBoundings = t.Result.Item1;
302+
var imageBounds = t.Result.Item1;
317303
var windowLocation = t.Result.Item2;
318-
if (!imageBoundings.IsEmpty)
304+
if (!imageBounds.IsEmpty)
319305
{
320-
if ((imageBoundings.Width > 150) && (imageBoundings.Height > 50))
306+
if ((imageBounds.Width > 150) && (imageBounds.Height > 50))
321307
{
322308
this.PositionWindow(t.Result.Item2, t.Result.Item1);
323309
}

Src/ScreenGrid.Views/ScreenGridWindow.xaml.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ public ScreenGridWindow()
4141
private void Window_Loaded(object sender, RoutedEventArgs e)
4242
{
4343
this.cntxMenu = CreateContextMenu();
44-
this.vm.SnapToRenderView();
4544
}
4645

4746
private void Window_MouseDown(object sender, MouseButtonEventArgs e)

Src/ScreenGrid.WinApiInterop/GetWindowCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
{
33
// http://pinvoke.net/default.aspx/user32/GetWindow.html
44

5-
enum GetWindowCommand : uint
5+
public enum GetWindowCommand : uint
66
{
77
GW_HWNDFIRST = 0,
88
GW_HWNDLAST = 1,

Src/ScreenGrid.WinApiInterop/NativeMethods.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,19 @@ private static extern UInt64 BitBlt
5454
[DllImport("user32.dll")]
5555
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
5656

57+
[DllImport("user32.dll")]
58+
public static extern IntPtr GetTopWindow(IntPtr hWnd);
59+
60+
[DllImport("user32.dll")]
61+
public static extern IntPtr GetForegroundWindow();
62+
63+
[DllImport("user32.dll")]
64+
[return: MarshalAs(UnmanagedType.Bool)]
65+
public static extern bool IsWindowVisible(IntPtr hWnd);
66+
67+
[DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindow", SetLastError = true)]
68+
public static extern IntPtr GetNextWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.U4)] int wFlag);
69+
5770
[DllImport("user32.dll")]
5871
public static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
5972

0 commit comments

Comments
 (0)