†Sibylのお部屋†
作成開始日 2022.02.02
最終更新日 2022.02.02
以下のサンプルコードは、OS/2 APIリファレンスなどに掲載されている「システムメニューの[クローズ]項目を無効化する」というもの。ウィンドウ左上のアイコンをクリックすると出てくるアレである。そのコードに若干手を入れて、理解しやすくした。なお、ここでは、プロジェクトに「Form2」という2番目のフォームを追加していることが前提。まあ、Form1(メインのフォーム)を処理対象にしても良いが、メインウィンドウがクローズできなくなるのも面倒臭いので。
Var hwndWindow : HWND; hwndSysMenu: HWND; Begin Form2.show; // ウィンドウを表示 // ウィンドウのハンドル取得 hwndWindow:=Form2.Frame.Handle; // 例によってフレームのハンドル // システムメニューのハンドル取得 hwndSysMenu := WinWindowFromID(hwndWindow, FID_SYSMENU); // システムメニューの[クローズ]を無効化 WinSendMsg(hwndSysMenu, // @送り先 MM_SETITEMATTR, // Aメッセージ(大雑把な内容) MPFROM2SHORT(SC_CLOSE, 1), // Bパラメータ1(処理の対象) MPFROM2SHORT(MIA_DISABLED, MIA_DISABLED)); // Cパラメータ2(処理の内容) End;「Form2.Show;」と「hwndWindos:=...」に関しては別項で述べたので、ここでは説明を割愛。
次の「WinWindowFrom」関数は、指定されたウィンドウ内の、指定されたパーツ(item)のハンドルを取得する関数。最初の引数(hwndWindow)がウィンドウを指定するハンドルで、2番目の引数(FID_SYSMENU)が取得するパーツの識別子。「FID_SYSMENU」は「システムメニュー」を意味する。
この他に、「FID_TITLEBAR」(タイトルバー)、「FID_MINMAX」(最小化・最大化ボタン)などが指定できる。「FID_」は恐らく「frame-control identifiers」から名付けられた物と思われる。その他のパーツの指定に関しては「Presentation Manager Programming Guide and Ref vol.4」(pm4.inf)を参照。
@は上記の手順で取得したシステムメニューのハンドル。
Aは処理内容を示すメッセージで、「MM_SETITEMATTR」は「項目の属性の設定」を意味する。また、「MM_QUERYITEMATTR」(項目の属性の取得)、「MM_SETITEM」(項目そのものの設定)、「MM_REMOVEITEM」(項目の削除)などが設定できる。使用可能なメッセージの一覧は「Presentation Manager Programming Guide & Ref Vol.3」(pm3.inf)を参照。
Bはメッセージに付随するパラメータで、これはメッセージによって指定する内容が異なる。ここでは、Aで「項目属性を変更する」と指定したので、このBで「どのパーツ(item)」に対して、次のCで「どんな属性」を設定するのかを指定する。
その前に、パラメータの前に付いている「MPFROM2SHORT」は何ぞや?と言う事になるのだが、これは2つのSHORT型変数を1つのMPARAM型変数にまとめるもの。「2つのSHORT型から(FROM)メッセージパラメータ型(MP)を作成する」ので「MPFROM2SHORT」関数。前述の通り、1つのパラメータを上下2バイトずつに分けて、2つの情報を送るために使用する。なお、MPARAM型=ULONG型(4byte)、SHORT型(正確にはUSHORT型)=WORD型(2byte)。
では、B第1パラメータの内容を見ると;
上位2バイト | 処理の対象 | ここでは「SC_CLOSE」(クローズ項目)を指定 |
下位2バイト | サブメニュー に関する設定 | 「1」ならば当該項目をサブメニューからも探す、 「0」ならばサブメニューからは探さない |
つまり、「MPFROM2SHORT(SC_CLOSE, 1)」はサブメニューも含めた項目の中から[クローズ]を探して出して処理の対象とする、と言う意味。[クローズ]以外の処理対象には、「SC_SIZE」(サイズ変更)、「SC_MOVE」(移動)などがある。詳しくは「Presentation Manager Programming Guide & Ref vol.5」(pm5.inf)参照。なお、ここでは「SC_」をシステムメニューの項目のように扱っているが、そもそもは「System Command」そのもののことらしい。
Cの第2パラメータは少し判り難い。内容自体は「MIA_DISABLED」=「当該項目の無効化」ではっきりししているのだが、なぜ、同じ内容を二つ並べるのか?「MM_SETITEMATTR」の仕様を見ると、このパラメータは「Attribute mask (USHORT)」と「Attribute data (USHORT)」となっている。後者は処理内容を指すとして、前者の「マスク」とは何か?
それについては何の記述もないけど、察するに、前者と後者をAND演算した結果をパラメータとして使用しているのではないかと…「MIA_DISABLED」と「MIA_DISABLED」をAND演算しても、答えは「MIA_DISABLED」そのものなので、要するに「MIA_DISABLED」と言うこと。
なぜこんな回りくどい事をするのかと言うと、これまた推察にすぎないが、おそらく、命令の一部を無効化する必要がある時のためだろう。「MIA_DISABLE」などの定数は、複数の処理を指定する一連のビット列として処理される(と思う)が、その中で「このビットの処理だけはしないでね」みたいに、そもそもの定数の処理内容にバリエーションを持たせるのが目的(だと思う)。ゆえに、特段の理由がなければ、同じ定数を二つ並べる、でいいんじゃないかと思う。
なお、「MIA」は「Menu Item Attributes」のことで、「MIA_DISABLE」の他には、「MIA_HILITED」(項目選択表示)、「MIA_CHECKED」(チェックマーク付き)などがある。詳しくは「Presentation Manager Programming Guide & Ref vol.3」(pm3.inf)参照。
ソースの変更は簡単。[サイズ変更]を無効化したければ、「SC_CLOSE」を「SC_SIZE」とすれば良いだけだ。が、これを実行すると……あれ?[サイズ変更]が無効化されていない!じゃあ、[移動]はと「SC_MOVE」に変更しても、やっぱりダメ!コンパイルが通るからミスタイプ等があるわけじゃない。しかも、戻り値を確認すると、「SC_CLOSE」のときと同じく「1」が帰って来る。つまり、メッセージの送付は成功しているのである。オイオイ…
これって、つまり「お手紙は承った、しかし乍ら貴殿の御要望に沿いかねる」ってハナシなわけだ。具体的に何でこんなことになるのかは判らないが;
@他の設定と矛盾が生じたため設定そのものが反映されなかった、
A設定は反映されたが直後に元の設定に書き戻された、
のいずれかだろう。ここがAPI関数、就中WinSendMsgの厄介なところ。メッセージの送信に成功しても、期待通りの結果が得られるとは限らないのである。そして、なんでダメなのかの理由が、素人には全くわからない。
では、次はメッセージ自体を変更してみよう。今度はアイテムの属性変更(MM_SETITEMATTR)ではなく、アイテムの削除(MM_REMOVEITEM)を指定してみる。削除対象は[サイズ変更](SC_SIZE)とする。なお、このメッセージでは第2パラメータは不要のため「0」を指定する。
rc:=WinSendMsg(hwndSysMenu, // @送り先 MM_REMOVEITEM, // A処理内容は項目削除 MPFROM2SHORT(SC_SIZE, 1), // B処理対象は[サイズ変更] 0); // C第2パラメータは不要これはどうなるかと言うと、ちゃんとシステムメニューから[サイズ変更]が削除されるのであった。こんな感じで、我等シロウトとしては、試行錯誤しながら使っていくしかないのであった。