mieki256's diary



2026/01/27(火) [n年前の日記]

#1 [delphi] Delphi 12 CEのブラシデザイナが表示できない

Windows11 x64 25H2 + Delphi 12.1 CE (Community Edition) 上で FMX (FireMonkey) の使い方を勉強していたけれど、ブラシデザイナ? なる機能が呼び出せなくて困ってしまった。一応、ソースコードにガリガリと処理を書いても同じことはできるらしいけど…。

Delphi でGUIアプリを作る場合、昔から存在してる VCLライブラリを使う方法と、OpenGLやDirectXで描画する FMX (FireMonkey)ライブラリを使う方法があるそうで、後者が気になったので試してたのけど…。

本来であれば、FMX のプロジェクトを新規作成して、TRectangle を置いて、Fill プロパティをダブルクリックするとブラシデザイナが起動するらしいのだけど…。

「0による浮動小数点数除算」というエラーメッセージが表示されて、それっきり。エラーダイアログが出るだけで、IDEは落ちずに済んでるけれど…。新規プロジェクトを作成して試しても同じエラーが出るので、プロジェクトの内容が悪さをしているわけではなさそう。

ググってみても対策が分からない…。そもそも、そういう不具合事例すら見かけない。Delphiユーザが少ないことに加えて FMX を使っている人は更に少ないということだろうか。それとも自分の環境がおかしいだけだろうか…。

仮にバグだとしても修正される見込みは無いだろうな…。現行版は Delphi 13 で、1つ前のバージョンを条件付きで無償利用できることにしているのが Community Edition らしいし。おそらく体験版のような位置づけだろうから、不具合が見つかっても放置だろう…。一応、12.2、12.3 の修正内容も眺めてみたけど、修正された的な記述も無く。バグ報告がどこに集まってるのかも分からない。たぶんログインしないと見れないような、比較的クローズドな場所に集まってるんだろう…。

Delphi は本来20万円以上する開発環境だけど、何十万も払ってこういうバグに遭遇したら萎えそうな予感…。

Lazarus に移行できるならしたほうがいいのかな。あっちはオープンソースだし…。

#2 [lazarus] Lazarusでビルド後にコマンドを実行

Windows11 x64 25H2 + Lazarus 4.4 で、ビルド後にコマンドを実行したい。.exe を .scr にリネームコピーしたい。

Delphi はビルド後に指定したコマンドを実行できるけど、Lazarus も使えるのだろうか? 調べてみたら、使えそう。


これでなんとかなりそう。

使えるマクロ名が分からない :

コマンドを記述する際に使えるマクロ(?)名が分からない…。一応、以下のマクロは使えそうだと分かったけれど…。
  • $(TargetFile) : 生成される .exe のフルパス。
  • $(ProjPath) : プロジェクトフォルダのフルパス。最後に区切り文字 "\" が含まれている。

しかし、拡張子を除いた生成ファイル名のマクロがあるんだか、ないんだか…。

AIに尋ねたら、「いっそファイル名を直接書いちまえよ。それなら間違いないぞ」と言ってきた。それはまあ、たしかに…。以下にしてみたら一応目的は果たせた。

cmd /C copy /Y "$(TargetFile)" "$(ProjPath)sslazarus1.scr"


_IDE Macros in paths and filenames - Free Pascal wiki

む? もしかして、$NameOnly() を使えば拡張子を除いたファイル名だけ取り出せないか…?

cmd /C copy /Y "$(TargetFile)" "$(ProjPath)$NameOnly($(TargetFile)).scr"

これで実現できたかも。

文字化けについて :

IDEの下のほうにメッセージが表示されているけれど、右クリックして「プロジェクト次の後にコマンドを実行:について」を選ぶと、実際にどんなコマンドが実行されたのか確認できる。もし、「(不明なマクロ)」という記述が見えた場合はマクロ名の指定で失敗してる。

文字化けしてる感じのメッセージも表示されているけれど…。たぶん copyコマンドが出力しているメッセージと、出力ウインドウの文字コードが違うのだろう…。

AIに尋ねてみたら「PowerShellを使えばメッセージは出ないで」と言ってきた。DOS窓で以下を打ってみたら、たしかに処理はされつつメッセージも出ないように見える。

powershell -command "Copy-Item 'sslazarus1.exe' 'sslazarus1.scr' -Force"

Lazarus上で指定するなら以下になるのかな…。

powershell -command "Copy-Item '$(TargetFile)' '$(ProjPath)$NameOnly($(TargetFile)).scr' -Force"

これでも一応動作しているように見える。

#3 [lazarus] Lazarusでスクリーンセーバを作ろうとしてハマった

Windows11 x64 25H2 + Lazarus 4.4 でWindows用のスクリーンセーバを作ろうとしたけど、かなりハマった…。

