启动终端程序,但在终端关闭后继续运行 - Lazarus 或 Delphi

Posted

技术标签:

【中文标题】启动终端程序,但在终端关闭后继续运行 - Lazarus 或 Delphi【英文标题】:Launch a terminal program but have it continue to run once terminal is closed - Lazarus or Delphi 【发布时间】:2015-02-02 16:52:37 【问题描述】:

序言:我在 Windows 7 上使用 Lazarus 1.2.6 和 Freepascal 2.6.4,我的解决方案必须基于此 - 而不是 C 或 C++。不过,如果存在类似的东西,我可以使用 Delphi。

问题:我希望创建一个小程序,理想情况下是从命令行启动,然后只是在后台运行,而无需显式打开控制台应用程序。

我正在努力研究如何最好地实现它。

我读过 this link 和 this link 和 this C based example 和 this Linux example 但正如一位用户指出的那样“如果你不想要控制台应用程序,就不要制作”,这就引出了一个问题:什么还有其他方法吗?如果您不想要 GUI,也不想要控制台,我认为还有另一种方法可以创建静默程序,然后启动它,然后让它在后台运行?大概是作为一种服务或类似的东西?

或者,我想到的另一种方法是创建一个包含我的程序函数的库(当然在编译时会生成一个 DLL),在 DLL 的末尾导出这些函数,然后从单独的终端调用它们我假设我可以关闭但从 DLL 调用的函数可能会继续运行的应用程序?换句话说 - 两个程序 - 一个终端程序启动另一个不可见的程序,然后关闭启动程序?这是可能的还是推荐的?

【问题讨论】:

如果您不需要控制台或 GUI 应用程序,解决方案仍然是制作一个 GUI 应用程序,但不显示一个(例如托盘图标的工作方式)。这些是后台进程。或者,您可以编写一个 Windows 服务。 我不知道你是否为此投了反对票,但如果你投了反对票,我可以这样说:我很清楚我正在使用 Windows 并开发一个 Windows 应用程序。我没有提及为其他平台创建它。 “Linux 示例”只是另一个涵盖相同主题的主题,因此我将其链接起来以对其他读者有所帮助。当人们出于对某些事情不太了解而对有时提出的问题投反对票时,我会感到厌烦,然后他们因为不准确而被投反对票。 请原谅我没有完全精通现有的所有各种编程。 @Gizmo_the_Great,你可能也想摆脱讽刺。如果您进行一些研究并对您感兴趣的问题了解最少,那么没有人会拒绝您。 【参考方案1】:

I've written about this topic before,但不是专门针对 Delphi 或 Free Pascal。

使用$APPTYPE GUI 指令告诉编译器生成GUI 应用程序 而不是控制台应用程序。您通常会将它放在主项目文件的顶部附近,program 语句所在的位置。当您使用该指令时,程序既不会继承其父级的控制台,也不会创建新的控制台。如果您实际上并不想要 GUI,则不要显示任何窗口;如果您有控制台应用程序,操作系统会自动为您创建控制台,因为"consoleness" is a property of the EXE file。

使用单独的程序和 DLL 不会产生您想要的效果。如您所知,函数会阻塞调用者,直到它们返回。因此,当宿主程序调用你的 DLL 函数时,它会一直等到它返回才退出。 DLL 不是一个单独的程序;它不能没有它的主机运行。 (使用单独的线程也不行,因为当主线程终止程序时,它会破坏所有其他线程,无论它们是否完成。)

【讨论】:

链接器,而不是编译器。值得一提的是,Delphi 中的这种行为还由“链接器选项”中的“生成控制台应用程序”或-cc 命令行开关控制。 -1 : 你是否回复“我希望创建一个小程序,理想情况下是从命令行启动,然后只在后台运行而无需显式打开控制台应用程序“?你给这个问题一个简单的解决方案吗? 我的答案一个简单的解决方案,@Bbaz。这是一个完整的程序:program Foo; $APPTYPE GUI begin end. 它没有控制台,也不会阻止命令提示符接受进一步的命令。从父进程的角度来看,它将在“后台”运行。【参考方案2】:

使用 Lazarus 非常简单。只需编写小型启动器程序:

program project1;

uses
    Process;

var
    p: TProcess;
begin
    p := TProcess.Create(nil);
    try
        p.ShowWindow := swoHIDE; // To hide your console app
        //p.ShowWindow := swoShowNormal; // To show your console app
        p.Options := [poNewConsole];
        p.CommandLine := 'cmd'; // Change to your app name
        p.Execute;
        Writeln('Programm launched.');
    finally
        p.Free;
    end;
end.  

其实不是Lazarus,而是纯FPC程序。

【讨论】:

【参考方案3】:

