mirror of
https://github.com/terrymacdonald/DisplayMagician.git
synced 2024-08-30 18:32:20 +00:00
561 lines
23 KiB
C#
561 lines
23 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using DisplayMagicianShared;
|
|
using Microsoft.Win32;
|
|
using Newtonsoft.Json;
|
|
|
|
// This file is taken from Soroush Falahati's amazing HeliosDisplayManagement software
|
|
// available at https://github.com/falahati/HeliosDisplayManagement
|
|
|
|
// Substantial modifications made by Terry MacDonald 2022 onwards
|
|
|
|
namespace DisplayMagicianShared.Windows
|
|
{
|
|
public class TaskBarStuckRectangle
|
|
{
|
|
|
|
public enum TaskBarEdge : UInt32
|
|
{
|
|
Left = 0,
|
|
Top = 1,
|
|
Right = 2,
|
|
Bottom = 3
|
|
}
|
|
|
|
[Flags]
|
|
public enum TaskBarOptions : UInt32
|
|
{
|
|
None = 0,
|
|
AutoHide = 1 << 0,
|
|
KeepOnTop = 1 << 1,
|
|
UseSmallIcons = 1 << 2,
|
|
HideClock = 1 << 3,
|
|
HideVolume = 1 << 4,
|
|
HideNetwork = 1 << 5,
|
|
HidePower = 1 << 6,
|
|
WindowPreview = 1 << 7,
|
|
Unknown1 = 1 << 8,
|
|
Unknown2 = 1 << 9,
|
|
HideActionCenter = 1 << 10,
|
|
Unknown3 = 1 << 11,
|
|
HideLocation = 1 << 12,
|
|
HideLanguageBar = 1 << 13
|
|
}
|
|
|
|
private const string MainDisplayAddress =
|
|
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\StuckRects{0:D}";
|
|
|
|
private const string MultiDisplayAddress =
|
|
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MMStuckRects{0:D}";
|
|
|
|
/*private static readonly Dictionary<int, byte[]> Headers = new Dictionary<int, byte[]>
|
|
{
|
|
{2, new byte[] {0x28, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF}},
|
|
{3, new byte[] {0x30, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF}}
|
|
};
|
|
*/
|
|
public TaskBarStuckRectangle(string devicePath)
|
|
{
|
|
bool MMStuckRectVerFound = false;
|
|
// Check if key exists
|
|
int version = 3;
|
|
string address = string.Format(MultiDisplayAddress, version);
|
|
if (Registry.CurrentUser.OpenSubKey(address) != null)
|
|
{
|
|
MMStuckRectVerFound = true;
|
|
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found MMStuckRect3 registry key! {address}");
|
|
}
|
|
else
|
|
{
|
|
// If it's not version 3, then try version 2
|
|
version = 2;
|
|
address = string.Format(MultiDisplayAddress, version);
|
|
if (Registry.CurrentUser.OpenSubKey(address) != null)
|
|
{
|
|
MMStuckRectVerFound = true;
|
|
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found MMStuckRect2 registry key! {address}");
|
|
}
|
|
else
|
|
{
|
|
// It's not v2 or v3, so it must be a single display
|
|
MMStuckRectVerFound = false;
|
|
SharedLogger.logger.Warn($"TaskBarStuckRectangle/TaskBarStuckRectangle: Couldn't find an MMStuckRect2 or MMStuckRect3 registry key! Going to test if it is a single display only.");
|
|
}
|
|
}
|
|
|
|
bool foundDevicePath = false;
|
|
if (MMStuckRectVerFound)
|
|
{
|
|
// Check if value exists
|
|
if (version >= 2 && version <= 3)
|
|
{
|
|
using (var key = Registry.CurrentUser.OpenSubKey(
|
|
address,
|
|
RegistryKeyPermissionCheck.ReadSubTree))
|
|
{
|
|
var binary = key?.GetValue(devicePath) as byte[];
|
|
if (binary?.Length > 0)
|
|
{
|
|
foundDevicePath = true;
|
|
MainScreen = false;
|
|
DevicePath = devicePath;
|
|
Binary = binary;
|
|
OriginalBinary = new byte[binary.Length];
|
|
binary.CopyTo(OriginalBinary, 0);
|
|
Version = version;
|
|
|
|
// Extract the values from the binary byte field
|
|
PopulateFieldsFromBinary();
|
|
|
|
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: The taskbar for {DevicePath} is against the {Edge} edge, is positioned at ({Location.X},{Location.Y}) and is {Location.Width}x{Location.Height} in size.");
|
|
}
|
|
else
|
|
{
|
|
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Unable to get the TaskBarStuckRectangle binary settings from {devicePath} screen.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!foundDevicePath)
|
|
{
|
|
bool StuckRectVerFound = false;
|
|
// Check if string exists
|
|
version = 3;
|
|
address = string.Format(MainDisplayAddress, version);
|
|
if (Registry.CurrentUser.OpenSubKey(address) != null)
|
|
{
|
|
StuckRectVerFound = true;
|
|
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found StuckRect3 single display registry key! {address}");
|
|
}
|
|
else
|
|
{
|
|
// If it's not version 3, then try version 2
|
|
version = 2;
|
|
address = string.Format(MainDisplayAddress, version);
|
|
if (Registry.CurrentUser.OpenSubKey(address) != null)
|
|
{
|
|
StuckRectVerFound = true;
|
|
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Found StuckRect2 single display registry key! {address}");
|
|
}
|
|
else
|
|
{
|
|
SharedLogger.logger.Error($"TaskBarStuckRectangle/TaskBarStuckRectangle: Couldn't find an single display StuckRect2 or StuckRect3 registry key! So we have to just return after doing nothing as there is nothing we can do.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (StuckRectVerFound)
|
|
{
|
|
// Check if value exists
|
|
if (version >= 2 && version <= 3)
|
|
{
|
|
using (var key = Registry.CurrentUser.OpenSubKey(
|
|
address,
|
|
RegistryKeyPermissionCheck.ReadSubTree))
|
|
{
|
|
var binary = key?.GetValue(devicePath) as byte[];
|
|
if (binary?.Length > 0)
|
|
{
|
|
foundDevicePath = true;
|
|
MainScreen = true;
|
|
DevicePath = devicePath;
|
|
Binary = binary;
|
|
OriginalBinary = new byte[binary.Length];
|
|
binary.CopyTo(OriginalBinary, 0);
|
|
Version = version;
|
|
|
|
// Extract the values from the binary byte field
|
|
PopulateFieldsFromBinary();
|
|
|
|
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: The taskbar for {DevicePath} is against the {Edge} edge, is positioned at ({Location.X},{Location.Y}) and is {Location.Width}x{Location.Height} in size.");
|
|
}
|
|
else
|
|
{
|
|
SharedLogger.logger.Trace($"TaskBarStuckRectangle/TaskBarStuckRectangle: Unable to get the TaskBarStuckRectangle binary settings from {devicePath} screen.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public TaskBarStuckRectangle()
|
|
{
|
|
}
|
|
|
|
public byte[] Binary { get; set; }
|
|
|
|
public byte[] OriginalBinary { get; set; }
|
|
|
|
public string DevicePath { get; set; }
|
|
|
|
public bool MainScreen { get; set; }
|
|
|
|
public UInt32 DPI { get; set; }
|
|
|
|
public TaskBarEdge Edge { get; set; }
|
|
|
|
public Rectangle Location { get; set; }
|
|
|
|
public Size MinSize { get; set; }
|
|
|
|
public TaskBarOptions Options { get; set; }
|
|
|
|
public uint Rows { get; set; }
|
|
|
|
public int Version { get; set; }
|
|
|
|
public override bool Equals(object obj) => obj is TaskBarStuckRectangle other && this.Equals(other);
|
|
public bool Equals(TaskBarStuckRectangle other)
|
|
{
|
|
return Version == other.Version &&
|
|
DevicePath == other.DevicePath &&
|
|
MainScreen == other.MainScreen &&
|
|
DPI == other.DPI &&
|
|
Edge == other.Edge &&
|
|
Location == other.Location &&
|
|
MinSize == other.MinSize &&
|
|
Options == other.Options &&
|
|
Rows == other.Rows;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return (Version, MainScreen, DevicePath, DPI, Edge, Location, MinSize, Options, Rows).GetHashCode();
|
|
}
|
|
public static bool operator ==(TaskBarStuckRectangle lhs, TaskBarStuckRectangle rhs) => lhs.Equals(rhs);
|
|
|
|
public static bool operator !=(TaskBarStuckRectangle lhs, TaskBarStuckRectangle rhs) => !(lhs == rhs);
|
|
|
|
static bool Xor(byte[] a, byte[] b)
|
|
|
|
{
|
|
|
|
int x = a.Length ^ b.Length;
|
|
|
|
for (int i = 0; i < a.Length && i < b.Length; ++i)
|
|
|
|
{
|
|
|
|
x |= a[i] ^ b[i];
|
|
|
|
}
|
|
|
|
return x == 0;
|
|
|
|
}
|
|
|
|
private bool PopulateFieldsFromBinary()
|
|
{
|
|
// Now we decipher the binary properties features to populate the stuckrectangle
|
|
// DPI
|
|
if (Binary.Length < 44)
|
|
{
|
|
DPI = 0;
|
|
}
|
|
else
|
|
{
|
|
DPI = BitConverter.ToUInt32(Binary, 40);
|
|
}
|
|
// Edge
|
|
if (Binary.Length < 16)
|
|
{
|
|
Edge = TaskBarEdge.Bottom;
|
|
}
|
|
else
|
|
{
|
|
Edge = (TaskBarEdge)BitConverter.ToUInt32(Binary, 12);
|
|
}
|
|
// Location
|
|
if (Binary.Length < 40)
|
|
{
|
|
Location = Rectangle.Empty;
|
|
}
|
|
else
|
|
{
|
|
var left = BitConverter.ToInt32(Binary, 24);
|
|
var top = BitConverter.ToInt32(Binary, 28);
|
|
var right = BitConverter.ToInt32(Binary, 32);
|
|
var bottom = BitConverter.ToInt32(Binary, 36);
|
|
|
|
Location = Rectangle.FromLTRB(left, top, right, bottom);
|
|
}
|
|
// MinSize
|
|
if (Binary.Length < 24)
|
|
{
|
|
MinSize = Size.Empty;
|
|
}
|
|
else
|
|
{
|
|
var width = BitConverter.ToInt32(Binary, 16);
|
|
var height = BitConverter.ToInt32(Binary, 20);
|
|
|
|
MinSize = new Size(width, height);
|
|
}
|
|
// Options
|
|
if (Binary.Length < 12)
|
|
{
|
|
Options = 0;
|
|
}
|
|
else
|
|
{
|
|
Options = (TaskBarOptions)BitConverter.ToUInt32(Binary, 8);
|
|
}
|
|
// Rows
|
|
if (Binary.Length < 48)
|
|
{
|
|
Rows = 1;
|
|
}
|
|
else
|
|
{
|
|
Rows = BitConverter.ToUInt32(Binary, 44);
|
|
}
|
|
|
|
SharedLogger.logger.Trace($"TaskBarStuckRectangle/PopulateFieldsFromBinary: Grabbed the following settings for {DevicePath} from the registry: DPI = {DPI}, Edge = {Edge}, Location = ({Location.X},{Location.Y}), MinSize = {Location.Width}x{Location.Height}, Options = {Options}, Rows = {Rows}.");
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool PopulateBinaryFromFields()
|
|
{
|
|
// Set the DPI
|
|
if (Binary.Length < 44)
|
|
{
|
|
DPI = 0;
|
|
var bytes = BitConverter.GetBytes(DPI);
|
|
Array.Copy(bytes, 0, Binary, 40, 4);
|
|
}
|
|
else
|
|
{
|
|
var bytes = BitConverter.GetBytes(DPI);
|
|
Array.Copy(bytes, 0, Binary, 40, 4);
|
|
}
|
|
// Edge
|
|
if (Binary.Length < 16)
|
|
{
|
|
Edge = TaskBarEdge.Bottom;
|
|
var bytes = BitConverter.GetBytes((uint)Edge);
|
|
Array.Copy(bytes, 0, Binary, 12, 1);
|
|
}
|
|
else
|
|
{
|
|
var bytes = BitConverter.GetBytes((uint)Edge);
|
|
Array.Copy(bytes, 0, Binary, 12, 1);
|
|
}
|
|
// Location
|
|
if (Binary.Length < 40)
|
|
{
|
|
var bytes = BitConverter.GetBytes(0);
|
|
Array.Copy(bytes, 0, Binary, 24, 4);
|
|
|
|
bytes = BitConverter.GetBytes(0);
|
|
Array.Copy(bytes, 0, Binary, 28, 4);
|
|
|
|
bytes = BitConverter.GetBytes(0);
|
|
Array.Copy(bytes, 0, Binary, 32, 4);
|
|
|
|
bytes = BitConverter.GetBytes(0);
|
|
Array.Copy(bytes, 0, Binary, 36, 4);
|
|
}
|
|
else
|
|
{
|
|
var bytes = BitConverter.GetBytes(Location.Left);
|
|
Array.Copy(bytes, 0, Binary, 24, 4);
|
|
|
|
bytes = BitConverter.GetBytes(Location.Top);
|
|
Array.Copy(bytes, 0, Binary, 28, 4);
|
|
|
|
bytes = BitConverter.GetBytes(Location.Right);
|
|
Array.Copy(bytes, 0, Binary, 32, 4);
|
|
|
|
bytes = BitConverter.GetBytes(Location.Bottom);
|
|
Array.Copy(bytes, 0, Binary, 36, 4);
|
|
}
|
|
// MinSize
|
|
if (Binary.Length < 24)
|
|
{
|
|
var bytes = BitConverter.GetBytes(0);
|
|
Array.Copy(bytes, 0, Binary, 16, 4);
|
|
|
|
bytes = BitConverter.GetBytes(0);
|
|
Array.Copy(bytes, 0, Binary, 20, 4);
|
|
}
|
|
else
|
|
{
|
|
var bytes = BitConverter.GetBytes(MinSize.Width);
|
|
Array.Copy(bytes, 0, Binary, 16, 4);
|
|
|
|
bytes = BitConverter.GetBytes(MinSize.Height);
|
|
Array.Copy(bytes, 0, Binary, 20, 4);
|
|
}
|
|
// Options
|
|
if (Binary.Length < 12)
|
|
{
|
|
var bytes = BitConverter.GetBytes((uint)0);
|
|
Array.Copy(bytes, 0, Binary, 8, 4);
|
|
}
|
|
else
|
|
{
|
|
var bytes = BitConverter.GetBytes((uint)Options);
|
|
Array.Copy(bytes, 0, Binary, 8, 4);
|
|
}
|
|
// Rows
|
|
if (Binary.Length < 48)
|
|
{
|
|
var bytes = BitConverter.GetBytes(1);
|
|
Array.Copy(bytes, 0, Binary, 44, 4);
|
|
}
|
|
else
|
|
{
|
|
var bytes = BitConverter.GetBytes(Rows);
|
|
Array.Copy(bytes, 0, Binary, 44, 4);
|
|
}
|
|
|
|
SharedLogger.logger.Trace($"TaskBarStuckRectangle/PopulateBinaryFromFields: Set the following settings for {DevicePath} into registry: DPI = {DPI}, Edge = {Edge}, Location = ({Location.X},{Location.Y}), MinSize = {Location.Width}x{Location.Height}, Options = {Options}, Rows = {Rows}.");
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool WriteToRegistry()
|
|
{
|
|
// Update the binary with the current settings from the object
|
|
PopulateBinaryFromFields();
|
|
|
|
// Write the binary field to registry
|
|
string address;
|
|
if (MainScreen)
|
|
{
|
|
address = string.Format(MainDisplayAddress, Version);
|
|
// Set the Main Screen
|
|
try
|
|
{
|
|
using (var key = Registry.CurrentUser.OpenSubKey(
|
|
address,
|
|
RegistryKeyPermissionCheck.ReadWriteSubTree))
|
|
{
|
|
key.SetValue(DevicePath, Binary);
|
|
SharedLogger.logger.Trace($"TaskBarStuckRectangle/Apply: Successfully applied TaskBarStuckRectangle registry settings for the {DevicePath} Screen in {address}!");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/GetCurrent: Unable to set the {DevicePath} TaskBarStuckRectangle registry settings in {address} due to an exception!");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
address = string.Format(MultiDisplayAddress, Version);
|
|
// Grab the main screen taskbar placement
|
|
try
|
|
{
|
|
using (var key = Registry.CurrentUser.OpenSubKey(
|
|
address,
|
|
RegistryKeyPermissionCheck.ReadWriteSubTree))
|
|
{
|
|
key.SetValue(DevicePath, Binary);
|
|
SharedLogger.logger.Trace($"TaskBarStuckRectangle/WriteToRegistry: Successfully applied TaskBarStuckRectangle registry settings for the {DevicePath} Screen in {address}!");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SharedLogger.logger.Error(ex, $"TaskBarStuckRectangle/WriteToRegistry: Unable to set the {DevicePath} TaskBarStuckRectangle registry settings in {address} due to an exception!");
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static bool RepositionMainTaskBar(TaskBarEdge edge)
|
|
{
|
|
// Tell Windows to refresh the Main Screen Windows Taskbar
|
|
// Find the "Shell_TrayWnd" window
|
|
IntPtr mainToolBarHWnd = Utils.FindWindow("Shell_TrayWnd", null);
|
|
// Send the "Shell_TrayWnd" window a WM_USER_REFRESHTASKBAR with a wParameter of 0006 and a lParamater of the position (e.g. 0000 for left, 0001 for top, 0002 for right and 0003 for bottom)
|
|
IntPtr taskBarPositionBuffer = new IntPtr((Int32)edge);
|
|
Utils.SendMessage(mainToolBarHWnd, Utils.WM_USER_REFRESHTASKBAR, (IntPtr)Utils.wParam_SHELLTRAY, taskBarPositionBuffer);
|
|
return true;
|
|
}
|
|
|
|
public static bool RepositionSecondaryTaskBars()
|
|
{
|
|
// Tell Windows to refresh the Other Windows Taskbars if needed
|
|
IntPtr lastTaskBarWindowHwnd = (IntPtr)Utils.NULL;
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
// Find the next "Shell_SecondaryTrayWnd" window
|
|
IntPtr nextTaskBarWindowHwnd = Utils.FindWindowEx((IntPtr)Utils.NULL, lastTaskBarWindowHwnd, "Shell_SecondaryTrayWnd", null);
|
|
if (nextTaskBarWindowHwnd == (IntPtr)Utils.NULL)
|
|
{
|
|
// No more windows taskbars to notify
|
|
break;
|
|
}
|
|
// Send the "Shell_TrayWnd" window a WM_SETTINGCHANGE with a wParameter of SPI_SETWORKAREA
|
|
Utils.SendMessage(lastTaskBarWindowHwnd, Utils.WM_SETTINGCHANGE, (IntPtr)Utils.SPI_SETWORKAREA, (IntPtr)Utils.NULL);
|
|
lastTaskBarWindowHwnd = nextTaskBarWindowHwnd;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static void RefreshTrayArea()
|
|
{
|
|
// Finds the Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> "Notification Area" containing the visible notification area icons (windows 7 version)
|
|
IntPtr systemTrayContainerHandle = Utils.FindWindow("Shell_TrayWnd", null);
|
|
IntPtr systemTrayHandle = Utils.FindWindowEx(systemTrayContainerHandle, IntPtr.Zero, "TrayNotifyWnd", null);
|
|
IntPtr sysPagerHandle = Utils.FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager", null);
|
|
IntPtr notificationAreaHandle = Utils.FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "Notification Area");
|
|
// If the visible notification area icons (Windows 7 aren't found, then we're on a later version of windows, and we need to look for different window names
|
|
if (notificationAreaHandle == IntPtr.Zero)
|
|
{
|
|
// Finds the Shell_TrayWnd -> TrayNotifyWnd -> SysPager -> "User Promoted Notification Area" containing the visible notification area icons (windows 10+ version)
|
|
notificationAreaHandle = Utils.FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", "User Promoted Notification Area");
|
|
// Also attempt to find the NotifyIconOverflowWindow -> "Overflow Notification Area' window which is the hidden windoww that notification icons live when they are
|
|
// too numberous or are hidden by the user.
|
|
IntPtr notifyIconOverflowWindowHandle = Utils.FindWindow("NotifyIconOverflowWindow", null);
|
|
IntPtr overflowNotificationAreaHandle = Utils.FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero, "ToolbarWindow32", "Overflow Notification Area");
|
|
// Fool the "Overflow Notification Area' window into thinking the mouse is moving over it
|
|
// which will force windows to refresh the "Overflow Notification Area' window and remove old icons.
|
|
RefreshTrayArea(overflowNotificationAreaHandle);
|
|
notifyIconOverflowWindowHandle = IntPtr.Zero;
|
|
overflowNotificationAreaHandle = IntPtr.Zero;
|
|
}
|
|
// Fool the "Notification Area" or "User Promoted Notification Area" window (depends on the version of windows) into thinking the mouse is moving over it
|
|
// which will force windows to refresh the "Notification Area" or "User Promoted Notification Area" window and remove old icons.
|
|
RefreshTrayArea(notificationAreaHandle);
|
|
systemTrayContainerHandle = IntPtr.Zero;
|
|
systemTrayHandle = IntPtr.Zero;
|
|
sysPagerHandle = IntPtr.Zero;
|
|
notificationAreaHandle = IntPtr.Zero;
|
|
|
|
}
|
|
|
|
|
|
private static void RefreshTrayArea(IntPtr windowHandle)
|
|
{
|
|
// Moves the mouse around within the window area of the supplied window
|
|
Utils.RECT rect;
|
|
Utils.GetClientRect(windowHandle, out rect);
|
|
for (var x = 0; x < rect.right; x += 5)
|
|
for (var y = 0; y < rect.bottom; y += 5)
|
|
Utils.SendMessage(windowHandle, Utils.WM_MOUSEMOVE, 0, (y << 16) + x);
|
|
}
|
|
|
|
/*public void DoMouseLeftClick(IntPtr handle, Point x)
|
|
{
|
|
Utils.SendMessage(handle, (int)Utils.WM_MOUSEMOVE, 0, Utils.MakeLParam(x.X, x.Y));
|
|
//SendMessage(handle, (int)Utils.WM_LBUTTONUP, 0, Utils.MakeLParam(x.X, x.Y));
|
|
|
|
return;
|
|
|
|
//I have tried PostMessage, and SendMessage, and both of them at the same time, and neither works.
|
|
|
|
Utils.PostMessage(handle, Utils.WM_MOUSEMOVE, 0, Utils.MakeLParam(x.X, x.Y));
|
|
//PostMessage(handle, (uint)Utils.WM_LBUTTONUP, 0, Utils.MakeLParam(x.X, x.Y));
|
|
}
|
|
*/
|
|
}
|
|
} |