Delphi と似たノリで作れるかなと試していたけれど、全画面表示モード、設定画面モードについては似た感じで作れたものの、プレビュー画面モードで躓いた。

Windowsから与えられたウインドウハンドルを、フォームの親ウインドウを指定するプロパティ、ParentWindow に代入すれば済むだろう、Delphi ならそれだけで上手く行ったし…。

しかし試してみたら、プレビュー画面モードで起動したプロセスがいつまで経っても終了してくれない。「スクリーンセーバーの変更」ウインドウでリストを切り替えるたびに、プロセスが次々に発生して、そのまま残り続ける…。大量のプロセスがずっと残ったままになる…。

AI君に対策を尋ねてみたけれど、どれもなかなか上手く行かなくて…。


A. 親ウインドウの存在をチェックする方法は、「スクリーンセーバの変更」ウインドウを閉じた時しか効かなかった。「スクリーンセーバーの変更」ウインドウが画面に表示されてる間は、大量のプロセスが残り続けてしまう。どうやら件のウインドウが表示されてる間、親ウインドウになるべきウインドウは、ずっと同じ状態で存在しているのだろう…。

B. WndProc()のオーバーライドも、「スクリーンセーバーの変更」ウインドウを閉じた時しか効かず…。

C. 持っている親ウインドウハンドルと、与えられたウインドウハンドルが違っているかチェックする方法は、フォームが表示された直後に終了してしまう。何故。

D. 自身が非表示になったら終了する方法を試したら、ようやくプロセスがその都度終了してくれた。この方法で大丈夫なのか分からんけど…。でも、プロセスが大量に残り続けるよりはいいだろう…。

Windowsの「スクリーンセーバーの変更」ウインドウは、一体何を子ウインドウに送ることで子ウインドウを消滅させているのだろうか…。

ソース :

一応、プレビュー画面モード部分のソースを貼っておく。

_previewformunit.pas
unit PreviewFormUnit;

{$mode ObjFPC}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, LCLType,
  StdCtrls, LCLIntf, ExtCtrls,
  Windows;

type

  { TPreviewForm }

  TPreviewForm = class(TForm)
    Label1: TLabel;
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: word; Shift: TShiftState);
    procedure Timer1Timer(Sender: TObject);
  private
    FParentHWND: HWND;
  protected
    procedure WndProc(var Message: TMessage); override;
  public
    procedure EmbedIntoParent(pHWND: HWND);

  end;

var
  PreviewForm: TPreviewForm;

implementation

{$R *.lfm}

{ TPreviewForm }

procedure TPreviewForm.FormCreate(Sender: TObject);
begin
  //FParentHWND := 0;
  BorderStyle := bsNone;
  Left := 0;
  Top := 0;
  Width := 152;
  Height := 112;

  Label1.Left := (ClientWidth - Label1.Width) div 2;
  Label1.Top := (ClientHeight - Label1.Height) div 2;
  Label1.Font.Color := clBlue;
end;

// 親ウインドウを指定
procedure TPreviewForm.EmbedIntoParent(pHWND: HWND);
var
  r: TRect;
begin
  FParentHWND := pHWND;

  if pHWND <> 0 then
  begin
    ParentWindow := pHWND;
    Windows.SetParent(self.Handle, pHWND);

    SetWindowLong(Self.Handle, GWL_STYLE, GetWindowLong(self.Handle, GWL_STYLE) or
      WS_CHILD);

    Windows.GetClientRect(pHWND, r);
    MoveWindow(Self.Handle, 0, 0, r.Right - r.Left, r.Bottom - r.Top, True);
    Visible := True;
  end;
end;

procedure TPreviewForm.Timer1Timer(Sender: TObject);
begin
  // 一定時間毎に自身が消えるべきかチェックする
  //Windows.Beep(440, 100);
  if (FParentHWND <> 0) and (not Windows.IsWindow(FParentHWND)) then
  begin
    // 親ウインドウが存在していないので終了
    //Windows.Beep(1000, 100);
    Application.Terminate;
  end
  else if not Windows.IsWindowVisible(self.Handle) then
  begin
    // 自分が非表示にされているなら終了
    //Windows.Beep(1000, 1000);
    Application.Terminate;
  end;
end;

procedure TPreviewForm.WndProc(var Message: TMessage);
begin
  //Windowsから閉じろとメッセージが来ているなら終了
  case Message.Msg of
    WM_CLOSE, WM_DESTROY, WM_NCDESTROY:
    begin
      //Windows.Beep(2000, 300);
      Application.Terminate;
    end;
  end;

  inherited WndProc(Message);
end;

