在进行窗口编程时,经常需要对菜单窗口进行自定义处理,比如实现菜单的透明化效果。本文将介绍一种不使用钩子函数(hooks)的方法来实现这一目的。
首先,需要找到已经创建的菜单窗口。在Delphi中,可以使用FindWindow函数来查找具有特定类名的窗口。
var
mh: HWND;
begin
mh := FindWindow('#32768', nil);
if mh = 0 then
// 处理错误
end;
如果mh不为0,说明成功找到了菜单窗口。接下来,需要设置新的窗口过程来处理菜单窗口的消息。
通过SetWindowLong函数,可以设置窗口的新过程。同时,需要保存旧的窗口过程,以便在新过程中调用。
var
OldMenuProc: Pointer;
begin
OldMenuProc := SetWindowLong(mh, GWL_WNDPROC, Integer(@MenuProc));
if OldMenuProc = nil then
// 处理错误
end;
现在,可以定义新的窗口过程MenuProc,它将处理菜单窗口的消息。
在新的窗口过程中,可以处理特定的消息,比如设置窗口的透明效果。
function MenuProc(h: HWND; uMsg: UINT; wp: WPARAM; lp: LPARAM): LRESULT; stdcall;
begin
Result := 1;
case uMsg of
WM_INITMENUPOPUP: // 仅作为示例
begin
SetWindowLong(h, GWL_EXSTYLE, GetWindowLong(h, GWL_EXSTYLE) or WS_EX_LAYERED);
SetLayeredWindowAttributes(h, 0, 127, LWA_ALPHA);
end;
end;
if Result = 1 then
Result := CallWindowProc(OldMenuProc, h, uMsg, wp, lp);
end;
通过这种方式,成功地使菜单窗口变得透明。需要注意的是,MenuProc不会接收到所有常见的消息,因为它是在菜单已经创建之后设置的。
MenuProc接收到的消息是菜单被调用和销毁几乎同时发生的。例如:
19:23:13 : MenuProc: 482 wParam - 1 lParam - 0
19:23:13 : MenuProc: 124 wParam - -20 lParam - 1243400 // 仅当WS_EX_*样式改变时出现
19:23:13 : MenuProc: 125 wParam - -20 lParam - 1243400 // 仅当WS_EX_*样式改变时出现
19:23:13 : MenuProc: 70 wParam - 0 lParam - 1243264
19:23:13 : MenuProc: 131 wParam - 1 lParam - 1243220
19:23:13 : MenuProc: 71 wParam - 0 lParam - 1243264
19:23:13 : MenuProc: 5 wParam - 0 lParam - 3342476
19:23:13 : MenuProc: 70 wParam - 0 lParam - 1243628
19:23:13 : MenuProc: 133 wParam - 1 lParam - 0
19:23:13 : MenuProc: 20 wParam - -1392438729 lParam - 0
19:23:13 : MenuProc: 71 wParam - 0 lParam - 1243628
19:23:13 : MenuProc: 15 wParam - 0 lParam - 0
19:23:13 : MenuProc: 485 wParam - -1 lParam - 0
...
19:23:14 : MenuProc: 485 wParam - -1 lParam - 0
19:23:14 : MenuProc: 70 wParam - 0 lParam - 1243628
19:23:14 : MenuProc: 71 wParam - 0 lParam - 1243628
19:23:14 : MenuProc: 2 wParam - 0 lParam - 0
19:23:14 : MenuProc: 130 wParam - 0 lParam - 0
此外,调用菜单时应使用TrackPopupMenuEx函数,并传递TPM_NOANIMATION标志,以关闭所有可能阻塞应用更改的效果。