You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

因TStyleManager.TrySetStyle导致MSG_LateFormInit消息丢失的解决方案问询

解决MSG_LateFormInit消息在TStyleManager.TrySetStyle后丢失的问题

针对主窗体Handle因TStyleManager.TrySetStyle重建导致消息丢失的问题,以下是几个无需改动用户DPR代码的可靠解决方案:

方案1:监听窗体Handle变更事件,自动重发消息

当TStyleManager.TrySetStyle重建窗体时,会触发主窗体的OnHandleChange事件,利用这个时机重新投递初始化消息,同时通过标记避免重复执行:

type
  TAppData = class(TApplication)
  private
    FMainForm: TForm;
    FIsInitialized: Boolean;
    procedure MainFormHandleChange(Sender: TObject);
  public
    procedure InitMainForm(AMainFormClass: TFormClass);
  end;

procedure TAppData.InitMainForm(AMainFormClass: TFormClass);
begin
  FIsInitialized := False;
  FMainForm := AMainFormClass.Create(nil);
  FMainForm.OnHandleChange := MainFormHandleChange;
  // 初始投递消息
  PostMessage(FMainForm.Handle, MSG_LateFormInit, 0, 0);
end;

procedure TAppData.MainFormHandleChange(Sender: TObject);
begin
  if not FIsInitialized and (FMainForm.Handle <> 0) then
  begin
    // 窗体Handle重建后,重新投递初始化消息
    PostMessage(FMainForm.Handle, MSG_LateFormInit, 0, 0);
  end;
end;

// 在MSG_LateFormInit的处理函数中标记初始化完成
procedure TMainForm.WMLateFormInit(var Msg: TMessage);
begin
  inherited;
  if not TAppData(Application).FIsInitialized then
  begin
    // 执行延迟初始化逻辑
    // ...
    TAppData(Application).FIsInitialized := True;
  end;
end;

方案2:改用TApplication.OnIdle事件执行延迟初始化

放弃PostMessage,转而利用Application的空闲事件触发初始化,这种方式不受窗体Handle变更影响,且能保证在消息循环启动后执行:

type
  TAppData = class(TApplication)
  private
    FInitDone: Boolean;
    procedure OnAppIdle(Sender: TObject; var Done: Boolean);
  public
    procedure InitMainForm(AMainFormClass: TFormClass);
  end;

procedure TAppData.InitMainForm(AMainFormClass: TFormClass);
begin
  FInitDone := False;
  CreateForm(AMainFormClass, FMainForm);
  // 注册空闲事件
  OnIdle := OnAppIdle;
end;

procedure TAppData.OnAppIdle(Sender: TObject; var Done: Boolean);
begin
  if not FInitDone then
  begin
    // 执行延迟初始化逻辑
    FMainForm.Perform(MSG_LateFormInit, 0, 0);
    FInitDone := True;
    // 移除事件避免重复触发
    OnIdle := nil;
  end;
end;

方案3:通过Application Handle转发消息

将消息投递到Application的Handle(该Handle不会随窗体重建改变),在Application的消息处理中转发给主窗体,确保消息不会丢失:

type
  TAppData = class(TApplication)
  private
    FMainForm: TForm;
    FIsInitialized: Boolean;
    procedure WndProc(var Msg: TMessage); override;
  public
    procedure InitMainForm(AMainFormClass: TFormClass);
  end;

procedure TAppData.InitMainForm(AMainFormClass: TFormClass);
begin
  FIsInitialized := False;
  FMainForm := AMainFormClass.Create(nil);
  // 投递消息到Application Handle
  PostMessage(Handle, MSG_LateFormInit, 0, 0);
end;

procedure TAppData.WndProc(var Msg: TMessage);
begin
  inherited;
  if (Msg.Msg = MSG_LateFormInit) and not FIsInitialized then
  begin
    if (FMainForm <> nil) and (FMainForm.Handle <> 0) then
    begin
      // 转发给主窗体执行初始化
      FMainForm.Perform(MSG_LateFormInit, 0, 0);
      FIsInitialized := True;
    end
    else
    begin
      // 主窗体Handle尚未就绪,重新投递消息
      PostMessage(Handle, MSG_LateFormInit, 0, 0);
    end;
  end;
end;

以上方案都无需用户修改DPR代码,同时兼容是否调用TStyleManager.TrySetStyle的场景,推荐优先使用方案2或3,稳定性更强。

内容的提问来源于stack exchange,提问作者Error - CPU Not Foud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 15:03:22