LoginSignup
8
6

More than 1 year has passed since last update.

【Delphi】使い捨て (或いは検証用) アプリケーションの内容を確認できるようにする

Last updated at Posted at 2020-04-07

はじめに

Delphi で使い捨て用のアプリを書くことがあります。多くはコンソールアプリケーションで、一時的に何かに組み込んで使う事もあります。Qiita 用の検証コードもコンソールアプリケーションで作ることが多いです。

割と雑に書かれたコードなので、実行可能ファイルをどこか別の場所に置いたまま時間が経過すると「あれ?これ何のために作ったんだっけ?」ってなります。ファイル名もデフォルトの Project1.exe とかなので判別できない事もあります。

気を利かせて HogeHoge.exe ってリネームしてあったとしても、元々のプロジェクトファイルが Project1.dproj のようにデフォルトのままだと、「あれ?これどのプロジェクトから作ったんだっけ?」となります。

...なりますよね?

アプリケーションの内容確認

スクリプト言語なら、そのスクリプトをテキストエディタで開けばいい事なのですが、コンパイラ型言語はソースファイルと実行可能ファイルが別々に存在するため ソースコードを紛失する という事態が発生します。

先述のように実行可能ファイルの名前を変更したために、プロジェクトファイル名と一致しなくなる事もあります 1

検証用アプリケーションだと、同じプロジェクトファイルを使いまわす事があるため、異なる挙動をする Project1.exe が生成され、

  • Project1.exe
  • _Project1.exe
  • __Project1.exe
  • Project1_new.exe
  • Project1_old.exe
  • Project1_bak.exe
  • Project1_test.exe

というファイルが散らばることになります。Delphi IDE ではソースコードの履歴を管理できるのですが、image.png
実行可能ファイルがどのリビジョンで作られたものなのかが判断できないため、実行するのに危険が伴う事もあります。

解決法?

「バージョン管理に EXE も突っ込む」
「必ずプロジェクトファイルをコピーして使う」
「バージョンリソースに情報を入力する」

...使い捨て (或いは検証用) で"ない"アプリケーションならこれでいいのでしょうけれど。

シンプルな解決法

例えば、次のような FizzBuzz アプリケーションを作ったとします。
image.png

Project1.dpr
program Project1;

{$APPTYPE CONSOLE}

begin
  for var i := 1 to 100 do
    begin
      if ((i mod 3) +  (i mod 5)) = 0 then
        Writeln('Fizz Buzz')
      else if (i mod 3) = 0 then
        Writeln('Fizz')
      else if (i mod 5) = 0 then
        Writeln('Buzz')
      else
        Writeln(i);
    end;
end.

この状態で [プロジェクト | リソースと画像] でリソース管理ダイアログを表示します。
image.png
ここに自分自身 (コンソールアプリケーションの場合 *.dpr) を指定します。リソース識別子は判りやすいように SourceCode にしていますが、デフォルトのままでも構いません。リソースタイプは RCDATA です。

こうしておくと 2 つのメリットが生まれます。

一つは本来の目的である、実行可能ファイルにコンパイル時点のソースコードが埋め込まれる事です。この実行可能ファイルがどういった動作をするのかは、リソースエディタで開けば解ります。ちゃんと保存している限り 2、(リソースファイルの) ソースコードのロジックと実行可能ファイルの挙動は必ず一致します。ファイル名が変更されようが、どこに放置されようが、です。
image.png

もう一つは小さなメリットですが、プロジェクトファイルを間違って閉じてもプロジェクトマネージャからダブルクリックで開けるようになります。
image.png

おわりに

リソースエディタでイチイチ確認するのが面倒なのであれば、次のようなロジックを入れておきましょう。

project1.dpr
program Project1;

{$APPTYPE CONSOLE}

{$R *.dres}

uses                                             // <- 追加
  System.SysUtils, System.Classes, System.Types; // <- 追加

begin
  { 追加: ここから }
  if FindCmdLineSwitch('ShowSource', True) then
    begin
      var RS := TResourceStream.Create(HInstance, 'SOURCECODE', RT_RCDATA); // 第 2 パラメータはリソース識別子
      var SL := TStringList.Create;
      try
        SL.LoadFromStream(RS);
        Writeln(SL.Text);
      finally
        SL.Free;
        RS.Free;
      end;
      Exit;
    end;
  { 追加: ここまで}

  for var i := 1 to 100 do
    begin
      if ((i mod 3) +  (i mod 5)) = 0 then
        Writeln('Fizz Buzz')
      else if (i mod 3) = 0 then
        Writeln('Fizz')
      else if (i mod 5) = 0 then
        Writeln('Buzz')
      else
        Writeln(i);
    end;
end.

普通に実行すると FizzBuzz が表示され、
image.png
コマンドラインパラメータに -ShowSource (または /ShowSource) を指定するとソースコードが表示されます。
image.png
リソースを表示する部分は手続き化して別ユニットにすると -ShowSource した時に読みやすいコードになると思います。

uShowSource.pas
unit uShowSource;

interface

uses
  System.SysUtils, System.Classes, System.Types;

implementation

procedure ShowSource;
begin
  if IsConsole and FindCmdLineSwitch('ShowSource', True) then
    begin
      var RS := TResourceStream.Create(HInstance, 'SOURCECODE', RT_RCDATA);
      var SL := TStringList.Create;
      try
        SL.LoadFromStream(RS);
        Writeln(SL.Text);
      finally
        SL.Free;
        RS.Free;
      end;
      Halt(0);
    end;
end;

Initialization
  ShowSource;
end.

uShowSourceuses に追加するだけなのでお手軽です。
image.png
macOS 用にビルドしてももちろん動作します。
image.png


  1. まぁ、リネームしなくても実行ファイルを別の名前で出力する事はできますが。 

  2. EXE 生成前 (コンパイル前) には〔Ctrl〕+〔S〕で確実にプロジェクトファイルを保存しておく必要があります。 

8
6
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
8
6