procedure TPreviewForm.FormKeyDown(Sender: TObject; var Key: word; Shift: TShiftState);
begin
  if FParentHWND = 0 then
  begin
    // 開発時用。ESCキーで終了
    if Key = VK_ESCAPE then
      Application.Terminate;
  end;
end;

//initialization
//  RegisterClass(TPreviewForm);

end.

_sslazarus1.lpr
program sslazarus1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  {$IFDEF HASAMIGA}
  athreads,
  {$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms,
  LCLIntf,
  LCLType,
  Windows,
  SysUtils,
  FullScrFormUnit,
  ConfigFormUnit,
  PreviewFormUnit { you can add units after this };

  {$R *.res}

var
  arg: string;
  phwnd: HWND;
  hMutex: THandle;

const
  MUTEX_NAME: string = 'ScreenSaverLazarus1Mutex8686';

begin
  RequireDerivedFormResource := True;
  Application.Scaled := True;
  {$PUSH}
  {$WARN 5044 OFF}
  //Application.MainFormOnTaskbar := True;
  Application.MainFormOnTaskbar := False;
  {$POP}
  Application.Initialize;

  if ParamCount >= 1 then
    arg := LowerCase(Copy(ParamStr(1), 1, 2))
  else
    arg := '';

  if arg = '/s' then
  begin
    // Fullscreen mode
    hMutex := CreateMutex(nil, False, PChar(MUTEX_NAME));
    if (hMutex = 0) or (GetLastError = ERROR_ALREADY_EXISTS) then
    begin
      if hMutex <> 0 then
        CloseHandle(hMutex);

      Exit;
    end;

    try
      Application.CreateForm(TFullScreenForm, FullScreenForm);
      Application.Run;
    finally
      if hMutex <> 0 then
        CloseHandle(hMutex);
    end;
  end
  else if arg = '/c' then
  begin
    // Config mode
    Application.CreateForm(TConfigForm, ConfigForm);
    Application.Run;
    Exit;
  end
  else if arg = '/p' then
  begin
    // Preview mode
    if ParamCount >= 2 then
      phwnd := HWND(StrToInt64Def(ParamStr(2), 0))
    else
      phwnd := 0;

    Application.CreateForm(TPreviewForm, PreviewForm);
    if phwnd <> 0 then
      PreviewForm.EmbedIntoParent(phwnd);

    Application.Run;
  end
  else
  begin
    // Config mode
    Application.CreateForm(TConfigForm, ConfigForm);
    Application.Run;
  end;

end.

余談。プロセスの確認 :

プロセスが残り続けているかどうかは、System Explorer 7.1.0.5359 を使ってチェックした。

_System Explorer Portable | PortableApps.com

右上のフィルタ入力欄(?)に文字列を打ち込めば、その文字列を含んだ名前のプロセスがリストアップされる。

#4 [nitijyou] オノヤの方が来訪

ここ1週間ばかり、トイレの壁の後ろから出ているパイプから、水がポタポタと出続けている。下にバケツを置いて水を溜めていたけれど、1日でバケツから溢れるほどの量…。お袋さんがオノヤに電話で連絡したら、業者(?)の方が来訪して見てくれることになった。今日の夕方、15:45-16:20頃まで説明や調整をしてくれた。 *1

簡易水洗トイレの上のタンクから水が溢れそうになると後ろのパイプから出てくるということで、汚水の類ではないらしい。いや、手洗いをした水が上のタンクに入るから、一応汚水なのか…? 何にせよ、そのパイプから水が出てくる状況は全然アリらしい。にしても、ずっと出続けてるのはおかしい…。

業者の方が、上のタンクの中の、フロートの位置を数段階下げてくれた。これでタンク内に溜まる水の量が少なくなって漏れ出ることも少なくなる…のかな? そういうロジックでいいのか? 本当に? ちょっと自信が無い。何にしても、これで漏れ出る量が変化する可能性はあるだろう…。

タンクの設計がよろしくない :

フロートの調整作業がとにかく大変そうだった。手洗い用の水が出るところが邪魔になって蓋を外せず、斜めにして仮置きして作業するから重い蓋が落ちそうで危険極まりない。

水が出るところをシャワーヘッドのように回して外せたら蓋をスポンと抜いて作業できそうなのに…。INAXの設計はダメ過ぎないか…。いや、コストダウンでこうしたのかな…。あるいは水が流れる部分だから部品点数を少なめにしないと危険なのだろうか。だとしても、あの設計はどうかと思う。現場の苦労を無駄に増やす設計というか…。もうちょっとどうにかならなかったのか…。

*1: 本当は先週末に来てくれるという話だったのだけど…。「あそこは色々面倒臭いから行きたくねえ」みたいな扱いになってるのかな…。

以上、1 日分です。

過去ログ表示

Prev - 2026/01 - Next
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project