#c_sharp #winapi #графика #gdi
Нужно написать на С# программу, которая будет определять над каким окном Windows сейчас находится курсор и обводить это окно рамкой (указывая пользователю, над каким элементом находится курсор, ведь в WinApi, окном является не только само окно, содержащее в себе множество других элементов, но и эти элементы тоже являются окнами). Handler окна под курсором получить легко: ... Point point; WinApi.GetCursorPos(out point); WinApi.WindowFromPoint(point); ... Но вот нарисовать что то на окне не выходит, хоть убейте. public static void drawSelectionRectangle(IntPtr handler) { Rectangle rectangle; WinApi.GetWindowRect(handler, out rectangle); WinApi.PAINTSTRUCT paintProperties; IntPtr paintContext = WinApi.BeginPaint(handler, out paintProperties); IntPtr pen = WinApi.CreatePen(WinApi.PenStyle.PS_SOLID, 5, (uint) ColorTranslator.ToWin32(Color.Red)); WinApi.SelectObject(paintContext, pen); WinApi.Rectangle(paintContext, rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom); WinApi.ValidateRect(handler, IntPtr.Zero); WinApi.EndPaint(handler, ref paintProperties); } drawSelectionRectangle(IntPtr handler) вызывал и одиночно (по нажатию кнопки) и в цикле (так как предполагал, что отрисовка может выполнятся за один кадр, после чего, исчезать). Ни так ни так не работает. Подскажите, пожалуйста, в чем проблема... Скоро курсовой сдавать, а ничего не готово :(
Ответы
Ответ 1
Проблема в неверном подходе. Во-первых, забудьте про функцию BeginPaint (вне обработки сообщения WM_PAINT), во-вторых, рисовать надо не в контексте целевого окна, а в контексте его родительского окна (контекст окна позволяет рисовать только в его клиентской области, а рамка-то нам нужна снаружи). Я предлагаю сделать как-то так: using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; namespace DrawingTest { public partial class Form1 : Form { [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool GetCursorPos(out POINT lpPoint); [DllImport("user32.dll")] static extern IntPtr WindowFromPoint(POINT p); [DllImport("user32.dll", SetLastError = true)] static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect); [DllImport("user32.dll")] static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint); [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] public static extern IntPtr GetParent(IntPtr hWnd); public Form1() { InitializeComponent(); } private void timer1_Tick(object sender, EventArgs e) { //получаем окно в текущей позиции курсора POINT pt; GetCursorPos(out pt); IntPtr hwnd = WindowFromPoint(pt); //получаем родительское окно IntPtr hwnd_p = GetParent(hwnd); //получаем границы окна RECT rc; GetWindowRect(hwnd, out rc); //перевод из экранных координат в клиентские POINT pt1=new POINT(rc.Left,rc.Top), pt2=new POINT(rc.Right,rc.Bottom); ScreenToClient(hwnd_p, ref pt1); ScreenToClient(hwnd_p, ref pt2); RECT rc_client = new RECT(); rc_client.Left = pt1.X-1; rc_client.Top = pt1.Y-1; rc_client.Right = pt2.X; rc_client.Bottom = pt2.Y; //формируем структуру для GDI+ Rectangle rect = new Rectangle(rc_client.Left, rc_client.Top, rc_client.Right - rc_client.Left, rc_client.Bottom - rc_client.Top); //получаем контекст окна Graphics g = System.Drawing.Graphics.FromHwnd(hwnd_p); using (g) { //рисуем прямоугольник g.DrawRectangle(Pens.Red, rect); } } } [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; public POINT(int x, int y) { this.X = x; this.Y = y; } public POINT(System.Drawing.Point pt) : this(pt.X, pt.Y) { } public static implicit operator System.Drawing.Point(POINT p) { return new System.Drawing.Point(p.X, p.Y); } public static implicit operator POINT(System.Drawing.Point p) { return new POINT(p.X, p.Y); } } [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; // x position of upper-left corner public int Top; // y position of upper-left corner public int Right; // x position of lower-right corner public int Bottom; // y position of lower-right corner } } Если целевое окно перекрывается другими окнами, соответствующая часть рамки будет скрыта. Чтобы рисовать рамку поверх всех окон, код рисования нужно изменить, используя контекст рабочего стола: //получаем окно в текущей позиции курсора POINT pt; GetCursorPos(out pt); IntPtr hwnd = WindowFromPoint(pt); //получаем границы окна RECT rc; GetWindowRect(hwnd, out rc); //формируем структуру для GDI+ Rectangle rect = new Rectangle(rc.Left, rc.Top, rc.Right - rc.Left, rc.Bottom - rc.Top); //получаем контекст рабочего стола Graphics g = System.Drawing.Graphics.FromHwnd((IntPtr)0); using (g) { //рисуем прямоугольник g.DrawRectangle(Pens.Red, rect); } Иллюстрация различия между этими двумя методами:
Комментариев нет:
Отправить комментарий