2016-05-29 9 views
0

私はRegisterClassEx()で作成したカスタムウィンドウクラスを持っています。このクラスのウィンドウインスタンスを作成し、そのHMENUプロパティを設定すると、CreateWindowEx()関数が失敗します。HMENUのIDが設定されていない場合、

この種のウィンドウのID/HMENU IDを設定できないのはなぜですか?

// hwnd = NULL 
hwnd = CreateWindowEx(0, WND_CLASS_NAME.c_str(), wndTitle.c_str(), wndFlags,  
    wndDimensions.left, wndDimensions.top, wndDimensions.right, wndDimensions.bottom, 
    NULL, (HMENU)50001, hinstance, NULL); 

// hwnd is valid 
hwnd = CreateWindowEx(0, WND_CLASS_NAME.c_str(), wndTitle.c_str(), wndFlags,  
    wndDimensions.left, wndDimensions.top, wndDimensions.right, wndDimensions.bottom, 
    NULL, 0, hinstance, NULL); 

目的はすべてGetDlgCtrlId(hwnd);を呼び出すことです。

+0

50001は有効なメニューハンドルだと思いますか? – immibis

+0

@immibis有効なメニュー値の範囲は? – Sam

+0

'CreateMenu'によって返されたハンドルについてはどうですか? '(HWND)50001'をウィンドウハンドルとして使用しないで、'(HMENU)50001'をメニューハンドルとして使うのはなぜですか? – immibis

答えて

2

これは機能しません。 CreateWindowEx関数は、作成しているウィンドウの種類によって、パラメータの解釈が異なるという点で、ちょっと混乱します。間違った前提を避けるために、ドキュメントを慎重に読む必要があります。

two fundamental types of windowsがあります重複/ポップアップウィンドウが(私は戻って16ビットWindowsでの違いがあるように使用さだと思いませんが、その区別はもはや適切である。これらは実質的に同一であり)と子ウィンドウ 。最初のタイプは直観的に考えるものです。のように見えます。のようなものです。アプリケーションはメインウィンドウ、ダイアログボックス、フローティングツールウィンドウなどのためにアプリケーションが使用します。第2のタイプは、の別のウィンドウの子として使用できる特定の種類のウィンドウです。コントロールは、子ウィンドウ(ボタン、静的コントロール、リストビューなど)です。子ウィンドウは親ウィンドウ(常に親を持っています)によってホストされます。子ウィンドウは、別の子ウィンドウまたはオーバーラップ/ポップアップウィンドウのいずれかになります。

子ウィンドウには、アプリケーション定義IDがあります。CreateWindowEx関数をWS_CHILDスタイルフラグ(子ウィンドウの作成を要求する)を指定して呼び出すときに、このIDを指定します。そのフラグが存在する場合、hMenuパラメータはメニューへのハンドルとして解釈されません。むしろ、子ウィンドウのIDとして解釈されます。 なしWS_CHILDスタイルフラグ(我々はすでに見てきたあなたはWS_OVERLAPPEDWS_POPUPのいずれかを渡していること、本質的に交換可能である)CreateWindowEx関数を呼び出すときに、hMenuパラメータがハンドルとして解釈され

メニュー。それがメニューに対する有効なハンドルである場合、このメニューはウィンドウに関連付けられます。 NULLの場合、ウィンドウはクラスメニュー(ウィンドウクラスの作成中にRegisterClassExが呼び出されたときに指定されたもの)を使用します。

The function's documentationは、hMenuパラメータの説明でこれを明確にしようとしています。
それは言う:

HMENU [オプション、中]
         タイプ:HMENU

メニューへのハンドル、またはに応じて、子ウィンドウのIDを指定しますウィンドウスタイル。オーバーラップまたはポップアップウィンドウの場合、hメニューは、ウィンドウで使用するメニューを識別します。クラスメニューを使用する場合はNULLにすることができます。子ウィンドウの場合、hMenuは、子ウィンドウ識別子を指定します。これは、ダイアログボックスコントロールがイベントについて親に通知するために使用する整数値です。アプリケーションは、子ウィンドウ識別子を決定します。同じ親ウィンドウを持つすべての子ウィンドウで一意でなければなりません。

意味は明らかです。 ウィンドウはメニューとIDの両方を持つことはできません。 メニュー(重複/ポップアップウィンドウの場合)または子ウィンドウID(子ウィンドウの場合)。子ウィンドウにはメニューがありません。これはIDを持つため技術的に不可能です。だからあなたがしようとしていることは不可能です:重複した/ポップアップウィンドウはIDを設定することはできません。

GetDlgCtrlID関数を呼び出せるようにすることを目的としていますが、that function's documentationは、子ウィンドウに対してのみ機能するということについてはっきりしています。はじめに、関数の名前は、のコントロール( "ctrl"と略記)のために働くことを暗示しています。これは定義上、子ウィンドウでなければなりません。 (イタリック体の注釈が地雷です)さらに読む:

GetDlgCtrlIDを扱うだけでなく、ダイアログボックス内のコントロールのハンドルを子ウィンドウを受け入れます。 [技術的には、これは不要な区別です。今まで見てきたように、ダイアログボックスのコントロールはです。子ウィンドウはです。しかし、おそらく、作者はできるだけ明確になるように特別な注意を払っていました。CreateWindowまたはCreateWindowEx関数を呼び出すときに識別子値をhmenuパラメータに割り当てることによってウィンドウを作成するときに、子ウィンドウの識別子がアプリケーションによって設定されます。 hwndCtlは、トップレベルウィンドウへのハンドル、トップレベルウィンドウ[これによっては、オーバーラップまたはポップアップウィンドウのいずれかを意味する]持つことができない識別子と、そのようなリターンがある場合GetDlgCtrlIDなお

は、値を返すことができます値は決して有効ではありません。

特に、最終的な文章に注意してください。

もちろん、です。重複したウィンドウとポップアップウィンドウを識別する方法は、そのハンドルです。これはCreateWindowEx関数によって返された値です(成功したものとします)。このハンドルをウィンドウのIDとして保存できます。システム全体で一意であることが保証されています(ただし、ウィンドウが破棄された後に別のウィンドウで再利用される可能性があります)。ウィンドウを識別する最も信頼できる方法です。

何らかの理由でウィンドウハンドルを保存できないが、後でトップレベルのウィンドウを見つける必要がある場合は、FindWindow関数を呼び出すことができます。これはウィンドウクラス名とウィンドウキャプションを使用して一致するウィンドウを検索します。一致するものが見つかった場合は、ウィンドウハンドルを返します。子ウィンドウを検索する場合は、代わりにFindWindowExに電話する必要があります(子ウィンドウを検索する場合は、FindWindowは子ウィンドウでは機能しません)。注†)


子ウィンドウが作成されると、そのIDは、それぞれ、GetWindowLongPtrまたはSetWindowLongPtr関数にGWL_IDインデックスを渡すことによって設定または取得することができる、ということ。このインデックスは、IDを持つ他のタイプのウィンドウがないため、子ウィンドウに対してのみ意味を持ちます。 ‡

重複/ポップアップウィンドウが作成されると、そのメニューのハンドルがGetMenuで取得またはSetMenuで設定することができ、ということに注意してください。これらの関数のドキュメンテーションは、子ウィンドウにメニューを持たせることができないという事実を強調しなければなりません。 GetMenuは、子ウィンドウで呼び出されたときに失敗し、 "未定義"の結果を返します。 SetMenuも同様にエラーコードを設定して失敗します。

関連する問題