如果您不想要控制台应用程序,请不要制作。

这听起来像是我可能会说的话!是的,这就是处理这个问题的方法。当一个控制台应用程序启动另一个控制台应用程序时,父进程会阻塞,直到子进程完成。您可以安排子进程脱离其父控制台,但最终只会得到两个控制台。

您真正想做的是创建一个针对 GUI 子系统而不是控制台子系统的进程。换句话说,你不想要一个控制台应用程序,所以不要做一个。改为制作一个 GUI 应用程序。

现在,GUI 应用程序并不意味着您必须显示 GUI。这样做没有任何内疚。您有一个要脱离的进程,在后台执行,而不是附加到父控制台。这是一个针对 GUI 子系统但不显示任何 GUI 的应用程序。

例如,这个程序以 GUI 子系统为目标,但没有显示 GUI。它相当没用,因为它无限期地阻塞。但是,您可以将其替换为您的后台任务。

program project1;
$apptype gui
uses
  windows;
begin
  Sleep(INFINITE);
end.

【讨论】:

谢谢大卫。是的-我认为这是您的报价!使用 Lazarus,你知道如何“创建一个以 GUI 子系统为目标但不显示任何 GUI 的应用程序”吗?创建新项目时,唯一的选项是“应用程序”(传统 GUI)、“程序”(基本终端程序)、“控制台程序”(具有增强功能的终端程序)、“库”(DLL)、“ InstantFPC 程序,最后是 FPC 单元。使用 Lazarus 创建传统应用程序时,顶部有一个模式,上面写着“$mode objfpc$H+”, 'Application'(传统 GUI) 似乎是选择。然后由您决定禁止 IDE 从其应用模板创建的任何 GUI。 -1,因为您还没有回答 Q。OP 希望明确回答明确的 Q,而不是评论说“不要这样做不要那样做”。 @BBaz 我认为从您的 cmets 到您的回答很清楚,您不了解该主题领域。具体来说,您不了解 PE 子系统。因此,您无法判断这里写的任何内容。 -1 : 你是否回复“我希望创建一个小程序,理想情况下是从命令行启动,然后只在后台运行而无需显式打开控制台应用程序“?你给这个问题一个简单的解决方案吗?我有一件特别的事情要给你大卫:github.com/BBasile/enumset【参考方案4】:

假设你只是在Windows下使用这个程序,你可以直接调用FreeConsole from the Windows API:

FreeConsole 功能

从控制台分离调用进程。

例如这个简单的程序:

program project1;
uses
  sysutils, windows;
begin
  FreeConsole;
  while(true) do
    sleep(50);
end.

可以从资源管理器或 cmd 启动并无限运行而不显示自己的控制台。从另一个控制台启动时,即使关闭另一个 cmd 实例,它也会继续运行。

【讨论】:

如果您总是放弃控制台,那么制作控制台应用程序是个坏主意。完全没有意义。只需制作一个 GUI 应用程序,然后就没有控制台开始了。 -1 GUI 应用程序会因为 LCL(RTL 也是)初始化而产生大量无用代码:TApplication、TScreen 等在 .text 中创建了数百 kbytes,只有当 GUI 应用程序具有图形用户界面。顺便说一句,您的论点可能会被推翻:如果您不显示表单,则制作 gui 应用程序是个坏主意。完全没有意义。只需制作控制台应用程序,然后就没有要隐藏的 gui。 GUI 应用程序不需要有 GUI。我们在这里讨论的是 PE 子系统。我们不会展示 GUI。在 Delphi 中,这只不过是$APPTYPE GUI。使用 MS 工具时,它是 /SUBSYSTEM:Windows。这些都不会强迫你有任何膨胀。 调用FreeConsole 几乎肯定不是你想要使用的。 I've written about it before. 你提到你可以从命令提示符运行你的程序。您没有提到的是命令提示符会挂起,同时它会继续等待您的程序终止,即使在控制台被释放后也是如此! @Rob 的意思是当你从命令解释器启动这个程序时,命令解释器等待程序返回。它永远不会这样做,因为它永远不会终止。因此,命令解释器变得无用,无限期地阻塞,直到这个进程被杀死。这也杀死了命令解释器。同样,这是展示一些 GoodTrait 枚举的机会。

以上是关于启动终端程序,但在终端关闭后继续运行 - Lazarus 或 Delphi的主要内容,如果未能解决你的问题,请参考以下文章

linux如何设置程序开机启动后台运行?

通过终端启动多个同时连续运行的脚本,这些脚本在终端会话结束后继续运行

[Linux]在终端启动程序关闭终端不退出的方法

linux中nohup 与 & 的区别

Ubuntu 在终端关闭情况下仍然运行进程

如何在 macOS 上通过命令隐藏终端窗口