メニューの高さを取得
メインメニューの高さを知りたいと思いました。
というのもウィンドウの幅を狭めるとメニューが二階建てになったりするので、その状態であるかどうかを判定したかったのです。
参考サイト
GetMenuBarInfo
GetSystemMetrics(SM_CYMENU)でいけると思ったのですが、これは一行の時の高さしか返してくれず、今現在のメニューの高さを返してくれるわけではありませんでした。
さてどうしたものかと思っていたところ、GetMenuBarInfoというAPIがあるのを知りました。
そのものずばりメニューバーの高さが取得できるAPIのようです。
ところがどうやっても、なんとしてもDelphi 6ではエラーが返ってきてしまいます。
色々試行錯誤した結果tagMENUBARINFOを書き換えてみたらいけました。
type
{ Menubar information }
{$EXTERNALSYM PMenuBarInfo}
PMenuBarInfo = ^TMenuBarInfo;
{$EXTERNALSYM tagMENUBARINFO}
tagMENUBARINFO = packed record
cbSize: DWORD;
rcBar: TRect; { rect of bar, popup, item }
hMenu: HMENU; { real menu handle of bar, popup }
hwndMenu: HWND; { hwnd of item submenu if one }
{ fBarFocused:1: BOOL;} { bar, popup has the focus }
{ fFocused:1: BOOL; } { item has the focus }
FocusedBits: BYTE;
end;
{$EXTERNALSYM TMenuBarInfo}
TMenuBarInfo = tagMENUBARINFO;
{$EXTERNALSYM GetMenuBarInfo}
function GetMenuBarInfo(hend: HWND; idObject, idItem: Longint; var pmbi: TMenuBarInfo): BOOL; stdcall;
これがオリジナル。
type
{$EXTERNALSYM tagMENUBARINFO}
tagMENUBARINFO = {packed} record
cbSize: DWORD;
rcBar: TRect; { rect of bar, popup, item }
hMenu: HMENU; { real menu handle of bar, popup }
hwndMenu: HWND; { hwnd of item submenu if one }
// fBarFocused: Boolean;{ bar, popup has the focus }
// fFocused: Boolean;{ item has the focus }
FocusedBits: BYTE;
end;
{$EXTERNALSYM TMenuBarInfo}
TMenuBarInfo = tagMENUBARINFO;
{$EXTERNALSYM PMenuBarInfo}
PMenuBarInfo = ^TMenuBarInfo;
function GetMenuBarInfo(hend: HWND; idObject, idItem: Longint; var pmbi: TMenuBarInfo): BOOL; stdcall external 'user32.dll';
そしてこれが書き換えたものです。
tagMENUBARINFO = packed record の packed を削りました。それだけです。
後は GetMenuBarInfo も再宣言しておきます。
これをしないと
'変数実パラメータと変数仮パラメータとは同一の型でなければなりません'
というエラーが出てコンパイルできません。
そしてこれをGetMenuBarInfoを使うユニットの中に書きます。
Windows.pasに書かれているオリジナルよりもこちらを優先させるわけです。
procedure TForm1.Button1Click(Sender: TObject);
var
lr_Info: TMenuBarInfo;
begin
FillChar(lr_Info, SizeOf(lr_Info), 0);
lr_Info.cbSize := SizeOf(lr_Info);
if (GetMenuBarInfo(Self.Handle, Longint(OBJID_MENU), 0, lr_Info))
then begin
myDebug.gpcDebugAdd(lr_Info.rcBar);
end else begin
Beep;
end;
end;
これでメインメニューのメニューバーのRectが取得できます。
他にも第2引数の値や第3引数の値に応じて色々なメニューの状態やRectが取得できるようです。
ちなみに第2引数の定数はLongintでキャストしないとコンパイルの時に
'定数式が範囲を越えました'
という警告が出ます。
第2引数にOBJID_MENUを指定した場合
GetMenuBarInfo APIの第2引数のidObjectにOBJID_MENUを指定した場合の第3引数のidItemの各値の結果は以下のようになります。
- 第3引数に0を指定
- TMenuBarInfoのrcBarにはメインメニューのメニューバーのRectが返ります。
- TMenuBarInfoのhMenuにはメインメニューのHandleプロパティの値が返ります。
- メインメニューが非表示になっている場合TMenuBarInfoのrcBarにはRect(0, 0,
0, 0)が返ります。
- メインメニューがない場合はエラーになります。
- 第3引数に1以上を指定
第3引数に1以上を指定する場合はメニューバーに並ぶメニューの順番を1から指定します。
例えば「ファイル」「編集」「ウィンドウ」「ヘルプ」という四つのメニューがあるとすると、
- 「ファイル」は 1
- 「編集」は 2
- 「ウィンドウ」は 3
- 「ヘルプ」は 4
になります。
※0ベースのインデックスではないことに注意。
- TMenuBarInfoのrcBarには各メニューにマウスカーソルが乗ったときに色がつく範囲のRectが返ります。
「ファイル」などの、まさにその「ファイル」が占めるRectが返ります。
「ファイル」をクリックするとドロップダウンするメニューのRectではありません。
※細かくいえば色がつく範囲より右と下に1ピクセルずつ広い範囲が返ります。
- TMenuBarInfoのhMenuには、例えば「ファイル」メニューならその「ファイル」メニューのMenuItemのHandleプロパティが返ります。
- TMenuBarInfoのhwndMenuにはドロップダウンしたメニューのウィンドウハンドルが返ります。
このハンドルをGetWindowRectに与えてドロップダウンしたメニューのRectを求めることもできます。
ただしこのウィンドウハンドルはドロップダウンするたびに変わるのとメニューが表示されてからでないと取得できません。
「ファイル」メニューをクリックする前にドロップダウンするメニューのウィンドウハンドルを取得することはできないということです。
第3引数にメニューバーに並んでいるメニューの数以上の数値を指定するとエラーになります。
例えば上記の例だとメニューバーには四つのメニューしかないので5以上の数を与えるとエラーになります。
第2引数にOBJID_SYSTEMを指定した場合
GetMenuBarInfo APIの第2引数のidObjectにOBJID_SYSTEMを指定した場合の第3引数のidItemの各値の結果は以下のようになります。
- 第3引数に0を指定
- TMenuBarInfoのrcBarにはタイトルバーのアイコンをクリックしてシステムメニューがドロップダウンするエリアのRectが返ります。
- 第3引数に1を指定
- 第3引数に2以上を指定
第3引数に2以上を指定するとエラーになります。