Go to Nazona Web Site

謎奈の泉 > Delphi Memo Pad > エラーの話 その1

Memo List content pic
エラーの話 その1
Delphiで共用体
タスクバーボタンを非表示に

関連コンテンツ content pic
ソフトウェア
プログラム掲示板
リンク集

戻る content pic
謎奈の泉 トップページ
エラーの話 その1 index pic
■ 前書き
 私はDelphiをやっているとエラーをよく出します。
 コンパイル・エラーであれば、キャスト・ミスであったりスペル・ミスであったりと、 簡単なバグも多いですが、デバッガの例外は結構ややこしいものです。
 私の場合、TListViewのインデックス・ミス(存在しないインデックスのアイテムにアクセスしようとしたバグ)による デバッガの例外によく出くわしますが、これはデバッガがTListViewのエラーであると告げてくれるので簡単に気づきます。 ですが、これがまったく見当のつかないメッセージだとなかなか気づかないかもしれません。
 今回は私が体験したデバッガの例外のことを書きたいと思います。

■ プログラム例(バグあり)
unit memo0001;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ShellAPI;

type
  TForm1 = class(TForm)
    PopupMenu1: TPopupMenu;
  protected
    procedure WndProc(var Msg: TMessage); override;
  end;

const
  TASKTRAY_MSG = WM_USER + 100;

var
  Form1: TForm1;

implementation
{$R *.dfm}

procedure TForm.WndProc(var Msg: TMessage);
var
  pt: TPoint;
begin
  if Msg.Msg = TASKTRAY_MSG then begin
    case Msg.LParam of
      WM_RBUTTONDOWN: begin
        GetCursorPos(pt);
        SetForegroundWindow(Handle);
        PopupMenu1.Popup(pt.X, pt.Y);
      end;
    end;
  end;
end;

■ 解説
 このプログラムはタスクトレイにアイコンを追加するプログラムの一部分を抜粋したものです。 TASKTRAY_MSG メッセージを定義し、Shell_NotifyIcon API で タスクトレイに登録する処理がこの後に書いてあります。 タスクトレイのアイコンにイベントが起こったときに TASKTRAY_MSG メッセージを Windows が知らせてくるので、 ウィンドウプロシージャーをオーバーライドしてメッセージをチェックしています。

 このプログラムを実行した結果、
プロジェクト Project1.exe が EOSError クラスの例外を生成しました。
'A call to an OS function failed'
プロセスは停止しています。再開するにはステップ実行または実行を選択してください。

 というデバッガの例外が発生しました。もう何が間違っているのかをもう気づいている方もいるかもしれません。

 結論を言ってしまえば、オーバーライドとくれば、ペアになってくるのがinheritedです。 このプログラムにはinheritedがないためにバグがおきたわけです。
 Windowsから送られてくるすべてのメッセージを処理するウィンドウプロシージャをオーバーライドしたのだから、 本物のウィンドウプロシージャーに戻してあげなければ、プログラムが正常に動くはずがなかったのです。
 今思えば、message指令でプロシージャを定義していれば、こんな謎めいたエラーなど起こるはずもなかったのですが……。

■ プログラム例(修正部のみ)
procedure TForm.WndProc(var Msg: TMessage);
var
  pt: TPoint;
begin
  if Msg.Msg = TASKTRAY_MSG then begin
    case Msg.LParam of
      WM_RBUTTONDOWN: begin
        GetCursorPos(pt);
        SetForegroundWindow(Handle);
        PopupMenu1.Popup(pt.X, pt.Y);
      end;
    end;
  end else inherited; // 本物のWndProcに戻してやる;
end;

■ 最後に
 A call to an OS function failed エラーの原因がすべて、 このような状況でしか起こらないということはないと思いますが、 インターネットで探してもなかなか対策が見つからなかった希少価値の高い(?)バグですので、 私の体験が参考になったらと思います。
Write : 2004/12/24

Copyright (c) 2002-2004 謎奈 / うえちょこ All rights reserved.