Нужно написать на С# программу, которая будет определять над каким окном 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) вызывал и одиночно (по нажатию кнопки) и в цикле (так как предполагал, что отрисовка может выполнятся за один кадр, после чего, исчезать). Ни так ни так не работает.
Подскажите, пожалуйста, в чем проблема... Скоро курсовой сдавать, а ничего не готово :(
Ответ
Проблема в неверном подходе. Во-первых, забудьте про функцию 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);
}
Иллюстрация различия между этими двумя методами:
Комментариев нет:
Отправить комментарий