【问题标题】:Receive and Handle Windows Messages in Lazarus在 Lazarus 中接收和处理 Windows 消息
【发布时间】:2017-04-08 07:21:18
【问题描述】:

我正在尝试将我用 Delphi 编写的一个类移植到 Lazarus。它依靠WM_DEVICECHANGE 来检测连接的USB 设备。我无法让我的组件接收 Windows 消息,而它在 Delphi 中运行良好。

在意识到AllocateHwnd 只是 Free Pascal 中的一个占位符后,我开始模仿 LCL 为此目的所做的工作。

TUSB = class(TComponent)
private
    FHandle: HWND;
    procedure WndProc(var Msg: TMessage);
    procedure AllocHandle(Method: TWndMethod);
public
    constructor Create(AOwner: TComponent);
end;
.
.
.
procedure CallbackAllocateHWnd(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam); stdcall;
var
  Msg: TMessage;
  PMethod: ^TWndMethod;
begin
  FillChar(Msg{%H-}, SizeOf(Msg), #0);

  Msg.msg := uMsg;
  Msg.wParam := wParam;
  Msg.lParam := lParam;

  PMethod := {%H-}Pointer(GetWindowLong(ahwnd, GWL_USERDATA));

  if Assigned(PMethod) then PMethod^(Msg);

  Windows.DefWindowProc(ahwnd, uMsg, wParam, lParam);
end;

procedure TUSB.AllocHandle(Method: TWndMethod);
var
  PMethod: ^TWndMethod;
begin
  FHandle := Windows.CreateWindow(PChar('STATIC'), '', WS_OVERLAPPED, 0, 0, 0, 0, 0, 0, MainInstance, nil);
  if Assigned(Method) then 
  begin
    Getmem(PMethod, SizeOf(TMethod));
    PMethod^ := Method;

    SetWindowLong(FHandle, GWL_USERDATA, {%H-}PtrInt(PMethod));
  end;

  SetWindowLong(FHandle, GWL_WNDPROC, {%H-}PtrInt(@CallbackAllocateHWnd));
end; 

constructor TUSB.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  AllocHandle(@WndProc);
end;

这给了我一个有效的窗口句柄,但从未调用过 CallbackAllocateHWnd。我知道这些东西是 Windows 特定的并且不可移植,但这不是现在的问题。我只想从TComponent 派生一个类,并能够接收和处理 Windows 消息。完全相同的代码行,在 Delphi 中工作。

编辑:还尝试将 HWND_MESSAGE 设为 hWndParent

编辑2:我发现在SetWindowLong(FHandle, GWL_WNDPROC, {%H-}PtrInt(@CallbackAllocateHWnd)); 之后调用GetLastError 返回1413,这意味着索引无效。我什至在那里尝试了GetWindowLong 并给了我同样的错误!

【问题讨论】:

  • allochandle 是否运行?同样 afaik setwindowlong 返回旧的 wndproc,保存并在您的 wndproc 中调用它
  • FHandle 运行 AllocHandle 后有一个有效的窗口句柄,但是我的自定义 WndProc 在发送消息时没有触发。

标签: delphi lazarus freepascal windows-messages


【解决方案1】:

仅供最终访问此页面的其他人参考:

从 Lazarus 论坛得到想法后,我发现在 uses 子句中包含 LCLIntf 单元可以解决问题。我在运行时跟踪了代码,它最终调用了Windows.SetWindowLongPtrW。因此,只需将第二次调用 SetWindowLong 替换为 Windows.SetWindowLongPtrW 现在就可以了!

【讨论】:

    猜你喜欢
    • 2016-10-28
    • 1970-01-01
    • 2016-03-19
    • 1970-01-01
    • 2011-03-09
    • 2014-08-20
    • 1970-01-01
    • 2012-12-26
    相关资源
    最近更新 更多