none
CWinにキャストされた派生クラスの名前を知りたい RRS feed

  • 質問

  • CWnd::WindowFromPoint()でウインドウのオブジェクトをとったのですが、これがラジオボタンなのかチェックボックスなのかあるいは全く別のものなのかが分かりません。
    ヘルプでCWndのメンバを見ても、それが調べられそうなものが見つかりません。
    何か識別する方法はあるでしょうか。
    2011年9月13日 13:03

回答

  • 直接の回答はしづらいですが、思いつくままヒントを並べてみます。

    1.SDK等に付属のSPY++というツールがあります。このツールは
     マウス直下のウインドウのクラススタイルやウインドウスタイルを
     取得できます。つまり、原理的にSPY++ができることは、他のアプリでも
     できます。まず、これでAアプリを観察してみましょう。

    2.クラス名称が"Button"であるウインドウがラジオボタンであるかどうかは、
     ウインドウスタイルにBS_AUTORADIOBUTTONやBS_RADIOBUTTONなどの、
     ラジオボタンを意味するウインドウスタイルが設定されているかどうかで
     (ある程度)判断できます。SPY++で確認してみましょう。

    3.CWnd*が一時オブジェクトであっても、そのメンバであるm_hWndは
     MFCの管理外であり、OSのカーネルが保障する値です。そのウインドウが
     WM_DESTROYなどの破棄指令を受け取るまではMFCとは無関係に有効です。
     MFCはSDKの単なるラッパであることを意識しましょう。 

    4.タブオーダーやグループがWindowFromPoint()の結果に影響を与えるとは
     思えません。タブオーダーとは、ウインドウマネージャが管理している
     ウインドウの配列の中で、WS_TABSTOPスタイルを持つウインドウの
     一連のZオーダーの順列を意味します。同じく、グループとはWS_GROUP
     スタイルを持つウインドウから、次のWS_GROUPスタイルを持つウインドウ
     までの兄弟の集合を意味します。
     WS_xxxはHWNDを修飾するための単なるフラグに過ぎません。
     これもSPY++で確認できます。

    いずれにしても、別アプリをコントロールするには、プロセスやスレッド等
    に対する詳細な理解と、ウインドウメッセージに対する理解が必要です。
    部分的にはMFCを頼りにできないので覚悟してやりましょう。

    2011年9月15日 1:33

