質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.87%

  • C#

    6228questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

C#でウィンドウを最背面にして移動したい

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 999

cancat

score 239

こんにちは。 
Windows10でWindows Formのアプリケーションを開発しています。 
Visual Studio 2017 Communityを使っています。 

前提・実現したいこと

いつも見る必要のないウィンドウをサブのディスプレイに移動したいです。表示はしておきたいけれど、いつも見る必要はないので、ウィンドウを最背面にしたいです。
セカンダリディスプレイは、DisplayLinkを使って、USBから出力しています。

試したこと

下記コードを実行すると、
・WindowBack()を実行すると、ウィンドウ位置がメインウィンドウに移動します。ウィンドウは最背面になります。最背面なのはいいけれどウィンドウ位置がいまいち。
・WindowBack()をコメントアウトして実行しないと、ウィンドウ位置はセカンダリウィンドウに配置できます。ウィンドウは最背面にできません。ウィンドウ位置はいいけど最背面でないので邪魔なことがあります。

ここからは推測です。
WindowBack()を実行したときにウィンドウ位置がメインウィンドウに移動する理由は、ウィンドウの親としてProgram Managerをさがしているためです。
とすると、DisplayLinkで表示しているウィンドウのウィンドウハンドルは、Program Managerではないのかもしれません。そうだとすれば、DisplayLinkのウィンドウのハンドルを探して、それを親にすれば、サブウィンドウに最背面で表示できることになります。
そこで質問。

DisplayLinkで表示しているウィンドウのウィンドウハンドルの名前を知りたいです。
あるいは、もしこの推測が違っているのであれば、違っているところをご指摘いただけるとうれしいです。さらに、

いつも見る必要のないウィンドウをサブのディスプレイに移動したいです。表示はしておきたいけれど、いつも見る必要はないので、ウィンドウを最背面にしたいです。

という目的を達成できるコードを教えていただけるとうれしいです。

発生している問題・エラーメッセージ

DisplayLinkを使ったサブウィンドウに、ウィンドウを最背面にして移動できない。

該当のソースコード

private void Form1_Load(object sender, EventArgs e) {
    var windowgoback = new windowBack.WindowBack();
    windowgoback.windowBack(this.Handle);

    this.Location = new Point(4000, 100);
}
using System;
using System.Runtime.InteropServices;

namespace windowBack {
    public class WindowBack {
        [DllImport("USER32.DLL", CharSet = CharSet.Auto)]
        private static extern System.IntPtr FindWindow(
            string lpClassName,
            string lpWindowName
        );

        [DllImport("USER32.DLL", CharSet = CharSet.Auto)]
        private static extern System.IntPtr SetParent(
            System.IntPtr hWndChild,
            System.IntPtr hWndNewParent
        );

        public void windowBack(IntPtr Handle) {
            System.IntPtr hProgramManagerHandle = FindWindow(null, "Program Manager");

            if (!hProgramManagerHandle.Equals(System.IntPtr.Zero))
                SetParent(Handle, hProgramManagerHandle);
        }
    }
}

補足情報(言語/FW/ツール等のバージョンなど)

Microsoft Visual Studio Community 2017
Version 15.0.26228.9 D15RTWSVC
Microsoft .NET Framework
Version 4.6.01586

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

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

ウィンドウを最背面に持っていくには、SetParentを使うのでなく、SetWindowPosを使ってください。
SetWindowPos

サブのディスプレイにウィンドを移動するには、以下を参照してください。
指定したモニターにフォームを表示する

この二つを組み合わせれば、お望みの動作が実現できると思います。


追記

SetWindowPosのHWND_BOTTOMの値は、1です。

uFlagsは、SWP_NOSIZE(値としては1)とSWP_NOMOVE(値としては2)のOR、すなわち3を渡してください。

以下を参考にしてください。 

SetWindowPos (user32)


追記2

常に最背面にしたいということであれば、以下のコードで実現できます。

    public partial class Form1 : Form
    {
        private const int WM_WINDOWPOSCHANGING = 0x0046;
        private IntPtr HWND_BOTTOM = (IntPtr)1;

        [StructLayout(LayoutKind.Sequential)]
        public struct WINDOWPOS
        {
            public IntPtr hwnd;
            public IntPtr hwndInsertAfter;
            public int x;
            public int y;
            public int cx;
            public int cy;
            public uint flags;
        }

        public Form1()
        {
            InitializeComponent();
        }

        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_WINDOWPOSCHANGING:
                    WINDOWPOS wp = (WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(WINDOWPOS));
                    wp.hwndInsertAfter = HWND_BOTTOM;
                    Marshal.StructureToPtr(wp, m.LParam, true);
                    break;
            }
            base.WndProc(ref m);
        }
    }

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/03 15:46

    ありがとうございます。夜に試します!

    キャンセル

  • 2017/10/03 20:44

    すみません。C#だとHWND_BOTTOMはどう指定すればよいですか?

    [DllImport("USER32.DLL", CharSet = CharSet.Auto)]
    private static extern bool SetWindowPos(
    System.IntPtr hWnd, // ウィンドウのハンドル
    System.IntPtr hWndInsertAfter, // 配置順序のハンドル
    int X, // 横方向の位置
    int Y, // 縦方向の位置
    int cx, // 幅
    int cy, // 高さ
    uint uFlags // ウィンドウ位置のオプション
    );

    public void SetWindowBack(IntPtr Handle, int X, int Y, int width, int height) {
    SetWindowPos(Handle, HWND_BOTTOM, X, Y, width, height, 0);
    }

    キャンセル

  • 2017/10/03 22:43

    ありがとうございます。
    下記の通りですが、残念ながら、最背面にはなりませんでした。

    windowgoback.SetWindowBack(this.Handle, this.Location.X, this.Location.Y, this.Width, this.Height);

    public void SetWindowBack(IntPtr Handle, int X, int Y, int width, int height) {
    SetWindowPos(Handle, (System.IntPtr)1, X, Y, width, height, 3);
    }

    キャンセル

  • 2017/10/04 11:05

    以下のコードで、最背面に移動することは確認してます。

    public partial class Form1 : Form
    {
    [System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
    static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
    public Form1()
    {
    InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
    SetWindowPos(this.Handle, (IntPtr)1, 0, 0, 0, 0, 3);

    }
    }

    なにか、それ以外に原因があるのでは?

    キャンセル

  • 2017/10/04 18:16

    質問者さんが求めているのは、一時的なZオーダーの移動ではなく
    常に最背面(TOPMOSTの逆)なのでは?
    Program Managerの子にするというのも検索で出てきますしね

    当方には質問者さんの環境が作れないので分かりませんが、もし質問者さんの
    推測していることが原因なのであれば、SPY++等で調べてみてはいいのでは?

    キャンセル

  • 2017/10/10 16:43

    コメントありがとうございます。
    そうです。常に最背面にしたいです。TOPMOSTの逆です。
    SPY++だと何を探せばよさそうでしょうね?

    キャンセル

  • 2017/10/11 15:24

    ありがとうございます。また夜に試します!!

    キャンセル

  • 2017/10/11 20:28

    残念。最背面にはなりませんでした。背面にもなりませんでした。別のウィンドウの上に表示しています。

    キャンセル

  • 2017/10/11 20:57

    私の環境では、提示したコードで最背面に固定されることを確認しています。おかしいですね。なにが違うのでしょうか?

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.87%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C#

    6228questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。