none
WPF Window の親ウィンドウに C++ CWnd のウィンドウハンドルを設定したい RRS feed

  • 質問

  • こんにちは。

    C#のWindowsForm を WPFのWindow に変更することになり、開発しています。

    ①C++アプリから②C#常駐アプリにメッセージ送信し、②がメッセージを受信したら③C#ウィンドウを表示する仕様で、

    ③のC#FormをWPFウィンドウに変更しています。

    ①、②、③は既に運用中で、画面構成を変える事は出来ません。


    ③のWindow表示時にモーダル状態にしたいのですが、どのような方法がありますでしょうか。

    (③の親ウィンドウに①で表示しているCWndのウィンドウハンドルを設定したいです。)


    WPFのWindow.Ownerに①を設定してやればクリックしても最前面を保ってくれますが、

    親ウィンドウには設定されないため①のCWndは操作できてしまいます(モードレス状態)


    SetParent(https://msdn.microsoft.com/ja-jp/library/cc411061.aspx)を

    試しましたがSpy++で確認しても親ウィンドウには設定されていませんでした。

    親ウィンドウの設定はこれを使用するのでしょうか。


    また、他に良い方法がありましたらお教え頂きたいです。

    よろしくお願いいたします。

    2016年5月12日 3:47

回答

  • WPFのWindow.Ownerに①を設定した際に、①のWindowを無効に設定し(EbableWindow FALSE)

    WPFのウィンドウを閉じる際に①のWindowを有効に設定(EbableWindow TRUE)するのはどうでしょうか?

    参考サイト: http://stackoverflow.com/questions/14557050/showing-wpf-window-from-other-process-in-modal-mode

    • 編集済み kenjinoteMVP 2016年5月12日 6:05
    • 回答としてマーク OPmk 2016年5月12日 7:41
    2016年5月12日 4:29
  • handle オブジェクトは、System.Windows.Window クラスかその派生クラスになっていますか?

    モードレスにはならないけど、裏に隠れないという場合は、ShowDialog の前後で、Win32側のウィンドウを無効化してやる(EnableWindow API相当を呼び出す)必要があると思います。おそらく、対応していないのでしょう。

    そうではなく、裏に隠れてしまうという場合は、そもそもWPFのシステム側がオーナーであることを認識していないと思います。

    WPF と Win32(Windows.Formsも同じ)とでは、同じ Windows OS 上で動作していますが、ウィンドウ管理システムは全く別物です(WPF側が独自のシステムを持っている)。

    そのため、対応が中途半端だとうまくいかない可能性は十分考えられます。そのあたりは、先に貼った相互運用のリンク先にいろいろ書かれているので、一読しておくことをお勧めします。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    • 回答としてマーク OPmk 2016年5月12日 7:32
    2016年5月12日 7:15

すべての返信

  • WPFのWindow.Ownerに①を設定した際に、①のWindowを無効に設定し(EbableWindow FALSE)

    WPFのウィンドウを閉じる際に①のWindowを有効に設定(EbableWindow TRUE)するのはどうでしょうか?

    参考サイト: http://stackoverflow.com/questions/14557050/showing-wpf-window-from-other-process-in-modal-mode

    • 編集済み kenjinoteMVP 2016年5月12日 6:05
    • 回答としてマーク OPmk 2016年5月12日 7:41
    2016年5月12日 4:29
  • ③を①の子ウィンドウにしたいということですか?今まで(WPFになるまえ)はそういう形の運用だったのでしょうか?

    そうではなく、③のWPFウィンドウを1をオーナーウィンドウとするモーダルウィンドウとして表示したいのですよね?

    であれば、ちょっと特殊なかたちで対応となります。

    ②のメッセージ受信時に、

    1. ①のトップレベルウィンドウを取得する(親がいないHWNDが出るまでGetParentでたどる)。
    2. 1.から③のオーナーにできるウィンドウオブジェクトを用意
    3. Owner プロパティで、1. をオーナーに設定して、③をShowDialog。

    とすることで、別プロセスのトップレベルウィンドウをオーナーとするモーダルダイアログを出せます。

    2はどうすればいいかよくわかりませんが、WPF と Win32 の相互運用性 に書いてあるみたいです(リンクたどっただけです)。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    2016年5月12日 4:55
  • kenjinote様

    お返事ありがとうございます。


    EbableWindowも必要な事を知りませんでした。

    非常に助かりました。

    ありがとうございました。
    • 編集済み OPmk 2016年5月12日 7:41
    2016年5月12日 5:02
  • とっちゃん様

    ありがとうございます。

    質問内容としては、お察しの通り後者の方です。

    WPFにする前は③のShowDialog(①.handle) のように

    引数に①のウィンドウハンドルを渡してモーダルウィンドウになっていました。

    WPFの場合は③.Owner = ①.handleのようにしてもモーダルウィンドウになりません。

    ①.hadleはプロセスIDからウィンドウハンドルを取得していたため、

    これをトップレベルウィンドウの検索に変えて試したいと思います。

    結果がわかりましたらまたお返事します。

    アドバイスありがとうございました。

    • 編集済み OPmk 2016年5月12日 5:21
    2016年5月12日 5:12
  • とっちゃん様

    トップレベルウィンドウの検索で試した結果です。

    トップレベルウィンドウのウィンドウハンドルを③のOwnerに設定しても、

    最前面状態にはなりますがモーダル状態にはなりませんでした。

    試す前の①のプロセスIDから取得した場合と同じ結果です。

    ウィンドウハンドルの取得は問題ではないようです。
    (プロセスIDから取得した場合もトップレベルウィンドウ検索で取得した場合と同じウィンドウハンドル)

    C#の場合もWPFの場合も
    Visual StudioツールのSpy++で確認すると
    [Owner Window] にはウィンドウハンドルが設定されていますが、
    [Parent Window] にはウィンドウハンドルが設定されていません。

    C#
    WindowsForm.ShowDialog(handle);
    ではモーダル状態なのに、

    WPF
    Window.Owner = handle;
    Window.ShowDialog();
    ではモードレス状態になってしまいます。

    シンプルなテストプロジェクトを試作して同じ結果であれば諦めようと思います。

    ありがとうございました。

    2016年5月12日 6:42
  • 試しにC# WindowsFormからWPF Windowを表示してみましたが、
    やはりモードレス状態になってしまいます。

    Window.Owner = [C# WindowsForm].handle;
    Window.ShowDialog();


    裏をクリック出来ないようモーダル状態にするには別の方法が必要なのでしょうか。

    どなたかお教えいただけるとありがたいです。

    よろしくお願いいたします。

    • 編集済み OPmk 2016年5月12日 7:12
    2016年5月12日 7:11
  • handle オブジェクトは、System.Windows.Window クラスかその派生クラスになっていますか?

    モードレスにはならないけど、裏に隠れないという場合は、ShowDialog の前後で、Win32側のウィンドウを無効化してやる(EnableWindow API相当を呼び出す)必要があると思います。おそらく、対応していないのでしょう。

    そうではなく、裏に隠れてしまうという場合は、そもそもWPFのシステム側がオーナーであることを認識していないと思います。

    WPF と Win32(Windows.Formsも同じ)とでは、同じ Windows OS 上で動作していますが、ウィンドウ管理システムは全く別物です(WPF側が独自のシステムを持っている)。

    そのため、対応が中途半端だとうまくいかない可能性は十分考えられます。そのあたりは、先に貼った相互運用のリンク先にいろいろ書かれているので、一読しておくことをお勧めします。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    • 回答としてマーク OPmk 2016年5月12日 7:32
    2016年5月12日 7:15
  • とっちゃん様

    返信ありがとうございます。


    Win32側のウィンドウ無効化等は、全く対応していません。

    無効化にする必要がある事を理解していませんでした。

    相互運用のリンク先を参考に学習します。

    ありがとうございました。

    非常に助かりました。


    2016年5月12日 7:32