VC++ MFC SDI CFormView です。
メニューを動的に追加したくて、下記のコードを書きました。
追加したメニュー項目をクリックしたとき発生するIDを調べたところ、ヘンな値とな
っています。
これでいいのでしょうか、教えてください。
【メニュー構成】
ファイル ↓
新規作成
開く
北斗の拳 ↓
ケンシロウ
ヒューイ
シュレン
動的に追加するのは、POPUPの「北斗の拳」と、その下に最大10個です。
【発生するIDの値】
「ケンシロウ」をクリックすると 14464 という数値が発生します。
「ヒューイ」では 14465、以下一つずつ増えます。
ID_ADDMENU 80000 なのに、これとは違った値になっているのが疑問です。
ID_ADDMENU を 90000 に変えても、発生する uID の値は同じ 14464 です。
【コード】
<Resource.h>
#define ID_ADDMENU 80000
#define ID_ADDMENU_RANGE 10
<MainFrame.cpp>
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_INITMENU()
END_MESSAGE_MAP()
void CMainFrame::OnInitMenu(CMenu* pMenu)
{
HMENU hMenu = CreatePopupMenu();
CMenu *pSub = pMenu->GetSubMenu(0);
pSub->InsertMenu(2, MF_BYPOSITION | MF_POPUP, (UINT)hMenu, _T(北斗の拳));
CMenu *pHokuto = pSub->GetSubMenu(2);
pHokuto->AppendMenu(MF_BYPOSITION, ID_ADDMENU+0, _T(ケンシロウ));
pHokuto->AppendMenu(MF_BYPOSITION, ID_ADDMENU+1, _T(ヒューイ));
pHokuto->AppendMenu(MF_BYPOSITION, ID_ADDMENU+2, _T(シュレン));
}
<HokotoView.cpp>
BEGIN_MESSAGE_MAP(CHokutoView, CFormView)
ON_COMMAND_RANGE(ID_ADDMENU, ID_ADDMENU+ID_ADDMENU_RANGE-1, OnHokutoGame)
・・・・・・・・
END_MESSAGE_MAP()
void CHokutoView::OnHokutoGame(UINT uID)
{
if (uID == ○○○) ◇◇◇;
と書きたくて、ここに発生する uID の値を調べました。
}
80000 = 0x13880
14464 = 0x03880
これで何か気づかない?
AppendMenuの第二引数のUINTでUINTはunsigned intなんで、80000は表現できるはず
なんだけど、メニューIDはunsigned shortの範囲でしか扱えない。そのため、上位
ワードが切り捨てられたとは考えられない?
# この辺にまだ16ビットの遺産が...
> ID_ADDMENU を 90000 に変えても、発生する uID の値は同じ 14464 です。
これはわかりません。コンパイルが正しく行われていないかも?
maru様、応答して戴き有り難うございます。
> メニューIDはunsigned shortの範囲でしか扱えない。
unsigned short の最大値は 65535 とのことなので、80000 を 60000 に変えてやってみ
ましたが、やはり 14464 (= 0x03880) が発生します。
USHRT_MAX-10 としても、極端に 2000 としても同じです。
> コンパイルが正しく行われていないかも?
質問するまでは Visual Studio 2010 試用版でビルドしていましたが、今回 VS2005 で
コンパイルしたところ、次の警告が出ました。(VS2005でビルドしても発生するIDの値
は同じ 14464 です。)
「・・・・・warning C4311: '型キャスト' : ポインタを 'HMENU' から 'UINT' へ切り
詰めます。」
この行に対して↓
pSub->InsertMenu(2, MF_BYPOSITION | MF_POPUP, (UINT)hMenu, _T(北斗の拳));
POPUPメニューの作り方が間違っているでしょうか?
pSub->InsertMenu(2, MF_BYPOSITION | MF_POPUP, (UINT)hMenu, _T(北斗の拳));
この行の中の (UINT) を (UINT_PTR) に変えたら、警告は出なくなりました。
CMenu::AppendMenu
http://msdn.microsoft.com/ja-jp/library/kb145b0a.aspx
第一引数に MF_BYPOSITION を指定していいとは書いてありませんが…
有り難うございます。
不注意のミスです。
MF_STRING に書き換えました。
しかし、結果は同じです。14464 (= 0x03880) が発生します。
まぁともかくも、WM_COMMAND を処理する際にメニューIDは16bitに切り捨てられてしま
うので、65535までにしておくのがいいと思います。
>> ID_ADDMENU を 90000 に変えても、発生する uID の値は同じ 14464 です。
> これはわかりません。コンパイルが正しく行われていないかも?
これは謎ですが…
aetos様、有り難うございます。
1桁小さい 8000 にしました。
ところで、不思議な現象が出ました。
<手順1>
試しに、メニューをもう1個追加しました。
ファイル ↓
新規作成
開く
北斗の拳 ↓
ケンシロウ
ヒューイ
北斗の拳2 ↓
ケンシロウ
ヒューイ
<Resource.h>
#define ID_ADDMENU 8000
#define ID_ADDMENU_RANGE 10
#define ID_ADDMENU2 8100
#define ID_ADDMENU2_RANGE 10
あーら不思議!
北斗の拳→ケンシロウ で 8000 が発生
北斗の拳2→ケンシロウ で 8100 が発生
<手順2>
追加した「北斗の拳2」を削除して、元の状態に戻しました。
北斗の拳→ケンシロウ で 8000 が発生
<手順3>
#define ID_ADDMENU を 9000 に変更しても、8000 が発生します。
どう変えても 8000 が発生します。
コンパイラのバグでしょうか?
VS2005 と VS1010 の両方で同じことをやりましたが、同じ結果です。
1ヶ月以内にすべて(WindowsもVSも)クリーン・インストールするつもりですが、そし
たらまた 14464 が出ることでしょうね。 (^o^)
(誤)VS2005 と VS1010 の両方で同じことをやりましたが、同じ結果です。
(正)VS2005 と VS2010 の両方で同じことをやりましたが、同じ結果です。
> #define ID_ADDMENU を 9000 に変更しても、8000 が発生します。
現象を確認しました。
原因は resource.h のみが変更された場合、ビルドではソースファイルのコンパイル
が実行されないことでしょう。
[ビルド]-[ソリューションのリビルド]を実行してみてください。
resource.h はメインヘッダーにインクルードされているので、本来これが変更され
れば、全てのソースファイルをコンパイル/リンクするべきと思いますが、VCはこの
ファイルを何か特殊処理しているのでしょうね。
元々このメニューIDはリソースには関係しないので、resource.h に記述するのでは
なく、メインヘッダーにでも入れておくほうがよかったのでは?
また、メニューIDの範囲の問題は、プロジェクトのプロパティで警告レベルを4に
あげておけば、
「warning C4310: キャストによって定数値が切り捨てられました。」
という警告があがりますので、それでわかったはずです。
プロジェクトを作成したら、まず警告レベルを上げることをお勧めいたします。
> 「warning C4310: キャストによって定数値が切り捨てられました。」
> という警告があがりますので、それでわかったはずです。
ちなみに警告があがるのは、AppendMenuではなくて、ON_COMMAND_RANGEマクロです。
うーーん
そういえば、メニュー関連に限らず、リソースIDって32768未満て決まり
があったとだと思ったのですが。。。
> [ビルド]-[ソリューションのリビルド]を実行してみてください。
やりました。バッチリ、IDと同じ数値が発生します。
> resource.h に記述するのではなく、メインヘッダーにでも入れておくほうがよかった
のでは?
はい、MainFrame.h に書きました。OKです。
(ネット上で見つけたサンプルが Resource.h に書くようになっていたので、何も考え
ず真似してしまいました。)
> プロジェクトのプロパティで警告レベルを4にあげて・・・
レベル4にして、IDの値が 65535 より大きいと、「warning C4310: キャストによって
定数値が切り捨てられました。」が出るのを確認しました。
(ほかにも沢山警告が出ちゃいました。笑)
ID と同じ uID が発生するようになったので安心しました。
maru様はじめ皆様、ありがとうございました。
> そういえば、メニュー関連に限らず、リソースIDって32768未満て決まり
> があったとだと思ったのですが。。。
いえいえそんなことはありません。
AppWizardでMFCアプリを生成すると50000以上の文字列IDをたくさん作ってくれます。
>いえいえそんなことはありません。
>AppWizardでMFCアプリを生成すると50000以上の文字列IDをたくさん作ってくれます
そうですか、
ありがとうございます。
別のIDと勘違いしたのかも知れませんね。