すべての返信

  • ローテクな方法としては、API の GetClassName を使うとか?
    すぱっとよい方法があるかどうかは、MFC を最近触ってないので忘れた。。。

    # この関数の場合、CWnd などのクラスではなく、ウィンドウクラス("BUTTON" とか)になります。
    # CheckBox, RadioButton も "BUTTON" ではあるはずなので、BS_CHECKBOX も見ないといけなくなりますが...。


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2011年9月13日 14:15
    モデレータ
  • >ローテクな方法としては、API の GetClassName を使うとか?

    CWnd::WindowFromPoint() とかって、一時的な CWnd を返しませんでしたっけ?

    2011年9月14日 1:12
  • 渋木のおっしゃる通り、一時オブジェクトですね。
    ですが、GetClassName()はHWNDを使用するので、実行に支障はありません。

    コントロールの種別を判定できた後、そのCWnd*に対して
    何をしようとしているかによって、危険な場合と、いけちゃう場合があります。
    現時点では、一時オブジェクトは派生先にキャストできないので、派生クラスを使いたい
    ならAttachしてください。としか言えませんね。
    ueda111さんは、やりたいことをもちっと詳しく説明をすると、よりましな回答が
    得られるかもしれません。


    2011年9月14日 2:04
  • Azuleanさん渋木さん有難う御座います。

    試したところ、エディットボックスを取ってもチェックボックスを取ってもすべて「Button」で取得されるという問題に遭遇しました。
    試行錯誤の結果、GetClassNameが悪いのではなく、グループボックスの中に入っているオブジェクトはすべて「Button」で帰ってくることに 気づきました。GetWindowText()でキャプションを取ってみると、グループボックスのキャプションが取れるので、そもそも WindowFromPoint()でグループボックス内のオブジェクトは取得できないということのようです。

    グループボックスのポインタから含まれるコントロールを取得するために、そこからまた試行錯誤をしました。
    VBだとControlsで取れることが分かりましたがVC++での方法が分かりません。
    なお、ChildWindowFromPoint()ではグループボックス自身のポインタが帰ってきました。
    GetControlContainer()も名前はそれらしいのですがActiveXのコントロールだそうで、ちょっと違いそうです。

    VBでできるのだからVC++でも手段がありそうに思うのですが。
    2011年9月14日 7:59
  • そもそもどんな動作を実装したいんでしょうか?

     

    2011年9月14日 10:00
  • 仲澤さん有難う御座います。

    充分に「まし」な回答をして頂いていまして、それどころか大変助かりまして、ここでそもそもの話を書き出すのは何か図々しいかもしれないのですが、やりたいことは以下です。

    アプリケーションAとBがあります。Aにはチェックボックスやエディットボックスがあります。
    Aを操作したいのですが、直接操作するのではなく、間に操作とそのときのAの状態を記録するアプリケーションBを介在したいです。Bからこのチェックボックスの状態を取ったり、エディットボックスに字を入れたりしようとしています。
    Aのソースはいじれません。
    そこで、CWnd*が分かって、それがボタンだとかエディットボックスだとかの区別が付けば、たとえばチェック状態を知りたければ直接IsIconicなどを呼んで取ってしまえばよいのではと考えた次第です。

    で、いろいろ試した結果、タブオーダー順がグループボックスの直後のオブジェクトは、WindowFromPoint()では取れない(グループボックスが取れる)ということが分かりました。
    タブオーダー順がグループボックスより前ならWindowFromPoint()でも取れました。
    グループボックスはラジオボタンをグループ化したりするので、何か特殊な事情があるのだろうと思います。

    タブオーダー順がグループボックスの直後のオブジェクトを座標から取る問題については、以下の要領で何とかなりました。

    1.グループボックスの最後の兄弟オブジェクトをGetWindow(GW_HWNDLAST )で取る
    2.そこからGetWindow(GW_HWNDPREV)ですべてのオブジェクトを取る
    3.GetWindowRect()で、取得した全オブジェクトの位置を取る
    4.PtInRect()で、指定座標位置にあるオブジェクトを特定する


    一時的なオブジェクトがいつまで保持されるか、そういえばはっきり知らないのですが、CWndの取得処理をした関数内なら問題なかろうと思っています。
    でも改めて考えると、CWndを取得した直後にアプリケーションAが落ちるかも知れず、「いつまでは使っても問題ない」というのははっきり決まらないかもしれないと気づきました。
    アプリケーションAが落ちて対象が見つからないというぐらいなら例外処理で解決ですが、全然違うところを指しているととても怖いですね。
    何か根本的にやり方を変えたほうがよいのかも知れない気がしてきました。

    2011年9月14日 12:03
  • 直接の回答はしづらいですが、思いつくままヒントを並べてみます。

    1.SDK等に付属のSPY++というツールがあります。このツールは
     マウス直下のウインドウのクラススタイルやウインドウスタイルを
     取得できます。つまり、原理的にSPY++ができることは、他のアプリでも
     できます。まず、これでAアプリを観察してみましょう。

    2.クラス名称が"Button"であるウインドウがラジオボタンであるかどうかは、
     ウインドウスタイルにBS_AUTORADIOBUTTONやBS_RADIOBUTTONなどの、
     ラジオボタンを意味するウインドウスタイルが設定されているかどうかで
     (ある程度)判断できます。SPY++で確認してみましょう。

    3.CWnd*が一時オブジェクトであっても、そのメンバであるm_hWndは
     MFCの管理外であり、OSのカーネルが保障する値です。そのウインドウが
     WM_DESTROYなどの破棄指令を受け取るまではMFCとは無関係に有効です。
     MFCはSDKの単なるラッパであることを意識しましょう。 

    4.タブオーダーやグループがWindowFromPoint()の結果に影響を与えるとは
     思えません。タブオーダーとは、ウインドウマネージャが管理している
     ウインドウの配列の中で、WS_TABSTOPスタイルを持つウインドウの
     一連のZオーダーの順列を意味します。同じく、グループとはWS_GROUP
     スタイルを持つウインドウから、次のWS_GROUPスタイルを持つウインドウ
     までの兄弟の集合を意味します。
     WS_xxxはHWNDを修飾するための単なるフラグに過ぎません。
     これもSPY++で確認できます。

    いずれにしても、別アプリをコントロールするには、プロセスやスレッド等
    に対する詳細な理解と、ウインドウメッセージに対する理解が必要です。
    部分的にはMFCを頼りにできないので覚悟してやりましょう。

    2011年9月15日 1:33
  • ヒント有難う御座います。

    気になっていた「一時的なオブジェクト」問題はハンドルのほうを使えばかなり心配が減らせそうですね。
    SPY++も試してみます。

    Azuleanさん、渋木さん、仲澤さん、本当にどうも有難う御座いました。
    2011年9月15日 4:40