4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Delphi】フォームのない常駐アプリケーションを作る

4
Last updated at Posted at 2026-04-19

はじめに

たまには小さな EXE を作りたい時がありますよね?「フォームは要らない、でもコンソールアプリケーションじゃないのがいい」みたいなの。

コード

こんな感じでしょうか?

formless.dpr
program FormLess;

{.$DEFINE USE_COM}

uses
  Winapi.Windows, Winapi.Messages{$IFDEF USE_COM}, Winapi.ActiveX{$ENDIF};

{$R *.res}

var
  Msg: TMsg;
  Handles: array [0..0] of THandle = (0);

  // 起動時に一度だけ実行する処理
  procedure Setup;
  begin
    // put your setup code here, to run once:
    
  end; { Setup }

  // 毎ループで実行する処理
  function Loop: Boolean;
  begin
    // put your main code here, to run repeatedly:

    Result := True;  // False を返せば終了
  end; { Loop }

begin
  {$IFDEF USE_COM}
  CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
  {$ENDIF}
  try
    Setup;
    repeat
      case MsgWaitForMultipleObjects(0, Handles, False, INFINITE, QS_ALLINPUT) of
        WAIT_OBJECT_0:
          while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
          begin
            if Msg.Message = WM_QUIT then
              Exit;
            TranslateMessage(Msg);
            DispatchMessage(Msg);
          end;
      end;
    until not Loop;
  finally
    {$IFDEF USE_COM}
    CoUninitialize;
    {$ENDIF}
  end;
end.

構造的には Arduino っぽくしてあります。

image.png

COM を使う場合には USE_COM を有効にしてください。具体的には {.$DEFINE USE_COM} のドットを抜いて {$DEFINE USE_COM} にしてださい。

See also:

これと何が違うの?

多分、素朴な疑問として「コレ (単純ループ版)と何が違うの?」というのがあるかと思います。

FormLess2.dpr
program FormLess2;

{$R *.res}

  // 起動時に一度だけ実行する処理
  procedure Setup;
  begin
    // put your setup code here, to run once:

  end; { Setup }

  // 毎ループで実行する処理
  function Loop: Boolean;
  begin
    // put your main code here, to run repeatedly:

    Result := True;  // False を返せば終了
  end; { Loop }

begin
  Setup;
  repeat
  until not Loop;
end.

違いは 2つのプログラムを同時に実行させると解ります。

image.png

前者はメッセージループがあるので、処理内容が空なら CPU を殆ど使いません。後者は単なる無限ループなので、メッセージを利用する機構がすべて動作せず、処理内容が空でも CPU を使ってしまいます。

フォームのあるアプリケーションでは Application.Run がメッセージループの本体で、メインフォームが閉じられるとメッセージループを抜ける (=アプリケーションが終了する) ようになっています。

*.dpr
  ...

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

See also:

では、これとは何が違うの?

毎ループで実行する処理の部分をスレッドにしてみました。

program FormLess3;

{.$DEFINE USE_COM}

uses
  Winapi.Windows, Winapi.Messages{$IFDEF USE_COM}, Winapi.ActiveX{$ENDIF},
  System.SysUtils, System.Classes;

{$R *.res}

type
  TWorkerThread = class(TThread)
  protected
    procedure Execute; override;
  end;

var
  Msg: TMsg;
  Handles: array [0..0] of THandle;

  // 起動時に一度だけ実行する処理
  procedure Setup;
  begin
     // put your setup code here, to run once:

  end; { Setup }

  // 毎ループで実行する処理
  procedure TWorkerThread.Execute;
  begin
    try
      while not Terminated do
      begin
        // put your main code here, to run repeatedly:

        // Terminate() を呼べば終了
      end;
    except
      Terminate;
    end;
  end; { Execute }

begin
  {$IFDEF USE_COM}
  CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
  {$ENDIF}
  try
    Setup;
    var wt := TWorkerThread.Create(False);
    Handles[0] := wt.Handle;
    while True do
      case MsgWaitForMultipleObjects(1, Handles, False, INFINITE, QS_ALLINPUT) of
        WAIT_OBJECT_0:
          begin
            wt.Free;
            Exit;
          end;
        WAIT_OBJECT_0 + 1:
          while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do
          begin
            if Msg.Message = WM_QUIT then
              Exit;
            TranslateMessage(Msg);
            DispatchMessage(Msg);
          end;
      end;
  finally
    {$IFDEF USE_COM}
    CoUninitialize;
    {$ENDIF}
  end;
end.

毎ループで実行する処理の部分をスレッド化しても無意味では?と思えるかもしれませんが、このやり方だとメッセージへの応答性が向上します。

  • Windows の終了を阻害しない
  • アプリケーションが 応答なし にならない

言うまでもなく、メインスレッドをメッセージループ専用に使っているからです。

See also:

おわりに

常駐プログラムなら、本当は普通に作って TTrayIcon 貼ってタスクトレイから設定できるようにするのがセオリーかとは思いますが、本当に何も要らなくて裏で延々と動作してくれてればいい (何かの機器の状態をポーリングするとか)、みたいなのがたまに必要になりますよね。

 ...ならん?

See also:

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?