Native code refactoring.

Group switching completed and working.
Fixed side panel opening.
This commit is contained in:
Lorenz Cuno Klopfenstein 2010-07-01 01:19:31 +02:00
parent 78917c9c12
commit bf91b420ab
21 changed files with 1045 additions and 789 deletions

View file

@ -4,8 +4,9 @@ using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using VistaControls.Dwm.Helpers;
using System.Drawing;
using System.ComponentModel;
using OnTopReplica.Native;
using System.Drawing;
namespace OnTopReplica {
@ -102,7 +103,7 @@ namespace OnTopReplica {
Size = new Size(newWidth, newHeight);
int deltaX = Size.Width - origSize.Width;
int deltaY = Size.Height - origSize.Height;
Location = new Point(Location.X - (deltaX / 2), Location.Y - (deltaY / 2));
Location = new System.Drawing.Point(Location.X - (deltaX / 2), Location.Y - (deltaY / 2));
}
/// <summary>
@ -133,14 +134,14 @@ namespace OnTopReplica {
/// Improved with code from: http://stoyanoff.info/blog/2010/06/27/resizing-forms-while-keeping-aspect-ratio/
/// </summary>
protected override void WndProc(ref Message m) {
if (KeepAspectRatio && m.Msg == NativeMethods.WM_SIZING) {
var rc = (NativeMethods.Rectangle)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.Rectangle));
if (KeepAspectRatio && m.Msg == MessagingMethods.WM_SIZING) {
var rc = (Native.NRectangle)Marshal.PtrToStructure(m.LParam, typeof(Native.NRectangle));
int res = m.WParam.ToInt32();
int width = (rc.Right - rc.Left) - clientSizeConversionWidth - ExtraPadding.Horizontal;
int height = (rc.Bottom - rc.Top) - clientSizeConversionHeight - ExtraPadding.Vertical;
if (res == NativeMethods.WMSZ_LEFT || res == NativeMethods.WMSZ_RIGHT) {
if (res == MessagingMethods.WMSZ_LEFT || res == MessagingMethods.WMSZ_RIGHT) {
//Left or right resize, adjust top and bottom
int targetHeight = (int)(width / AspectRatio);
int diffHeight = height - targetHeight;
@ -148,7 +149,7 @@ namespace OnTopReplica {
rc.Top += (int)(diffHeight / 2.0);
rc.Bottom = rc.Top + targetHeight + ExtraPadding.Vertical + clientSizeConversionHeight;
}
else if (res == NativeMethods.WMSZ_TOP || res == NativeMethods.WMSZ_BOTTOM) {
else if (res == MessagingMethods.WMSZ_TOP || res == MessagingMethods.WMSZ_BOTTOM) {
//Up or down resize, adjust left and right
int targetWidth = (int)(height * AspectRatio);
int diffWidth = width - targetWidth;
@ -156,11 +157,11 @@ namespace OnTopReplica {
rc.Left += (int)(diffWidth / 2.0);
rc.Right = rc.Left + targetWidth + ExtraPadding.Horizontal + clientSizeConversionWidth;
}
else if (res == NativeMethods.WMSZ_RIGHT + NativeMethods.WMSZ_BOTTOM || res == NativeMethods.WMSZ_LEFT + NativeMethods.WMSZ_BOTTOM) {
else if (res == MessagingMethods.WMSZ_RIGHT + MessagingMethods.WMSZ_BOTTOM || res == MessagingMethods.WMSZ_LEFT + MessagingMethods.WMSZ_BOTTOM) {
//Lower corner resize, adjust bottom
rc.Bottom = rc.Top + (int)(width / AspectRatio) + ExtraPadding.Vertical + clientSizeConversionHeight;
}
else if (res == NativeMethods.WMSZ_LEFT + NativeMethods.WMSZ_TOP || res == NativeMethods.WMSZ_RIGHT + NativeMethods.WMSZ_TOP) {
else if (res == MessagingMethods.WMSZ_LEFT + MessagingMethods.WMSZ_TOP || res == MessagingMethods.WMSZ_RIGHT + MessagingMethods.WMSZ_TOP) {
//Upper corner resize, adjust top
rc.Top = rc.Bottom - (int)(width / AspectRatio) - ExtraPadding.Vertical - clientSizeConversionHeight;
}

View file

@ -151,7 +151,7 @@
this.dualWindowModeToolStripMenuItem.Name = "dualWindowModeToolStripMenuItem";
this.dualWindowModeToolStripMenuItem.Size = new System.Drawing.Size(177, 22);
this.dualWindowModeToolStripMenuItem.Text = "Dual window mode";
this.dualWindowModeToolStripMenuItem.Click += new System.EventHandler(this.Menu_Dual_click);
this.dualWindowModeToolStripMenuItem.Click += new System.EventHandler(this.Menu_Group_click);
//
// menuContextOpacity
//

View file

@ -5,19 +5,21 @@ using System.Windows.Forms;
using OnTopReplica.Properties;
using VistaControls.Dwm;
using VistaControls.TaskDialog;
using System.Collections.Generic;
using OnTopReplica.Native;
namespace OnTopReplica {
partial class MainForm : AspectRatioForm {
//GUI elements
ThumbnailPanel _thumbnailPanel;
//GUI elements
ThumbnailPanel _thumbnailPanel;
SidePanel _currentSidePanel = null;
Panel _sidePanelContainer;
//Window manager
WindowManager _windowManager = new WindowManager();
WindowHandle _lastWindowHandle = null;
WindowHandle _lastWindowHandle = null;
//Message pump extension
MessagePumpManager _msgPumpManager = new MessagePumpManager();
@ -26,16 +28,16 @@ namespace OnTopReplica {
InitializeComponent();
KeepAspectRatio = false;
//Thumbnail panel
_thumbnailPanel = new ThumbnailPanel {
Location = Point.Empty,
Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right,
Size = ClientSize
//Thumbnail panel
_thumbnailPanel = new ThumbnailPanel {
Location = Point.Empty,
Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right,
Size = ClientSize
};
_thumbnailPanel.CloneClick += new EventHandler<CloneClickEventArgs>(Thumbnail_CloneClick);
Controls.Add(_thumbnailPanel);
Controls.Add(_thumbnailPanel);
//Side panel
//Side panel
_sidePanelContainer = new Panel {
Location = new Point(ClientSize.Width, 0),
Anchor = AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom,
@ -44,12 +46,12 @@ namespace OnTopReplica {
Size = new Size(100, ClientSize.Height),
Padding = new Padding(4)
};
Controls.Add(_sidePanelContainer);
Controls.Add(_sidePanelContainer);
//Set native renderer on context menus
Asztal.Szótár.NativeToolStripRenderer.SetToolStripRenderer(
menuContext, menuWindows, menuOpacity, menuResize, menuLanguages
);
//Set native renderer on context menus
Asztal.Szótár.NativeToolStripRenderer.SetToolStripRenderer(
menuContext, menuWindows, menuOpacity, menuResize, menuLanguages
);
//Hook keyboard handler
this.KeyUp += new KeyEventHandler(Form_KeyUp);
@ -68,19 +70,20 @@ namespace OnTopReplica {
EventHandler RequestClosingHandler;
const int SidePanelMargin = 2;
const int SidePanelMargin = 1;
const int ScreenBorderMargin = 10;
bool _sidePanelDidMoveForm = false;
Point _sidePanelPreviousFormLocation;
bool _sidePanelDidMoveForm = false;
Point _sidePanelPreviousFormLocation;
/// <summary>
/// Opens a new side panel.
/// </summary>
/// <param name="panel">The side panel to embed.</param>
public void SetSidePanel(SidePanel panel) {
if (_currentSidePanel != null)
if (_currentSidePanel != null) {
CloseSidePanel();
}
_currentSidePanel = panel;
_currentSidePanel.OnFirstShown(this);
@ -95,13 +98,17 @@ namespace OnTopReplica {
//Resize container
_sidePanelContainer.ClientSize = new Size(
panel.Width + intHorzMargin,
panel.MinimumSize.Width + intHorzMargin,
ClientSize.Height
);
int rightHorzMargin = _sidePanelContainer.Width + SidePanelMargin; //horz margin between the two controls
//Resize rest
MinimumSize = new Size(
20 + panel.MinimumSize.Width + SidePanelMargin + intHorzMargin,
panel.MinimumSize.Height + intVertMargin
);
ClientSize = new Size(
ClientSize.Width + rightHorzMargin,
ClientSize.Height
@ -115,10 +122,6 @@ namespace OnTopReplica {
ClientSize.Width - rightHorzMargin,
0
);
MinimumSize = new Size(
20 + panel.MinimumSize.Width + SidePanelMargin + intHorzMargin,
panel.MinimumSize.Height + intVertMargin
);
//Move window if needed
var screenCurr = Screen.FromControl(this);
@ -175,14 +178,14 @@ namespace OnTopReplica {
CloseSidePanel();
}
void Thumbnail_CloneClick(object sender, CloneClickEventArgs e) {
void Thumbnail_CloneClick(object sender, CloneClickEventArgs e) {
//TODO: handle other mouse buttons
Win32Helper.InjectFakeMouseClick(_lastWindowHandle.Handle, e.ClientClickLocation, e.IsDoubleClick);
}
Win32Helper.InjectFakeMouseClick(_lastWindowHandle.Handle, e.ClientClickLocation, e.IsDoubleClick);
}
#endregion
#region Event override
#region Event override
protected override void OnShown(EventArgs e) {
base.OnShown(e);
@ -202,7 +205,7 @@ namespace OnTopReplica {
protected override void OnResize(EventArgs e) {
base.OnResize(e);
this.GlassMargins = (_currentSidePanel != null) ?
new Margins(ClientSize.Width - _sidePanelContainer.Width, 0, 0, 0) :
new Margins(-1);
@ -228,22 +231,22 @@ namespace OnTopReplica {
protected override void WndProc(ref Message m) {
_msgPumpManager.PumpMessage(m);
switch(m.Msg){
case NativeMethods.WM_NCRBUTTONUP:
switch (m.Msg) {
case MessagingMethods.WM_NCRBUTTONUP:
//Open context menu if right button clicked on caption (i.e. all of the window area because of glass)
if (m.WParam.ToInt32() == NativeMethods.HTCAPTION) {
if (m.WParam.ToInt32() == MessagingMethods.HTCAPTION) {
menuContext.Show(MousePosition);
m.Result = IntPtr.Zero;
return;
}
break;
case NativeMethods.WM_NCLBUTTONDBLCLK:
case MessagingMethods.WM_NCLBUTTONDBLCLK:
//Toggle fullscreen mode if double click on caption (whole glass area)
if (m.WParam.ToInt32() == NativeMethods.HTCAPTION) {
if (m.WParam.ToInt32() == MessagingMethods.HTCAPTION) {
IsFullscreen = !IsFullscreen;
m.Result = IntPtr.Zero;
return;
}
@ -253,7 +256,7 @@ namespace OnTopReplica {
base.WndProc(ref m);
}
#endregion
#endregion
#region Menu Event Handling
@ -261,46 +264,46 @@ namespace OnTopReplica {
this.Close();
}
private void Menu_opening(object sender, CancelEventArgs e) {
//Cancel if currently in "fullscreen" mode or a side panel is open
if (IsFullscreen || _currentSidePanel != null) {
e.Cancel = true;
return;
}
private void Menu_opening(object sender, CancelEventArgs e) {
//Cancel if currently in "fullscreen" mode or a side panel is open
if (IsFullscreen || _currentSidePanel != null) {
e.Cancel = true;
return;
}
selectRegionToolStripMenuItem.Enabled = _thumbnailPanel.IsShowingThumbnail;
switchToWindowToolStripMenuItem.Enabled = _thumbnailPanel.IsShowingThumbnail;
resizeToolStripMenuItem.Enabled = _thumbnailPanel.IsShowingThumbnail;
chromeToolStripMenuItem.Checked = (FormBorderStyle == FormBorderStyle.Sizable);
forwardClicksToolStripMenuItem.Checked = _thumbnailPanel.ReportThumbnailClicks;
}
selectRegionToolStripMenuItem.Enabled = _thumbnailPanel.IsShowingThumbnail;
switchToWindowToolStripMenuItem.Enabled = _thumbnailPanel.IsShowingThumbnail;
resizeToolStripMenuItem.Enabled = _thumbnailPanel.IsShowingThumbnail;
chromeToolStripMenuItem.Checked = (FormBorderStyle == FormBorderStyle.Sizable);
forwardClicksToolStripMenuItem.Checked = _thumbnailPanel.ReportThumbnailClicks;
}
private void Menu_Close_click(object sender, EventArgs e) {
this.Close();
}
private void Menu_About_click(object sender, EventArgs e) {
this.Hide();
this.Hide();
using (var box = new AboutForm()) {
box.Location = RecenterLocation(this, box);
box.ShowDialog();
Location = RecenterLocation(box, this);
}
this.Show();
this.Show();
}
private void Menu_Language_click(object sender, EventArgs e) {
ToolStripItem tsi = (ToolStripItem)sender;
private void Menu_Language_click(object sender, EventArgs e) {
ToolStripItem tsi = (ToolStripItem)sender;
string langCode = tsi.Tag as string;
string langCode = tsi.Tag as string;
if (Program.ForceGlobalLanguageChange(langCode))
this.Close();
else
MessageBox.Show("Error");
}
if (Program.ForceGlobalLanguageChange(langCode))
this.Close();
else
MessageBox.Show("Error");
}
void Menu_Windows_itemclick(object sender, EventArgs e) {
//Ensure the menu is closed
@ -309,41 +312,41 @@ namespace OnTopReplica {
//Get clicked item and window index from tag
ToolStripItem tsi = (ToolStripItem)sender;
//Handle special "none" window
if (tsi.Tag == null) {
UnsetThumbnail();
return;
}
//Handle special "none" window
if (tsi.Tag == null) {
UnsetThumbnail();
return;
}
var selectionData = (WindowListHelper.WindowSelectionData)tsi.Tag;
SetThumbnail(selectionData.Handle, selectionData.Region);
}
private void Menu_Switch_click(object sender, EventArgs e) {
if (_lastWindowHandle == null)
return;
private void Menu_Switch_click(object sender, EventArgs e) {
if (_lastWindowHandle == null)
return;
Program.Platform.HideForm(this);
NativeMethods.SetForegroundWindow(_lastWindowHandle.Handle);
}
private void Menu_Dual_click(object sender, EventArgs e) {
Native.WindowManagerMethods.SetForegroundWindow(_lastWindowHandle.Handle);
}
private void Menu_Forward_click(object sender, EventArgs e) {
if (Settings.Default.FirstTimeClickForwarding && !_thumbnailPanel.ReportThumbnailClicks) {
private void Menu_Group_click(object sender, EventArgs e) {
SetSidePanel(new SidePanels.GroupSwitchPanel());
}
private void Menu_Forward_click(object sender, EventArgs e) {
if (Settings.Default.FirstTimeClickForwarding && !_thumbnailPanel.ReportThumbnailClicks) {
TaskDialog dlg = new TaskDialog(Strings.InfoClickForwarding, Strings.InfoClickForwardingTitle, Strings.InfoClickForwardingContent) {
CommonButtons = TaskDialogButton.Yes | TaskDialogButton.No
};
if (dlg.Show(this).CommonButton == Result.No)
return;
if (dlg.Show(this).CommonButton == Result.No)
return;
Settings.Default.FirstTimeClickForwarding = false;
}
Settings.Default.FirstTimeClickForwarding = false;
}
_thumbnailPanel.ReportThumbnailClicks = !_thumbnailPanel.ReportThumbnailClicks;
}
_thumbnailPanel.ReportThumbnailClicks = !_thumbnailPanel.ReportThumbnailClicks;
}
private void Menu_Opacity_opening(object sender, CancelEventArgs e) {
ToolStripMenuItem[] items = {
@ -353,12 +356,12 @@ namespace OnTopReplica {
toolStripMenuItem4
};
foreach (ToolStripMenuItem i in items) {
if ((double)i.Tag == this.Opacity)
i.Checked = true;
else
i.Checked = false;
}
foreach (ToolStripMenuItem i in items) {
if ((double)i.Tag == this.Opacity)
i.Checked = true;
else
i.Checked = false;
}
}
private void Menu_Opacity_click(object sender, EventArgs e) {
@ -371,84 +374,84 @@ namespace OnTopReplica {
}
}
private void Menu_Region_click(object sender, EventArgs e) {
private void Menu_Region_click(object sender, EventArgs e) {
SetSidePanel(new OnTopReplica.SidePanels.RegionPanel());
}
private void Menu_Resize_opening(object sender, CancelEventArgs e) {
if (!_thumbnailPanel.IsShowingThumbnail)
e.Cancel = true;
}
}
private void Menu_Resize_Double(object sender, EventArgs e) {
FitToThumbnail(2.0);
}
private void Menu_Resize_opening(object sender, CancelEventArgs e) {
if (!_thumbnailPanel.IsShowingThumbnail)
e.Cancel = true;
}
private void Menu_Resize_FitToWindow(object sender, EventArgs e) {
FitToThumbnail(1.0);
}
private void Menu_Resize_Double(object sender, EventArgs e) {
FitToThumbnail(2.0);
}
private void Menu_Resize_Half(object sender, EventArgs e) {
FitToThumbnail(0.5);
}
private void Menu_Resize_FitToWindow(object sender, EventArgs e) {
FitToThumbnail(1.0);
}
private void Menu_Resize_Quarter(object sender, EventArgs e) {
FitToThumbnail(0.25);
}
private void Menu_Resize_Half(object sender, EventArgs e) {
FitToThumbnail(0.5);
}
private void Menu_Resize_Fullscreen(object sender, EventArgs e) {
private void Menu_Resize_Quarter(object sender, EventArgs e) {
FitToThumbnail(0.25);
}
private void Menu_Resize_Fullscreen(object sender, EventArgs e) {
IsFullscreen = true;
}
}
private void Menu_Position_TopLeft(object sender, EventArgs e) {
var screen = Screen.FromControl(this);
private void Menu_Position_TopLeft(object sender, EventArgs e) {
var screen = Screen.FromControl(this);
Location = new Point(
Location = new Point(
screen.WorkingArea.Left - ChromeBorderHorizontal,
screen.WorkingArea.Top - ChromeBorderVertical
);
}
);
}
private void Menu_Position_TopRight(object sender, EventArgs e) {
var screen = Screen.FromControl(this);
private void Menu_Position_TopRight(object sender, EventArgs e) {
var screen = Screen.FromControl(this);
Location = new Point(
Location = new Point(
screen.WorkingArea.Width - Size.Width + ChromeBorderHorizontal,
screen.WorkingArea.Top - ChromeBorderVertical
);
}
);
}
private void Menu_Position_BottomLeft(object sender, EventArgs e) {
var screen = Screen.FromControl(this);
private void Menu_Position_BottomLeft(object sender, EventArgs e) {
var screen = Screen.FromControl(this);
Location = new Point(
Location = new Point(
screen.WorkingArea.Left - ChromeBorderHorizontal,
screen.WorkingArea.Height - Size.Height + ChromeBorderVertical
);
}
);
}
private void Menu_Position_BottomRight(object sender, EventArgs e) {
var screen = Screen.FromControl(this);
private void Menu_Position_BottomRight(object sender, EventArgs e) {
var screen = Screen.FromControl(this);
Location = new Point(
screen.WorkingArea.Width - Size.Width + ChromeBorderHorizontal,
Location = new Point(
screen.WorkingArea.Width - Size.Width + ChromeBorderHorizontal,
screen.WorkingArea.Height - Size.Height + ChromeBorderVertical
);
}
);
}
private void Menu_Reduce_click(object sender, EventArgs e) {
//Hide form in a platform specific way
Program.Platform.HideForm(this);
}
private void Menu_Windows_opening(object sender, EventArgs e) {
//Refresh window list
_windowManager.Refresh(WindowManager.EnumerationMode.TaskWindows);
private void Menu_Windows_opening(object sender, EventArgs e) {
//Refresh window list
_windowManager.Refresh(WindowManager.EnumerationMode.TaskWindows);
WindowListHelper.PopulateMenu(this, _windowManager, menuWindows, _lastWindowHandle, new EventHandler(Menu_Windows_itemclick));
}
WindowListHelper.PopulateMenu(this, _windowManager, menuWindows, _lastWindowHandle, new EventHandler(Menu_Windows_itemclick));
}
private void Menu_Chrome_click(object sender, EventArgs e) {
private void Menu_Chrome_click(object sender, EventArgs e) {
if (FormBorderStyle == FormBorderStyle.Sizable) {
FormBorderStyle = FormBorderStyle.None;
Location = new Point {
@ -464,12 +467,12 @@ namespace OnTopReplica {
};
}
Invalidate();
}
Invalidate();
}
#endregion
#region Event handling
#region Event handling
void Form_KeyUp(object sender, KeyEventArgs e) {
//ALT
@ -521,9 +524,9 @@ namespace OnTopReplica {
}
}
#endregion
#endregion
#region Fullscreen
#region Fullscreen
bool _isFullscreen = false;
Point _preFullscreenLocation;
@ -560,9 +563,9 @@ namespace OnTopReplica {
}
}
#endregion
#endregion
#region Thumbnail operation
#region Thumbnail operation
/// <summary>
/// Sets a new thumbnail.
@ -571,8 +574,9 @@ namespace OnTopReplica {
/// <param name="region">Region of the window to clone.</param>
public void SetThumbnail(WindowHandle handle, StoredRegion region) {
try {
_lastWindowHandle = handle;
_thumbnailPanel.SetThumbnailHandle(handle);
_lastWindowHandle = handle;
_thumbnailPanel.SetThumbnailHandle(handle);
if (region != null)
_thumbnailPanel.SelectedRegion = region.Rect;
else
@ -586,13 +590,32 @@ namespace OnTopReplica {
SetAspectRatio(_thumbnailPanel.ThumbnailOriginalSize);
}
/// <summary>
/// Enables group mode on a list of window handles.
/// </summary>
/// <param name="handles">List of window handles.</param>
public void SetThumbnailGroup(IList<WindowHandle> handles) {
if (handles.Count == 0)
return;
//At last one thumbnail
SetThumbnail(handles[0], null);
//Handle if no real group
if (handles.Count == 1)
return;
_lastWindowHandle = null;
_msgPumpManager.Get<MessagePumpProcessors.GroupSwitchManager>().EnableGroupMode(handles);
}
/// <summary>
/// Disables the cloned thumbnail.
/// </summary>
public void UnsetThumbnail(){
public void UnsetThumbnail() {
//Unset handle
_lastWindowHandle = null;
_thumbnailPanel.UnsetThumbnail();
_lastWindowHandle = null;
_thumbnailPanel.UnsetThumbnail();
//Disable aspect ratio
KeepAspectRatio = false;
@ -632,30 +655,39 @@ namespace OnTopReplica {
}
}
private void ThumbnailError(Exception ex, bool suppress, string title){
/// <summary>
/// Gets the form's message pump manager.
/// </summary>
public MessagePumpManager MessagePumpManager {
get {
return _msgPumpManager;
}
}
private void ThumbnailError(Exception ex, bool suppress, string title) {
if (!suppress) {
ShowErrorDialog(title, Strings.ErrorGenericThumbnailHandleError, ex.Message);
}
UnsetThumbnail();
}
/// <summary>Automatically sizes the window in order to accomodate the thumbnail p times.</summary>
/// <param name="p">Scale of the thumbnail to consider.</param>
private void FitToThumbnail(double p) {
try {
Size originalSize = _thumbnailPanel.ThumbnailOriginalSize;
Size fittedSize = new Size((int)(originalSize.Width * p), (int)(originalSize.Height * p));
ClientSize = fittedSize;
}
catch (Exception ex) {
ThumbnailError(ex, false, Strings.ErrorUnableToFit);
}
}
/// <summary>Automatically sizes the window in order to accomodate the thumbnail p times.</summary>
/// <param name="p">Scale of the thumbnail to consider.</param>
private void FitToThumbnail(double p) {
try {
Size originalSize = _thumbnailPanel.ThumbnailOriginalSize;
Size fittedSize = new Size((int)(originalSize.Width * p), (int)(originalSize.Height * p));
ClientSize = fittedSize;
}
catch (Exception ex) {
ThumbnailError(ex, false, Strings.ErrorUnableToFit);
}
}
#endregion
#region GUI stuff
#region GUI stuff
private Point RecenterLocation(Control original, Control final) {
int origX = original.Location.X + original.Size.Width / 2;
@ -702,19 +734,19 @@ namespace OnTopReplica {
/// <param name="mainInstruction">Main instruction of the error dialog.</param>
/// <param name="explanation">Detailed informations about the error.</param>
/// <param name="errorMessage">Expanded error codes/messages.</param>
private void ShowErrorDialog(string mainInstruction, string explanation, string errorMessage) {
private void ShowErrorDialog(string mainInstruction, string explanation, string errorMessage) {
TaskDialog dlg = new TaskDialog(mainInstruction, Strings.ErrorGenericTitle, explanation) {
CommonIcon = TaskDialogIcon.Stop,
IsExpanded = false
};
if (!string.IsNullOrEmpty(errorMessage)) {
dlg.ExpandedInformation = Strings.ErrorGenericInfoText + errorMessage;
dlg.ExpandedControlText = Strings.ErrorGenericInfoButton;
}
if (!string.IsNullOrEmpty(errorMessage)) {
dlg.ExpandedInformation = Strings.ErrorGenericInfoText + errorMessage;
dlg.ExpandedControlText = Strings.ErrorGenericInfoButton;
}
dlg.Show(this);
}
dlg.Show(this);
}
/// <summary>
/// Ensures that the main form is visible (either closing the fullscreen mode or reactivating from task icon).
@ -765,7 +797,7 @@ namespace OnTopReplica {
this.Activate();
}
#endregion
#endregion
}
}
}

View file

@ -1,58 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using System.Windows.Forms;
using OnTopReplica.Native;
namespace OnTopReplica.MessagePumpProcessors {
class DualModeManager : BaseMessagePumpProcessor {
public DualModeManager() {
_hookMsgId = HookMethods.RegisterWindowMessage("SHELLHOOK");
if (_hookMsgId == 0)
Console.Error.WriteLine("Failed to register SHELLHOOK Windows message.");
}
uint _hookMsgId;
bool _active = false;
public void EnableDualMode(IEnumerable<WindowHandle> handles) {
if (!HookMethods.RegisterShellHookWindow(Form.Handle)) {
Console.WriteLine("Failed to register shell hook window.");
return;
}
_active = true;
}
public void Disable() {
if (!_active)
return;
if (!HookMethods.DeregisterShellHookWindow(Form.Handle))
Console.WriteLine("Failed to deregister shell hook window.");
_active = false;
}
public override void Process(Message msg) {
if (msg.Msg == _hookMsgId) {
int hookCode = msg.WParam.ToInt32();
if (hookCode == HookMethods.HSHELL_WINDOWACTIVATED ||
hookCode == HookMethods.HSHELL_RUDEAPPACTIVATED) {
IntPtr activeHandle = msg.LParam;
}
}
}
protected override void Shutdown() {
Disable();
}
}
}

View file

@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using System.Windows.Forms;
using OnTopReplica.Native;
namespace OnTopReplica.MessagePumpProcessors {
class GroupSwitchManager : BaseMessagePumpProcessor {
public GroupSwitchManager() {
_hookMsgId = HookMethods.RegisterWindowMessage("SHELLHOOK");
if (_hookMsgId == 0)
Console.Error.WriteLine("Failed to register SHELLHOOK Windows message.");
}
uint _hookMsgId;
bool _active = false;
IList<WindowHandle> _handles;
public void EnableGroupMode(IList<WindowHandle> handles) {
//Enable new hook
if (!_active) {
if (!HookMethods.RegisterShellHookWindow(Form.Handle)) {
Console.WriteLine("Failed to register shell hook window.");
return;
}
}
//Okey dokey, will now track handles
_handles = handles;
_active = true;
}
public void Disable() {
if (!_active)
return;
if (!HookMethods.DeregisterShellHookWindow(Form.Handle))
Console.WriteLine("Failed to deregister shell hook window.");
_active = false;
}
public override void Process(Message msg) {
if (_active && msg.Msg == _hookMsgId) {
int hookCode = msg.WParam.ToInt32();
if (hookCode == HookMethods.HSHELL_WINDOWACTIVATED ||
hookCode == HookMethods.HSHELL_RUDEAPPACTIVATED) {
IntPtr activeHandle = msg.LParam;
Console.WriteLine("New foreground: {0}", activeHandle);
HandleForegroundWindowChange(activeHandle);
}
}
}
private void HandleForegroundWindowChange(IntPtr activeWindow) {
int iActive = -1;
for (int i = 0; i < _handles.Count; ++i) {
if (_handles[i].Handle == activeWindow)
iActive = i;
}
if (iActive < 0) {
//new foreground window is not tracked
Console.WriteLine("Active window is not tracked.");
return;
}
//Get new handle to clone
int iNewToClone = (iActive + 1) % _handles.Count;
Console.WriteLine("Tracked as {0}. Switching to {1}.", iActive, iNewToClone);
Form.SetThumbnail(_handles[iNewToClone], null);
}
protected override void Shutdown() {
Disable();
}
/// <summary>
/// Gets whether the group switch manager ia active.
/// </summary>
public bool IsActive {
get {
return _active;
}
}
}
}

View file

@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace OnTopReplica.Native {
/// <summary>
/// Common Win32 error handling methods.
/// </summary>
static class ErrorMethods {
[DllImport("kernel32.dll")]
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource,
int dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer,
uint nSize, IntPtr Arguments);
/// <summary>
/// Gets a string representation of a Win32 error code.
/// </summary>
/// <param name="msgCode">ID of the Win32 error code.</param>
/// <returns>String representation of the error.</returns>
public static string GetErrorMessage(int msgCode) {
var sb = new StringBuilder(300);
FormatMessage((uint)(0x00001000), IntPtr.Zero, msgCode, 0, sb, 299, IntPtr.Zero);
return sb.ToString();
}
/// <summary>
/// Gets a string representation of the last Win32 error on this thread.
/// </summary>
public static string GetLastErrorMessage() {
int errorCode = Marshal.GetLastWin32Error();
return GetErrorMessage(errorCode);
}
}
}

View file

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace OnTopReplica.Native {
/// <summary>
/// Common methods for Win32 messaging.
/// </summary>
static class MessagingMethods {
public const int WM_GETICON = 0x7f;
public const int WM_SIZING = 0x214;
public const int WMSZ_LEFT = 1;
public const int WMSZ_RIGHT = 2;
public const int WMSZ_TOP = 3;
public const int WMSZ_BOTTOM = 6;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[Flags]
public enum SendMessageTimeoutFlags : uint {
AbortIfHung = 2,
Block = 1,
Normal = 0
}
[DllImport("user32.dll")]
public static extern IntPtr SendMessageTimeout(IntPtr hwnd, uint message, IntPtr wparam, IntPtr lparam, SendMessageTimeoutFlags flags, uint timeout, out IntPtr result);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = false)]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
public const int HTTRANSPARENT = -1;
public const int HTCLIENT = 1;
public const int HTCAPTION = 2;
public const int WM_NCHITTEST = 0x84;
public const int WM_NCPAINT = 0x0085;
public const int WM_LBUTTONDOWN = 0x0201;
public const int WM_LBUTTONUP = 0x0202;
public const int WM_LBUTTONDBLCLK = 0x0203;
public const int WM_NCLBUTTONUP = 0x00A2;
public const int WM_NCLBUTTONDOWN = 0x00A1;
public const int WM_NCLBUTTONDBLCLK = 0x00A3;
public const int WM_NCRBUTTONUP = 0x00A5;
public const int MK_LBUTTON = 0x0001;
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_MAXIMIZE = 61458;
public const int SC_RESTORE = 61490;
public static IntPtr MakeLParam(int LoWord, int HiWord) {
return new IntPtr((HiWord << 16) | (LoWord & 0xffff));
}
}
}

View file

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace OnTopReplica.Native {
/// <summary>
/// Native Point structure.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct NPoint {
public int X, Y;
public NPoint(int x, int y) {
X = x;
Y = y;
}
public NPoint(NPoint copy) {
X = copy.X;
Y = copy.Y;
}
public static NPoint FromPoint(System.Drawing.Point point) {
return new NPoint(point.X, point.Y);
}
public System.Drawing.Point ToPoint() {
return new System.Drawing.Point(X, Y);
}
public override string ToString() {
return "{" + X + "," + Y + "}";
}
}
}

View file

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace OnTopReplica.Native {
/// <summary>A native Rectangle Structure.</summary>
[StructLayout(LayoutKind.Sequential)]
struct NRectangle {
public NRectangle(int left, int top, int right, int bottom) {
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public NRectangle(System.Drawing.Rectangle rect) {
Left = rect.X;
Top = rect.Y;
Right = rect.Right;
Bottom = rect.Bottom;
}
public int Left;
public int Top;
public int Right;
public int Bottom;
public int Width {
get {
return Right - Left;
}
}
public int Height {
get {
return Bottom - Top;
}
}
public System.Drawing.Rectangle ToRectangle() {
return new System.Drawing.Rectangle(Left, Top, Right - Left, Bottom - Top);
}
}
}

View file

@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace OnTopReplica.Native {
/// <summary>
/// Common Win32 Window Manager native methods.
/// </summary>
static class WindowManagerMethods {
[DllImport("user32.dll")]
public static extern IntPtr RealChildWindowFromPoint(IntPtr parent, NPoint point);
[return: MarshalAs(UnmanagedType.Bool)]
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
static extern bool ClientToScreen(IntPtr hwnd, ref NPoint point);
/// <summary>
/// Converts a point in client coordinates of a window to screen coordinates.
/// </summary>
/// <param name="hwnd">Handle to the window of the original point.</param>
/// <param name="clientPoint">Point expressed in client coordinates.</param>
/// <returns>Point expressed in screen coordinates.</returns>
public static NPoint ClientToScreen(IntPtr hwnd, NPoint clientPoint) {
NPoint localCopy = new NPoint(clientPoint);
if (ClientToScreen(hwnd, ref localCopy))
return localCopy;
else
return new NPoint();
}
[DllImport("user32.dll")]
static extern bool ScreenToClient(IntPtr hwnd, ref NPoint point);
/// <summary>
/// Converts a point in screen coordinates in client coordinates relative to a window.
/// </summary>
/// <param name="hwnd">Handle of the window whose client coordinate system should be used.</param>
/// <param name="screenPoint">Point expressed in screen coordinates.</param>
/// <returns>Point expressed in client coordinates.</returns>
public static NPoint ScreenToClient(IntPtr hwnd, NPoint screenPoint) {
NPoint localCopy = new NPoint(screenPoint);
if (ScreenToClient(hwnd, ref localCopy))
return localCopy;
else
return new NPoint();
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetParent(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = false)]
public static extern bool SetForegroundWindow(IntPtr hwnd);
public enum GetWindowMode : uint {
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
[DllImport("user32.dll")]
public static extern IntPtr GetWindow(IntPtr hwnd, GetWindowMode mode);
}
}

View file

@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace OnTopReplica.Native {
/// <summary>
/// Common Win32 methods for operating on windows.
/// </summary>
static class WindowMethods {
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, [Out] StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetWindowTextLength(IntPtr hWnd);
public enum WindowLong {
WndProc = (-4),
HInstance = (-6),
HwndParent = (-8),
Style = (-16),
ExStyle = (-20),
UserData = (-21),
Id = (-12)
}
public enum ClassLong {
Icon = -14,
IconSmall = -34
}
[Flags]
public enum WindowStyles : long {
None = 0,
Disabled = 0x8000000L,
Minimize = 0x20000000L,
MinimizeBox = 0x20000L,
Visible = 0x10000000L
}
[Flags]
public enum WindowExStyles : long {
AppWindow = 0x40000,
Layered = 0x80000,
NoActivate = 0x8000000L,
ToolWindow = 0x80,
TopMost = 8,
Transparent = 0x20
}
public static IntPtr GetWindowLong(IntPtr hWnd, WindowLong i) {
if (IntPtr.Size == 8) {
return GetWindowLongPtr64(hWnd, (int)i);
}
else {
return new IntPtr(GetWindowLong32(hWnd, (int)i));
}
}
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
static extern int GetWindowLong32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
public static IntPtr GetClassLongPtr(IntPtr hWnd, ClassLong i) {
if (IntPtr.Size == 8) {
return GetClassLong64(hWnd, (int)i);
}
else {
return new IntPtr(GetClassLong32(hWnd, (int)i));
}
}
[DllImport("user32.dll", EntryPoint = "GetClassLongPtrW")]
static extern IntPtr GetClassLong64(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetClassLongW")]
static extern int GetClassLong32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
public static extern IntPtr GetMenu(IntPtr hwnd);
}
}

View file

@ -1,312 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace OnTopReplica
{
static class NativeMethods
{
/// <summary>A native Rectangle Structure.</summary>
[StructLayout(LayoutKind.Sequential)]
public struct Rectangle
{
public Rectangle(int left, int top, int right, int bottom) {
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public Rectangle(System.Drawing.Rectangle rect) {
Left = rect.X;
Top = rect.Y;
Right = rect.Right;
Bottom = rect.Bottom;
}
public int Left;
public int Top;
public int Right;
public int Bottom;
public int Width {
get {
return Right - Left;
}
}
public int Height {
get {
return Bottom - Top;
}
}
public System.Drawing.Rectangle ToRectangle() {
return new System.Drawing.Rectangle(Left, Top, Right - Left, Bottom - Top);
}
}
[StructLayout(LayoutKind.Sequential)]
public struct Point {
public int X, Y;
public Point(int x, int y) {
X = x;
Y = y;
}
public Point(Point copy) {
X = copy.X;
Y = copy.Y;
}
public static Point FromPoint(System.Drawing.Point point) {
return new Point(point.X, point.Y);
}
public System.Drawing.Point ToPoint() {
return new System.Drawing.Point(X, Y);
}
public override string ToString() {
return "{" + X + "," + Y + "}";
}
}
[DllImport("user32.dll")]
public static extern IntPtr RealChildWindowFromPoint(IntPtr parent, Point point);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect);
public static System.Drawing.Rectangle GetClient(IntPtr hWnd) {
Rectangle ret;
if (GetClientRect(hWnd, out ret))
return ret.ToRectangle();
else
throw new Exception("Failed to get Client Rectangle.");
}
[DllImport("user32.dll")]
static extern bool GetWindowRect(IntPtr hWnd, out Rectangle lpRect);
public static System.Drawing.Rectangle GetWindowBounds(IntPtr hWnd) {
Rectangle ret = new Rectangle();
if (GetWindowRect(hWnd, out ret))
return ret.ToRectangle();
else
throw new Exception("Failed to get Window Bounds.");
}
[return: MarshalAs(UnmanagedType.Bool)]
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
static extern bool ClientToScreen(IntPtr hwnd, ref Point point);
public static Point ClientToScreen(IntPtr hwnd, Point clientPoint) {
Point localCopy = new Point(clientPoint);
if (ClientToScreen(hwnd, ref localCopy))
return localCopy;
else
return new Point();
}
[DllImport("user32.dll")]
static extern bool ScreenToClient(IntPtr hwnd, ref Point point);
public static Point ScreenToClient(IntPtr hwnd, Point screenPoint) {
Point localCopy = new Point(screenPoint);
if (ScreenToClient(hwnd, ref localCopy))
return localCopy;
else
return new Point();
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetParent(IntPtr hWnd);
public enum GetAncestorMode : uint {
Parent = 1,
Root = 2,
RootOwner = 3
}
public enum GetWindowMode : uint {
GW_HWNDFIRST = 0,
GW_HWNDLAST = 1,
GW_HWNDNEXT = 2,
GW_HWNDPREV = 3,
GW_OWNER = 4,
GW_CHILD = 5,
GW_ENABLEDPOPUP = 6
}
[DllImport("user32.dll")]
public static extern IntPtr GetWindow(IntPtr hwnd, GetWindowMode mode);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetWindowText(IntPtr hWnd, [Out] StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetWindowTextLength(IntPtr hWnd);
public enum WindowLong {
WndProc = (-4),
HInstance = (-6),
HwndParent = (-8),
Style = (-16),
ExStyle = (-20),
UserData = (-21),
Id = (-12)
}
public enum ClassLong {
Icon = -14,
IconSmall = -34
}
[Flags]
public enum WindowStyles : long {
None = 0,
Disabled = 0x8000000L,
Minimize = 0x20000000L,
MinimizeBox = 0x20000L,
Visible = 0x10000000L
}
[Flags]
public enum WindowExStyles : long {
AppWindow = 0x40000,
Layered = 0x80000,
NoActivate = 0x8000000L,
ToolWindow = 0x80,
TopMost = 8,
Transparent = 0x20
}
public static IntPtr GetWindowLong(IntPtr hWnd, WindowLong i) {
if (IntPtr.Size == 8) {
return GetWindowLongPtr64(hWnd, (int)i);
}
else {
return new IntPtr(GetWindowLong32(hWnd, (int)i));
}
}
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
private static extern int GetWindowLong32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);
public static IntPtr GetClassLongPtr(IntPtr hWnd, ClassLong i) {
if (IntPtr.Size == 8) {
return GetClassLong64(hWnd, (int)i);
}
return new IntPtr(GetClassLong32(hWnd, (int)i));
}
[DllImport("user32.dll", EntryPoint = "GetClassLongPtrW")]
private static extern IntPtr GetClassLong64(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetClassLongW")]
private static extern int GetClassLong32(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr SendMessageTimeout(IntPtr hwnd, uint message, IntPtr wparam, IntPtr lparam, SendMessageTimeoutFlags flags, uint timeout, out IntPtr result);
public const uint WM_GETICON = 0x7f;
public const int WM_SIZING = 0x214;
public const int WMSZ_LEFT = 1;
public const int WMSZ_RIGHT = 2;
public const int WMSZ_TOP = 3;
public const int WMSZ_BOTTOM = 6;
[Flags]
public enum SendMessageTimeoutFlags : uint {
AbortIfHung = 2,
Block = 1,
Normal = 0
}
public const int HTTRANSPARENT = -1;
public const int HTCLIENT = 1;
public const int HTCAPTION = 2;
public const int WM_NCHITTEST = 0x84;
public const int WM_NCPAINT = 0x0085;
public const int WM_LBUTTONDOWN = 0x0201;
public const int WM_LBUTTONUP = 0x0202;
public const int WM_LBUTTONDBLCLK = 0x0203;
public const int WM_NCLBUTTONUP = 0x00A2;
public const int WM_NCLBUTTONDOWN = 0x00A1;
public const int WM_NCLBUTTONDBLCLK = 0x00A3;
public const int WM_NCRBUTTONUP = 0x00A5;
public const int MK_LBUTTON = 0x0001;
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_MAXIMIZE = 61458;
public const int SC_RESTORE = 61490;
public static IntPtr MakeLParam(int LoWord, int HiWord) {
return new IntPtr((HiWord << 16) | (LoWord & 0xffff));
}
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = false)]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = false)]
public static extern bool SetForegroundWindow(IntPtr hwnd);
[DllImport("user32.dll")]
public static extern IntPtr GetMenu(IntPtr hwnd);
[DllImport("user32.dll")]
public static extern short GetKeyState(VirtualKeyState nVirtKey);
[DllImport("kernel32.dll")]
static extern uint FormatMessage(uint dwFlags, IntPtr lpSource,
int dwMessageId, uint dwLanguageId, [Out] StringBuilder lpBuffer,
uint nSize, IntPtr Arguments);
public static string GetLastErrorMessage(int msgCode) {
var sb = new StringBuilder(300);
FormatMessage((uint)(0x00001000), IntPtr.Zero, msgCode, 0, sb, 299, IntPtr.Zero);
return sb.ToString();
}
}
}

View file

@ -133,14 +133,26 @@
<Compile Include="CloneClickEventArgs.cs" />
<Compile Include="CloseRequestEventArgs.cs" />
<Compile Include="MessagePumpManager.cs" />
<Compile Include="MessagePumpProcessors\DualModeManager.cs" />
<Compile Include="MessagePumpProcessors\GroupSwitchManager.cs" />
<Compile Include="IMessagePumpProcessor.cs" />
<Compile Include="MessagePumpProcessors\BaseMessagePumpProcessor.cs" />
<Compile Include="Native\ErrorMethods.cs" />
<Compile Include="Native\HookMethods.cs" />
<Compile Include="Native\HotKeyMethods.cs" />
<Compile Include="Native\MessagingMethods.cs" />
<Compile Include="Native\Point.cs" />
<Compile Include="Native\Rectangle.cs" />
<Compile Include="Native\WindowManagerMethods.cs" />
<Compile Include="Native\WindowMethods.cs" />
<Compile Include="SidePanel.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="SidePanels\GroupSwitchPanel.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="SidePanels\GroupSwitchPanel.Designer.cs">
<DependentUpon>GroupSwitchPanel.cs</DependentUpon>
</Compile>
<Compile Include="StoredRegionComparer.cs" />
<Compile Include="WindowsSevenMethods.cs" />
<None Include="CommonControls.cs" />
@ -176,7 +188,6 @@
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="NativeMethods.cs" />
<Compile Include="NativeToolStripRenderer.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@ -184,6 +195,10 @@
<DependentUpon>AboutForm.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="SidePanels\GroupSwitchPanel.resx">
<DependentUpon>GroupSwitchPanel.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Strings.cs.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.cs.Designer.cs</LastGenOutput>
@ -245,7 +260,6 @@
<Compile Include="ThumbnailPanel.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="VirtualKeyState.cs" />
<Compile Include="Win32Helper.cs" />
<Compile Include="WindowHandle.cs" />
<Compile Include="WindowListHelper.cs" />

View file

@ -0,0 +1,129 @@
namespace OnTopReplica.SidePanels {
partial class GroupSwitchPanel {
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing) {
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent() {
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.buttonCancel = new System.Windows.Forms.Button();
this.buttonEnable = new System.Windows.Forms.Button();
this.listWindows = new System.Windows.Forms.ListView();
this.colName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.labelStatus = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// groupBox1
//
this.groupBox1.Controls.Add(this.labelStatus);
this.groupBox1.Controls.Add(this.buttonCancel);
this.groupBox1.Controls.Add(this.buttonEnable);
this.groupBox1.Controls.Add(this.listWindows);
this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.groupBox1.Location = new System.Drawing.Point(0, 0);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(228, 296);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Group switch mode";
//
// buttonCancel
//
this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonCancel.Location = new System.Drawing.Point(152, 267);
this.buttonCancel.Name = "buttonCancel";
this.buttonCancel.Size = new System.Drawing.Size(70, 23);
this.buttonCancel.TabIndex = 2;
this.buttonCancel.Text = "Disable";
this.buttonCancel.UseVisualStyleBackColor = true;
this.buttonCancel.Click += new System.EventHandler(this.Cancel_click);
//
// buttonEnable
//
this.buttonEnable.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonEnable.Image = global::OnTopReplica.Properties.Resources.xiao_ok;
this.buttonEnable.Location = new System.Drawing.Point(12, 267);
this.buttonEnable.Name = "buttonEnable";
this.buttonEnable.Size = new System.Drawing.Size(134, 23);
this.buttonEnable.TabIndex = 1;
this.buttonEnable.Text = "Enable group mode";
this.buttonEnable.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.buttonEnable.UseVisualStyleBackColor = true;
this.buttonEnable.Click += new System.EventHandler(this.Enable_click);
//
// listWindows
//
this.listWindows.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listWindows.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.colName});
this.listWindows.FullRowSelect = true;
this.listWindows.GridLines = true;
this.listWindows.HideSelection = false;
this.listWindows.LabelWrap = false;
this.listWindows.Location = new System.Drawing.Point(6, 19);
this.listWindows.Name = "listWindows";
this.listWindows.Size = new System.Drawing.Size(216, 225);
this.listWindows.TabIndex = 0;
this.listWindows.UseCompatibleStateImageBehavior = false;
this.listWindows.View = System.Windows.Forms.View.Details;
//
// colName
//
this.colName.Text = "Windows";
this.colName.Width = 220;
//
// labelStatus
//
this.labelStatus.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.labelStatus.Location = new System.Drawing.Point(3, 247);
this.labelStatus.Name = "labelStatus";
this.labelStatus.Size = new System.Drawing.Size(219, 17);
this.labelStatus.TabIndex = 3;
this.labelStatus.Text = "-";
this.labelStatus.TextAlign = System.Drawing.ContentAlignment.BottomRight;
//
// GroupSwitchPanel
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.groupBox1);
this.MinimumSize = new System.Drawing.Size(220, 220);
this.Name = "GroupSwitchPanel";
this.Size = new System.Drawing.Size(228, 296);
this.groupBox1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Button buttonCancel;
private System.Windows.Forms.Button buttonEnable;
private System.Windows.Forms.ListView listWindows;
private System.Windows.Forms.ColumnHeader colName;
private System.Windows.Forms.Label labelStatus;
}
}

View file

@ -0,0 +1,72 @@
using System;
using System.Drawing;
using System.Windows.Forms;
using OnTopReplica.Properties;
using System.Collections.Generic;
using OnTopReplica.MessagePumpProcessors;
namespace OnTopReplica.SidePanels {
partial class GroupSwitchPanel : SidePanel {
public GroupSwitchPanel() {
InitializeComponent();
}
public override void OnFirstShown(MainForm form) {
base.OnFirstShown(form);
LoadWindowList();
labelStatus.Text = (ParentForm.MessagePumpManager.Get<GroupSwitchManager>().IsActive) ?
"Group switching is active." :
"Select multiple windows to enable.";
}
private void LoadWindowList() {
var manager = new WindowManager();
manager.Refresh(WindowManager.EnumerationMode.TaskWindows);
var imageList = new ImageList();
foreach (var w in manager.Windows) {
var item = new ListViewItem(w.Title) {
Tag = w
};
if (w.Icon != null) {
imageList.Images.Add(w.Icon);
item.ImageIndex = imageList.Images.Count - 1;
}
listWindows.Items.Add(item);
}
listWindows.SmallImageList = imageList;
}
public override void OnClosing(MainForm form) {
base.OnClosing(form);
if (_enableOnClose) {
List<WindowHandle> ret = new List<WindowHandle>();
foreach (ListViewItem i in listWindows.SelectedItems) {
ret.Add((WindowHandle)i.Tag);
}
form.SetThumbnailGroup(ret);
}
else {
form.MessagePumpManager.Get<GroupSwitchManager>().Disable();
}
}
bool _enableOnClose = false;
private void Enable_click(object sender, EventArgs e) {
_enableOnClose = true;
OnRequestClosing();
}
private void Cancel_click(object sender, EventArgs e) {
OnRequestClosing();
}
}
}

View file

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -6,6 +6,7 @@ using VistaControls.Dwm;
using VistaControls.ThemeText;
using System.Drawing;
using System.Windows.Forms.VisualStyles;
using OnTopReplica.Native;
namespace OnTopReplica {
@ -135,9 +136,10 @@ namespace OnTopReplica {
base.WndProc(ref m);
//Make transparent to hit-testing if clicks must not be registered
if (m.Msg == NativeMethods.WM_NCHITTEST && m.Result.ToInt32() == NativeMethods.HTCLIENT &&
if (m.Msg == MessagingMethods.WM_NCHITTEST && m.Result.ToInt32() == MessagingMethods.HTCLIENT &&
!DrawMouseRegions && !ReportThumbnailClicks) {
m.Result = new IntPtr(NativeMethods.HTTRANSPARENT);
m.Result = new IntPtr(MessagingMethods.HTTRANSPARENT);
}
}

View file

@ -1,195 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace OnTopReplica {
enum VirtualKeyState : int {
VK_LBUTTON = 0x01,
VK_RBUTTON = 0x02,
VK_CANCEL = 0x03,
VK_MBUTTON = 0x04,
//
VK_XBUTTON1 = 0x05,
VK_XBUTTON2 = 0x06,
//
VK_BACK = 0x08,
VK_TAB = 0x09,
//
VK_CLEAR = 0x0C,
VK_RETURN = 0x0D,
//
VK_SHIFT = 0x10,
VK_CONTROL = 0x11,
VK_MENU = 0x12,
VK_PAUSE = 0x13,
VK_CAPITAL = 0x14,
//
VK_KANA = 0x15,
VK_HANGEUL = 0x15, /* old name - should be here for compatibility */
VK_HANGUL = 0x15,
VK_JUNJA = 0x17,
VK_FINAL = 0x18,
VK_HANJA = 0x19,
VK_KANJI = 0x19,
//
VK_ESCAPE = 0x1B,
//
VK_CONVERT = 0x1C,
VK_NONCONVERT = 0x1D,
VK_ACCEPT = 0x1E,
VK_MODECHANGE = 0x1F,
//
VK_SPACE = 0x20,
VK_PRIOR = 0x21,
VK_NEXT = 0x22,
VK_END = 0x23,
VK_HOME = 0x24,
VK_LEFT = 0x25,
VK_UP = 0x26,
VK_RIGHT = 0x27,
VK_DOWN = 0x28,
VK_SELECT = 0x29,
VK_PRINT = 0x2A,
VK_EXECUTE = 0x2B,
VK_SNAPSHOT = 0x2C,
VK_INSERT = 0x2D,
VK_DELETE = 0x2E,
VK_HELP = 0x2F,
//
VK_LWIN = 0x5B,
VK_RWIN = 0x5C,
VK_APPS = 0x5D,
//
VK_SLEEP = 0x5F,
//
VK_NUMPAD0 = 0x60,
VK_NUMPAD1 = 0x61,
VK_NUMPAD2 = 0x62,
VK_NUMPAD3 = 0x63,
VK_NUMPAD4 = 0x64,
VK_NUMPAD5 = 0x65,
VK_NUMPAD6 = 0x66,
VK_NUMPAD7 = 0x67,
VK_NUMPAD8 = 0x68,
VK_NUMPAD9 = 0x69,
VK_MULTIPLY = 0x6A,
VK_ADD = 0x6B,
VK_SEPARATOR = 0x6C,
VK_SUBTRACT = 0x6D,
VK_DECIMAL = 0x6E,
VK_DIVIDE = 0x6F,
VK_F1 = 0x70,
VK_F2 = 0x71,
VK_F3 = 0x72,
VK_F4 = 0x73,
VK_F5 = 0x74,
VK_F6 = 0x75,
VK_F7 = 0x76,
VK_F8 = 0x77,
VK_F9 = 0x78,
VK_F10 = 0x79,
VK_F11 = 0x7A,
VK_F12 = 0x7B,
VK_F13 = 0x7C,
VK_F14 = 0x7D,
VK_F15 = 0x7E,
VK_F16 = 0x7F,
VK_F17 = 0x80,
VK_F18 = 0x81,
VK_F19 = 0x82,
VK_F20 = 0x83,
VK_F21 = 0x84,
VK_F22 = 0x85,
VK_F23 = 0x86,
VK_F24 = 0x87,
//
VK_NUMLOCK = 0x90,
VK_SCROLL = 0x91,
//
VK_OEM_NEC_EQUAL = 0x92, // '=' key on numpad
//
VK_OEM_FJ_JISHO = 0x92, // 'Dictionary' key
VK_OEM_FJ_MASSHOU = 0x93, // 'Unregister word' key
VK_OEM_FJ_TOUROKU = 0x94, // 'Register word' key
VK_OEM_FJ_LOYA = 0x95, // 'Left OYAYUBI' key
VK_OEM_FJ_ROYA = 0x96, // 'Right OYAYUBI' key
//
VK_LSHIFT = 0xA0,
VK_RSHIFT = 0xA1,
VK_LCONTROL = 0xA2,
VK_RCONTROL = 0xA3,
VK_LMENU = 0xA4,
VK_RMENU = 0xA5,
//
VK_BROWSER_BACK = 0xA6,
VK_BROWSER_FORWARD = 0xA7,
VK_BROWSER_REFRESH = 0xA8,
VK_BROWSER_STOP = 0xA9,
VK_BROWSER_SEARCH = 0xAA,
VK_BROWSER_FAVORITES = 0xAB,
VK_BROWSER_HOME = 0xAC,
//
VK_VOLUME_MUTE = 0xAD,
VK_VOLUME_DOWN = 0xAE,
VK_VOLUME_UP = 0xAF,
VK_MEDIA_NEXT_TRACK = 0xB0,
VK_MEDIA_PREV_TRACK = 0xB1,
VK_MEDIA_STOP = 0xB2,
VK_MEDIA_PLAY_PAUSE = 0xB3,
VK_LAUNCH_MAIL = 0xB4,
VK_LAUNCH_MEDIA_SELECT = 0xB5,
VK_LAUNCH_APP1 = 0xB6,
VK_LAUNCH_APP2 = 0xB7,
//
VK_OEM_1 = 0xBA, // ';:' for US
VK_OEM_PLUS = 0xBB, // '+' any country
VK_OEM_COMMA = 0xBC, // ',' any country
VK_OEM_MINUS = 0xBD, // '-' any country
VK_OEM_PERIOD = 0xBE, // '.' any country
VK_OEM_2 = 0xBF, // '/?' for US
VK_OEM_3 = 0xC0, // '`~' for US
//
VK_OEM_4 = 0xDB, // '[{' for US
VK_OEM_5 = 0xDC, // '\|' for US
VK_OEM_6 = 0xDD, // ']}' for US
VK_OEM_7 = 0xDE, // ''"' for US
VK_OEM_8 = 0xDF,
//
VK_OEM_AX = 0xE1, // 'AX' key on Japanese AX kbd
VK_OEM_102 = 0xE2, // "<>" or "\|" on RT 102-key kbd.
VK_ICO_HELP = 0xE3, // Help key on ICO
VK_ICO_00 = 0xE4, // 00 key on ICO
//
VK_PROCESSKEY = 0xE5,
//
VK_ICO_CLEAR = 0xE6,
//
VK_PACKET = 0xE7,
//
VK_OEM_RESET = 0xE9,
VK_OEM_JUMP = 0xEA,
VK_OEM_PA1 = 0xEB,
VK_OEM_PA2 = 0xEC,
VK_OEM_PA3 = 0xED,
VK_OEM_WSCTRL = 0xEE,
VK_OEM_CUSEL = 0xEF,
VK_OEM_ATTN = 0xF0,
VK_OEM_FINISH = 0xF1,
VK_OEM_COPY = 0xF2,
VK_OEM_AUTO = 0xF3,
VK_OEM_ENLW = 0xF4,
VK_OEM_BACKTAB = 0xF5,
//
VK_ATTN = 0xF6,
VK_CRSEL = 0xF7,
VK_EXSEL = 0xF8,
VK_EREOF = 0xF9,
VK_PLAY = 0xFA,
VK_ZOOM = 0xFB,
VK_NONAME = 0xFC,
VK_PA1 = 0xFD,
VK_OEM_CLEAR = 0xFE
}
}

View file

@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using OnTopReplica.Native;
namespace OnTopReplica {
public static class Win32Helper {
@ -11,19 +10,18 @@ namespace OnTopReplica {
/// <param name="window">Target window to click on.</param>
/// <param name="clickLocation">Location of the mouse click expressed in client coordiantes of the target window.</param>
/// <param name="doubleClick">True if a double click should be injected.</param>
public static void InjectFakeMouseClick(IntPtr window, Point clickLocation, bool doubleClick) {
NativeMethods.Point scrClickLocation = NativeMethods.ClientToScreen(window,
NativeMethods.Point.FromPoint(clickLocation));
public static void InjectFakeMouseClick(IntPtr window, System.Drawing.Point clickLocation, bool doubleClick) {
NPoint scrClickLocation = WindowManagerMethods.ClientToScreen(window, NPoint.FromPoint(clickLocation));
//HACK (?)
//If target window has a Menu (which appears on the thumbnail) move the clicked location down
//in order to adjust (the menu isn't part of the window's client rect).
IntPtr hMenu = NativeMethods.GetMenu(window);
IntPtr hMenu = WindowMethods.GetMenu(window);
if (hMenu != IntPtr.Zero)
scrClickLocation.Y -= SystemInformation.MenuHeight;
scrClickLocation.Y -= System.Windows.Forms.SystemInformation.MenuHeight;
IntPtr hChild = GetRealChildControlFromPoint(window, scrClickLocation);
NativeMethods.Point clntClickLocation = NativeMethods.ScreenToClient(hChild, scrClickLocation);
NPoint clntClickLocation = WindowManagerMethods.ScreenToClient(hChild, scrClickLocation);
if (doubleClick)
InjectDoubleLeftMouseClick(hChild, clntClickLocation);
@ -31,25 +29,25 @@ namespace OnTopReplica {
InjectLeftMouseClick(hChild, clntClickLocation);
}
private static void InjectLeftMouseClick(IntPtr child, NativeMethods.Point clientLocation) {
IntPtr lParamClickLocation = NativeMethods.MakeLParam(clientLocation.X, clientLocation.Y);
private static void InjectLeftMouseClick(IntPtr child, Native.NPoint clientLocation) {
IntPtr lParamClickLocation = MessagingMethods.MakeLParam(clientLocation.X, clientLocation.Y);
NativeMethods.PostMessage(child, NativeMethods.WM_LBUTTONDOWN,
new IntPtr(NativeMethods.MK_LBUTTON), lParamClickLocation);
MessagingMethods.PostMessage(child, MessagingMethods.WM_LBUTTONDOWN,
new IntPtr(MessagingMethods.MK_LBUTTON), lParamClickLocation);
NativeMethods.PostMessage(child, NativeMethods.WM_LBUTTONUP,
new IntPtr(NativeMethods.MK_LBUTTON), lParamClickLocation);
MessagingMethods.PostMessage(child, MessagingMethods.WM_LBUTTONUP,
new IntPtr(MessagingMethods.MK_LBUTTON), lParamClickLocation);
#if DEBUG
Console.WriteLine("Left click on window #" + child.ToString() + " at " + clientLocation.ToString());
#endif
}
private static void InjectDoubleLeftMouseClick(IntPtr child, NativeMethods.Point clientLocation) {
IntPtr lParamClickLocation = NativeMethods.MakeLParam(clientLocation.X, clientLocation.Y);
private static void InjectDoubleLeftMouseClick(IntPtr child, NPoint clientLocation) {
IntPtr lParamClickLocation = MessagingMethods.MakeLParam(clientLocation.X, clientLocation.Y);
NativeMethods.PostMessage(child, NativeMethods.WM_LBUTTONDBLCLK,
new IntPtr(NativeMethods.MK_LBUTTON), lParamClickLocation);
MessagingMethods.PostMessage(child, MessagingMethods.WM_LBUTTONDBLCLK,
new IntPtr(MessagingMethods.MK_LBUTTON), lParamClickLocation);
#if DEBUG
Console.WriteLine("Double left click on window #" + child.ToString() + " at " + clientLocation.ToString());
@ -59,10 +57,11 @@ namespace OnTopReplica {
/// <summary>Returns the child control of a window corresponding to a screen location.</summary>
/// <param name="parent">Parent window to explore.</param>
/// <param name="scrClickLocation">Child control location in screen coordinates.</param>
private static IntPtr GetRealChildControlFromPoint(IntPtr parent, NativeMethods.Point scrClickLocation) {
private static IntPtr GetRealChildControlFromPoint(IntPtr parent, NPoint scrClickLocation) {
IntPtr curr = parent, child = IntPtr.Zero;
do {
child = NativeMethods.RealChildWindowFromPoint(curr, NativeMethods.ScreenToClient(curr, scrClickLocation));
child = WindowManagerMethods.RealChildWindowFromPoint(curr,
WindowManagerMethods.ScreenToClient(curr, scrClickLocation));
if (child == IntPtr.Zero || child == curr)
break;

View file

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using OnTopReplica.Native;
namespace OnTopReplica {
@ -29,7 +30,8 @@ namespace OnTopReplica {
//Fetch icon from window
IntPtr hIcon;
if (NativeMethods.SendMessageTimeout(_handle, NativeMethods.WM_GETICON, new IntPtr(2), new IntPtr(0), NativeMethods.SendMessageTimeoutFlags.AbortIfHung | NativeMethods.SendMessageTimeoutFlags.Block, 500, out hIcon) == IntPtr.Zero)
if (MessagingMethods.SendMessageTimeout(_handle, MessagingMethods.WM_GETICON, new IntPtr(2), new IntPtr(0),
MessagingMethods.SendMessageTimeoutFlags.AbortIfHung | MessagingMethods.SendMessageTimeoutFlags.Block, 500, out hIcon) == IntPtr.Zero)
hIcon = IntPtr.Zero;
if (hIcon.ToInt64() != 0) {
@ -37,7 +39,7 @@ namespace OnTopReplica {
}
else {
//Fetch icon from window class
hIcon = (IntPtr)NativeMethods.GetClassLongPtr(_handle, NativeMethods.ClassLong.IconSmall);
hIcon = (IntPtr)WindowMethods.GetClassLongPtr(_handle, WindowMethods.ClassLong.IconSmall);
if (hIcon.ToInt64() != 0) {
_icon = Icon.FromHandle(hIcon);

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using OnTopReplica.Native;
namespace OnTopReplica {
/// <summary>A helper class that allows you to easily build and keep a list of Windows (in the form of WindowHandle objects).</summary>
@ -23,22 +24,22 @@ namespace OnTopReplica {
public void Refresh(EnumerationMode mode) {
_windows = new List<WindowHandle>();
NativeMethods.EnumWindowsProc proc = null;
WindowManagerMethods.EnumWindowsProc proc = null;
switch (mode) {
case EnumerationMode.AllVisible:
proc = new NativeMethods.EnumWindowsProc(EnumWindowProcAll);
proc = new WindowManagerMethods.EnumWindowsProc(EnumWindowProcAll);
break;
case EnumerationMode.AllTopLevel:
proc = new NativeMethods.EnumWindowsProc(EnumWindowProcTopLevel);
proc = new WindowManagerMethods.EnumWindowsProc(EnumWindowProcTopLevel);
break;
case EnumerationMode.TaskWindows:
proc = new NativeMethods.EnumWindowsProc(EnumWindowProcTask);
proc = new WindowManagerMethods.EnumWindowsProc(EnumWindowProcTask);
break;
}
NativeMethods.EnumWindows(proc, IntPtr.Zero);
WindowManagerMethods.EnumWindows(proc, IntPtr.Zero);
}
@ -51,7 +52,7 @@ namespace OnTopReplica {
private bool EnumWindowProcAll(IntPtr hwnd, IntPtr lParam) {
if (NativeMethods.IsWindowVisible(hwnd)) {
if (WindowManagerMethods.IsWindowVisible(hwnd)) {
string title = GetWindowTitle(hwnd);
_windows.Add( new WindowHandle(hwnd, title));
}
@ -59,9 +60,9 @@ namespace OnTopReplica {
}
private bool EnumWindowProcTopLevel(IntPtr hwnd, IntPtr lParam) {
if (NativeMethods.IsWindowVisible(hwnd)) {
if (WindowManagerMethods.IsWindowVisible(hwnd)) {
//Check if window has no parent
if ((long)NativeMethods.GetParent(hwnd) == 0 && NativeMethods.GetDesktopWindow() != hwnd) {
if ((long)WindowManagerMethods.GetParent(hwnd) == 0 && WindowManagerMethods.GetDesktopWindow() != hwnd) {
string title = GetWindowTitle(hwnd);
_windows.Add( new WindowHandle(hwnd, title));
}
@ -84,13 +85,13 @@ namespace OnTopReplica {
if (string.IsNullOrEmpty(title))
return true;
if (NativeMethods.IsWindowVisible(hwnd)) {
if ((long)NativeMethods.GetParent(hwnd) == 0) {
bool hasOwner = (long)NativeMethods.GetWindow(hwnd, NativeMethods.GetWindowMode.GW_OWNER) != 0;
NativeMethods.WindowExStyles exStyle = (NativeMethods.WindowExStyles)NativeMethods.GetWindowLong(hwnd, NativeMethods.WindowLong.ExStyle);
if (WindowManagerMethods.IsWindowVisible(hwnd)) {
if ((long)WindowManagerMethods.GetParent(hwnd) == 0) {
bool hasOwner = (long)WindowManagerMethods.GetWindow(hwnd, WindowManagerMethods.GetWindowMode.GW_OWNER) != 0;
WindowMethods.WindowExStyles exStyle = (WindowMethods.WindowExStyles)WindowMethods.GetWindowLong(hwnd, WindowMethods.WindowLong.ExStyle);
if (((exStyle & NativeMethods.WindowExStyles.ToolWindow) == 0 && !hasOwner) || //unowned non-tool window
((exStyle & NativeMethods.WindowExStyles.AppWindow) == NativeMethods.WindowExStyles.AppWindow && hasOwner)) { //owned application window
if (((exStyle & WindowMethods.WindowExStyles.ToolWindow) == 0 && !hasOwner) || //unowned non-tool window
((exStyle & WindowMethods.WindowExStyles.AppWindow) == WindowMethods.WindowExStyles.AppWindow && hasOwner)) { //owned application window
_windows.Add(new WindowHandle(hwnd, title));
}
}
@ -102,11 +103,11 @@ namespace OnTopReplica {
#region Auxiliary methods
private string GetWindowTitle(IntPtr hwnd) {
int length = NativeMethods.GetWindowTextLength(hwnd);
int length = WindowMethods.GetWindowTextLength(hwnd);
if (length > 0) {
StringBuilder sb = new StringBuilder(length + 1);
if (NativeMethods.GetWindowText(hwnd, sb, sb.Capacity) > 0)
if (WindowMethods.GetWindowText(hwnd, sb, sb.Capacity) > 0)
return sb.ToString();
else
return String.Empty;