如果只是要得到句柄,那么转贴一篇文章。
首 先 需 要 说 明 要 在 Delphi 实 现 Sendkeys功 能 , 应 该 使 用 Journal Playback钩 子 (hook)函 数 ,
而 不 是 使 用 SendMessage函 数 。 下 面 我 们 来 介 绍 如 何 利 用 鼠 标 移 动 让 用 户 选 择 窗 口 ,
而 程 序 进 一 步 得 到 窗 口 的 句 柄 。 Windows API中 有 一 个 函 数 WindowFromPoint, 只 要 知 道
鼠 标 的 位 置 (屏 幕 坐 标 ), 就 可 以 得 到 该 位 置 所 属 的 窗 口 的 句 柄 , 有 了 句 柄 , 就
可 以 利 用 其 他 的 函 数 得 到 更 多 的 信 息 。 如 果 鼠 标 在 程 序 的 窗 口 中 移 动 , 可 以 得
到 MouseMove事 件 。 要 想 鼠 标 在 窗 口 外 部 移 动 时 , 仍 能 得 到 鼠 标 事 件 , 必 须 使 用
SetCapture函 数 。 下 面 这 个 例 子 就 是 利 用 这 两 个 函 数 来 实 现 你 所 要 求 的 功 能 。
type
TForm1 = class(TForm)
… … … …
public
procedure InvertTracker(hwndDest : Integer);
end;
… … … …
var
Form1: TForm1;
mlngHwndCaptured: Integer;
hWndLast: Integer;
… … … …
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var pt : TPoint;
begin
if GetCapture() <> 0 then // 处 于 捕 捉 状 态
begin
pt.X := X;
pt.Y := Y;
ClientToScreen(pt); // 获 得 鼠 标 的 屏 幕 位 置
// 获 得 窗 口 句 柄
mlngHwndCaptured := WindowFromPoint(pt);
if hWndLast <> mlngHwndCaptured then
begin
if hWndLast <> 0 then // 使 窗 口 边 框 加 粗
InvertTracker(hWndLast);
InvertTracker(mlngHwndCaptured);
hWndLast := mlngHwndCaptured;
end
end;
// 显 示 坐 标 和 窗 口 句 柄
Caption := 'X: ' + IntToStr(x) + ', Y: ' + IntToStr
+ ', hWnd: ' + IntToStr(mlngHwndCaptured);
end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if SetCapture(handle) <> 0 then // 开 始 捕 捉
Cursor := crUpArrow;
end;
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var strCaption: PChar;
begin
If mlngHwndCaptured <> 0 Then
begin // 获 得 窗 口 标 题
strCaption := StrAlloc(1000);
GetWindowText(mlngHwndCaptured, strCaption, 1000);
Caption := StrPas(strCaption);
InvalidateRect(0, PRect(0), True);
mlngHwndCaptured := 0;
Cursor := crDefault;
ReleaseCapture;
StrDispose(strCaption);
hWndLast := 0;
end
end;
// 使 窗 口 边 框 变 粗
procedure TForm1.InvertTracker(hwndDest: Integer);
var
hdcDest, hPen, hOldPen, hOldBrush : Integer;
cxBorder, cxFrame, cyFrame, cxScreen, cyScreen, cr : Integer;
rc : TRect;
Const NULL_BRUSH = 5;
Const R2_NOT = 6;
Const PS_INSIDEFRAME = 6;
begin
cxScreen := GetSystemMetrics(0);
cyScreen := GetSystemMetrics(1);
cxBorder := GetSystemMetrics(5);
cxFrame := GetSystemMetrics(32);
cyFrame := GetSystemMetrics(33);
GetWindowRect(hwndDest, rc);
hdcDest := GetWindowDC(hwndDest);
SetROP2(hdcDest, R2_NOT);
cr := clBlack;
hPen := CreatePen(PS_INSIDEFRAME, 3 * cxBorder, cr);
hOldPen := SelectObject(hdcDest, hPen);
hOldBrush := SelectObject(hdcDest, GetStockObject(NULL_BRUSH));
Rectangle(hdcDest, 0, 0, rc.Right - rc.Left, rc.Bottom - rc.Top);
SelectObject(hdcDest, hOldBrush);
SelectObject(hdcDest, hOldPen);
ReleaseDC(hwndDest, hdcDest);
DeleteObject(hPen);
end;
// 将 窗 口 移 动 到 左 上 角 , 并 减 少 窗 口 高 度 , 便 于 操 作
procedure TForm1.FormCreate(Sender: TObject);
begin
Left := 0;
Top :=0;
ClientHeight := 76;
end;
运 行 该 程 序 时 , 先 在 程 序 窗 口 内 点 一 下 , 然 后 按 住 鼠 标 左 键 不 放 , 移 动 鼠 标
, 这 时 你 会 看 到 程 序 窗 口 的 标 题 位 置 不 断 显 示 鼠 标 的 当 前 位 置 (窗 口 坐 标 )和 鼠 标
所 在 位 置 的 窗 口 句 柄 。 同 时 , 被 选 中 的 窗 口 边 框 加 粗 , 一 旦 放 开 左 键 , 则 程 序 窗
口 的 标 题 就 改 为 所 选 中 窗 口 的 标 题 。 相 信 许 多 人 对 这 种 操 作 方 式 都 会 感 到 熟 悉 ,
因 为 象 Spy++(Visual C++)、 Magic Mouse、 Capture Professional等 很 多 软 件 都 是 采 用 类 似 的 操 作
来 选 择 窗 口 的 。