delphi - 调用 RecreateWnd 后窗口类样式 CS_NOCLOSE 不起作用

标签 delphi winapi

我需要一个表单来禁用菜单关闭按钮(并且还禁用使用 Alt-F4 关闭),因此我使用了 CS_NOCLOSE类(class)风格。如果我在 CreateParams 中设置它,它会按预期工作:

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;  
  Params.WindowClass.style := Params.WindowClass.style or CS_NOCLOSE;
end;

关闭按钮被禁用,您无法使用 ALT+F4 关闭窗口(我有自己的关闭按钮)。

现在我添加了一个标志:FNoCloseButton,最初设置为False

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;
  if FNoCloseButton then
    Params.WindowClass.style := Params.WindowClass.style or CS_NOCLOSE;
end;

创建表单后,我有这个:

procedure TForm1.Button1Click(Sender: TObject);
begin
  FNoCloseButton := True;
  RecreateWnd;
end;

单击 Button1 后,将重新创建窗口,但 CS_NOCLOSE 现在无效并被忽略。

为什么会出现这种行为?为什么在创建窗口类样式后无法更改它? (我认为我可以,因为 SetClassLong api 存在)

我也尝试过SetClassLong与:

procedure TForm1.Button2Click(Sender: TObject);
begin
  SetClassLong(Self.Handle, GCL_STYLE, GetClassLong(Self.Handle, GCL_STYLE) or CS_NOCLOSE);
  DrawMenuBar(Self.Handle); // Must call this to invalidate
end;

这有效。关闭已禁用(加上 Alt-F4),但系统菜单项“关闭”可见,我可以通过单击它来关闭窗口。因此 SetClassLong 的行为有点不同。

我错过了什么?

最佳答案

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;
  if FNoCloseButton then
    Params.WindowClass.style := Params.WindowClass.style or CS_NOCLOSE;
end;

上面代码中修改窗口类信息的行没有任何作用,因为该类已经在代码第一次运行时注册;当 FNoCloseButton 为 false 时。

调用RecreateWindow后,VCL会销毁并创建窗口,但不会尝试重新注册类,否则会因ERROR_CLASS_ALREADY_EXISTS而失败。您可能会争辩说,在销毁窗口时不取消注册该类是一个设计错误,但事实并非如此。不要忘记,您可以在 VCL 应用程序生命周期的不同时间拥有一个或多个表单类实例。


对于解决方案,如果您可以确保要销毁的窗口是同类的唯一实例,则可以自行取消注册该类。然后VCL查询类信息并发现它没有注册,就会在创建窗口之前为您注册它。否则,您必须像您已经在做的那样使用 SetClassLong[Ptr]

type
  TForm1 = class(TForm)
    ..
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure DestroyHandle; override;
    ...

..

procedure TForm1.DestroyHandle;
begin
  inherited;
  if not winapi.windows.UnregisterClass(PChar(ClassName), HInstance) then
    RaiseLastOSError;
end;

关于delphi - 调用 RecreateWnd 后窗口类样式 CS_NOCLOSE 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44521877/

相关文章:

c++ - NtEnumerateKey() 的 KeyInformation 参数

c - "HANDLE"与类型为 "HINSTANCE"的参数不兼容

c++ - CreateProcessAsUser 返回错误代码 2

c++ - 如何检测窗口当前正在运行模态对话框?

delphi - 静态类方法和常规例程指针的兼容性如何?

Delphi 调用 API 函数 (SOAP)

ios - 如何从cocoapods下载SDK二进制文件

c++ - 在 windows xp 中获取所有已注册的 usb hid 设备的列表

c++ - 为什么这个带有 WINAPI 的 c++ 语法是什么意思?

delphi - 将变体转换为 double 时出错 [Delphi XE + IBObjects 4.9.12]