【发布时间】:2018-07-08 19:54:38
【问题描述】:
问题已解决,请参阅我的回答,但由于堆栈溢出的 2 天规则,目前无法接受。感谢大家的投入!
edit:答案被删除,答案是删除行:
function registerWindowMessage( lpString : PChar ) : integer; stdcall; external user32 name 'RegisterWindowMessageA';
来自项目,因为它已经在delphi windows api文件中定义,就是这样。不需要重新定义,而且重新定义的版本也不匹配。
我尝试将一些旧的 Delphi 5 Enterprise(32 位)项目恢复/迁移到新的/现代的 Delphi 版本(Delphi 10.2、32 位),但是旧版本可以在任何操作系统上编译和运行。总的来说,相当兼容。
现在我遇到了这个奇怪的问题,Delphi 10.2 表单不喜欢处理SHELLHOOK 消息,旧编译的 Delphi 5 版本可以。因为我没有 Delphi 10.2(免费版)forms.pas 的来源,所以我看不到实际发生了什么(不同),也无法弄清楚为什么它不起作用。无法调试。
钩子注册似乎没问题,FormCreate 中的writeln 显示以下值(在额外的控制台窗口中):
但是overrided WndProc 过程不处理任何shellhook 消息。我做了一个演示,您可以自己尝试创建一个新项目,双击表单的onCreate 和onDestroy 事件并将表单代码替换为:
unit main;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
const
// Constant for shell hook events
HSHELL_WINDOWCREATED = 1;
HSHELL_WINDOWDESTROYED = 2;
HSHELL_ACTIVATESHELLWINDOW = 3;
HSHELL_WINDOWACTIVATED = 4;
HSHELL_GETMINRECT = 5;
HSHELL_REDRAW = 6;
HSHELL_TASKMAN = 7;
HSHELL_LANGUAGE = 8;
HSHELL_ACCESSIBILITYSTATE = 11;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
FHookMsg : integer;
procedure WMShellHook(var Msg: TMessage );
protected
procedure WndProc(var Msg : TMessage); override;
public
{ Public declarations }
end;
var
Form1: TForm1;
// Not implemented Windows API functions, available at WinXP and later
function registerWindowMessage( lpString : PChar ) : integer; stdcall; external user32 name 'RegisterWindowMessageA';
function registerShellHookWindow( hWnd : THandle ) : bool; stdcall; external user32 name 'RegisterShellHookWindow';
function deregisterShellHookWindow( hWnd : THandle ) : bool; stdcall; external user32 name 'DeregisterShellHookWindow';
implementation
{$R *.dfm}
procedure TForm1.FormActivate(Sender: TObject);
begin
// send a message
sendMessage( handle, WM_USER+$40, 1, 2 );
postMessage( handle, WM_USER+$40, 3, 4 );
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
writeln( handle );
FHookMsg:=registerWindowMessage('SHELLHOOK'+#0 );
writeln( FHookMsg );
writeln( registerShellHookWindow( handle ) );
writeln( handle ); // handle still the same
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
deregisterShellHookWindow( handle );
writeln( handle ); // set breakpoint here, handle still the same
end;
procedure TForm1.FormShow(Sender: TObject);
begin
writeln( handle ); // handle still the same
end;
procedure TForm1.WndProc(var Msg : TMessage);
begin
// writeln( handle ); even when i showed this, handle is still the same
if( Msg.Msg = WM_USER+$40 ) then
begin
writeln( 'wParam is: ', Msg.wParam );
writeln( 'lParam is: ', Msg.lParam );
exit;
end;
if( Msg.Msg = FHookMsg ) then
begin
// Not executed in Delphi 10.2 generated exe
writeln( 'wParam is: ', Msg.wParam );
WMShellHook( Msg );
exit;
end;
inherited; // call this for default behaviour
end;
procedure TForm1.WMShellHook( var Msg: TMessage );
begin
// Simple however effective way to detect window changes at low costs.
if( Msg.wparam = HSHELL_WINDOWCREATED )
or ( Msg.wparam = HSHELL_WINDOWDESTROYED )
or ( Msg.wparam = HSHELL_WINDOWACTIVATED ) then
begin
// Not executed in Delphi 10.2 generated exe
writeln('here' );
end;
end;
end.
PS:不要忘记打开链接器选项“生成控制台应用程序”以避免在运行此演示时出现 writeln 错误。
有人能说出发生了什么以及为什么它不起作用吗?
编辑:
allocateHwnd 和 deallocateHwnd 的示例没有收到任何内容。为什么不?关注this 示例。
unit unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs;
const
// Constant for shell hook events
HSHELL_WINDOWCREATED = 1;
HSHELL_WINDOWDESTROYED = 2;
HSHELL_ACTIVATESHELLWINDOW = 3;
HSHELL_WINDOWACTIVATED = 4;
HSHELL_GETMINRECT = 5;
HSHELL_REDRAW = 6;
HSHELL_TASKMAN = 7;
HSHELL_LANGUAGE = 8;
HSHELL_ACCESSIBILITYSTATE = 11;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
FHookWndHandle : THandle;
FHookMsg : integer;
procedure WMShellHook(var Msg: TMessage );
protected
procedure WndMethod(var Msg: TMessage);
public
{ Public declarations }
end;
var
Form1: TForm1;
// Not implemented Windows API functions, available at WinXP and later
function registerWindowMessage( lpString : PChar ) : integer; stdcall; external user32 name 'RegisterWindowMessageA';
function registerShellHookWindow( hWnd : THandle ) : bool; stdcall; external user32 name 'RegisterShellHookWindow';
function deregisterShellHookWindow( hWnd : THandle ) : bool; stdcall; external user32 name 'DeregisterShellHookWindow';
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FHookWndHandle:=allocateHWnd(WndMethod);
FHookMsg:=registerWindowMessage('SHELLHOOK'+#0 );
writeln( FHookMsg );
writeln( registerShellHookWindow( FHookWndHandle ) );
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
deregisterShellHookWindow( FHookWndHandle );
deallocateHWnd( FHookWndHandle );
end;
procedure TForm1.WndMethod(var Msg: TMessage);
begin
if( Msg.Msg = FHookMsg ) then
begin
// Not executed in Delphi 10.2 generated exe
writeln( 'wParam is: ', Msg.wParam );
WMShellHook( Msg );
exit;
end;
end;
procedure TForm1.WMShellHook( var Msg: TMessage );
begin
// Simple however effective way to detect window changes at low costs.
if( Msg.wparam = HSHELL_WINDOWCREATED )
or ( Msg.wparam = HSHELL_WINDOWDESTROYED )
or ( Msg.wparam = HSHELL_WINDOWACTIVATED ) then
begin
// Not executed in Delphi 10.2 generated exe
writeln('here' );
end;
end;
end.
【问题讨论】:
标签: windows forms delphi winapi delphi-10.2-tokyo