delphi AllocConsole、SetConsoleCtrlHandler阻止终止

bq8i3lrv  于 2023-03-29  发布在  其他
关注(0)|答案(1)|浏览(205)

在认为这是一个重复的问题之前,请阅读以下内容:是的,这个问题在不同的语言中存在,至少在 Delphi ,C#和C++中,但它们都有一些共同点:他们谈论的是处理一个干净的关闭,而不是防止它。
我们开始吧:
在一个VCL应用程序中,我使用AllocConsole打开了一个新的控制台窗口,但是当关闭右上角有十字的窗口时,我的应用程序终止了。我想 * 防止 * 不处理!
部分代码:

function Handler(dwCtrlType: DWORD): Boolean; cdecl;
begin
  case dwCtrlType of
    CTRL_CLOSE_EVENT, CTRL_C_EVENT, CTRL_BREAK_EVENT:
      Exit(True);
  else
    Exit(false);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  AllocConsole;
  SetConsoleCtrlHandler(@Handler, True);
end;

我读过WinAPI documentation,但它没有说任何关于防止应用程序终止。
我尝试在我的MainForm上添加WM_ENDSESSIONWM_QUERYENDSESSIONWM_CLOSEWM_QUIT的消息处理程序,但它们都没有被调用。我还尝试添加FormCloseQuery事件,但它也没有被调用。
我已经阅读并尝试了解决方案,发现here,但SetConsoleCtrlHandler(nil, True);不提供终止应用程序
那么,如何预防流产呢?

aamkag61

aamkag611#

理论上,这是通过重载WinProc,并在防止控制台关闭事件后调用FreeConsole来完成的。我正在尝试以这种方式重写WinProc函数:

function GetConsoleWindow: HWND; stdcall; external kernel32 name 'GetConsoleWindow';

var
  FConsoleHandle: HWND;

function ConsoleWndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
  if Msg = WM_CLOSE then
  begin
    // Ignore the close message
    Result := 0;
  end
  else
  begin
    // Handle other messages
    Result := DefWindowProc(hWnd, Msg, wParam, lParam);
  end;
end;

procedure TMainForm.cbDebugConsoleClick(Sender: TObject);
var
  m: HMENU; s: string; r: NativeInt;
begin
  if cbDebugConsole.Checked then
  begin
    AllocConsole;
    FConsoleHandle := GetConsoleWindow;
    r := SetWindowLong(FConsoleHandle, GWL_WNDPROC, LongInt(@ConsoleWndProc));
    s := SysErrorMessage(GetLastError);
  end else
    FreeConsole;
end;

所以,SetWindowLong返回0,表示“访问被拒绝”。我不知道如何获得访问权限来更改控制台窗口的WinProc。

相关问题