无控制台创建Gnat进程

3
我需要一个可以在后台静默运行的应用程序,并且仍然可以与当前用户的桌面交互,但不是服务。
我希望该应用程序在启动时不会生成控制台输出窗口。
在C语言中,似乎可以使用Kernel32.dll中的FreeConsole函数来实现此功能,因此我已经导入了该函数:
procedure Free_Console
  is
  use System;

  type Shared_Library_Function
    is access function
      return Interfaces.C.Int;
    pragma Convention(Stdcall, Shared_Library_Function);
  function To_Shared_Library_Function
    is new Ada.Unchecked_Conversion(System.Address, Shared_Library_Function);

  function Load_Library(
    File_Name : in Interfaces.C.Char_Array)
    return System.Address;
  pragma Import(Stdcall, Load_Library, "LoadLibrary", "_LoadLibraryA@4");

  function Get_Function_Address(
    Module        : in System.Address;
    Function_Name : in Char_Array)
    return System.Address;
  pragma Import(stdcall, Get_Function_Address, "GetProcAddress", "_GetProcAddress@8");

  Library : System.Address := Load_Library(To_C("kernel32.dll"));
  Pointer : System.Address := Get_Function_Address(Library, To_C("FreeConsole"));
  begin
    if Pointer /= System.Null_Address then
      declare
        Result : Interfaces.C.Int := 1;
      begin
        Result := To_Shared_Library_Function(Pointer).all;
      end;
    else
      -- TODO Handle Error
      null;
    end if;
  end Free_Console;

这只是将进程与控制台分离,而不是删除控制台。有关此行为的详细信息,请单击此处

因此,我尝试跟踪窗口句柄,然后使用CloseHandle()进行关闭。

function Get_Console_Handle
  return System.Address
  is
  use System;
  STD_INPUT_HANDLE  : constant Interfaces.C.Unsigned_Long := -10;
  STD_OUTPUT_HANDLE : constant Interfaces.C.Unsigned_Long := -11;
  STD_ERROR_HANDLE  : constant Interfaces.C.Unsigned_Long := -12;

  type Shared_Library_Function
    is access function(
      Standard_Handle : Interfaces.C.Unsigned_Long)
      return System.Address;
    pragma Convention(Stdcall, Shared_Library_Function);
  function To_Shared_Library_Function
    is new Ada.Unchecked_Conversion(System.Address, Shared_Library_Function);

  function Load_Library(
    File_Name : in Interfaces.C.Char_Array)
    return System.Address;
  pragma Import(Stdcall, Load_Library, "LoadLibrary", "_LoadLibraryA@4"); 

  function Get_Function_Address(
    Module        : in System.Address;
    Function_Name : in Char_Array)
    return System.Address;
  pragma Import(stdcall, Get_Function_Address, "GetProcAddress", "_GetProcAddress@8");

  Library : System.Address := Load_Library(To_C("kernel32.dll"));
  Pointer : System.Address := Get_Function_Address(Library, To_C("GetStdHandle"));
  begin
    if Pointer /= System.Null_Address then
      return To_Shared_Library_Function(Pointer).all(STD_OUTPUT_HANDLE);
    else
      return System.Null_Address;
    end if;
  end Get_Console_Handle;

--winbase.CloseHandle
  function Close_Handle(
    Object_Handle : in System.Address)
    return Interfaces.C.Int;
  pragma Import(Stdcall, "CloseHandle");

这个也没做任何事情。我猜 Get_Console_Handle 返回了一个错误的句柄。

我的问题是,是否有 Gnat 命令行选项可以不创建控制台窗口,或者关闭控制台窗口的方法?


1
在Windows上,-mwindows是否与GNAT兼容?对于*nix,您不需要任何东西,不应该出现控制台窗口。 - Rommudoh
@oenone 我在man页面中没有看到“-mwindows”,但我会尝试一下。在Windows上,GNAT会自动将控制台附加到应用程序上。 - Ignoreme
@oenone,这个方法可行,如果你把它作为答案发表,我会点赞并接受它。 - Ignoreme
完成。这不是GNAT在做,而是GCC。 - Rommudoh
1个回答

3

控制台窗口实际上并不是GNAT特定的,而是在Windows上更多地使用GCC。

您可以使用-Wl,-subsystem,windows-mwindows使其不弹出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接